fuse-3.18.3/0000755000175000017500000000000015250106404011513 5ustar berndberndfuse-3.18.3/.ackrc0000644000175000017500000000005115250106036012574 0ustar berndbernd--ignore-dir=build --ignore-dir=doc/html fuse-3.18.3/.clang-format0000644000175000017500000000636415250106036014100 0ustar berndbernd# SPDX-License-Identifier: GPL-2.0 # # clang-format configuration file. Intended for clang-format >= 11. # # For more information, see: # # Documentation/process/clang-format.rst # https://clang.llvm.org/docs/ClangFormat.html # https://clang.llvm.org/docs/ClangFormatStyleOptions.html # --- AccessModifierOffset: -4 AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left AlignOperands: true AlignTrailingComments: false AllowAllParametersOfDeclarationOnNextLine: false AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: None AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false AlwaysBreakTemplateDeclarations: false BinPackArguments: true BinPackParameters: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: false BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeComma BreakAfterJavaFieldAnnotations: false BreakStringLiterals: false ColumnLimit: 80 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerIndentWidth: 8 ContinuationIndentWidth: 8 Cpp11BracedListStyle: false DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false FixNamespaceComments: false IncludeBlocks: Preserve IncludeCategories: - Regex: '.*' Priority: 1 IncludeIsMainRegex: '(Test)?$' IndentCaseLabels: false IndentGotoLabels: false IndentPPDirectives: None IndentWidth: 8 IndentWrappedFunctionNames: false JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: None ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true # Taken from git's rules PenaltyBreakAssignment: 10 PenaltyBreakBeforeFirstCallParameter: 30 PenaltyBreakComment: 10 PenaltyBreakFirstLessLess: 0 PenaltyBreakString: 10 PenaltyExcessCharacter: 100 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Right ReflowComments: false SortIncludes: false SortUsingDeclarations: false SpaceAfterCStyleCast: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatementsExceptForEachMacros SpaceBeforeRangeBasedForLoopColon: true SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInAngles: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Cpp03 TabWidth: 8 UseTab: Always ... fuse-3.18.3/.codespellrc0000644000175000017500000000101515250106036014011 0ustar berndbernd[codespell] skip = .git,*.pdf,*.svg,AUTHORS # The following strings shouldn't actually be accepted, but they're wrongly # identified as words and there is currently no way to exclude them on # a by-line basis (https://github.com/codespell-project/codespell/pull/2400). # Therefore, pretend that they are correctly spelled words: # - alse: used in regex # - siz: wanted short # - fiter: variable # - re-used: intentional hyphenation # - re-using: intentional hyphenation ignore-words-list = alse,siz,fiter,re-used,re-using fuse-3.18.3/.dir-locals.el0000644000175000017500000000523615250106036014153 0ustar berndbernd((python-mode . ((indent-tabs-mode . nil))) (c++-mode . ((c-file-style . "linux-kernel") (c-basic-offset . 8) (c-label-minimum-indentation . 0) (c-offsets-alist . ( (arglist-close . c-lineup-arglist-tabs-only) (arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only)) (arglist-intro . +) (brace-list-intro . +) (c . c-lineup-C-comments) (case-label . 0) (comment-intro . c-lineup-comment) (cpp-define-intro . +) (cpp-macro . -1000) (cpp-macro-cont . +) (defun-block-intro . +) (else-clause . 0) (func-decl-cont . +) (inclass . +) (inher-cont . c-lineup-multi-inher) (knr-argdecl-intro . 0) (label . -1000) (statement . 0) (statement-block-intro . +) (statement-case-intro . +) (statement-cont . +) (substatement . +) )) (indent-tabs-mode . t) (show-trailing-whitespace . t) )) (c-mode . ((c-file-style . "linux-kernel") (c-basic-offset . 8) (c-label-minimum-indentation . 0) (c-offsets-alist . ( (arglist-close . c-lineup-arglist-tabs-only) (arglist-cont-nonempty . (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only)) (arglist-intro . +) (brace-list-intro . +) (c . c-lineup-C-comments) (case-label . 0) (comment-intro . c-lineup-comment) (cpp-define-intro . +) (cpp-macro . -1000) (cpp-macro-cont . +) (defun-block-intro . +) (else-clause . 0) (func-decl-cont . +) (inclass . +) (inher-cont . c-lineup-multi-inher) (knr-argdecl-intro . 0) (label . -1000) (statement . 0) (statement-block-intro . +) (statement-case-intro . +) (statement-cont . +) (substatement . +) )) (indent-tabs-mode . t) (show-trailing-whitespace . t) )) ) fuse-3.18.3/AUTHORS0000644000175000017500000002556315250106036012577 0ustar berndberndCurrent Maintainers ------------------ Bernd Schubert Ashley Pittman Antonio SJ Musumeci Past Maintainers ---------------- Nikolaus Rath (until 02/2024) Miklos Szeredi (until 12/2015) Contributors ------------ CUSE has been written by Tejun Heo . Furthermore, the following people have contributed patches (autogenerated list): 1c7718e7 a1346054 <36859588+a1346054@users.noreply.github.com> admorgan Ahmed Masud AKowshik Alan Somers Albert Chen <58009229+hselin-kalista-io@users.noreply.github.com> Albert Chen Aleksandr Mikhailov Alexander alex Alex Richman Amir Goldstein amosonn Anatol Pomozov André Schröder Andrew Gaul Andrew Gaul Angelo G. Del Regno Anthony Rebello Antonio SJ Musumeci Arunav Sanyal asafkahlon <35964924+asafkahlon@users.noreply.github.com> Ashley Pittman AsumFace Banglang Baptiste Daroussin Benjamin Barenblat Bernd Schubert Bernd Schubert Bill Zissimooulos Bill Zissimopoulos bobrofon Brian Naylor Carl Edquist Carlos Maiolino Chad Austin Changli Gao Christian Menges Christopher Harrison Ciaran Consus Craig Chi Csaba Henk Csaba Henk cvs2git <> Dalvik Khertel Daniel Fullmer Daniel Thau David Galeano David McNab David Sheets dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Dharmendra singh Dharmendra Singh divinity76 DrDaveD <2129743+DrDaveD@users.noreply.github.com> Dr. David Alan Gilbert Emily Herbert Emmanuel Dreyfus Enke Chen Eric Engestrom Eric Wong Etienne Dublé Fabian Vogt Fabrice Bauzac Fabrice Fontaine Fedor Korotkov Feng Shuo ferivoz <72023087+ferivoz@users.noreply.github.com> Feverfew Fina Wilke Florian Weimer Forty-Bot Frank Dinoff Giulio Benetti Giuseppe Scrivano Goswin von Brederlow guraga HazelFZ Heiko Becker Hendrik Brueckner HereThereBeDragons Hookey human ikbenlike Ikey Doherty itsdeepak Jan Blumschein Jann Horn Jay Hankins Jean-Pierre André Jean-Yves VET Jérémie Galarneau Joachim Schiele Joachim Schiele Joerg Thalheim John Baber-Lucero John Muir Joseph Dodge Josh Soref Junichi Uekawa Junichi Uekawa Junichi Uekawa Kangjing "Chaser" Huang Ken Schalk Kevin Vigor Kirill Smelkov Kyle Lippincott Laszlo Boszormenyi (GCS) Laszlo Papp Laurent Bigonville Lilo Huang Liu Bo Li-Wen Hsu lixiaokeng <63774002+lixiaokeng@users.noreply.github.com> lixiaokeng Luis Henriques Madan Valluri Manuel Jacob Marcin Sulikowski Mark Glines Martin Blanchard Martin Pärtel Mateusz UrbaÅ„czyk Matthias Goergens Matthias Görgens Mattias Nissler maxice8 <30738253+maxice8@users.noreply.github.com> Maximilian Heinzler Max Krasnyansky Michael Forney Michael Grigoriev Mihail Konev Miklos Szeredi Miklos Szeredi Miklos Szeredi Miklos Szeredi Misono Tomohiro mkmm@gmx-topmail.de mrdvdrm Natanael Copa Niels de Vos Nikola Petrov <73067824+Petrov22Nikola@users.noreply.github.com> Nikolaus Rath Nozomi Miyamori <99280467+nm004@users.noreply.github.com> Oded Arbel Olivier Blin pablomh Pedro Kaj Kjellerup Nacht Pedro Nacht Peri Peter Lemenkov philmd Pierre Labastie Przemyslaw Pawelczyk PrzemysÅ‚aw PaweÅ‚czyk psykose Ratna_Bolla@dell.com Rethan <359062468@qq.con> Reuben Hawkins rfjakob richardweinberger Richard W.M. Jones Riku Voipio Robo Shimmer Roland Bauerschmidt Roman Bogorodskiy Rosen Penev Rostislav Rostislav Skudnov Rudi Heitbaum Sam Huffman <40582525+samh-sifive@users.noreply.github.com> Sam James Sam Stuewe Sangwoo Moon Sarath Lakshman Sargun Dhillon scosu Scott Worley Sebastian Pipping Sergey Fedoseev Seunghoon Yeon SÅ‚awek Rudnicki Stefan Hajnoczi Stefan Hajnoczi Stephen Kitt Tej Chajed tenzap <46226844+tenzap@users.noreply.github.com> therealneworld@gmail.com Tobias Nießen Tofik Sonono Tomasz Kulasek <34129113+tkulasek@users.noreply.github.com> Tom Callaway Tom Callaway Tomohiro Kusumi userwithuid Valentin Plugaru Vivek Goyal Waldir Pimenta wdlkmpx William Woodruff Winfried Koehler winndows Xiubo Li Yaroslav Halchenko y Yuri Per Zhansong Gao Zhiqiang Liu zsugabubus # New authors since fuse-3.16.2 farlongsignal <141166749+farlongsignal@users.noreply.github.com> yangyun50 <149988609+yangyun50@users.noreply.github.com> bigbrotherwei <1965867461@qq.com> Caian Benedicto <2220062+Caian@users.noreply.github.com> desertwitch <24509509+desertwitch@users.noreply.github.com> SteveYang <40466358+SteveY4ng@users.noreply.github.com> FredyVia <942513309@qq.com> legezywzh <94814730+legezywzh@users.noreply.github.com> CismonX amitgeron Bernd Schubert Daniel Rosenberg Horst Birthelmer Joanne Koong Josef Bacik Matthew gandalfs_cat MJ Harvey Nils Norman Wilson leipeng Vladimir Serbinenko George Hilliard Tyler Hall yangyun Abhishek # New authors since fuse-3.17.1 Luis Henriques Zegang swj <1186093704@qq.com> Gleb Popov <6yearold@gmail.com> WekaJosh <80121792+WekaJosh@users.noreply.github.com> Alexander Monakov Ben Dooks Ben Linsay Dave Vasilevsky Darrick J. Wong Georgi Valkov Alik Aslanyan jnr0006 Jingbo Xu Long Li Maksim Harbachou Meng Lu Wang Vassili Tchersky Vassili Tchersky izxl007 Zeno Sebastian Endemann # New authors since fuse-3.18.1 Abhinav Agarwal # New authors since fuse-3.18.2 Robert Doebbelin Ashish Ahuja Benjamin Peterson wilkis Jan Engelhardt Alexander Mikhalitsyn wangrzneu nikola-sh Mikhail Novosyolov Keerthana KT fuse-3.18.3/ChangeLog.rst0000644000175000017500000011634615250106036014110 0ustar berndberndlibfuse 3.18.3 (2026-09-09) =========================== Security Fixes -------------- * ``fuse_session_custom_io()`` is disabled unless libfuse is built with ``-Denable-custom-io=true``, and returns ``-ENOTSUP`` otherwise. The ``hello_ll_uds`` example is built only with that option, and enabling it warns at configure time. Reason is a custom io peer might not be a kernel and can forge requests that libfuse parses without bounds checks, crashing or corrupting the filesystem process. See ``doc/README.custom-io``. * fusermount3: resolve the mountpoint once, through an ``O_PATH|O_NOFOLLOW`` descriptor. A symlink swapped in between the type check and the second lookup could redirect the mount. * fusermount3: run the auto-unmount probe as the calling user. It opened the caller-supplied mountpoint with elevated privileges before, so a symlink could get an attacker-chosen path opened as root. * mount_util: terminate the ``/bin/mount`` and ``/bin/umount`` argument vectors with ``--``. ``fsname`` reaches them straight from ``-ofsname=`` in setuid-root fusermount3, and the child raises the real uid to 0 before ``execle()``, so an unprivileged caller controlled a positional operand of a mount(8) that was not in restricted mode. * mount_util: skip the mtab update entirely for option-like mount arguments. BusyBox mount(8) does not honour ``--``. * fusermount3: unmount through ``unmount_fuse()`` when passing the device descriptor to the caller fails, so that path drops privileges and runs the ``fusermount3 -u`` checks instead of calling ``umount2()`` as root on a caller-supplied path. * fusermount3 and lib: pass ``UMOUNT_NOFOLLOW`` on the kernel and non-setuid unmount paths. * fusermount3: check the ``fstat()`` return value when validating the communication file descriptor. * fusermount3: fix an out-of-bounds read at index -1 in ``get_mnt_opts()`` when the option string is empty, which a read-only mount with no further options reaches. * util: avoid a pointer underflow when trimming ``fuse.conf`` lines. * fusermount3: reject a negative ``mount_max`` other than the documented -1. A typo such as -2 made the limit comparison always true and blocked every non-root mount. * lib: relay the KILLPRIV_V2 kill-suidgid flags to the filesystem in the new ``fuse_file_info::kill_suidgid``. Only ``setattr`` saw them before, so a filesystem that had taken over clearing suid/sgid never learned of it on ``O_TRUNC`` open and on write, and the bits survived. Note: ``fuse_file_info::kill_suidgid`` is new in 3.18.3 and ``FUSE_VERSION`` carries no patch level. A filesystem built against these headers but running against an older 3.18 library finds the field permanently zero, so require 3.18.3 at run time as well. Important Fixes --------------- * Fixed a hang on ``statx`` in builds without ``HAVE_STATX``: ``_do_statx()`` never replied, so the kernel waited forever. * io-uring: the CQE dispatch validated the opcode against ``fuse_ll_ops[]`` but called through ``fuse_ll_ops2[]``, so an opcode with no handler there was called as a null function pointer. * io-uring: fixed the notify-retrieve reply buffer handling. The ``fuse_notify_retrieve_in`` header sits at the start of the payload buffer, not in the ring header. * io-uring: fixed the ``req_header_sz`` calculation, which sized the header buffer from the wrong struct. * io-uring: create the rings with ``IORING_SETUP_SUBMIT_ALL``, so one failing commit SQE no longer leaves the rest of the batch unsubmitted. * io-uring: ``fuse_reply_none()`` commits the ring entry. A FORGET answered that way leaked the entry and left the kernel-side request outstanding. * fusermount3: treat ``ECONNABORTED`` like ``ENOTCONN`` when deciding whether to auto-unmount, so a daemon that dies with io-uring registered no longer leaves the mount behind. * ``receive_fd()``: check ``CMSG_FIRSTHDR()`` for NULL before dereferencing it. * ``fuse_session_loop_mt_312()`` no longer destroys ``se->mt_lock`` before ``fuse_session_destroy()`` destroys it again, which was undefined behaviour on every multi-threaded shutdown. * ``fuse_loop_cfg_create()`` returning NULL is checked before the config is dereferenced in ``fuse_session_loop_mt_312()`` and ``fuse_session_loop_mt_31()``. * iconv: the error check after opening the ``fromfs`` descriptor tested ``tofs``, so a failed ``iconv_open()`` was ignored and left an invalid descriptor behind. * mount.fuse: a failure to clear ``FD_CLOEXEC`` went undetected, because the result was compared against 1 rather than -1. * ``grow_pipe_to_max()`` opens ``/proc/sys/fs/pipe-max-size`` with ``O_CLOEXEC``; a concurrent fork+exec leaked the descriptor into the child. * Fixed a build failure for ``FUSE_USE_VERSION`` 312 and newer without symbol versioning, where ``fuse_loop_mt()`` expanded to an undeclared ``fuse_loop_mt_312()``. * Fixed a Clang 21 build failure in ``ST_MTIM_NSEC``. * Fixed leaks: the pipe when its size cannot be grown, the mountpoint in ``fuse_session_mount()`` and ``fuse_session_destroy()``, the pipe descriptors when ``fork()`` or ``setsid()`` fail in ``fuse_daemonize()``, the context when ``pthread_setspecific()`` fails, ``print_module_help()``, and a ``fuse_pollhandle`` in ``fuse_lib_poll()``. * Examples: ``update_fs()`` uses ``localtime_r()``. ``localtime()`` returns a shared static ``struct tm``, so it raced with the session threads and ``strftime()`` could format a half-overwritten time. * Examples: ``cuse_client`` caps the transfer size at 16 MiB. ``do_rw()`` passed the SIZE argument straight to ``calloc()``. * Examples: memfs_ll locking, refcounting and bounds fixes, including a use-after-free on rename overwrite and on a concurrent forget. * Examples: passthrough_hp lock-order and lifetime fixes. The directory stream is protected by a per-handle lock, ``fs.mutex`` is taken before ``Inode::m`` and when ``link()`` raises nlookup, and no inode lock is held across a syscall or a reply. Documentation ------------- * The fuse-devel mailing list moved to lists.linux.dev. * Man page and README corrections. libfuse 3.18.2 (2026-03-18) =========================== * Fix two io-uring issues that might be security critical * fuse-io-uring: Fix UAF and NULL deref in startup error path * fuse-io-uring: Fix NULL deref and memory leak in fuse_uring_init_queue libfuse 3.18.1 (2025-12-20) =========================== * Fix a critical ABI issue compared to libfuse-3.17.3+ * Note: This breaks ABI compatibility to libfuse-3.18.0 (given that 3.18.0 is out for 2 days only, probably the lesser evil) libfuse 3.18.0 (2025-12-18) =========================== New Features ------------ * fuse-over-io-uring communication * statx support * Request timeouts: Prevent hung operations * FUSE_NOTIFY_INC_EPOCH: New notification mechanism for epoch counters Important Fixes ---------------- * Fixed double unmount on FUSE_DESTROY * Fixed junk readdirplus results when filesystem doesn't fill stat info * Fixed memory deallocation in fuse_session_loop_remember * Fixed COPY_FILE_RANGE interface Platform Support ---------------- * Improved FreeBSD support (mount error reporting, test runner, build fixes) * Fixed 32-bit architecture builds * Fixed build with musl libc and older kernels (< 5.9) Other Improvements ------------------ * Added PanFS to fusermount whitelist * Thread naming support for easier debugging libfuse 3.17.4 (2025-08-19) =========================== - Try to detect mount-utils by checking for /run/mount/utab and don't try to update mtab if it does not exist - Fix a build warning when HAVE_BACKTRACE is undefined - fuse_loop_mt.c: fix close-on-exec flag on clone fd - Remove struct size assertions from fuse_common.h libfuse 3.17.3 (2025-07-16) =========================== * more conn->want / conn->want_ext conversion fixes * Fix feature detection for close_range * Avoid double unmount on FUSE_DESTROY libfuse 3.17.2 (2025-04-23) =========================== * Fixed uninitized bufsize value (compilation warning and real issue when HAVE_SPLICE was not defined) * Fixed initialization races related to buffer realocation when large buf sizes are used (/proc/sys/fs/fuse/max_pages_limit) * Fix build with kernel < 5.9 * Fix static_assert build failure with C++ version < 11 * Compilation fix (remove second fuse_main_real_versioned declaration) * Another conn.want flag conversion fix for high-level applications * Check if pthread_setname_np() exists before use it * fix example/memfs_ll rename deadlock error * signal handlers: Store fuse_session unconditionally and restore previous behavior that with multiple sessions the last session was used for the signal exist handler libfuse 3.17.1 (2025-03-24) =========================== * fuse: Fix want conn.want flag conversion * Prevent re-usage of stdio FDs for fusermount * PanFS added to fusermount whitelist libfuse 3.17.1-rc1 (2025-02-18) =============================== * several BSD fixes * x86 (32bit) build fixes * nested declarations moved out of the inlined functions to avoid build warnings * signify public key added for future 3.18 libfuse 3.17.1-rc0 (2025-02.10) =============================== * Fix libfuse build with FUSE_USE_VERSION 30 * Fix build of memfs_ll without manual meson reconfigure * Fix junk readdirplus results when filesystem not filling stat info * Fix conn.want_ext truncation to 32bit * Fix some build warnings with -Og * Fix fuse_main_real symbols * Several changes related to functions/symbols that added in the libfuse version in 3.17 * Add thread names to libfuse threads * With auto-umounts the FUSE_COMMFD2 (parent process fd is exported to be able to silence leak checkers libfuse 3.17 (2025-01-01, not officially releaesed) ================================================== * 3.11 and 3.14.2 introduced ABI incompatibilities, the ABI is restored to 3.10, .so version was increased since there were releases with the incompatible ABI * The libfuse version a program was compiled against is now encoded into that program, using inlined functions in fuse_lowlevel.h and fuse.h * Allows to handle fatal signals and to print a backtrace. New API function: fuse_set_fail_signal_handlers() * Allows fuse_log() messages to be send to syslog instead of stderr New API functions: fuse_log_enable_syslog() and fuse_log_close_syslog() * Handle buffer misalignment for FUSE_WRITE * Added support for filesystem passthrough read/write of files when FUSE_PASSTHROUGH capability is enabled New API functions: fuse_passthrough_open() and fuse_passthrough_close(), also see example/passthrough_hp.cc * Added fmask and dmask options to high-level API - dmask: umask applied to directories - fmask: umask applied to non-directories * Added FUSE_FILL_DIR_DEFAULTS enum to support C++ programs using fuse_fill_dir_t function * Added support for FUSE_CAP_HANDLE_KILLPRIV_V2 Fixes: * Fixed compilation failure on FreeBSD (mount_bsd.c now points to correct header) libfuse 3.16.2 (2023-10-10) =========================== * Various small fixes and improvements. libfuse 3.16.1 (2023-08-08) =========================== * Readdir kernel cache can be enabled from high-level API. libfuse 3.15.1 (2023-07-05) =========================== Future libfuse releases will be signed with `signify`_ rather than PGP (rationale_). This release is the last to be signed with PGP and contains the signify public key for current (3.15.X) and upcoming (3.16.X) minor release cycle. .. _signify: https://www.openbsd.org/papers/bsdcan-signify.html .. _rationale: https://latacora.micro.blog/2019/07/16/the-pgp-problem.html libfuse 3.15.0 (2023-06-09) =========================== * Improved support for some less common systems (32 bit, alternative libcs) * Unsupported mount options are no longer silently accepted. * auto_unmount is now compatible with allow_other. libfuse 3.14.1 (2023-03-26) =========================== * The extended attribute name passed to the setxattr() handler is no longer truncated at the beginning (bug introduced in 3.13.0). * As a result of the above, the additional setattr() flags introduced in 3.14 are no longer available for now. They will hopefully be reintroduced in the next release. * Further improvements of configuration header handling. libfuse 3.14.0 (2023-02-17) =========================== * Properly fix the header installation issue. The fix in 3.13.1 resulted in conflicts with other packages. * Introduce additional setattr() flags (FORCE, KILL_SUID, KILL_SGID, FILE, KILL_PRIV, OPEN, TIMES_SET) libfuse 3.13.1 (2023-02-03) =========================== * Fixed an issue that resulted in errors when attempting to compile against installed libfuse headers (because libc symbol versioning support was not detected correctly in this case). libfuse 3.13.0 (2023-01-13) =========================== * There is a new low-level API function `fuse_session_custom_io` that allows to implement a daemon with a custom io. This can be used to create a daemon that can process incoming FUSE requests to other destinations than `/dev/fuse`. * A segfault when loading custom FUSE modules has been fixed. * There is a new `fuse_notify_expire_entry` function. * A deadlock when resolving paths in the high-level API has been fixed. * libfuse can now be build explicitly for C libraries without symbol versioning support. libfuse 3.12.0 (2022-09-08) =========================== * There is a new build parameter to specify where the SysV init script should be installed. * The *max_idle_threads* parameter has been deprecated in favor of the new max_threads* parameter (which avoids the excessive overhead of creating and destructing threads). Using max_threads == 1 and calling fuse_session_loop_mt() will run single threaded similar to fuse_session_loop(). The following changes apply when using the most recent API (-DFUSE_USE_VERSION=312, see `example/passthrough_hp.cc` for an example for how to usse the new API): * `struct fuse_loop_config` is now private and has to be constructed using *fuse_loop_cfg_create()* and destroyed with *fuse_loop_cfg_destroy()*. Parameters can be changed using `fuse_loop_cfg_set_*()` functions. * *fuse_session_loop_mt()* now accepts `struct fuse_loop_config *` as NULL pointer. * *fuse_parse_cmdline()* now accepts a *max_threads* option. libfuse 3.11.0 (2022-05-02) =========================== * Add support for flag FOPEN_NOFLUSH for avoiding flush on close. * Fixed returning an error condition to ioctl(2) libfuse 3.10.5 (2021-09-06) =========================== * Various improvements to make unit tests more robust. libfuse 3.10.4 (2021-06-09) =========================== * Building of unit tests is now optional. * Fixed a test failure when running tests under XFS. * Fixed memory leaks in examples. * Minor documentation fixes. libfuse 3.10.3 (2021-04-12) =========================== * Fix returning d_ino and d_type from readdir(3) in non-plus mode libfuse 3.10.2 (2021-02-05) =========================== * Allow "nonempty" as a mount option, for backwards compatibility with fusermount 2. The option has no effect since mounting over non-empty directories is allowed by default. * Fix returning inode numbers from readdir() in offset==0 mode. * FUSE filesystems can now be mounted underneath EXFAT mountpoints. * Various minor bugfixes. libfuse 3.10.1 (2020-12-07) =========================== * Various minor bugfixes. libfuse 3.10.0 (2020-10-09) =========================== * Add FUSE_CAP_CACHE_SYMLINKS: allow caching symlinks in kernel page cache. * Various minor bugfixes and improvements. libfuse 3.9.4 (2020-08-09) ========================== This was an "accidental" release, it is equivalent to 3.9.3. libfuse 3.9.3 (2020-08-09) ========================== * Fixed compilation under OS X and µClibc. * Minor bugfixes and doc updates. libfuse 3.9.2 (2020-06-12) ========================== * Remove obsolete workarounds in examples. * Do not require C++ compiler for building. * Minor bugfixes. libfuse 3.9.1 (2020-03-19) =========================== * Fixed memory leak in fuse_session_new(). * Fixed an issue with the linker version script. * Make ioctl prototype conditional on FUSE_USE_VERSION. Define FUSE_USE_VERSION < 35 to get old ioctl prototype with int commands; define FUSE_USE_VERSION >= 35 to get new ioctl prototype with unsigned int commands. * Various small bugfixes. libfuse 3.9.0 (2019-12-14) ========================== * Added support for FUSE_EXPLICIT_INVAL_DATA to enable only invalidate cached pages on explicit request. libfuse 3.8.0 (2019-11-03) ========================== * Added support for FUSE_LSEEK operation which can be used to report holes in sparse files. libfuse 3.7.0 (2019-09-27) ========================== * Added UFSD to whitelist (so users can now mount FUSE filesystems on mountpoints within UFSD filesystems). * Added custom log message handler function support so that libfuse applications can direct messages to syslog(3) or other logging systems. stderr remains the default. See `fuse_log.h` for the new API. libfuse 3.6.2 (2019-07-09) ========================== * The init script is now installed to /etc/ rather than /usr/local/etc by default. libfuse 3.6.1 (2019-06-13) ========================== * Fixed version number (release 3.6.0 was shipped with a declared version of 3.0.0). libfuse 3.6.0 (2019-06-13) ========================== * Added a new example (passthrough_hp). The functionality is similar to passthrough_ll, but the implementation focuses on performance and correctness rather than simplicity. * Added support for fuse kernel feature `max_pages` which allows to increase the maximum number of pages that can be used per request. This feature was introduced in kernel 4.20. `max_pages` is set based on the value in `max_write`. By default `max_write` will be 1MiB now for kernels that support `max_pages`. If you want smaller buffers or writes you have to set `max_write` manually. libfuse 3.5.0 (2019-04-16) ========================== * Changed ioctl commands to "unsigned int" in order to support commands which do not fit into a signed int. Commands issued by applications are still truncated to 32 bits. * Added SMB2 to whitelist (so users can now mount FUSE filesystems on mountpoints within SMB 2.0 filesystems). * Added a new `cache_readdir` flag to `fuse_file_info` to enable caching of readdir results. Supported by kernels 4.20 and newer. * Add support and documentation for FUSE_CAP_NO_OPENDIR_SUPPORT. libfuse 3.4.2 (2019-03-09) ========================== * Fixed a memory leak in `examples/passthrough_ll.c`. * Added OpenAFS to whitelist (so users can now mount FUSE filesystems on mountpoints within OpenAFS filesystems). * Added HFS+ to whitelist (so users can now mount FUSE filesystems on mountpoints within HFS+ filesystems). * Documentation improvements. libfuse 3.4.1 (2018-12-22) ========================== * The `examples/passthrough_ll.c` example filesystem has been significantly extended. * Support for `copy_file_range` has been added. * Build system updates for non-Linux systems. libfuse 3.4.0 ============= * Add `copy_file_range()` to support efficient copying of data from one file to an other. libfuse 3.3.0 (2018-11-06) ========================== * The `auto_unmount` mode now works correctly in combination with autofs. * The FUSE_CAP_READDIRPLUS_AUTO capability is no longer enabled by default unless the file system defines both a readdir() and a readdirplus() handler. * The description of the FUSE_CAP_READDIRPLUS_AUTO flag has been improved. * Allow open `/dev/fuse` file descriptors to be passed via mountpoints of the special format `/dev/fd/%u`. This allows mounting to be handled by the parent so the FUSE filesystem process can run fully unprivileged. * Add a `drop_privileges` option to mount.fuse3 which causes it to open `/dev/fuse` and mount the file system itself, then run the FUSE file filesystem fully unprivileged and unable to re-acquire privilege via setuid, fscaps, etc. * Documented under which conditions the `fuse_lowlevel_notify_*` functions may block. libfuse 3.2.6 (2018-08-31) ========================== * The fuse_main() function now returns more fine-grained error codes. * FUSE filesystems may now be mounted on mountpoint within bcachefs, aufs and FAT filesystems. * libfuse may now be used as a Meson subproject. * Fix a few low-impact memory leaks. * The `fuse.conf` file is no longer looked for in `/etc`, but in the *sysconfdir* directory (which can be set with `meson configure`). By default, the location is thus `/usr/local/etc/fuse.conf`. libfuse 3.2.5 (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). * 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. * 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`. libfuse 3.2.4 (2018-07-11) ========================== * Fixed `rename` deadlock on FreeBSD. libfuse 3.2.3 (2018-05-11) ========================== * Fixed a number of compiler warnings. libfuse 3.2.2 (2018-03-31) ========================== * Added example fuse.conf file. * Added "support" for -o nofail mount option (the option is accepted and ignored). * Various small bugfixes. libfuse 3.2.1 (2017-11-14) ========================== * Various small bugfixes. libfuse 3.2.0 (2017-09-12) ========================== * Support for building with autotools has been dropped. * Added new `fuse_invalidate_path()` routine for cache invalidation from the high-level FUSE API, along with an example and tests. * There's a new `printcap` example that can be used to determine the capabilities of the running kernel. * `fuse_loop_mt()` now returns the minus the actual errno if there was an error (instead of just -1). * `fuse_loop()` no longer returns a positive value if the filesystem loop was terminated without errors or signals. * Improved documentation of `fuse_lowlevel_notify_*` functions. * `fuse_lowlevel_notify_inval_inode()` and `fuse_lowlevel_notify_inval_entry()` now return -ENOSYS instead of an undefined error if the function is not supported by the kernel. * Documented the special meaning of the *zero* offset for the fuse_fill_dir_t function. * The `passthrough_fh` example now works under FreeBSD. * libfuse can now be build without libiconv. * Fixed support for `FUSE_CAP_POSIX_ACL`: setting this capability flag had no effect in the previous versions of libfuse 3.x; now ACLs should actually work. * Fixed a number of compilation problems under FreeBSD. * Fixed installation directory for udev rules. * Fixed compilation with LTO. libfuse 3.1.1 (2017-08-06) ========================== * Documentation: clarified how filesystems are supposed to process open() and create() flags (see include/fuse_lowlevel.h). * Fixed a compilation problem of the passthrough_ll example on 32 bit systems (wrong check and wrong error message). * pkg-config is now used to determine the proper directory for udev rules. * Fixed a symbol versioning problem that resulted in very strange failures (segfaults, unexpected behavior) in different situations. * Fixed a test failure when /tmp is on btrfs. * The maximum number of idle worker threads used by `fuse_loop_mt()` is now configurable. * `fuse_loop_mt()` and `fuse_session_loop_mt()` now take a `struct fuse_loop_config` parameter that supersedes the *clone_fd* parameter. * Incorporated several patches from the FreeBSD port. libfuse should now compile under FreeBSD without the need for patches. * The passthrough_ll example now supports writeback caching. libfuse 3.1.0 (2017-07-08) ========================== * Added new `fuse_lib_help()` function. File-systems that previously passed a ``--help`` option to `fuse_new()` must now process the ``--help`` option internally and call `fuse_lib_help()` to print the help for generic FUSE options. * Fixed description of the `fuse_conn_info->time_gran`. The default value of zero actually corresponds to full nanosecond resolution, not one second resolution. * The init script is now installed into the right location (``$DESTDIR/etc/init.d`` rather than ``$prefix/$sysconfdir/init.d``) * The `example/passthrough_ll` filesystem now supports creating and writing to files. * `fuse_main()` / `fuse_remove_signal_handlers()`: do not reset `SIGPIPE` handler to `SIG_DFL` if it was not set by us. * Documented the `RENAME_EXCHANGE` and `RENAME_NOREPLACE` flags that may be passed to the `rename` handler of both the high- and low-level API. Filesystem authors are strongly encouraged to check that these flags are handled correctly. libfuse 3.0.2 (2017-05-24) ========================== * Option parsing for the high-level API now works correctly (previously, default values would override specified values). * Tests should now build (and run) under FreeBSD. * Improved documentation of `struct fuse_context` * Internal: calculate request buffer size from page size and kernel page limit instead of using hardcoded 128 kB limit. libfuse 3.0.1 (2017-04-10) ========================== * Re-introduced *examples/null.c*. * Added experimental support for building with Meson. * Document that `-o auto_unmount` implies `-o nodev,nosuid`. * Document that the *use_ino* option of the high-level interface does not affect the inode that libfuse and the kernel use internally. * Fixed test cases for passthrough* examples (they weren't actually testing the examples). * Fixed several bugs in the passthrough* examples. libfuse 3.0.0 (2016-12-08) ========================== * NOTE TO PACKAGERS: libfuse 3 is designed to be co-installable with libfuse 2. However, some files will be installed by both libfuse 2 and libfuse 3 (e.g. /etc/fuse.conf, the udev and init scripts, and the mount.fuse(8) manpage). These files should be taken from libfuse 3. The format/content is guaranteed to remain backwards compatible with libfuse 2. We recommend to ship libfuse2 and libfuse3 in three separate packages: a libfuse-common package that contains files shared by libfuse 2+3 (taken from the libfuse3 tarball), and libfuse2 and libfuse3 packages that contain the shared library and helper programs for the respective version. * Fixed test errors when running tests as root. * Made check for util-linux version more robust. * Added documentation for all fuse capability flags (`FUSE_CAP_*`) and `struct fuse_conn_info` fields. * fuse_loop(), fuse_loop_mt(), fuse_session_loop() and fuse_session_loop_mt() now return more detailed error codes instead of just -1. See the documentation of fuse_session_loop() for details. * The FUSE main loop is now aborted if the file-system requests capabilities that are not supported by the kernel. In this case, the session loop is exited with a return code of ``-EPROTO``. * Most file-system capabilities that were opt-in in libfuse2 are now enabled by default. Filesystem developers are encouraged to review the documentation of the FUSE_CAP_* features to ensure that their filesystem is compatible with the new semantics. As before, a particular capability can still be disabled by unsetting the corresponding bit of `fuse_conn_info.wants` in the init() handler. * Added FUSE_CAP_PARALLEL_DIROPS and FUSE_CAP_POSIX_ACL, FUSE_HANDLE_KILLPRIV feature flags. * FUSE filesystems are now responsible for unsetting the setuid/setgid flags when a file is written, truncated, or its owner changed. Previously, this was handled by the kernel but subject to race conditions. * The fusermount and mount.fuse binaries have been renamed to fusermount3 and mount.fuse3 to allow co-installation of libfuse 2.x and 3.x * Added a `max_read` field to `struct fuse_conn_info`. For the time being, the maximum size of read requests has to be specified both there *and* passed to fuse_session_new() using the ``-o max_read=`` mount option. At some point in the future, specifying the mount option will no longer be necessary. * Documentation: clarified that the fuse_argv structure that is passed to `fuse_new()` and `fuse_lowlevel_new()` must always contain at least one element. * The high-level init() handler now receives an additional struct fuse_config pointer that can be used to adjust high-level API specific configuration options. * The `nopath_flag` field of struct fuse_operations has been removed. Instead, a new `nullpath_ok` flag can now be set in struct fuse_config. * File systems that use the low-level API and support lookup requests for '.' and '..' should continue make sure to set the FUSE_CAP_EXPORT_SUPPORT bit in fuse_conn_info->want. (This has actually always been the case, but was not very obvious from the documentation). * The help text generated by fuse_lowlevel_help(), fuse_new() (and indirectly fuse_main()) no longer includes options that are unlikely to be of interest to end-users. The full list of accepted options is now included in the respective function's documentation (located in the fuse.h/fuse_lowlevel.h and doc/html). * The ``-o nopath`` option has been dropped - it never actually did anything (since it is unconditionally overwritten with the value of the `nopath` flag in `struct fuse_operations`). * The ``-o large_read`` mount option has been dropped. Hopefully no one uses a Linux 2.4 kernel anymore. * The `-o nonempty` mount point has been removed, mounting over non-empty directories is now always allowed. This brings the behavior of FUSE file systems in-line with the behavior of the regular `mount` command. File systems that do not want to allow mounting to non-empty directories should perform this check themselves before handing control to libfuse. * The chmod, chown, truncate, utimens and getattr handlers of the high-level API now all receive an additional struct fuse_file_info pointer (which, however, may be NULL even if the file is currently open). The fgetattr and ftruncate handlers have become obsolete and have been removed. * The `fuse_session_new` function no longer accepts the ``-o clone_fd`` option. Instead, this has become a parameter of the `fuse_session_loop_mt` and `fuse_loop_mt` functions. * For low-level file systems that implement the `write_buf` handler, the `splice_read` option is now enabled by default. As usual, this can be changed in the file system's `init` handler. * The treatment of low-level options has been made more consistent: Options that can be set in the init() handler (via the fuse_conn_info parameter) can now be set only here, i.e. fuse_session_new() no longer accepts arguments that change the fuse_conn_info object before or after the call do init(). As a side effect, this removes the ambiguity where some options can be overwritten by init(), while others overwrite the choices made by init(). For file systems that wish to offer command line options for these settings, the new fuse_parse_conn_info_opts() and fuse_apply_conn_info_opts() functions are available. Consequently, the fuse_lowlevel_help() method has been dropped. * The `async_read` field in `struct fuse_conn_info` has been removed. To determine if the kernel supports asynchronous reads, file systems should check the `FUSE_CAP_ASYNC_READ` bit of the `capable` field. To enable/disable asynchronous reads, file systems should set the flag in the `wanted` field. * The `fuse_parse_cmdline` function no longer prints out help when the ``--verbose`` or ``--help`` flags are given. This needs to be done by the file system (e.g. using the `fuse_cmdline_help()` and `fuse_lowlevel_help()` functions). * Added ``example/cuse_client.c`` to test ``example/cuse.c``. * Removed ``example/null.c``. This has not been working for a while for unknown reasons -- maybe because it tries to treat the mountpoint as a file rather than a directory? * There are several new examples that demonstrate the use of the ``fuse_lowlevel_notify_*`` functions: - ``example/notify_store_retrieve.c`` - ``example/notify_inval_inode.c`` - ``example/notify_inval_entry.c`` * The ``-o big_writes`` mount option has been removed. It is now always active. File systems that want to limit the size of write requests should use the ``-o max_write=`` option instead. * The `fuse_lowlevel_new` function has been renamed to `fuse_session_new` and no longer interprets the --version or --help options. To print help or version information, use the new `fuse_lowlevel_help` and `fuse_lowlevel_version` functions. * The ``allow_other`` and ``allow_root`` mount options (accepted by `fuse_session_new()`) may now be specified together. In this case, ``allow_root`` takes precedence. * There are new `fuse_session_unmount` and `fuse_session_mount` functions that should be used in the low-level API. The `fuse_mount` and `fuse_unmount` functions should be used with the high-level API only. * Neither `fuse_mount` nor `fuse_session_mount` take struct fuse_opts parameters anymore. Mount options are parsed by `fuse_new` (for the high-level API) and `fuse_session_new` (for the low-level API) instead. To print help or version information, use the new `fuse_mount_help` and `fuse_mount_version` functions. * The ``fuse_lowlevel_notify_*`` functions now all take a `struct fuse_session` parameter instead of a `struct fuse_chan`. * The channel interface (``fuse_chan_*`` functions) has been made private. As a result, the typical initialization sequence of a low-level file system has changed from :: ch = fuse_mount(mountpoint, &args); se = fuse_lowlevel_new(&args, &lo_oper, sizeof(lo_oper), &lo); fuse_set_signal_handlers(se); fuse_session_add_chan(se, ch); fuse_daemonize(fg); if (mt) fuse_session_loop_mt(se); else fuse_session_loop(se); fuse_remove_signal_handlers(se); fuse_session_remove_chan(ch); fuse_session_destroy(se); fuse_unmount(mountpoint, ch); to :: se = fuse_session_new(&args, &ll_ops, sizeof(ll_ops), NULL); fuse_set_signal_handlers(se); fuse_session_mount(se, mountpoint); fuse_daemonize(fg); if (mt) fuse_session_loop_mt(se); else fuse_session_loop(se); fuse_remove_signal_handlers(se); fuse_session_unmount(se); fuse_lowlevel_destroy(se); The typical high-level setup has changed from :: ch = fuse_mount(*mountpoint, &args); fuse = fuse_new(ch, &args, op, op_size, user_data); se = fuse_get_session(fuse); fuse_set_signal_handlers(se); fuse_daemonize(fg); if (mt) fuse_loop_mt(fuse); else fuse_loop(fuse); fuse_remove_signal_handlers(se); fuse_unmount(mountpoint, ch); fuse_destroy(fuse); to :: fuse = fuse_new(&args, op, op_size, user_data); se = fuse_get_session(fuse); fuse_set_signal_handlers(se); fuse_mount(fuse, mountpoint); fuse_daemonize(fg); if (mt) fuse_loop_mt(fuse); else fuse_loop(fuse); fuse_remove_signal_handlers(se); fuse_unmount(fuse); fuse_destroy(fuse); File systems that use `fuse_main` are not affected by this change. For integration with custom event loops, the new `fuse_session_fd` function provides the file descriptor that's used for communication with the kernel. * Added *clone_fd* option. This creates a separate device file descriptor for each processing thread, which might improve performance. * Added *writeback_cache* option. With kernel 3.14 and newer this enables write-back caching which can significantly improve performance. * Added *async_dio* option. With kernel 3.13 and newer, this allows direct I/O to be done asynchronously. * The (high- and low-level) `rename` handlers now takes a *flags* parameter (with values corresponding to the *renameat2* system call introduced in Linux 3.15). * The "ulockmgr_server" has been dropped. * There is a new (low-level) `readdirplus` handler, with a corresponding example in ``examples/fuse_lo-plus.c`` and a new `fuse_add_direntry_plus` API function. * The (high-level) `readdir` handler now takes a *flags* argument. * The (high-level) `filler` function passed to `readdir` now takes an additional *flags* argument. * The (high-level) `getdir` handler has been dropped. * The *flag_nullpath_ok* and *flag_utime_omit_ok* flags have been dropped. * The (high-level) *utime* handler has been dropped. * The `fuse_invalidate` function has been removed. * The `fuse_is_lib_option` function has been removed. * The *fh_old* member of `struct fuse_file_info` has been dropped. * The type of the *writepage* member of `struct fuse_file_info` was changed from *int* to *unsigned int*. * The `struct fuse_file_info` gained a new *poll_events* member. * There is a new `fuse_pkgversion` function. * The *fuse_off_t* and *fuse_ino_t* changed from *unsigned long* to *uint64_t*, i.e. they are now 64 bits also on 32-bit systems. * The type of the *generation* member of `struct fuse_entry_param*` changed from *unsigned* to *uint64_t*. * The (low-level) `setattr` handler gained a *FUSE_SET_ATTR_CTIME* bit *for its *to_set* parameter. * The `struct fuse_session_ops` data structure has been dropped. * The documentation has been clarified and improved in many places. 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. * Initialize 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) ================================== Please see Git history, e.g. at https://github.com/libfuse/libfuse/blob/fuse_2_9_3/ChangeLog. fuse-3.18.3/GPL2.txt0000644000175000017500000004325415250106036012771 0ustar berndbernd 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-3.18.3/LGPL2.txt0000644000175000017500000006364215250106036013110 0ustar berndbernd GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, 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 and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, 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 library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete 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 distribute a copy of this License along with the Library. 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 Library or any portion of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, 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 Library, 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 Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you 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. If distribution of 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 satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be 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. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library 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. 9. 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 Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library 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 with this License. 11. 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 Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library 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 Library. 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. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library 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. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library 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 Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, 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 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. 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 LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. 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 library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; 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. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! fuse-3.18.3/LICENSE0000644000175000017500000000066315250106036012526 0ustar berndberndThe following files may be used under the terms of the GNU Lesser General Public License, version 2.1 ("LGPL"): - All files in the include/ directory. - All files in the lib/ directory. - meson.build The full terms of the LGPL can be found in the LGPL2.txt file. All other files may be used only under the terms of the GNU General Public License, version 2 ("GPL"). The full text of this license can be found in the GPL2.txt file. fuse-3.18.3/README.md0000644000175000017500000001477315250106036013007 0ustar berndberndlibfuse ======= 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. Development Status ------------------ libfuse is shipped by all major Linux distributions and has been in production use across a wide range of systems for many years. However, at present libfuse does not have any active, regular contributors. The current maintainer continues to apply pull requests and makes regular releases, but unfortunately has no capacity to do any development beyond addressing high-impact issues. When reporting bugs, please understand that unless you are including a pull request or are reporting a critical issue, you will probably not get a response. If you are using libfuse, please consider contributing to the project. Supported Platforms ------------------- * Linux (fully) * BSD (mostly/best-effort) * For OS-X, please use [OSXFUSE](https://osxfuse.github.io/) Installation ------------ You can download libfuse from https://github.com/libfuse/libfuse/releases. To build and install, you must use [Meson](http://mesonbuild.com/) and [Ninja](https://ninja-build.org). After downloading the tarball and `.sig` file, verify it using [signify](https://www.openbsd.org/papers/bsdcan-signify.html): signify -V -m fuse-X.Y.Z.tar.gz -p fuse-X.Y.pub The `fuse-X.Y.pub` file contains the signing key and needs to be obtained from a trustworthy source. Each libfuse release contains the signing key for the release after it in the `signify` directory, so you only need to manually acquire this file once when you install libfuse for the first time. After you have validated the tarball, extract it, create a (temporary) build directory and run Meson: $ tar xzf fuse-X.Y.Z.tar.gz; cd fuse-X.Y.Z $ mkdir build; cd build $ meson setup .. Normally, the default build options will work fine. If you nevertheless want to adjust them, you can do so with the *meson configure* command: $ meson configure # list options $ meson configure -D disable-mtab=true # set an option $ # ensure all meson options are applied to the final build system $ meson setup --reconfigure ../ To build, test, and install libfuse, you then use Ninja: $ ninja $ sudo ../test/run-tests.py --build-dir . $ sudo ninja install Running the tests requires bash, Python 3 and (to resolve core dumps) gdb. Instead of running the tests as root, the majority of tests can also be run as a regular user if *util/fusermount3* is made setuid root first; the rest then skip themselves: $ ../test/run-tests.py --build-dir . --setuid-helpers Each test gets its own working and log directory, and the runner prints what every one of them cost. See the README under *test/cases* for how to add one and where to look when one fails. Security implications --------------------- The *fusermount3* program is installed setuid root. This is done to allow normal users to mount their own filesystem implementations. To limit the harm that malicious users can do this way, *fusermount3* enforces the following limitations: - The user can only mount on a mountpoint for which they have write permission - The mountpoint must not be 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 */etc/fuse.conf*) If you intend to use the *allow_other* mount options, be aware that FUSE has an unresolved [security bug](https://github.com/libfuse/libfuse/issues/15): if the *default_permissions* mount option is not used, the results of the first permission check performed by the file system for a directory entry will be re-used for subsequent accesses as long as the inode of the accessed entry is present in the kernel cache - even if the permissions have since changed, and even if the subsequent access is made by a different user. This is of little concern if the filesystem is accessible only to the mounting user (which has full access to the filesystem anyway), but becomes a security issue when other users are allowed to access the filesystem (since they can exploit this to perform operations on the filesystem that they do not actually have permissions for). 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 use `default_permissions` (which does not currently support ACLs), or to completely disable caching of directory entry attributes. Building your own filesystem ------------------------------ FUSE comes with several example file systems in the `example` directory. For example, the *passthrough* examples mirror 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 by mailing , archive at https://lore.kernel.org/fuse-devel/). Please report any bugs on the GitHub issue tracker at https://github.com/libfuse/libfuse/issues. fuse-3.18.3/SECURITY.md0000644000175000017500000000155615250106036013314 0ustar berndbernd# Security Policy If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives me time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. Please submit information on the vulnerability as a [private report](https://github.com/libfuse/libfuse/security/advisories/new). Please provide the following information in your report: - A description of the vulnerability and its impact - How to reproduce the issue This project is maintained by a single volunteer on a reasonable-effort basis. As such, I ask that you give me 90 days to work on a fix before public exposure. Note we are aware of a long-standing security issue when using `allow_others` (see [#15](https://github.com/libfuse/libfuse/issues/15)).fuse-3.18.3/checkpatch.pl0000755000175000017500000073340315250106036014163 0ustar berndbernd#!/usr/bin/env perl # SPDX-License-Identifier: GPL-2.0 # # (c) 2001, Dave Jones. (the file handling bit) # (c) 2005, Joel Schopp (the ugly bit) # (c) 2007,2008, Andy Whitcroft (new conditions, test suite) # (c) 2008-2010 Andy Whitcroft # (c) 2010-2018 Joe Perches use strict; use warnings; use POSIX; use File::Basename; use Cwd 'abs_path'; use Term::ANSIColor qw(:constants); use Encode qw(decode encode); my $P = $0; my $D = dirname(abs_path($P)); my $V = '0.32'; use Getopt::Long qw(:config no_auto_abbrev); my $quiet = 0; my $verbose = 0; my %verbose_messages = (); my %verbose_emitted = (); my $tree = 1; my $chk_signoff = 1; my $chk_fixes_tag = 1; my $chk_patch = 1; my $tst_only; my $emacs = 0; my $terse = 0; my $showfile = 0; my $file = 0; my $git = 0; my %git_commits = (); my $check = 0; my $check_orig = 0; my $summary = 1; my $mailback = 0; my $summary_file = 0; my $show_types = 0; my $list_types = 0; my $fix = 0; my $fix_inplace = 0; my $root; my $gitroot = $ENV{'GIT_DIR'}; $gitroot = ".git" if !defined($gitroot); my %debug; my %camelcase = (); my %use_type = (); my @use = (); my %ignore_type = (); my @ignore = (); my $help = 0; my $configuration_file = ".checkpatch.conf"; my $max_line_length = 100; my $ignore_perl_version = 0; my $minimum_perl_version = 5.10.0; my $min_conf_desc_length = 4; my $spelling_file = "$D/spelling.txt"; my $codespell = 0; my $codespellfile = "/usr/share/codespell/dictionary.txt"; my $user_codespellfile = ""; my $conststructsfile = "$D/const_structs.checkpatch"; my $docsfile = "$D/../Documentation/dev-tools/checkpatch.rst"; my $typedefsfile; my $color = "auto"; my $allow_c99_comments = 1; # Can be overridden by --ignore C99_COMMENT_TOLERANCE # git output parsing needs US English output, so first set backtick child process LANGUAGE my $git_command ='export LANGUAGE=en_US.UTF-8; git'; my $tabsize = 8; my ${CONFIG_} = "CONFIG_"; my %maybe_linker_symbol; # for externs in c exceptions, when seen in *vmlinux.lds.h sub help { my ($exitcode) = @_; print << "EOM"; Usage: $P [OPTION]... [FILE]... Version: $V Options: -q, --quiet quiet -v, --verbose verbose mode --no-tree run without a kernel tree --no-signoff do not check for 'Signed-off-by' line --no-fixes-tag do not check for 'Fixes:' tag --patch treat FILE as patchfile (default) --emacs emacs compile window format --terse one line per report --showfile emit diffed file position, not input file position -g, --git treat FILE as a single commit or git revision range single git commit with: ^ ~n multiple git commits with: .. ... - git merges are ignored -f, --file treat FILE as regular source file --subjective, --strict enable more subjective tests --list-types list the possible message types --types TYPE(,TYPE2...) show only these comma separated message types --ignore TYPE(,TYPE2...) ignore various comma separated message types --show-types show the specific message type in the output --max-line-length=n set the maximum line length, (default $max_line_length) if exceeded, warn on patches requires --strict for use with --file --min-conf-desc-length=n set the minimum description length for config symbols in lines, if shorter, warn (default $min_conf_desc_length) --tab-size=n set the number of spaces for tab (default $tabsize) --root=PATH PATH to the kernel tree root --no-summary suppress the per-file summary --mailback only produce a report in case of warnings/errors --summary-file include the filename in summary --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of 'values', 'possible', 'type', and 'attr' (default is all off) --test-only=WORD report only warnings/errors containing WORD literally --fix EXPERIMENTAL - may create horrible results If correctable single-line errors exist, create ".EXPERIMENTAL-checkpatch-fixes" with potential errors corrected to the preferred checkpatch style --fix-inplace EXPERIMENTAL - may create horrible results Is the same as --fix, but overwrites the input file. It's your fault if there's no backup or git --ignore-perl-version override checking of perl version. expect runtime errors. --codespell Use the codespell dictionary for spelling/typos (default:$codespellfile) --codespellfile Use this codespell dictionary --typedefsfile Read additional types from this file --color[=WHEN] Use colors 'always', 'never', or only when output is a terminal ('auto'). Default is 'auto'. --kconfig-prefix=WORD use WORD as a prefix for Kconfig symbols (default ${CONFIG_}) -h, --help, --version display this help and exit When FILE is - read standard input. EOM exit($exitcode); } my $DO_WHILE_0_ADVICE = q{ do {} while (0) advice is over-stated in a few situations: The more obvious case is macros, like MODULE_PARM_DESC, invoked at file-scope, where C disallows code (it must be in functions). See $exceptions if you have one to add by name. More troublesome is declarative macros used at top of new scope, like DECLARE_PER_CPU. These might just compile with a do-while-0 wrapper, but would be incorrect. Most of these are handled by detecting struct,union,etc declaration primitives in $exceptions. Theres also macros called inside an if (block), which "return" an expression. These cannot do-while, and need a ({}) wrapper. Enjoy this qualification while we work to improve our heuristics. }; sub uniq { my %seen; return grep { !$seen{$_}++ } @_; } sub list_types { my ($exitcode) = @_; my $count = 0; local $/ = undef; open(my $script, '<', abs_path($P)) or die "$P: Can't read '$P' $!\n"; my $text = <$script>; close($script); my %types = (); # Also catch when type or level is passed through a variable while ($text =~ /(?:(\bCHK|\bWARN|\bERROR|&\{\$msg_level})\s*\(|\$msg_type\s*=)\s*"([^"]+)"/g) { if (defined($1)) { if (exists($types{$2})) { $types{$2} .= ",$1" if ($types{$2} ne $1); } else { $types{$2} = $1; } } else { $types{$2} = "UNDETERMINED"; } } print("#\tMessage type\n\n"); if ($color) { print(" ( Color coding: "); print(RED . "ERROR" . RESET); print(" | "); print(YELLOW . "WARNING" . RESET); print(" | "); print(GREEN . "CHECK" . RESET); print(" | "); print("Multiple levels / Undetermined"); print(" )\n\n"); } foreach my $type (sort keys %types) { my $orig_type = $type; if ($color) { my $level = $types{$type}; if ($level eq "ERROR") { $type = RED . $type . RESET; } elsif ($level eq "WARN") { $type = YELLOW . $type . RESET; } elsif ($level eq "CHK") { $type = GREEN . $type . RESET; } } print(++$count . "\t" . $type . "\n"); if ($verbose && exists($verbose_messages{$orig_type})) { my $message = $verbose_messages{$orig_type}; $message =~ s/\n/\n\t/g; print("\t" . $message . "\n\n"); } } exit($exitcode); } my $conf = which_conf($configuration_file); if (-f $conf) { my @conf_args; open(my $conffile, '<', "$conf") or warn "$P: Can't find a readable $configuration_file file $!\n"; while (<$conffile>) { my $line = $_; $line =~ s/\s*\n?$//g; $line =~ s/^\s*//g; $line =~ s/\s+/ /g; next if ($line =~ m/^\s*#/); next if ($line =~ m/^\s*$/); my @words = split(" ", $line); foreach my $word (@words) { last if ($word =~ m/^#/); push (@conf_args, $word); } } close($conffile); unshift(@ARGV, @conf_args) if @conf_args; } sub load_docs { open(my $docs, '<', "$docsfile") or warn "$P: Can't read the documentation file $docsfile $!\n"; my $type = ''; my $desc = ''; my $in_desc = 0; while (<$docs>) { chomp; my $line = $_; $line =~ s/\s+$//; if ($line =~ /^\s*\*\*(.+)\*\*$/) { if ($desc ne '') { $verbose_messages{$type} = trim($desc); } $type = $1; $desc = ''; $in_desc = 1; } elsif ($in_desc) { if ($line =~ /^(?:\s{4,}|$)/) { $line =~ s/^\s{4}//; $desc .= $line; $desc .= "\n"; } else { $verbose_messages{$type} = trim($desc); $type = ''; $desc = ''; $in_desc = 0; } } } if ($desc ne '') { $verbose_messages{$type} = trim($desc); } close($docs); } # Perl's Getopt::Long allows options to take optional arguments after a space. # Prevent --color by itself from consuming other arguments foreach (@ARGV) { if ($_ eq "--color" || $_ eq "-color") { $_ = "--color=$color"; } } GetOptions( 'q|quiet+' => \$quiet, 'v|verbose!' => \$verbose, 'tree!' => \$tree, 'signoff!' => \$chk_signoff, 'fixes-tag!' => \$chk_fixes_tag, 'patch!' => \$chk_patch, 'emacs!' => \$emacs, 'terse!' => \$terse, 'showfile!' => \$showfile, 'f|file!' => \$file, 'g|git!' => \$git, 'subjective!' => \$check, 'strict!' => \$check, 'ignore=s' => \@ignore, 'types=s' => \@use, 'show-types!' => \$show_types, 'list-types!' => \$list_types, 'max-line-length=i' => \$max_line_length, 'min-conf-desc-length=i' => \$min_conf_desc_length, 'tab-size=i' => \$tabsize, 'root=s' => \$root, 'summary!' => \$summary, 'mailback!' => \$mailback, 'summary-file!' => \$summary_file, 'fix!' => \$fix, 'fix-inplace!' => \$fix_inplace, 'ignore-perl-version!' => \$ignore_perl_version, 'debug=s' => \%debug, 'test-only=s' => \$tst_only, 'codespell!' => \$codespell, 'codespellfile=s' => \$user_codespellfile, 'typedefsfile=s' => \$typedefsfile, 'color=s' => \$color, 'no-color' => \$color, #keep old behaviors of -nocolor 'nocolor' => \$color, #keep old behaviors of -nocolor 'kconfig-prefix=s' => \${CONFIG_}, 'h|help' => \$help, 'version' => \$help ) or $help = 2; if ($user_codespellfile) { # Use the user provided codespell file unconditionally $codespellfile = $user_codespellfile; } elsif (!(-f $codespellfile)) { # If /usr/share/codespell/dictionary.txt is not present, try to find it # under codespell's install directory: /data/dictionary.txt if (($codespell || $help) && which("python3") ne "") { my $python_codespell_dict = << "EOF"; import os.path as op import codespell_lib codespell_dir = op.dirname(codespell_lib.__file__) codespell_file = op.join(codespell_dir, 'data', 'dictionary.txt') print(codespell_file, end='') EOF my $codespell_dict = `python3 -c "$python_codespell_dict" 2> /dev/null`; $codespellfile = $codespell_dict if (-f $codespell_dict); } } # $help is 1 if either -h, --help or --version is passed as option - exitcode: 0 # $help is 2 if invalid option is passed - exitcode: 1 help($help - 1) if ($help); die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix)); die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse); if ($color =~ /^[01]$/) { $color = !$color; } elsif ($color =~ /^always$/i) { $color = 1; } elsif ($color =~ /^never$/i) { $color = 0; } elsif ($color =~ /^auto$/i) { $color = (-t STDOUT); } else { die "$P: Invalid color mode: $color\n"; } load_docs() if ($verbose); list_types(0) if ($list_types); $fix = 1 if ($fix_inplace); $check_orig = $check; my $exit = 0; my $perl_version_ok = 1; if ($^V && $^V lt $minimum_perl_version) { $perl_version_ok = 0; printf "$P: requires at least perl version %vd\n", $minimum_perl_version; exit(1) if (!$ignore_perl_version); } #if no filenames are given, push '-' to read patch from stdin if ($#ARGV < 0) { push(@ARGV, '-'); } # skip TAB size 1 to avoid additional checks on $tabsize - 1 die "$P: Invalid TAB size: $tabsize\n" if ($tabsize < 2); sub hash_save_array_words { my ($hashRef, $arrayRef) = @_; my @array = split(/,/, join(',', @$arrayRef)); foreach my $word (@array) { $word =~ s/\s*\n?$//g; $word =~ s/^\s*//g; $word =~ s/\s+/ /g; $word =~ tr/[a-z]/[A-Z]/; next if ($word =~ m/^\s*#/); next if ($word =~ m/^\s*$/); $hashRef->{$word}++; } } sub hash_show_words { my ($hashRef, $prefix) = @_; if (keys %$hashRef) { print "\nNOTE: $prefix message types:"; foreach my $word (sort keys %$hashRef) { print " $word"; } print "\n"; } } hash_save_array_words(\%ignore_type, \@ignore); hash_save_array_words(\%use_type, \@use); my $dbg_values = 0; my $dbg_possible = 0; my $dbg_type = 0; my $dbg_attr = 0; for my $key (keys %debug) { ## no critic eval "\${dbg_$key} = '$debug{$key}';"; die "$@" if ($@); } my $rpt_cleaners = 0; if ($terse) { $emacs = 1; $quiet++; } if ($tree) { if (defined $root) { if (!top_of_kernel_tree($root)) { die "$P: $root: --root does not point at a valid tree\n"; } } else { if (top_of_kernel_tree('.')) { $root = '.'; } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ && top_of_kernel_tree($1)) { $root = $1; } } if (!defined $root) { print "Must be run from the top-level dir. of a kernel tree\n"; exit(2); } } my $emitted_corrupt = 0; our $Ident = qr{ [A-Za-z_][A-Za-z\d_]* (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)* }x; our $Storage = qr{extern|static|asmlinkage}; our $Sparse = qr{ __user| __kernel| __force| __iomem| __must_check| __kprobes| __ref| __refconst| __refdata| __rcu| __private }x; our $InitAttributePrefix = qr{__(?:mem|cpu|dev|net_|)}; our $InitAttributeData = qr{$InitAttributePrefix(?:initdata\b)}; our $InitAttributeConst = qr{$InitAttributePrefix(?:initconst\b)}; our $InitAttributeInit = qr{$InitAttributePrefix(?:init\b)}; our $InitAttribute = qr{$InitAttributeData|$InitAttributeConst|$InitAttributeInit}; # Notes to $Attribute: # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check our $Attribute = qr{ const| volatile| __percpu| __nocast| __safe| __bitwise| __packed__| __packed2__| __naked| __maybe_unused| __always_unused| __noreturn| __used| __cold| __pure| __noclone| __deprecated| __read_mostly| __ro_after_init| __kprobes| $InitAttribute| __aligned\s*\(.*\)| ____cacheline_aligned| ____cacheline_aligned_in_smp| ____cacheline_internodealigned_in_smp| __weak| __alloc_size\s*\(\s*\d+\s*(?:,\s*\d+\s*)?\)| _Atomic }x; our $Modifier; our $Inline = qr{inline|__always_inline|noinline|__inline|__inline__}; our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]}; our $Lval = qr{$Ident(?:$Member)*}; our $Int_type = qr{(?i)llu|ull|ll|lu|ul|l|u}; our $Binary = qr{(?i)0b[01]+$Int_type?}; our $Hex = qr{(?i)0x[0-9a-f]+$Int_type?}; our $Int = qr{[0-9]+$Int_type?}; our $Octal = qr{0[0-7]+$Int_type?}; our $String = qr{(?:\b[Lu])?"[X\t]*"}; our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?}; our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?}; our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?}; our $Float = qr{$Float_hex|$Float_dec|$Float_int}; our $Constant = qr{$Float|$Binary|$Octal|$Hex|$Int}; our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=}; our $Compare = qr{<=|>=|==|!=|<|(?}; our $Arithmetic = qr{\+|-|\*|\/|%}; our $Operators = qr{ <=|>=|==|!=| =>|->|<<|>>|<|>|!|~| &&|\|\||,|\^|\+\+|--|&|\||$Arithmetic }x; our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; our $BasicType; our $NonptrType; our $NonptrTypeMisordered; our $NonptrTypeWithAttr; our $Type; our $TypeMisordered; our $Declare; our $DeclareMisordered; our $NON_ASCII_UTF8 = qr{ [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 }x; our $UTF8 = qr{ [\x09\x0A\x0D\x20-\x7E] # ASCII | $NON_ASCII_UTF8 }x; our $typeC99Typedefs = qr{(?:__)?(?:[us]_?)?int_?(?:8|16|32|64)_t}; our $typeOtherOSTypedefs = qr{(?x: u_(?:char|short|int|long) | # bsd u(?:nchar|short|int|long) # sysv )}; our $typeKernelTypedefs = qr{(?x: (?:__)?(?:u|s|be|le)(?:8|16|32|64)| atomic_t )}; our $typeStdioTypedefs = qr{(?x: FILE )}; our $typeTypedefs = qr{(?x: $typeC99Typedefs\b| $typeOtherOSTypedefs\b| $typeKernelTypedefs\b| $typeStdioTypedefs\b )}; our $zero_initializer = qr{(?:(?:0[xX])?0+$Int_type?|NULL|false)\b}; our $logFunctions = qr{(?x: printk(?:_ratelimited|_once|_deferred_once|_deferred|)| (?:[a-z0-9]+_){1,2}(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)| TP_printk| WARN(?:_RATELIMIT|_ONCE|)| panic| MODULE_[A-Z_]+| seq_vprintf|seq_printf|seq_puts )}; our $allocFunctions = qr{(?x: (?:(?:devm_)? (?:kv|k|v)[czm]alloc(?:_array)?(?:_node)? | kstrdup(?:_const)? | kmemdup(?:_nul)?) | (?:\w+)?alloc_skb(?:_ip_align)? | # dev_alloc_skb/netdev_alloc_skb, et al dma_alloc_coherent )}; our $signature_tags = qr{(?xi: Signed-off-by:| Co-developed-by:| Acked-by:| Tested-by:| Reviewed-by:| Reported-by:| Suggested-by:| To:| Cc: )}; our @link_tags = qw(Link Closes); #Create a search and print patterns for all these strings to be used directly below our $link_tags_search = ""; our $link_tags_print = ""; foreach my $entry (@link_tags) { if ($link_tags_search ne "") { $link_tags_search .= '|'; $link_tags_print .= ' or '; } $entry .= ':'; $link_tags_search .= $entry; $link_tags_print .= "'$entry'"; } $link_tags_search = "(?:${link_tags_search})"; our $tracing_logging_tags = qr{(?xi: [=-]*> | <[=-]* | \[ | \] | start | called | entered | entry | enter | in | inside | here | begin | exit | end | done | leave | completed | out | return | [\.\!:\s]* )}; # Device ID types like found in include/linux/mod_devicetable.h. our $dev_id_types = qr{\b[a-z]\w*_device_id\b}; sub edit_distance_min { my (@arr) = @_; my $len = scalar @arr; if ((scalar @arr) < 1) { # if underflow, return return; } my $min = $arr[0]; for my $i (0 .. ($len-1)) { if ($arr[$i] < $min) { $min = $arr[$i]; } } return $min; } sub get_edit_distance { my ($str1, $str2) = @_; $str1 = lc($str1); $str2 = lc($str2); $str1 =~ s/-//g; $str2 =~ s/-//g; my $len1 = length($str1); my $len2 = length($str2); # two dimensional array storing minimum edit distance my @distance; for my $i (0 .. $len1) { for my $j (0 .. $len2) { if ($i == 0) { $distance[$i][$j] = $j; } elsif ($j == 0) { $distance[$i][$j] = $i; } elsif (substr($str1, $i-1, 1) eq substr($str2, $j-1, 1)) { $distance[$i][$j] = $distance[$i - 1][$j - 1]; } else { my $dist1 = $distance[$i][$j - 1]; #insert distance my $dist2 = $distance[$i - 1][$j]; # remove my $dist3 = $distance[$i - 1][$j - 1]; #replace $distance[$i][$j] = 1 + edit_distance_min($dist1, $dist2, $dist3); } } } return $distance[$len1][$len2]; } sub find_standard_signature { my ($sign_off) = @_; my @standard_signature_tags = ( 'Signed-off-by:', 'Co-developed-by:', 'Acked-by:', 'Tested-by:', 'Reviewed-by:', 'Reported-by:', 'Suggested-by:' ); foreach my $signature (@standard_signature_tags) { return $signature if (get_edit_distance($sign_off, $signature) <= 2); } return ""; } our $obsolete_archives = qr{(?xi: \Qfreedesktop.org/archives/dri-devel\E | \Qlists.infradead.org\E | \Qlkml.org\E | \Qmail-archive.com\E | \Qmailman.alsa-project.org/pipermail\E | \Qmarc.info\E | \Qozlabs.org/pipermail\E | \Qspinics.net\E )}; our @typeListMisordered = ( qr{char\s+(?:un)?signed}, qr{int\s+(?:(?:un)?signed\s+)?short\s}, qr{int\s+short(?:\s+(?:un)?signed)}, qr{short\s+int(?:\s+(?:un)?signed)}, qr{(?:un)?signed\s+int\s+short}, qr{short\s+(?:un)?signed}, qr{long\s+int\s+(?:un)?signed}, qr{int\s+long\s+(?:un)?signed}, qr{long\s+(?:un)?signed\s+int}, qr{int\s+(?:un)?signed\s+long}, qr{int\s+(?:un)?signed}, qr{int\s+long\s+long\s+(?:un)?signed}, qr{long\s+long\s+int\s+(?:un)?signed}, qr{long\s+long\s+(?:un)?signed\s+int}, qr{long\s+long\s+(?:un)?signed}, qr{long\s+(?:un)?signed}, ); our @typeList = ( qr{void}, qr{(?:(?:un)?signed\s+)?char}, qr{(?:(?:un)?signed\s+)?short\s+int}, qr{(?:(?:un)?signed\s+)?short}, qr{(?:(?:un)?signed\s+)?int}, qr{(?:(?:un)?signed\s+)?long\s+int}, qr{(?:(?:un)?signed\s+)?long\s+long\s+int}, qr{(?:(?:un)?signed\s+)?long\s+long}, qr{(?:(?:un)?signed\s+)?long}, qr{(?:un)?signed}, qr{float}, qr{double}, qr{bool}, qr{struct\s+$Ident}, qr{union\s+$Ident}, qr{enum\s+$Ident}, qr{${Ident}_t}, qr{${Ident}_handler}, qr{${Ident}_handler_fn}, @typeListMisordered, ); our $C90_int_types = qr{(?x: long\s+long\s+int\s+(?:un)?signed| long\s+long\s+(?:un)?signed\s+int| long\s+long\s+(?:un)?signed| (?:(?:un)?signed\s+)?long\s+long\s+int| (?:(?:un)?signed\s+)?long\s+long| int\s+long\s+long\s+(?:un)?signed| int\s+(?:(?:un)?signed\s+)?long\s+long| long\s+int\s+(?:un)?signed| long\s+(?:un)?signed\s+int| long\s+(?:un)?signed| (?:(?:un)?signed\s+)?long\s+int| (?:(?:un)?signed\s+)?long| int\s+long\s+(?:un)?signed| int\s+(?:(?:un)?signed\s+)?long| int\s+(?:un)?signed| (?:(?:un)?signed\s+)?int )}; our @typeListFile = (); our @typeListWithAttr = ( @typeList, qr{struct\s+$InitAttribute\s+$Ident}, qr{union\s+$InitAttribute\s+$Ident}, ); our @modifierList = ( qr{fastcall}, ); our @modifierListFile = (); our @mode_permission_funcs = ( ["module_param", 3], ["module_param_(?:array|named|string)", 4], ["module_param_array_named", 5], ["debugfs_create_(?:file|u8|u16|u32|u64|x8|x16|x32|x64|size_t|atomic_t|bool|blob|regset32|u32_array)", 2], ["proc_create(?:_data|)", 2], ["(?:CLASS|DEVICE|SENSOR|SENSOR_DEVICE|IIO_DEVICE)_ATTR", 2], ["IIO_DEV_ATTR_[A-Z_]+", 1], ["SENSOR_(?:DEVICE_|)ATTR_2", 2], ["SENSOR_TEMPLATE(?:_2|)", 3], ["__ATTR", 2], ); my $word_pattern = '\b[A-Z]?[a-z]{2,}\b'; #Create a search pattern for all these functions to speed up a loop below our $mode_perms_search = ""; foreach my $entry (@mode_permission_funcs) { $mode_perms_search .= '|' if ($mode_perms_search ne ""); $mode_perms_search .= $entry->[0]; } $mode_perms_search = "(?:${mode_perms_search})"; our %deprecated_apis = ( "kmap" => "kmap_local_page", "kunmap" => "kunmap_local", "kmap_atomic" => "kmap_local_page", "kunmap_atomic" => "kunmap_local", #These should be enough to drive away new IDR users "DEFINE_IDR" => "DEFINE_XARRAY", "idr_init" => "xa_init", "idr_init_base" => "xa_init_flags", "rcu_read_lock_trace" => "rcu_read_lock_tasks_trace", "rcu_read_unlock_trace" => "rcu_read_unlock_tasks_trace", ); #Create a search pattern for all these strings to speed up a loop below our $deprecated_apis_search = ""; foreach my $entry (keys %deprecated_apis) { $deprecated_apis_search .= '|' if ($deprecated_apis_search ne ""); $deprecated_apis_search .= $entry; } $deprecated_apis_search = "(?:${deprecated_apis_search})"; our $mode_perms_world_writable = qr{ S_IWUGO | S_IWOTH | S_IRWXUGO | S_IALLUGO | 0[0-7][0-7][2367] }x; our %mode_permission_string_types = ( "S_IRWXU" => 0700, "S_IRUSR" => 0400, "S_IWUSR" => 0200, "S_IXUSR" => 0100, "S_IRWXG" => 0070, "S_IRGRP" => 0040, "S_IWGRP" => 0020, "S_IXGRP" => 0010, "S_IRWXO" => 0007, "S_IROTH" => 0004, "S_IWOTH" => 0002, "S_IXOTH" => 0001, "S_IRWXUGO" => 0777, "S_IRUGO" => 0444, "S_IWUGO" => 0222, "S_IXUGO" => 0111, ); #Create a search pattern for all these strings to speed up a loop below our $mode_perms_string_search = ""; foreach my $entry (keys %mode_permission_string_types) { $mode_perms_string_search .= '|' if ($mode_perms_string_search ne ""); $mode_perms_string_search .= $entry; } our $single_mode_perms_string_search = "(?:${mode_perms_string_search})"; our $multi_mode_perms_string_search = qr{ ${single_mode_perms_string_search} (?:\s*\|\s*${single_mode_perms_string_search})* }x; sub perms_to_octal { my ($string) = @_; return trim($string) if ($string =~ /^\s*0[0-7]{3,3}\s*$/); my $val = ""; my $oval = ""; my $to = 0; my $curpos = 0; my $lastpos = 0; while ($string =~ /\b(($single_mode_perms_string_search)\b(?:\s*\|\s*)?\s*)/g) { $curpos = pos($string); my $match = $2; my $omatch = $1; last if ($lastpos > 0 && ($curpos - length($omatch) != $lastpos)); $lastpos = $curpos; $to |= $mode_permission_string_types{$match}; $val .= '\s*\|\s*' if ($val ne ""); $val .= $match; $oval .= $omatch; } $oval =~ s/^\s*\|\s*//; $oval =~ s/\s*\|\s*$//; return sprintf("%04o", $to); } our $allowed_asm_includes = qr{(?x: irq| memory| time| reboot )}; # memory.h: ARM has a custom one # Load common spelling mistakes and build regular expression list. my $misspellings; my %spelling_fix; if (open(my $spelling, '<', $spelling_file)) { while (<$spelling>) { my $line = $_; $line =~ s/\s*\n?$//g; $line =~ s/^\s*//g; next if ($line =~ m/^\s*#/); next if ($line =~ m/^\s*$/); my ($suspect, $fix) = split(/\|\|/, $line); $spelling_fix{$suspect} = $fix; } close($spelling); } else { warn "No typos will be found - file '$spelling_file': $!\n"; } if ($codespell) { if (open(my $spelling, '<', $codespellfile)) { while (<$spelling>) { my $line = $_; $line =~ s/\s*\n?$//g; $line =~ s/^\s*//g; next if ($line =~ m/^\s*#/); next if ($line =~ m/^\s*$/); next if ($line =~ m/, disabled/i); $line =~ s/,.*$//; my ($suspect, $fix) = split(/->/, $line); $spelling_fix{$suspect} = $fix; } close($spelling); } else { warn "No codespell typos will be found - file '$codespellfile': $!\n"; } } $misspellings = join("|", sort keys %spelling_fix) if keys %spelling_fix; sub read_words { my ($wordsRef, $file) = @_; if (open(my $words, '<', $file)) { while (<$words>) { my $line = $_; $line =~ s/\s*\n?$//g; $line =~ s/^\s*//g; next if ($line =~ m/^\s*#/); next if ($line =~ m/^\s*$/); if ($line =~ /\s/) { print("$file: '$line' invalid - ignored\n"); next; } $$wordsRef .= '|' if (defined $$wordsRef); $$wordsRef .= $line; } close($file); return 1; } return 0; } my $const_structs; if (show_type("CONST_STRUCT")) { read_words(\$const_structs, $conststructsfile) or warn "No structs that should be const will be found - file '$conststructsfile': $!\n"; } if (defined($typedefsfile)) { my $typeOtherTypedefs; read_words(\$typeOtherTypedefs, $typedefsfile) or warn "No additional types will be considered - file '$typedefsfile': $!\n"; $typeTypedefs .= '|' . $typeOtherTypedefs if (defined $typeOtherTypedefs); } sub build_types { my $mods = "(?x: \n" . join("|\n ", (@modifierList, @modifierListFile)) . "\n)"; my $all = "(?x: \n" . join("|\n ", (@typeList, @typeListFile)) . "\n)"; my $Misordered = "(?x: \n" . join("|\n ", @typeListMisordered) . "\n)"; my $allWithAttr = "(?x: \n" . join("|\n ", @typeListWithAttr) . "\n)"; $Modifier = qr{(?:$Attribute|$Sparse|$mods)}; $BasicType = qr{ (?:$typeTypedefs\b)| (?:${all}\b) }x; $NonptrType = qr{ (?:$Modifier\s+|const\s+)* (?: (?:typeof|__typeof__)\s*\([^\)]*\)| (?:$typeTypedefs\b)| (?:${all}\b) ) (?:\s+$Modifier|\s+const)* }x; $NonptrTypeMisordered = qr{ (?:$Modifier\s+|const\s+)* (?: (?:${Misordered}\b) ) (?:\s+$Modifier|\s+const)* }x; $NonptrTypeWithAttr = qr{ (?:$Modifier\s+|const\s+)* (?: (?:typeof|__typeof__)\s*\([^\)]*\)| (?:$typeTypedefs\b)| (?:${allWithAttr}\b) ) (?:\s+$Modifier|\s+const)* }x; $Type = qr{ $NonptrType (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} (?:\s+$Inline|\s+$Modifier)* }x; $TypeMisordered = qr{ $NonptrTypeMisordered (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*\s*(?:const\s*)?|\[\])+|(?:\s*\[\s*\])+){0,4} (?:\s+$Inline|\s+$Modifier)* }x; $Declare = qr{(?:$Storage\s+(?:$Inline\s+)?)?$Type}; $DeclareMisordered = qr{(?:$Storage\s+(?:$Inline\s+)?)?$TypeMisordered}; } build_types(); our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*}; # Using $balanced_parens, $LvalOrFunc, or $FuncArg # requires at least perl version v5.10.0 # Any use must be runtime checked with $^V our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/; our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; our $declaration_macros = qr{(?x: (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| (?:$Storage\s+)?[HLP]?LIST_HEAD\s*\(| (?:SKCIPHER_REQUEST|SHASH_DESC|AHASH_REQUEST)_ON_STACK\s*\(| (?:$Storage\s+)?(?:XA_STATE|XA_STATE_ORDER)\s*\(| __cacheline_group_(?:begin|end)(?:_aligned)?\s*\(| __dma_from_device_group_(?:begin|end)\s*\( )}; our %allow_repeated_words = ( add => '', added => '', bad => '', be => '', ); sub deparenthesize { my ($string) = @_; return "" if (!defined($string)); while ($string =~ /^\s*\(.*\)\s*$/) { $string =~ s@^\s*\(\s*@@; $string =~ s@\s*\)\s*$@@; } $string =~ s@\s+@ @g; return $string; } sub seed_camelcase_file { my ($file) = @_; return if (!(-f $file)); local $/; open(my $include_file, '<', "$file") or warn "$P: Can't read '$file' $!\n"; my $text = <$include_file>; close($include_file); my @lines = split('\n', $text); foreach my $line (@lines) { next if ($line !~ /(?:[A-Z][a-z]|[a-z][A-Z])/); if ($line =~ /^[ \t]*(?:#[ \t]*define|typedef\s+$Type)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)/) { $camelcase{$1} = 1; } elsif ($line =~ /^\s*$Declare\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[\(\[,;]/) { $camelcase{$1} = 1; } elsif ($line =~ /^\s*(?:union|struct|enum)\s+(\w*(?:[A-Z][a-z]|[a-z][A-Z])\w*)\s*[;\{]/) { $camelcase{$1} = 1; } } } our %maintained_status = (); sub is_maintained_obsolete { my ($filename) = @_; return 0 if (!$tree || !(-e "$root/scripts/get_maintainer.pl")); if (!exists($maintained_status{$filename})) { $maintained_status{$filename} = `perl $root/scripts/get_maintainer.pl --status --nom --nol --nogit --nogit-fallback -f $filename 2>&1`; } return $maintained_status{$filename} =~ /obsolete/i; } sub is_SPDX_License_valid { my ($license) = @_; return 1 if (!$tree || which("python3") eq "" || !(-x "$root/scripts/spdxcheck.py") || !(-e "$gitroot")); my $root_path = abs_path($root); my $status = `cd "$root_path"; echo "$license" | scripts/spdxcheck.py -`; return 0 if ($status ne ""); return 1; } my $camelcase_seeded = 0; sub seed_camelcase_includes { return if ($camelcase_seeded); my $files; my $camelcase_cache = ""; my @include_files = (); $camelcase_seeded = 1; if (-e "$gitroot") { my $git_last_include_commit = `${git_command} log --no-merges --pretty=format:"%h%n" -1 -- include`; chomp $git_last_include_commit; $camelcase_cache = ".checkpatch-camelcase.git.$git_last_include_commit"; } else { my $last_mod_date = 0; $files = `find $root/include -name "*.h"`; @include_files = split('\n', $files); foreach my $file (@include_files) { my $date = POSIX::strftime("%Y%m%d%H%M", localtime((stat $file)[9])); $last_mod_date = $date if ($last_mod_date < $date); } $camelcase_cache = ".checkpatch-camelcase.date.$last_mod_date"; } if ($camelcase_cache ne "" && -f $camelcase_cache) { open(my $camelcase_file, '<', "$camelcase_cache") or warn "$P: Can't read '$camelcase_cache' $!\n"; while (<$camelcase_file>) { chomp; $camelcase{$_} = 1; } close($camelcase_file); return; } if (-e "$gitroot") { $files = `${git_command} ls-files "include/*.h"`; @include_files = split('\n', $files); } foreach my $file (@include_files) { seed_camelcase_file($file); } if ($camelcase_cache ne "") { unlink glob ".checkpatch-camelcase.*"; open(my $camelcase_file, '>', "$camelcase_cache") or warn "$P: Can't write '$camelcase_cache' $!\n"; foreach (sort { lc($a) cmp lc($b) } keys(%camelcase)) { print $camelcase_file ("$_\n"); } close($camelcase_file); } } sub git_is_single_file { my ($filename) = @_; return 0 if ((which("git") eq "") || !(-e "$gitroot")); my $output = `${git_command} ls-files -- $filename 2>/dev/null`; my $count = $output =~ tr/\n//; return $count eq 1 && $output =~ m{^${filename}$}; } sub git_commit_info { my ($commit, $id, $desc) = @_; return ($id, $desc) if ((which("git") eq "") || !(-e "$gitroot")); my $output = `${git_command} log --no-color --format='%H %s' -1 $commit 2>&1`; $output =~ s/^\s*//gm; my @lines = split("\n", $output); return ($id, $desc) if ($#lines < 0); if ($lines[0] =~ /^error: short SHA1 $commit is ambiguous/) { # Maybe one day convert this block of bash into something that returns # all matching commit ids, but it's very slow... # # echo "checking commits $1..." # git rev-list --remotes | grep -i "^$1" | # while read line ; do # git log --format='%H %s' -1 $line | # echo "commit $(cut -c 1-12,41-)" # done } elsif ($lines[0] =~ /^fatal: ambiguous argument '$commit': unknown revision or path not in the working tree\./ || $lines[0] =~ /^fatal: bad object $commit/) { $id = undef; } else { $id = substr($lines[0], 0, 12); $desc = substr($lines[0], 41); } return ($id, $desc); } $chk_signoff = 0 if ($file); $chk_fixes_tag = 0 if ($file); my @rawlines = (); my @lines = (); my @fixed = (); my @fixed_inserted = (); my @fixed_deleted = (); my $fixlinenr = -1; # If input is git commits, extract all commits from the commit expressions. # For example, HEAD-3 means we need check 'HEAD, HEAD~1, HEAD~2'. die "$P: No git repository found\n" if ($git && !-e "$gitroot"); if ($git) { my @commits = (); foreach my $commit_expr (@ARGV) { my $git_range; if ($commit_expr =~ m/^(.*)-(\d+)$/) { $git_range = "-$2 $1"; } elsif ($commit_expr =~ m/\.\./) { $git_range = "$commit_expr"; } else { $git_range = "-1 $commit_expr"; } my $lines = `${git_command} log --no-color --no-merges --pretty=format:'%H %s' $git_range`; foreach my $line (split(/\n/, $lines)) { $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/; next if (!defined($1) || !defined($2)); my $sha1 = $1; my $subject = $2; unshift(@commits, $sha1); $git_commits{$sha1} = $subject; } } die "$P: no git commits after extraction!\n" if (@commits == 0); @ARGV = @commits; } my $vname; $allow_c99_comments = !defined $ignore_type{"C99_COMMENT_TOLERANCE"}; for my $filename (@ARGV) { my $FILE; my $is_git_file = git_is_single_file($filename); my $oldfile = $file; $file = 1 if ($is_git_file); if ($git) { open($FILE, '-|', "git format-patch -M --stdout -1 $filename") || die "$P: $filename: git format-patch failed - $!\n"; } elsif ($file) { open($FILE, '-|', "diff -u /dev/null $filename") || die "$P: $filename: diff failed - $!\n"; } elsif ($filename eq '-') { open($FILE, '<&STDIN'); } else { open($FILE, '<', "$filename") || die "$P: $filename: open failed - $!\n"; } if ($filename eq '-') { $vname = 'Your patch'; } elsif ($git) { $vname = "Commit " . substr($filename, 0, 12) . ' ("' . $git_commits{$filename} . '")'; } else { $vname = $filename; } while (<$FILE>) { chomp; push(@rawlines, $_); $vname = qq("$1") if ($filename eq '-' && $_ =~ m/^Subject:\s+(.+)/i); } close($FILE); if ($#ARGV > 0 && $quiet == 0) { print '-' x length($vname) . "\n"; print "$vname\n"; print '-' x length($vname) . "\n"; } if (!process($filename)) { $exit = 1; } @rawlines = (); @lines = (); @fixed = (); @fixed_inserted = (); @fixed_deleted = (); $fixlinenr = -1; @modifierListFile = (); @typeListFile = (); build_types(); $file = $oldfile if ($is_git_file); } if (!$quiet) { hash_show_words(\%use_type, "Used"); hash_show_words(\%ignore_type, "Ignored"); if (!$perl_version_ok) { print << "EOM" NOTE: perl $^V is not modern enough to detect all possible issues. An upgrade to at least perl $minimum_perl_version is suggested. EOM } if ($exit) { print << "EOM" NOTE: If any of the errors are false positives, please report them to the maintainer, see CHECKPATCH in MAINTAINERS. EOM } } exit($exit); sub top_of_kernel_tree { my ($root) = @_; my @tree_check = ( "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", "README", "Documentation", "arch", "include", "drivers", "fs", "init", "ipc", "kernel", "lib", "scripts", ); foreach my $check (@tree_check) { if (! -e $root . '/' . $check) { return 0; } } return 1; } sub parse_email { my ($formatted_email) = @_; my $name = ""; my $quoted = ""; my $name_comment = ""; my $address = ""; my $comment = ""; if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) { $name = $1; $address = $2; $comment = $3 if defined $3; } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) { $address = $1; $comment = $2 if defined $2; } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) { $address = $1; $comment = $2 if defined $2; $formatted_email =~ s/\Q$address\E.*$//; $name = $formatted_email; $name = trim($name); $name =~ s/^\"|\"$//g; # If there's a name left after stripping spaces and # leading quotes, and the address doesn't have both # leading and trailing angle brackets, the address # is invalid. ie: # "joe smith joe@smith.com" bad # "joe smith ]+>$/) { $name = ""; $address = ""; $comment = ""; } } # Extract comments from names excluding quoted parts # "John D. (Doe)" - Do not extract if ($name =~ s/\"(.+)\"//) { $quoted = $1; } while ($name =~ s/\s*($balanced_parens)\s*/ /) { $name_comment .= trim($1); } $name =~ s/^[ \"]+|[ \"]+$//g; $name = trim("$quoted $name"); $address = trim($address); $address =~ s/^\<|\>$//g; $comment = trim($comment); if ($name =~ /[^\w \-]/i) { ##has "must quote" chars $name =~ s/(?"; } $formatted_email .= "$comment"; return $formatted_email; } sub reformat_email { my ($email) = @_; my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); return format_email($email_name, $name_comment, $email_address, $comment); } sub same_email_addresses { my ($email1, $email2) = @_; my ($email1_name, $name1_comment, $email1_address, $comment1) = parse_email($email1); my ($email2_name, $name2_comment, $email2_address, $comment2) = parse_email($email2); return $email1_name eq $email2_name && $email1_address eq $email2_address && $name1_comment eq $name2_comment && $comment1 eq $comment2; } sub which { my ($bin) = @_; foreach my $path (split(/:/, $ENV{PATH})) { if (-e "$path/$bin") { return "$path/$bin"; } } return ""; } sub which_conf { my ($conf) = @_; foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) { if (-e "$path/$conf") { return "$path/$conf"; } } return ""; } sub expand_tabs { my ($str) = @_; my $res = ''; my $n = 0; for my $c (split(//, $str)) { if ($c eq "\t") { $res .= ' '; $n++; for (; ($n % $tabsize) != 0; $n++) { $res .= ' '; } next; } $res .= $c; $n++; } return $res; } sub copy_spacing { (my $res = shift) =~ tr/\t/ /c; return $res; } sub line_stats { my ($line) = @_; # Drop the diff line leader and expand tabs $line =~ s/^.//; $line = expand_tabs($line); # Pick the indent from the front of the line. my ($white) = ($line =~ /^(\s*)/); return (length($line), length($white)); } my $sanitise_quote = ''; sub sanitise_line_reset { my ($in_comment) = @_; if ($in_comment) { $sanitise_quote = '*/'; } else { $sanitise_quote = ''; } } sub sanitise_line { my ($line) = @_; my $res = ''; my $l = ''; my $qlen = 0; my $off = 0; my $c; # Always copy over the diff marker. $res = substr($line, 0, 1); for ($off = 1; $off < length($line); $off++) { $c = substr($line, $off, 1); # Comments we are whacking completely including the begin # and end, all to $;. if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') { $sanitise_quote = '*/'; substr($res, $off, 2, "$;$;"); $off++; next; } if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') { $sanitise_quote = ''; substr($res, $off, 2, "$;$;"); $off++; next; } if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') { $sanitise_quote = '//'; substr($res, $off, 2, $sanitise_quote); $off++; next; } # A \ in a string means ignore the next character. if (($sanitise_quote eq "'" || $sanitise_quote eq '"') && $c eq "\\") { substr($res, $off, 2, 'XX'); $off++; next; } # Regular quotes. if ($c eq "'" || $c eq '"') { if ($sanitise_quote eq '') { $sanitise_quote = $c; substr($res, $off, 1, $c); next; } elsif ($sanitise_quote eq $c) { $sanitise_quote = ''; } } #print "c<$c> SQ<$sanitise_quote>\n"; if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") { substr($res, $off, 1, $;); } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") { substr($res, $off, 1, $;); } elsif ($off != 0 && $sanitise_quote && $c ne "\t") { substr($res, $off, 1, 'X'); } else { substr($res, $off, 1, $c); } } if ($sanitise_quote eq '//') { $sanitise_quote = ''; } # The pathname on a #include may be surrounded by '<' and '>'. if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) { my $clean = 'X' x length($1); $res =~ s@\<.*\>@<$clean>@; # The whole of a #error is a string. } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) { my $clean = 'X' x length($1); $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@; } if ($allow_c99_comments && $res =~ m@(//.*$)@) { my $match = $1; $res =~ s/\Q$match\E/"$;" x length($match)/e; } return $res; } sub get_quoted_string { my ($line, $rawline) = @_; return "" if (!defined($line) || !defined($rawline)); return "" if ($line !~ m/($String)/g); return substr($rawline, $-[0], $+[0] - $-[0]); } sub ctx_statement_block { my ($linenr, $remain, $off) = @_; my $line = $linenr - 1; my $blk = ''; my $soff = $off; my $coff = $off - 1; my $coff_set = 0; my $loff = 0; my $type = ''; my $level = 0; my @stack = (); my $p; my $c; my $len = 0; my $remainder; while (1) { @stack = (['', 0]) if ($#stack == -1); #warn "CSB: blk<$blk> remain<$remain>\n"; # If we are about to drop off the end, pull in more # context. if ($off >= $len) { for (; $remain > 0; $line++) { last if (!defined $lines[$line]); next if ($lines[$line] =~ /^-/); $remain--; $loff = $len; $blk .= $lines[$line] . "\n"; $len = length($blk); $line++; last; } # Bail if there is no further context. #warn "CSB: blk<$blk> off<$off> len<$len>\n"; if ($off >= $len) { last; } if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) { $level++; $type = '#'; } } $p = $c; $c = substr($blk, $off, 1); $remainder = substr($blk, $off); #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n"; # Handle nested #if/#else. if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) { push(@stack, [ $type, $level ]); } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) { ($type, $level) = @{$stack[$#stack - 1]}; } elsif ($remainder =~ /^#\s*endif\b/) { ($type, $level) = @{pop(@stack)}; } # Statement ends at the ';' or a close '}' at the # outermost level. if ($level == 0 && $c eq ';') { last; } # An else is really a conditional as long as its not else if if ($level == 0 && $coff_set == 0 && (!defined($p) || $p =~ /(?:\s|\}|\+)/) && $remainder =~ /^(else)(?:\s|{)/ && $remainder !~ /^else\s+if\b/) { $coff = $off + length($1) - 1; $coff_set = 1; #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n"; #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n"; } if (($type eq '' || $type eq '(') && $c eq '(') { $level++; $type = '('; } if ($type eq '(' && $c eq ')') { $level--; $type = ($level != 0)? '(' : ''; if ($level == 0 && $coff < $soff) { $coff = $off; $coff_set = 1; #warn "CSB: mark coff<$coff>\n"; } } if (($type eq '' || $type eq '{') && $c eq '{') { $level++; $type = '{'; } if ($type eq '{' && $c eq '}') { $level--; $type = ($level != 0)? '{' : ''; if ($level == 0) { if (substr($blk, $off + 1, 1) eq ';') { $off++; } last; } } # Preprocessor commands end at the newline unless escaped. if ($type eq '#' && $c eq "\n" && $p ne "\\") { $level--; $type = ''; $off++; last; } $off++; } # We are truly at the end, so shuffle to the next line. if ($off == $len) { $loff = $len + 1; $line++; $remain--; } my $statement = substr($blk, $soff, $off - $soff + 1); my $condition = substr($blk, $soff, $coff - $soff + 1); #warn "STATEMENT<$statement>\n"; #warn "CONDITION<$condition>\n"; #print "coff<$coff> soff<$off> loff<$loff>\n"; return ($statement, $condition, $line, $remain + 1, $off - $loff + 1, $level); } sub statement_lines { my ($stmt) = @_; # Strip the diff line prefixes and rip blank lines at start and end. $stmt =~ s/(^|\n)./$1/g; $stmt =~ s/^\s*//; $stmt =~ s/\s*$//; my @stmt_lines = ($stmt =~ /\n/g); return $#stmt_lines + 2; } sub statement_rawlines { my ($stmt) = @_; my @stmt_lines = ($stmt =~ /\n/g); return $#stmt_lines + 2; } sub statement_block_size { my ($stmt) = @_; $stmt =~ s/(^|\n)./$1/g; $stmt =~ s/^\s*{//; $stmt =~ s/}\s*$//; $stmt =~ s/^\s*//; $stmt =~ s/\s*$//; my @stmt_lines = ($stmt =~ /\n/g); my @stmt_statements = ($stmt =~ /;/g); my $stmt_lines = $#stmt_lines + 2; my $stmt_statements = $#stmt_statements + 1; if ($stmt_lines > $stmt_statements) { return $stmt_lines; } else { return $stmt_statements; } } sub ctx_statement_full { my ($linenr, $remain, $off) = @_; my ($statement, $condition, $level); my (@chunks); # Grab the first conditional/block pair. ($statement, $condition, $linenr, $remain, $off, $level) = ctx_statement_block($linenr, $remain, $off); #print "F: c<$condition> s<$statement> remain<$remain>\n"; push(@chunks, [ $condition, $statement ]); if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) { return ($level, $linenr, @chunks); } # Pull in the following conditional/block pairs and see if they # could continue the statement. for (;;) { ($statement, $condition, $linenr, $remain, $off, $level) = ctx_statement_block($linenr, $remain, $off); #print "C: c<$condition> s<$statement> remain<$remain>\n"; last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s)); #print "C: push\n"; push(@chunks, [ $condition, $statement ]); } return ($level, $linenr, @chunks); } sub ctx_block_get { my ($linenr, $remain, $outer, $open, $close, $off) = @_; my $line; my $start = $linenr - 1; my $blk = ''; my @o; my @c; my @res = (); my $level = 0; my @stack = ($level); for ($line = $start; $remain > 0; $line++) { next if ($rawlines[$line] =~ /^-/); $remain--; $blk .= $rawlines[$line]; # Handle nested #if/#else. if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) { push(@stack, $level); } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) { $level = $stack[$#stack - 1]; } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) { $level = pop(@stack); } foreach my $c (split(//, $lines[$line])) { ##print "C<$c>L<$level><$open$close>O<$off>\n"; if ($off > 0) { $off--; next; } if ($c eq $close && $level > 0) { $level--; last if ($level == 0); } elsif ($c eq $open) { $level++; } } if (!$outer || $level <= 1) { push(@res, $rawlines[$line]); } last if ($level == 0); } return ($level, @res); } sub ctx_block_outer { my ($linenr, $remain) = @_; my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0); return @r; } sub ctx_block { my ($linenr, $remain) = @_; my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0); return @r; } sub ctx_statement { my ($linenr, $remain, $off) = @_; my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off); return @r; } sub ctx_block_level { my ($linenr, $remain) = @_; return ctx_block_get($linenr, $remain, 0, '{', '}', 0); } sub ctx_statement_level { my ($linenr, $remain, $off) = @_; return ctx_block_get($linenr, $remain, 0, '(', ')', $off); } sub ctx_locate_comment { my ($first_line, $end_line) = @_; # If c99 comment on the current line, or the line before or after my ($current_comment) = ($rawlines[$end_line - 1] =~ m@^\+.*(//.*$)@); return $current_comment if (defined $current_comment); ($current_comment) = ($rawlines[$end_line - 2] =~ m@^[\+ ].*(//.*$)@); return $current_comment if (defined $current_comment); ($current_comment) = ($rawlines[$end_line] =~ m@^[\+ ].*(//.*$)@); return $current_comment if (defined $current_comment); # Catch a comment on the end of the line itself. ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@); return $current_comment if (defined $current_comment); # Look through the context and try and figure out if there is a # comment. my $in_comment = 0; $current_comment = ''; for (my $linenr = $first_line; $linenr < $end_line; $linenr++) { my $line = $rawlines[$linenr - 1]; #warn " $line\n"; if ($linenr == $first_line and $line =~ m@^.\s*\*@) { $in_comment = 1; } if ($line =~ m@/\*@) { $in_comment = 1; } if (!$in_comment && $current_comment ne '') { $current_comment = ''; } $current_comment .= $line . "\n" if ($in_comment); if ($line =~ m@\*/@) { $in_comment = 0; } } chomp($current_comment); return($current_comment); } sub ctx_has_comment { my ($first_line, $end_line) = @_; my $cmt = ctx_locate_comment($first_line, $end_line); ##print "LINE: $rawlines[$end_line - 1 ]\n"; ##print "CMMT: $cmt\n"; return ($cmt ne ''); } sub raw_line { my ($linenr, $cnt) = @_; my $offset = $linenr - 1; $cnt++; my $line; while ($cnt) { $line = $rawlines[$offset++]; next if (defined($line) && $line =~ /^-/); $cnt--; } return $line; } sub get_stat_real { my ($linenr, $lc) = @_; my $stat_real = raw_line($linenr, 0); for (my $count = $linenr + 1; $count <= $lc; $count++) { $stat_real = $stat_real . "\n" . raw_line($count, 0); } return $stat_real; } sub get_stat_here { my ($linenr, $cnt, $here) = @_; my $herectx = $here . "\n"; for (my $n = 0; $n < $cnt; $n++) { $herectx .= raw_line($linenr, $n) . "\n"; } return $herectx; } sub cat_vet { my ($vet) = @_; my ($res, $coded); $res = ''; while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) { $res .= $1; if ($2 ne '') { $coded = sprintf("^%c", unpack('C', $2) + 64); $res .= $coded; } } $res =~ s/$/\$/; return $res; } my $av_preprocessor = 0; my $av_pending; my @av_paren_type; my $av_pend_colon; sub annotate_reset { $av_preprocessor = 0; $av_pending = '_'; @av_paren_type = ('E'); $av_pend_colon = 'O'; } sub annotate_values { my ($stream, $type) = @_; my $res; my $var = '_' x length($stream); my $cur = $stream; print "$stream\n" if ($dbg_values > 1); while (length($cur)) { @av_paren_type = ('E') if ($#av_paren_type < 0); print " <" . join('', @av_paren_type) . "> <$type> <$av_pending>" if ($dbg_values > 1); if ($cur =~ /^(\s+)/o) { print "WS($1)\n" if ($dbg_values > 1); if ($1 =~ /\n/ && $av_preprocessor) { $type = pop(@av_paren_type); $av_preprocessor = 0; } } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') { print "CAST($1)\n" if ($dbg_values > 1); push(@av_paren_type, $type); $type = 'c'; } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) { print "DECLARE($1)\n" if ($dbg_values > 1); $type = 'T'; } elsif ($cur =~ /^($Modifier)\s*/) { print "MODIFIER($1)\n" if ($dbg_values > 1); $type = 'T'; } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) { print "DEFINE($1,$2)\n" if ($dbg_values > 1); $av_preprocessor = 1; push(@av_paren_type, $type); if ($2 ne '') { $av_pending = 'N'; } $type = 'E'; } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) { print "UNDEF($1)\n" if ($dbg_values > 1); $av_preprocessor = 1; push(@av_paren_type, $type); } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) { print "PRE_START($1)\n" if ($dbg_values > 1); $av_preprocessor = 1; push(@av_paren_type, $type); push(@av_paren_type, $type); $type = 'E'; } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) { print "PRE_RESTART($1)\n" if ($dbg_values > 1); $av_preprocessor = 1; push(@av_paren_type, $av_paren_type[$#av_paren_type]); $type = 'E'; } elsif ($cur =~ /^(\#\s*(?:endif))/o) { print "PRE_END($1)\n" if ($dbg_values > 1); $av_preprocessor = 1; # Assume all arms of the conditional end as this # one does, and continue as if the #endif was not here. pop(@av_paren_type); push(@av_paren_type, $type); $type = 'E'; } elsif ($cur =~ /^(\\\n)/o) { print "PRECONT($1)\n" if ($dbg_values > 1); } elsif ($cur =~ /^(__attribute__)\s*\(?/o) { print "ATTR($1)\n" if ($dbg_values > 1); $av_pending = $type; $type = 'N'; } elsif ($cur =~ /^(sizeof)\s*(\()?/o) { print "SIZEOF($1)\n" if ($dbg_values > 1); if (defined $2) { $av_pending = 'V'; } $type = 'N'; } elsif ($cur =~ /^(if|while|for)\b/o) { print "COND($1)\n" if ($dbg_values > 1); $av_pending = 'E'; $type = 'N'; } elsif ($cur =~/^(case)/o) { print "CASE($1)\n" if ($dbg_values > 1); $av_pend_colon = 'C'; $type = 'N'; } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) { print "KEYWORD($1)\n" if ($dbg_values > 1); $type = 'N'; } elsif ($cur =~ /^(\()/o) { print "PAREN('$1')\n" if ($dbg_values > 1); push(@av_paren_type, $av_pending); $av_pending = '_'; $type = 'N'; } elsif ($cur =~ /^(\))/o) { my $new_type = pop(@av_paren_type); if ($new_type ne '_') { $type = $new_type; print "PAREN('$1') -> $type\n" if ($dbg_values > 1); } else { print "PAREN('$1')\n" if ($dbg_values > 1); } } elsif ($cur =~ /^($Ident)\s*\(/o) { print "FUNC($1)\n" if ($dbg_values > 1); $type = 'V'; $av_pending = 'V'; } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) { if (defined $2 && $type eq 'C' || $type eq 'T') { $av_pend_colon = 'B'; } elsif ($type eq 'E') { $av_pend_colon = 'L'; } print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1); $type = 'V'; } elsif ($cur =~ /^($Ident|$Constant)/o) { print "IDENT($1)\n" if ($dbg_values > 1); $type = 'V'; } elsif ($cur =~ /^($Assignment)/o) { print "ASSIGN($1)\n" if ($dbg_values > 1); $type = 'N'; } elsif ($cur =~/^(;|{|})/) { print "END($1)\n" if ($dbg_values > 1); $type = 'E'; $av_pend_colon = 'O'; } elsif ($cur =~/^(,)/) { print "COMMA($1)\n" if ($dbg_values > 1); $type = 'C'; } elsif ($cur =~ /^(\?)/o) { print "QUESTION($1)\n" if ($dbg_values > 1); $type = 'N'; } elsif ($cur =~ /^(:)/o) { print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1); substr($var, length($res), 1, $av_pend_colon); if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') { $type = 'E'; } else { $type = 'N'; } $av_pend_colon = 'O'; } elsif ($cur =~ /^(\[)/o) { print "CLOSE($1)\n" if ($dbg_values > 1); $type = 'N'; } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) { my $variant; print "OPV($1)\n" if ($dbg_values > 1); if ($type eq 'V') { $variant = 'B'; } else { $variant = 'U'; } substr($var, length($res), 1, $variant); $type = 'N'; } elsif ($cur =~ /^($Operators)/o) { print "OP($1)\n" if ($dbg_values > 1); if ($1 ne '++' && $1 ne '--') { $type = 'N'; } } elsif ($cur =~ /(^.)/o) { print "C($1)\n" if ($dbg_values > 1); } if (defined $1) { $cur = substr($cur, length($1)); $res .= $type x length($1); } } return ($res, $var); } sub possible { my ($possible, $line) = @_; my $notPermitted = qr{(?: ^(?: $Modifier| $Storage| $Type| DEFINE_\S+ )$| ^(?: goto| return| case| else| asm|__asm__| do| \#| \#\#| )(?:\s|$)| ^(?:typedef|struct|enum)\b )}x; warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2); if ($possible !~ $notPermitted) { # Check for modifiers. $possible =~ s/\s*$Storage\s*//g; $possible =~ s/\s*$Sparse\s*//g; if ($possible =~ /^\s*$/) { } elsif ($possible =~ /\s/) { $possible =~ s/\s*$Type\s*//g; for my $modifier (split(' ', $possible)) { if ($modifier !~ $notPermitted) { warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible); push(@modifierListFile, $modifier); } } } else { warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible); push(@typeListFile, $possible); } build_types(); } else { warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1); } } my $prefix = ''; sub show_type { my ($type) = @_; $type =~ tr/[a-z]/[A-Z]/; return defined $use_type{$type} if (scalar keys %use_type > 0); return !defined $ignore_type{$type}; } sub report { my ($level, $type, $msg) = @_; if (!show_type($type) || (defined $tst_only && $msg !~ /\Q$tst_only\E/)) { return 0; } my $output = ''; if ($color) { if ($level eq 'ERROR') { $output .= RED; } elsif ($level eq 'WARNING') { $output .= YELLOW; } else { $output .= GREEN; } } $output .= $prefix . $level . ':'; if ($show_types) { $output .= BLUE if ($color); $output .= "$type:"; } $output .= RESET if ($color); $output .= ' ' . $msg . "\n"; if ($showfile) { my @lines = split("\n", $output, -1); splice(@lines, 1, 1); $output = join("\n", @lines); } if ($terse) { $output = (split('\n', $output))[0] . "\n"; } if ($verbose && exists($verbose_messages{$type}) && !exists($verbose_emitted{$type})) { $output .= $verbose_messages{$type} . "\n\n"; $verbose_emitted{$type} = 1; } push(our @report, $output); return 1; } sub report_dump { our @report; } sub fixup_current_range { my ($lineRef, $offset, $length) = @_; if ($$lineRef =~ /^\@\@ -\d+,\d+ \+(\d+),(\d+) \@\@/) { my $o = $1; my $l = $2; my $no = $o + $offset; my $nl = $l + $length; $$lineRef =~ s/\+$o,$l \@\@/\+$no,$nl \@\@/; } } sub fix_inserted_deleted_lines { my ($linesRef, $insertedRef, $deletedRef) = @_; my $range_last_linenr = 0; my $delta_offset = 0; my $old_linenr = 0; my $new_linenr = 0; my $next_insert = 0; my $next_delete = 0; my @lines = (); my $inserted = @{$insertedRef}[$next_insert++]; my $deleted = @{$deletedRef}[$next_delete++]; foreach my $old_line (@{$linesRef}) { my $save_line = 1; my $line = $old_line; #don't modify the array if ($line =~ /^(?:\+\+\+|\-\-\-)\s+\S+/) { #new filename $delta_offset = 0; } elsif ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@/) { #new hunk $range_last_linenr = $new_linenr; fixup_current_range(\$line, $delta_offset, 0); } while (defined($deleted) && ${$deleted}{'LINENR'} == $old_linenr) { $deleted = @{$deletedRef}[$next_delete++]; $save_line = 0; fixup_current_range(\$lines[$range_last_linenr], $delta_offset--, -1); } while (defined($inserted) && ${$inserted}{'LINENR'} == $old_linenr) { push(@lines, ${$inserted}{'LINE'}); $inserted = @{$insertedRef}[$next_insert++]; $new_linenr++; fixup_current_range(\$lines[$range_last_linenr], $delta_offset++, 1); } if ($save_line) { push(@lines, $line); $new_linenr++; } $old_linenr++; } return @lines; } sub fix_insert_line { my ($linenr, $line) = @_; my $inserted = { LINENR => $linenr, LINE => $line, }; push(@fixed_inserted, $inserted); } sub fix_delete_line { my ($linenr, $line) = @_; my $deleted = { LINENR => $linenr, LINE => $line, }; push(@fixed_deleted, $deleted); } sub ERROR { my ($type, $msg) = @_; if (report("ERROR", $type, $msg)) { our $clean = 0; our $cnt_error++; return 1; } return 0; } sub WARN { my ($type, $msg) = @_; if (report("WARNING", $type, $msg)) { our $clean = 0; our $cnt_warn++; return 1; } return 0; } sub CHK { my ($type, $msg) = @_; if ($check && report("CHECK", $type, $msg)) { our $clean = 0; our $cnt_chk++; return 1; } return 0; } sub check_absolute_file { my ($absolute, $herecurr) = @_; my $file = $absolute; ##print "absolute<$absolute>\n"; # See if any suffix of this path is a path within the tree. while ($file =~ s@^[^/]*/@@) { if (-f "$root/$file") { ##print "file<$file>\n"; last; } } if (! -f _) { return 0; } # It is, so see if the prefix is acceptable. my $prefix = $absolute; substr($prefix, -length($file)) = ''; ##print "prefix<$prefix>\n"; if ($prefix ne ".../") { WARN("USE_RELATIVE_PATH", "use relative pathname instead of absolute in changelog text\n" . $herecurr); } } sub trim { my ($string) = @_; $string =~ s/^\s+|\s+$//g; return $string; } sub ltrim { my ($string) = @_; $string =~ s/^\s+//; return $string; } sub rtrim { my ($string) = @_; $string =~ s/\s+$//; return $string; } sub string_find_replace { my ($string, $find, $replace) = @_; $string =~ s/$find/$replace/g; return $string; } sub tabify { my ($leading) = @_; my $source_indent = $tabsize; my $max_spaces_before_tab = $source_indent - 1; my $spaces_to_tab = " " x $source_indent; #convert leading spaces to tabs 1 while $leading =~ s@^([\t]*)$spaces_to_tab@$1\t@g; #Remove spaces before a tab 1 while $leading =~ s@^([\t]*)( {1,$max_spaces_before_tab})\t@$1\t@g; return "$leading"; } sub pos_last_openparen { my ($line) = @_; my $pos = 0; my $opens = $line =~ tr/\(/\(/; my $closes = $line =~ tr/\)/\)/; my $last_openparen = 0; if (($opens == 0) || ($closes >= $opens)) { return -1; } my $len = length($line); for ($pos = 0; $pos < $len; $pos++) { my $string = substr($line, $pos); if ($string =~ /^($FuncArg|$balanced_parens)/) { $pos += length($1) - 1; } elsif (substr($line, $pos, 1) eq '(') { $last_openparen = $pos; } elsif (index($string, '(') == -1) { last; } } return length(expand_tabs(substr($line, 0, $last_openparen))) + 1; } sub get_raw_comment { my ($line, $rawline) = @_; my $comment = ''; for my $i (0 .. (length($line) - 1)) { if (substr($line, $i, 1) eq "$;") { $comment .= substr($rawline, $i, 1); } } return $comment; } sub exclude_global_initialisers { my ($realfile) = @_; # Do not check for BPF programs (tools/testing/selftests/bpf/progs/*.c, samples/bpf/*_kern.c, *.bpf.c). return $realfile =~ m@^tools/testing/selftests/bpf/progs/.*\.c$@ || $realfile =~ m@^samples/bpf/.*_kern\.c$@ || $realfile =~ m@/bpf/.*\.bpf\.c$@; } sub is_userspace { my ($realfile) = @_; return ($realfile =~ m@^tools/@ || $realfile =~ m@^scripts/@); } sub process { my $filename = shift; my $linenr=0; my $prevline=""; my $prevrawline=""; my $stashline=""; my $stashrawline=""; my $length; my $indent; my $previndent=0; my $stashindent=0; our $clean = 1; my $signoff = 0; my $fixes_tag = 0; my $is_revert = 0; my $needs_fixes_tag = ""; my $author = ''; my $authorsignoff = 0; my $author_sob = ''; my $is_patch = 0; my $is_binding_patch = -1; my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch my $has_patch_separator = 0; #Found a --- line my $has_commit_log = 0; #Encountered lines before patch my $commit_log_lines = 0; #Number of commit log lines my $commit_log_possible_stack_dump = 0; my $commit_log_long_line = 0; my $commit_log_has_diff = 0; my $reported_maintainer_file = 0; my $non_utf8_charset = 0; my $last_git_commit_id_linenr = -1; my $last_blank_line = 0; my $last_coalesced_string_linenr = -1; our @report = (); our $cnt_lines = 0; our $cnt_error = 0; our $cnt_warn = 0; our $cnt_chk = 0; # Trace the real file/line as we go. my $realfile = ''; my $realline = 0; my $realcnt = 0; my $here = ''; my $context_function; #undef'd unless there's a known function my $in_comment = 0; my $comment_edge = 0; my $first_line = 0; my $p1_prefix = ''; my $prev_values = 'E'; # suppression flags my %suppress_ifbraces; my %suppress_whiletrailers; my %suppress_export; my $suppress_statement = 0; my %signatures = (); # Pre-scan the patch sanitizing the lines. # Pre-scan the patch looking for any __setup documentation. # my @setup_docs = (); my $setup_docs = 0; my $camelcase_file_seeded = 0; my $checklicenseline = 1; sanitise_line_reset(); my $line; foreach my $rawline (@rawlines) { $linenr++; $line = $rawline; push(@fixed, $rawline) if ($fix); if ($rawline=~/^\+\+\+\s+(\S+)/) { $setup_docs = 0; if ($1 =~ m@Documentation/admin-guide/kernel-parameters.txt$@) { $setup_docs = 1; } #next; } if ($rawline =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) { $realline=$1-1; if (defined $2) { $realcnt=$3+1; } else { $realcnt=1+1; } $in_comment = 0; # Guestimate if this is a continuing comment. Run # the context looking for a comment "edge". If this # edge is a close comment then we must be in a comment # at context start. my $edge; my $cnt = $realcnt; for (my $ln = $linenr + 1; $cnt > 0; $ln++) { next if (defined $rawlines[$ln - 1] && $rawlines[$ln - 1] =~ /^-/); $cnt--; #print "RAW<$rawlines[$ln - 1]>\n"; last if (!defined $rawlines[$ln - 1]); if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ && $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) { ($edge) = $1; last; } } if (defined $edge && $edge eq '*/') { $in_comment = 1; } # Guestimate if this is a continuing comment. If this # is the start of a diff block and this line starts # ' *' then it is very likely a comment. if (!defined $edge && $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@) { $in_comment = 1; } ##print "COMMENT:$in_comment edge<$edge> $rawline\n"; sanitise_line_reset($in_comment); } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) { # Standardise the strings and chars within the input to # simplify matching -- only bother with positive lines. $line = sanitise_line($rawline); } push(@lines, $line); if ($realcnt > 1) { $realcnt-- if ($line =~ /^(?:\+| |$)/); } else { $realcnt = 0; } #print "==>$rawline\n"; #print "-->$line\n"; if ($setup_docs && $line =~ /^\+/) { push(@setup_docs, $line); } } $prefix = ''; $realcnt = 0; $linenr = 0; $fixlinenr = -1; foreach my $line (@lines) { $linenr++; $fixlinenr++; my $sline = $line; #copy of $line $sline =~ s/$;/ /g; #with comments as spaces my $rawline = $rawlines[$linenr - 1]; my $raw_comment = get_raw_comment($line, $rawline); # check if it's a mode change, rename or start of a patch if (!$in_commit_log && ($line =~ /^ mode change [0-7]+ => [0-7]+ \S+\s*$/ || ($line =~ /^rename (?:from|to) \S+\s*$/ || $line =~ /^diff --git a\/[\w\/\.\_\-]+ b\/\S+\s*$/))) { $is_patch = 1; } #extract the line range in the file after the patch is applied if (!$in_commit_log && $line =~ /^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@(.*)/) { my $context = $4; $is_patch = 1; $first_line = $linenr + 1; $realline=$1-1; if (defined $2) { $realcnt=$3+1; } else { $realcnt=1+1; } annotate_reset(); $prev_values = 'E'; %suppress_ifbraces = (); %suppress_whiletrailers = (); %suppress_export = (); $suppress_statement = 0; if ($context =~ /\b(\w+)\s*\(/) { $context_function = $1; } else { undef $context_function; } next; # track the line number as we move through the hunk, note that # new versions of GNU diff omit the leading space on completely # blank context lines so we need to count that too. } elsif ($line =~ /^( |\+|$)/) { $realline++; $realcnt-- if ($realcnt != 0); # Measure the line length and indent. ($length, $indent) = line_stats($rawline); # Track the previous line. ($prevline, $stashline) = ($stashline, $line); ($previndent, $stashindent) = ($stashindent, $indent); ($prevrawline, $stashrawline) = ($stashrawline, $rawline); #warn "line<$line>\n"; } elsif ($realcnt == 1) { $realcnt--; } my $hunk_line = ($realcnt != 0); $here = "#$linenr: " if (!$file); $here = "#$realline: " if ($file); my $found_file = 0; # extract the filename as it passes if ($line =~ /^diff --git.*?(\S+)$/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; $found_file = 1; } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); $in_commit_log = 0; $p1_prefix = $1; if (!$file && $tree && $p1_prefix ne '' && -e "$root/$p1_prefix") { WARN("PATCH_PREFIX", "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); } if ($realfile =~ m@^include/asm/@) { ERROR("MODIFIED_INCLUDE_ASM", "do not modify files in include/asm, change architecture specific files in arch//include/asm\n" . "$here$rawline\n"); } $found_file = 1; } #make up the handle for any error we report on this line if ($showfile) { $prefix = "$realfile:$realline: " } elsif ($emacs) { if ($file) { $prefix = "$filename:$realline: "; } else { $prefix = "$filename:$linenr: "; } } if ($found_file) { if (is_maintained_obsolete($realfile)) { WARN("OBSOLETE", "$realfile is marked as 'obsolete' in the MAINTAINERS hierarchy. No unnecessary modifications please.\n"); } if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { $check = 1; } else { $check = $check_orig; } $checklicenseline = 1; if ($realfile !~ /^MAINTAINERS/) { my $last_binding_patch = $is_binding_patch; $is_binding_patch = () = $realfile =~ m@^(?:Documentation/devicetree/|include/dt-bindings/)@; if (($last_binding_patch != -1) && ($last_binding_patch ^ $is_binding_patch)) { WARN("DT_SPLIT_BINDING_PATCH", "DT binding docs and includes should be a separate patch. See: Documentation/devicetree/bindings/submitting-patches.rst\n"); } } next; } $here .= "FILE: $realfile:$realline:" if ($realcnt != 0); my $hereline = "$here\n$rawline\n"; my $herecurr = "$here\n$rawline\n"; my $hereprev = "$here\n$prevrawline\n$rawline\n"; $cnt_lines++ if ($realcnt != 0); # Verify the existence of a commit log if appropriate # 2 is used because a $signature is counted in $commit_log_lines if ($in_commit_log) { if ($line !~ /^\s*$/) { $commit_log_lines++; #could be a $signature } } elsif ($has_commit_log && $commit_log_lines < 2) { WARN("COMMIT_MESSAGE", "Missing commit description - Add an appropriate one\n"); $commit_log_lines = 2; #warn only once } # Check if the commit log has what seems like a diff which can confuse patch if ($in_commit_log && !$commit_log_has_diff && (($line =~ m@^\s+diff\b.*a/([\w/]+)@ && $line =~ m@^\s+diff\b.*a/[\w/]+\s+b/$1\b@) || $line =~ m@^\s*(?:\-\-\-\s+a/|\+\+\+\s+b/)@ || $line =~ m/^\s*\@\@ \-\d+,\d+ \+\d+,\d+ \@\@/)) { ERROR("DIFF_IN_COMMIT_MSG", "Avoid using diff content in the commit message - patch(1) might not work\n" . $herecurr); $commit_log_has_diff = 1; } # Check for incorrect file permissions if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { my $permhere = $here . "FILE: $realfile\n"; if ($realfile !~ m@scripts/@ && $realfile !~ /\.(py|pl|awk|sh)$/) { ERROR("EXECUTE_PERMISSIONS", "do not set execute permissions for source files\n" . $permhere); } } # Check the patch for a From: if (decode("MIME-Header", $line) =~ /^From:\s*(.*)/) { $author = $1; my $curline = $linenr; while(defined($rawlines[$curline]) && ($rawlines[$curline++] =~ /^[ \t]\s*(.*)/)) { $author .= $1; } $author = encode("utf8", $author) if ($line =~ /=\?utf-8\?/i); $author =~ s/"//g; $author = reformat_email($author); } # Check the patch for a signoff: if ($line =~ /^\s*signed-off-by:\s*(.*)/i) { $signoff++; $in_commit_log = 0; if ($author ne '' && $authorsignoff != 1) { if (same_email_addresses($1, $author)) { $authorsignoff = 1; } else { my $ctx = $1; my ($email_name, $email_comment, $email_address, $comment1) = parse_email($ctx); my ($author_name, $author_comment, $author_address, $comment2) = parse_email($author); if (lc $email_address eq lc $author_address && $email_name eq $author_name) { $author_sob = $ctx; $authorsignoff = 2; } elsif (lc $email_address eq lc $author_address) { $author_sob = $ctx; $authorsignoff = 3; } elsif ($email_name eq $author_name) { $author_sob = $ctx; $authorsignoff = 4; my $address1 = $email_address; my $address2 = $author_address; if ($address1 =~ /(\S+)\+\S+(\@.*)/) { $address1 = "$1$2"; } if ($address2 =~ /(\S+)\+\S+(\@.*)/) { $address2 = "$1$2"; } if ($address1 eq $address2) { $authorsignoff = 5; } } } } } # Check for invalid patch separator if ($in_commit_log && $line =~ /^---.+/) { if (ERROR("BAD_COMMIT_SEPARATOR", "Invalid commit separator - some tools may have problems applying this\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/-/=/g; } } # Check for patch separator if ($line =~ /^---$/) { $has_patch_separator = 1; $in_commit_log = 0; } # Check if MAINTAINERS is being updated. If so, there's probably no need to # emit the "does MAINTAINERS need updating?" message on file add/move/delete if ($line =~ /^\s*MAINTAINERS\s*\|/) { $reported_maintainer_file = 1; } # Check signature styles if (!$in_header_lines && $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) { my $space_before = $1; my $sign_off = $2; my $space_after = $3; my $email = $4; my $ucfirst_sign_off = ucfirst(lc($sign_off)); if ($sign_off !~ /$signature_tags/) { my $suggested_signature = find_standard_signature($sign_off); if ($suggested_signature eq "") { WARN("BAD_SIGN_OFF", "Non-standard signature: $sign_off\n" . $herecurr); } else { if (WARN("BAD_SIGN_OFF", "Non-standard signature: '$sign_off' - perhaps '$suggested_signature'?\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/$sign_off/$suggested_signature/; } } } if (defined $space_before && $space_before ne "") { if (WARN("BAD_SIGN_OFF", "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr) && $fix) { $fixed[$fixlinenr] = "$ucfirst_sign_off $email"; } } if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) { if (WARN("BAD_SIGN_OFF", "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr) && $fix) { $fixed[$fixlinenr] = "$ucfirst_sign_off $email"; } } if (!defined $space_after || $space_after ne " ") { if (WARN("BAD_SIGN_OFF", "Use a single space after $ucfirst_sign_off\n" . $herecurr) && $fix) { $fixed[$fixlinenr] = "$ucfirst_sign_off $email"; } } my ($email_name, $name_comment, $email_address, $comment) = parse_email($email); my $suggested_email = format_email(($email_name, $name_comment, $email_address, $comment)); if ($suggested_email eq "") { ERROR("BAD_SIGN_OFF", "Unrecognized email address: '$email'\n" . $herecurr); } else { my $dequoted = $suggested_email; $dequoted =~ s/^"//; $dequoted =~ s/" 1) { WARN("BAD_SIGN_OFF", "Use a single name comment in email: '$email'\n" . $herecurr); } # stable@vger.kernel.org or stable@kernel.org shouldn't # have an email name. In addition comments should strictly # begin with a # if ($email =~ /^.*stable\@(?:vger\.)?kernel\.org/i) { if (($comment ne "" && $comment !~ /^#.+/) || ($email_name ne "")) { my $cur_name = $email_name; my $new_comment = $comment; $cur_name =~ s/[a-zA-Z\s\-\"]+//g; # Remove brackets enclosing comment text # and # from start of comments to get comment text $new_comment =~ s/^\((.*)\)$/$1/; $new_comment =~ s/^\[(.*)\]$/$1/; $new_comment =~ s/^[\s\#]+|\s+$//g; $new_comment = trim("$new_comment $cur_name") if ($cur_name ne $new_comment); $new_comment = " # $new_comment" if ($new_comment ne ""); my $new_email = "$email_address$new_comment"; if (WARN("BAD_STABLE_ADDRESS_STYLE", "Invalid email format for stable: '$email', prefer '$new_email'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; } } } elsif ($comment ne "" && $comment !~ /^(?:#.+|\(.+\))$/) { my $new_comment = $comment; # Extract comment text from within brackets or # c89 style /*...*/ comments $new_comment =~ s/^\[(.*)\]$/$1/; $new_comment =~ s/^\/\*(.*)\*\/$/$1/; $new_comment = trim($new_comment); $new_comment =~ s/^[^\w]$//; # Single lettered comment with non word character is usually a typo $new_comment = "($new_comment)" if ($new_comment ne ""); my $new_email = format_email($email_name, $name_comment, $email_address, $new_comment); if (WARN("BAD_SIGN_OFF", "Unexpected content after email: '$email', should be: '$new_email'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$email\E/$new_email/; } } } # Check for duplicate signatures my $sig_nospace = $line; $sig_nospace =~ s/\s//g; $sig_nospace = lc($sig_nospace); if (defined $signatures{$sig_nospace}) { WARN("BAD_SIGN_OFF", "Duplicate signature\n" . $herecurr); } else { $signatures{$sig_nospace} = 1; } # Check Co-developed-by: immediately followed by Signed-off-by: with same name and email if ($sign_off =~ /^co-developed-by:$/i) { if ($email eq $author) { WARN("BAD_SIGN_OFF", "Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . $herecurr); } if (!defined $lines[$linenr]) { WARN("BAD_SIGN_OFF", "Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr); } elsif ($rawlines[$linenr] !~ /^signed-off-by:\s*(.*)/i) { WARN("BAD_SIGN_OFF", "Co-developed-by: must be immediately followed by Signed-off-by:\n" . $herecurr . $rawlines[$linenr] . "\n"); } elsif ($1 ne $email) { WARN("BAD_SIGN_OFF", "Co-developed-by and Signed-off-by: name/email do not match\n" . $herecurr . $rawlines[$linenr] . "\n"); } } # check if Reported-by: is followed by a Closes: tag if ($sign_off =~ /^reported(?:|-and-tested)-by:$/i) { if (!defined $lines[$linenr]) { WARN("BAD_REPORTED_BY_LINK", "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . "\n"); } elsif ($rawlines[$linenr] !~ /^closes:\s*/i) { WARN("BAD_REPORTED_BY_LINK", "Reported-by: should be immediately followed by Closes: with a URL to the report\n" . $herecurr . $rawlines[$linenr] . "\n"); } } } # These indicate a bug fix if (!$in_header_lines && !$is_patch && $line =~ /^This reverts commit/) { $is_revert = 1; } if (!$in_header_lines && !$is_patch && $line =~ /((?:(?:BUG: K.|UB)SAN: |Call Trace:|stable\@|syzkaller))/) { $needs_fixes_tag = $1; } # Check Fixes: styles is correct if (!$in_header_lines && $line =~ /^\s*(fixes:?)\s*(?:commit\s*)?([0-9a-f]{5,40})(?:\s*($balanced_parens))?/i) { my $tag = $1; my $orig_commit = $2; my $title; my $title_has_quotes = 0; $fixes_tag = 1; if (defined $3) { # Always strip leading/trailing parens then double quotes if existing $title = substr($3, 1, -1); if ($title =~ /^".*"$/) { $title = substr($title, 1, -1); $title_has_quotes = 1; } } else { $title = "commit title" } my $tag_case = not ($tag eq "Fixes:"); my $tag_space = not ($line =~ /^fixes:? [0-9a-f]{5,40} ($balanced_parens)/i); my $id_length = not ($orig_commit =~ /^[0-9a-f]{12,40}$/i); my $id_case = not ($orig_commit !~ /[A-F]/); my $id = "0123456789ab"; my ($cid, $ctitle) = git_commit_info($orig_commit, $id, $title); if (defined($cid) && ($ctitle ne $title || $tag_case || $tag_space || $id_length || $id_case || !$title_has_quotes)) { my $fixed = "Fixes: $cid (\"$ctitle\")"; if (WARN("BAD_FIXES_TAG", "Please use correct Fixes: style 'Fixes: <12+ chars of sha1> (\"\")' - ie: '$fixed'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] = $fixed; } } } # Check email subject for common tools that don't need to be mentioned if ($in_header_lines && $line =~ /^Subject:.*\b(?:checkpatch|sparse|smatch)\b[^:]/i) { WARN("EMAIL_SUBJECT", "A patch subject line should describe the change not the tool that found it\n" . $herecurr); } # Check for Gerrit Change-Ids not in any patch context if ($realfile eq '' && !$has_patch_separator && $line =~ /^\s*change-id:/i) { if (ERROR("GERRIT_CHANGE_ID", "Remove Gerrit Change-Id's before submitting upstream\n" . $herecurr) && $fix) { fix_delete_line($fixlinenr, $rawline); } } # Check if the commit log is in a possible stack dump if ($in_commit_log && !$commit_log_possible_stack_dump && ($line =~ /^\s*(?:WARNING:|BUG:)/ || $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || # timestamp $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/) || $line =~ /^(?:\s+\w+:\s+[0-9a-fA-F]+){3,3}/ || $line =~ /^\s*\#\d+\s*\[[0-9a-fA-F]+\]\s*\w+ at [0-9a-fA-F]+/) { # stack dump address styles $commit_log_possible_stack_dump = 1; } # Check for line lengths > 75 in commit log, warn once if ($in_commit_log && !$commit_log_long_line && length($line) > 75 && !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || # file delta changes $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ || # filename then : $line =~ /^\s*(?:Fixes:|https?:|$link_tags_search|$signature_tags)/i || # A Fixes:, link or signature tag line $commit_log_possible_stack_dump)) { WARN("COMMIT_LOG_LONG_LINE", "Prefer a maximum 75 chars per line (possible unwrapped commit description?)\n" . $herecurr); $commit_log_long_line = 1; } # Reset possible stack dump if a blank line is found if ($in_commit_log && $commit_log_possible_stack_dump && $line =~ /^\s*$/) { $commit_log_possible_stack_dump = 0; } # Check for odd tags before a URI/URL if ($in_commit_log && $line =~ /^\s*(\w+:)\s*http/ && $1 !~ /^$link_tags_search$/) { if ($1 =~ /^v(?:ersion)?\d+/i) { WARN("COMMIT_LOG_VERSIONING", "Patch version information should be after the --- line\n" . $herecurr); } else { WARN("COMMIT_LOG_USE_LINK", "Unknown link reference '$1', use $link_tags_print instead\n" . $herecurr); } } # Check for misuse of the link tags if ($in_commit_log && $line =~ /^\s*(\w+:)\s*(\S+)/) { my $tag = $1; my $value = $2; if ($tag =~ /^$link_tags_search$/ && $value !~ m{^https?://}) { WARN("COMMIT_LOG_WRONG_LINK", "'$tag' should be followed by a public http(s) link\n" . $herecurr); } } # Check for lines starting with a # if ($in_commit_log && $line =~ /^#/) { if (WARN("COMMIT_COMMENT_SYMBOL", "Commit log lines starting with '#' are dropped by git as comments\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^/ /; } } # Check for auto-generated unhandled placeholder text (mostly for cover letters) if (($in_commit_log || $in_header_lines) && $rawline =~ /(?:SUBJECT|BLURB) HERE/) { ERROR("PLACEHOLDER_USE", "Placeholder text detected\n" . $herecurr); } # Check for git id commit length and improperly formed commit descriptions # A correctly formed commit description is: # commit <SHA-1 hash length 12+ chars> ("Complete commit subject") # with the commit subject '("' prefix and '")' suffix # This is a fairly compilicated block as it tests for what appears to be # bare SHA-1 hash with minimum length of 5. It also avoids several types of # possible SHA-1 matches. # A commit match can span multiple lines so this block attempts to find a # complete typical commit on a maximum of 3 lines if ($perl_version_ok && $in_commit_log && !$commit_log_possible_stack_dump && $line !~ /^\s*(?:Link|Patchwork|http|https|BugLink|base-commit):/i && $line !~ /^This reverts commit [0-9a-f]{7,40}/ && (($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || ($line =~ /\bcommit\s*$/i && defined($rawlines[$linenr]) && $rawlines[$linenr] =~ /^\s*[0-9a-f]{5,}\b/i)) || ($line =~ /(?:\s|^)[0-9a-f]{12,40}(?:[\s"'\(\[]|$)/i && $line !~ /[\<\[][0-9a-f]{12,40}[\>\]]/i && $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) { my $init_char = "c"; my $orig_commit = ""; my $short = 1; my $long = 0; my $case = 1; my $space = 1; my $id = '0123456789ab'; my $orig_desc = "commit description"; my $description = ""; my $herectx = $herecurr; my $has_parens = 0; my $has_quotes = 0; my $input = $line; if ($line =~ /(?:\bcommit\s+[0-9a-f]{5,}|\bcommit\s*$)/i) { for (my $n = 0; $n < 2; $n++) { if ($input =~ /\bcommit\s+[0-9a-f]{5,}\s*($balanced_parens)/i) { $orig_desc = $1; $has_parens = 1; # Always strip leading/trailing parens then double quotes if existing $orig_desc = substr($orig_desc, 1, -1); if ($orig_desc =~ /^".*"$/) { $orig_desc = substr($orig_desc, 1, -1); $has_quotes = 1; } last; } last if ($#lines < $linenr + $n); $input .= " " . trim($rawlines[$linenr + $n]); $herectx .= "$rawlines[$linenr + $n]\n"; } $herectx = $herecurr if (!$has_parens); } if ($input =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { $init_char = $1; $orig_commit = lc($2); $short = 0 if ($input =~ /\bcommit\s+[0-9a-f]{12,40}/i); $long = 1 if ($input =~ /\bcommit\s+[0-9a-f]{41,}/i); $space = 0 if ($input =~ /\bcommit [0-9a-f]/i); $case = 0 if ($input =~ /\b[Cc]ommit\s+[0-9a-f]{5,40}[^A-F]/); } elsif ($input =~ /\b([0-9a-f]{12,40})\b/i) { $orig_commit = lc($1); } ($id, $description) = git_commit_info($orig_commit, $id, $orig_desc); if (defined($id) && ($short || $long || $space || $case || ($orig_desc ne $description) || !$has_quotes) && $last_git_commit_id_linenr != $linenr - 1) { ERROR("GIT_COMMIT_ID", "Please use git commit description style 'commit <12+ chars of sha1> (\"<title line>\")' - ie: '${init_char}ommit $id (\"$description\")'\n" . $herectx); } #don't report the next line if this line ends in commit and the sha1 hash is the next line $last_git_commit_id_linenr = $linenr if ($line =~ /\bcommit\s*$/i); } # Check for mailing list archives other than lore.kernel.org if ($rawline =~ m{http.*\b$obsolete_archives}) { WARN("PREFER_LORE_ARCHIVE", "Use lore.kernel.org archive links when possible - see https://lore.kernel.org/lists.html\n" . $herecurr); } # Check for added, moved or deleted files if (!$reported_maintainer_file && !$in_commit_log && ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && (defined($1) || defined($2))))) { $is_patch = 1; $reported_maintainer_file = 1; WARN("FILE_PATH_CHANGES", "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); } # Check for adding new DT bindings not in schema format if (!$in_commit_log && ($line =~ /^new file mode\s*\d+\s*$/) && ($realfile =~ m@^Documentation/devicetree/bindings/.*\.txt$@)) { WARN("DT_SCHEMA_BINDING_PATCH", "DT bindings should be in DT schema format. See: Documentation/devicetree/bindings/writing-schema.rst\n"); } # Check for wrappage within a valid hunk of the file if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) { ERROR("CORRUPTED_PATCH", "patch seems to be corrupt (line wrapped?)\n" . $herecurr) if (!$emitted_corrupt++); } # UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php if (($realfile =~ /^$/ || $line =~ /^\+/) && $rawline !~ m/^$UTF8*$/) { my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/); my $blank = copy_spacing($rawline); my $ptr = substr($blank, 0, length($utf8_prefix)) . "^"; my $hereptr = "$hereline$ptr\n"; CHK("INVALID_UTF8", "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr); } # Check if it's the start of a commit log # (not a header line and we haven't seen the patch filename) if ($in_header_lines && $realfile =~ /^$/ && !($rawline =~ /^\s+(?:\S|$)/ || $rawline =~ /^(?:commit\b|from\b|[\w-]+:)/i)) { $in_header_lines = 0; $in_commit_log = 1; $has_commit_log = 1; } # Check if there is UTF-8 in a commit log when a mail header has explicitly # declined it, i.e defined some charset where it is missing. if ($in_header_lines && $rawline =~ /^Content-Type:.+charset="(.+)".*$/ && $1 !~ /utf-8/i) { $non_utf8_charset = 1; } if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ && $rawline =~ /$NON_ASCII_UTF8/) { WARN("UTF8_BEFORE_PATCH", "8-bit UTF-8 used in possible commit log\n" . $herecurr); } # Check for absolute kernel paths in commit message if ($tree && $in_commit_log) { while ($line =~ m{(?:^|\s)(/\S*)}g) { my $file = $1; if ($file =~ m{^(.*?)(?::\d+)+:?$} && check_absolute_file($1, $herecurr)) { # } else { check_absolute_file($file, $herecurr); } } } # Check for various typo / spelling mistakes if (defined($misspellings) && ($in_commit_log || $line =~ /^(?:\+|Subject:)/i)) { my $rawline_utf8 = decode("utf8", $rawline); while ($rawline_utf8 =~ /(?:^|[^\w\-'`])($misspellings)(?:[^\w\-'`]|$)/gi) { my $typo = $1; my $blank = copy_spacing($rawline_utf8); my $ptr = substr($blank, 0, $-[1]) . "^" x length($typo); my $hereptr = "$hereline$ptr\n"; my $typo_fix = $spelling_fix{lc($typo)}; $typo_fix = ucfirst($typo_fix) if ($typo =~ /^[A-Z]/); $typo_fix = uc($typo_fix) if ($typo =~ /^[A-Z]+$/); my $msg_level = \&WARN; $msg_level = \&CHK if ($file); if (&{$msg_level}("TYPO_SPELLING", "'$typo' may be misspelled - perhaps '$typo_fix'?\n" . $hereptr) && $fix) { $fixed[$fixlinenr] =~ s/(^|[^A-Za-z@])($typo)($|[^A-Za-z@])/$1$typo_fix$3/; } } } # check for invalid commit id if ($in_commit_log && $line =~ /(^fixes:|\bcommit)\s+([0-9a-f]{6,40})\b/i) { my $id; my $description; ($id, $description) = git_commit_info($2, undef, undef); if (!defined($id)) { WARN("UNKNOWN_COMMIT_ID", "Unknown commit id '$2', maybe rebased or not pulled?\n" . $herecurr); } } # check for repeated words separated by a single space # avoid false positive from list command eg, '-rw-r--r-- 1 root root' if (($rawline =~ /^\+/ || $in_commit_log) && $rawline !~ /[bcCdDlMnpPs\?-][rwxsStT-]{9}/) { pos($rawline) = 1 if (!$in_commit_log); while ($rawline =~ /\b($word_pattern) (?=($word_pattern))/g) { my $first = $1; my $second = $2; my $start_pos = $-[1]; my $end_pos = $+[2]; if ($first =~ /(?:struct|union|enum)/) { pos($rawline) += length($first) + length($second) + 1; next; } next if (lc($first) ne lc($second)); next if ($first eq 'long'); # check for character before and after the word matches my $start_char = ''; my $end_char = ''; $start_char = substr($rawline, $start_pos - 1, 1) if ($start_pos > ($in_commit_log ? 0 : 1)); $end_char = substr($rawline, $end_pos, 1) if ($end_pos < length($rawline)); next if ($start_char =~ /^\S$/); next if (index(" \t.,;?!", $end_char) == -1); # avoid repeating hex occurrences like 'ff ff fe 09 ...' if ($first =~ /\b[0-9a-f]{2,}\b/i) { next if (!exists($allow_repeated_words{lc($first)})); } if (WARN("REPEATED_WORD", "Possible repeated word: '$first'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b$first $second\b/$first/; } } # if it's a repeated word on consecutive lines in a comment block if ($prevline =~ /$;+\s*$/ && $prevrawline =~ /($word_pattern)\s*$/) { my $last_word = $1; if ($rawline =~ /^\+\s*\*\s*$last_word /) { if (WARN("REPEATED_WORD", "Possible repeated word: '$last_word'\n" . $hereprev) && $fix) { $fixed[$fixlinenr] =~ s/(\+\s*\*\s*)$last_word /$1/; } } } } # ignore non-hunk lines and lines being removed next if (!$hunk_line || $line =~ /^-/); #trailing whitespace if ($line =~ /^\+.*\015/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; if (ERROR("DOS_LINE_ENDINGS", "DOS line endings\n" . $herevet) && $fix) { $fixed[$fixlinenr] =~ s/[\s\015]+$//; } } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; if (ERROR("TRAILING_WHITESPACE", "trailing whitespace\n" . $herevet) && $fix) { $fixed[$fixlinenr] =~ s/\s+$//; } $rpt_cleaners = 1; } # Check for FSF mailing addresses. if ($rawline =~ /\bwrite to the Free/i || $rawline =~ /\b675\s+Mass\s+Ave/i || $rawline =~ /\b59\s+Temple\s+Pl/i || $rawline =~ /\b51\s+Franklin\s+St/i) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; my $msg_level = \&ERROR; $msg_level = \&CHK if ($file); &{$msg_level}("FSF_MAILING_ADDRESS", "Do not include the paragraph about writing to the Free Software Foundation's mailing address from the sample GPL notice. The FSF has changed addresses in the past, and may do so again. Linux already includes a copy of the GPL.\n" . $herevet) } # check for Kconfig help text having a real description # Only applies when adding the entry originally, after that we do not have # sufficient context to determine whether it is indeed long enough. if ($realfile =~ /Kconfig/ && # 'choice' is usually the last thing on the line (though # Kconfig supports named choices), so use a word boundary # (\b) rather than a whitespace character (\s) $line =~ /^\+\s*(?:config|menuconfig|choice)\b/) { my $ln = $linenr; my $needs_help = 0; my $has_help = 0; my $help_length = 0; while (defined $lines[$ln]) { my $f = $lines[$ln++]; next if ($f =~ /^-/); last if ($f !~ /^[\+ ]/); # !patch context if ($f =~ /^\+\s*(?:bool|tristate|prompt)\s*["']/) { $needs_help = 1; next; } if ($f =~ /^\+\s*help\s*$/) { $has_help = 1; next; } $f =~ s/^.//; # strip patch context [+ ] $f =~ s/#.*//; # strip # directives $f =~ s/^\s+//; # strip leading blanks next if ($f =~ /^$/); # skip blank lines # At the end of this Kconfig block: # This only checks context lines in the patch # and so hopefully shouldn't trigger false # positives, even though some of these are # common words in help texts if ($f =~ /^(?:config|menuconfig|choice|endchoice| if|endif|menu|endmenu|source)\b/x) { last; } $help_length++ if ($has_help); } if ($needs_help && $help_length < $min_conf_desc_length) { my $stat_real = get_stat_real($linenr, $ln - 1); WARN("CONFIG_DESCRIPTION", "please write a help paragraph that fully describes the config symbol with at least $min_conf_desc_length lines\n" . "$here\n$stat_real\n"); } } # check MAINTAINERS entries if ($realfile =~ /^MAINTAINERS$/) { # check MAINTAINERS entries for the right form if ($rawline =~ /^\+[A-Z]:/ && $rawline !~ /^\+[A-Z]:\t\S/) { if (WARN("MAINTAINERS_STYLE", "MAINTAINERS entries use one tab after TYPE:\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(\+[A-Z]):\s*/$1:\t/; } } # check MAINTAINERS entries for the right ordering too my $preferred_order = 'MRLSWQBCPTFXNK'; if ($rawline =~ /^\+[A-Z]:/ && $prevrawline =~ /^[\+ ][A-Z]:/) { $rawline =~ /^\+([A-Z]):\s*(.*)/; my $cur = $1; my $curval = $2; $prevrawline =~ /^[\+ ]([A-Z]):\s*(.*)/; my $prev = $1; my $prevval = $2; my $curindex = index($preferred_order, $cur); my $previndex = index($preferred_order, $prev); if ($curindex < 0) { WARN("MAINTAINERS_STYLE", "Unknown MAINTAINERS entry type: '$cur'\n" . $herecurr); } else { if ($previndex >= 0 && $curindex < $previndex) { WARN("MAINTAINERS_STYLE", "Misordered MAINTAINERS entry - list '$cur:' before '$prev:'\n" . $hereprev); } elsif ((($prev eq 'F' && $cur eq 'F') || ($prev eq 'X' && $cur eq 'X')) && ($prevval cmp $curval) > 0) { WARN("MAINTAINERS_STYLE", "Misordered MAINTAINERS entry - list file patterns in alphabetic order\n" . $hereprev); } } } } # check for DT compatible documentation if (defined $root && (($realfile =~ /\.dtsi?$/ && $line =~ /^\+\s*compatible\s*=\s*\"/) || ($realfile =~ /\.[ch]$/ && $line =~ /^\+.*\.compatible\s*=\s*\"/))) { my @compats = $rawline =~ /\"([a-zA-Z0-9\-\,\.\+_]+)\"/g; my $dt_path = $root . "/Documentation/devicetree/bindings/"; my $vp_file = $dt_path . "vendor-prefixes.yaml"; foreach my $compat (@compats) { my $compat2 = $compat; $compat2 =~ s/\,[a-zA-Z0-9]*\-/\,<\.\*>\-/; my $compat3 = $compat; $compat3 =~ s/\,([a-z]*)[0-9]*\-/\,$1<\.\*>\-/; `grep -Erq "$compat|$compat2|$compat3" $dt_path`; if ( $? >> 8 ) { WARN("UNDOCUMENTED_DT_STRING", "DT compatible string \"$compat\" appears un-documented -- check $dt_path\n" . $herecurr); } next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; my $vendor = $1; `grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`; if ( $? >> 8 ) { WARN("UNDOCUMENTED_DT_STRING", "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); } } } # Check for RGMII phy-mode with delay on PCB if ($realfile =~ /\.(dts|dtsi|dtso)$/ && $line =~ /^\+\s*(phy-mode|phy-connection-type)\s*=\s*"/ && !ctx_has_comment($first_line, $linenr)) { my $prop = $1; my $mode = get_quoted_string($line, $rawline); if ($mode =~ /^"rgmii(?:|-rxid|-txid)"$/) { WARN("UNCOMMENTED_RGMII_MODE", "$prop $mode without comment -- delays on the PCB should be described, otherwise use \"rgmii-id\"\n" . $herecurr); } } # check for using SPDX license tag at beginning of files if ($realline == $checklicenseline) { if ($rawline =~ /^[ \+]\s*\#\!\s*\//) { $checklicenseline = 2; } elsif ($rawline =~ /^\+/) { my $comment = ""; if ($realfile =~ /\.(h|s|S)$/) { $comment = '/*'; } elsif ($realfile =~ /\.(c|rs|dts|dtsi)$/) { $comment = '//'; } elsif (($checklicenseline == 2) || $realfile =~ /\.(sh|pl|py|awk|tc|yaml)$/) { $comment = '#'; } elsif ($realfile =~ /\.rst$/) { $comment = '..'; } # check SPDX comment style for .[chsS] files if ($realfile =~ /\.[chsS]$/ && $rawline =~ /SPDX-License-Identifier:/ && $rawline !~ m@^\+\s*\Q$comment\E\s*@) { WARN("SPDX_LICENSE_TAG", "Improper SPDX comment style for '$realfile', please use '$comment' instead\n" . $herecurr); } if ($comment !~ /^$/ && $rawline !~ m@^\+\Q$comment\E SPDX-License-Identifier: @) { WARN("SPDX_LICENSE_TAG", "Missing or malformed SPDX-License-Identifier tag in line $checklicenseline\n" . $herecurr); } elsif ($rawline =~ /(SPDX-License-Identifier: .*)/) { my $spdx_license = $1; if (!is_SPDX_License_valid($spdx_license)) { WARN("SPDX_LICENSE_TAG", "'$spdx_license' is not supported in LICENSES/...\n" . $herecurr); } if ($realfile =~ m@^Documentation/devicetree/bindings/@ && $spdx_license !~ /GPL-2\.0(?:-only)? OR BSD-2-Clause/) { my $msg_level = \&WARN; $msg_level = \&CHK if ($file); if (&{$msg_level}("SPDX_LICENSE_TAG", "DT binding documents should be licensed (GPL-2.0-only OR BSD-2-Clause)\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/SPDX-License-Identifier: .*/SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)/; } } if ($realfile =~ m@^include/dt-bindings/@ && $spdx_license !~ /GPL-2\.0(?:-only)? OR \S+/) { WARN("SPDX_LICENSE_TAG", "DT binding headers should be licensed (GPL-2.0-only OR .*)\n" . $herecurr); } } } } # check for embedded filenames if ($rawline =~ /^\+.*\b\Q$realfile\E\b/) { WARN("EMBEDDED_FILENAME", "It's generally not useful to have the filename in the file\n" . $herecurr); } # check we are in a valid source file if not then ignore this hunk next if ($realfile !~ /\.(h|c|rs|s|S|sh|dtsi|dts)$/); # check for using SPDX-License-Identifier on the wrong line number if ($realline != $checklicenseline && $rawline =~ /\bSPDX-License-Identifier:/ && substr($line, @-, @+ - @-) eq "$;" x (@+ - @-)) { WARN("SPDX_LICENSE_TAG", "Misplaced SPDX-License-Identifier tag - use line $checklicenseline instead\n" . $herecurr); } # line length limit (with some exclusions) # # There are a few types of lines that may extend beyond $max_line_length: # logging functions like pr_info that end in a string # lines with a single string # #defines that are a single string # lines with an RFC3986 like URL # # There are 3 different line length message types: # LONG_LINE_COMMENT a comment starts before but extends beyond $max_line_length # LONG_LINE_STRING a string starts before but extends beyond $max_line_length # LONG_LINE all other lines longer than $max_line_length # # if LONG_LINE is ignored, the other 2 types are also ignored # if ($line =~ /^\+/ && $length > $max_line_length) { my $msg_type = "LONG_LINE"; # Check the allowed long line types first # logging functions that end in a string that starts # before $max_line_length if ($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(?:KERN_\S+\s*|[^"]*))?($String\s*(?:|,|\)\s*;)\s*)$/ && length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { $msg_type = ""; # lines with only strings (w/ possible termination) # #defines with only strings } elsif ($line =~ /^\+\s*$String\s*(?:\s*|,|\)\s*;)\s*$/ || $line =~ /^\+\s*#\s*define\s+\w+\s+$String$/) { $msg_type = ""; # More special cases } elsif ($line =~ /^\+.*\bEFI_GUID\s*\(/ || $line =~ /^\+\s*(?:\w+)?\s*DEFINE_PER_CPU/) { $msg_type = ""; # URL ($rawline is used in case the URL is in a comment) } elsif ($rawline =~ /^\+.*\b[a-z][\w\.\+\-]*:\/\/\S+/i) { $msg_type = ""; # Otherwise set the alternate message types # a comment starts before $max_line_length } elsif ($line =~ /($;[\s$;]*)$/ && length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { $msg_type = "LONG_LINE_COMMENT" # a quoted string starts before $max_line_length } elsif ($sline =~ /\s*($String(?:\s*(?:\\|,\s*|\)\s*;\s*))?)$/ && length(expand_tabs(substr($line, 1, length($line) - length($1) - 1))) <= $max_line_length) { $msg_type = "LONG_LINE_STRING" } if ($msg_type ne "" && show_type("LONG_LINE") && show_type($msg_type)) { my $msg_level = \&WARN; $msg_level = \&CHK if ($file); &{$msg_level}($msg_type, "line length of $length exceeds $max_line_length columns\n" . $herecurr); } } # check for adding lines without a newline. if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) { if (WARN("MISSING_EOF_NEWLINE", "adding a line without newline at end of file\n" . $herecurr) && $fix) { fix_delete_line($fixlinenr+1, "No newline at end of file"); } } # check for .L prefix local symbols in .S files if ($realfile =~ /\.S$/ && $line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) { WARN("AVOID_L_PREFIX", "Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/core-api/asm-annotations.rst\n" . $herecurr); } # check we are in a valid source file C or perl if not then ignore this hunk next if ($realfile !~ /\.(h|c|pl|dtsi|dts)$/); # at the beginning of a line any tabs must come first and anything # more than $tabsize must use tabs. if ($rawline =~ /^\+\s* \t\s*\S/ || $rawline =~ /^\+\s* \s*/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; $rpt_cleaners = 1; if (ERROR("CODE_INDENT", "code indent should use tabs where possible\n" . $herevet) && $fix) { $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; } } # check for space before tabs. if ($rawline =~ /^\+/ && $rawline =~ / \t/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; if (WARN("SPACE_BEFORE_TAB", "please, no space before tabs\n" . $herevet) && $fix) { while ($fixed[$fixlinenr] =~ s/(^\+.*) {$tabsize,$tabsize}\t/$1\t\t/) {} while ($fixed[$fixlinenr] =~ s/(^\+.*) +\t/$1\t/) {} } } # check for assignments on the start of a line if ($sline =~ /^\+\s+($Assignment)[^=]/) { my $operator = $1; if (CHK("ASSIGNMENT_CONTINUATIONS", "Assignment operator '$1' should be on the previous line\n" . $hereprev) && $fix && $prevrawline =~ /^\+/) { # add assignment operator to the previous line, remove from current line $fixed[$fixlinenr - 1] .= " $operator"; $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; } } # check for && or || at the start of a line if ($rawline =~ /^\+\s*(&&|\|\|)/) { my $operator = $1; if (CHK("LOGICAL_CONTINUATIONS", "Logical continuations should be on the previous line\n" . $hereprev) && $fix && $prevrawline =~ /^\+/) { # insert logical operator at last non-comment, non-whitepsace char on previous line $prevline =~ /[\s$;]*$/; my $line_end = substr($prevrawline, $-[0]); $fixed[$fixlinenr - 1] =~ s/\Q$line_end\E$/ $operator$line_end/; $fixed[$fixlinenr] =~ s/\Q$operator\E\s*//; } } # check indentation starts on a tab stop if ($perl_version_ok && $sline =~ /^\+\t+( +)(?:$c90_Keywords\b|\{\s*$|\}\s*(?:else\b|while\b|\s*$)|$Declare\s*$Ident\s*[;=])/) { my $indent = length($1); if ($indent % $tabsize) { if (WARN("TABSTOP", "Statements should start on a tabstop\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s@(^\+\t+) +@$1 . "\t" x ($indent/$tabsize)@e; } } } # check multi-line statement indentation matches previous line if ($perl_version_ok && $prevline =~ /^\+([ \t]*)((?:$c90_Keywords(?:\s+if)\s*)|(?:$Declare\s*)?(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*|(?:\*\s*)*$Lval\s*=\s*$Ident\s*)\(.*(\&\&|\|\||,)\s*$/) { $prevline =~ /^\+(\t*)(.*)$/; my $oldindent = $1; my $rest = $2; my $pos = pos_last_openparen($rest); if ($pos >= 0) { $line =~ /^(\+| )([ \t]*)/; my $newindent = $2; my $goodtabindent = $oldindent . "\t" x ($pos / $tabsize) . " " x ($pos % $tabsize); my $goodspaceindent = $oldindent . " " x $pos; if ($newindent ne $goodtabindent && $newindent ne $goodspaceindent) { if (CHK("PARENTHESIS_ALIGNMENT", "Alignment should match open parenthesis\n" . $hereprev) && $fix && $line =~ /^\+/) { $fixed[$fixlinenr] =~ s/^\+[ \t]*/\+$goodtabindent/; } } } } # check for space after cast like "(int) foo" or "(struct foo) bar" # avoid checking a few false positives: # "sizeof(<type>)" or "__alignof__(<type>)" # function pointer declarations like "(*foo)(int) = bar;" # structure definitions like "(struct foo) { 0 };" # multiline macros that define functions # known attributes or the __attribute__ keyword if ($line =~ /^\+(.*)\(\s*$Type\s*\)([ \t]++)((?![={]|\\$|$Attribute|__attribute__))/ && (!defined($1) || $1 !~ /\b(?:sizeof|__alignof__)\s*$/)) { if (CHK("SPACING", "No space is necessary after a cast\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(\(\s*$Type\s*\))[ \t]+/$1/; } } # Block comments use * on subsequent lines if ($prevline =~ /$;[ \t]*$/ && #ends in comment $prevrawline =~ /^\+.*?\/\*/ && #starting /* $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ $rawline =~ /^\+/ && #line is new $rawline !~ /^\+[ \t]*\*/) { #no leading * WARN("BLOCK_COMMENT_STYLE", "Block comments use * on subsequent lines\n" . $hereprev); } # Block comments use */ on trailing lines if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ WARN("BLOCK_COMMENT_STYLE", "Block comments use a trailing */ on a separate line\n" . $herecurr); } # Block comment * alignment if ($prevline =~ /$;[ \t]*$/ && #ends in comment $line =~ /^\+[ \t]*$;/ && #leading comment $rawline =~ /^\+[ \t]*\*/ && #leading * (($prevrawline =~ /^\+.*?\/\*/ && #leading /* $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */ $prevrawline =~ /^\+[ \t]*\*/)) { #leading * my $oldindent; $prevrawline =~ m@^\+([ \t]*/?)\*@; if (defined($1)) { $oldindent = expand_tabs($1); } else { $prevrawline =~ m@^\+(.*/?)\*@; $oldindent = expand_tabs($1); } $rawline =~ m@^\+([ \t]*)\*@; my $newindent = $1; $newindent = expand_tabs($newindent); if (length($oldindent) ne length($newindent)) { WARN("BLOCK_COMMENT_STYLE", "Block comments should align the * on each line\n" . $hereprev); } } # check for missing blank lines after struct/union declarations # with exceptions for various attributes and macros if ($prevline =~ /^[\+ ]};?\s*$/ && $line =~ /^\+/ && !($line =~ /^\+\s*$/ || $line =~ /^\+\s*(?:EXPORT_SYMBOL|early_param|ALLOW_ERROR_INJECTION)/ || $line =~ /^\+\s*MODULE_/i || $line =~ /^\+\s*\#\s*(?:end|elif|else)/ || $line =~ /^\+[a-z_]*init/ || $line =~ /^\+\s*(?:static\s+)?[A-Z_]*ATTR/ || $line =~ /^\+\s*DECLARE/ || $line =~ /^\+\s*builtin_[\w_]*driver/ || $line =~ /^\+\s*__setup/)) { if (CHK("LINE_SPACING", "Please use a blank line after function/struct/union/enum declarations\n" . $hereprev) && $fix) { fix_insert_line($fixlinenr, "\+"); } } # check for multiple consecutive blank lines if ($prevline =~ /^[\+ ]\s*$/ && $line =~ /^\+\s*$/ && $last_blank_line != ($linenr - 1)) { if (CHK("LINE_SPACING", "Please don't use multiple blank lines\n" . $hereprev) && $fix) { fix_delete_line($fixlinenr, $rawline); } $last_blank_line = $linenr; } # check for missing blank lines after declarations # (declarations must have the same indentation and not be at the start of line) if (($prevline =~ /\+(\s+)\S/) && $sline =~ /^\+$1\S/) { # use temporaries my $sl = $sline; my $pl = $prevline; # remove $Attribute/$Sparse uses to simplify comparisons $sl =~ s/\b(?:$Attribute|$Sparse)\b//g; $pl =~ s/\b(?:$Attribute|$Sparse)\b//g; if (($pl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || # function pointer declarations $pl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || # foo bar; where foo is some local typedef or #define $pl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || # known declaration macros $pl =~ /^\+\s+$declaration_macros/) && # for "else if" which can look like "$Ident $Ident" !($pl =~ /^\+\s+$c90_Keywords\b/ || # other possible extensions of declaration lines $pl =~ /(?:$Compare|$Assignment|$Operators)\s*$/ || # not starting a section or a macro "\" extended line $pl =~ /(?:\{\s*|\\)$/) && # looks like a declaration !($sl =~ /^\+\s+$Declare\s*$Ident\s*[=,;:\[]/ || # function pointer declarations $sl =~ /^\+\s+$Declare\s*\(\s*\*\s*$Ident\s*\)\s*[=,;:\[\(]/ || # foo bar; where foo is some local typedef or #define $sl =~ /^\+\s+$Ident(?:\s+|\s*\*\s*)$Ident\s*[=,;\[]/ || # known declaration macros $sl =~ /^\+\s+$declaration_macros/ || # start of struct or union or enum $sl =~ /^\+\s+(?:static\s+)?(?:const\s+)?(?:union|struct|enum|typedef)\b/ || # start or end of block or continuation of declaration $sl =~ /^\+\s+(?:$|[\{\}\.\#\"\?\:\(\[])/ || # bitfield continuation $sl =~ /^\+\s+$Ident\s*:\s*\d+\s*[,;]/ || # other possible extensions of declaration lines $sl =~ /^\+\s+\(?\s*(?:$Compare|$Assignment|$Operators)/)) { if (WARN("LINE_SPACING", "Missing a blank line after declarations\n" . $hereprev) && $fix) { fix_insert_line($fixlinenr, "\+"); } } } # check for spaces at the beginning of a line. # Exceptions: # 1) within comments # 2) indented preprocessor commands # 3) hanging labels if ($rawline =~ /^\+ / && $line !~ /^\+ *(?:$;|#|$Ident:)/) { my $herevet = "$here\n" . cat_vet($rawline) . "\n"; if (WARN("LEADING_SPACE", "please, no spaces at the start of a line\n" . $herevet) && $fix) { $fixed[$fixlinenr] =~ s/^\+([ \t]+)/"\+" . tabify($1)/e; } } # check we are in a valid C source file if not then ignore this hunk next if ($realfile !~ /\.(h|c)$/); # check for unusual line ending [ or ( if ($line =~ /^\+.*([\[\(])\s*$/) { CHK("OPEN_ENDED_LINE", "Lines should not end with a '$1'\n" . $herecurr); } # check if this appears to be the start function declaration, save the name if ($sline =~ /^\+\{\s*$/ && $prevline =~ /^\+(?:(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*)?($Ident)\(/) { $context_function = $1; } # check if this appears to be the end of function declaration if ($sline =~ /^\+\}\s*$/) { undef $context_function; } # check indentation of any line with a bare else # (but not if it is a multiple line "if (foo) return bar; else return baz;") # if the previous line is a break or return and is indented 1 tab more... if ($sline =~ /^\+([\t]+)(?:}[ \t]*)?else(?:[ \t]*{)?\s*$/) { my $tabs = length($1) + 1; if ($prevline =~ /^\+\t{$tabs,$tabs}break\b/ || ($prevline =~ /^\+\t{$tabs,$tabs}return\b/ && defined $lines[$linenr] && $lines[$linenr] !~ /^[ \+]\t{$tabs,$tabs}return/)) { WARN("UNNECESSARY_ELSE", "else is not generally useful after a break or return\n" . $hereprev); } } # check indentation of a line with a break; # if the previous line is a goto, return or break # and is indented the same # of tabs if ($sline =~ /^\+([\t]+)break\s*;\s*$/) { my $tabs = $1; if ($prevline =~ /^\+$tabs(goto|return|break)\b/) { if (WARN("UNNECESSARY_BREAK", "break is not useful after a $1\n" . $hereprev) && $fix) { fix_delete_line($fixlinenr, $rawline); } } } # check for RCS/CVS revision markers if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) { WARN("CVS_KEYWORD", "CVS style keyword markers, these will _not_ be updated\n". $herecurr); } # check for old HOTPLUG __dev<foo> section markings if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) { WARN("HOTPLUG_SECTION", "Using $1 is unnecessary\n" . $herecurr); } # Check for potential 'bare' types my ($stat, $cond, $line_nr_next, $remain_next, $off_next, $realline_next); #print "LINE<$line>\n"; if ($linenr > $suppress_statement && $realcnt && $sline =~ /.\s*\S/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0); $stat =~ s/\n./\n /g; $cond =~ s/\n./\n /g; #print "linenr<$linenr> <$stat>\n"; # If this statement has no statement boundaries within # it there is no point in retrying a statement scan # until we hit end of it. my $frag = $stat; $frag =~ s/;+\s*$//; if ($frag !~ /(?:{|;)/) { #print "skip<$line_nr_next>\n"; $suppress_statement = $line_nr_next; } # Find the real next line. $realline_next = $line_nr_next; if (defined $realline_next && (!defined $lines[$realline_next - 1] || substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) { $realline_next++; } my $s = $stat; $s =~ s/{.*$//s; # Ignore goto labels. if ($s =~ /$Ident:\*$/s) { # Ignore functions being called } elsif ($s =~ /^.\s*$Ident\s*\(/s) { } elsif ($s =~ /^.\s*else\b/s) { # declarations always start with types } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) { my $type = $1; $type =~ s/\s+/ /g; possible($type, "A:" . $s); # definitions in global scope can only start with types } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) { possible($1, "B:" . $s); } # any (foo ... *) is a pointer cast, and foo is a type while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) { possible($1, "C:" . $s); } # Check for any sort of function declaration. # int foo(something bar, other baz); # void (*store_gdt)(x86_descr_ptr *); if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) { my ($name_len) = length($1); my $ctx = $s; substr($ctx, 0, $name_len + 1, ''); $ctx =~ s/\)[^\)]*$//; for my $arg (split(/\s*,\s*/, $ctx)) { if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) { possible($1, "D:" . $s); } } } } # # Checks which may be anchored in the context. # # Check for switch () and associated case and default # statements should be at the same indent. if ($line=~/\bswitch\s*\(.*\)/) { my $err = ''; my $sep = ''; my @ctx = ctx_block_outer($linenr, $realcnt); shift(@ctx); for my $ctx (@ctx) { my ($clen, $cindent) = line_stats($ctx); if ($ctx =~ /^\+\s*(case\s+|default:)/ && $indent != $cindent) { $err .= "$sep$ctx\n"; $sep = ''; } else { $sep = "[...]\n"; } } if ($err ne '') { ERROR("SWITCH_CASE_INDENT_LEVEL", "switch and case should be at the same indent\n$hereline$err"); } } # if/while/etc brace do not go on next line, unless defining a do while loop, # or if that brace on the next line is for something else if ($line =~ /(.*)\b((?:if|while|for|switch|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) { my $pre_ctx = "$1$2"; my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0); if ($line =~ /^\+\t{6,}/) { WARN("DEEP_INDENTATION", "Too many leading tabs - consider code refactoring\n" . $herecurr); } my $ctx_cnt = $realcnt - $#ctx - 1; my $ctx = join("\n", @ctx); my $ctx_ln = $linenr; my $ctx_skip = $realcnt; while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt && defined $lines[$ctx_ln - 1] && $lines[$ctx_ln - 1] =~ /^-/)) { ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n"; $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/); $ctx_ln++; } #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n"; #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n"; if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) { ERROR("OPEN_BRACE", "that open brace { should be on the previous line\n" . "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); } if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ && $ctx =~ /\)\s*\;\s*$/ && defined $lines[$ctx_ln - 1]) { my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]); if ($nindent > $indent) { WARN("TRAILING_SEMICOLON", "trailing semicolon indicates no statements, indent implies otherwise\n" . "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n"); } } } # Check relative indent for conditionals and blocks. if ($line =~ /\b(?:(?:if|while|for|(?:[a-z_]+|)for_each[a-z_]+)\s*\(|(?:do|else)\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0) if (!defined $stat); my ($s, $c) = ($stat, $cond); substr($s, 0, length($c), ''); # remove inline comments $s =~ s/$;/ /g; $c =~ s/$;/ /g; # Find out how long the conditional actually is. my @newlines = ($c =~ /\n/gs); my $cond_lines = 1 + $#newlines; # Make sure we remove the line prefixes as we have # none on the first line, and are going to readd them # where necessary. $s =~ s/\n./\n/gs; while ($s =~ /\n\s+\\\n/) { $cond_lines += $s =~ s/\n\s+\\\n/\n/g; } # We want to check the first line inside the block # starting at the end of the conditional, so remove: # 1) any blank line termination # 2) any opening brace { on end of the line # 3) any do (...) { my $continuation = 0; my $check = 0; $s =~ s/^.*\bdo\b//; $s =~ s/^\s*{//; if ($s =~ s/^\s*\\//) { $continuation = 1; } if ($s =~ s/^\s*?\n//) { $check = 1; $cond_lines++; } # Also ignore a loop construct at the end of a # preprocessor statement. if (($prevline =~ /^.\s*#\s*define\s/ || $prevline =~ /\\\s*$/) && $continuation == 0) { $check = 0; } my $cond_ptr = -1; $continuation = 0; while ($cond_ptr != $cond_lines) { $cond_ptr = $cond_lines; # If we see an #else/#elif then the code # is not linear. if ($s =~ /^\s*\#\s*(?:else|elif)/) { $check = 0; } # Ignore: # 1) blank lines, they should be at 0, # 2) preprocessor lines, and # 3) labels. if ($continuation || $s =~ /^\s*?\n/ || $s =~ /^\s*#\s*?/ || $s =~ /^\s*$Ident\s*:/) { $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0; if ($s =~ s/^.*?\n//) { $cond_lines++; } } } my (undef, $sindent) = line_stats("+" . $s); my $stat_real = raw_line($linenr, $cond_lines); # Check if either of these lines are modified, else # this is not this patch's fault. if (!defined($stat_real) || $stat !~ /^\+/ && $stat_real !~ /^\+/) { $check = 0; } if (defined($stat_real) && $cond_lines > 1) { $stat_real = "[...]\n$stat_real"; } #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; if ($check && $s ne '' && (($sindent % $tabsize) != 0 || ($sindent < $indent) || ($sindent == $indent && ($s !~ /^\s*(?:\}|\{|else\b)/)) || ($sindent > $indent + $tabsize))) { WARN("SUSPECT_CODE_INDENT", "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); } } # Track the 'values' across context and added lines. my $opline = $line; $opline =~ s/^./ /; my ($curr_values, $curr_vars) = annotate_values($opline . "\n", $prev_values); $curr_values = $prev_values . $curr_values; if ($dbg_values) { my $outline = $opline; $outline =~ s/\t/ /g; print "$linenr > .$outline\n"; print "$linenr > $curr_values\n"; print "$linenr > $curr_vars\n"; } $prev_values = substr($curr_values, -1); #ignore lines not being added next if ($line =~ /^[^\+]/); # check for self assignments used to avoid compiler warnings # e.g.: int foo = foo, *bar = NULL; # struct foo bar = *(&(bar)); if ($line =~ /^\+\s*(?:$Declare)?([A-Za-z_][A-Za-z\d_]*)\s*=/) { my $var = $1; if ($line =~ /^\+\s*(?:$Declare)?$var\s*=\s*(?:$var|\*\s*\(?\s*&\s*\(?\s*$var\s*\)?\s*\)?)\s*[;,]/) { WARN("SELF_ASSIGNMENT", "Do not use self-assignments to avoid compiler warnings\n" . $herecurr); } } # check for dereferences that span multiple lines if ($prevline =~ /^\+.*$Lval\s*(?:\.|->)\s*$/ && $line =~ /^\+\s*(?!\#\s*(?!define\s+|if))\s*$Lval/) { $prevline =~ /($Lval\s*(?:\.|->))\s*$/; my $ref = $1; $line =~ /^.\s*($Lval)/; $ref .= $1; $ref =~ s/\s//g; WARN("MULTILINE_DEREFERENCE", "Avoid multiple line dereference - prefer '$ref'\n" . $hereprev); } # check for declarations of signed or unsigned without int while ($line =~ m{\b($Declare)\s*(?!char\b|short\b|int\b|long\b)\s*($Ident)?\s*[=,;\[\)\(]}g) { my $type = $1; my $var = $2; $var = "" if (!defined $var); if ($type =~ /^(?:(?:$Storage|$Inline|$Attribute)\s+)*((?:un)?signed)((?:\s*\*)*)\s*$/) { my $sign = $1; my $pointer = $2; $pointer = "" if (!defined $pointer); if (WARN("UNSPECIFIED_INT", "Prefer '" . trim($sign) . " int" . rtrim($pointer) . "' to bare use of '$sign" . rtrim($pointer) . "'\n" . $herecurr) && $fix) { my $decl = trim($sign) . " int "; my $comp_pointer = $pointer; $comp_pointer =~ s/\s//g; $decl .= $comp_pointer; $decl = rtrim($decl) if ($var eq ""); $fixed[$fixlinenr] =~ s@\b$sign\s*\Q$pointer\E\s*$var\b@$decl$var@; } } } # TEST: allow direct testing of the type matcher. if ($dbg_type) { if ($line =~ /^.\s*$Declare\s*$/) { ERROR("TEST_TYPE", "TEST: is type\n" . $herecurr); } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) { ERROR("TEST_NOT_TYPE", "TEST: is not type ($1 is)\n". $herecurr); } next; } # TEST: allow direct testing of the attribute matcher. if ($dbg_attr) { if ($line =~ /^.\s*$Modifier\s*$/) { ERROR("TEST_ATTR", "TEST: is attr\n" . $herecurr); } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) { ERROR("TEST_NOT_ATTR", "TEST: is not attr ($1 is)\n". $herecurr); } next; } # check for initialisation to aggregates open brace on the next line if ($line =~ /^.\s*{/ && $prevline =~ /(?:^|[^=])=\s*$/) { if (ERROR("OPEN_BRACE", "that open brace { should be on the previous line\n" . $hereprev) && $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { fix_delete_line($fixlinenr - 1, $prevrawline); fix_delete_line($fixlinenr, $rawline); my $fixedline = $prevrawline; $fixedline =~ s/\s*=\s*$/ = {/; fix_insert_line($fixlinenr, $fixedline); $fixedline = $line; $fixedline =~ s/^(.\s*)\{\s*/$1/; fix_insert_line($fixlinenr, $fixedline); } } # # Checks which are anchored on the added line. # # check for malformed paths in #include statements (uses RAW line) if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) { my $path = $1; if ($path =~ m{//}) { ERROR("MALFORMED_INCLUDE", "malformed #include filename\n" . $herecurr); } if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) { ERROR("UAPI_INCLUDE", "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr); } } # no C99 // comments if ($line =~ m{//}) { if (ERROR("C99_COMMENTS", "do not use C99 // comments\n" . $herecurr) && $fix) { my $line = $fixed[$fixlinenr]; if ($line =~ /\/\/(.*)$/) { my $comment = trim($1); $fixed[$fixlinenr] =~ s@\/\/(.*)$@/\* $comment \*/@; } } } # Remove C99 comments. $line =~ s@//.*@@; $opline =~ s@//.*@@; # EXPORT_SYMBOL should immediately follow the thing it is exporting, consider # the whole statement. #print "APW <$lines[$realline_next - 1]>\n"; if (defined $realline_next && exists $lines[$realline_next - 1] && !defined $suppress_export{$realline_next} && ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/)) { # Handle definitions which produce identifiers with # a prefix: # XXX(foo); # EXPORT_SYMBOL(something_foo); my $name = $1; $name =~ s/^\s*($Ident).*/$1/; if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ && $name =~ /^${Ident}_$2/) { #print "FOO C name<$name>\n"; $suppress_export{$realline_next} = 1; } elsif ($stat !~ /(?: \n.}\s*$| ^.DEFINE_$Ident\(\Q$name\E\)| ^.DECLARE_$Ident\(\Q$name\E\)| ^.LIST_HEAD\(\Q$name\E\)| ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(| \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\() )/x) { #print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n"; $suppress_export{$realline_next} = 2; } else { $suppress_export{$realline_next} = 1; } } if (!defined $suppress_export{$linenr} && $prevline =~ /^.\s*$/ && ($line =~ /EXPORT_SYMBOL.*\((.*)\)/)) { #print "FOO B <$lines[$linenr - 1]>\n"; $suppress_export{$linenr} = 2; } if (defined $suppress_export{$linenr} && $suppress_export{$linenr} == 2) { WARN("EXPORT_SYMBOL", "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr); } # check for global initialisers. if ($line =~ /^\+$Type\s*$Ident(?:\s+$Modifier)*\s*=\s*($zero_initializer)\s*;/ && !exclude_global_initialisers($realfile)) { if (ERROR("GLOBAL_INITIALISERS", "do not initialise globals to $1\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(^.$Type\s*$Ident(?:\s+$Modifier)*)\s*=\s*$zero_initializer\s*;/$1;/; } } # check for static initialisers. if ($line =~ /^\+.*\bstatic\s.*=\s*($zero_initializer)\s*;/) { if (ERROR("INITIALISED_STATIC", "do not initialise statics to $1\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(\bstatic\s.*?)\s*=\s*$zero_initializer\s*;/$1;/; } } # check for misordered declarations of char/short/int/long with signed/unsigned while ($sline =~ m{(\b$TypeMisordered\b)}g) { my $tmp = trim($1); WARN("MISORDERED_TYPE", "type '$tmp' should be specified in [[un]signed] [short|int|long|long long] order\n" . $herecurr); } # check for unnecessary <signed> int declarations of short/long/long long while ($sline =~ m{\b($TypeMisordered(\s*\*)*|$C90_int_types)\b}g) { my $type = trim($1); next if ($type !~ /\bint\b/); next if ($type !~ /\b(?:short|long\s+long|long)\b/); my $new_type = $type; $new_type =~ s/\b\s*int\s*\b/ /; $new_type =~ s/\b\s*(?:un)?signed\b\s*/ /; $new_type =~ s/^const\s+//; $new_type = "unsigned $new_type" if ($type =~ /\bunsigned\b/); $new_type = "const $new_type" if ($type =~ /^const\b/); $new_type =~ s/\s+/ /g; $new_type = trim($new_type); if (WARN("UNNECESSARY_INT", "Prefer '$new_type' over '$type' as the int is unnecessary\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b\Q$type\E\b/$new_type/; } } # check for static const char * arrays. if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) { WARN("STATIC_CONST_CHAR_ARRAY", "static const char * array should probably be static const char * const\n" . $herecurr); } # check for initialized const char arrays that should be static const if ($line =~ /^\+\s*const\s+(char|unsigned\s+char|_*u8|(?:[us]_)?int8_t)\s+\w+\s*\[\s*(?:\w+\s*)?\]\s*=\s*"/) { if (WARN("STATIC_CONST_CHAR_ARRAY", "const array should probably be static const\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(^.\s*)const\b/${1}static const/; } } # check for static char foo[] = "bar" declarations. if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) { WARN("STATIC_CONST_CHAR_ARRAY", "static char array declaration should probably be static const char\n" . $herecurr); } # check for const <foo> const where <foo> is not a pointer or array type if ($sline =~ /\bconst\s+($BasicType)\s+const\b/) { my $found = $1; if ($sline =~ /\bconst\s+\Q$found\E\s+const\b\s*\*/) { WARN("CONST_CONST", "'const $found const *' should probably be 'const $found * const'\n" . $herecurr); } elsif ($sline !~ /\bconst\s+\Q$found\E\s+const\s+\w+\s*\[/) { WARN("CONST_CONST", "'const $found const' should probably be 'const $found'\n" . $herecurr); } } # check for const static or static <non ptr type> const declarations # prefer 'static const <foo>' over 'const static <foo>' and 'static <foo> const' if ($sline =~ /^\+\s*const\s+static\s+($Type)\b/ || $sline =~ /^\+\s*static\s+($BasicType)\s+const\b/) { if (WARN("STATIC_CONST", "Move const after static - use 'static const $1'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bconst\s+static\b/static const/; $fixed[$fixlinenr] =~ s/\bstatic\s+($BasicType)\s+const\b/static const $1/; } } # check for non-global char *foo[] = {"bar", ...} declarations. if ($line =~ /^.\s+(?:static\s+|const\s+)?char\s+\*\s*\w+\s*\[\s*\]\s*=\s*\{/) { WARN("STATIC_CONST_CHAR_ARRAY", "char * array declaration might be better as static const\n" . $herecurr); } # check for sizeof(foo)/sizeof(foo[0]) that could be ARRAY_SIZE(foo) if ($line =~ m@\bsizeof\s*\(\s*($Lval)\s*\)@) { my $array = $1; if ($line =~ m@\b(sizeof\s*\(\s*\Q$array\E\s*\)\s*/\s*sizeof\s*\(\s*\Q$array\E\s*\[\s*0\s*\]\s*\))@) { my $array_div = $1; if (WARN("ARRAY_SIZE", "Prefer ARRAY_SIZE($array)\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$array_div\E/ARRAY_SIZE($array)/; } } } # check for function declarations without arguments like "int foo()" if ($line =~ /(\b$Type\s*$Ident)\s*\(\s*\)/) { if (ERROR("FUNCTION_WITHOUT_ARGS", "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/; } } # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && $line !~ /\b__bitwise\b/) { WARN("NEW_TYPEDEFS", "do not add new typedefs\n" . $herecurr); } # * goes on variable not on type # (char*[ const]) while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) { #print "AA<$1>\n"; my ($ident, $from, $to) = ($1, $2, $2); # Should start with a space. $to =~ s/^(\S)/ $1/; # Should not end with a space. $to =~ s/\s+$//; # '*'s should not have spaces between. while ($to =~ s/\*\s+\*/\*\*/) { } ## print "1: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to) { if (ERROR("POINTER_LOCATION", "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr) && $fix) { my $sub_from = $ident; my $sub_to = $ident; $sub_to =~ s/\Q$from\E/$to/; $fixed[$fixlinenr] =~ s@\Q$sub_from\E@$sub_to@; } } } while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) { #print "BB<$1>\n"; my ($match, $from, $to, $ident) = ($1, $2, $2, $3); # Should start with a space. $to =~ s/^(\S)/ $1/; # Should not end with a space. $to =~ s/\s+$//; # '*'s should not have spaces between. while ($to =~ s/\*\s+\*/\*\*/) { } # Modifiers should have spaces. $to =~ s/(\b$Modifier$)/$1 /; ## print "2: from<$from> to<$to> ident<$ident>\n"; if ($from ne $to && $ident !~ /^$Modifier$/) { if (ERROR("POINTER_LOCATION", "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr) && $fix) { my $sub_from = $match; my $sub_to = $match; $sub_to =~ s/\Q$from\E/$to/; $fixed[$fixlinenr] =~ s@\Q$sub_from\E@$sub_to@; } } } # do not use BUG() or variants if ($line =~ /\b(?!AA_|BUILD_|IDA_|KVM_|RWLOCK_|snd_|SPIN_)(?:[a-zA-Z_]*_)?BUG(?:_ON)?(?:_[A-Z_]+)?\s*\(/) { my $msg_level = \&WARN; $msg_level = \&CHK if ($file); &{$msg_level}("AVOID_BUG", "Do not crash the kernel unless it is absolutely unavoidable--use WARN_ON_ONCE() plus recovery code (if feasible) instead of BUG() or variants\n" . $herecurr); } # avoid LINUX_VERSION_CODE if ($line =~ /\bLINUX_VERSION_CODE\b/) { WARN("LINUX_VERSION_CODE", "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); } # check for uses of printk_ratelimit if ($line =~ /\bprintk_ratelimit\s*\(/) { WARN("PRINTK_RATELIMITED", "Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr); } # printk should use KERN_* levels if ($line =~ /\bprintk\s*\(\s*(?!KERN_[A-Z]+\b)/) { WARN("PRINTK_WITHOUT_KERN_LEVEL", "printk() should include KERN_<LEVEL> facility level\n" . $herecurr); } # prefer variants of (subsystem|netdev|dev|pr)_<level> to printk(KERN_<LEVEL> if ($line =~ /\b(printk(_once|_ratelimited)?)\s*\(\s*KERN_([A-Z]+)/) { my $printk = $1; my $modifier = $2; my $orig = $3; $modifier = "" if (!defined($modifier)); my $level = lc($orig); $level = "warn" if ($level eq "warning"); my $level2 = $level; $level2 = "dbg" if ($level eq "debug"); $level .= $modifier; $level2 .= $modifier; WARN("PREFER_PR_LEVEL", "Prefer [subsystem eg: netdev]_$level2([subsystem]dev, ... then dev_$level2(dev, ... then pr_$level(... to $printk(KERN_$orig ...\n" . $herecurr); } # prefer dev_<level> to dev_printk(KERN_<LEVEL> if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) { my $orig = $1; my $level = lc($orig); $level = "warn" if ($level eq "warning"); $level = "dbg" if ($level eq "debug"); WARN("PREFER_DEV_LEVEL", "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr); } # trace_printk should not be used in production code. if ($line =~ /\b(trace_printk|trace_puts|ftrace_vprintk)\s*\(/) { WARN("TRACE_PRINTK", "Do not use $1() in production code (this can be ignored if built only with a debug config option)\n" . $herecurr); } # ENOSYS means "bad syscall nr" and nothing else. This will have a small # number of false positives, but assembly files are not checked, so at # least the arch entry code will not trigger this warning. if ($line =~ /\bENOSYS\b/) { WARN("ENOSYS", "ENOSYS means 'invalid syscall nr' and nothing else\n" . $herecurr); } # ENOTSUPP is not a standard error code and should be avoided in new patches. # Folks usually mean EOPNOTSUPP (also called ENOTSUP), when they type ENOTSUPP. # Similarly to ENOSYS warning a small number of false positives is expected. if (!$file && $line =~ /\bENOTSUPP\b/) { if (WARN("ENOTSUPP", "ENOTSUPP is not a SUSV4 error code, prefer EOPNOTSUPP\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bENOTSUPP\b/EOPNOTSUPP/; } } # function brace can't be on same line, except for #defines of do while, # or if closed on same line if ($perl_version_ok && $sline =~ /$Type\s*$Ident\s*$balanced_parens\s*\{/ && $sline !~ /\#\s*define\b.*do\s*\{/ && $sline !~ /}/) { if (ERROR("OPEN_BRACE", "open brace '{' following function definitions go on the next line\n" . $herecurr) && $fix) { fix_delete_line($fixlinenr, $rawline); my $fixed_line = $rawline; $fixed_line =~ /(^..*$Type\s*$Ident\(.*\)\s*)\{(.*)$/; my $line1 = $1; my $line2 = $2; fix_insert_line($fixlinenr, ltrim($line1)); fix_insert_line($fixlinenr, "\+{"); if ($line2 !~ /^\s*$/) { fix_insert_line($fixlinenr, "\+\t" . trim($line2)); } } } # open braces for enum, union and struct go on the same line. if ($line =~ /^.\s*{/ && $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) { if (ERROR("OPEN_BRACE", "open brace '{' following $1 go on the same line\n" . $hereprev) && $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { fix_delete_line($fixlinenr - 1, $prevrawline); fix_delete_line($fixlinenr, $rawline); my $fixedline = rtrim($prevrawline) . " {"; fix_insert_line($fixlinenr, $fixedline); $fixedline = $rawline; $fixedline =~ s/^(.\s*)\{\s*/$1\t/; if ($fixedline !~ /^\+\s*$/) { fix_insert_line($fixlinenr, $fixedline); } } } # missing space after union, struct or enum definition if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident){1,2}[=\{]/) { if (WARN("SPACING", "missing space after $1 definition\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(.\s*(?:typedef\s+)?(?:enum|union|struct)(?:\s+$Ident){1,2})([=\{])/$1 $2/; } } # Function pointer declarations # check spacing between type, funcptr, and args # canonical declaration is "type (*funcptr)(args...)" if ($line =~ /^.\s*($Declare)\((\s*)\*(\s*)($Ident)(\s*)\)(\s*)\(/) { my $declare = $1; my $pre_pointer_space = $2; my $post_pointer_space = $3; my $funcname = $4; my $post_funcname_space = $5; my $pre_args_space = $6; # the $Declare variable will capture all spaces after the type # so check it for a missing trailing missing space but pointer return types # don't need a space so don't warn for those. my $post_declare_space = ""; if ($declare =~ /(\s+)$/) { $post_declare_space = $1; $declare = rtrim($declare); } if ($declare !~ /\*$/ && $post_declare_space =~ /^$/) { WARN("SPACING", "missing space after return type\n" . $herecurr); $post_declare_space = " "; } # unnecessary space "type (*funcptr)(args...)" # This test is not currently implemented because these declarations are # equivalent to # int foo(int bar, ...) # and this is form shouldn't/doesn't generate a checkpatch warning. # # elsif ($declare =~ /\s{2,}$/) { # WARN("SPACING", # "Multiple spaces after return type\n" . $herecurr); # } # unnecessary space "type ( *funcptr)(args...)" if (defined $pre_pointer_space && $pre_pointer_space =~ /^\s/) { WARN("SPACING", "Unnecessary space after function pointer open parenthesis\n" . $herecurr); } # unnecessary space "type (* funcptr)(args...)" if (defined $post_pointer_space && $post_pointer_space =~ /^\s/) { WARN("SPACING", "Unnecessary space before function pointer name\n" . $herecurr); } # unnecessary space "type (*funcptr )(args...)" if (defined $post_funcname_space && $post_funcname_space =~ /^\s/) { WARN("SPACING", "Unnecessary space after function pointer name\n" . $herecurr); } # unnecessary space "type (*funcptr) (args...)" if (defined $pre_args_space && $pre_args_space =~ /^\s/) { WARN("SPACING", "Unnecessary space before function pointer arguments\n" . $herecurr); } if (show_type("SPACING") && $fix) { $fixed[$fixlinenr] =~ s/^(.\s*)$Declare\s*\(\s*\*\s*$Ident\s*\)\s*\(/$1 . $declare . $post_declare_space . '(*' . $funcname . ')('/ex; } } # check for spacing round square brackets; allowed: # 1. with a type on the left -- int [] a; # 2. at the beginning of a line for slice initialisers -- [0...10] = 5, # 3. inside a curly brace -- = { [0...10] = 5 } while ($line =~ /(.*?\s)\[/g) { my ($where, $prefix) = ($-[1], $1); if ($prefix !~ /$Type\s+$/ && ($where != 0 || $prefix !~ /^.\s+$/) && $prefix !~ /[{,:]\s+$/) { if (ERROR("BRACKET_SPACE", "space prohibited before open square bracket '['\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(\+.*?)\s+\[/$1\[/; } } } # check for spaces between functions and their parentheses. while ($line =~ /($Ident)\s+\(/g) { my $name = $1; my $ctx_before = substr($line, 0, $-[1]); my $ctx = "$ctx_before$name"; # Ignore those directives where spaces _are_ permitted. if ($name =~ /^(?: if|for|while|switch|return|case| volatile|__volatile__| __attribute__|format|__extension__| asm|__asm__|scoped_guard)$/x) { # cpp #define statements have non-optional spaces, ie # if there is a space between the name and the open # parenthesis it is simply not a parameter group. } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) { # cpp #elif statement condition may start with a ( } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) { # If this whole things ends with a type its most # likely a typedef for a function. } elsif ($ctx =~ /$Type$/) { } else { if (WARN("SPACING", "space prohibited between function name and open parenthesis '('\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b$name\s+\(/$name\(/; } } } # Check operator spacing. if (!($line=~/\#\s*include/)) { my $fixed_line = ""; my $line_fixed = 0; my $ops = qr{ <<=|>>=|<=|>=|==|!=| \+=|-=|\*=|\/=|%=|\^=|\|=|&=| =>|->|<<|>>|<|>|=|!|~| &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| \?:|\?|: }x; my @elements = split(/($ops|;)/, $opline); ## print("element count: <" . $#elements . ">\n"); ## foreach my $el (@elements) { ## print("el: <$el>\n"); ## } my @fix_elements = (); my $off = 0; foreach my $el (@elements) { push(@fix_elements, substr($rawline, $off, length($el))); $off += length($el); } $off = 0; my $blank = copy_spacing($opline); my $last_after = -1; for (my $n = 0; $n < $#elements; $n += 2) { my $good = $fix_elements[$n] . $fix_elements[$n + 1]; ## print("n: <$n> good: <$good>\n"); $off += length($elements[$n]); # Pick up the preceding and succeeding characters. my $ca = substr($opline, 0, $off); my $cc = ''; if (length($opline) >= ($off + length($elements[$n + 1]))) { $cc = substr($opline, $off + length($elements[$n + 1])); } my $cb = "$ca$;$cc"; my $a = ''; $a = 'V' if ($elements[$n] ne ''); $a = 'W' if ($elements[$n] =~ /\s$/); $a = 'C' if ($elements[$n] =~ /$;$/); $a = 'B' if ($elements[$n] =~ /(\[|\()$/); $a = 'O' if ($elements[$n] eq ''); $a = 'E' if ($ca =~ /^\s*$/); my $op = $elements[$n + 1]; my $c = ''; if (defined $elements[$n + 2]) { $c = 'V' if ($elements[$n + 2] ne ''); $c = 'W' if ($elements[$n + 2] =~ /^\s/); $c = 'C' if ($elements[$n + 2] =~ /^$;/); $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/); $c = 'O' if ($elements[$n + 2] eq ''); $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/); } else { $c = 'E'; } my $ctx = "${a}x${c}"; my $at = "(ctx:$ctx)"; my $ptr = substr($blank, 0, $off) . "^"; my $hereptr = "$hereline$ptr\n"; # Pull out the value of this operator. my $op_type = substr($curr_values, $off + 1, 1); # Get the full operator variant. my $opv = $op . substr($curr_vars, $off, 1); # Ignore operators passed as parameters. if ($op_type ne 'V' && $ca =~ /\s$/ && $cc =~ /^\s*[,\)]/) { # # Ignore comments # } elsif ($op =~ /^$;+$/) { # ; should have either the end of line or a space or \ after it } elsif ($op eq ';') { if ($ctx !~ /.x[WEBC]/ && $cc !~ /^\\/ && $cc !~ /^;/) { if (ERROR("SPACING", "space required after that '$op' $at\n" . $hereptr)) { $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; $line_fixed = 1; } } # // is a comment } elsif ($op eq '//') { # : when part of a bitfield } elsif ($opv eq ':B') { # skip the bitfield test for now # No spaces for: # -> } elsif ($op eq '->') { if ($ctx =~ /Wx.|.xW/) { if (ERROR("SPACING", "spaces prohibited around that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; } $line_fixed = 1; } } # , must not have a space before and must have a space on the right. } elsif ($op eq ',') { my $rtrim_before = 0; my $space_after = 0; if ($ctx =~ /Wx./) { if (ERROR("SPACING", "space prohibited before that '$op' $at\n" . $hereptr)) { $line_fixed = 1; $rtrim_before = 1; } } if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) { if (ERROR("SPACING", "space required after that '$op' $at\n" . $hereptr)) { $line_fixed = 1; $last_after = $n; $space_after = 1; } } if ($rtrim_before || $space_after) { if ($rtrim_before) { $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); } else { $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); } if ($space_after) { $good .= " "; } } # '*' as part of a type definition -- reported already. } elsif ($opv eq '*_') { #warn "'*' is part of type\n"; # unary operators should have a space before and # none after. May be left adjacent to another # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || $opv eq '*U' || $opv eq '-U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { if (ERROR("SPACING", "space required before that '$op' $at\n" . $hereptr)) { if ($n != $last_after + 2) { $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]); $line_fixed = 1; } } } if ($op eq '*' && $cc =~/\s*$Modifier\b/) { # A unary '*' may be const } elsif ($ctx =~ /.xW/) { if (ERROR("SPACING", "space prohibited after that '$op' $at\n" . $hereptr)) { $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]); if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; } $line_fixed = 1; } } # unary ++ and unary -- are allowed no space on one side. } elsif ($op eq '++' or $op eq '--') { if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) { if (ERROR("SPACING", "space required one side of that '$op' $at\n" . $hereptr)) { $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " "; $line_fixed = 1; } } if ($ctx =~ /Wx[BE]/ || ($ctx =~ /Wx./ && $cc =~ /^;/)) { if (ERROR("SPACING", "space prohibited before that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); $line_fixed = 1; } } if ($ctx =~ /ExW/) { if (ERROR("SPACING", "space prohibited after that '$op' $at\n" . $hereptr)) { $good = $fix_elements[$n] . trim($fix_elements[$n + 1]); if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; } $line_fixed = 1; } } # << and >> may either have or not have spaces both sides } elsif ($op eq '<<' or $op eq '>>' or $op eq '&' or $op eq '^' or $op eq '|' or $op eq '+' or $op eq '-' or $op eq '*' or $op eq '/' or $op eq '%') { if ($check) { if (defined $fix_elements[$n + 2] && $ctx !~ /[EW]x[EW]/) { if (CHK("SPACING", "spaces preferred around that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; $fix_elements[$n + 2] =~ s/^\s+//; $line_fixed = 1; } } elsif (!defined $fix_elements[$n + 2] && $ctx !~ /Wx[OE]/) { if (CHK("SPACING", "space preferred before that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]); $line_fixed = 1; } } } elsif ($ctx =~ /Wx[^WCE]|[^WCE]xW/) { if (ERROR("SPACING", "need consistent spacing around '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; } $line_fixed = 1; } } # A colon needs no spaces before when it is # terminating a case value or a label. } elsif ($opv eq ':C' || $opv eq ':L') { if ($ctx =~ /Wx./ and $realfile !~ m@.*\.lds\.h$@) { if (ERROR("SPACING", "space prohibited before that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]); $line_fixed = 1; } } # All the others need spaces both sides. } elsif ($ctx !~ /[EWC]x[CWE]/) { my $ok = 0; # Ignore email addresses <foo@bar> if (($op eq '<' && $cc =~ /^\S+\@\S+>/) || ($op eq '>' && $ca =~ /<\S+\@\S+$/)) { $ok = 1; } # for asm volatile statements # ignore a colon with another # colon immediately before or after if (($op eq ':') && ($ca =~ /:$/ || $cc =~ /^:/)) { $ok = 1; } # messages are ERROR, but ?: are CHK if ($ok == 0) { my $msg_level = \&ERROR; $msg_level = \&CHK if (($op eq '?:' || $op eq '?' || $op eq ':') && $ctx =~ /VxV/); if (&{$msg_level}("SPACING", "spaces required around that '$op' $at\n" . $hereptr)) { $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " "; if (defined $fix_elements[$n + 2]) { $fix_elements[$n + 2] =~ s/^\s+//; } $line_fixed = 1; } } } $off += length($elements[$n + 1]); ## print("n: <$n> GOOD: <$good>\n"); $fixed_line = $fixed_line . $good; } if (($#elements % 2) == 0) { $fixed_line = $fixed_line . $fix_elements[$#elements]; } if ($fix && $line_fixed && $fixed_line ne $fixed[$fixlinenr]) { $fixed[$fixlinenr] = $fixed_line; } } # check for whitespace before a non-naked semicolon if ($line =~ /^\+.*\S\s+;\s*$/) { if (WARN("SPACING", "space prohibited before semicolon\n" . $herecurr) && $fix) { 1 while $fixed[$fixlinenr] =~ s/^(\+.*\S)\s+;/$1;/; } } # check for multiple assignments if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) { CHK("MULTIPLE_ASSIGNMENTS", "multiple assignments should be avoided\n" . $herecurr); } ## # check for multiple declarations, allowing for a function declaration ## # continuation. ## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ && ## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) { ## ## # Remove any bracketed sections to ensure we do not ## # falsely report the parameters of functions. ## my $ln = $line; ## while ($ln =~ s/\([^\(\)]*\)//g) { ## } ## if ($ln =~ /,/) { ## WARN("MULTIPLE_DECLARATION", ## "declaring multiple variables together should be avoided\n" . $herecurr); ## } ## } #need space before brace following if, while, etc if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\)\{/) || $line =~ /\b(?:else|do)\{/) { if (ERROR("SPACING", "space required before the open brace '{'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(\+.*(?:do|else|\)))\{/$1 {/; } } ## # check for blank lines before declarations ## if ($line =~ /^.\t+$Type\s+$Ident(?:\s*=.*)?;/ && ## $prevrawline =~ /^.\s*$/) { ## WARN("SPACING", ## "No blank lines before declarations\n" . $hereprev); ## } ## # closing brace should have a space following it when it has anything # on the line if ($line =~ /}(?!(?:,|;|\)|\}))\S/) { if (ERROR("SPACING", "space required after that close brace '}'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/}((?!(?:,|;|\)))\S)/} $1/; } } # check spacing on square brackets if ($line =~ /\[\s/ && $line !~ /\[\s*$/) { if (ERROR("SPACING", "space prohibited after that open square bracket '['\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\[\s+/\[/; } } if ($line =~ /\s\]/) { if (ERROR("SPACING", "space prohibited before that close square bracket ']'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\s+\]/\]/; } } # check spacing on parentheses if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ && $line !~ /for\s*\(\s+;/) { if (ERROR("SPACING", "space prohibited after that open parenthesis '('\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\(\s+/\(/; } } if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ && $line !~ /for\s*\(.*;\s+\)/ && $line !~ /:\s+\)/) { if (ERROR("SPACING", "space prohibited before that close parenthesis ')'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\s+\)/\)/; } } # check unnecessary parentheses around addressof/dereference single $Lvals # ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) { my $var = $1; if (CHK("UNNECESSARY_PARENTHESES", "Unnecessary parentheses around $var\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/; } } # check for unnecessary parentheses around function pointer uses # ie: (foo->bar)(); should be foo->bar(); # but not "if (foo->bar) (" to avoid some false positives if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) { my $var = $2; if (CHK("UNNECESSARY_PARENTHESES", "Unnecessary parentheses around function pointer $var\n" . $herecurr) && $fix) { my $var2 = deparenthesize($var); $var2 =~ s/\s//g; $fixed[$fixlinenr] =~ s/\Q$var\E/$var2/; } } # check for unnecessary parentheses around comparisons # except in drivers/staging if (($realfile !~ m@^(?:drivers/staging/)@) && $perl_version_ok && defined($stat) && $stat =~ /(^.\s*if\s*($balanced_parens))/) { my $if_stat = $1; my $test = substr($2, 1, -1); my $herectx; while ($test =~ /(?:^|[^\w\&\!\~])+\s*\(\s*([\&\!\~]?\s*$Lval\s*(?:$Compare\s*$FuncArg)?)\s*\)/g) { my $match = $1; # avoid parentheses around potential macro args next if ($match =~ /^\s*\w+\s*$/); if (!defined($herectx)) { $herectx = $here . "\n"; my $cnt = statement_rawlines($if_stat); for (my $n = 0; $n < $cnt; $n++) { my $rl = raw_line($linenr, $n); $herectx .= $rl . "\n"; last if $rl =~ /^[ \+].*\{/; } } CHK("UNNECESSARY_PARENTHESES", "Unnecessary parentheses around '$match'\n" . $herectx); } } # check that goto labels aren't indented (allow a single space indentation) # and ignore bitfield definitions like foo:1 # Strictly, labels can have whitespace after the identifier and before the : # but this is not allowed here as many ?: uses would appear to be labels if ($sline =~ /^.\s+[A-Za-z_][A-Za-z\d_]*:(?!\s*\d+)/ && $sline !~ /^. [A-Za-z\d_][A-Za-z\d_]*:/ && $sline !~ /^.\s+default:/) { if (WARN("INDENTED_LABEL", "labels should not be indented\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(.)\s+/$1/; } } # check if a statement with a comma should be two statements like: # foo = bar(), /* comma should be semicolon */ # bar = baz(); if (defined($stat) && $stat =~ /^\+\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*,\s*(?:$Lval\s*$Assignment\s*)?$FuncArg\s*;\s*$/) { my $cnt = statement_rawlines($stat); my $herectx = get_stat_here($linenr, $cnt, $here); WARN("SUSPECT_COMMA_SEMICOLON", "Possible comma where semicolon could be used\n" . $herectx); } # return is not a function if (defined($stat) && $stat =~ /^.\s*return(\s*)\(/s) { my $spacing = $1; if ($perl_version_ok && $stat =~ /^.\s*return\s*($balanced_parens)\s*;\s*$/) { my $value = $1; $value = deparenthesize($value); if ($value =~ m/^\s*$FuncArg\s*(?:\?|$)/) { ERROR("RETURN_PARENTHESES", "return is not a function, parentheses are not required\n" . $herecurr); } } elsif ($spacing !~ /\s+/) { ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr); } } # unnecessary return in a void function # at end-of-function, with the previous line a single leading tab, then return; # and the line before that not a goto label target like "out:" if ($sline =~ /^[ \+]}\s*$/ && $prevline =~ /^\+\treturn\s*;\s*$/ && $linenr >= 3 && $lines[$linenr - 3] =~ /^[ +]/ && $lines[$linenr - 3] !~ /^[ +]\s*$Ident\s*:/) { WARN("RETURN_VOID", "void function return statements are not generally useful\n" . $hereprev); } # if statements using unnecessary parentheses - ie: if ((foo == bar)) if ($perl_version_ok && $line =~ /\bif\s*((?:\(\s*){2,})/) { my $openparens = $1; my $count = $openparens =~ tr@\(@\(@; my $msg = ""; if ($line =~ /\bif\s*(?:\(\s*){$count,$count}$LvalOrFunc\s*($Compare)\s*$LvalOrFunc(?:\s*\)){$count,$count}/) { my $comp = $4; #Not $1 because of $LvalOrFunc $msg = " - maybe == should be = ?" if ($comp eq "=="); WARN("UNNECESSARY_PARENTHESES", "Unnecessary parentheses$msg\n" . $herecurr); } } # comparisons with a constant or upper case identifier on the left # avoid cases like "foo + BAR < baz" # only fix matches surrounded by parentheses to avoid incorrect # conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" if ($perl_version_ok && $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { my $lead = $1; my $const = $2; my $comp = $3; my $to = $4; my $newcomp = $comp; if ($lead !~ /(?:$Operators|\.)\s*$/ && $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && WARN("CONSTANT_COMPARISON", "Comparisons should place the constant on the right side of the test\n" . $herecurr) && $fix) { if ($comp eq "<") { $newcomp = ">"; } elsif ($comp eq "<=") { $newcomp = ">="; } elsif ($comp eq ">") { $newcomp = "<"; } elsif ($comp eq ">=") { $newcomp = "<="; } $fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/; } } # Return of what appears to be an errno should normally be negative if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { my $name = $1; if ($name ne 'EOF' && $name ne 'ERROR' && $name !~ /^EPOLL/) { WARN("USE_NEGATIVE_ERRNO", "return of an errno should typically be negative (ie: return -$1)\n" . $herecurr); } } # Need a space before open parenthesis after if, while etc if ($line =~ /\b(if|while|for|switch)\(/) { if (ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b(if|while|for|switch)\(/$1 \(/; } } # Check for illegal assignment in if conditional -- and check for trailing # statements after the conditional. if ($line =~ /do\s*(?!{)/) { ($stat, $cond, $line_nr_next, $remain_next, $off_next) = ctx_statement_block($linenr, $realcnt, 0) if (!defined $stat); my ($stat_next) = ctx_statement_block($line_nr_next, $remain_next, $off_next); $stat_next =~ s/\n./\n /g; ##print "stat<$stat> stat_next<$stat_next>\n"; if ($stat_next =~ /^\s*while\b/) { # If the statement carries leading newlines, # then count those as offsets. my ($whitespace) = ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s); my $offset = statement_rawlines($whitespace) - 1; $suppress_whiletrailers{$line_nr_next + $offset} = 1; } } if (!defined $suppress_whiletrailers{$linenr} && defined($stat) && defined($cond) && $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) { my ($s, $c) = ($stat, $cond); my $fixed_assign_in_if = 0; if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) { if (ERROR("ASSIGN_IN_IF", "do not use assignment in if condition\n" . $herecurr) && $fix && $perl_version_ok) { if ($rawline =~ /^\+(\s+)if\s*\(\s*(\!)?\s*\(\s*(($Lval)\s*=\s*$LvalOrFunc)\s*\)\s*(?:($Compare)\s*($FuncArg))?\s*\)\s*(\{)?\s*$/) { my $space = $1; my $not = $2; my $statement = $3; my $assigned = $4; my $test = $8; my $against = $9; my $brace = $15; fix_delete_line($fixlinenr, $rawline); fix_insert_line($fixlinenr, "$space$statement;"); my $newline = "${space}if ("; $newline .= '!' if defined($not); $newline .= '(' if (defined $not && defined($test) && defined($against)); $newline .= "$assigned"; $newline .= " $test $against" if (defined($test) && defined($against)); $newline .= ')' if (defined $not && defined($test) && defined($against)); $newline .= ')'; $newline .= " {" if (defined($brace)); fix_insert_line($fixlinenr + 1, $newline); $fixed_assign_in_if = 1; } } } # Find out what is on the end of the line after the # conditional. substr($s, 0, length($c), ''); $s =~ s/\n.*//g; $s =~ s/$;//g; # Remove any comments if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ && $c !~ /}\s*while\s*/) { # Find out how long the conditional actually is. my @newlines = ($c =~ /\n/gs); my $cond_lines = 1 + $#newlines; my $stat_real = ''; $stat_real = raw_line($linenr, $cond_lines) . "\n" if ($cond_lines); if (defined($stat_real) && $cond_lines > 1) { $stat_real = "[...]\n$stat_real"; } if (ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line\n" . $herecurr . $stat_real) && !$fixed_assign_in_if && $cond_lines == 0 && $fix && $perl_version_ok && $fixed[$fixlinenr] =~ /^\+(\s*)((?:if|while|for)\s*$balanced_parens)\s*(.*)$/) { my $indent = $1; my $test = $2; my $rest = rtrim($4); if ($rest =~ /;$/) { $fixed[$fixlinenr] = "\+$indent$test"; fix_insert_line($fixlinenr + 1, "$indent\t$rest"); } } } } # Check for bitwise tests written as boolean if ($line =~ / (?: (?:\[|\(|\&\&|\|\|) \s*0[xX][0-9]+\s* (?:\&\&|\|\|) | (?:\&\&|\|\|) \s*0[xX][0-9]+\s* (?:\&\&|\|\||\)|\]) )/x) { WARN("HEXADECIMAL_BOOLEAN_TEST", "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr); } # if and else should not have general statements after it if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) { my $s = $1; $s =~ s/$;//g; # Remove any comments if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) { ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line\n" . $herecurr); } } # if should not continue a brace if ($line =~ /}\s*if\b/) { ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line (or did you mean 'else if'?)\n" . $herecurr); } # case and default should not have general statements after them if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g && $line !~ /\G(?: (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$| \s*return\s+ )/xg) { ERROR("TRAILING_STATEMENTS", "trailing statements should be on next line\n" . $herecurr); } # Check for }<nl>else {, these must be at the same # indent level to be relevant to each other. if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ && $previndent == $indent) { if (ERROR("ELSE_AFTER_BRACE", "else should follow close brace '}'\n" . $hereprev) && $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { fix_delete_line($fixlinenr - 1, $prevrawline); fix_delete_line($fixlinenr, $rawline); my $fixedline = $prevrawline; $fixedline =~ s/}\s*$//; if ($fixedline !~ /^\+\s*$/) { fix_insert_line($fixlinenr, $fixedline); } $fixedline = $rawline; $fixedline =~ s/^(.\s*)else/$1} else/; fix_insert_line($fixlinenr, $fixedline); } } if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ && $previndent == $indent) { my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0); # Find out what is on the end of the line after the # conditional. substr($s, 0, length($c), ''); $s =~ s/\n.*//g; if ($s =~ /^\s*;/) { if (ERROR("WHILE_AFTER_BRACE", "while should follow close brace '}'\n" . $hereprev) && $fix && $prevline =~ /^\+/ && $line =~ /^\+/) { fix_delete_line($fixlinenr - 1, $prevrawline); fix_delete_line($fixlinenr, $rawline); my $fixedline = $prevrawline; my $trailing = $rawline; $trailing =~ s/^\+//; $trailing = trim($trailing); $fixedline =~ s/}\s*$/} $trailing/; fix_insert_line($fixlinenr, $fixedline); } } } #Specific variable tests while ($line =~ m{($Constant|$Lval)}g) { my $var = $1; #CamelCase if ($var !~ /^$Constant$/ && $var =~ /[A-Z][a-z]|[a-z][A-Z]/ && #Ignore C keywords $var !~ /^_Generic$/ && #Ignore some autogenerated defines and enum values $var !~ /^(?:[A-Z]+_){1,5}[A-Z]{1,3}[a-z]/ && #Ignore Page<foo> variants $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && #Ignore ETHTOOL_LINK_MODE_<foo> variants $var !~ /^ETHTOOL_LINK_MODE_/ && #Ignore SI style variants like nS, mV and dB #(ie: max_uV, regulator_min_uA_show, RANGE_mA_VALUE) $var !~ /^(?:[a-z0-9_]*|[A-Z0-9_]*)?_?[a-z][A-Z](?:_[a-z0-9_]+|_[A-Z0-9_]+)?$/ && #Ignore some three character SI units explicitly, like MiB and KHz $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) { while ($var =~ m{\b($Ident)}g) { my $word = $1; next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/); if ($check) { seed_camelcase_includes(); if (!$file && !$camelcase_file_seeded) { seed_camelcase_file($realfile); $camelcase_file_seeded = 1; } } if (!defined $camelcase{$word}) { $camelcase{$word} = 1; CHK("CAMELCASE", "Avoid CamelCase: <$word>\n" . $herecurr); } } } } #no spaces allowed after \ in define if ($line =~ /\#\s*define.*\\\s+$/) { if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION", "Whitespace after \\ makes next lines useless\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\s+$//; } } # warn if <asm/foo.h> is #included and <linux/foo.h> is available and includes # itself <asm/foo.h> (uses RAW line) if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) { my $file = "$1.h"; my $checkfile = "include/linux/$file"; if (-f "$root/$checkfile" && $realfile ne $checkfile && $1 !~ /$allowed_asm_includes/) { my $asminclude = `grep -Ec "#include\\s+<asm/$file>" $root/$checkfile`; if ($asminclude > 0) { if ($realfile =~ m{^arch/}) { CHK("ARCH_INCLUDE_LINUX", "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr); } else { WARN("INCLUDE_LINUX", "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr); } } } } # Usually multi-statement macros should be enclosed in a do {} while # (0) loop. Grab the first statement and ensure its the whole macro # if its not enclosed in a known good container if ($realfile !~ m@/vmlinux.lds.h$@ && $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) { my $ln = $linenr; my $cnt = $realcnt; my ($off, $dstat, $dcond, $rest); my $ctx = ''; my $has_flow_statement = 0; my $has_arg_concat = 0; ($dstat, $dcond, $ln, $cnt, $off) = ctx_statement_block($linenr, $realcnt, 0); $ctx = $dstat; #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n"; #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n"; $has_flow_statement = 1 if ($ctx =~ /\b(goto|return)\b/); $has_arg_concat = 1 if ($ctx =~ /\#\#/ && $ctx !~ /\#\#\s*(?:__VA_ARGS__|args)\b/); $dstat =~ s/^.\s*\#\s*define\s+$Ident(\([^\)]*\))?\s*//; my $define_args = $1; my $define_stmt = $dstat; my @def_args = (); if (defined $define_args && $define_args ne "") { $define_args = substr($define_args, 1, length($define_args) - 2); $define_args =~ s/\s*//g; $define_args =~ s/\\\+?//g; @def_args = split(",", $define_args); } $dstat =~ s/$;//g; $dstat =~ s/\\\n.//g; $dstat =~ s/^\s*//s; $dstat =~ s/\s*$//s; # Flatten any parentheses and braces while ($dstat =~ s/\([^\(\)]*\)/1u/ || $dstat =~ s/\{[^\{\}]*\}/1u/ || $dstat =~ s/.\[[^\[\]]*\]/1u/) { } # Flatten any obvious string concatenation. while ($dstat =~ s/($String)\s*$Ident/$1/ || $dstat =~ s/$Ident\s*($String)/$1/) { } # Make asm volatile uses seem like a generic function $dstat =~ s/\b_*asm_*\s+_*volatile_*\b/asm_volatile/g; my $exceptions = qr{ $Declare| # named exceptions module_param_named| MODULE_PARM_DESC| DECLARE_PER_CPU| DEFINE_PER_CPU| static_assert| # declaration primitives __typeof__\(| union| struct| \.$Ident\s*=\s*| ^\"|\"$| ^\[ }x; #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n"; $ctx =~ s/\n*$//; my $stmt_cnt = statement_rawlines($ctx); my $herectx = get_stat_here($linenr, $stmt_cnt, $here); if ($dstat ne '' && $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(), $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo(); $dstat !~ /^[!~-]?(?:$Lval|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo // foo->bar // foo.bar->baz $dstat !~ /^'X'$/ && $dstat !~ /^'XX'$/ && # character constants $dstat !~ /$exceptions/ && $dstat !~ /^\.$Ident\s*=/ && # .foo = $dstat !~ /^(?:\#\s*$Ident|\#\s*$Constant)\s*$/ && # stringification #foo $dstat !~ /^case\b/ && # case ... $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...) $dstat !~ /^while\s*$Constant\s*$Constant\s*$/ && # while (...) {...} $dstat !~ /^for\s*$Constant$/ && # for (...) $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() $dstat !~ /^do\s*{/ && # do {... $dstat !~ /^\(\{/ && # ({... $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) { if ($dstat =~ /^\s*if\b/) { ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE", "Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects\n" . "$herectx"); } elsif ($dstat =~ /;/) { WARN("MULTISTATEMENT_MACRO_USE_DO_WHILE", "Non-declarative macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx\nBUT SEE:\n$DO_WHILE_0_ADVICE"); } else { ERROR("COMPLEX_MACRO", "Macros with complex values should be enclosed in parentheses\n" . "$herectx\nBUT SEE:\n$DO_WHILE_0_ADVICE"); } } # Make $define_stmt single line, comment-free, etc my @stmt_array = split('\n', $define_stmt); my $first = 1; $define_stmt = ""; foreach my $l (@stmt_array) { $l =~ s/\\$//; if ($first) { $define_stmt = $l; $first = 0; } elsif ($l =~ /^[\+ ]/) { $define_stmt .= substr($l, 1); } } $define_stmt =~ s/$;//g; $define_stmt =~ s/\s+/ /g; $define_stmt = trim($define_stmt); # check if any macro arguments are reused (ignore '...' and 'type') foreach my $arg (@def_args) { next if ($arg =~ /\.\.\./); next if ($arg =~ /^type$/i); my $tmp_stmt = $define_stmt; $tmp_stmt =~ s/\b(__must_be_array|offsetof|sizeof|sizeof_field|__stringify|typeof|__typeof__|__builtin\w+|typecheck\s*\(\s*$Type\s*,|\#+)\s*\(*\s*$arg\s*\)*\b//g; $tmp_stmt =~ s/\#+\s*$arg\b//g; $tmp_stmt =~ s/\b$arg\s*\#\#//g; my $use_cnt = () = $tmp_stmt =~ /\b$arg\b/g; if ($use_cnt > 1) { CHK("MACRO_ARG_REUSE", "Macro argument reuse '$arg' - possible side-effects?\n" . "$herectx"); } # check if any macro arguments may have other precedence issues if ($tmp_stmt =~ m/($Operators)?\s*\b$arg\b\s*($Operators)?/m && ((defined($1) && $1 ne ',') || (defined($2) && $2 ne ','))) { CHK("MACRO_ARG_PRECEDENCE", "Macro argument '$arg' may be better as '($arg)' to avoid precedence issues\n" . "$herectx"); } # check if this is an unused argument if ($define_stmt !~ /\b$arg\b/ && $define_stmt) { WARN("MACRO_ARG_UNUSED", "Argument '$arg' is not used in function-like macro\n" . "$herectx"); } } # check for macros with flow control, but without ## concatenation # ## concatenation is commonly a macro that defines a function so ignore those if ($has_flow_statement && !$has_arg_concat) { my $cnt = statement_rawlines($ctx); my $herectx = get_stat_here($linenr, $cnt, $here); WARN("MACRO_WITH_FLOW_CONTROL", "Macros with flow control statements should be avoided\n" . "$herectx"); } # check for line continuations outside of #defines, preprocessor #, and asm } elsif ($realfile =~ m@/vmlinux.lds.h$@) { $line =~ s/(\w+)/$maybe_linker_symbol{$1}++/ge; #print "REAL: $realfile\nln: $line\nkeys:", sort keys %maybe_linker_symbol; } else { if ($prevline !~ /^..*\\$/ && $line !~ /^\+\s*\#.*\\$/ && # preprocessor $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm $line =~ /^\+.*\\$/) { WARN("LINE_CONTINUATIONS", "Avoid unnecessary line continuations\n" . $herecurr); } } # do {} while (0) macro tests: # single-statement macros do not need to be enclosed in do while (0) loop, # macro should not end with a semicolon if ($perl_version_ok && $realfile !~ m@/vmlinux.lds.h$@ && $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) { my $ln = $linenr; my $cnt = $realcnt; my ($off, $dstat, $dcond, $rest); my $ctx = ''; ($dstat, $dcond, $ln, $cnt, $off) = ctx_statement_block($linenr, $realcnt, 0); $ctx = $dstat; $dstat =~ s/\\\n.//g; $dstat =~ s/$;/ /g; if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) { my $stmts = $2; my $semis = $3; $ctx =~ s/\n*$//; my $cnt = statement_rawlines($ctx); my $herectx = get_stat_here($linenr, $cnt, $here); if (($stmts =~ tr/;/;/) == 1 && $stmts !~ /^\s*(if|while|for|switch)\b/) { WARN("SINGLE_STATEMENT_DO_WHILE_MACRO", "Single statement macros should not use a do {} while (0) loop\n" . "$herectx"); } if (defined $semis && $semis ne "") { WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON", "do {} while (0) macros should not be semicolon terminated\n" . "$herectx"); } } elsif ($dstat =~ /^\+\s*#\s*define\s+$Ident.*;\s*$/) { $ctx =~ s/\n*$//; my $cnt = statement_rawlines($ctx); my $herectx = get_stat_here($linenr, $cnt, $here); WARN("TRAILING_SEMICOLON", "macros should not use a trailing semicolon\n" . "$herectx"); } } # check for redundant bracing round if etc if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) { my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, 1); #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n"; #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n"; if ($#chunks > 0 && $level == 0) { my @allowed = (); my $allow = 0; my $seen = 0; my $herectx = $here . "\n"; my $ln = $linenr - 1; for my $chunk (@chunks) { my ($cond, $block) = @{$chunk}; # If the condition carries leading newlines, then count those as offsets. my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s); my $offset = statement_rawlines($whitespace) - 1; $allowed[$allow] = 0; #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n"; # We have looked at and allowed this specific line. $suppress_ifbraces{$ln + $offset} = 1; $herectx .= "$rawlines[$ln + $offset]\n[...]\n"; $ln += statement_rawlines($block) - 1; substr($block, 0, length($cond), ''); $seen++ if ($block =~ /^\s*{/); #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n"; if (statement_lines($cond) > 1) { #print "APW: ALLOWED: cond<$cond>\n"; $allowed[$allow] = 1; } if ($block =~/\b(?:if|for|while)\b/) { #print "APW: ALLOWED: block<$block>\n"; $allowed[$allow] = 1; } if (statement_block_size($block) > 1) { #print "APW: ALLOWED: lines block<$block>\n"; $allowed[$allow] = 1; } $allow++; } if ($seen) { my $sum_allowed = 0; foreach (@allowed) { $sum_allowed += $_; } if ($sum_allowed == 0) { WARN("BRACES", "braces {} are not necessary for any arm of this statement\n" . $herectx); } elsif ($sum_allowed != $allow && $seen != $allow) { CHK("BRACES", "braces {} should be used on all arms of this statement\n" . $herectx); } } } } if (!defined $suppress_ifbraces{$linenr - 1} && $line =~ /\b(if|while|for|else)\b/) { my $allowed = 0; # Check the pre-context. if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) { #print "APW: ALLOWED: pre<$1>\n"; $allowed = 1; } my ($level, $endln, @chunks) = ctx_statement_full($linenr, $realcnt, $-[0]); # Check the condition. my ($cond, $block) = @{$chunks[0]}; #print "CHECKING<$linenr> cond<$cond> block<$block>\n"; if (defined $cond) { substr($block, 0, length($cond), ''); } if (statement_lines($cond) > 1) { #print "APW: ALLOWED: cond<$cond>\n"; $allowed = 1; } if ($block =~/\b(?:if|for|while)\b/) { #print "APW: ALLOWED: block<$block>\n"; $allowed = 1; } if (statement_block_size($block) > 1) { #print "APW: ALLOWED: lines block<$block>\n"; $allowed = 1; } # Check the post-context. if (defined $chunks[1]) { my ($cond, $block) = @{$chunks[1]}; if (defined $cond) { substr($block, 0, length($cond), ''); } if ($block =~ /^\s*\{/) { #print "APW: ALLOWED: chunk-1 block<$block>\n"; $allowed = 1; } } if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) { my $cnt = statement_rawlines($block); my $herectx = get_stat_here($linenr, $cnt, $here); WARN("BRACES", "braces {} are not necessary for single statement blocks\n" . $herectx); } } # check for single line unbalanced braces if ($sline =~ /^.\s*\}\s*else\s*$/ || $sline =~ /^.\s*else\s*\{\s*$/) { CHK("BRACES", "Unbalanced braces around else statement\n" . $herecurr); } # check for unnecessary blank lines around braces if (($line =~ /^.\s*}\s*$/ && $prevrawline =~ /^.\s*$/)) { if (CHK("BRACES", "Blank lines aren't necessary before a close brace '}'\n" . $hereprev) && $fix && $prevrawline =~ /^\+/) { fix_delete_line($fixlinenr - 1, $prevrawline); } } if (($rawline =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) { if (CHK("BRACES", "Blank lines aren't necessary after an open brace '{'\n" . $hereprev) && $fix) { fix_delete_line($fixlinenr, $rawline); } } # no volatiles please my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b}; if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) { WARN("VOLATILE", "Use of volatile is usually wrong: see Documentation/process/volatile-considered-harmful.rst\n" . $herecurr); } # Check for user-visible strings broken across lines, which breaks the ability # to grep for the string. Make exceptions when the previous string ends in a # newline (multiple lines in one string constant) or '\t', '\r', ';', or '{' # (common in inline assembly) or is a octal \123 or hexadecimal \xaf value if ($line =~ /^\+\s*$String/ && $prevline =~ /"\s*$/ && $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) { if (WARN("SPLIT_STRING", "quoted string split across lines\n" . $hereprev) && $fix && $prevrawline =~ /^\+.*"\s*$/ && $last_coalesced_string_linenr != $linenr - 1) { my $extracted_string = get_quoted_string($line, $rawline); my $comma_close = ""; if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) { $comma_close = $1; } fix_delete_line($fixlinenr - 1, $prevrawline); fix_delete_line($fixlinenr, $rawline); my $fixedline = $prevrawline; $fixedline =~ s/"\s*$//; $fixedline .= substr($extracted_string, 1) . trim($comma_close); fix_insert_line($fixlinenr - 1, $fixedline); $fixedline = $rawline; $fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//; if ($fixedline !~ /\+\s*$/) { fix_insert_line($fixlinenr, $fixedline); } $last_coalesced_string_linenr = $linenr; } } # check for missing a space in a string concatenation if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) { WARN('MISSING_SPACE', "break quoted strings at a space character\n" . $hereprev); } # check for an embedded function name in a string when the function is known # This does not work very well for -f --file checking as it depends on patch # context providing the function name or a single line form for in-file # function declarations if ($line =~ /^\+.*$String/ && defined($context_function) && get_quoted_string($line, $rawline) =~ /\b$context_function\b/ && length(get_quoted_string($line, $rawline)) != (length($context_function) + 2)) { WARN("EMBEDDED_FUNCTION_NAME", "Prefer using '\"%s...\", __func__' to using '$context_function', this function's name, in a string\n" . $herecurr); } # check for unnecessary function tracing like uses # This does not use $logFunctions because there are many instances like # 'dprintk(FOO, "%s()\n", __func__);' which do not match $logFunctions if ($rawline =~ /^\+.*\([^"]*"$tracing_logging_tags{0,3}%s(?:\s*\(\s*\)\s*)?$tracing_logging_tags{0,3}(?:\\n)?"\s*,\s*__func__\s*\)\s*;/) { if (WARN("TRACING_LOGGING", "Unnecessary ftrace-like logging - prefer using ftrace\n" . $herecurr) && $fix) { fix_delete_line($fixlinenr, $rawline); } } # check for spaces before a quoted newline if ($rawline =~ /^.*\".*\s\\n/) { if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE", "unnecessary whitespace before a quoted newline\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/; } } # concatenated string without spaces between elements if ($line =~ /$String[A-Z_]/ || ($line =~ /([A-Za-z0-9_]+)$String/ && $1 !~ /^[Lu]$/)) { if (CHK("CONCATENATED_STRING", "Concatenated strings should use spaces between elements\n" . $herecurr) && $fix) { while ($line =~ /($String)/g) { my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); $fixed[$fixlinenr] =~ s/\Q$extracted_string\E([A-Za-z0-9_])/$extracted_string $1/; $fixed[$fixlinenr] =~ s/([A-Za-z0-9_])\Q$extracted_string\E/$1 $extracted_string/; } } } # uncoalesced string fragments if ($line =~ /$String\s*[Lu]?"/) { if (WARN("STRING_FRAGMENTS", "Consecutive strings are generally better as a single string\n" . $herecurr) && $fix) { while ($line =~ /($String)(?=\s*")/g) { my $extracted_string = substr($rawline, $-[0], $+[0] - $-[0]); $fixed[$fixlinenr] =~ s/\Q$extracted_string\E\s*"/substr($extracted_string, 0, -1)/e; } } } # check for non-standard and hex prefixed decimal printf formats my $show_L = 1; #don't show the same defect twice my $show_Z = 1; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { my $string = substr($rawline, $-[1], $+[1] - $-[1]); $string =~ s/%%/__/g; # check for %L if ($show_L && $string =~ /%[\*\d\.\$]*L([diouxX])/) { WARN("PRINTF_L", "\%L$1 is non-standard C, use %ll$1\n" . $herecurr); $show_L = 0; } # check for %Z if ($show_Z && $string =~ /%[\*\d\.\$]*Z([diouxX])/) { WARN("PRINTF_Z", "%Z$1 is non-standard C, use %z$1\n" . $herecurr); $show_Z = 0; } # check for 0x<decimal> if ($string =~ /0x%[\*\d\.\$\Llzth]*[diou]/) { ERROR("PRINTF_0XDECIMAL", "Prefixing 0x with decimal output is defective\n" . $herecurr); } } # check for line continuations in quoted strings with odd counts of " if ($rawline =~ /\\$/ && $sline =~ tr/"/"/ % 2) { WARN("LINE_CONTINUATIONS", "Avoid line continuations in quoted strings\n" . $herecurr); } # warn about #if 0 if ($line =~ /^.\s*\#\s*if\s+0\b/) { WARN("IF_0", "Consider removing the code enclosed by this #if 0 and its #endif\n" . $herecurr); } # warn about #if 1 if ($line =~ /^.\s*\#\s*if\s+1\b/) { WARN("IF_1", "Consider removing the #if 1 and its #endif\n" . $herecurr); } # check for needless "if (<foo>) fn(<foo>)" uses if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { my $tested = quotemeta($1); my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;'; if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) { my $func = $1; if (WARN('NEEDLESS_IF', "$func(NULL) is safe and this check is probably not required\n" . $hereprev) && $fix) { my $do_fix = 1; my $leading_tabs = ""; my $new_leading_tabs = ""; if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) { $leading_tabs = $1; } else { $do_fix = 0; } if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) { $new_leading_tabs = $1; if (length($leading_tabs) + 1 ne length($new_leading_tabs)) { $do_fix = 0; } } else { $do_fix = 0; } if ($do_fix) { fix_delete_line($fixlinenr - 1, $prevrawline); $fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/; } } } } # check for unnecessary "Out of Memory" messages if ($line =~ /^\+.*\b$logFunctions\s*\(/ && $prevline =~ /^[ \+]\s*if\s*\(\s*(\!\s*|NULL\s*==\s*)?($Lval)(\s*==\s*NULL\s*)?\s*\)/ && (defined $1 || defined $3) && $linenr > 3) { my $testval = $2; my $testline = $lines[$linenr - 3]; my ($s, $c) = ctx_statement_block($linenr - 3, $realcnt, 0); # print("line: <$line>\nprevline: <$prevline>\ns: <$s>\nc: <$c>\n\n\n"); if ($s =~ /(?:^|\n)[ \+]\s*(?:$Type\s*)?\Q$testval\E\s*=\s*(?:\([^\)]*\)\s*)?\s*$allocFunctions\s*\(/ && $s !~ /\b__GFP_NOWARN\b/ ) { WARN("OOM_MESSAGE", "Possible unnecessary 'out of memory' message\n" . $hereprev); } } # check for logging functions with KERN_<LEVEL> if ($line !~ /printk(?:_ratelimited|_once)?\s*\(/ && $line =~ /\b$logFunctions\s*\(.*\b(KERN_[A-Z]+)\b/) { my $level = $1; if (WARN("UNNECESSARY_KERN_LEVEL", "Possible unnecessary $level\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\s*$level\s*//; } } # check for logging continuations if ($line =~ /\bprintk\s*\(\s*KERN_CONT\b|\bpr_cont\s*\(/) { WARN("LOGGING_CONTINUATION", "Avoid logging continuation uses where feasible\n" . $herecurr); } # check for unnecessary use of %h[xudi] and %hh[xudi] in logging functions if (defined $stat && $line =~ /\b$logFunctions\s*\(/ && index($stat, '"') >= 0) { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; my $stat_real = get_stat_real($linenr, $lc); pos($stat_real) = index($stat_real, '"'); while ($stat_real =~ /[^\"%]*(%[\#\d\.\*\-]*(h+)[idux])/g) { my $pspec = $1; my $h = $2; my $lineoff = substr($stat_real, 0, $-[1]) =~ tr@\n@@; if (WARN("UNNECESSARY_MODIFIER", "Integer promotion: Using '$h' in '$pspec' is unnecessary\n" . "$here\n$stat_real\n") && $fix && $fixed[$fixlinenr + $lineoff] =~ /^\+/) { my $nspec = $pspec; $nspec =~ s/h//g; $fixed[$fixlinenr + $lineoff] =~ s/\Q$pspec\E/$nspec/; } } } # check for mask then right shift without a parentheses if ($perl_version_ok && $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ && $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so WARN("MASK_THEN_SHIFT", "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr); } # check for pointer comparisons to NULL if ($perl_version_ok) { while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) { my $val = $1; my $equal = "!"; $equal = "" if ($4 eq "!="); if (CHK("COMPARISON_TO_NULL", "Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/; } } } # check for bad placement of section $InitAttribute (e.g.: __initdata) if ($line =~ /(\b$InitAttribute\b)/) { my $attr = $1; if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) { my $ptr = $1; my $var = $2; if ((($ptr =~ /\b(union|struct)\s+$attr\b/ && ERROR("MISPLACED_INIT", "$attr should be placed after $var\n" . $herecurr)) || ($ptr !~ /\b(union|struct)\s+$attr\b/ && WARN("MISPLACED_INIT", "$attr should be placed after $var\n" . $herecurr))) && $fix) { $fixed[$fixlinenr] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e; } } } # check for $InitAttributeData (ie: __initdata) with const if ($line =~ /\bconst\b/ && $line =~ /($InitAttributeData)/) { my $attr = $1; $attr =~ /($InitAttributePrefix)(.*)/; my $attr_prefix = $1; my $attr_type = $2; if (ERROR("INIT_ATTRIBUTE", "Use of const init definition must use ${attr_prefix}initconst\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/$InitAttributeData/${attr_prefix}initconst/; } } # check for $InitAttributeConst (ie: __initconst) without const if ($line !~ /\bconst\b/ && $line =~ /($InitAttributeConst)/) { my $attr = $1; if (ERROR("INIT_ATTRIBUTE", "Use of $attr requires a separate use of const\n" . $herecurr) && $fix) { my $lead = $fixed[$fixlinenr] =~ /(^\+\s*(?:static\s+))/; $lead = rtrim($1); $lead = "$lead " if ($lead !~ /^\+$/); $lead = "${lead}const "; $fixed[$fixlinenr] =~ s/(^\+\s*(?:static\s+))/$lead/; } } # check for __read_mostly with const non-pointer (should just be const) if ($line =~ /\b__read_mostly\b/ && $line =~ /($Type)\s*$Ident/ && $1 !~ /\*\s*$/ && $1 =~ /\bconst\b/) { if (ERROR("CONST_READ_MOSTLY", "Invalid use of __read_mostly with const type\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\s+__read_mostly\b//; } } # don't use __constant_<foo> functions outside of include/uapi/ if ($realfile !~ m@^include/uapi/@ && $line =~ /(__constant_(?:htons|ntohs|[bl]e(?:16|32|64)_to_cpu|cpu_to_[bl]e(?:16|32|64)))\s*\(/) { my $constant_func = $1; my $func = $constant_func; $func =~ s/^__constant_//; if (WARN("CONSTANT_CONVERSION", "$constant_func should be $func\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b$constant_func\b/$func/g; } } # prefer usleep_range over udelay if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) { my $delay = $1; # ignore udelay's < 10, however if (! ($delay < 10) ) { CHK("USLEEP_RANGE", "usleep_range is preferred over udelay; see function description of usleep_range() and udelay().\n" . $herecurr); } if ($delay > 2000) { WARN("LONG_UDELAY", "long udelay - prefer mdelay; see function description of mdelay().\n" . $herecurr); } } # warn about unexpectedly long msleep's if ($line =~ /\bmsleep\s*\((\d+)\);/) { if ($1 < 20) { WARN("MSLEEP", "msleep < 20ms can sleep for up to 20ms; see function description of msleep().\n" . $herecurr); } } # check for comparisons of jiffies if ($line =~ /\bjiffies\s*$Compare|$Compare\s*jiffies\b/) { WARN("JIFFIES_COMPARISON", "Comparing jiffies is almost always wrong; prefer time_after, time_before and friends\n" . $herecurr); } # check for comparisons of get_jiffies_64() if ($line =~ /\bget_jiffies_64\s*\(\s*\)\s*$Compare|$Compare\s*get_jiffies_64\s*\(\s*\)/) { WARN("JIFFIES_COMPARISON", "Comparing get_jiffies_64() is almost always wrong; prefer time_after64, time_before64 and friends\n" . $herecurr); } # warn about #ifdefs in C files # if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) { # print "#ifdef in C files should be avoided\n"; # print "$herecurr"; # $clean = 0; # } # warn about spacing in #ifdefs if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) { if (ERROR("SPACING", "exactly one space required after that #$1\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/^(.\s*\#\s*(ifdef|ifndef|elif))\s{2,}/$1 /; } } # check for spinlock_t definitions without a comment. if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ || $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) { my $which = $1; if (!ctx_has_comment($first_line, $linenr)) { CHK("UNCOMMENTED_DEFINITION", "$1 definition without comment\n" . $herecurr); } } # check for memory barriers without a comment. my $barriers = qr{ mb| rmb| wmb }x; my $barrier_stems = qr{ mb__before_atomic| mb__after_atomic| store_release| load_acquire| store_mb| (?:$barriers) }x; my $all_barriers = qr{ (?:$barriers)| smp_(?:$barrier_stems)| virt_(?:$barrier_stems) }x; if ($line =~ /\b(?:$all_barriers)\s*\(/) { if (!ctx_has_comment($first_line, $linenr)) { WARN("MEMORY_BARRIER", "memory barrier without comment\n" . $herecurr); } } my $underscore_smp_barriers = qr{__smp_(?:$barrier_stems)}x; if ($realfile !~ m@^include/asm-generic/@ && $realfile !~ m@/barrier\.h$@ && $line =~ m/\b(?:$underscore_smp_barriers)\s*\(/ && $line !~ m/^.\s*\#\s*define\s+(?:$underscore_smp_barriers)\s*\(/) { WARN("MEMORY_BARRIER", "__smp memory barriers shouldn't be used outside barrier.h and asm-generic\n" . $herecurr); } # check for waitqueue_active without a comment. if ($line =~ /\bwaitqueue_active\s*\(/) { if (!ctx_has_comment($first_line, $linenr)) { WARN("WAITQUEUE_ACTIVE", "waitqueue_active without comment\n" . $herecurr); } } # check for data_race without a comment. if ($line =~ /\bdata_race\s*\(/) { if (!ctx_has_comment($first_line, $linenr)) { WARN("DATA_RACE", "data_race without comment\n" . $herecurr); } } # check for context_unsafe without a comment. if ($line =~ /\bcontext_unsafe\b/ && !ctx_has_comment($first_line, $linenr)) { WARN("CONTEXT_UNSAFE", "context_unsafe without comment\n" . $herecurr); } # check of hardware specific defines if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) { CHK("ARCH_DEFINES", "architecture specific defines should be avoided\n" . $herecurr); } # check that the storage class is not after a type if ($line =~ /\b($Type)\s+($Storage)\b/) { WARN("STORAGE_CLASS", "storage class '$2' should be located before type '$1'\n" . $herecurr); } # Check that the storage class is at the beginning of a declaration if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage/ && $line =~ /^.\s*(.+?)\$Storage\s/ && $1 !~ /[\,\)]\s*$/) { WARN("STORAGE_CLASS", "storage class should be at the beginning of the declaration\n" . $herecurr); } # check the location of the inline attribute, that it is between # storage class and type. if ($line =~ /\b$Type\s+$Inline\b/ || $line =~ /\b$Inline\s+$Storage\b/) { ERROR("INLINE_LOCATION", "inline keyword should sit between storage class and type\n" . $herecurr); } # Check for __inline__ and __inline, prefer inline if ($realfile !~ m@\binclude/uapi/@ && $line =~ /\b(__inline__|__inline)\b/) { if (WARN("INLINE", "plain inline is preferred over $1\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b(__inline__|__inline)\b/inline/; } } # Check for compiler attributes if ($realfile !~ m@\binclude/uapi/@ && $rawline =~ /\b__attribute__\s*\(\s*($balanced_parens)\s*\)/) { my $attr = $1; $attr =~ s/\s*\(\s*(.*)\)\s*/$1/; my %attr_list = ( "alias" => "__alias", "aligned" => "__aligned", "always_inline" => "__always_inline", "assume_aligned" => "__assume_aligned", "cold" => "__cold", "const" => "__attribute_const__", "copy" => "__copy", "designated_init" => "__designated_init", "externally_visible" => "__visible", "format" => "printf|scanf", "gnu_inline" => "__gnu_inline", "malloc" => "__malloc", "mode" => "__mode", "no_caller_saved_registers" => "__no_caller_saved_registers", "noclone" => "__noclone", "noinline" => "noinline", "nonstring" => "__nonstring", "noreturn" => "__noreturn", "packed" => "__packed", "pure" => "__pure", "section" => "__section", "used" => "__used", "weak" => "__weak" ); while ($attr =~ /\s*(\w+)\s*(${balanced_parens})?/g) { my $orig_attr = $1; my $params = ''; $params = $2 if defined($2); my $curr_attr = $orig_attr; $curr_attr =~ s/^[\s_]+|[\s_]+$//g; if (exists($attr_list{$curr_attr})) { my $new = $attr_list{$curr_attr}; if ($curr_attr eq "format" && $params) { $params =~ /^\s*\(\s*(\w+)\s*,\s*(.*)/; $new = "__$1\($2"; } else { $new = "$new$params"; } if (WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", "Prefer $new over __attribute__(($orig_attr$params))\n" . $herecurr) && $fix) { my $remove = "\Q$orig_attr\E" . '\s*' . "\Q$params\E" . '(?:\s*,\s*)?'; $fixed[$fixlinenr] =~ s/$remove//; $fixed[$fixlinenr] =~ s/\b__attribute__/$new __attribute__/; $fixed[$fixlinenr] =~ s/\}\Q$new\E/} $new/; $fixed[$fixlinenr] =~ s/ __attribute__\s*\(\s*\(\s*\)\s*\)//; } } } # Check for __attribute__ unused, prefer __always_unused or __maybe_unused if ($attr =~ /^_*unused/) { WARN("PREFER_DEFINED_ATTRIBUTE_MACRO", "__always_unused or __maybe_unused is preferred over __attribute__((__unused__))\n" . $herecurr); } } # Check for __attribute__ weak, or __weak declarations (may have link issues) if ($perl_version_ok && $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ && ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ || $line =~ /\b__weak\b/)) { ERROR("WEAK_DECLARATION", "Using weak declarations can have unintended link defects\n" . $herecurr); } # check for c99 types like uint8_t used outside of uapi/ and tools/ if ($realfile !~ m@\binclude/uapi/@ && $realfile !~ m@\btools/@ && $line =~ /\b($Declare)\s*$Ident\s*[=;,\[]/) { my $type = $1; if ($type =~ /\b($typeC99Typedefs)\b/) { $type = $1; my $kernel_type = 'u'; $kernel_type = 's' if ($type =~ /^_*[si]/); $type =~ /(\d+)/; $kernel_type .= $1; if (CHK("PREFER_KERNEL_TYPES", "Prefer kernel type '$kernel_type' over '$type'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b$type\b/$kernel_type/; } } } # check for cast of C90 native int or longer types constants if ($line =~ /(\(\s*$C90_int_types\s*\)\s*)($Constant)\b/) { my $cast = $1; my $const = $2; my $suffix = ""; my $newconst = $const; $newconst =~ s/${Int_type}$//; $suffix .= 'U' if ($cast =~ /\bunsigned\b/); if ($cast =~ /\blong\s+long\b/) { $suffix .= 'LL'; } elsif ($cast =~ /\blong\b/) { $suffix .= 'L'; } if (WARN("TYPECAST_INT_CONSTANT", "Unnecessary typecast of c90 int constant - '$cast$const' could be '$const$suffix'\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$cast\E$const\b/$newconst$suffix/; } } # check for sizeof(&) if ($line =~ /\bsizeof\s*\(\s*\&/) { WARN("SIZEOF_ADDRESS", "sizeof(& should be avoided\n" . $herecurr); } # check for sizeof without parenthesis if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) { if (WARN("SIZEOF_PARENTHESIS", "sizeof $1 should be sizeof($1)\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex; } } # check for struct spinlock declarations if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) { WARN("USE_SPINLOCK_T", "struct spinlock should be spinlock_t\n" . $herecurr); } # check for seq_printf uses that could be seq_puts if ($sline =~ /\bseq_printf\s*\(.*"\s*\)\s*;\s*$/) { my $fmt = get_quoted_string($line, $rawline); $fmt =~ s/%%//g; if ($fmt !~ /%/) { if (WARN("PREFER_SEQ_PUTS", "Prefer seq_puts to seq_printf\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bseq_printf\b/seq_puts/; } } } # check for vsprintf extension %p<foo> misuses if ($perl_version_ok && defined $stat && $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && $1 !~ /^_*volatile_*$/) { my $stat_real; my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; for (my $count = $linenr; $count <= $lc; $count++) { my $specifier; my $extension; my $qualifier; my $bad_specifier = ""; my $fmt = get_quoted_string($lines[$count - 1], raw_line($count, 0)); $fmt =~ s/%%//g; while ($fmt =~ /(\%[\*\d\.]*p(\w)(\w*))/g) { $specifier = $1; $extension = $2; $qualifier = $3; if ($extension !~ /[4SsBKRraEehMmIiUDdgVCbGNOxtf]/ || ($extension eq "f" && defined $qualifier && $qualifier !~ /^w/) || ($extension eq "4" && defined $qualifier && $qualifier !~ /^c(?:[hlbc]|hR)$/)) { $bad_specifier = $specifier; last; } if ($extension eq "x" && !defined($stat_real)) { if (!defined($stat_real)) { $stat_real = get_stat_real($linenr, $lc); } WARN("VSPRINTF_SPECIFIER_PX", "Using vsprintf specifier '\%px' potentially exposes the kernel memory layout, if you don't really need the address please consider using '\%p'.\n" . "$here\n$stat_real\n"); } } if ($bad_specifier ne "") { my $stat_real = get_stat_real($linenr, $lc); my $msg_level = \&WARN; my $ext_type = "Invalid"; my $use = ""; if ($bad_specifier =~ /p[Ff]/) { $use = " - use %pS instead"; $use =~ s/pS/ps/ if ($bad_specifier =~ /pf/); } elsif ($bad_specifier =~ /pA/) { $use = " - '%pA' is only intended to be used from Rust code"; $msg_level = \&ERROR; } &{$msg_level}("VSPRINTF_POINTER_EXTENSION", "$ext_type vsprintf pointer extension '$bad_specifier'$use\n" . "$here\n$stat_real\n"); } } } # Check for misused memsets if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/) { my $ms_addr = $2; my $ms_val = $7; my $ms_size = $12; if ($ms_size =~ /^(0x|)0$/i) { ERROR("MEMSET", "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n"); } elsif ($ms_size =~ /^(0x|)1$/i) { WARN("MEMSET", "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n"); } } # Check for memcpy(foo, bar, ETH_ALEN) that could be ether_addr_copy(foo, bar) # if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # if (WARN("PREFER_ETHER_ADDR_COPY", # "Prefer ether_addr_copy() over memcpy() if the Ethernet addresses are __aligned(2)\n" . "$here\n$stat\n") && # $fix) { # $fixed[$fixlinenr] =~ s/\bmemcpy\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/ether_addr_copy($2, $7)/; # } # } # Check for memcmp(foo, bar, ETH_ALEN) that could be ether_addr_equal*(foo, bar) # if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemcmp\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # WARN("PREFER_ETHER_ADDR_EQUAL", # "Prefer ether_addr_equal() or ether_addr_equal_unaligned() over memcmp()\n" . "$here\n$stat\n") # } # check for memset(foo, 0x0, ETH_ALEN) that could be eth_zero_addr # check for memset(foo, 0xFF, ETH_ALEN) that could be eth_broadcast_addr # if ($perl_version_ok && # defined $stat && # $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*ETH_ALEN\s*\)/) { # # my $ms_val = $7; # # if ($ms_val =~ /^(?:0x|)0+$/i) { # if (WARN("PREFER_ETH_ZERO_ADDR", # "Prefer eth_zero_addr over memset()\n" . "$here\n$stat\n") && # $fix) { # $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_zero_addr($2)/; # } # } elsif ($ms_val =~ /^(?:0xff|255)$/i) { # if (WARN("PREFER_ETH_BROADCAST_ADDR", # "Prefer eth_broadcast_addr() over memset()\n" . "$here\n$stat\n") && # $fix) { # $fixed[$fixlinenr] =~ s/\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*,\s*ETH_ALEN\s*\)/eth_broadcast_addr($2)/; # } # } # } # strcpy uses that should likely be strscpy if ($line =~ /\bstrcpy\s*\(/ && !is_userspace($realfile)) { WARN("STRCPY", "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr); } # strlcpy uses that should likely be strscpy if ($line =~ /\bstrlcpy\s*\(/ && !is_userspace($realfile)) { WARN("STRLCPY", "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr); } # strncpy uses that should likely be strscpy or strscpy_pad if ($line =~ /\bstrncpy\s*\(/ && !is_userspace($realfile)) { WARN("STRNCPY", "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr); } # ethtool_sprintf uses that should likely be ethtool_puts if ($line =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { if (WARN("PREFER_ETHTOOL_PUTS", "Prefer ethtool_puts over ethtool_sprintf with only two arguments\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; } } # use $rawline because $line loses %s via sanitization and thus we can't match against it. if ($rawline =~ /\bethtool_sprintf\s*\(\s*$FuncArg\s*,\s*\"\%s\"\s*,\s*$FuncArg\s*\)/) { if (WARN("PREFER_ETHTOOL_PUTS", "Prefer ethtool_puts over ethtool_sprintf with standalone \"%s\" specifier\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bethtool_sprintf\s*\(\s*($FuncArg)\s*,\s*"\%s"\s*,\s*($FuncArg)/ethtool_puts($1, $7)/; } } # typecasts on min/max could be min_t/max_t if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) { if (defined $2 || defined $7) { my $call = $1; my $cast1 = deparenthesize($2); my $arg1 = $3; my $cast2 = deparenthesize($7); my $arg2 = $8; my $cast; if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) { $cast = "$cast1 or $cast2"; } elsif ($cast1 ne "") { $cast = $cast1; } else { $cast = $cast2; } WARN("MINMAX", "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n"); } } # check usleep_range arguments if ($perl_version_ok && defined $stat && $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) { my $min = $1; my $max = $7; if ($min eq $max) { WARN("USLEEP_RANGE", "usleep_range should not use min == max args; see function description of usleep_range().\n" . "$here\n$stat\n"); } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ && $min > $max) { WARN("USLEEP_RANGE", "usleep_range args reversed, use min then max; see function description of usleep_range().\n" . "$here\n$stat\n"); } } # check for naked sscanf if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/ && ($stat !~ /$Ident\s*=\s*sscanf\s*$balanced_parens/ && $stat !~ /\bsscanf\s*$balanced_parens\s*(?:$Compare)/ && $stat !~ /(?:$Compare)\s*\bsscanf\s*$balanced_parens/)) { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; my $stat_real = get_stat_real($linenr, $lc); WARN("NAKED_SSCANF", "unchecked sscanf return value\n" . "$here\n$stat_real\n"); } # check for simple sscanf that should be kstrto<foo> if ($perl_version_ok && defined $stat && $line =~ /\bsscanf\b/) { my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; my $stat_real = get_stat_real($linenr, $lc); if ($stat_real =~ /\bsscanf\b\s*\(\s*$FuncArg\s*,\s*("[^"]+")/) { my $format = $6; my $count = $format =~ tr@%@%@; if ($count == 1 && $format =~ /^"\%(?i:ll[udxi]|[udxi]ll|ll|[hl]h?[udxi]|[udxi][hl]h?|[hl]h?|[udxi])"$/) { WARN("SSCANF_TO_KSTRTO", "Prefer kstrto<type> to single variable sscanf\n" . "$here\n$stat_real\n"); } } } # check for new externs in .h files. if ($realfile =~ /\.h$/ && $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) { if (CHK("AVOID_EXTERNS", "extern prototypes should be avoided in .h files\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(.*)\bextern\b\s*(.*)/$1$2/; } } # check for new externs in .c files. if ($realfile =~ /\.c$/ && defined $stat && $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s) { my $function_name = $1; my $paren_space = $2; my $s = $stat; if (defined $cond) { substr($s, 0, length($cond), ''); } if ($s =~ /^\s*;/) { WARN("AVOID_EXTERNS", "externs should be avoided in .c files\n" . $herecurr); } if ($paren_space =~ /\n/) { WARN("FUNCTION_ARGUMENTS", "arguments for function declarations should follow identifier\n" . $herecurr); } } elsif ($realfile =~ /\.c$/ && defined $stat && $stat =~ /^\+extern struct\s+(\w+)\s+(\w+)\[\];/) { my ($st_type, $st_name) = ($1, $2); for my $s (keys %maybe_linker_symbol) { #print "Linker symbol? $st_name : $s\n"; goto LIKELY_LINKER_SYMBOL if $st_name =~ /$s/; } WARN("AVOID_EXTERNS", "found a file-scoped extern type:$st_type name:$st_name in .c file\n" . "is this a linker symbol ?\n" . $herecurr); LIKELY_LINKER_SYMBOL: } elsif ($realfile =~ /\.c$/ && defined $stat && $stat =~ /^.\s*extern\s+/) { WARN("AVOID_EXTERNS", "externs should be avoided in .c files\n" . $herecurr); } # check for function declarations that have arguments without identifier names if (defined $stat && $stat =~ /^.\s*(?:extern\s+)?$Type\s*(?:$Ident|\(\s*\*\s*$Ident\s*\))\s*\(\s*([^{]+)\s*\)\s*;/s && $1 ne "void") { my $args = trim($1); while ($args =~ m/\s*($Type\s*(?:$Ident|\(\s*\*\s*$Ident?\s*\)\s*$balanced_parens)?)/g) { my $arg = trim($1); if ($arg =~ /^$Type$/ && $arg !~ /enum\s+$Ident$/) { WARN("FUNCTION_ARGUMENTS", "function definition argument '$arg' should also have an identifier name\n" . $herecurr); } } } # check for function definitions if ($perl_version_ok && defined $stat && $stat =~ /^.\s*(?:$Storage\s+)?$Type\s*($Ident)\s*$balanced_parens\s*{/s) { $context_function = $1; # check for multiline function definition with misplaced open brace my $ok = 0; my $cnt = statement_rawlines($stat); my $herectx = $here . "\n"; for (my $n = 0; $n < $cnt; $n++) { my $rl = raw_line($linenr, $n); $herectx .= $rl . "\n"; $ok = 1 if ($rl =~ /^[ \+]\{/); $ok = 1 if ($rl =~ /\{/ && $n == 0); last if $rl =~ /^[ \+].*\{/; } if (!$ok) { ERROR("OPEN_BRACE", "open brace '{' following function definitions go on the next line\n" . $herectx); } } # checks for new __setup's if ($rawline =~ /\b__setup\("([^"]*)"/) { my $name = $1; if (!grep(/$name/, @setup_docs)) { CHK("UNDOCUMENTED_SETUP", "__setup appears un-documented -- check Documentation/admin-guide/kernel-parameters.txt\n" . $herecurr); } } # check for pointless casting of alloc functions if ($line =~ /\*\s*\)\s*$allocFunctions\b/) { WARN("UNNECESSARY_CASTS", "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr); } # alloc style # p = alloc(sizeof(struct foo), ...) should be p = alloc(sizeof(*p), ...) if ($perl_version_ok && $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k|v)[mz]alloc(?:_node)?)\s*\(\s*(sizeof\s*\(\s*struct\s+$Lval\s*\))/) { CHK("ALLOC_SIZEOF_STRUCT", "Prefer $3(sizeof(*$1)...) over $3($4...)\n" . $herecurr); } # check for (kv|k)[mz]alloc that could be kmalloc_obj/kvmalloc_obj/kzalloc_obj/kvzalloc_obj if ($perl_version_ok && defined $stat && $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/) { my $oldfunc = $3; my $a1 = $4; my $newfunc = "kmalloc_obj"; $newfunc = "kvmalloc_obj" if ($oldfunc eq "kvmalloc"); $newfunc = "kvzalloc_obj" if ($oldfunc eq "kvzalloc"); $newfunc = "kzalloc_obj" if ($oldfunc eq "kzalloc"); if ($a1 =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/) { my $cnt = statement_rawlines($stat); my $herectx = get_stat_here($linenr, $cnt, $here); if (WARN("ALLOC_WITH_SIZEOF", "Prefer $newfunc over $oldfunc with sizeof\n" . $herectx) && $cnt == 1 && $fix) { $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*,/$1 = $newfunc($a1,/; } } } # check for (kv|k)[mz]alloc with multiplies that could be kmalloc_objs/kvmalloc_objs/kzalloc_objs/kvzalloc_objs if ($perl_version_ok && defined $stat && $stat =~ /^\+\s*($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)\s*,/) { my $oldfunc = $3; my $a1 = $4; my $a2 = $10; my $newfunc = "kmalloc_objs"; $newfunc = "kvmalloc_objs" if ($oldfunc eq "kvmalloc"); $newfunc = "kvzalloc_objs" if ($oldfunc eq "kvzalloc"); $newfunc = "kzalloc_objs" if ($oldfunc eq "kzalloc"); my $r1 = $a1; my $r2 = $a2; if ($a1 =~ /^sizeof\s*\S/) { $r1 = $a2; $r2 = $a1; } if ($r1 !~ /^sizeof\b/ && $r2 =~ /^sizeof\s*\S/ && !($r1 =~ /^$Constant$/ || $r1 =~ /^[A-Z_][A-Z0-9_]*$/)) { my $cnt = statement_rawlines($stat); my $herectx = get_stat_here($linenr, $cnt, $here); if (WARN("ALLOC_WITH_MULTIPLY", "Prefer $newfunc over $oldfunc with multiply\n" . $herectx) && $cnt == 1 && $fix) { my $sized = trim($r2); $sized =~ s/^sizeof\s*\S\(?([^\)]*)\)?$/$1/; $fixed[$fixlinenr] =~ s/\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*((?:kv|k)[mz]alloc)\s*\(\s*($FuncArg)\s*\*\s*($FuncArg)/$1 . ' = ' . "$newfunc(" . $sized . ', ' . trim($r1)/e; } } } # check for krealloc arg reuse if ($perl_version_ok && $line =~ /\b($Lval)\s*\=\s*(?:$balanced_parens)?\s*krealloc\s*\(\s*($Lval)\s*,/ && $1 eq $3) { WARN("KREALLOC_ARG_REUSE", "Reusing the krealloc arg is almost always a bug\n" . $herecurr); } # check for alloc argument mismatch if ($line =~ /\b((?:devm_)?((?:k|kv)?(calloc|malloc_array)(?:_node)?))\s*\(\s*sizeof\b/) { WARN("ALLOC_ARRAY_ARGS", "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr); } # check for multiple semicolons if ($line =~ /;\s*;\s*$/) { if (WARN("ONE_SEMICOLON", "Statements terminations use 1 semicolon\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/(\s*;\s*){2,}$/;/g; } } # check for #defines like: 1 << <digit> that could be BIT(digit), it is not exported to uapi if ($realfile !~ m@^include/uapi/@ && $line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) { my $ull = ""; $ull = "_ULL" if (defined($1) && $1 =~ /ll/i); if (CHK("BIT_MACRO", "Prefer using the BIT$ull macro\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/; } } # check for IS_ENABLED() without CONFIG_<FOO> ($rawline for comments too) if ($rawline =~ /\bIS_ENABLED\s*\(\s*(\w+)\s*\)/ && $1 !~ /^${CONFIG_}/) { WARN("IS_ENABLED_CONFIG", "IS_ENABLED($1) is normally used as IS_ENABLED(${CONFIG_}$1)\n" . $herecurr); } # check for #if defined CONFIG_<FOO> || defined CONFIG_<FOO>_MODULE if ($line =~ /^\+\s*#\s*if\s+defined(?:\s*\(?\s*|\s+)(${CONFIG_}[A-Z_]+)\s*\)?\s*\|\|\s*defined(?:\s*\(?\s*|\s+)\1_MODULE\s*\)?\s*$/) { my $config = $1; if (WARN("PREFER_IS_ENABLED", "Prefer IS_ENABLED(<FOO>) to ${CONFIG_}<FOO> || ${CONFIG_}<FOO>_MODULE\n" . $herecurr) && $fix) { $fixed[$fixlinenr] = "\+#if IS_ENABLED($config)"; } } # check for /* fallthrough */ like comment, prefer fallthrough; my @fallthroughs = ( 'fallthrough', '@fallthrough@', 'lint -fallthrough[ \t]*', 'intentional(?:ly)?[ \t]*fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)', '(?:else,?\s*)?FALL(?:S | |-)?THR(?:OUGH|U|EW)[ \t.!]*(?:-[^\n\r]*)?', 'Fall(?:(?:s | |-)[Tt]|t)hr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', 'fall(?:s | |-)?thr(?:ough|u|ew)[ \t.!]*(?:-[^\n\r]*)?', ); if ($raw_comment ne '') { foreach my $ft (@fallthroughs) { if ($raw_comment =~ /$ft/) { my $msg_level = \&WARN; $msg_level = \&CHK if ($file); &{$msg_level}("PREFER_FALLTHROUGH", "Prefer 'fallthrough;' over fallthrough comment\n" . $herecurr); last; } } } # check for switch/default statements without a break; if ($perl_version_ok && defined $stat && $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) { my $cnt = statement_rawlines($stat); my $herectx = get_stat_here($linenr, $cnt, $here); WARN("DEFAULT_NO_BREAK", "switch default: should use break\n" . $herectx); } # check for gcc specific __FUNCTION__ if ($line =~ /\b__FUNCTION__\b/) { if (WARN("USE_FUNC", "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\b__FUNCTION__\b/__func__/g; } } # check for uses of __DATE__, __TIME__, __TIMESTAMP__ while ($line =~ /\b(__(?:DATE|TIME|TIMESTAMP)__)\b/g) { ERROR("DATE_TIME", "Use of the '$1' macro makes the build non-deterministic\n" . $herecurr); } # check for use of yield() if ($line =~ /\byield\s*\(\s*\)/) { WARN("YIELD", "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr); } # check for comparisons against true and false if ($line =~ /\+\s*(.*?)\b(true|false|$Lval)\s*(==|\!=)\s*(true|false|$Lval)\b(.*)$/i) { my $lead = $1; my $arg = $2; my $test = $3; my $otype = $4; my $trail = $5; my $op = "!"; ($arg, $otype) = ($otype, $arg) if ($arg =~ /^(?:true|false)$/i); my $type = lc($otype); if ($type =~ /^(?:true|false)$/) { if (("$test" eq "==" && "$type" eq "true") || ("$test" eq "!=" && "$type" eq "false")) { $op = ""; } CHK("BOOL_COMPARISON", "Using comparison to $otype is error prone\n" . $herecurr); ## maybe suggesting a correct construct would better ## "Using comparison to $otype is error prone. Perhaps use '${lead}${op}${arg}${trail}'\n" . $herecurr); } } # check for semaphores initialized locked if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) { WARN("CONSIDER_COMPLETION", "consider using a completion\n" . $herecurr); } # recommend kstrto* over simple_strto* and strict_strto* if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) { WARN("CONSIDER_KSTRTO", "$1 is obsolete, use k$3 instead\n" . $herecurr); } # check for __initcall(), use device_initcall() explicitly or more appropriate function please if ($line =~ /^.\s*__initcall\s*\(/) { WARN("USE_DEVICE_INITCALL", "please use device_initcall() or more appropriate function instead of __initcall() (see include/linux/init.h)\n" . $herecurr); } # check for spin_is_locked(), suggest lockdep instead if ($line =~ /\bspin_is_locked\(/) { WARN("USE_LOCKDEP", "Where possible, use lockdep_assert_held instead of assertions based on spin_is_locked\n" . $herecurr); } # check for deprecated apis if ($line =~ /\b($deprecated_apis_search)\b\s*\(/) { my $deprecated_api = $1; my $new_api = $deprecated_apis{$deprecated_api}; WARN("DEPRECATED_API", "Deprecated use of '$deprecated_api', prefer '$new_api' instead\n" . $herecurr); } # check for various structs that are normally const (ops, kgdb, device_tree) # and avoid what seem like struct definitions 'struct foo {' if (defined($const_structs) && $line !~ /\bconst\b/ && $line =~ /\bstruct\s+($const_structs)\b(?!\s*\{)/) { WARN("CONST_STRUCT", "struct $1 should normally be const\n" . $herecurr); } # use of NR_CPUS is usually wrong # ignore definitions of NR_CPUS and usage to define arrays as likely right # ignore designated initializers using NR_CPUS if ($line =~ /\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ && $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ && $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ && $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/ && $line !~ /^.\s*\.\w+\s*=\s*.*\bNR_CPUS\b/) { WARN("NR_CPUS", "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr); } # Use of __ARCH_HAS_<FOO> or ARCH_HAVE_<BAR> is wrong. if ($line =~ /\+\s*#\s*define\s+((?:__)?ARCH_(?:HAS|HAVE)\w*)\b/) { ERROR("DEFINE_ARCH_HAS", "#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr); } # likely/unlikely comparisons similar to "(likely(foo) > 0)" if ($perl_version_ok && $line =~ /\b((?:un)?likely)\s*\(\s*$FuncArg\s*\)\s*$Compare/) { WARN("LIKELY_MISUSE", "Using $1 should generally have parentheses around the comparison\n" . $herecurr); } # return sysfs_emit(foo, fmt, ...) fmt without newline if ($line =~ /\breturn\s+sysfs_emit\s*\(\s*$FuncArg\s*,\s*($String)/ && substr($rawline, $-[6], $+[6] - $-[6]) !~ /\\n"$/) { my $offset = $+[6] - 1; if (WARN("SYSFS_EMIT", "return sysfs_emit(...) formats should include a terminating newline\n" . $herecurr) && $fix) { substr($fixed[$fixlinenr], $offset, 0) = '\\n'; } } # check for array definition/declarations that should use flexible arrays instead if ($sline =~ /^[\+ ]\s*\}(?:\s*__packed)?\s*;\s*$/ && $prevline =~ /^\+\s*(?:\}(?:\s*__packed\s*)?|$Type)\s*$Ident\s*\[\s*(0|1)\s*\]\s*;\s*$/) { if (ERROR("FLEXIBLE_ARRAY", "Use C99 flexible arrays - see https://docs.kernel.org/process/deprecated.html#zero-length-and-one-element-arrays\n" . $hereprev) && $1 == '0' && $fix) { $fixed[$fixlinenr - 1] =~ s/\[\s*0\s*\]/[]/; } } # nested likely/unlikely calls if ($line =~ /\b(?:(?:un)?likely)\s*\(\s*!?\s*(IS_ERR(?:_OR_NULL|_VALUE)?|WARN)/) { WARN("LIKELY_MISUSE", "nested (un)?likely() calls, $1 already uses unlikely() internally\n" . $herecurr); } # whine mightly about in_atomic if ($line =~ /\bin_atomic\s*\(/) { if ($realfile =~ m@^drivers/@) { ERROR("IN_ATOMIC", "do not use in_atomic in drivers\n" . $herecurr); } elsif ($realfile !~ m@^kernel/@) { WARN("IN_ATOMIC", "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr); } } # Complain about RCU Tasks Trace used outside of BPF (and of course, RCU). our $rcu_trace_funcs = qr{(?x: rcu_read_lock_trace | rcu_read_lock_trace_held | rcu_read_unlock_trace | call_rcu_tasks_trace | synchronize_rcu_tasks_trace | rcu_barrier_tasks_trace | rcu_request_urgent_qs_task )}; our $rcu_trace_paths = qr{(?x: kernel/bpf/ | include/linux/bpf | net/bpf/ | kernel/rcu/ | include/linux/rcu )}; if ($line =~ /\b($rcu_trace_funcs)\s*\(/) { if ($realfile !~ m{^$rcu_trace_paths}) { WARN("RCU_TASKS_TRACE", "use of RCU tasks trace is incorrect outside BPF or core RCU code\n" . $herecurr); } } # check for lockdep_set_novalidate_class if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ || $line =~ /__lockdep_no_validate__\s*\)/ ) { if ($realfile !~ m@^kernel/lockdep@ && $realfile !~ m@^include/linux/lockdep@ && $realfile !~ m@^drivers/base/core@) { ERROR("LOCKDEP", "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr); } } if ($line =~ /debugfs_create_\w+.*\b$mode_perms_world_writable\b/ || $line =~ /DEVICE_ATTR.*\b$mode_perms_world_writable\b/) { WARN("EXPORTED_WORLD_WRITABLE", "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr); } # check for DEVICE_ATTR uses that could be DEVICE_ATTR_<FOO> # and whether or not function naming is typical and if # DEVICE_ATTR permissions uses are unusual too if ($perl_version_ok && defined $stat && $stat =~ /\bDEVICE_ATTR\s*\(\s*(\w+)\s*,\s*\(?\s*(\s*(?:${multi_mode_perms_string_search}|0[0-7]{3,3})\s*)\s*\)?\s*,\s*(\w+)\s*,\s*(\w+)\s*\)/) { my $var = $1; my $perms = $2; my $show = $3; my $store = $4; my $octal_perms = perms_to_octal($perms); if ($show =~ /^${var}_show$/ && $store =~ /^${var}_store$/ && $octal_perms eq "0644") { if (WARN("DEVICE_ATTR_RW", "Use DEVICE_ATTR_RW\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*$store\s*\)/DEVICE_ATTR_RW(${var})/; } } elsif ($show =~ /^${var}_show$/ && $store =~ /^NULL$/ && $octal_perms eq "0444") { if (WARN("DEVICE_ATTR_RO", "Use DEVICE_ATTR_RO\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*$show\s*,\s*NULL\s*\)/DEVICE_ATTR_RO(${var})/; } } elsif ($show =~ /^NULL$/ && $store =~ /^${var}_store$/ && $octal_perms eq "0200") { if (WARN("DEVICE_ATTR_WO", "Use DEVICE_ATTR_WO\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bDEVICE_ATTR\s*\(\s*$var\s*,\s*\Q$perms\E\s*,\s*NULL\s*,\s*$store\s*\)/DEVICE_ATTR_WO(${var})/; } } elsif ($octal_perms eq "0644" || $octal_perms eq "0444" || $octal_perms eq "0200") { my $newshow = "$show"; $newshow = "${var}_show" if ($show ne "NULL" && $show ne "${var}_show"); my $newstore = $store; $newstore = "${var}_store" if ($store ne "NULL" && $store ne "${var}_store"); my $rename = ""; if ($show ne $newshow) { $rename .= " '$show' to '$newshow'"; } if ($store ne $newstore) { $rename .= " '$store' to '$newstore'"; } WARN("DEVICE_ATTR_FUNCTIONS", "Consider renaming function(s)$rename\n" . $herecurr); } else { WARN("DEVICE_ATTR_PERMS", "DEVICE_ATTR unusual permissions '$perms' used\n" . $herecurr); } } # Mode permission misuses where it seems decimal should be octal # This uses a shortcut match to avoid unnecessary uses of a slow foreach loop # o Ignore module_param*(...) uses with a decimal 0 permission as that has a # specific definition of not visible in sysfs. # o Ignore proc_create*(...) uses with a decimal 0 permission as that means # use the default permissions if ($perl_version_ok && defined $stat && $line =~ /$mode_perms_search/) { foreach my $entry (@mode_permission_funcs) { my $func = $entry->[0]; my $arg_pos = $entry->[1]; my $lc = $stat =~ tr@\n@@; $lc = $lc + $linenr; my $stat_real = get_stat_real($linenr, $lc); my $skip_args = ""; if ($arg_pos > 1) { $arg_pos--; $skip_args = "(?:\\s*$FuncArg\\s*,\\s*){$arg_pos,$arg_pos}"; } my $test = "\\b$func\\s*\\(${skip_args}($FuncArg(?:\\|\\s*$FuncArg)*)\\s*[,\\)]"; if ($stat =~ /$test/) { my $val = $1; $val = $6 if ($skip_args ne ""); if (!($func =~ /^(?:module_param|proc_create)/ && $val eq "0") && (($val =~ /^$Int$/ && $val !~ /^$Octal$/) || ($val =~ /^$Octal$/ && length($val) ne 4))) { ERROR("NON_OCTAL_PERMISSIONS", "Use 4 digit octal (0777) not decimal permissions\n" . "$here\n" . $stat_real); } if ($val =~ /^$Octal$/ && (oct($val) & 02)) { ERROR("EXPORTED_WORLD_WRITABLE", "Exporting writable files is usually an error. Consider more restrictive permissions.\n" . "$here\n" . $stat_real); } } } } # check for uses of S_<PERMS> that could be octal for readability while ($line =~ m{\b($multi_mode_perms_string_search)\b}g) { my $oval = $1; my $octal = perms_to_octal($oval); if (WARN("SYMBOLIC_PERMS", "Symbolic permissions '$oval' are not preferred. Consider using octal permissions '$octal'.\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\Q$oval\E/$octal/; } } # validate content of MODULE_LICENSE against list from include/linux/module.h if ($line =~ /\bMODULE_LICENSE\s*\(\s*($String)\s*\)/) { my $extracted_string = get_quoted_string($line, $rawline); my $valid_licenses = qr{ GPL| GPL\ v2| GPL\ and\ additional\ rights| Dual\ BSD/GPL| Dual\ MIT/GPL| Dual\ MPL/GPL| Proprietary }x; if ($extracted_string !~ /^"(?:$valid_licenses)"$/x) { WARN("MODULE_LICENSE", "unknown module license " . $extracted_string . "\n" . $herecurr); } if (!$file && $extracted_string eq '"GPL v2"') { if (WARN("MODULE_LICENSE", "Prefer \"GPL\" over \"GPL v2\" - see commit bf7fbeeae6db (\"module: Cure the MODULE_LICENSE \"GPL\" vs. \"GPL v2\" bogosity\")\n" . $herecurr) && $fix) { $fixed[$fixlinenr] =~ s/\bMODULE_LICENSE\s*\(\s*"GPL v2"\s*\)/MODULE_LICENSE("GPL")/; } } } # check for sysctl duplicate constants if ($line =~ /\.extra[12]\s*=\s*&(zero|one|int_max)\b/) { WARN("DUPLICATED_SYSCTL_CONST", "duplicated sysctl range checking value '$1', consider using the shared one in include/linux/sysctl.h\n" . $herecurr); } # Check that *_device_id tables have sentinel entries. if (defined $stat && $line =~ /struct\s+$dev_id_types\s+\w+\s*\[\s*\]\s*=\s*\{/) { my $stripped = $stat; # Strip diff line prefixes. $stripped =~ s/(^|\n)./$1/g; # Line continuations. $stripped =~ s/\\\n/\n/g; # Strip whitespace, empty strings, zeroes, and commas. $stripped =~ s/""//g; $stripped =~ s/0x0//g; $stripped =~ s/[\s$;,0]//g; # Strip field assignments. $stripped =~ s/\.$Ident=//g; if (!(substr($stripped, -4) eq "{}};" || substr($stripped, -6) eq "{{}}};" || $stripped =~ /ISAPNP_DEVICE_SINGLE_END}};$/ || $stripped =~ /ISAPNP_CARD_END}};$/ || $stripped =~ /NULL};$/ || $stripped =~ /PCMCIA_DEVICE_NULL};$/)) { ERROR("MISSING_SENTINEL", "missing sentinel in ID array\n" . "$here\n$stat\n"); } } # check for uninitialized pointers with __free attribute while ($line =~ /\*\s*($Ident)\s+__free\s*\(\s*$Ident\s*\)\s*[,;]/g) { ERROR("UNINITIALIZED_PTR_WITH_FREE", "pointer '$1' with __free attribute should be initialized\n" . $herecurr); } } # If we have no input at all, then there is nothing to report on # so just keep quiet. if ($#rawlines == -1) { exit(0); } # In mailback mode only produce a report in the negative, for # things that appear to be patches. if ($mailback && ($clean == 1 || !$is_patch)) { exit(0); } # This is not a patch, and we are in 'no-patch' mode so # just keep quiet. if (!$chk_patch && !$is_patch) { exit(0); } if (!$is_patch && $filename !~ /cover-letter\.patch$/) { ERROR("NOT_UNIFIED_DIFF", "Does not appear to be a unified-diff format patch\n"); } if ($is_patch && $has_commit_log && $chk_fixes_tag) { if ($needs_fixes_tag ne "" && !$is_revert && !$fixes_tag) { WARN("MISSING_FIXES_TAG", "The commit message has '$needs_fixes_tag', perhaps it also needs a 'Fixes:' tag?\n"); } } if ($is_patch && $has_commit_log && $chk_signoff) { if ($signoff == 0) { ERROR("MISSING_SIGN_OFF", "Missing Signed-off-by: line(s)\n"); } elsif ($authorsignoff != 1) { # authorsignoff values: # 0 -> missing sign off # 1 -> sign off identical # 2 -> names and addresses match, comments mismatch # 3 -> addresses match, names different # 4 -> names match, addresses different # 5 -> names match, addresses excluding subaddress details (refer RFC 5233) match my $sob_msg = "'From: $author' != 'Signed-off-by: $author_sob'"; if ($authorsignoff == 0) { ERROR("NO_AUTHOR_SIGN_OFF", "Missing Signed-off-by: line by nominal patch author '$author'\n"); } elsif ($authorsignoff == 2) { CHK("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email comments mismatch: $sob_msg\n"); } elsif ($authorsignoff == 3) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email name mismatch: $sob_msg\n"); } elsif ($authorsignoff == 4) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email address mismatch: $sob_msg\n"); } elsif ($authorsignoff == 5) { WARN("FROM_SIGN_OFF_MISMATCH", "From:/Signed-off-by: email subaddress mismatch: $sob_msg\n"); } } } print report_dump(); if ($summary && !($clean == 1 && $quiet == 1)) { print "$filename " if ($summary_file); print "total: $cnt_error errors, $cnt_warn warnings, " . (($check)? "$cnt_chk checks, " : "") . "$cnt_lines lines checked\n"; } if ($quiet == 0) { # If there were any defects found and not already fixing them if (!$clean and !$fix) { print << "EOM" NOTE: For some of the reported defects, checkpatch may be able to mechanically convert to the typical style using --fix or --fix-inplace. EOM } # If there were whitespace errors which cleanpatch can fix # then suggest that. if ($rpt_cleaners) { $rpt_cleaners = 0; print << "EOM" NOTE: Whitespace errors detected. You may wish to use scripts/cleanpatch or scripts/cleanfile EOM } } if ($clean == 0 && $fix && ("@rawlines" ne "@fixed" || $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) { my $newfile = $filename; $newfile .= ".EXPERIMENTAL-checkpatch-fixes" if (!$fix_inplace); my $linecount = 0; my $f; @fixed = fix_inserted_deleted_lines(\@fixed, \@fixed_inserted, \@fixed_deleted); open($f, '>', $newfile) or die "$P: Can't open $newfile for write\n"; foreach my $fixed_line (@fixed) { $linecount++; if ($file) { if ($linecount > 3) { $fixed_line =~ s/^\+//; print $f $fixed_line . "\n"; } } else { print $f $fixed_line . "\n"; } } close($f); if (!$quiet) { print << "EOM"; Wrote EXPERIMENTAL --fix correction(s) to '$newfile' Do _NOT_ trust the results written to this file. Do _NOT_ submit these changes without inspecting them for correctness. This EXPERIMENTAL file is simply a convenience to help rewrite patches. No warranties, expressed or implied... EOM } } if ($quiet == 0) { print "\n"; if ($clean == 1) { print "$vname has no obvious style problems and is ready for submission.\n"; } else { print "$vname has style problems, please review.\n"; } } return $clean; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/dev-docs/�������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�15250106036�013220� 5����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/dev-docs/extend-authors.sh��������������������������������������������������������������0000755�0001750�0001750�00000002222�15250106036�016527� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # Check if a starting tag is provided if [ $# -eq 0 ]; then echo "Usage: $0 <starting_tag>" echo "Example: $0 fuse-3.16.2" exit 1 fi START_TAG=$1 # Extract email addresses from git log git_emails=$(git log ${START_TAG}..HEAD --format='<%aE>' | sort -u | sed 's/^<//;s/>$//') # Extract email addresses from AUTHORS file authors_emails=$(grep -oP '(?<=<)[^>]+' AUTHORS | sort -u) # Find new email addresses (in git_emails but not in authors_emails) # -1 suppresses lines unique to AUTHORS, -3 suppresses lines common to both # Result: only lines unique to git_emails (i.e., new authors) new_emails=$(comm -1 -3 <(echo "$authors_emails") <(echo "$git_emails")) # If there are new email addresses, add corresponding authors to the AUTHORS file if [ -n "$new_emails" ]; then echo -e "\nNew authors to be added:" echo -e "\n# New authors since ${START_TAG}" >> AUTHORS for email in $new_emails; do author=$(git log -1 --format='%aN <%aE>' --author="$email") echo "$author" echo "$author" >> AUTHORS done echo "AUTHORS file has been updated." else echo "No new authors found since ${START_TAG}." fi ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/dev-docs/release-process.md�������������������������������������������������������������0000644�0001750�0001750�00000003477�15250106036�016651� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Release Process =============== * `set TAG fuse-A.B.C` * Update version in * `ChangeLog.rst` * `meson.build` * `include/fuse_common.h` (`#define FUSE_{MINOR/MAJOR}_VERSION`) * When creating new minor release: * Create signing key for the next release: `P=fuse-<A.B+1> signify-openbsd -G -n -p signify/$P.pub -s signify/$P.sec; git add signify/$P.pub` * Expire old release signing keys (keep one around just in case) * To update authors run : dev-docs/extend-authors.sh * `git commit --all -m "Released $TAG"` * `git tag $TAG` * Build tarball, `./make_release_tarball.sh` * Test build: * `cd fuse-x.y.z` * `md build && (cd build && meson .. && ninja)` * `sudo sudo chown root:root build/util/fusermount3` * `sudo chmod 4755 build/util/fusermount3` * `(cd build; ../test/run-tests.py --build-dir .)` * Upload API docs: * `rm -r ../libfuse.github.io/doxygen && cp -a doc/html ../libfuse.github.io/doxygen` * `git -C ../libfuse.github.io add doxygen/` * `git -C ../libfuse.github.io commit --all -m "Re-generated doxygen documentation"` * `git -C ../libfuse.github.io push` * `git checkout master && git push && git push --tags` * Create release on Github * Write announcement to fuse-devel Announcement email template ``` To: fuse-devel@lists.linux.dev Subject: [ANNOUNCE] libfuse XXXX has been released Dear all, I am pleased to announce the release of libfuse XXX. The source code is available for download at https://github.com/libfuse/libfuse/releases. Please report any issues on this mailing list or the GitHub issue tracker at https://github.com/libfuse/libfuse/issues. From ChangeLog.rst: [INSERT NEW ENTRIES] The following people have contributed code to this release: [INSERT CONTRIBUTORS] (a full list of credits containing all known contributors is included in the `AUTHORS` file). Best, -Nikolaus ``` �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/������������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�15250106404�012260� 5����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/Doxyfile����������������������������������������������������������������������������0000644�0001750�0001750�00000352153�15250106036�014000� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Doxyfile 1.9.6 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). # # Note: # # Use doxygen to compare the used configuration file with the template # configuration file: # doxygen -x [configFile] # Use doxygen to compare the used configuration file with the template # configuration file without replacing the environment variables or CMake type # replacement variables: # doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the configuration # file that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = libfuse # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doc # If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 # sub-directories (in 2 levels) under the output directory of each output format # and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to # control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO # Controls the number of sub-directories that will be created when # CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every # level increment doubles the number of directories, resulting in 4096 # directories at level 8 which is the default and also the maximum value. The # sub-directories are organized in 2 levels, the first level always has a fixed # number of 16 directories. # Minimum value: 0, maximum value: 8, default value: 8. # This tag requires that the tag CREATE_SUBDIRS is set to YES. CREATE_SUBDIRS_LEVEL = 8 # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, # Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English # (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, # Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with # English messages), Korean, Korean-en (Korean with English messages), Latvian, # Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, # Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, # Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = YES # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line # such as # /*************** # as being the beginning of a Javadoc-style comment "banner". If set to NO, the # Javadoc-style will behave just like regular comments and it will not be # interpreted by doxygen. # The default value is: NO. JAVADOC_BANNER = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # By default Python docstrings are displayed as preformatted text and doxygen's # special commands cannot be used. By setting PYTHON_DOCSTRING to NO the # doxygen's special commands can be used and the contents of the docstring # documentation blocks is shown as doxygen documentation. # The default value is: YES. PYTHON_DOCSTRING = YES # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". Note that you cannot put \n's in the value part of an alias # to insert newlines (in the resulting output). You can put ^^ in the value part # of an alias to insert a newline as if a physical newline was in the original # file. When you need a literal { or } or , in the value part of an alias you # have to escape them by means of a backslash (\), this can lead to conflicts # with the commands \{ and \} for these it is advised to use the version @{ and # @} or use a double escape (\\{ and \\}) ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice # sources only. Doxygen will then generate output that is more tailored for that # language. For instance, namespaces will be presented as modules, types will be # separated into more groups, etc. # The default value is: NO. OPTIMIZE_OUTPUT_SLICE = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, # Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, # VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the # default for Fortran type files). For instance to make doxygen treat .inc files # as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. When specifying no_extension you should add # * to the FILE_PATTERNS. # # Note see also the list of default file extension mappings. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 5. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. TOC_INCLUDE_HEADINGS = 5 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = NO # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 # The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing # speed. At this moment only the input processing can be done using multiple # threads. Since this is still an experimental feature the default is set to 1, # which effectively disables parallel processing. Please report any issues you # encounter. Generating dot graphs in parallel is controlled by the # DOT_NUM_THREADS setting. # Minimum value: 0, maximum value: 32, default value: 1. NUM_PROC_THREADS = 1 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual # methods of a class will be included in the documentation. # The default value is: NO. EXTRACT_PRIV_VIRTUAL = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = NO # If this flag is set to YES, the name of an unnamed parameter in a declaration # will be determined by the corresponding definition. By default unnamed # parameters remain unnamed in the output. # The default value is: YES. RESOLVE_UNNAMED_PARAMS = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # will also hide undocumented C++ concepts if enabled. This option has no effect # if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = YES # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # declarations. If set to NO, these declarations will be included in the # documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # With the correct setting of option CASE_SENSE_NAMES doxygen will better be # able to match the capabilities of the underlying filesystem. In case the # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that # are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. # Possible values are: SYSTEM, NO and YES. # The default value is: SYSTEM. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = NO # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_HEADERFILE tag is set to YES then the documentation for a class # will show which file needs to be included to use the class. # The default value is: YES. SHOW_HEADERFILE = YES # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. See also section "Changing the # layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as documenting some parameters in # a documented function twice, or documenting parameters that don't exist or # using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete # function parameter documentation. If set to NO, doxygen will accept that some # parameters have no documentation without warning. # The default value is: YES. WARN_IF_INCOMPLETE_DOC = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong parameter # documentation, but not about the absence of documentation. If EXTRACT_ALL is # set to YES then this flag will automatically be disabled. See also # WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO # If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about # undocumented enumeration values. If set to NO, doxygen will accept # undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: NO. WARN_IF_UNDOC_ENUM_VAL = NO # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. # Possible values are: NO, YES and FAIL_ON_WARNINGS. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # In the $text part of the WARN_FORMAT command it is possible that a reference # to a more specific place is given. To make it easier to jump to this place # (outside of doxygen) the user can define a custom "cut" / "paste" string. # Example: # WARN_LINE_FORMAT = "'vi $file +$line'" # See also: WARN_FORMAT # The default value is: at line $line of file $file. WARN_LINE_FORMAT = "at line $line of file $file" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the # warning and error messages are written to standard error. When as file - is # specified the warning and error messages are written to standard output # (stdout). WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. # See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # This tag can be used to specify the character encoding of the source files # that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify # character encoding on a per file pattern basis. Doxygen will compare the file # name with each pattern and apply the encoding instead of the default # INPUT_ENCODING) if there is a match. The character encodings are a list of the # form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding # "INPUT_ENCODING" for further information on supported encodings. INPUT_FILE_ENCODING = # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, # *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C # comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, # *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = *.h \ *.c \ *.h \ *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = example # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = *.c \ *.h # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # <filter> <input-file> # # where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that doxygen will use the data processed and written to standard output # for further processing, therefore nothing else, like debug statements or used # commands (so in case of a Windows batch file always use @echo OFF), should be # written to standard output. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = # The Fortran standard specifies that for fixed formatted Fortran code all # characters from position 72 are to be considered as comment. A common # extension is to allow longer lines before the automatic comment starts. The # setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can # be processed before the automatic comment starts. # Minimum value: 7, maximum value: 10000, default value: 72. FORTRAN_COMMENT_AFTER = 72 #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # entity all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = NO # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = NO # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = NO # The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) # that should be ignored while generating the index headers. The IGNORE_PREFIX # tag works for classes, function and member names. The entity will be placed in # the alphabetical list under the first letter of the entity name that remains # after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). # Note: Since the styling of scrollbars can currently not be overruled in # Webkit/Chromium, the styling will be left out of the default doxygen.css if # one or more extra stylesheets have been specified. So if scrollbar # customization is desired it has to be added explicitly. For an example see the # documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = doc/fast17-vangoor.pdf # The HTML_COLORSTYLE tag can be used to specify if the generated HTML output # should be rendered with a dark or light theme. # Possible values are: LIGHT always generate light mode output, DARK always # generate dark mode output, AUTO_LIGHT automatically set the mode according to # the user preference, use light mode if no preference is set (the default), # AUTO_DARK automatically set the mode according to the user preference, use # dark mode if no preference is set and TOGGLE allow to user to switch between # light and dark mode via a button. # The default value is: AUTO_LIGHT. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE = AUTO_LIGHT # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = NO # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have JavaScript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: # https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To # create a documentation set, doxygen will generate a Makefile in the HTML # output directory. Running make will produce the docset in that directory and # running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Doxygen generated docs" # This tag determines the URL of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDURL = # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # on Windows. In the beginning of 2021 Microsoft took the original page, with # a.o. the download links, offline the HTML help workshop was already many years # in maintenance mode). You can download the HTML help workshop from the web # archives at Installation executable (see: # http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo # ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location (absolute path # including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to # run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine tune the look of the index (see "Fine-tuning the output"). As an # example, the default style sheet generated by doxygen has an example that # shows how to put an image at the root of the tree instead of the PROJECT_NAME. # Since the tree basically has the same information as the tab index, you could # consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview # area (value NO) or if it should extend to the full height of the window (value # YES). Setting this to YES gives a layout similar to # https://docs.readthedocs.io with more room for contents, but less room for the # project logo, title, and description. If either GENERATE_TREEVIEW or # DISABLE_INDEX is set to NO, this option has no effect. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. FULL_SIDEBAR = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email # addresses. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. OBFUSCATE_EMAILS = YES # If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg # tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see # https://inkscape.org) to generate formulas as SVG images instead of PNGs for # the HTML output. These images will generally look nicer at scaled resolutions. # Possible values are: png (the default) and svg (looks nicer but requires the # pdf2svg or inkscape tool). # The default value is: png. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FORMULA_FORMAT = png # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. FORMULA_MACROFILE = # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side JavaScript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = NO # With MATHJAX_VERSION it is possible to specify the MathJax version to be used. # Note that the different versions of MathJax have different requirements with # regards to the different settings, so it is possible that also other MathJax # settings have to be changed when switching between the different MathJax # versions. # Possible values are: MathJax_2 and MathJax_3. # The default value is: MathJax_2. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_VERSION = MathJax_2 # When MathJax is enabled you can set the default output format to be used for # the MathJax output. For more details about the output format see MathJax # version 2 (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 # (see: # http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best # compatibility. This is the name for Mathjax version 2, for MathJax version 3 # this will be translated into chtml), NativeMML (i.e. MathML. Only supported # for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This # is the name for Mathjax version 3, for MathJax version 2 this will be # translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. The default value is: # - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 # - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # for MathJax version 2 (see # https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # For example for MathJax version 3 (see # http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): # MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: # http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use <access key> + S # (what the <access key> is depends on the OS and browser, but it is typically # <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down # key> to jump into the search results window, the results can be navigated # using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel # the search. The filter options can be selected when the cursor is inside the # search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> # to select a filter and <Enter> or <escape> to activate or cancel the filter # option. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a web server instead of a web client using JavaScript. There # are two flavors of web server based searching depending on the EXTERNAL_SEARCH # setting. When disabled, doxygen will generate a PHP script for searching and # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing # and searching needs to be provided by external tools. See the section # "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. SERVER_BASED_SEARCH = NO # When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP # script for searching. Instead the search results are written to an XML file # which needs to be processed by an external indexer. Doxygen will invoke an # external search engine pointed to by the SEARCHENGINE_URL option to obtain the # search results. # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: # https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. # This tag requires that the tag SEARCHENGINE is set to YES. EXTERNAL_SEARCH = NO # The SEARCHENGINE_URL should point to a search engine hosted by a web server # which will return the search results when EXTERNAL_SEARCH is enabled. # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library # Xapian (see: # https://xapian.org/). See the section "External Indexing and Searching" for # details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the # SEARCHDATA_FILE tag the name of this file can be specified. # The default file is: searchdata.xml. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHDATA_FILE = searchdata.xml # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are # all added to the same external search index. Each project needs to have a # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of # to a relative location where the documentation can be found. The format is: # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. # The default value is: YES. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: latex. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # # Note that when not enabling USE_PDFLATEX the default is latex when enabling # USE_PDFLATEX the default is pdflatex and when in the later case latex is # chosen this is overwritten by pdflatex. For specific output languages the # default can have been set differently, this depends on the implementation of # the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. # Note: This tag is used in the Makefile / make.bat. # See also: LATEX_MAKEINDEX_CMD for the part in the generated output file # (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex # The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to # generate index for LaTeX. In case there is no backslash (\) as first character # it will be automatically added in the LaTeX code. # Note: This tag is used in the generated output file (.tex). # See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. # The default value is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_MAKEINDEX_CMD = makeindex # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used by the # printer. # Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x # 14 inches) and executive (7.25 x 10.5 inches). # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just # by its name or with the correct syntax as to be used with the LaTeX # \usepackage command. To get the times font for instance you can specify : # EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} # To use the option intlimits with the amsmath package you can specify: # EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for # the generated LaTeX document. The header should contain everything until the # first chapter. If it is left blank doxygen will generate a standard header. It # is highly recommended to start with a default header using # doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty # and then modify the file new_header.tex. See also section "Doxygen usage" for # information on how to generate the default header that doxygen normally uses. # # Note: Only use a user-defined header if you know what you are doing! # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. The following # commands have a special meaning inside the header (and footer): For a # description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for # the generated LaTeX document. The footer should contain everything after the # last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what # special commands can be used inside the footer. See also section "Doxygen # usage" for information on how to generate the default footer that doxygen # normally uses. Note: Only use a user-defined footer if you know what you are # doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined # LaTeX style sheets that are included after the standard style sheets created # by doxygen. Using this option one can overrule certain style aspects. Doxygen # will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_EXTRA_STYLESHEET = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output # directory. Note that the files will be copied as-is; there are no commands or # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will # contain links (just like the HTML output) instead of page references. This # makes the output suitable for online browsing using a PDF viewer. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as # specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX # files. Set this option to YES, to get a higher quality PDF documentation. # # See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode # command to the generated LaTeX files. This will instruct LaTeX to keep running # if errors occur, instead of asking the user for help. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BATCHMODE = NO # If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the # index chapters (such as File Index, Compound Index, etc.) in the output. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HIDE_INDICES = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = plain # If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated # page will contain the date and time when the page was generated. Setting this # to NO can help when comparing the output of multiple runs. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_TIMESTAMP = NO # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the # LATEX_OUTPUT directory will be used. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_EMOJI_DIRECTORY = #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The # RTF output is optimized for Word 97 and may not look too pretty with other RTF # readers/editors. # The default value is: NO. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: rtf. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF # documents. This may be useful for small projects and may help to save some # trees in general. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will # contain hyperlink fields. The RTF file will contain links (just like the HTML # output) instead of page references. This makes the output suitable for online # browsing using Word or some other Word compatible readers that support those # fields. # # Note: WordPad (write) and others do not support links. # The default value is: NO. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # configuration file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's configuration file. A template extensions file can be # generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for # classes and files. # The default value is: NO. GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. A directory man3 will be created inside the directory specified by # MAN_OUTPUT. # The default directory is: man. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to the generated # man pages. In case the manual section does not start with a number, the number # 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is # optional. # The default value is: .3. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_EXTENSION = .3 # The MAN_SUBDIR tag determines the name of the directory created within # MAN_OUTPUT in which the man pages are placed. If defaults to man followed by # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real # man page(s). These additional files only source the real man page, but without # them the man command would be unable to find the correct page. # The default value is: NO. # This tag requires that the tag GENERATE_MAN is set to YES. MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that # captures the structure of the code including all documentation. # The default value is: NO. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: xml. # This tag requires that the tag GENERATE_XML is set to YES. XML_OUTPUT = xml # If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program # listings (including syntax highlighting and cross-referencing information) to # the XML output. Note that enabling this will significantly increase the size # of the XML output. # The default value is: YES. # This tag requires that the tag GENERATE_XML is set to YES. XML_PROGRAMLISTING = YES # If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include # namespace members in file scope as well, matching the HTML output. # The default value is: NO. # This tag requires that the tag GENERATE_XML is set to YES. XML_NS_MEMB_FILE_SCOPE = NO #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- # If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files # that can be used to generate PDF. # The default value is: NO. GENERATE_DOCBOOK = NO # The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in # front of it. # The default directory is: docbook. # This tag requires that the tag GENERATE_DOCBOOK is set to YES. DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an # AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module # file that captures the structure of the code including all documentation. # # Note that this feature is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI # output from the Perl module output. # The default value is: NO. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely # formatted so it can be parsed by a human reader. This is useful if you want to # understand what is going on. On the other hand, if this tag is set to NO, the # size of the Perl module output will be much smaller and Perl will parse it # just the same. # The default value is: YES. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file are # prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful # so different doxyrules.make files included by the same Makefile don't # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all # C-preprocessor directives found in the sources and include files. # The default value is: YES. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names # in the source code. If set to NO, only conditional compilation will be # performed. Macro expansion can be done in a controlled way by setting # EXPAND_ONLY_PREDEF to YES. # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and # EXPAND_AS_DEFINED tags. # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES, the include files in the # INCLUDE_PATH will be searched if a #include is found. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the # preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of # RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will be # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. # gcc). The argument of the tag is a list of macros of the form: name or # name=definition (no spaces). If the definition and the "=" are omitted, "=1" # is assumed. To prevent a macro definition from being undefined via #undef or # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. PREDEFINED = FUSE_USE_VERSION=35 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The # macro definition that is found in the sources will be used. Use the PREDEFINED # tag if you want to use a different macro definition that overrules the # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have # an all uppercase name, and do not end with a semicolon. Such function macros # are typically used for boiler-plate code, and will confuse the parser if not # removed. # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tag files. For each tag # file the location of the external documentation should be added. The format of # a tag file without this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where loc1 and loc2 can be relative or absolute paths or URLs. See the # section "Linking to external documentation" for more information about the use # of tag files. # Note: Each tag file must have a unique name (where the name does NOT include # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES, all external class will be listed in # the class index. If set to NO, only the inherited external classes will be # listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed # in the modules index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. EXTERNAL_GROUPS = YES # If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in # the related pages index. If set to NO, only the current project's pages will # be listed. # The default value is: YES. EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. DIA_PATH = # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. HAVE_DOT = NO # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of # processors available in the system. You can set it explicitly to a value # larger than 0 to get control over the balance between CPU load and processing # speed. # Minimum value: 0, maximum value: 32, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. DOT_NUM_THREADS = 0 # DOT_COMMON_ATTR is common attributes for nodes, edges and labels of # subgraphs. When you want a differently looking font in the dot files that # doxygen generates you can specify fontname, fontcolor and fontsize attributes. # For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node, # Edge and Graph Attributes specification</a> You need to make sure dot is able # to find the font, which can be done by putting it in a standard location or by # setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the # directory containing the font. Default graphviz fontsize is 14. # The default value is: fontname=Helvetica,fontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" # DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can # add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a # href=https://graphviz.org/doc/info/arrows.html>Complete documentation about # arrows shapes.</a> # The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" # DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes # around nodes set 'shape=plain' or 'shape=plaintext' <a # href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a> # The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" # You can set the path where dot can find font specified with fontname in # DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a # graph for each documented class showing the direct and indirect inheritance # relations. In case HAVE_DOT is set as well dot will be used to draw the graph, # otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set # to TEXT the direct and indirect inheritance relations will be shown as texts / # links. # Possible values are: NO, YES, TEXT and GRAPH. # The default value is: YES. CLASS_GRAPH = TEXT # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the # class with other documented classes. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for # groups, showing the direct groups dependencies. See also the chapter Grouping # in the manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. UML_LOOK = NO # If the UML_LOOK tag is enabled, the fields and methods are shown inside the # class node. If there are many fields or methods and many nodes the graph may # become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the # number of items for each type to make the size more manageable. Set this to 0 # for no limit. Note that the threshold may be exceeded by 50% before the limit # is enforced. So when you set the threshold to 10, up to 15 fields may appear, # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. # This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 # If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and # methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS # tag is set to YES, doxygen will add type and arguments for attributes and # methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen # will not generate fields with class member information in the UML graphs. The # class diagrams will look similar to the default class diagrams but using UML # notation for the relationships. # Possible values are: NO, YES and NONE. # The default value is: NO. # This tag requires that the tag UML_LOOK is set to YES. DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold # significantly it will wrapped across multiple lines. Some heuristics are apply # to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. DOT_WRAP_THRESHOLD = 17 # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented # files. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented # files. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH tag is set to YES then doxygen will generate a call # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. Disabling a call graph can be # accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALL_GRAPH = NO # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller # dependency graph for every global function or class method. # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. Disabling a caller graph can be # accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical # hierarchy of all classes instead of a textual one. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the # files in the directories. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES # The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels # of child directories generated in directory dependency graphs by dot. # Minimum value: 1, maximum value: 25, default value: 1. # This tag requires that the tag DIRECTORY_GRAPH is set to YES. DIR_GRAPH_MAX_DEPTH = 1 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: # http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). # Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, # png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. DOT_IMAGE_FORMAT = png # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. # # Note that this requires a modern browser other than Internet Explorer. Tested # and working are Firefox, Chrome, Safari, and Opera. # Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make # the SVG files visible. Older versions of IE do not have SVG support. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. INTERACTIVE_SVG = NO # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file or to the filename of jar file # to be used. If left blank, it is assumed PlantUML is not used or called during # a preprocessing step. Doxygen will generate a warning when it encounters a # \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a # configuration file for plantuml. PLANTUML_CFG_FILE = # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. PLANTUML_INCLUDE_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes # larger than this value, doxygen will truncate the graph, which is visualized # by representing a node as a red box. Note that doxygen if the number of direct # children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. # Minimum value: 0, maximum value: 10000, default value: 50. # This tag requires that the tag HAVE_DOT is set to YES. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs # generated by dot. A depth value of 3 means that only nodes reachable from the # root by following a path via at most 3 edges will be shown. Nodes that lay # further from the root node will be omitted. Note that setting this option to 1 # or 2 may greatly reduce the computation time needed for large code bases. Also # note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. # Minimum value: 0, maximum value: 1000, default value: 0. # This tag requires that the tag HAVE_DOT is set to YES. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support # this, this feature is disabled by default. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. # Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal # graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. # # Note: This setting is not only used for dot files but also for msc temporary # files. # The default value is: YES. DOT_CLEANUP = YES ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/README.NFS��������������������������������������������������������������������������0000644�0001750�0001750�00000004154�15250106036�013572� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������NFS exporting is supported in Linux kernels 2.6.27 or later. You need to add an fsid=NNN option to /etc/exports to make exporting a FUSE directory work. Filesystem support ------------------ NFS exporting works to some extent on all fuse filesystems, but not perfectly. This is due to the stateless nature of the protocol, the server has no way of knowing whether the client is keeping a reference to a file or not, and hence that file may be removed from the server's cache. In that case there has to be a way to look up that object using the inode number, otherwise an ESTALE error will be returned. 1) low-level interface Filesystems need to set FUSE_CAP_EXPORT_SUPPORT in conn->wants and 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. Furthermore, setting FUSE_CAP_EXPORT_SUPPORT requires the file system to handle node-ids (fuse_ino_t) that the file system may does not know about - e.g. a fuse FORGET request might have been received or the node-id was used in a previous instance of the file system daemon. The node-id might not be valid at all when an invalid handle is passed to open_by_handle_at(). This implies that the filesystem *must not* reuse node-ids even if generation numbers are set correctly. This is because generation numbers are not provided by the kernel to e.g. the getattr() handler, so the handler would be unable to tell if the provided node-id refers to the "known" current one, or a previous one that has been forgotten and re-used. 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-3.18.3/doc/README.custom-io��������������������������������������������������������������������0000644�0001750�0001750�00000016460�15250106036�015066� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������FUSE over a Custom Transport ============================ This document describes fuse_session_custom_io(), which lets a session speak the FUSE protocol over a file descriptor the caller provides instead of over /dev/fuse, and the validation such a caller has to do. The example that ships with libfuse, example/hello_ll_uds.c, uses an AF_UNIX socket, which is where the shorthand "UDS" comes from. The API itself does not care what the descriptor is: a socket, a pipe pair, anything a read() and a writev() work on. Disabled by Default ------------------- fuse_session_custom_io() returns -ENOTSUP and logs a message unless libfuse was built with: meson setup build -Denable-custom-io=true The hello_ll_uds example is built only with that option, and the test that drives it skips without it. The reason is the trust model described below, not the transport itself. The symbols remain exported in every build, so an application that calls fuse_session_custom_io() keeps linking and loading; it is refused at run time. How It Works ------------ A normal session gets its descriptor from the kernel and the kernel is the peer at the other end: fuse_session_new() | v fuse_session_mount() --> open /dev/fuse, mount() | v fuse_session_loop() --> read()/writev() on the /dev/fuse fd peer: the kernel FUSE module A custom io session never mounts anything. The caller connects the descriptor itself and hands it, plus the io callbacks, to the session: fuse_session_new() | v caller creates fd --> socket(), connect()/accept(), ... | v fuse_session_custom_io(se, &io, sizeof(io), fd) | v fuse_session_loop() --> io->read()/io->writev() on that fd peer: whatever is at the other end From FUSE_INIT onwards the protocol is identical. The peer sends requests in the same wire format the kernel would, and the session replies the same way. The io Callbacks ---------------- struct fuse_custom_io has five members. read and writev are mandatory: fuse_session_custom_io() returns -EINVAL without them, because libfuse cannot fall back to plain read()/writev() on a descriptor it does not own. 1. **read(fd, buf, buf_len, userdata)**: must deliver exactly one request per call. buf_len is the session buffer size. A return value smaller than sizeof(struct fuse_in_header) ends the session loop with -EIO and the message "short read on fuse device", which is also what a peer closing the connection looks like. 2. **writev(fd, iov, count, userdata)**: must write every iovec. 3. **splice_send** and **splice_receive**: optional. Without them the session does not offer FUSE_CAP_SPLICE_WRITE, FUSE_CAP_SPLICE_MOVE and FUSE_CAP_SPLICE_READ, so replies and requests are copied instead. 4. **clone_fd**: optional, called by the multi-threaded loop to get a descriptor per worker. Without it every worker shares the one descriptor. The descriptor is closed by fuse_session_destroy(). What a Custom io Session Does Not Have -------------------------------------- 1. **No mountpoint.** fuse_session_mount() and fusermount3 are not involved, so none of the mount options, the setuid helper or /etc/mtab bookkeeping apply. 2. **No kernel.** FUSE_INIT arrives from the peer, so protocol version and feature negotiation are whatever the peer asks for. 3. **No io_uring.** fuse_session_custom_io() clears se->uring.enable: the ring is issued against a /dev/fuse descriptor and would bypass the io callbacks entirely. A session reports this on its own stderr as "FUSE_INIT: io_uring=off:custom_io". 4. **No trustworthy credentials.** The uid, gid and pid that fuse_req_ctx() returns are the ones the peer wrote into fuse_in_header. The allow_root option compares that same uid against the session owner, so it states what the peer claims, not who the peer is. The Trust Model: Unverified Opcodes ----------------------------------- libfuse was written against one producer, the Linux kernel, which does not need to validate the requests it sends because it builds them itself. A kernel-built request always has: - a fuse_in_header whose len matches the bytes written, - the per-opcode header the opcode calls for, - name arguments NUL terminated inside the message, - count and size fields describing data that is actually present. libfuse repeats almost none of these checks. What it does check: - FUSE_INIT and CUSE_INIT: enough bytes for the major/minor fields, at dispatch time, otherwise EPROTO. - FUSE_WRITE handled by op.write_buf: fuse_write_in.size against the bytes received, otherwise EIO. - FUSE_NOTIFY_REPLY: the same check. - The extension block: FUSE_EXT_SIZE(total_extlen) against the buffer length. Every other opcode is taken at face value, in three classes: 1. **Entry counts.** fuse_batch_forget_in.count bounds the loop over the fuse_forget_one array that follows it. Nothing compares it to the bytes that arrived, so an inflated count reads count * 16 bytes past the array and hands them to op.forget or op.forget_multi as inode numbers and lookup counts. 2. **Payload lengths.** FUSE_SETXATTR passes fuse_setxattr_in.size to op.setxattr as the length of the value, without checking that many bytes were received. 3. **Strings.** Name arguments are handed to the filesystem as a const char * and are expected to be terminated. FUSE_SYMLINK, FUSE_RENAME, FUSE_RENAME2 and FUSE_SETXATTR locate their second argument at name + strlen(name) + 1. A name without a NUL runs off the end of the receive buffer. A malformed request therefore reads memory outside the receive buffer. The usual outcome is a crash of the filesystem process; the batch forget case also feeds the out-of-bounds words into the filesystem's inode bookkeeping. **A custom io peer owes the session the validation the kernel would have made unnecessary.** The read callback is the place for it, because that is the last point before libfuse parses the bytes. At minimum, per message: - reject a fuse_in_header whose len is below sizeof(struct fuse_in_header) or above the buffer size, and deliver exactly len bytes; - reject an opcode whose per-opcode header does not fit in what arrived; - check every count and size field against the remaining bytes; - check that every name argument is NUL terminated within the message. A peer that forwards requests it did not build, or that accepts connections from anything but itself, has to treat this as the security boundary it is. Example ------- example/hello_ll_uds.c serves the protocol on an AF_UNIX socket: se = fuse_session_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), NULL); cfd = create_socket(socket_path); /* socket, bind, listen, accept */ fuse_session_custom_io(se, &io, sizeof(io), cfd); fuse_session_loop(se); Its stream_read() reads the header, takes the length from it and reads the rest of the message, which is the framing the read callback contract asks for but none of the validation the section above asks for. It is an example of the API, not a model for a peer that is not trusted. See Also -------- - doc/README.fuse-io-uring - the other non-default transport - doc/README.mount - what a /dev/fuse session does instead - include/fuse_lowlevel.h - fuse_session_custom_io() and struct fuse_custom_io ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/README.fuse-io-uring����������������������������������������������������������������0000644�0001750�0001750�00000002536�15250106036�015637� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-over-io-uring uses io-uring for transport of kernel/userspace messages. See also https://docs.kernel.org/filesystems/fuse/fuse-io-uring.html In order to enable it, the kernel module needs to have it enabled: echo 1 > /sys/module/fuse/parameters/enable_uring Additionally, FUSE_CAP_OVER_IO_URING needs to be set and se->uring.enable has to be true. The latter can be achieved with the libfuse option '-o io_uring'. Default queue-depth is 8 and can be changed with the parameter '-oio_uring_q_depth'. As of now there is always one queue per core. A reduced number of cores in development. Benefits: - Improved performance by using io_uring for kernel/userspace communication - Reduced system call overhead compared to traditional FUSE - Asynchronous I/O operations Usage: To enable io_uring support when mounting a FUSE filesystem: 1. Enable kernel support: echo 1 > /sys/module/fuse/parameters/enable_uring 2. Mount with io_uring option: -o io_uring 3. Optionally adjust queue depth: -o io_uring_q_depth=<depth> Example: ./my_fuse_fs /source /mountpoint -o io_uring -o io_uring_q_depth=16 Requirements: - Linux kernel with io_uring and FUSE io_uring support enabled - libfuse compiled with io_uring support Build Dependencies: - liburing (for io_uring support) - libnuma (required alongside liburing) - meson build system with option: -Denable-io-uring=true ������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/README.fuse_reply_errors������������������������������������������������������������0000644�0001750�0001750�00000000261�15250106036�016710� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Under normal operation, a call to any fuse_reply_* function should not result in an error. Should the kernel abort the fuse connection, a fuse_reply_* call can return -ENOENT. �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/README.notifications����������������������������������������������������������������0000644�0001750�0001750�00000003552�15250106036�016016� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������During the life-cycle of a user-space filesystem the usual flow is: 1. User-space application does a filesystem-related syscall 2. Kernel VFS calls into the FUSE kernel driver 3. FUSE kernel redirects request to the user-space filesystem 4. User-space server replies to request 5. FUSE returns reply to VFS 6. User-space application gets reply from the kernel However, there are occasions where the filesystem needs to send notifications to the kernel that are not in reply to any particular request. If, for example, when a READ request of 4096 bytes results in the filesystem having more data available for the specific inode, it may be useful to provide this extra data to the kernel cache so that future read operations will be faster. FUSE provides mechanisms for a user-space server to send the kernel certain types of asynchronous notifications. Currently, these are the available notifications: |-------------+----------------------------------| | Operation | libfuse function | |-------------+----------------------------------| | POLL | fuse_lowlevel_notify_poll | | INVAL_INODE | fuse_lowlevel_notify_inval_inode | | ENTRY | fuse_lowlevel_notify_inval_entry | | STORE | fuse_lowlevel_notify_store | | RETRIEVE | fuse_lowlevel_notify_retrieve | | DELETE | fuse_lowlevel_notify_delete | | RESEND | - | |-------------+----------------------------------| One important restriction is that these asynchronous operations SHALL NOT be performed while executing other FUSE requests. Doing so will likely result in deadlocking the user-space filesystem server. In the example above, if the server is replying to a READ request and has extra data to add to the kernel cache, it needs to reply to the READ request first, and, e.g., signal a different thread to do the STORE. ������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/fast17-vangoor.pdf������������������������������������������������������������������0000644�0001750�0001750�00002222165�15250106036�015544� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������%PDF-1.5 %âãÏÓ 2 0 obj <</Length 34769/Length1 1629/Length2 33845/Length3 532/Filter/FlateDecode>>stream xœ¬·ctem·&ÛvvlÛv*¶mÛ¬˜Û¶m;ÛNÅvºž÷íÓ§ÇùúûÓ}~¬1Ö=qM\óž{/2"e:!{#Sq{;:&zFn€œ¥­‘«³²¡�,�’©¹+à¯� †ŒLÄÉÔÐÅÒÞNÔÐÅ” nj5503˜¸¸¸`È�"öžN–æ.�JU%u*Úÿ”üc0òüÍ_OgKs;�ùß7S{[S;—¿ÿ׎ʦ¦� S€™¥�)@D^ASJN@)!§ �0µ3u2´(¸ÙXd-�MíœM©�föN�›�Æöv&–ÿ”æLÿKÈ`pv05¶üëfêalêð�Šà`êdkéìü÷`é 0w2´sùÛ{€¥�±�«É? ü•›Ùÿ+!'û¿¶uÁì�]œ��,\�£*ˆŠÿ;O C—b;[þUìÍþZšØ»þSÒ¿taþj] -íœ.¦.ÿÄ22˜X:;Øzþ�ýÌÁÉò_i¸:[Ú™ÿg´�'SsC'Sgç¿0±ÿéÎÖ øßª7tp°ñü—·ý¿¬þW–.Φ6fô0LÌc»ü�mniÃðÏ HÙ™Ù˜ÿ-7quø�›©Ó¿DùÏÌPýMÂÐÄÞÎÆ`bjà gïò7$€òÿŽeúÿ>’ÿ(þo!ø¿…Þÿ7rÿ+GÿÛ%þ½ÏÿZÜÕÆFÎÐöï�ü{Á�þng€,àŸccèôÿ17´µ´ñü?8üWCuÓ'ùÿƒ#åbø·Bvæ a¤gü·ÐÒYÜÒÃÔDÁÒÅØ`fhó·Sÿ’«Ú™˜:ÙXÚ™þeô_ÍÐ1±1ý�Š…¥±µÝ?­gû7œ©�ÉMþ/IÿJ�á¿.Ó©þ’î¢âéð7£ÿYÃ{“ÿuøÇYXØÞàMÇÄÁ  cædû{×™�\l,¾ÿ‡@ÿbúÏóC'K€ößjÿ:ýSóÿ|þó¤û_`ÄìŒíMþeC;“¿“õ¿ÿ³tKGWS)Ñ¿33r12ÿKjìêäô—æ­€¿ø�ó¿&ßÔÔÃÔþ,zÅ p€öûuÓ2ƒxP[›íÒª€-qÔVe¢S/‰æyyëç­™L„e–K“Óvn¬í+ÙÓÐØÙíWÓFyø%õö7 Ͷ�vì¹Ü–™�<шô0q÷‡�*Èëàý‘&  q�7óír~1'¢¢£Œy_�‚þW�³b6–E �hÓ®‹{2Ÿ'#U¶µö¼¦î¸tÄLàêÊ‹ÒwÖ¦.®f´%*þ�¶�x¾m$ ¿�1�‹m¬Ô"›l:·[ž,©MÑFUZ÷œ3ñÌí6À0ñ8Iyícô ­t(‹'QPÑXÊK¶ìsÿœÝZÂó¨´û®>¯ö´°Q+ÞÌ8Dó²£¹–Q�PÇ$suv—8xõ¼êãrJ$Pæ“$àf-¡‹{²ðÞòËÅ9Â\¨ Ûb÷·ƒôüØ#¸i÷a …¿·cò@»ÿ`=ÅÂ-p\Ê‹ÆëÅÙA‚4/s ²k|ê…¾ “ä:›DXPpµ}±cCµÐ�Õé™ìÇÖ.} ßë4“àŸð„ Wn›L¹.î¸ÕÑ­¨ÚR{u”ðN0ûaùŸTƒÃ^àQä‰Èîf:]JÎJ÷m_KrÑó‘úÚaˆÇð&4ÅWX¶T;f1¹þQ5¬y&Rƒ¶¬FQƒ¾'‘TwG#žÕwj%b(�ç1Ú0/AÀ"„Líð48¿‚ü/åÏ<«Ò‘x;1¸ ᎋX�·Ìf‹òmX‘Œ;f—Z´Z¨¶U�¶ Ÿ…Ûu¦=‡Äì$‰JÓ6¾ƒ¥ÄXÿx´‹!pbw¬wi“Ý|­JÂ5N!-�gQÁVdžÙ˜üuÆìñbîÂñ¬¸iS€û,þä`ÁzxˆBb•ÿØÜà9F èdµÔ áû¬ª^È쫯|‘,Ö ý2õµpm‰ó™n[‹ñi¾×,x( ¿)C[ñåãõ6o“nìD.vˆ`©àÿ†�Úêw¥ŽÌÊ•½Ç¯�M­úí…{ûn3²:¥.`>aV¬÷Çùãã+A5²•›óú{oyaÒÈîÔ!bJ¸øs¦q‹Gvù}78'îÓdoh„Ð(‚søÂcø>ƒF[”ZÐdH�|íç¼==ÆrÌ/g}¡[ë0%tܸ,�ü@$#e-óÜay÷ �e= ¼¼]yC¾i¼&Ä<®Á)İŸ>Â*›…¬ŽZ1m¦<©�ïxºÛÁ#¦®5~W�Êã¶â ’G‡6qUÄôkß­S%^@@¢MRØžúl経é€3výaþj’·l/æÙ¤lå8ä•Á]ûSÚ Þèû²ÑÉà´: ÷Šq˜f�\2ÒïVóÙ†çðS ßc]°»Cµ3@J`Ù&_¥Dþ� l"Ñ­ ëÕø�zM´•̳zNU,R¯M@Ö£ô‰;-rfx��F¨â»÷\�½¸E~X—„w¿@#‰¾"±‚�™ðæÐ� ˜�t A_Œò�³&,„Ó1¶:õ¥džâñ ·zXZ=±£ßÓÌoq6ò ‘÷t+™Gˆ+5¿U®ÎÇâ!§öûÛ3ã^TÙ�¦82·Æ‡1ŽU(X5ý0ÐÏ­‹æôyh͆¥¼T´%®hygïr!„´M݈¦ì?o¤›,» m\ÈÖ¯{3>Zm=%®_Øòª[ÝL¯æ]Báx`\ G1+À“—®µŠ©§Æqì$!¡ê`Vkç�d"¶@Ù•³“>Ô¶î…<—O#2xqŠÕ)uB]¥µUqãû‡rù”nÊH)Þƒƒq"”uîGy4ºø¶syÀ€³v)>®”£¯,DJÂ^�ëC +‘–Eò=Ì©`š9p@�( rÞé¥vJ Fg…3Æå+wS¶®0)±Mg’2šK �Ιþ÷ªãt†=çBy¾ÞÁ`ßËŸ)M¦ô¤uyU¥×:…ª�¦Ütâ ½gÔ–D‰ÁÕÖy 6Ò3g�¤œŠ4µ—-Æ?m�Cb'1ßð‡h3Hv— !uÄt *Ç›N,9Uãt†Þ�á–l»qp¡]:” @z\\M'gö@¦LŠ$Š]îÍU�Gu<}O;!n¯i´7.yæYÒTUá§‚�láŒaü 'É2˜úX¶¹þÒD *1©äa\ïwU�hM¬0Mºt"àÒ°@æŽïìµ¼O’Om�LBÏÅ‚Æ<ÍZ¢h™ šôlq± ±ÛA�4 X |Âæ£m¤ ¾Ÿcå—,ŸÚ5a‡¼ˆÓÁ­ãË*)ü^˜.«gNcŸ24»#º§�|ç ¦.¹™åɆO}¾ý–€®ŸS xkLÊŸ”¦üvŸÈ¹xÈ, Є·€ÓKŸ3£àJAÓó]•/,}A÷"�+¹*/Ðßb.b �xº0{ƒuò©qÛ¶¥•È÷$û1˜QŒáØKÈ?1a–ý X·�C=ñÁADñÄ‹¤íé¹Ç˜$Oᶤ­åJ�`ä‡VjågæqéM•!Án+fælŒ‹é÷LتUV%O\èø¸ÅEtN@Åœî¼.ªâ§~‘àcàEBâF«¨vb™-WHßË=ì•H1w'/78ejao >õ—a´=LVHÉ¢ šÃSÑo'ÜE…‚;à F´éˆØ ¥]½û€ä˜:©^ÄK¼„ ˜ÓSJx»|š"ä¼½šÝb¢� ã�A$MeçJÕù ’yžŸ¹&îð>ɶQÀä9.¸†ß;“fsØj× ø@Pë�†Ã©#þ™ˆ·Ayêb¿UµÊçôZŠ4óhr\«atéI,}‡iá|«I%ã D—juhéa+¢ß²,w®:×h¨wåx •wEGBòHº‰Ït$,'|¶‹SÓÙ"ø\>EŽAn�Þ”F �n�D’ïá{å��ë"Æ.Û®}µý�ô#c´f—¦ã¤g<¸H¤Ù'TXÓ³¡_iË�§bç®»Wä±D5<îøWyßùLœûJÍö•L—SïåÎqG,A;—Tv�­§¥1ûFd@r#åŸ�cŽyûkÝcó¸Þ­«aB#Él ¾»Ó¨¡s(gÀ^ÆoðëL‡‹µtÀ#\¬ éAÉïdX‚|KÐyÄa¡Á š�öŠÇ‘U„/)«ì-ˆkÐÒ;âà0+{A]6Á…#Û“\ÊWÉ€„³ÄG*{›ø6¤‡”v$; ‚Ûs!u3Ô#¹.YÄ9�ä._VGžçveƒ›gSÁ°YYô¿ÎrÝ%g•޼µ`¼²!TUTt¿(»5nRè$_éGŠs\‹ÁnzÎ}jç•ð@.Éð…á1…(Êès‘OK¼LOcÍA¹»·îÃsÆs˜*{hm\‚)öáO%´…/‰~†•¶5åf߯9;²bw�Q´¯ÕVZ Ù+FÁ(ò ›³¿@sî—ú*VL$¶Ù–˜(¢C<¾ŠíB$YOæL1¿bö°�Í`5°|÷ƒvòè*�ÌzþnHã½"úÖ�È:ÑE­×,5&¯”¢2ϹE^R9ô¾øÙþ´;±F+4€7ûidP¯¿š‡'x·¦Nƶ¤Mè>®Á^W\Ií}éƒ ¹õ(ÍS~1äÖLdñ 2ŸŒR#К ¯ aL:uÚ´ Ì =y±ˆT3*¦ï‹ø{ݸÃjpëµ¶l~­Æ®ƒ?oz&ÕyâÒZ£ÙqœñÙvQ‡0¼gŒB5‹ v@p¯›JûDÿCP�òÕØqNu\¸ªØuƒW(�ü̬–%þà}ŠËàZo¯(Ë:TÛõœ¸â b6õ²÷h²œbØ(M).ÔÊþcÍ÷¢<ú.Oh‡�Œh裗ƒÑbpÐ) �A!ùó`ƒE]‡\-Km;z#O U#rg|9ƒÇÄ©*âgÑçc¶Ž¯�)BWøã»Ö³s¸|O7è2 Už[-P¢ÚvËŒ¾Š²VýÞ§smÓ[].{�&ß—îL•ÏEìeÅ]á»1¬p e) ¿3sÜQ;w˜Ï£PWÝB“CI¸IðpE+ñþ¥ Ç!éèÇtøò¯ÚIEÑ%!�Ä0s¥XŠDP[ã{ÃLª¶R™¹ÑŒGýóW¦æõÈл¼µ) %ñ˨£ÉM’}Ö픂yyËäÔÞ¤ç͵9)UOË�çöÒaT><rã�ªÜl¥ô£2æá$Ô"D¹s�‘ŒÛ×z8‘݋ȷG­ëð’%CBj±^agª“h=Ï“vÉŸ9‹ò™;µ–M¯äšÊûÄý•þ«Ê­†ªQÏY<Hò—Õù§‰=VÀT„Èe¹øšÌPze"¾�7ÔÅv�Ö·³B ÔÑ/âH�Ç~º³r¢°=q`0)Ýh….”ˆ¦ä öS¶áS|ù 3�2›X[ù% ¥×Ð;OÊP'àÜo'(ÞÀñžW!eõ A3N°ä§0~ �Ý’_æpAšîJ5ÛáÉ É3å…°«˜ «y%(eô÷aF@Kï2òû<IV!Úú‚×À{’´ýM¼~dsÅ!»ž6ªAà̉g—PC7,œAlz�eíMÍUÉCéºgVªÎš§µU.QîOz¥²uå0Fê§S{ÌI‚ËãX|Ø‘}÷Î)ë|Ö!f�/Üø“¢$Ÿ´p8_‹ž %ýžÃÉÍŠå,:® Cõ�4(šb#1�À†K¼öð¾ 0!nK�RY„6øiý+)Ú D&"¢*hßVÍ ä9}Cí%z’ÝåT6�†4�Çz°+ÀÜùÁQ$Þq®NUëuZn˜YáÚ|­õ„bãß žß.ùe²Î¹Ãñh‹Â“•[òJ»¦iOP„(~5Ž€~P£ú�Õõµ•`áïšC£X²ò�&üŒnrKf˜¿QÔ2Ú�ü6�0øÍv\å°Wß —î¨Aá¨QÙc—«Ê*�‰ÔñãùÞyÓ1�wSMàjèø�.cá>Ôù§T ÙEýí?Ø\¼Ç–ö‡³ô.οIcDŸ1>$ùå\xÕ|2U.z:Ä7-Øp„p?ŠJ²»T‹K‘šŠ˜íàcäLbÛÌ�EºË �Xõ¯_T4é%ÙŽQ2[TgÐ� Vã’¾,ì‘êqÔ Ä £õƒúɳäi˜0 ¿¶á «Æ)<Ö‚Ö¿'"r¶LŠ€öŽ \ 7^ñm¸9?]&ìzT´/@úÅ.¼fp#ÁdV¶ 9úvü:(íä• ŒË”¨xûò`ç2UY:ôj]'Ô¿üÌÈûÉAÕô°À1eª&º¼uX¨>zW“æÖKËPÖUë ÿ€µnäZÀ‘])†ó¢5ךi£V[£#ÿÜÐÏkð‹ÕóMÆè>? [4gðæ"ß>¼Œ¯MÀ0‚êqF~Y¡Ètbùø:wU|øå¸-¬9»ZpA�·Q~©' i QÈØ †EȲz³·�÷Ò9ðÉo[³ÝB}á�[R-OC+N¯Ø05�ø×zsÑÖ�“E$‚õŠô0Öé 7—AgÜžI1ÎóÆxˆB`�ŸÏΚÑ�¹ Âö£i¹�òûŽ:­F_¿,\ta Þ±K@ �ÍëŽZì³ÑÅ$cÆóØ9÷]ûR�”h¶ á2˜„²w-¶˜·¾Çll•�0±6xr y9÷ °É‰Ë,E}e}þNëa½ýfoÝÆÃ°Ð…í�IÅ=£Eá³Òž›î¥ûùÖo®8©÷�À?:õ鞀çùèú~8O¤OÔKÒ\äG¾ }ú¬ÚŸÝðy8†#¨Þ¶˜ª ¨û~yzÞá{J猖â [¿FŒBøFuÅÉ�IŽòŠ «ÚÚloWÜ+¹ÕòÖ®ÃëMÜšu§'×�˜ÙJ 1Rí>`*…ÜFÇv¹ä™äÎòå۩䛨…žÚ?Øû˜$K€k[›Ó˵�L{ Üßñ…r.ºS8¯ç1‰éÒwÛ Ý™ï9ªT.zíÔ¯@¦þĬzÝÌ[}68�Íek-•ÛñÜúi8‡o”’Dˆ}w1-Ö‚ý�Í-¾ú1 B‹8­sY|qŽ‚°Ë_ùö‡ "=äÎH/¯¹…ž±3ÿfáyÈ™aK˜ÂNÚĺÄ[T¯K’áÁø6æ)Ú§,5ÈÙýâ«ê”Èp­‘¸DW{K=��ïÅnU€�«3!º¥¨™.|£8ÔKÔ?z,j-òa‹Ñh:­Ì¡Ÿ¯ë w¤îQ€ É„[I9GZaÿëd»á¾¸Ì³cXù~/�²Û@qŒ«.IÃW‰Fø#ÃÃaǤΧXa™âüº˜.#½ÈÉ!r�nÑ9— _ãµö 9,İîI6_�SC¬«HV8s×"Åů ÌÕƒ¹É Ä*…wÔ„[zI]p&Ø…é¿y|ÐxD$€C¢V_5Íœ „ÉCª%¯òù#ÜË”d‰\³ìƒ’ÙÄpÄŸnŽM³‰Û¹ß›K¨J¦àø(ÔSô¾ïêOuÔ.&zŃ|g)Ç`wa’FÄèÿìñt<ÁÚÎ?~ ¬Ê 6®�RÜM×­'äãÀëúTÚz»~X?Á iéäÍBµk¬±Û¹¤Lc,ØÜª>e!UhúZ€ KÊÔ°Ý[ˆ«À; ‡Ö?à®w%¨éæ{¨Ÿb�“�`¡aƒ�‰ú@ þ‹'7¶æÝDgvæ´´FPðâú'iD¹}´ÐíL×ßLSiøEîìä�RñAüÆŽˆ+�·pt•ZHõMJ(½°›ÏâGs*•ă!ôæ8𹤘(§‡Ä[»òqÈTܱÚÊ;9Xa¥››<¢¸tcn7ê;Ç%І=<�c¡™Öê™0jY¿M;­>Ë�ì ™u(w‹ ѲÄR|–£ü·L;Z/vé'g#q,°ÃÖV€Ý]èâ ôÔáá̃PýzK®%/ɹ¤¨µ±û÷^×°YòxÌ  U;õ_“Š—¶÷!ÀTÙ¥­&ùfÞÛ*œ˜Sv�ÄZz0ˆ_Þ¿úÛ}¬·ÿ -¿ãðzùb­žL_´æ�‚£ Ë ‚w]¼Øâ‚Œ 0f—i‡�kˆ‰TŽ;lqàüÈU6þð5qK>äa>À�fu�‡Px·cßJîòÇѡĂ„bnN Äþ´Œ™Á9»ñ¤ŸV™ÞŽ«ˆ õyÈXpdî¥Avפª'52Q–Ÿbýy^æ­1KøÊŸ�°ŠNh3Bv»L3þûדWf°(E%9ñ›�Û�蜆®ýtâºÚ s¼.t}™‹GÆñèV�ÚpýÏ&úb4;Ìþ_ÐA�  dóÊA»^ Ü  ßØ”ÜAmööd?¨Ÿž]̈ûØ«ÁC ›váDãÈyH;TÔR¯íArLá%ቀù× ßZ»PUY[¹:UWå@–ÉÊ %MÒÑgˆHSqòq©Œ ´MúJ4kÜk£U¨™~IBY®4 kR'@hÐQô�k>e¬éK- Û…ù…Ïx˜3Œ3죕…–¯>Ð�a×é6´–?èm´ûß^ÖäªN†€½¶ºü ôfÍH;J˜ƒTE~?­Ï�Š£7™©e_Þ�·œiçK*ì«~ XÏò¤¡ÄÍã4gv]#~óQ69ª‘¯Ô¬1çtÎGñ©4�æI;ÕÙ�sh¨z×=Aæ—…Ë$'‰¯G´ò˜$`È23uNìßÊ�ïÌtÎ!ø¼ÑÃ3ιÕÇkM8Û€<&M¶Ö¤JzùRÎpá^O ºö÷ô‹~EE¥üÖµI�ä ÒjZ2O*œÈzœqøë„ö1̳ïsudyý;eÎø«1дõÖO À“O°[ï’�Gõ<[3‚œ4áÛ4 }O-¢”! |Íš"Zà¢k`ÝãB7ÍvJH={kž‹9ÿh gt­Óè;¬oK0wFÿIY ~½ˆ(p¤2 —‘ÆVàðñ™pô‡ä ÆÊâ®Ï â$ïjÌùSæ­?æbØAYŒGy_î#‹|ÌqM“ú ß$üÝŒ7]�*7?¸yÔÂ.Äï˜é¸È/3�21ym>Øõ87‰"�ži=æ÷Î[ Ïäñ=Èw‹Öh§ø£iÕ)?°i‘Œ×iæWñ¹·ÀjÅt+ºÜÀV•j¶Ü�–Y,…®AWÄ™^whcûM9¡½“Õ«ŽaÂ2ºtd¦Ô/áÛž!ÊVˆ|ÌPMV]ö-µ«gŸÓ{°­NPÚ›­rÿ–@I)Š.+шßâC‹¥š$ñÀ;þŒ!R¶„ÂÊòpˆTD6'û•ŽLÖKwá�´­Y6X@­§Zé¢äž-6d? pÄ ò~T`‹d .ˆ¥Ù¦´¿˜©Êóâ�”™ÕÂ~,uÊXMÓ¯j×Uîlnq™¹�£è5v¿k>~¬[b¾å€Xé•Ö‹¸ Š<®%†ø8Ø! k¾&Ñóø³�Ó%æ1gÂ…ýysH5mQyñ¸£+­+ç,£ùl’S� À‚(<í0+dð—¨ãÍ×@IÊÓô�û8žU2 Ø’)ò¶0¯2¤•ö.ÌÕ›Î@éTÑ� aKÑaà$Ðy€çç ¦ºÞPò91ò gíÙšëÊ0!øgúëµ’bD®Ÿæ;Z�­Ál¼9+;OÝ.¥™9+®�,üi’øœÑ_:W§n‹áb¿0PFM^x`åtwL±µGXyº´iôS!ßh%øƒ ¤Þ‡JL7u)-”Ò¼åkhJF'°5¸¸dËLäÉ9¡,MËÿÄÉáæþlꬨ󑿨ÁÆÙy}Ü@t_4dŸï(^~Çܬò7d?žÑ…ô­8ô³Ž«;(µûÎHáÏÆÛ–6èf’gZ@GªÄ_ $IjDù!r‰žþIÕ¾¯ov€ÐÅ8Ò}kÄÚý`ó>�ÇݾgªÕ‰]ü3«)<’�Ñá¸çø:7ùlu„gEöLAŒ©h -ÈC3Ýá èí¡)qàh±‘–tÇ‚¡;ønaã‰]Þ1½cï�}ïäo»#¯¥é1‘Åó˜é�:;Fžáºs!ý>Ü݉ô->›“¼4CBBÚÀ9<öª»tŒ{Ç«Znߊ,(—æK]¥¿Ïe© ׎?ýê|ˆ1A,1UšwBg2¢ƒ×ù;WDäx˨£xû.e†É�ÊïíÌêÃíóHf/Ùúµì²;¿0µ­×Õ_ºe;4û:w>C"÷lí§0�p�SK9ŒÇÊ{lðôPui®O¨¾Õ¿Y2³.ÝušâùüZÑøH“]{o6 �]í}õ.!²ÁÕ‡Õ\X?˜Ê>DRà@d©GרÓÎ�j0` ÿ(Bûû#Ñ•…é�hÀMYj"¸$œ"<: ]‚§Å]€¬� y¯N81{L½ŠmyÞaIÌv ¢‡Ý¡Yy=®Ò  ƒêŠcà@>߈åxk/Φ×.ûØ gKê8+‰ÈþD"¥PÆQH~}º·ï„{óÈÇŽ&Ú½l®¡í ¡óÚéFÊT”�ô“š1 [‘T2.W™^ �/AžÝ÷4W$‡Ü É ª­¾Ú¨D·¡¯‰~‡ÉïËýÃùÓã§V\º7ì®V!·ÀÏ™«ÁÔ'ªyÍê£!Ä›¾7¤&›gKe-ç›BnÂÕ4FY»š‘âÈû ¦_;¿ûÁ'íÅœ†Ï{^T§C¡Fªüَ׊ª³BÇZú\·a¶f‡¶0ÙÈœÇ�ÝÇdÔÉ'J´ç5ǵdÊ2SÖ6÷[î@Ìn‘�á ªæ5ðË1ÏËëi}©¶* B•TúCè­\%�OR½ÏZ‚ÇL/Ð)`Û6S¼ÝIt™®¦;vª"U'²æM$Rè^/x8þJ¿#ºÃ�ç* (àÑ5aqe¾T–/öQ 8o£¾æ�oï­i@˜]Ïêq æZ缿_K�öC1dùŸo±c¨TVfÛÕäͰ@OÛ ’OQ1vác`¹B£ÎMPȉ®ìL— hƒlR�1²­Ë)yɳéyÆáF~4zñã^á!ghŒäD¥Ë¶ÌÄà˜L¯á¤b#³˜]Š}Œ]g:Ó ÉÞ�5oÎ3ÿ9!ð’jAêE7ö‹)›Æë ;å}&âÔ XjÀYŒ9+|lÞ¬i˜h›tz‡È(ÉrF3Æ8IM‹ôêåó¥›Ê _ ±-µÈ}c¾;^>®XÁ.Ü‘¯›$?é×ÒT\•Z°öYÀyY¦ð‚y¬Ða{?jë„ÁžäêA‘ÖÖÙ_·špbÞÌxÆ ‹CþjËí*›=«œ´ÚÙPŒ¬"”Ê„žŽC1+¼“Wº›úãùs¾Jv6š[e}ôG�j1˜z?Ä™jЉDùÚ«¹�‰7Mç'Gõ+;5Ê´I�ï3s&‰FJ_…éÖ€Rð*¹´ÞmG’:0½òA7²¨jÕgZP0T0ÁN„çÀ¨Ó¯*R,ód}Ō֗ÚB/áX„1vÚ"}ðò¡4w í9Eônå"l¦zðÐÊ?iþŽ÷££:5Øó ]x@Õ6–ý„=�åcPY2ã¹j¬KÃmtãÑŸ÷q†xË "U‹#�¥i ,<%š»Ï’FÀ³ØÞ\„/‹|…_+#>7Qµy†ônÁÇ…ïöh¶®« ÕŸXf‡"Ñ”ÙOŠ à+ó4:ZgŪפr÷?Ñ!u�s¨ºaÌ, Ž 4Ò/‰ØOud%r} ˜çÅ„^ƒÜ�Iþ5M`¥Q+¦e–‹sOðúg4܈|Q°Õ'Öâ>$QÈw¬eÛñ8”ÿñ‹öð|–ºÏÀ‹,¿©ÝÊkãºæ…Œkæ>`ÎíÌB>x Òr0§ì‡{sãä&"£ŸŒó¼ª@:-ÝM%ÔøA~‡'§~“tš åcªé¢µØ9l¯�Fë�ä4[K' '#‡1¢�”æÐêoxlݧHa¯Þ,1|(Gi“ÊHHU´®‚~Z'­£ÌY/›ø ¹|ùC}‹ø0`Â ÛÆ«Z Õw©Å_uSoVß© ùBéUBƒ£~ù�arîmJ‰-îÑ9Æ´ü‹á-;VZlSŽ 0«�… U�…Ì:.aÇL « áÖª•ˆ™ª¥Z‘œDˆJ\Z<—A§7(L7¢ 4®uG¿h ×s³Yé­¡e¨T©èÌDî�{Üf½àI€EUë±Z„°´A/ų€ÕèÕ¼V=|5ò±%#—ÇwB˳NohïÉ׈ºÈ„ÇÛ5Ç £ávGª&šïõ쎳ÔAIH[­(9«2¶[4¤>ÓM¡|ù1HCD·–¤DƒMñJGÇÃo{ŒW|L•à�MHƒÜ¼4 ¼p±úl¾ä‚†úv¥¡�Ú[ûwüB�ë.(Iÿ¶ïe¸Ù�ÁA}¤Øò#d´“úóýá£4Qè„»�ÿNÍ$`±…×j1NÇ€ Kp;×yLÅ`W+c^y¶V4î ääw ÿ¹mž"ðyÚćË/àìJÆxÃ׳ŒÍ%ÏC,ëdügé €’®d¡îm‘+ŽÐy§†¨†‰‡V…A˜ƒ^¹]iZ[…YSâcù¤.zb‹’ø?{)…yâ\¹<LtzZ6œ^Ò Àß"§cPqN†9À"8H@džP–8Ëè8ºtŠú–ô®õsÞû˜ÍÙ¥TêÅW±Ê­B%œ¬ÆÕíTuc! $ëŒÙúÛ¸Tï€�ËU·´BqÊšÙ�’�3Ñ#‹Zó^=cÆf#}ûÑŒÿ~/€BÿºryPrG[zÙbz}Å ‘ �¨ÖI�$Ú‚1RÌeÊÈ‘ö$�xHc÷Æ|Ô"î¹§ÿU.�«öÑBÀùQk³Û¾­Y¯ÎÆW�qj`ÙFCð fzzÌܦŴ¾ ’ö&ªAïéàñj’uRíõÁŽ_Ãð¥[��פYÐtŒs`’3“ë)9íé“x48XÅMì{›VÑÎw�Ø08 Ypõ¬fž�ÆçF÷˜ºGÓ&ýf¤•~¶1Ĥ˜ýÎð[¹Q=†ÛFÉ5ªÃ!²‚–Îù²�8ÐV$Ï:†ûÀÑ]aR×#^v�lO¤0dU‰ù©�à€P %dÁš{NªŒ“PN2š­bÙ©öK|µæÖ|i‡æçö6‡)̺ÍoIÅhˆžÁÀ¤Gž=p™š4ÃG1a€{‰DÜ ªÉUl” èYœqØï1“ó@5(m¬Q”ª1ó‹(æ�¾î†án÷»Ëƒ8ujù:t"jiŒa�Oäß@\©5•÷dùêÕ#‹ÄÁ¥ZÑUÝz‘lþ8Ü ˆ·Æû‘�Uß®¶\@…ïm/4 à@ÙÒ ²ômkÇÏö™¸L·n²›·“k² ê{ï? íuLŒóUÒòPðU㊹Àò%0œ>¨ì—ÌLoãOúº[uxÓê;à òõ¡M�‘èäg[Ò¸/QJ hDJcÍ>4 �ÜM…‹Ê­�¥íKc•f”;ÅìN/Íh°A` Tc¢ÐžJµX Lðw¿�O»~h ©båê›Ia †ÉñúÞÀ)àN3ûvõšiE˜»ùÈ Þ^õŽ\‘7¨%EÅ6}å…´=�ùã¦Ân�S­R³ˆ½¢ùRí—4§PÑדt„?tÙE�²4�éã–J‘ ©FXæ*…»&ó)ßkŠ”*šqþŸú?H:qšì3¼Ãú•åþ·†xÛ}Ô/cTHçŸîÙCZR$úû™‰Ì|üccä(Uä€{­†æpèvJ„wá,û{¾’ÚÐÞv£Ù)ONT‹òqÊ¿±¸Œÿ�ûa?Cj~Fè}gYåR ÄØåE´«´ö+ØÍ/R7§‘É£tjä‘E]œ Bžn�ú‡÷edþo“Ú_ü„1?n8’ó"†ù¥.¡ûv Ï3Ø’Y�—Éþ4ì5ÐM3âŠái~ìwiüνf'ãPÝLî zâ'b¶ý ST¯WD/Möƒ_¬¿7÷0_ÔÓ@kJ”E0Pãé¯lµ(À0f$[A´¯pÆ¿Ú8 a¼nè4ÓÌwåceJÌýJT@øå�&û!¢i0²»·ZûÛR[�Sî @µ2)v›¦ÞËî¶ÌÓÂZ\Úb/ëâ5¬ã>ê=ï<äÿZwc/‘¯ªæ2¢Ë¨è„�?9^¤J}ë ‘è ´y4¯}úÜ–ÃjlK�‚1$>èšq6˜Þ†bqŸ×z«$� Á–²õ‚¡Kƶ÷u� ¼C…Õ­¡E�‰? ÉkæÕø#Oˆ=MÚäVU2�̬£ÕQ_ -<—e0ûÌýTj|þz·«m<¿ÒC>ãÒÛÿ^'úÑì2˲£P–f*¿o�Vƒ’ ê˜!ôhYc¥§.Éñ‡çN4 ô�S#Á>ï‘D‘öþ��ì»×žÀ¢€+ Z¦¯râÍêA-?o@5´‚b¬ì‰T|þèXÞáW#jÄ/„’.ƒ¾K#H•d¾­&¾ïá£P{¸ÄÆ�úþ�g°«±y�a¦3ÒW¶R®›×p»qÛþÅ¢9§ö"ûI¡/ý ²u¹̼üfªÙ$C4G�ÁÎ#C·ÒÖZY¡-&uÙ£ÊAÕ‘.Õ g‡M»%&•ëÎväíþjÒ‡_$r±î¥U-Qƒ&Äšœž›s²Ÿ%¼°ïÕŠ\!#u9ÒfûΑ&›‚Î9Õ�É`†ïšFÜé­`ÃJ*uÖô9Á–©¯áßš8­T&™íHõ‘œ°8h§.\»£ ‹)yé-|·²lŸ!ã4[ÂÔ °íKiŠw‹…ëî0ùÙ‰@)ÅkÒ·hñØôÈHEÜ\‰ÖšUSž¬å�á‘D¦žÿ0〠€9Áuvd$«ÈóÄE< ¨ÁÔú©§%´’1m8®Œ °e·­Ux¥‘ï1i¥Ý»„�d%³÷(]Lrê’4Çaû¦'l&ìÅWJ!#W™¼fóÓ"ÆxþÒ#{H‰KìDýiò®ZŽ(U²ˆ)ÜI ²:,4ÎAŸ“\¥ëKrù cÓ*Á°wðñ+TVK09´3„Ös`¾‹0سõÃg½*0PÿBã«ed«… t–æHþ.y|škÍ÷9RìwýÏÔÀ.íÊrü¼3Ñ&¸ŠA¸ŠŸT+ÞÏsÛ)ÕÇ%"Žn\»#FMÏìÈݸÞ�ÄÑçÞWªŽT”€Ü�P=¹@·´"£~„±×çZÞõÍý/Û0Õì¾?9²¡ó õ*0±\ÑèùÆÂ«/¼P‰QÏ=!I¤‘*Iæ úþAb„Žx�ÒYàù>�œ'Þð'¿j½³'èé…je4{<õˆmoU²3#"Gz¯wÇŒ¤•c¯;ÌÃË´��îKtñ{3I ·¶‡åSì<š`>(QÁ5�Y&ˆ� Š(Þy2Å«h ’m»k´ /=–nâ±ÜZ(Æ+<FŒÛì.¶Ã®��Ø�QÇ?mɲÜñWÃ:©:z.噂vbßz‡ïí¨�¨Öˆ¨ýišž(_tEÍ=:ßê£E¦zÁ Ls“³N¥êW`è².h?Â㇬ž”W!MäË.-š[VÆÅúf(BSñ_ÎÏø[YEÙL GȼéWÆyçØv[êgà$Écž·ë‰*¡Ã’'¶@–øÁœ·úcûÁ~‚ÌÄÜKo€hÍ×íÍw(!\¦ù���Õÿ¡�¡s(£60jÎ~jÜ÷Éø¿&ÔÈýññè>d7¡(Ê})L1� Ò€l#|e0ñbÀ¢(ÔÆuÏöºah׿>PÒNÖ^sú®ù~£[ø×>±×SÙæk�Q6Â;R!v!XÇÌbŽQF+á4ƒ&ÐÉ­2`=á {Ôm*ÒãÒ-Ä&PV7Z~ ;|‘µèZ áz®ÝÌÏä�ùÃëmÁ`zb¸–JÆHÎK©…s¯ždêÛR½¸ƒŠK57%'‹s£ìƒ?pÉ ôê7-é¨oï,h¤&Æ b8ž‘Ÿ¿ùŽq½í>ðIÿd4ÛŸ¨ y¨=:Ç3“dÁ±…!¡‘ô�ê0¯¥âã%–âþ ‰¢<E ˆ¦¬½ûO’:‹*ÔÓm=ÑyþñcKfêÀE}ÉiÁŒ³‡8ÿõ‡ö49«\)›\i°’㜺úTîqå½çÊä­{ŽER äÌlø3~LíÓé™– „â�= ø.ƒÊz½(]Ö�öDãáeî«#©É17r¢YéRz^ך8||Ø1œXʬ®¯ß$â˜Õ½æZ3ƒ´gi�< ™0$ N¤Û—÷ÚÉ*T^²9zÔµm]«Úœù¨ˆ‘ÒƒLß÷ý`dHß<ÆÄX ±åŠ&n|<2 º9æ&”7µ›hÛ�^Ù‘]{¹qNÓÞøøQ¥úV¤�¡±Ñ3Ô§ÂèbÍ;üÃÍŸ’âÂk@¹µßè¦ÛbÚç{Ègýî„;â ¨­“`0s†~}îÂ|¡ Y‘y¯º„ì�[9s¨¯ó[D‰zFÆÄ:?d\× ±oÑJZ[Ž›è‹6ROP¨ç;ižîÒ€ø¼�ÌrgŠ|‰J£“°¸àå«v¸¥ 9�¼UfVæ�š�Ofìuc �¹‚¸øÚËæw@c¢q/¼Žá|ä¤Ó´7H00Ô¯Ã. <´èâê3OåŒÕv*ÚV¶‘ÕZ(û[Γ‚_X‚le–«Õ4ì»fƒUܼúZ³]ý¬í]s7Äè߀B´t.MQ©hßG ƒ ZRhnúsQ1â8úã-`½jú·1Ö)’Ë ÷¥D¸ Ç<å¼ öîo8á¿î›$e�]8¹.�®醯áò}¿Ü¯ãA+Š#wû5’àÆløyM˜Ïæ¼+÷CÉI“eϵnó§ÕçCÚ’o°¡ª%פ?}�­=uiÉ´³‘{b`õÎÏ;žS!#"œ×ÿ„ï!n:ŸèÅ} D±ÜŒEÁ€r0ÂVpÈz¶¨§cBÿùà0Œß¼âÌ®{g÷‹»¬ž<"„Å>šç“¶‚E¿©ÿN7ûŠÑZþ¡Ö;,=úÒ\¦"cú$Gpxõ*{ÉEm"f97fZ±“ÿ÷ �PqÓ*�™„};�©ÅgÁ|õ,�† å�£ÔO+NH“ˆBP›mÌKÒñ)Ç&|i%?Ü.nxNQ 3B.Ü"±„^кêsäZÙò{è3‘mï3<°^ézlb² Y TµX ¦?g€�…™½]Z0ÊØoVéeô™ä›Op· £î‡«Ëºrná¤óݹ¼ôÛ«ïš©°æ£7æÂ–ƒˆt‚Í˱�p)%nèÒmë`ns¦oð%Ê–„.éýðýEa ¿#DY”oo˜¿£uæ»’cÂÆ�2žÚdËsZa3v~"?âýrÒ¥Z ;9iŸ¹Ì~­Üáë�4-uŠÛ EÌ�aaÔ-ñ�õ*nk¾súEÖE#•µÐ¿ÇLwO2Æ/èDã.V��sŸs'è…5ü–ˆ3qÐqлɖ„Y†±€µÉ&œåUIÇD1‘n§�â`åêäz…Ô(yºÞö曨%¿bëEþ„EЦš3[ViBõçÝþ,ÏÍŽ"ÍSh{\=CæD†u ðkëyøû�±iˆ†dŽ… Q?é®8R9Ft¦eïË­X]ÜýðL›ðg ç�Ÿ�*w©øG™64A \mU`a·dï>¸D\]ElS�#Éõ@ÔÊaÏQ|ª*©à¼n#(ÍŒÄhgóƘÁƒí†¾¼K/GØÈp ]bÏz—�„2�Œ5K¬°8”H¢t5ÒÏrƒ ¿¢œÕ‰|z¨"¢óÐ2zC¬%UyÓ±“×lâ€.Uúi°}Ê¡èú·c»NF@Râ )ΙjÑÆ§„ü1/8(4g¤Ì‘ÆïnÚ�Ée›ÁpsY®vîŠÑÏåf �[ÒÒ;Cé�›Znؾ)|ÞÙ Þâ3“±gŠJX§ôô�¦�c? �÷̃‡•ØNMÔ e¬ôU#ØTÓ0w bÜL˜¥–�Û¬9ökS“Ÿ&DJç ÞvŽœÁÞnr:!«¾ý<±Â‡ &-Ъžœð"4ðH«íx‚ElùàJ™@? ~žÉŽ?”¬ý±žE|4�X|jfŒãsfÖ´xK›hróy®jÉæ Aõâf®m}m3ÕŒ»ß–bÛc7Œè è0ì6õÂß®.1aDö�,¹ºGE[—`T¢´¼ dÒ°‡Åt�ímdÊ\çEöýzH„´w£ÜÞ=>É Ýé”ÏAë]ú Í;C%xÏ¿å�͹5_mæjD¦ ç6Ĉ 2­�ñKÿ^NØ.Tw¬ƒÀÄ_:* $n xê# Ûêσ?=µ/»s0O¦ÆÕÐìMŒi)œ¤ÜEÜ5¹�!%WÛ›*“.¦ëpXXd1„F?òïY5ÞC}w©&ŒRvóÃwìÍL¶v¥~®ýf!1pÈ\Ÿh8:´Áð»nö[–SÛ@3­Nvå"Mvxhky;ˆ¤ÖUÏ~�Ò?ʰ|Òýuê­¶u}†“)d_rR¹€�™iðáv°r„=eó"*½óAšŽÝ¬‹òµD®èF! øæsø·E;;<«&ür2x£ÇrÉl·¶ÍRòŒÍmEOȃçE†ªÂ)÷²bÈ“ü·Ö[ÒMAØ)bë�@¼…F‡«}‚Ò"a÷vCy²&/’0�Á±î9®¥¾»ò‘†Éu‚L7ÉH bÒ�oÍ .4€Š9¹–¼¦ u½dø ΨÆ2ê7M½/Å-]G7×+e–^6p·<+¶ûºÙ¬Ô³b00c…léTUÙ÷ñùuFZBN‘Áw=­Ã÷%DÝSô$†‰’¥ý¡�õñAíÆþ­‡¨¼g-cÜ:ál׊ö]¿éÞx¦›lå~þÍ‚ÕOèo&‹Ee0Ñäyk¤ò"8Oª}¯ò"LæGà+¼Ü «>pûcÊ¿ÿÌEI£W&BÕÔ¶œ�¨ä“ùU:3?å±W'L$âË D¯®«?ý;ðQ$ØÏ¢C�N}ýhÌÚU `º«‹Žpñ †»5ô2$}#• Š¿Þ›Qç6]·agÑo$ Ÿ?Ë"@/Yµ’(eŒá˜>.Ýw±Éìò½ÅPx�òëÐ+Þ!Ú`Ë 'ÐÐ Ò¦íö€�mæYŠ  c›€Ìµ&bÅ| G(ª¿S׶̘#‚Ýòa¼uµôâ´‘³VaDÈ%�ŸÓ6  EjqaÉ•h#¢/döôëÖ‚LbÙÂ|fý¦ò †r�  kå7šÕn0GŽ‹.ÞR/+$EF?7[­Åïø £ �ŸWJT¸Óè<´‹³Å‹$—á>LSÉÔ›ÚÜ@ZC”þ€ P®½gàZ>ÛÊøA0žV2%,mfå #!#l¨`k‘»f‹³ Ä,ï6Ù¸ÇiD=þÉé ÷»jÖâoé:�{�±ƒ<Fõ9"E[}4Lcr°ÂmdNû ¿“Û–¥”KWL>zz¸{!¼Tÿ�êÑ�z¸=¼‡¯Ý !aÈHú|çâtçÝ7‡,™T¹®úë¾#ˆpíb— ±ÃLêVKžmHÙ‹DÄt²ùááu^¨Y?+1µÝà¤àq#óö§ëQ Ñ=?#'ƒ Ûuª]V”µà€}ªþYHµ´ÄåPy`@+–ÆŸ<o?F{Åv97ówJ1j¨ö'-ŒFȵúâøx0e¬“|TÙ5#ÕÀZŽ‚-�‹coÖ´2Ë¡¤JVMδBi¬$æåè˜&}¶·G³ú3Êý{£å°Z¼ä P#Õè!»…:wp<3…-…˜Ïu^IÐ">n¤Ñ‰{p—ÛÎ×›0i]è L��ïq)_qV±¡šj·?üšç‚ÅþàQ¡©xäM¡©Qdm¼ì}øD1Wè¼²d‹JÆhl,§ùC[C”¹¦ù±bÞ,šyƒI‹`«iVRAÓùM$V[©•qâÄ #è¦iUÍ Ïíwí‚xJE Aå…qôÎêäÁÓ<Tß×Û¦G_Ëyzé®×Õt¹µ zCŠŸÁ^Ãô‡ýzMJYßV‡˜(èV×äÐÝ�pœ�X ,e¼ì{z7Óæ© /Sü"itÅâ^»$Üø¾"¹wêH%`Ⱥ`Ål�<i¬ùÑ�ø|ö’¼c’{”Ž›w—°„Ú¨ùÅ*u¯ºåü%ÓWXå¾l=°<ô1mÉQY [ÝŽoî³&6hÑá!›·¾¡‹`'o½L²¥«‡­S[wU.oXsŽ´Jêó Y…JVLºì†�›ù9½¥&.b=¥ÛÑÿsS¯½¦‚»¹ø"*qGz6¿c8(¨12T‚„ÄX9î!2ñN®à.9ý{‹cÙ‡+&ÔÜ<¸8© kÌwS´÷ÛìTŒè‹9íÇe޽ääráºÌN•!FL�<ÓÒ R=ÿŒ'²[Ô«”ªÏµ¶Zy_¼LNºM¯¦÷‡‚V^&\ÕVŸ# mzØuæÑäs¯¾wù,%y¸ÊýKc,4å¨òl<H&ënf…jÎ[ú’³˜(Yç #ÚÆyÕÜ@lÚ@uC:aèÒ0ŒëPöL)ámÔ‚\`ÈYl²ûv4 üqU�$YÏbÐ%êL¿fxoÖùn_ Gå0¬Ïñ‚•0N�,‰ª ÎL}ÔÞ½%uè¡Ýa—'ªCYoÝÍ«/�-361�ëDÀò‘Æ«Ôâ½/jÇ>h¹ê�˜9`«?P™~—þž¹˜²(£Ü�ž¹Õñýd7)ÞQY…Ë�’–Ø›Ä�2#©°2™ ïÏ.¾?Y!‘]ÁÓ‡ ÃXÌf)Ûã€`…“Nu�:½�ŠÞà{Ë& KÚílF„Rµð½TlÕm�JÒ&¢>Ž¿`É‹ŠÙŠÖ™ðAú6WF7·ÆÑŸŽõó_‹�Gô¥Ýøî쌦:ûI†¶l;!õy^ÔUi 4û1(-PýéPj~èr€Q®�ú?Ž^a|cx�T!ìg[M¨ögPè� –ß0VWîrW¤åqË ¢JM,Ìq?‚mY½?°œ”/T�[ǽ J—U2�A]Éðò S讨ö,<‰Üç и¿Ò®2K@Ñ­ ôë›=€6ÚU°1pFLgU˜kaYø˜Fl ;nçÝž W+òkÀ+ÓdÏAfu Tú0üüfÈ*0j£Ø¤4ô’HusV1ýŽêÊ>ˆp’Å»£Â0±GZ¼Êî ŒeÓ|2¾ì\1¡sLG±å(ÛB†Ò1ÆWEúÉyl …* +çßJ „‘Ï„Y½Åv̹ÀˆÓ3™ž¨¹ÛEtÛM‹b�eU*O6Ö91N»\ÌÐPÄöì�Ù+VØ1²ØÎï‚YìOƒ¬Ü1i¦ŒeKéHM?§4È`ǘ�Yúö /¦’SX^#go ½wzz©ªH†Ð„yp�7ÚÏÆWÚ¼žà$RŒ75æ?©¢¯„Á"3…ë¶ýn¥€X—�QBÞˆ-E íy¾Yh`¤=ÇH D>BؼKL_�qÏhÃKñùƒvu-¹f-59ezÅÊîfô _©ùÕ² ½&vÑ‹ì£uëPC£à¼Öƒ#‹)'ŒNòzöl½Œ¬™ŸùSTE’™YgÇrqµbƒgwÎÝ…Rˆv�ú³ ‘mj�g©Q +Ἆ) mŸm”iÆæû ª/¦¶2½õ¬% aÁ}Ü$‡PËýa1fÛa[™<¢zA]?GVlCnY£á$O�#g`>#7£5ƒ!øC�×hs¬«�ׂæ5Sn…°?fß)PºmTƒMÄF‰4VåÊ[ÿ� @ö¿)ù sc•!{¼†Xx˜ÒBêeÕCw=Tæ¡;I+p²ÚÐ I±´Ã šê ÚôYØX5“p`vÖ/L@ï0Wm"怒öªz€‘B.™;Wx•šµu)TTŒ{G}êc~ ï8ž”Ë%ûù)ô�É“¨þ,KY]™ïkçèô‰Ì´èq8Ó6}÷–¤i þÒÇ�°SªSË)Ä%\‰?wIÄF¯nÑü»À¬�¾§íuŒzöÅc£X®.ˆS×®•Á˜‹‡¨#9>IÒ1pŽï$wWeÅ6Ïö[_e̼Åô.§$23M}™ìLž�òÃ$SþÓ®©ð"ùÉô6Ëb >èɦóYw±7ÜH᥎|—QdNSã.´r¦�·`ØJ”w\×ÀÚEi‹xÉÕ !ÒÛ²‚ZfÑA).L3�Daˆ¬—Pc±:­ä)Q kÜm+®Á»ž«.Ê®˜é˜‰&gZ—b�.Ò~3=§˜…^Di ´ZÿÊ„‚¦Óß"0ð¬t¨r¯o++S}„ÿÄwc¬ c¡W÷lv¬¤Ü»¡Ï¤ÚÉëV/eÃÛ‰Ò �AÉÌ=KnÒò7�+@Ÿ!!R�B¿'€ûF‰m:Ç!CßBã¬=”Èæ�lZŠ®óZƒt0:f ‰@cƒ,ÕÙ÷9ë½0-ò«]ƒî;~Òô¢‘„<Ýñ“*&¶™£Ï îH�? UÏç¨�I'¸OÌSÉÉÔávµ ¹ƒAÈf�êíŒfïß`2Uµ¨*jߨÀ]î¤Fx(FÃ#÷'ÕF³Õ8¢®�ŽÁ¬ ¶“A;·£š 0ùÙS3ȱÞ@×'Ÿ7?sË|&TN«\ÀR�fU mȯà<ˆþAÅÈØ¹�ÎQ«�r É@û[ øØÈææŠ�ò›þÊÿ1’ðñ#Ë— ‚ä}Á€×ÚVb˜¼}ϹƅBvÿt±uÖœQY úÏ ÊËŸ[š&ÜB²R âà·T;-<pйÏ1†`Uszfrcûõˆ™OÝuµ†çÍgE4 <hH*üÎp9Âö BÐ÷ «ŠÌ:¢ÿâÜ åb·í+d̦ ¦vcZV;va2Æ¡~ÌÁPMx;î>¢¦+ê,,œì UÚT [¦]š¡a,ÜÔD¡vˆæ£ºþ¥²<ƈÂ3åM¶(ºU¾f¸‚‹C߸ÓÀJ–l„ IkѨ²Xë㇛]½óý�µùRapïêíÕ|¶ñÕŠ-íÛ 3ñyùœÀË;rC³\:ö@«ôµW´Í”ûlÿ´ÿpWN¬¹¯M#M#[_÷âK#ø¿+F‘%iÄ{¨/Ä&ÙƒEþ�æÀUAÀÛB>åÄT^yöv4ç Á‚ûñ„eyÛBÊO~¼&MÞr:E¼I„Ø[ôýQŒ-È¥3YÞ,ؾО––o§ Ž/óûÁpÝN¼Ý ünhÅ ÷?À˜ëŠºTž?oj9}‡!¾öjà,áQÉ2·Ú9ÀƒØñkæ^'â‡vs†„ŽQ²åç^ÃÊÞ[Ó‹Ï.dÎJÀz£–o–”Uıè>Z ÑÇlŽ��š:ŒÎ€eƒ¼‹T<a@Û2üϰ zöƒáÈÞk²ôÏÁÿ*³¾Ö"Z�•š�¹6¦üIJX>Œ=è˜ðŸâ~nû…y.xèœàL\6 Ð(ž �.ìy«®¬?ç?¼='Aìš¾²½áö…¢Ž…Š«. Äâ†ßõ4Œ”3òS]C¹ÝxÛ™.{ï¨{ž)�¨ow¼<öt¨8–æ)<ú��'ÄÝ ìVÓò·8º¸²+‚£SØ÷B‡W|û±BŠÝŠš\Û}èc£”€]8~ì­oÒ^fì‚=Ó1ÛY¸‹�")#FX:Š¿5Õ¡zÿä*`]rø�€3üŸ*Ó™»HjB‡vÀ’�iЂ‘ÞAýH{–O0snùü»ßjÄ ½gMwÙVP¸ŸýrËdÉÅvÈ* ?Y|ry•X#ò¸Sð»åf±óA;ði#c~è´ÑÐ>*}îeSºG›Ä=vkd›Ú/•Æ®ƒ¾{•Ȇ±Ó”‚D}z�Ô¿(šÞòWÝ{æ×[é\q*Ê?Ň’4­aø†6œ¿ðÚ+B¡øªô>SLJizpÆQ²<à T9ä¯)v<Ф¾gÏÊ*X’6T Nnüµ°/CGûJ)<Ž5OÊuiíÌtHÈ]г MÖÅ{ÿÃ6bOºÒ˜a©±¾ÂÁÝ/!& l—³Q t¹]Úˬ ¼æÖ�ê|›­Ê4?AäxÖ“pŽ^ cßím«ôgal ¥ãÇš‹À­†`òÁÔâ´äûn îBÂÑ‚î ,}òÅŠ'BðßÁ<üYa3${ØBܶS³"ã©äXSEõ*A¤Sæ$ÆÊíøŽªÚ˜E÷ÔÈ}‹,´4ÄV/ꋃºÈ募O¸ê>Ár-#è’�©û ©$M‘ZÊåH´£ìøÈ%•;zÚa”að%yñ˜ðj?+]„4®÷(Ýôëî.ðß&<岯 (~D–Í�q>Hd¼Âu�‰•i¬jù|%×ÓTôÞôËß+ÔàQG­ÞvLäæeòw¸í[°mö‘ÂQÚ:Âõuô©yÿñ][]§@aþŰ€ÅÝ �n áÆi(þ%Áš� .€3( �Ò-1ZGäm¢.’ÀþÌ+X²�…P3m¡KžÁg?«»zR-z"à…í�V‡|_f§\v‘·*ÔB½fÓ69 ;¥ˆ{´Ïk覊Ù1v+p',m4ߺœÚ`¥Óü¢M ö‹íf)Œ§o0×þƒ^<õŽM,î€^�$;Ó î2éorÎ$gãî š‡K¢3€ÖÒÚ@„‡®^Ï>Ã0‘®A'´ ²÷zÃU¹°-å²™àËÓ{‘IÓ®bþ”(Ô…\£Àú‡šÇm†‹¯R9�¸ù²Tz(ïÐ{œ\eÞ¯>õÞéW¡§3†ÁýXsV~ޏgÕó*[ÍE‘¢ÿʈz„ÝP}™üÅ©NH>Ÿ*ñx4Ìš\2ºtuÓÎRXþ›:¹\à-¤šœb5¹  %øè×¼÷ŽÓ"ø°ÁОze}që—6gË3n˜E©Dq²’IM ¡{àyPB¥Ü=º–l‘¿ƒ¯F2Æ‘_œ~GŽICšV£ÏõnŽ8Yéê[·Á;è"“”zDÒÂÄïdo›aAqÚ¸ø¥Ë­Š³$ÈÚg‹ö¢—“Š<˜nч"ž-È.‘)Òòød‡Ð­¸ÎɺÁO3¿—‡±ûŒB‡,B$^#üg^h� —Ù@·«”Ì4¤èã$¾DÄqù]Í땹^>”~à”`ã=°f¸�脺¨ ¡üZ®"HøH;4ðœk…ºú¸4cL —ñ®Ét8Lúòäf„û³óY©cœÀ˜�@GÛã/”t;w&ÓÊå¼ib).ºgUãXðíJû¸¹1‡¡!~šž2œµšQ˜`^y EˆZdã=…àœˆ­ë­µÞcQm¨j(ž“òÛ,W™ 3w––}Qp·ùÒTÃmL¼YºÛŸ2eÂ-µù05tòó,”bmö¶+{…ó‘è€S•Ç�(RA9¶—Àt^1Î&ØóNŒgð�°¶.ˆ`Gcη7M±Ó½ä,²j"•é�g46}?�¶É¸x�~¶_§CP±¤tN’ýÕKÝŒ„H뱄¾KÏ]mXž¹n½»7{»À™2Nn�‘ñµÿüäiô–ÁÞåУý¤—HòUc%ӥРr�‹†¢yìœä0(?Ü=˜¬X¡ØRÙéß5ª©nN9Û« _$Lî¤xqSíš’ÁA€í�Ú-I×Í84¢�K6NÚ[rÞýÌÜ^X»µ!Õ9öQ|赚¥ÊƒÑR�Žõ´3ó@ã ȇˆTßÃÑ2³V˜œa”'(+ã?ÞLþòuö.r�«7»/(îíÿCP�Ô�=o_[ºÊ]dÉOS3>o m“¤åAØ …ùKÐR#9T€Pf7]°-^‚óùTMš¤ß™¿Ãî_*âvÚ;ûu™°.Z�0ô3•E ­M¹Æ§4üßÞ}Ú§)’Á˜¬´~>ø»§�ùËv�<Ø—ÇüF3Ðä¤]AÅîòZ*m\ùò‘É6ÏL1ä]]⮾„éät¶˜T7aÕ"x�4劌‚7��‡ÜÉð3èÄb„ÅÛÕ.dú¤7Î�ªéU“/͵à…ÁÎtÕØ˜l ¥8ÈW'ÆOVDgdнÍÂVÍÝõ9@B^C´!Ðyót)×ÕÖ:ìVØc-®Õ&~°dÿ˺²Iz¹P\vî¼ß14Ù(ª¹»ýöƒ—ƒD8°`=¾u2’YÇi“ª0Ñ«2·ï¦�jX#á=ƒÌ„šq½¦ ¸A¦†q³%²“çyE•ë9@\­„6’餋Ù犅ÂÒÌ TÈ«{_›¬è¦d´™ÐŒõõðPm˜×û�§ž� çá bfÕtÙß2-Mà­÷aó!SKH7Å6 I¹Ì†ÒÿäÄœ-4,§T×K& �2Zèê_§Úîÿ΋ ðçCDL?°°?‚ù‘MÛÎèíº!7ï;oš\o0LdÇd N´yîî fˆ )M¼8È_™Ò2Š[‹È»¤ì§�«ï •34°´¬À­¿L1o†!¼ Pg{GD4ÐL2ô�>öèØOlêÓéŠ1ÃOÑ€³?dTiüGk2%£SL­Xèœ7P€�-ö£¶hc¼h§B=F:¨ÁbÆ“°ó¤CehÒ8|à‘ÐcPwôáíQç–D7 WCé±^Þ»x¡@`¢TQt¬Í}ЄœKúÄàYÜ!®ì;j‡Á« ˆÖÕ¾îrKo…Ðd0üRÂ.À`ì�4|ŽöJK5ˆOù©e¼ikm¿Ü{ý,à¶�;B�•UÃ, ”Yl€ ôj|i¶¼° òÀ¡Çhüò:�Žÿó…Ùxln8´O3Ó_ÛßÉîQ ÷Uýý²ŽäÉÊ‹ð®�‚þvéè "è^Ú>OØ Åï:îÆ7]â=]íSÆ\Ëí5ç¹�À× Ðþùp`�,;vÜy[TZbUí'‰½Ó�,+#„1ŸŠ&¨6òåÙ;Š-¶ VÆTv^¡4Hš½aQBå1jzF¯Ë©r×D { Êb”M+‘T¢©O|?A†•ÑÝ—p­ÓZL±¦JE*É ÜÓGÂ�&á6‰t¬4âU¸n�šbf¼jµ–tYOïu»ãã‰ÝQ6Ù¹€p';\2ik�¥m¼ªµ(C¹³?Ïí7dÑü`TäÊÞ&è – éNf÷9ºÑ÷e¨Û{>€ø±ÁºX4ö¢xÔpxÖt-V¨HH`§îÕŒ°Il�ö­8 ûä QÇJúf'vâŽc¸9¸Yd‡pUEÉ@ÓôYØÖGaá/®,úâm²Ë:€W�%¥ Ú(ÂÜ5O|rëkxÙb6Eõ1OdŠ¯Ð¬—‘ùa(ÛLÇ£Ì4øR¦¦–�Ê›Ö<Û͞Ю…s«¥Š1c;äàZ$3½iŽûò¦[Aï¶Þ¢ ò˜ —7*Î�¿ìMÆÚÏ‚?ÅÑkÑ'§0ÊÈ:Ò_Àm�"†0ë@ÀÚ§M]N(Ì£J”¡¯«ÑŸ„ÂÒÛÍ[ð\7îË–T|:µðC|çn ˆÀ+Ü—uFgC"6sw•›ÁW0.ϹµñùrRÜÝ  qó w¯�ÏBd½;ê¹b­*ö~‘ì+‘‚D ü›7*ÃÛèZßÏ/ÒC,�„ã'ñ^ù' +[Žx¯ñçña§QÊn;¬|*Ïõ©Ž¹SÈý(3 édW¤VZ½B+Ç TÖ2»ÄMÎ=g»"uت³�å€èœÝ1NXééÆ˜ÅVkÆ©¢N/ź\1Hî°„»ÅYÒ¦B0¬mƒAcTÁzšþˆM “ãD|’n KìÎò…âÆÉH¯!ЍEƒ_¥â‘à‰<_£"�!‚RßTe×3Ãìxb³»t•ݸ“�öÉ VÛ=éÍx¯.ê”)•A6˜OwÉïNjܨ(ÞÛâ?/<&™$ �dç/È®�ƒ[ãY;Õ÷ÄÃËoqy`KïØé 1²÷&=`NS {MC~ï€1´ùËKFÐ*°^!¯“¤\»P^î½AkæA á�´,7ª{© ´¨vLjRN*WéݾV ŒVUßùÅ“+ }Çn¹þpj1ts>­º3§‡|ïv_å6F�™¾t‹Œ‡-¸9ˆ¢V\{R#z7Rs5?@€sTì¡UI€á;7þ&¸WPäs*û€¿E$7syèvˆsÒéÀ…»°ƒ��0òo}<­äâöîªäÄg¬–HmÌúI¬ê3G³%ʼBì óã£tƒ5|¹;þáÐ#)*¡!á{Åï®››•ô Sø·¶ê±n¤¶±ÁSXz Ñ<� KÞ\~_úçhœÉ*2xd¬…d¦�†š`†2Ù.Ù„Ä*W¥‰Šà—GÓwì ìÕ:"”Í Ê¾:§€™ÂÏ�JBb`?{°ÂšÈuùÌv™÷ZqSõ&�\`Ó»Àùì€�ÝkfÃXÀ±ú°bKƒó,XÙr×�-R¢§Y~Z}-ÖÕhGëõýÜdŽŸúµ*–S4^ë‡;7ÝðapûÊË|ªCÛ“f.šd‚ô;êdškj÷Ôk‡E}`�aù½:á�®ãæã I3P„CÆê±meçÀûUÓ*ƒO°¦ªvÙjŠÛ_ ~ËÍŠº;îu0)cnø�KrÞë9w¥ŠxW¨úO�x°(ÊÃî<~}aÿ Ö€ÏRÔÞìEã“ÉÇÁ”è´†.{ñ•�T b1s%„½±OÖR¾ä¦#J7~0·Àçî{5m?îÈþÄ">˜¯O#à ÚU«×|0ûR¥#¦¤8kr”‡w+‘¾”‹z›öô žqfP¼RÞ÷ÿ!i6îËÔ-‚B!nÄÞ|Ó)×»z»�€¸¸yG)Öák­m3 {뼞ªqr¨a�^8©—h¾â¹¿@ÀnKWopþU�•úEU'»©Påj2öÔ:°„–vûB ÕÝ{ÒêÙU{µ«£XfÿYqªÃs&UšÄ©ÍfÊ{v(ä/‡‡cŸ‚M‚Ý’t ðwŽë*MQ�õþ–Û»bܶ¹YØÄCÖ4œíûÏ”‹­º6@L‡윰ÍÞù·î)ôDئPÍÔU�Yýÿc“Í…mg~ȧÑxƒþsy¢gBü÷…È”�.�î‹ ÒðQ„í̵<žnÉ0¿Ùæþjó{¿Y•ï0éÑÊÖa?:ðÆ•'ëÒJ9™‹ˆí�Î .½K³TxuºO “q[tØ�þYÕ£­'Gê2þ´aöŽHØKlÿâ¸"Ù$æ{ñyzF†²‚_þî·Û¸]~DdˆsÖWOÉJŽˆ³Ðn+øgª E�Žô‚A§ËÃ7{yßUæ#š,ç©ç‡ >ìÆÃìõÏ+œ©'ü&­ÁÎÅÕ…„Å�œ«Â£‰î¢pß¹áï}oð�U…lÁïâMhw´U¢}ªáC*Ñsv’R8°>ˆåÑðªÿæ¢MY6ª Î¶ßþpo8gŽ6qx 6ôfÄú€‡£ô�ÞãšeÒ»L§€m¬™™ƒ÷zË'\_ñz1$ŒÇXÄB�,<—`NÓ­?©â¸£1ö:òVO:ÌÕÍüM;ʼnæÇ¼~ü=É—úž÷[<6É™oõF%ÐSc>£å€¨Vßç „g/0¦"†l¬w�x>Ö {B•wCç£k÷Ô£å>SÙ$é¹V‚hü0)¥õ[Çr 6ò¢)Iío©üÜ;'£wŽûz6ä%ž` P­•šÁ}V`�mûÖ¹ZuMÕÛÈÆöÇÛÇjòšººÿ/U%ôFœÙWšF™=>ÊÕ?eÈ}PÕÏ3I•nƒ9æÛ€ ÙÁ÷ZG ®‡�s.¤ˆ]1)§M„\Ñ�«ìö%>þâìÁ£+TEíwû/˜�gFûë%»¾ÑcêDåÍ£ÇÑTLô ¿Dj>_S£¬qÖÀWé!%Ç-óthsN£`|FÄ¿ðrëÜ{‘ »«¨ðTÇgÒ|U!ÚØÒ`5º=ÓmQùÐΚæÿk™oó¾î;^ðD3¢êV'^¨70Ÿí<ðöûû×ùWø^G‹ÏâfF‰½VG¨�Ú‘žpå5ÙÑÖG±Ïs$R:£Èô1Ý*´tÏ%¤Ê��VÙ÷íu�‘.qúC§Žè|%‘+E|ÄqL¥U :ùó¹dÔ,ÈþƒÄO­[KofÌ£•=CPí,!ù#FXüqàxÔìÇz\<—3ÆÔB/¡Í‰ö�‘3­vqßRÙ¶-Dñ¡àœ£@w0ïT¥Rí miÊB·žRúW0äx6ž/Èå™#Øý©öYX! þ×Ö%yrçRœ�Ä/Â�-Ö´‚îÇØŠƒ‘h`¤T-D³ªÐòB¨",ØG±ò‹6V»Â~„´{äÂ­ÎÆ0ݺä¢ÅµÔ^ýˆÌ%(,Á}W§;•ì§~›ÈW*GjY €[4Q&MÒÍSƒ¦’ÿHÁBú d)mœ±îªéßʸò»âÅÕ4€_‚Á‘>…¹V§g�…˜s` )Í:ºqâ|xè©®Dž“[‡»¸ÎL×~ ê}˜¬•AÄ==�â|k¸eòlХߎ‡É/fؼ½©;hmø¾Ë'D?Rü.hï«P¦„ˆ/ZúçJ-+ C1.¼jœ™ad/S•�Í¡V)ÅpëQ€³\V&Á¯Ã@¹Ÿí@c—íÿîÞ2÷«ì$—ÂØãáš ×Vc¯\7Èó^…غߦMjød]‘Ú±§ÉVµ(àÖÙ,‰¼U�îk³ug# à×X1f?´w}F˜¡—3¡ÓÈNÁÉÇþÐ<Àkï Š�ôEЦ~Ñ—È$�¡yÒÑA4œdíBÿ31»T£µœ“0c Ü)d£Q*ÀÑe˜šKt%ÃÂç±5¡ˆBâë´öLöcÈãv*¾™¸�ëÆíï´”ËdB6¿7;=K7]ÚV>)Ó7Jý2ð´ü€Q0$ ¶VöV¾²7ÞÍ�µªÇCñ1V'Pµ@ÌKz¦EEË…8rU BÊ�õ ú%мw‰�Æï „ _¯ÒQHw/Yµ!šß<_Ü¡‹Ú‘ö/¬/.)ïÒZxXÃ]Ÿ›‡}ئ7cÎ €9Ê´Ç?'¦hD/] lV�[R¡\EQˆ÷3½ÞðÒ� Ç�>¯¹­ý‚õÏ…ø<¾öË—¡çݤ¼ú.’a£%Ÿ,ònf K1ä®�Bu=u*�Ý�Íë:>ˆˆ$w8¦÷Š.Ô,¡›þgôˆØ“Ç2ò¬.íDå´ãÎ^a?ËŽx–^œÓÅ8&G½�Ã�[­¶ß~žž87Ü1hHv@"¸\6A«=r|UIˆƒp/^k)y8S- �Èœo{$ÞCî> ]µ�l }i3N�¢çYãJ§»«Þ�ú×|01µ¹b²:Æ�õ=×ÂÃ?„{¶íæ�´¯ÑÂ8áÈ_Wú§‰¾>$ê.¿ßle�Gq’…lEÄ-³À]§_ƒÔ(+#”Ä�£ ²FC mpíža�[×Y~œ†I2F;¿Ã8)§tKöÞŒù9cœ 4:_Êø ZfÙY¾9:�Âêï?ògëã›ë\"¨ ^ž¶8ýâ<7ØYJfë*l…|ZùûyGa“S/d­ZîU_4»÷^ÒG3?öðµÐÌ G’Ò¦Iæ-ù±ÂÖ�œÙ:E‡ Û~<—,æ]ZU�çnM¼˜}’ÌI*·‘ð«e2ÇñEù0fÂg¡[MíuoösS40bê (Ð�,÷iÈ0-�C¿Š&þÔ�é(¿°@÷ò q‚` ØF�æ–UÀ\ýj÷t‹ïƒNMüæøŽšÄ¦r½cÇQ]�2 °z0àS‚:/߆ª0¸Á÷áUˆó¬ÁõX”äÏi‹Bè<7ø(Ô×ÄðZëô�¶÷=vŒÄŽÐÊY›Ñûäm¦‡P R(Þ–ì øÞV=²ó`¢ù GQ³’Dv.Kfþ×Ôq=þA 0ºí?×…¸Vþ¦±µ«…õV”¸‹O×1Τ5E9‹ž®uŒ5.‡õ2±tûu¡®\¥Õù3LÄpM1có+Ìÿ°õË©¢‘:'o4ƒ«�l«Éä=áö.ìú³Þ@˜ƒdŸ¡º5`Æ]Úð„ZZéc7­–½dmŒúäùÔ·¸7nbùJøiÊøÂ,¬+Ý{ÙµÉLÄqëÊ+©�ú×ò~°Ÿ¾†ûãÏ«ôkZÍYß´6�KN-ÊžùW¦~ɆCŠÍ~ ¡ æj½2Ɉi)�ºE!ßé ŠwÔ� ŽCiVÃȺ?s´r_uw·½$ç‹n3L¸;@VÁ™ÕE `r~§…žþjIn|w: `– i�K{™å%JƒÛ�øÂ›€�Ï0½Eë}÷È1ý:Ò5^ïÜÝ{»b�T£Uv:Cîúà}Æ�VÀå RY†ÕJé¾l³yÍ„sJQ O›Eºj¦z{Z—·¿x"lj58PE—9ó·3vÄZh°i:ªl=˜B¥2ceÍÇ»ðO2P0%¨MÏ^ænÁ‡ì¡ÌäR˜�c!&np�]h\Evg Âu¯w/ÝF±#ø#C®[e®EŸ¹Å$d�P³V„‰RJØ4ÔUD &K¿¹�ñƒTtÍÙ3³Ïÿ‡ØË²°I°RŸÀ˜«jÕÑí­ÿ!‡uÛÍ踯 = dù?ói’Œ@¸b­DïšB'óñ8?�*æêUͰ¢NP¯ðòÐËv¦üYX�8€ÐjÇåç—ùÑý™Mþ„bû¥�ÁÉ•µÓ÷Ÿ.PºÜ†&wJÛL£è)å, LKϙ݅¸µíêÒP¹yº5y¾°QEržù׆ŸÄ³Ø±) ÕŸ¢ŠCT)n×±äÏó®”zYüÛµ754Ÿ…fЂç�ú�˜?l¿âD±©ÀƒÐÞÒBÌàìÃÅ7°z4§ñ¥)é¾»êBâö‚�‹pˆžF<Åìµ»ê�[èr ”F�r ùjÖ# ÇC¡¿75&ÏU Úóê|=z4 õÔ)Üý³NŒäKCM/æc<~QÐ8øåeZS`¸[�8 ��BWjœ”¦`hÎfKÌ^žÄ�µ£zñ¡a› Ø D³ÄèLouä ÜJPŠA-ŸÑÄUJ`‰+¹�«±a‰äŒñÓÉEȵÊKlnç@3Ö¸� â,òk©H¨Â`’ [Ô fáÌÐ"A’oâ®Íe‰ÛÃ¥§ytEšxxFzé_<ªF;¬3ö:W‹b¡(¡ÅzO²ÂÊN‰ö´{‡+úx¥`®«…󃤫rQ9X ÈÇ äÐú}M§ç¶e¬|Ô¾”›7Ý‹8s¨J*|a<´M,„i‹SÌ_éÖz37œ™ kS‰¹�Ú$LN ·vþa'—ŠºfR»ÛÆ´ÈÄ�ë�ß¹Ø2©pX†¼·éz>ž˜°GêÎÃ{ÈxQrù¨?ž/žb1âl˜loJÍwf¦ã« þâihkYÚiCOG̾˭«�p’Ån‹Ì#6ÀQ�! Z/~jú,�Ķ…�B`Ww¤“õÞzåM>×k̰@ëµEdp¹VÊå´™®XkÏ*€Z¹Þw6õûD�¸»××ñ°H0¾C‚w A©ž^ z‰d$/‘¿®_ô9ïSL]9€ð!›iâfPÙ(/ƉŠ�\±ˆîŸ(ƺbfç@ÅqO�6‡ßTízÒVXï�¯ì©X:ÉÞÿ‰÷Ê´PµÏNªPñ¤Æm Ø�}×Õ(íÊ¢ŒÛ¾QÅ,aŸ­ïó÷�ŸIûX^µPÚ9 Îú�â„êäÉÙ¢6²À»3n$P½wzç­“’>°#½B$£¡nþd3*Ÿ]|¯Ý‚rB64ÑŠ(‹å²A¨¤=i>õ`D�ºz¥¸™ÜvW¢øc<,AÌ©õc™˜É°µÆ×²wù�Oi ¸÷¿gK²³p“7”›çþ0ÑP÷}6% ´ ,�k_‘Ûûçcà`ÝÚ½ö¥wÂÖˆ«ÿxØc4ÀìÀmm¶iÅHó(VP…ªLú ^8gÆý¼mú“»y]ÿJ5tîròÿØýÅ ³q‹±i$Ï}�2áuŒÄ‡÷zŒœ�Zó— csÏ­Z^XÔ¦’¤;ºÖT¼at�˜|ûº“Dd¼x§þæ/Œ5c‡A#zÛw5 #‡É®st”íyõ�ÈtsvmLf5}|xáÌűݪfǹ.\$ˆ †Õ7×�•:œ ³)°"ñÎuuÄg³xpËfb(ä˜È:k”N Ð/IXhL5Gf1-zó9Ôø§Yí ü‘Vs m¬p«CUOlz®˜äÄÈg{â‡Qކ9ÄSN«8;u”|YöÆ­/*�·øú@ÏŒg�¸ÄJ!3‘ÍvÚø-¶#cÕ ãE²õÛÐÊ–i:ÑÖeò—ï–%åX­ê9 Âdm?%�#(18¼xñÑÜtÅòêWm&ª)‰‚Ú¿Sqá{èUe{¡ZF冰Lz`߉mØÜw¶Í½¢"[«�Tµ>¤°{! ŠÀ/úMZ[•º.à$îr€Â�oS½5I\›µdžHíË>'îôï‹�/c{æNUt?ÂÄ%Ýë8&!ݼޓrŸMcÃÚÔܼY(®h@:ÇÒëýÞ|¿ß�'s韉ZáT-ùºåšêxëáªCüÞŸò)ež�¾¯«qoÿz’B£i´Ø.Çc©yn–u:¨¹Ôc1–º¢Wn_²ÿ¯ý¶  ä;² hö¯äûï‹mD,„TÀÖ[é:SÜþö$†;âŠöì³VKýç2J<�€ÉqͱÑíûŠ8[7‰çÏ·AP•¶Ú$iþíS¿ÅT¢ï�oáÿðÞ¾f‚@þf¼.§8ç·/úÙc}A”ÌK]ï2Ž�eµ|3Ûh‡ü("" ÔiŽŒÜ&†œIï4q´ØQà§ç%V»ÿ̫Ė`¼âžËñ.Äã£QB»²œlmX²ÆDÚ°&*þÙ⼓,cœšÜ|¿³Ý*8—Fv¤dÔÊP5üE môWK�õH=rË·»ÎMF¢}8{@³ j¼rÇ�'ë6›®©™ò @QJ#³üþ†9’ﻈ(�fíÓ eÙ',lðÑ} »>Í«Èû0®1ˆ‚áóØA©­�e„wtŒþ6|¸MAàSH®¼²¡¡—ÏHèn[À¾€eLËhµÔðÅ~Á½;¦6LpýDO60%'„õþ@ <`G/eÅIŠÖg¹^%N½°¿dmF™Á=¼.´HŽÔà‹w,¿®yQ¨8+q/³;ü4�±Pþ)¯ABt¼Â„]Úª®hh€ÁA€ÃD˜h][ã`·b±-ˆüVó�ϳë^Ý�Ld Ô¹ÏHÜä¶P€÷Ö Ë)P‰°° õ›¶Œ§®ìâk^r{ÞÂ_·óÁ¶ÖFÇQ"†nœyS•tÂÄž_¤`¢™ ˆFhÁnWA†îDôü3ž¢ðˆóí1¤ÔS ½ÙÏXÇ�£ÔGQw½n#]R5hqT–m‹B‡�¡(‘Ú‘«‡v|§Q@à9Í‹ä³D9Ñ\�:y�ùúÅVÀ[§-,„Kª .÷2úÓ�ÒäaȱÓèU€ºÐÂP�OU$Üó8úê|aæñ®”‰*/P:!³ðn•ˆ˜I0C‘xÌÊY3ƒº¤J!•ë¨^m(Â7‚ñÆQ¨è´×€· ËNªÞ&Ö=ãÁ Á‹“#îL†æöX"%´qUi ž�”¯ø™Mct¸øiRé{'üªNuQ&ÃÂŽyV)§õ†ÚôxgÆe/nnÆwеÐMŽI``¸rú+Á"íöl 7nëKÍ…Ñi…JõSžÖÿ®#Qéþ:Ej,¡.}ѧò*5HL¾ ¤¨2¯{›jýM»€–gúsùirøÏH—»»v °aq€‡[y!ˆ·nþnkòslL�tV6„¥¨49Á”4œÍû¨Z—ÄZ¡Ù‰FK¢àR+‹rúÄ¥fÚ.“eòÅÁ:šRà|‰>”ÓíK½^³ñhã^ë�à>Ñ«=€9pv²Ùùòøº#Ñ5ÔŸq=Kå‹g}<k ]Ì|’üòÊ%1JÇÔ®´ôÎñÀ,‹3zâôVÕ¡“òý?F<¤«;òÃ&–0Á¼YɪÀ(§!…¿îÀ vxb{² +9­U¢÷� >%HWbb)мû'þ*!ùr ò‘ÂÉèW�Ã×çœ1ç+JŒaõ]�•Séa"¬È¼ø!ùCçÞ ¿Žô~�нÜÙ 7+äa ãp´Ö;x�Ý´È�ˆ#ºþÿ/ê€#]ì³ò^ÆéAxÌ݇¾Œ“We‰Õ*¡J!O´èG;B› @s¥cħÙsÿ6><| uiÔg%‘/¨­˜d¸«ÜŠÉ{1óókÝ¡ ( a#ýØÁâ½K^ÒœF%jëºx(lßG•¸Á•ß+CÂH#ˆÄÃÉ‘À%7.νÑÜw&~wã+  ƒ)w"¨Ww:'Ð5cÐþc c'ñ_G&5$E‹ü „ßà# Æ$íq;5=ψ�¿Ð?gç;Ár»½{š�e˜Lɹvã_r� vD�,Ûg ÃKx­Žyq®[¨Ç+Tâÿ½`~E°F˜Ž?8³=é¤jÉqÐã.o¥fh¦@í„w–ëKx¹¯•ˆßè ¢7¡�ŽUIŒ-÷þ12-�} “!CŠÄÈëçÍÿiSÑŠÑÂW3ÔQžâ"_Í"Z±ü×îÌ:æîÐDÆ#~�ˆzÜ”—Žª:¬ËFfOÑ(Õ�HÏIÓ>¿Êǽ0Ä­md42÷š­Tª¶)`…˜ˆ ÑUv�,hœSZF`�`]8¦M€»�ôŒQ¦õõÝÒŸýÕ V,¦reoãp¹l`}Ä—Ysù,5ƒ‚¹L*‹c6¨! huW\â ?ó¥Á'N«ã'ÏÏèÎò?ŽLV±‘™X¢ßšR­W øðã…tQ4n8¬enÏ¡a˜“fÍÓ8A‚cPÿ•â îAYÊÁ†5<0ˆONШ6cÒ õ…>]šY8  ˜×⎠�4Ô Äê8°ƒªBÙ Uðm,çô0˜ÞÙÉf•þP1•Úß —ôa‰½Yüi;:Ãàˆ¥A_2 Ù®F›ˆÓ•ÂÐX€¿›mZ6i“RØ… pê²?A€O­_Ýì2Ö×ÅœLƒà�fl°ڀëúbI>AE˜,S•Ì��å0€¢©ñ)¼ÑŽ€²Âs'ßøZÅ×Dµ°az×肹ëÉygͽ®®Ÿ!ó dÙrˆ�*¹Z<¶Ý¥¹ û!Á™Õ‹<ïk•þZ$›YúPc÷Z2l@�ÄÞg¡Æ;µD‰6Ù9ˆ!@ÿpnu.ã©Þ\v¡xòÇï4B’œÅJ”ä±O3‹Eô:ìú¢�ñß‘å‰5Þöjd›ÜŤ9͘•?gÁä8K�›Žø)Ét§vª(�RÅ�» L–¾H%‘IÈöwUë¢ñ —Ê× 3oÆ«`Š\ÓJŸïôßÛMß.n|{5†;;“a�òl‡:hH�íï4ÙºÜka%aƒ3! ‹íJ9@w¯ÌÍ‚ÏÂ3Æ—i9QbÐ99óQlâ¸ÑòvÏO™’j‡+sê¿öɳ÷•›èšCÓðÖÙ¬¤ûIÞfð§ÃI° Ýv„6÷Ž›ÁÒ"Ô?¹(ùnED¼ì{º´�Ð\iŠ¡Ûè¶¢}/‡‡aÆŠ«²j!sÇ.N‰4Û£bdckp9¾×HfJüft;A“ €»?>`ÂqWì nZ€ B5Ïí\óÜôì|l5ø†$Í9)Ü2Ëß\øî †ý 6èÝd™¯9J?õ÷ê$i^ÊÖé(êè:UnPÄ‘;l-L9�2’Âã  =¾Êíî£&â¤=¿Èa�þ™OËeÐD”¬ §°a\6�R}‡Ó N¢’"›báöut¼4ž—¼ñV˜û¥îPúËI�Ð\w'"ñDV—­Æ6Ô½ÃõOaW©Y*sµb³"ùÃjVP¸Ç}$dŽ„Q³©3$Œ�§Î×QÅëa-ïEŸØøÃ†±f¡#Jß9‚ÿ<¸}T4†|e ?·g‰êÕÔxkN.¯ rqÊ©˜îK£ôûa±Â2K?JëЯv*1hÒóS.…·»:é�³�ý¾^wìAÜ‘‹Ñ"Ÿ[ØT”¦¼‘X¯™Æ˜Ë�Ç#„dUyÈ�ˆŽnõ9^sAµ#lk,Qáµä·û\¦iŠRb7^†ùž/†h‘à36€Æ´ãX‹î}“²áýû­6CÉcÇi{«�(±0"¾¬¬Çõ�^žÈÉ„�‹fÉŠ`µ¾í�×–fÉ"4Õõ/!öŸFÏÔ°D1#fÙO;-À^yö”üF5Þþk‹)Å«ëéfçÞëÛÃæÃWÍ;s– Ô—a™œ¼§¥%ãõó+P�†#·çÜ@$yáÕåÑÿðݤ=Qs:j„�UÝë— `BÀ8v³Ý­Ä U;(Uõ0%1�¡ÅÉ€ÍA«½Àè2D7Òæ4Rx ZA"#¯­â'¯ðHA îkBÓîy¥e“ãñYV 41- ûÀ½ë¡TI®G‘ý -¦s·<qýå‡'狼yÅgWj“µA�ãÐ9�+ðþñx©¬ZÇ ‰ƒf‰«ªW2kßêÜÂõŠHJç ™{\¾Bb�\qéŸý…HÂOδS¸ËÃÌ%¬aÝ—[!•Ïøf�ÆD˜”-"ò¬9€3=sø¸(ÙÜZy %“ ÿ"´�ðNÎn$›DI}FO�i§Ý´'o˜p�GÃfÐã±;¢ú‹›«~M­UDÓùºte5ö&(p²ó_Ì+�œì®í®aY˜‚°]%v$³îZ0½Õy�Þˆð%Ü>çBRÊ2²TpÑÓeâS0j'gè2 oðû\³4-èþ•sX£^¸M·Rƒ¸[D̬yÓó�s\ß8­gËÅF¿ÜÒ”o_†uÐ=S�ÿòÁ}cù F²fIºÖ6w§¬êô¸¹¡‰ZéiÅøX­L£M×z)>øY9–KÁö&{ŸN ÜOª"sï¬Ý¹Û® žáуJÅ0áì+À×`Úp«/øÖPÎ<äß"Ï@Îu·Ö�7Ç›¶¯¹ùê¯b[ñ ™‹’dÛ¦-åF1×—Mh¤ó¼/°8ü¹–�í�5HWbÔPõÎðc#ÿc&MÂöÆuÁŠŸþM)ƒ¦£6 ®LÅ©C\iH)·Hqå+³©Ö§YcUçT1M�5…è¾>À; ”vh/5i1 b¶{³KE×ÓÞ<\c{«‘Ã>šzWcQ<} ¨Íþ– ¶¡Ýdãpª½&¦à9PigØÒùŸ=ëÜ­-EŸ¸‚Nºðì=ì§JS:¬|Š!€X:p¾öàÇ¨Š¯Çñ—ë¿Àœ^s‘uôÚ�^èbu}Ѹ1–Ì«6ªBªÛv˜-í!2IÑ:F…z�Å?µâ¤){@)º§‰Æ‹<ãbb|ôš…E§bÏx>DZ[Cð7UeÅs`Ì£¬b[z© Ç`s6ô½únª£fºr/y9·RÙ,&%Á3â¹=£pÅhd¢ßyÙA÷Õ%¢è—þ<¯±w¼©_œ¨ý:�n¢nÌ6ñÇ‹Ðþ2²bxý¾\÷-Kð¯xîMYÐíȵ¸f¿GÅÿVøâX}Ô|ÞÄE—døÖ°ÓáXÈ/pã �©ôƒè’'»i&Ѩš-í6‘W)Î�íH9+{òá}!”6ËÚÖ®âÍ™AäU’ª±M~ÉVåC±âÃä½ÍôüZ<Fâ_}±·ss,í·“y�Gœ†¨è¼äZÑpBIÿκÜEG‘ú ˆ%nˆÔ}¡Z#)'ðj{ñÉ(ÑL̂ʓ·{°(¦Ìg'3øÞ2˜­ð7Wå]¨IbÚ¯ Ìäö›œx½Ù�Œ«¹šÍøÕÏ~|d]¯”<P+\Û–ù×­éßkm-“›Ì‘vþOª�ÉtÈØ‘šèOŠ 9Ûßð¾a�©+EÙ£~Mv‡r]~;ùAén¨Äôê ˆ…WE;ŸYX©Óí�~Í]�lXCåõÑ�É×”)ú|¯¥øãáa$ µœI?­å ÚIäÔ˜ù‡òyŠW°PþäT¡çØ&W2 ”Êo ¥Nßän‰G8í>í¾ŒuuÐõ�°á—f®OG<Žû×"ŠŽ[¢ú\?¦Ã5éÆã/¼UÉ¡é æ�ë?$¶ =§–Æ]?¶ézĉQõHöh:#™+®•Unò¾®!Â+–VçcM¯ù¹O|¹ é—L)›[¸ôÙÑ*&iÖ)æ{Cä Cš°ØC�ÁŠÖðy$�oYqåë¦ìGQ0ÁL2\jÕ$#ðʘ°"©m1£ŽäèœÑ˜9ó�©A†• êbw"`p­eƒ!Ÿh=p�œà²Õar™;ò©95O»î3EÞ<ÊŸµOrQÝÃSo ‰–§ «ï¶s§ÄHŒã�É}f�6ìOgŒ'±JýDøL¹>%}DkGÌ}½ÜÍfù´Mù?Sf„ÈDœ.á /¥"K§‰ø=ŽýbP,%.Vº;+.Äã8§Zoz!®Úñ‹'Ýí]ñœ=ÊÓK�îDÔ£R�ñé(Î'� }\|^~±å¹ûZ9u€t*pè\ƒÔÅ'=<ì™Þû,»à�Ùî…Þç*{x{¯ I(ÞÊ#!QŸÈfZ �-=•qÐóxàšs͡ѡG,‡?° gk<úBè^w/LÄ<(ÛI ¸ú.K‹zç?Cé`;µ Ë;eˆ:o¿ÑñR9˜Ý¢ë¦+£Þñg¡‹<³!Ï }(È‚ç7gFÉÏŸwšï‘�ôÿ4ES¨S�Ÿ]ˆoc–È‹< [–·„/{íêlK?¶ö8©€ç¬3ÅP½bqíDûRµÓ �ØI£â�e¾_æEj£—ÇÐß�-çû-ôCÀPd“Äd²DV­§"œãaÏ12³bSâ¥W¼E‹8ŸÎB#EwoU=íœçÜ–]`gE.#åfb ›<Ggݨ3fá˜ìîF9ÔíÚPú–�>ĆŷKêôRGAXoæk¦.5ªÖ|Q­l›³ÃVó.èµý£øúþ1Ý¿Ad¼‡ú •ÇlÝΩÿ²#›;¼Ja¨� ÊE—&Ç:èÀÏ@Ø´u ˜¤G0Üä§–e©ÌÍÖkÙä¶÷]ì±²’;fŽ£ü&±t#Ëä6B š T·I÷ûñÒAi®ušš)žç`¼¯•Å–‰\œ¯]¸*ÃÍhúVYÑOB\W“³8•õ<š„àÃ<ÝÅFEš£§œDL7ÂF§¶‘Cs½$äbBu‹Q±ß¿nJ¹1·AÝ>¡Â· EÄ„ï8è&:î^b0øuüü8ÓÔÖ¸¾óÀJÆ€O8ü0ÀMŸtºâ£yuMg}&‰ 8#éôǾ+Xžù+ X¶¹IýѽõüHBÑÈ€Íküxˆ x!èY¸ðJ­u ¹Ð�Þ�Ëš!ÿ‚sFmp>L8¹8À%n±W ö¬D¿�»¬±×êÒ“Àã,@—˜XUÓLâQbͪ4·ö->)®OY©úŸƒ�³1°™gm�á?éè4ÔŽôd‡¬Èÿ­]‚\[óÙAÀ{šâã §º©+b†d0Õ(àm_Â~®ŸEgib³„¼K†%¬ºÍý´9ÒAº¯Š‰ÓgÊ@iæÉðà[RS1h¨©¼ŸTJYH�©›¶§ånxž4ª¢­O]Åä’ßšîá,m´ûp†¡I_DŸ¡c=¸µˆõMËŸ¥8Qð/&#N5H’ß¿QsT6²ªUéŒWYV<ç;çSb]ÖUEâOL,gÀ(È‹‰8³¦ ¯~)Œ…ÆÆ(ƒÄÏHmÕ¶êpâ&)eøãÕ5 j²Hìû©‘Þ¹dV%â$â–sÁßëôciDËçm�î@R2Vlî˾>Ü Ë™"´£ïšGaùÆžeÞZÐBmI´iPÔc7aŸ†¯Î¥¡7b�?Vi �A�ÛRbÄ$ñŽ£úcQrÓÿ6Ñšµi­äÑ䥑¼qÎ ‘Θ;�æ0u€‰%½x‚Ñö¤Û½À&`[0ô¯1¹> p ¦r[Yyë‰ãK?•¤ŸßXjšñ1‹7½–É8ߑ泦ÝB²ï£�õ¥ß–ÁíÕÌz˜‹ÌLwAL5ªjÈf±°ø5"æˆêmÌC:ì!Í)ô> æÿ�ù6!­F§®îJ'ò©–¶q@ÁØËM�òù¦°Ï˜oÙ$�÷Y¤$) £v4ø#%Ïeqñ"Õu»08Î[HÍë\Áâ¤ã¤O¬g»eÉ�ÊRe_œýÃ}´Ox—�ãf5Mÿ¡©„«~ÚñL¶úlu“./)Œ]ÿŠE«îk‚—Êã\îÿhðè¯)Voô uOLOýÉ”ÀBTVv·÷ÐJÔí$'ëHOÕ:…Ä3Qám¾ "ìm=ó7ýî+ñÃð.±ÊÄQáûå=S¢‡0‚°çýŠ8È“�°ü{w†Ë’幨Õq‘º}·.ÌØž,o;F̾4eN&TéÏëÕ–í!iƒ¼fv;€ _‰pN‰6©î@"d‚Éreòœø­íè ³…7‘->_+‚�hnŠZz¹€22WJB 0Á†‹_=l­5»)6‘jµ&3]Ò+ €€À«Ãm÷É ³§soÕßEHŒbÐò-°Rœ9}¸Ø2‰lÑL±tÚð~ës²�s´R~RYy"<ˆP^­nïRp[ûƒd:Á3zåÿÅôbT¾ˆm¨ {=ì’eša]÷ÅÊ%ãÊì$þEDeØ>hÎ^ýio^®Q«Õ�’üžXLkÈ‚ˆv”|ùn×ué»N€v|ìs%ôˆÐt"ijU¤â®Ê=Ü`3®:<þ ¸‘Ñ™Jh¡÷Žn<1Z=8A¼dt!gbA#_Jp€áݰåôõ–¾ìÝÙ8ŽE«¿¦b[�¡AÃÚæø·DW Ø€Y7MϪ¡úYŠ:.û1°¬dRn §‚��àmª¦|YF IöLôK|׎ÄV_JenÛÙJØ­IÔ�/Y‘Pgð œ&+&GªÜ�âŸÁ�° ><ÜWãÃþîŒ0>¬»ØÅ›l?°2Dk¼ÂlŠÖáºÃ1­:÷� åíÕë? Àq1&÷Û4!¶c{fDÂ�Yó)G†\æ–…ãr\G†IÊÌš[Èí!9¹åRDX£æ¶6Däú¸„¢FÎùλóy~À÷í/Q¾Ì×ï�ºmm�"55Ú»¿®m­êèûUÔ&Ñä½7ºÈŠ&˜•Õéa$¿.‡ÂOwXv‚ÅU«A¢OüSž”!A\K�Rßö™èÏ@çLgG±(xi¹Ê½Ùm»’äÏ‹8“¦{!õm†Ý¶X•�ïØ_/¿%´NY ¹{³“БüS²B55ã¶M½К¸Üæ»g´M·øá±O2Û ¡ Uhà¦Ë€ùæNÞÅÝ ú…?Èi©Ç{Dw•^4ì7ŒM¶"à ±¯ßqòR�: ‘~+£"¦¸Z“6Š‘ ¸´ó|"ãð0€&²º¢óœÒ™Þ;ÖL úÉëà鳋‘îg ®À�ê§Á®ÒZ1 ñ?y7úʋƅpøªuÐO1Q~ÐŽc¥ïçZU_LÈnw}“w�N BYVèqCgÂW6Gf£‡ÀÅ¢ÚHYмõÔ‰¾£9;¢2Côžgøq¡.`%›ž{±H…9,ÇÅÑï‚[‡Ï¹fÄTÞÕM@e¶§„ˆS–t@äÖÚ²<T•/è~]ñerö�rÖ.…]=û“±ä9p/ëkÏž�lNC©Ó¢ °%”ð²¥G®>hët9ø÷ZM’i«©?'VË/7�Õ¨÷;Ó²_¡LÇ^ÛR»|”ò¸P[åEá»�¨P*3(’'ˆ¨w²ãý';î8mq§®•�"aU|D­ÄÝ3U~Ñ뙂²JËÄlîåœ^W#�§„ˆØìöôL¨°½,ñ'|©¤ø¾Õ^n5±ï_,škœ_¥¸'A—ÎP@Ÿ³[û™�®Y½OÞÏVŽÁç>áÄÏc¯šš¼3£;sÎ ù¬ƒç°j‹ŒúCÖ«L½ ÕÌ‚‹�º'É|Ì3]h>wƒb[R™e/RßTý|T´]³A;†Ð�î*Ø×>-æ¶·s�¿ª½-Q9±@Wý"OXáöûBfÄHÞ'‡3qÑíŒìäƒEvŠGü¨c¾f§ž!ýXtŽÛìÿcÉ,s¯ ¢yEÄ:QJ}˜Z 4É�;¡QÐxÖ—¨&¾ð¼åµYÅnºBÇ,ÔW¢Íê >c~¸jÉŠŠö¤3h‘hÂ�o™.ER»�k$r\¹ê¦™nÓá ¾°`Ž";bX‘ýžç7 2Ãf˜Snuu¦» Ô‚ÑUˆ¤Óµ+jQð_‰ ï)Z1뎨‰ïy®GÎöÎôJ «Çj³–G~z=ÔÉe”ÔdÖž–Ë¡šI‰‘ŠŽ›æÈd›]ŵm!çÑ54Ã7^�Íq�ð¼y´+8v°]çþ8Kò]‚L�J'ËÏ^BÜ¢|Dăƒ³¯¾r.þÔÄ€Ç÷ æSîÂh�½f›5kýc¤”tÐøçîH2þ Ü+œ,2ž·wÍCž¾oÇduÁa³b…1¬*}éÈZ ·‹zT©MhF4ãã‚Q>kÚ«Q n £Òª´yÊËa†] ŽÙ¡{`ÞúQ¬ …³Æ…÷{­]ÖùÑ]Ñ­1Ö:ºa6ß�ÏÝ«kÚésHè{9]K…B ™£øiµ¤Nç[r;_«ûâ»^L%œºó�rò%óŒZg¢U>ß5Ño«¥m›ÃæìÿGPqQ·/ÈO†½LâC<Y2è\@3GýY©�1\ b9¸4KQ�•è…å�q5¿$fM{YÀ«µýØ|�ÿ#ö(ôòNìu€«Ja']¿µ>!!¸ºÄüˆ²MÙN�~äŸ:|'2´ˆ_ljVÿª JÞü¢ÀÞïsgg‰. �¹ÝÌa—ªÔg—oi¬�+^Ô¯ùm­öãêäí#$x�ñ÷!?ÛõFž/åE,IË%ØÏ¶°ac·Î/Åî$P*ÇâF™@5sWZN é")N¢��Ï:>%ƳÕ�î†0ßþ2SÁ­SÑ9ûG¼¾öUIäVy¨WÁà£ûàHeâëñeáCÞ@7dä{h2̆Œ<ÈžüØ{þ‚“I•Ój€™$7ÕN4ÉYÃ~h·N(;qxY�é©0KK—ÀØö�†4ê¼×· @Ìê|�ò´zJ+QÍbðÃ#x�Þ `¼É†Ü¼`c_ <ÏÒ¿}Ã\ƧÉCyбßÍÅtÔŸ×ñ›kÞè÷ˆ;ùLÞÊ̘³Éþ“þ?ð¯�ˆ7ý}"¢ÂB|"HBB¥JC¥ endstream endobj 3 0 obj <</Type/FontDescriptor/Ascent 729/CapHeight 729/Descent -218/FontBBox[-174 -285 1001 953]/FontName/NimbusSanL-Regu/ItalicAngle 0/StemV 80/FontFile 2 0 R/Flags 32>> endobj 1 0 obj <</Type/Font/Subtype/Type1/BaseFont/NimbusSanL-Regu/Encoding/WinAnsiEncoding/FirstChar 32/LastChar 116/Widths[278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 556 556 556 556 556 556 556 556 556 556 0 0 0 0 0 0 0 667 0 722 0 667 611 0 0 278 0 0 0 0 722 0 0 0 0 667 611 722 0 0 667 0 0 0 0 0 0 0 0 556 0 500 556 556 278 556 556 222 0 0 222 0 556 556 0 0 333 500 278]/FontDescriptor 3 0 R>> endobj 4 0 obj <</Producer(pdfTeX-1.40.17; modified using iText® 5.5.9 ©2000-2015 iText Group NV \(AGPL-version\))/Creator(TeX)/CreationDate(D:20170131183532-05'00')/ModDate(D:20170201191245Z)/Trapped/False/PTEX.Fullbanner(This is pdfTeX, Version 3.14159265-2.6-1.40.17 \(TeX Live 2016\) kpathsea version 6.2.2)>> endobj 5 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 6 0 obj <</Length 152/Filter/FlateDecode>>stream xœeŽ» Â@DûûSj£yl–*l„�Ò†x“¬Ä½¸›ÿÇE,gÊaæ jz4ň‚c ’ úAÛÖ(ì Z]›êrn±÷^zÓ-FìZß©ÒTÿv“2Ú¤Å?Ζ Ÿ‘£Ø�Ûž!'33:{C³ˆëF†æ~²2ËhØ#(O¿PÑ›ãF '•‚ÊË�uLCHkz�Ä4: endstream endobj 7 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 8 0 obj <</Length 153/Filter/FlateDecode>>stream xœmޱ Â@DûýŠ)µÑ\¼SªD°BNHâ^roñ’ÿÇC,Üéf˜y‹ŠžQC I”Bž"Í`´nœÚ €±´ˆf<•Í®uy978Š·Øw ñ8¹‘ÑúêYBÛ3 wƒ—QzÇÓÒÜ©4Týrt–¯ŠüëØO“t®��ø¯�äÝ=Å�´†ÞîâT`²1­èi•4¦ endstream endobj 9 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 10 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.åÊšy´0èˆx{«¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC I´Bž"Í`´m]�ÆÒj·G”Ê–צºœ[Å[ì{†xœÜÄèü Í"¡†ûÑË$ƒãymîTªgt–oŠüêÓ_γô®[œø/>yÃa xRkèøK!0Ù˜ÖôÕ4U endstream endobj 11 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 12 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.µš¦- ºâ^ÅÞê†í£ÕÿOKt(š93ß ¦gðAS!‹§ÐÚ¶V¡€6´º6ÕåÜ¢œgém·Xqk}§JSýÛ�sµÙeÿý(]F|FŽâ {v=CNvbtî†fß Íýèd’ÁòŒ ´øB©7ÇN& ’} žÉ„´¦�%47 endstream endobj 13 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 14 0 obj <</Length 151/Filter/FlateDecode>>stream xœe޽ Â@„û}Š)µÑÜ™ßR%‚�rBÚ7ÉI¼ÅKÞ±Pœ)‡™oPÑ3ø`H! VÈ4tó mc5 ˜žV׺¼œìçY:Û.VÜÚÜ©4TývumvÙ_%ˈÏÈQ\Ïž]LJ“�­»¡^Ä·Ãp7:™d°<#(U_¨èÍñ…“qŒ8ÍÔ3õ!­èŽ844 endstream endobj 15 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 16 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.¥²ºy¬0èˆx{®¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC)’è:C–Ã<hÛ:�f UQ *Í—צºœ[ÅØ÷ ñ8¹‰ÑùšEBg†ûÑË$Öñ¼6wª Õ¿3*×›RÿO}ú÷ó,½ë'þ‹OÞp°O*UìbS`bZÓ ©4O endstream endobj 17 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 18 0 obj <</Length 151/Filter/FlateDecode>>stream xœe޽ Â@„û}Š)µÑ$æ·T‰`#„œ�6ÄÍå$ÞâåÞ±Pœ)‡™oÐÐ3ø (F£H�dPÚv¦D5ÒêÚÖ—s‡ý²È`zoÄ®Õ�jEÍo7)£Í®øïÇ™Ÿð9ŠÙ±bq23£·7´^\¯ЇÉÊ,Úð‚ ¼øBEoŽÓN¦)Ò¼ PÇ4†´¡•Ü4F endstream endobj 19 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 20 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.¥¶j- ºâ^ÅÞê†í£ÕÿOKt(š9ßÌ ¦gðASŒ(8Fž I¡´mí´¡U– (N—צºœ[Åöìz†8œìÄèÜ Í"¾šûÑÉ$ƒåy­ïTiªgTšoŠüêÓ_γô¶[¬¸/>zÃ~ pR)¨lš<“ iM/Q4C endstream endobj 21 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 22 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.åʪy¬0èˆx{«¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC I´B‘"Í`´m�B ci•'ˆRÙ2âÚT—s‹£xË�}Ï�“›�¿¡Y$tÃp?z™dp<¯Í�*CõïŒÎŠMYüO}ú÷ó,½ë'þ‹OÞp(žÔ:ßŦÀdcZÓ %4= endstream endobj 23 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 24 0 obj <</Length 152/Filter/FlateDecode>>stream xœm޽ Â@„û}Š)µÑ»˜ßR%‚�rBÚ7ÉI¼ÅKÞ±Pp¦f¾AEÏàƒ! ¬‘Eˆ˜m« ˜žV׺¼œìçY:Û.VÜÚÜ©4Tý–£\mvÙŸ�,#>+Gq={vCNvb´î†zß ÃÝèd’ÁòŒ ´øb©7ÈnÆ1â4TÏÔ‡´¢àk4š endstream endobj 25 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 26 0 obj <</Length 152/Filter/FlateDecode>>stream xœeŽO ‚@ÄïïS̱.¥æúçXaÐ%7ð*ö\7l­~Z¢CÑÌq˜ù jz4ň‚cä ý mk3”Э®Mu9·ØÏ³ô¶[¬¸µ¾S¥©þí&E´ÙåÿýX-#>#Gq{v=CNvbtî†f߆æ~t2‰±<#(S_¨èÍñ†ÂÉ4EšꙆ�Öô“P4@ endstream endobj 27 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 28 0 obj <</Length 152/Filter/FlateDecode>>stream xœmŽ1 Â0„÷÷+nÔE›ØÚ:ªTpJ#t-õ¥�Ô<Lûÿ1ˆƒ‚wãq÷*zF )$Ñ ¹†Î`´nœÒØÁXZ\ëòrn°Ÿ&é\;;ñKs§ÒPõ[ÖE²ÚäT6ø¬Å[ì;†xœÜÈhý õ,¡í†»ÁË(½ã Q¹úb%oPè)ÞLS¤Û"R“�iE/á€4— endstream endobj 29 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 30 0 obj <</Length 151/Filter/FlateDecode>>stream xœeŽA ‚@„ïïW̱.¥²«y¬0èˆx{®¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC)’èE†LÃ<hÛ:�f U®•êeĵ©.çGñö=C<Nnbtþ†f‘ÐY†á~ô2‰u<¯Í�*CõïŒÒŦ,þ§>ýûy–Þu‹ÿÅ'o8XŠ'•‚Êw±)0 1­é}4I endstream endobj 31 0 obj <</Length 10/Filter/FlateDecode>>stream xœ+ä��î�| endstream endobj 32 0 obj <</Length 152/Filter/FlateDecode>>stream xœmŽA ‚@„ïïW̱.åÊÚæÑ K nàUì©¶�Vÿ?-Ñ¡ ™ã0ó *zF,)$Ñ &EšÁ>hÛ8¥�Ãö´2 ¢T¶Œ¸ÖååÜà(¾çÀ¾cˆÇÉMŒÖßP/Ú�a¹½L28ž×öN¥¥ê—£3³ÉÍÖP̳t®]œø¯�äÝÅ›ZCïöq*0õ1­èfe4  endstream endobj 33 0 obj <</Font<</F38 34 0 R/F39 35 0 R/F22 36 0 R/F40 37 0 R/F14 38 0 R>>/ProcSet[/PDF/Text]>> endobj 39 0 obj <</Type/Page/Contents[11 0 R 40 0 R 12 0 R]/Resources<</Font<</F38 34 0 R/F39 35 0 R/F22 36 0 R/F40 37 0 R/F14 38 0 R/Xi0 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 40 0 obj <</Length 4383/Filter/FlateDecode>>stream xÚ�:ÉvãF’w/݆Þ1È[שÊU^¦½=Kîy¯Õu�ˆÄ°Ðjùë'¶1U5™‘‘{ì‘Ñf¿‰6ß}}áûîþ«ÿúÖdeCc½¹Üäyh“ME¡ŠÍæ¾Ú<÷7¹ú›­Ž£àÛßï>p©øûs?qaZ ü�‹¿Þè(¨‡Çþ±èÊZ:?ò÷÷±nLlïN…kû¶i¥t÷<Nõq¼ùxÿß°Ì|£T˜Ç1-Óê0Wùf«L˜ÛŒ×ùîP Åt྿Qqp>²Êßêªzæâ?n”RAÑí{Ø ­õ& ó4R8²ŠUÇvGSÒÀÊ»‚05f³] Ý®Æ›V&¼¿É¢�–6ö¸¦?<s¦I¨u¼œR¿6¥öMYt> õŸ\úgQõŸ<Se*L’äjw›­‰T˜æéúHeç6ze‚v7õ�löÝpcá²an¾à®ù®XEÁØL€¢Ür}Ÿ…©N7‹qõkÓ›Õô?¼ûÉÝòXDP%õá_Z§oÛcQÕŽô*0\¦Øª$ �N6[mC¥x–·»qŠršo&óp?ÍC“ÇÐ/ -ÐŽ°�‰ƒ¡¨š©é»¢jHb¼0§Á¿¢H#•@…Ê¡’Oõ àæxjëcÝMuÅ€BPNÅ0ñ•áà$há OŠŒeTürÇßOxôõÐÕíÞlc8”ï{䯧ÿÿÀS‚ë±-ÌMýÊ§Çæÿн!ŒÇÎ/‹ØxaQ8I^JÌKÙ4Ǔ۶Î��8$�§ƒNÚ©rÔ,Nv´Šý ¬­s�¦Û3fµØFÛŸè¨�£é| :£°ÙêD#J8c5È/^œSQÏ#²Tb¤×vÉ”Dói·F¬ƒ@ûÇ©~mn\[Æb¿§¡ŸúéùTs•Xؤy ;‚¿¢=“4_Î qOй(õ¸RÖ癞W k4œÙØì;Ü}d‚e÷ÔrQ}Ó�hFþ–}76�fÅõé ÇÂÔU3o¢›Š=`[˜ ¿/Ïaîl±<Ÿ-Vvˆyž¸Bc�I{ZM¿à�%€N;Èb<í]K'�àC1r¡[q!îj¸@jä)NmÏÛ¯«˜šÒ±sèÛü[=Í‚‚?C=žÛéÖ­¨fèÔŸš’‹´Zø^‘Àf’ʸ��Šgïe<T‚´­ñæ¦Aôírlеs·~`M hc¬çtÕXS×KÒú‹T†DÓîMœ#mg=3¬C[ D±ðÝÕŒ%ì�¦ã/\Xu.Qt¢ì€“ëqS2vUo}óÏr�™Ñ�ç¶ÝÂjM]íé ½–q.,­—,mhtBÃ8¡á!·�ׂ`drÃÒ©8a7,>Õü-@<ÿ‰- „PfF‡Qqaý…w›¼z“§,‘s¡*ûqbÐ\" ýÔ1—K¯——Šè³ø…vž™‡âXÏâ²>¡‚E{¿¼|Pþ%ÚaåT m Í4ra)a|ã÷Â…s n‚Øk5™¹/khû¢BåfUüšZÒ¸cÎNƒbO2^} Ô¨rå„ )yÀIaì— Þ¹�¶‹įImDyª<0üP·¤�x ×É{£BŸŽJÃ�¬…1´ìúijë®.?� `«QAÄ $$h\sÑn}äú<²\OE4�¤ âàê `‘|p�xz‚ÛtȽ©æÚt(&.Uõ©†&ÔÈXí½ú@ÄžY]B´ìš€j*Và £T¸eq·>�”4?š`_}–I¬ ÊB¤ ”wÏüe7ÆX­‚F¢ÑÉò™˜y ÌXe}šš�_ê!Í‚1ͦXR‡fX@à Ü‘dæ/ܼP97?\©‡YŽÀ5Õ”yVŒè4Ô-Pߥ§oßüú;[Áç©i›? r� =b¡éÊ¡.Fq¯vb²õ—PŒÚ•‘= »ó¶*Š"�vô ¶œ ½¶‡±gÆV,göèTn/"+=ù…�((UN<�P8ÿ#.Ë ð.x�H¥Œ@"‚ÐO§ V ã{¨½(�;‘†Áþ¬Š©Ãçm;ú3Þ”ÖyplÊ¡ß.ŒeÆŸ1Wge¡IûéŽ`¤X“E¢C¡NÞðAa+°3Uòœ²NvCã,Œ±Ï¬S#±3±@>�•à=«€ìÛôQ‰„¥‚ÕÎð�àü@bZSÁÆ~D!6à:똑÷¢Žø°} õÉø×7¨œN² ‡˜t„‹�cp{*Æ‘—ÆÉ¡Q.àGîÍ7ã›s}[K/øÊjXUÔG¢¬<¤¸i°_nÇ^ºRñE«Ç ÷‡º$ Àò3¸—(ê òýUG*±új ñÂØÀòÒqò9rC�lj’œé(ë¼?�Ûb`w àÄ ØðH"AÈܰI¸Ç$A?-Žü)n¼[®´h¹/hµò“_'íˆõÂYÕÉ‚¡¡¨*�žêìJ”\ÜòxîJv{y¹z}ÏŒÄjÆ;9*Z$�8º˜&Xž§ç†8ªÃ}'§è×TçY$0QP¨ƒ²óÎ5²¦0˜2'fH@$~ăC† ¿/Ž´¤±Dˆ^”EU›‚¡,«üÛ_ß3d¬'�Ù*èö#¹ý1ˆÿ» È$BÝá%T\ù÷¹)|¥Ÿ� W²,8çÒ¸ÄzV1�Ù…s‰À¥s‰�†‚Li�ËWÅRЊ Y`#Y¦è¤ ŸŽõ’ä<âYb rßÖ.CÛvéÞcë%ø€˜?Ñæ9Að©ÈäÃ2švØJìè»|çÝÇKruüóÛ;†?Øø£À~¾Ÿ�:vbbK}-ïƒ?õƒ Š„WtMíwÔÈÈШ ;vÉ®$Wn_Šß¿¡‘žaÌëë;îôݯ´*@}0ÑG//]À~ÄP®l"ƒM�òAsêçæ¸c?(ÇhÞP�Ýîë¯o`o##óöîG×ͺnoOH)€Þ~ÿç²À ûXpc¿ëû=Ý @Ù2°À5w¡ \eòouõ}1ÉÔø]{½f-˜ ´1”ï:ÿ(¡Ñ÷ ò¥Ô£Çì†"Èû¹ƒM\‡z*?£Ø~"â² Z´KZ4WÑ3D ×¾È1o$¸�´¥œl`ógBio3Ë�]“ ¶Í Êæ°â×ܲX[1—a@ä¢M<÷¶àÈï¦áQ\ïF¾/Ä9@²˜c›ÿ±ÿff�ŒCüTræOŒáŪ^�ÇêV.Aé½ ùá­�.Až§¢}ì�×=Á/dKjiÖ`3Ÿý~äaÙFp9ãÁ-Þh«B½‰Ó$T.@þtè‰m¢9|€«P �z$lò„Q�ÝMÿ5W�ËÉíDtrÏ�vD1â¡t¤ØW]QH×?-ªYÐ6».–‚ƒJ¼D„ƒXwéx”à) ‚O}{ÌoÑ b89Ó,î¦e£€]‰×m-×vç²9¹'paЇ×ì¥Ã8qöÙ&·ùõÈ6¿XÆØ~á¸\,c„RˆÉÎÎ<&¨ ^c.b&ðªf„åq,R/4Ðgc“ôÔ�ç7ª<4{ù.(ÒÙUýy7y)»®Púƒeôey>I˜ ëV<‹€®a‹ÖNÂ�ú×C‘;å‘¿dxÇ>ò‘‰ÁÊæ¤肪ÞAeäÊ®žž(ü‰ —Sß±ÿ�u¦£Ü€“º‚7þ�Æ,�qø #´«T2°€ö¬úHl™÷Áš—‚4¹‰ó¡\ ý™xÄæÄ7Làý×ÛWÀèZ¢–-$(*O›%+Ë.ŽŠèÝîkvÉI>˜ClæE$/ßi¸„|t»ñ[ð@×®)ÝdWNwédŒ…Ejðy‚gŒG‘¹]Œ�3½±à›‰¿�Ù9 W‹Xˆ'Áëø+¾,”\ œüà…JI�~1@Ë>µËœÔb“—Ø>3l<ïþøvï¸e¥‰!"FaÆ�ºŠ–�bðûÃOCýHF™I“«Ë¶tçL⬯9•#ÃÎîS^¶­ô{S”ȉ�õxj†eR¿TÕ%?¨5ÈpŒõqÊV`�SX:�wm3ˆ‰�…z#�z˜a;[dß}²{ŽqÄÑ%kå+åu1þƒ³'` "qÊ;ˆa{¦@G~°.&Éë–ð¼¶<^©½VÓËåÞΩäK˜Ê¦a‡Å1*‰ ¿ˆdi|1#ÝJè‰C¿/#Ý¡ð-‡⊵‹MÓŠSj›¿pE&ê˜DþtàØKÁ€ª…ßr&8š3SE'¾bë~~áŒ\3§ûd4?{¬e Ò’ÄÙ¸p–’DP†ªl%C¡‘å#Š¡<4°ïyˆßç%Å…Ä‘äD-­æ7I—bW`¹éèx]&G± •hŽvE+©Ù“'ëxÕ¨¡Ô:òUÙ>¿áTì›ÅÖõÉ‚˜‚“)¥§´X¢€2v¨šÇ­ßÆŽt f„ÄQÕ™K‘ûc„¾8AŸ»ò0ôÎôãÎfîù|à ­{M×sçb©oØafuŸé¥k‹UF™YÀ?ïO8S†Ó$†c½jAÖ˜a¡­SnÛ�žñ+¥®¨a»ï7`��ãð#–œ€®×ï•æG s>×#Ó\bÉRöñêÑ��sÒçèåÐ:¹Œ�Îí—ÄF-¶b¼� û,r©>)æ°¥X89uaÁãÛΉ÷¤ñ¥fο¡ˆ}%ÿ–8o†3)XAÏœîG î8‘9`DÍÃ÷Ã&Ë%ŠsÌH/´['-æ>Þ´ùœ»³FòÁÚ’-Œ�ÉB‰wþ :Ö ‹L‰³ÉÈö¢�ËEà*Uxûj„‰¸U²d¢P"o•˜Räš�MNæ@éèWƘÓ8ŒîÞóÞËŒça™Â`¢çK¹èŽ…“gžÃJK‹*—;!�Œ·yïô’‡Ë3—MÌWÛ¥ÔÄüê°ØM,¡$é;ò÷©nÛ%$§ÛöøÅØÒ’*Ñ⺠@ÖL |”�æÈ-,^Ñ}¯¹Í°ÖVv¡µ•FÝ:µ�§ïÑí*‚å(‡4¶ÏPª¡e«m𳤄o%S's:óv«LFôðkÁE¨où¥Œ‹È÷Œ¥i'�3t l1.Ùj§ÓŒ]<Û1’7ö YlËO¥ø“ÇEÆ®ðÔ|¬'XÄH6Šbg ñÖÙnû¹X=åËÝË+ÎP)åÒs¬Z¡�D"\Bж²Ýq@ ŹF£Ö°0˜®íù޳Ç"(RíÞú¤Ús”)ÏO�:í�Ï\[çÔÓ×^Žá:oùäBe@c.ÆE=�ðt¸mB]wsµ@ý Mœí‡¦/æYèI†k¶ØäÞ—>º§¸/d‚^<’x%Ë›…Y’º'—œå½<ô}Ϥ?Ë›„Yj/‡DïA€ÚfÅ…{DÝ‚�dÌ#¹}Æe ¡ÀÙOÄ“—+žS�Ëή_�!lö²ã�Ü—\ðƒ‰?Ò«‘(x[–ýP¹ ¬‡­L”;7Ÿó´Xãzb Ìõ1„ANð¸4µ`7K8Z.,(ÿÓ�3nËÇ�8ä P¸ÿŠcÅgÍjN*`³HU# µãÖ“PÂ\„·­Ÿ±]‚•, Noj¯3~ˆp¯¸¨æ«Ç”ŸÙ±¶éâ–M/ù!®> %ÁV�–‚¥Ì6>¹ê–Ã~TJ†3ŠM_ÍÃ�ÓÙ½˲8�/ffוQ¹°{?g?.ž¤vñ“(—7~vùÆÏ’.R�´¬Þ#€�_ úÃýWÿÈNÕð endstream endobj 34 0 obj <</Type/Font/Subtype/Type1/BaseFont/DXHQIH+NimbusRomNo9L-Medi/FontDescriptor 42 0 R/FirstChar 2/LastChar 122/Widths 43 0 R/Encoding 44 0 R>> endobj 35 0 obj <</Type/Font/Subtype/Type1/BaseFont/NCLNVQ+NimbusRomNo9L-Regu/FontDescriptor 45 0 R/FirstChar 2/LastChar 151/Widths 46 0 R/Encoding 44 0 R>> endobj 36 0 obj <</Type/Font/Subtype/Type1/BaseFont/PXOHER+CMR8/FontDescriptor 47 0 R/FirstChar 49/LastChar 50/Widths 48 0 R>> endobj 37 0 obj <</Type/Font/Subtype/Type1/BaseFont/SUQKZJ+NimbusRomNo9L-ReguItal/FontDescriptor 49 0 R/FirstChar 2/LastChar 151/Widths 50 0 R/Encoding 44 0 R>> endobj 38 0 obj <</Type/Font/Subtype/Type1/BaseFont/DVCMRV+CMSY10/FontDescriptor 51 0 R/FirstChar 2/LastChar 2/Widths 52 0 R>> endobj 41 0 obj <</Type/Pages/Count 6/Parent 53 0 R/Kids[39 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R]>> endobj 59 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/fuse.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 60 0 R/BBox[0 0 390 151]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 61 0 R>>/Font<</R10 62 0 R/R8 63 0 R>>>>/Length 1096/Filter/FlateDecode>>stream xœ¥WKo9 ¾Ï¯ÐmÛ3Ñûql�v»@‘ÚíŠ=8ö$vkg;iÑ¿$¥ñHò¨]�ÅÉ�úDQÔã�`ÿÒïr×\}pìîІû»Fzí™T†…À™6œíûæöU£;Ã~4dË>ü9©5ƒéäDèà™�Q8Μ5ÉÉÔçAs‚V8«kè©Ï‹gX0Š&³›ž˜5hk Œ­gÛ¨À³Mm›uc!HÍmg¹U””°0ã¸ÍFƒF-Yï™Rz�2_è›t­ï„¸#ɘ�ôÆÑ q"�o£y’r_èûŸWì>ª\#" LÍškXñ]^:+�J×À饦k�¯ø,ø©¸+ØØKM6¦%�æ¼P˜âÞ À$:‹[¯¤ùpPš�bÎ룘yŒ ¬J”’(¸Ñƒn>Ô&D�\™NŒ“)#’‡] Ê IqCé­‚*œÃæü†5îÏ Ç_›}„~¹ùúŒT�Üæ8$Æý—‚‹|8ú¯EîóØ ��ê#‘$¦í'Ý|<rx"úŒþÂå1’¥B ê˜ u ¥· ªtŽ¥úrk:ª5Ç%_5›¶J…ß1*ÖL,R¦R�­ŽµC(Û‰Ϋ!BñÐYf 2"¤4ܦ¡DðAeB�Ê¡ y6c²­RÆøÀ·²*iâNV¸~ 8“¶ð³sΑÐÂB:(îп�nÓP+&•)Á{è:Ë<�tà��Ó‰Žñâ+q§üp䔚ˆóÍ�Ž#zµ/Ÿ™²ì_àeÕh¨„b�8SÞÇá–z{›‡FÄqúYîØ›9´lp£y6¿¥&¨Å>Hèû1hÒæ»æÅ_ýþ¾ß¾œiÞÎaéŸ`ìá¤[éÁþCê‰è£åÇs¥ñØYêí†öh�g­”ð6Oiîkh”Æ‚‚Rª‚¨˜ ÇBRIÞ�(wVtJ©R(®n•FøÂY‰SºN�Ò–C£”ñYðSqW°•¥KL׿’uعóŽ/>“:tJC:uãÇäë1ï\]¬slþwóâéå <8<çγÖuÞrèžç«¤ÚÊÎ@Q•p’:¡!œ¹Æ™ˆ¨�3@l%Çœé !�Òëoß¶›åâqóß=ª ¸ùM¼û8{Ën7Û¾=ü<<ö;¶Zô»¨ôÜÙ� H‡çã¡ß�� åêsñ<?)Ú�%ÑwÈNe{³8ô+�O'"Æ`Y ––‚}5M|z7©Hä·J€Y\êr±\÷'d @£Õ!¹_í7ßãª8­>qtâÙ‹N{¸&[èéIëéÈDù¶3ÁÄWò’=·êïÏ¿Ó*Ó‰ËòJX‡Å–¿Zõ߯nŸýqÙ+—+*‚ÕSsâó…Cqʪ¸õ”�ÛÍÍ~±ÿ9Œ3ñÒª‚™øü‹ÁTY¯õ÷&eøûÇu¿g_�—f~›ÒâðtÓðpŒóºù™‘J� endstream endobj 64 0 obj <</Font<</F39 35 0 R/F38 34 0 R/F40 37 0 R/F57 65 0 R>>/XObject<</Im1 59 0 R>>/ProcSet[/PDF/Text]>> endobj 54 0 obj <</Type/Page/Contents[21 0 R 66 0 R 22 0 R]/Resources<</Font<</F39 35 0 R/F38 34 0 R/F40 37 0 R/F57 65 0 R/Xi1 1 0 R>>/XObject<</Im1 59 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 66 0 obj <</Length 5400/Filter/FlateDecode>>stream xÚ­<ÛrÛF²ïþ VíÃ�ªL3`€=OŽm%>‘¯%¯7•ä"! kà míן¾Ì�rHQ²KUÂÜ0—¾w£‡ÑìvÍ~z™ç�WÏ~8�óYæ©LgW73-gZDaëÙÕröGpþáòõŸRêþ®¨?ugó8Ž‚uQÕ«{(Ë<ènëïJnèªõfUrã‹wo¸±ê¹aÓ6g" >W˲ÃYÏþºú?ØÈ\ˆ0O^qUõ=N D|9ƒMûÉ©W–Mm55?·õ²l»¾¨—U}ËMUoFWu_¶u±âZÑžÉ(˜ûV_ÜU}¹è·mù¶¬²€Ž³.ë¾è«¦¦FÀx°,Ø”íMÓ®‹zQrÃRÿžÍ•çxÔ¦õ­Òl[žgAy&ø¯Xmil7�ƒþáÈØXvì£ÂS`�šÇss{ÝôÜÑ –<«#Nÿç,I˜W ÜU·wó•Ù ì¹\q; ©º­¹|�Ûö\)V]Ã¥®Y—vp_T+3csÃO‚?ÖSh§¼´µ\o*‚ªðØJàƒ•/%?ÿŒ" ‡æ ltÑVצË9žçð×EW-pW‰`4b¨·æÎ/“€øºY©sÇ¢lû¡DÑ@µî‡*ÄKQ½Ek¬-�ð¨:¢�r;žB™É¡Z×ÌG:�ÃB  ‘Ô@ïo—e÷w 쌠ãÙAW®�„%žUÇÁEUo¿bà¶-¹ I _Ðð8tÞmÚ²Xr϶+a×qÏ2µÀR÷ÿ…™}çF‰ Ó8X4K*²€†;4´EÍ-Üe[!=tf¸éfZ}‰8ÇN x‚¶€dêŽ t´™š)¡ÁBÚ>!¯�” òGì#‡=w›)Òàš6[Õ5É�Ýe|dß6ÿŒ ü¬BŠ`›‚\±°�SËdXØ/¹d(AQ]·E{ÏÍ‹f½‰á9ùßâ,½×ÿ‹”@ã¶Õl°ÀûÄ3/´|–a*s2²<Íf¼hjä„ÎOj;*ò ·`uSô‹»²ãÊ—»jqgŠ%?—Õ ’õ�´ï3­,VÛ¥—ÚoÚf Ü�%)«"푲�o­óÞ8„ø¶X¡^Ã/R¬«a�-ÐdzÕ4ݯö 0‘¸Á�œGFN £"±¡Z—ÜDðÏ@ãQÛª'2Âf#Ò‚œÞú«QÆ9€ ŸÙ°Gj\ÿF‚í7e�º­ãnÍAF1â, Âø/e[ò˜b¹ÜYÜ3ÉŽÄJ3,u©C,2“@¡Tt¦Bìáö:*‰,ù ׂ¨„%ÁFÉf|`‰F ì@ŠPéœw C”EQð3j²‹Ò%bM3¾hÏD6êv¬í †Ðë«g ÑL gY˜©t¶X?ûϳ0Ñ2æN§H]öÓðÛµ˜½jžýþìÄvȦ�;ó’奢Y–WªðP˜å°¸Vð4G;?C¢º…-Ç:0À ìcáÜ*p<¶=rA¯,°m86Í áäìö¹c Î%”eÈVa’ÊÑt@YB$ÙUÑzlž?\QŠõMÑöf�‘ô8dËíûû–EÉâ|޻Ч4¿&&VðÎQQ–Ox–™U±¹ [cŽH ŠŽ\µÚ`:™‡è×ÍrKÚ”.rßs4,5H3´#°qÕÀ/Ôœñ³†èÀí¸¿`º !.’<L�ó‘d�Cý.^Df:µƒP,¬@UßÃÜk–Ð Áu2ײ­ÉŒ‚ìéª7¢—ÎmMBìúçùeÈ¥+Mž½Â6’(±Û8÷ï¸ô³äÛC±è�&(ÌÒ?@"}½7RQ¨ÓlGÌ“ðs—åz[5[Ä%˜½Ý¦\T—`q™áÔqeJ ðæõ=w,«œôæˆIQ²í$`ì^[6³4,ÃÔrÛºekeM\Áúž.Õ°JPìä;Vì±ÌDý�îYÂ>6šp*ؤa§¹µ@t´GÀ:²œh—(¤ÅH›?,ËÏ? âD‡*“väõªY|ây—–çE¦Â4ÙÁúçj�vh*æ<ó{É�¯È#mÒ2L?ùO(k®“3xC6…}åºì¿”¥éPêµp6ü:x, ÑaDs3‹8e,Dì�LNNb¯‚Û²F3é9Ã{�wÑž¨CsRhŽw\4Â_¢pù϶$AŒídýø0“†Jž†™8ÔyfG>Gí/‘è~v7Q(¥Ú1îˆðHùÔËAÃ×\BÆì26«ÊV® D= n|;W 3Ÿ°ñÐì4~ËÃwÂH+Ô¨(Àšø�Áp×GuÜ:q‘¡Ûë"ø¢! �4øˆG>ÄnÀ¾:2F¥b XLD¡ãû×:g:œaöYø fk„Ú`ÛK0âA­ƒœ�B; ZAìs¡m¶Œ­({Ç-0Ñ1q!‡õ‰€�úŽHÐß'g5ŽRkWMà[`|7‹‚¶DÕq-ßù K°{Üõí–ðÃ.´1@t°ÙöÆëæèTTµõÂéam�4€Ù¶¥qÚ_˜i{£w×Þ4 ^PïÕ°�ÐÚ²VRc­cs·½w�0Åf¸ƒkl'9ÍÛnë•ìµ�ÅC4t�ë2mív *Ó ®s_’ñ4EöTgÐÇRŽË½¥òÝãW Je© :°ÂîÙ¤b·�Ü$psidš¢à¨Þ0ž¤ØÙÉQQ‘†i¤¬¨`i•¹RªÆaÃvs�ðÃ;ÅÛ1Èßͬ¶I`¼)BE†IE4 ím9G+ÄhùÄ€{&Üõâö Ã5¸�‰ÈÉò'Æyóæ9{’DÚ)XíäƒÅ&Caî�šX|2''Ð Gã"u�‹<Ú‹mXCÓ‰T†¾;±DÝq'ù�cEqsuo‚(jW0ȱowÖû3J¢2¼ MÈâõ×^A“ ˆ‡"c•‰|˜ó£03¡�‚d�̯ µ8!‘t„�‹Í¹×yšI¶î,�³1vn`5ˆÐ\�ÐÉÕ Íó˜qh”d>0J®Æ·�™D 6OèƒÊGÖ»YlâäHÅlîcÛfBÁÒzl©ÕBîпQ!8ÛQ%sN�Ù}gxÒnx75£ð3u@áÇ ©ãÇ+|Ä8(Ä]›WdhùdG¬Þ$ÝW9IjL,­‹–>}$VDCÁáëÔ˜C–cyž°ªñÀŠ…1oÁØ@*šDš¶º­è{ÅàcPÉ`n×£ÐBÀ¹/É^ù¨ì±l¸Êj†Øœ¡(Ì ‹òž–Ü�¢Ÿh5ÓÓ±T™7 œ �àR^³í‡®õ¶¦™�þø]Ð&‚;® pàUtàƒ†±.ˆ¿È¢È†0$Çve¢°ü‡¯1¯ â0v¤^ N}ÓyEݦ¸-M|´ Q)€ÀâŽEHb„Žõ¢iƒq_Å×p_ÔlÃmü å�°Ÿ‰¼]¢mÀ´Õ.m(Ík ù ±ƒ±6)k“&ÖöfòaŒç|e>íó*n]‡±0q-xM"ŠY²/›Dèzw‹-ZJسMÆN4Çð�L‡ç+L:ý “¤©ý :4WæëB’ê‘Þ\4áx`º¾Y4覥`ž ¡w|é��Ó—OÔÐÚí`†$Cm4]C Ç€Y?vd‡<|BU¬·«¾òeº3&Ò®Fy>:YDiánðsŒeÆ"=–ˆ,ÄPçbýì�¿¢Ùº`É0qû…®gRâÀh¶š]>ûÇÎqžÏ’H‡‘Ž�MÃ#8Bnæà¯Ñ™�1ʤSؼh½·Ÿ(~ÛX™‰ÀßPåÓ™¦gÑi.Ù÷ÙJ&C¥åt+ïË6ru¦Up¿ayº‘$†�Dâ ÙCL”†™Vß‚•'¡飡‘{£ò<Œ¢Ø( ¼Y�…h‰�£å©Éffê4hIs=Ýðˆò_é?—¯‘äÜn Ã ¿qrroðŠ&z�Á§àÒLŠÿߣÔ~©(ƒß=Ë�ês­ZfàîýÊYòý°˜ >Pùµ_¦¶ÇÃw—Úp†äø R["(Òwt*³8}˜Ú2¦ÊHô· Å—E_Œä&ÔôöÄ­xéÍÝÊáã7çÿ/ôÿaè��(â0‘É1¢�?bpîLýž&ýi ?qƒ­¥~h�!®ö#ÑÕ‹³8&¢ÁKšùç}`ª\†B @¦’£¤�(c”H\è¯ (¿×Isg¡¹P°R†A@&vùÒYƒgqFRœ—Û_Hæ>œ¹ %a–;ùà0ò­â²ö/þr)Z`ÀÙ…#ß~¥|“‚"Oµ>y×ï‘ó+zi�ly{,1êÅôÑ xv9 ÇŸû©B!ô‘§mS5ªA˜K”^¶,3͸ßIûÚ@Ú37~ŒVǘ Lµ(Ê}@¾pÈ›ÏpiVóª’8ÉŽ�šÖFX5úi maXìÒw´-äãYéÜQŠ¿;ôøÒ·FŠ(9Yž3ë|p ó³V•¤'Ï €Ö$�¬ {íÌyD£>ZƒìiT˜AŸáA�ª¢PHõ}ì7جæs䫉6•(Ó'ï£LÝ]¸ÌÁ ñÊÏrÑQ©6±Ý>²~4&;€êGŸoÕ1Êóä›P-³Pƒìü.¨A%Æ�Ñ÷mer:mê¤?y?¤»ûùÉAº‘WøIÈÔyy¨Â(;™.)>•‰–Þ!‡GŸ|�`†$;‰ÀeQ F¾ 9ȈÐ@ yýµ/k“ßu�óO^Úƒywé)V°ü/£ O!€'ˆ91¥2,ÿkjø[K¡ß?U1HåÑ ò`ÜüãÆõ鈎òPƒ*<Ê÷yNOÝŽùîv\»øòi$ @ŠDéÉBÀÕ.o­¯žû?�öc«@ùcá³'`™|S¼-Fw*�¿ ÍÀKaœ™ ×åýzUÑå�µÄÓw²O.Ó�6~w,ý]ÈïXÅI˜$âd1á³@Žxq~’x<vi"Î1ô›B}q*ÂLdÇ7z8ñAš�7=’&ÂöªjËEß`Ü…~€(ž¼Q¸[yë\^9äðÞï&äÑQ}î_<¥ƒ·§ÎœŒÞÇ2ŽÄ1Çò”u€”óD�¾ÎÔÝΦîv¦ò]w;{ÐݾØãŽK§åÁýƒMœåÇ0�†¹JbÅW+° uÓÉËŒ§1v1„÷üŽt‚ê@<‘Îr¤½´q@ò<šÓö$Ì�Šü›$O…êû|cˆñ;¿²C³øÄy §}cxò><RÇÝǾ)yq0‡Á‰ütõ³o_*8åS] wjüÿñM=Œ{$ÈôÛ p @"ß„a´ÿ M�ÙçÆ¬x[u‹‘ ÒêÉ»ðP”»‹móÂÈoÜ#;Î…±b Ÿ� žÍbš©”µÏËS¢Þ dš>´à0ÀÕÆ¿±|á�áä õÉS¿q> ¼œ0žgê8ǽ$ó�ž‹ƒ³‹Üï=Èu¤Ý2åܘ³ûßX@Ëg ÐG rø�¯ðûßX&ûˆ³PkA3©Øa{g©"ßFö4Ñïñ¿Ô p Û¿ e&œõE'¹:Ëe`¯fJº…)Ø69^|çÉ~¤‡†?Ð?çÌyJ.…¶ÛoYqB�”$8çªqÐUÿ5ÓÓ-"|ÖüÜð+7ãÄ!¥þ®ìª…IÈ÷µÞ�‰ú˜—ar†„¬TõNºN_¢¯þµwït•Ó±×Íj9Íç Kgšzž„õ¹?`š LcSP05…ÓP4fÀRn¥»„¾ËG0–>pš!¾èæc}’ßõ�l#NÍ3“í]¡äô0ŒO$"¥&zR¢†DsÛ8ñ‹Òd$%tc£I¤Ç¢ï¾•?‹LM©f)h²|ø‚1¤—c~x–8XÆë8wæ1žšçïÑ"lêmÒÈlnæžfÔ–›Òü¦]Ú¬ùiÒ§#›Ñw&�”œnXõžk‹Æ¤ùÑF¨=¥Ì{Lj½Âd,ÃE0Vð´+¾ÝGw?WÞKp*æËâ†Ýtìdzã¥rËj:ö²7Љï4e^U-»r]Ô}µÀ«ñ±Îƒn—5M˜ëÆ.ãÜÑjàØ_ðcI+—×ÅfÃðÔ&wÓ| «ðæòÕ¼D=$Pþ�3N‰“c4tC‡žæ´8|åÆŒ¸æ_¿à«j±³÷£‰Í£zÉu$ŒÙåâ˜÷⹋Ó�Ò²³¦ lu|âçñq~ô("ç^"QôCæ:T «ëé÷°Rs>fϵ›f±í¸Ø ¿ÿ`³.çàí‹]¦X•£Ìì·€·QºØ;FNjsØ`âaB¯Muµ"t*T]–À+·,Æ$Ý^Ý•h¢¥™&¾´žÝ”¤É}I¥»aÌ1Î_�ç¦m–Û¥˜f|?"ÎL#6LRL1{¸‘Z˜K ‚â¥;¤ÆÙ®JÄC®°¬ð°ÍÜ'ÂKóyF7`°—/­c?Ýyá"§*c·ÎØx Irz÷Pš¸múªèÍMJë1´¤§jHGq͹0Î £ð÷¾T«•½Xã¿ÌÙÒ‚2×,]s^X‡2æ]¯ÏíÏF@_á§nL AKæ ?îšÒÿ3'fj†šw»²&ñ%Õoû­½ÛŠu»ÁÄW¾¹ŒÛâºZÁRœnŸОç� «Øx‡õvãŽJ”a>~ÔçK);;À‹fašìh{ú¼Mü‘_||‘ƒld—�„0^Ï## Ú8"@)ä“»ÁØ&[±.{¾}L@TuãË�g€¹0J¦Ϙ&y|^ܱ<ƒ:Z‰xëKjççnÛ¢Þ®`ýþÞØ�:VÁKW·]¹"]üüÐo¨x�™†ñkôç%R ”{y‰#LºHz_Öàm¡ŽŸ›(P"9“GãoXLxêËm;ülÅx! ü$q@Öàe–5ÃmAü*U“¬á©¤sßaž@�ÍMl¿eÄq¥ðiÈóÛô.�<-¸X£Úšû)7A‚NÏq9ù2dA-¼ ß'éäJ­•q2Þ ŠYÊãÓþŽùQŒØ˜)ð4÷CùUúMl­Kf¥û.'�O÷ÿ7Bê endstream endobj 65 0 obj <</Type/Font/Subtype/Type1/BaseFont/LEWTPW+NimbusMonL-Regu/FontDescriptor 67 0 R/FirstChar 40/LastChar 121/Widths 68 0 R/Encoding 44 0 R>> endobj 60 0 obj <</Producer(GPL Ghostscript 9.19)/CreationDate(D:20170131180939-05'00')/ModDate(D:20170131180939-05'00')/Title(figures/fuse.fig)/Creator(fig2dev Version 3.2 Patchlevel 5d)/Author(Bharath@Bharaths-MacBook-Pro.local \(Bharath Kumar Reddy\))>> endobj 61 0 obj <</Type/ExtGState/OPM 1>> endobj 62 0 obj <</BaseFont/ZRCVAK+Times-Roman/FontDescriptor 69 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 0 0 0 0 0 564 0 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 722 0 0 0 611 556 0 0 0 0 722 0 0 0 722 0 722 0 556 0 722 722 0 0 0 0 0 0 0 0 0 0 444 500 444 500 444 333 0 500 278 0 500 278 778 500 500 500 0 333 389 278 500 500 0 0 500]/Encoding 70 0 R/Subtype/Type1>> endobj 63 0 obj <</BaseFont/THIFVF+Times-Bold/FontDescriptor 71 0 R/Type/Font/FirstChar 75/LastChar 115/Widths[778 0 0 0 0 0 0 0 0 0 722 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 444 0 0 0 0 0 0 278 0 556 0 0 0 444 389]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 69 0 obj <</Type/FontDescriptor/FontName/ZRCVAK+Times-Roman/FontBBox[0 -218 775 683]/Flags 4/Ascent 683/CapHeight 683/Descent -218/ItalicAngle 0/StemV 116/MissingWidth 250/CharSet(/A/E/F/K/O/Q/S/U/V/a/b/c/d/e/f/h/i/k/l/m/minus/n/o/p/r/s/slash/space/t/u/v/y)/FontFile3 72 0 R>> endobj 70 0 obj <</Type/Encoding/BaseEncoding/WinAnsiEncoding/Differences[45/minus]>> endobj 71 0 obj <</Type/FontDescriptor/FontName/THIFVF+Times-Bold/FontBBox[0 -19 761 662]/Flags 131104/Ascent 662/CapHeight 662/Descent -19/ItalicAngle 0/StemV 114/MissingWidth 250/XHeight 463/CharSet(/K/U/e/l/n/r/s)/FontFile3 73 0 R>> endobj 72 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 3413>>stream xœ}WyTS׺?1pöV‘¶Ð(yØ„jÕÞ:ûl•Njq¸½ "ó  (£¦�!s€’�‰�„È SÔ2ª¥8´ÞÚV±^kK]½í»½½·«¾Û·öamúÖ;±ë®»Þzk½$$gŸœýû¾ßïû~ßæP (‡”PPœS±>®¤8Käÿ½š ç0Ë0/p͵ÍíDA\p~y°(>‡ žÁûž¥¸ήô⨒Қò‚¼|qÄˉqÉ¿[»vÝ¿®lÙ´ykDvÍ?W"vçTä‰"V³_ªrŠJJ‹sDâÅÙ•O7�8P—“WY”UþW(ŠŠØ%*)ÝS¾·B\Y•�]sìxÎÁÜCùñ'‹’Š×oŒ ¨ÔA*–:D­¦â©5T•H%QÉÔ;Ô:*ŠJ£vS{¨½Ô&jµ…z—úµ•Š¡^£öSÛ¨T/õ,Å¡^d“BP9Ô}Î N÷‚°U f¹ùÜÑ€ð€ÚÀ—ÏÒÏÑ6ú¯ Ü€Q°sá–…‹8‹zoYܳx6h[Ð÷AÌ’g–„`sð\.òà”æEg.©ƒ—aÖ8ògˆ‰¹VM“ãóªh²Z%K×ó%8­¤W·ô·˜]ÖVá^ˆÝôÈÚ–R[RðQ¹´.É�%¸Ì+±ƒ‡îÃ�ô3�ÈÃð®p¾œÅ»g¹íKq¾›N5ËZ‘â³`ò½®–3^ì.zWHr€þ*YZ#”ããn�fU·.B\~ȼºëH‘4zŸà!¨7¥Õ¨d|)h2;ŒNûìò4!1C¬Z™ÚÙ 5}Ì–>NÿwØõ›™£<²lóZ" Ëÿ²‡à�ÁB¶ñò¼PY›½¾–¼@èŒßï<žÛ}¡JX2%û }ÿ:q뮀})ÆÅ/|#äþ,®|¼,´ÕJŠyX×Nï4ª†�!Þ B%…¾.Íh8^ü=À«ð³{þüJ|fEB¦ðК«ò• R¾ Ø�6dGð¬MsX8ŸP’Z«…¡ïá Ì oàªobæâ²PšB¤íŒ:ç``–ž#Ø>Äùé —ù¿Å+¡Ó_Ì('+ °”^i6Ñ0Äo�³úVUk$ìÂr1­z]¡Ú¦‡d.§�K‚8œÆPïQ´m�=t#^8ß'¡ïéZ”¦(8 ôQJET”0çA0~ÌR¶ÝÃùb–k]ŠëÝôïM2—þ:Ä•À;z©¯É®Ó8mr§®Án÷ɾ3Už‚,QeTšð?€Î”T™§Œ•°ñºÌvc ‚=vY¦�˜�>Y«�Q³ü|ø¿BªÀ2 ¨ß”*"YÈ«žB6›ûŒ/ÿ ï†×4ê:Vsg:À³Âe¸±¯_Ú-¯³ñ5�*ójWÈ·pägËØLßÁŸðð �jZ[§kÔ!-Ò˜ÔVq³ØZ�à›qÉQñÞcߤ § ÏUŸ¬@EüÌ%){󇞈2²©•¶9,&6¢Ð'jÑwù¹Óöžnð„ÿé£éÏ.‰Ïð õqI›¼õòG{'® nîãAÍäåÌÌrq “Ä[�!íЛu‚CÛŠ DRu½VË"i4êÍzø!¹Lo8zýâP÷Ô�ÒYY&«­Dü\yïGB<ü3ðË{š ñøëiï,—‘_âéè4S}³aâÉ)¸ÕØ¢A©�¨�*Ñ)êÒÊ"U1‚ÇOœâ‡dµLê] c:$Vðæû)÷ηõö ÆÆ·‹þ’ÇçüÀÅgwQx˜7=¦ŒÅK„rÚÛèÖ Òè5 š—IKØ*l׺]ÈÎGíNÛ93t“9ÒÛ4/á r!̤5×›ëØw½Ygj°èͨ ÙZÝçñóx&¬ÿN“mÀÌR«¹7Í„u‡\ý¿üˆ¥ˆ9ðGžT¡ÒÉ׻ƅ8 )]¿¼»Òw´#Áõ»ÒbÄÕÝݧ<�ƒÕ`êí†fdƒ½ÞÎ {E‰‚€lØ/­;šSY­(@…,[1ã™7ÇGNMÝ„¶&YÛ«GÂÏ¢S-ç†Ø%²ñk*Ö©«TåŠÒº*óKÎŽ -Àxc|/�OûãÜ/dµúÊÜ2Þ�ÆæT�*ÅÅ )dy5 gã}‡ýQì ç%à�Ω2½ó›>Õê·üú<×Þ¶ªœ†ˆ‚Ó§þkÅ;.ïA|¤PÖ‹ :¤F*ëœî�ÉF…cÓ߈›Ãp޽s»­ùŽ•ßAÜOy÷2‹?â|:‹«¿åâõsoñt¦,yiÝa%_T(MF ²!8Ò\›%œoE³…�pؼ�¯ÄÏîøËš‡òS«IÓ¾©¾�ä”À[Ô¹EAÂM�ŽLÎè<ý´Ý‰f™›,í%~ÚÃYÚÛje mc½ðÒO�nÒº\ÈÁ’î¶�™XÒ³àtÃIu³ÓÄÖRj4X5}©m¹HŽdâÒ"yy•DÁª»–­³[�E†`…DR^8X>vgâ ^uEȶ¿u­^§£ÛÌ÷ëá.ØÏéyÀeVàM¼ô=yqnŒùƒ\ù쑯U�ë6U6‹Ú¥�ˆúTG×Õ=“ÛÒRªó²…©™%ûÐ�ðnÀÜ÷.´ ú½]}ןzÂóo}œÞǸš-Õ4OiТóêœBæc¶m¥Kó5Ñþ6ÝllBÍž·k²…dÈñ–:�!HÀHV�çg¶bîÕ!ÏäYa4°4â5S�dí ª¯WiÔÒê2�Áí _âgpàÅ™/.¿8Iè�êS,òbàã0[ðv^úŽ£¢h‡Žö‹®Õ Õ{õ· ¾I×ÝÖô—{‹}GN%£Tt¸&§àpvén ‰àî«ü8sS£ò'¼Žç|xÖwÝDÝ%­[ýUø˜ÿöqÎbšyÓ\üëÜv‰'ËÉJ’±Þ»ñrœp:æÏÇ¿e= /g½/ã'Ñã„ë˜O·ùÖ²)˜@5¾—Ó×#²Å*÷V'×–KËÅâüüŒš$te´ç ¦LþŒ0=éûÛè$»ØyÁ߬b…gõq0dÛÛ}¿nžaûÛõŽ�¡ÎV�¨]ÐVÖ¢9ÉE{{—/óôÁ˜äÒŒ2aYF]žá yâ+ò ­ß©Qïö»~«DšÕNtâOp0`#›{þ_qÍ"ÿÎ#´ù�ñ×¹Óê;9qaæ�Cß³˜ Î ËñJ6dÐ/‘Ìß D^� gy«?¯˜L»ó^’…·¢VäD#l¢ÉwsÓ¼14!9Wt9Ý»‘@ô²hÕ±#¹ÙÉ┎2Oæz“'Oü„ð"ôcÿßG&.Œ¿jÁ߆™¥—9÷fñVG27/Ñ®³>‡8ü’}926«âà¾tæUy]¼Œ_ê/M‹ÑŒ¬Ž5×Ο`½VWWÏÆ[䇬uN=û-�89Œà¥ž¼=B’ô»kÕq:ö¦|Ö�Ùm§Ÿ„|óäµÙe¡Ÿv-Å7ý®µÞî·< ÌdcB œUn‹©ÕhGüî§–+ú]µš}�0ô0·‰W*—ˆ:+û:;ûûÅ�"V˜*|•†ŒxB>Œ?/ ]ÇijꩢC—‹Ôji¸I-ÒfzÆ•›Û\ž…2¥…¢ü¢š,”ŒÞ�DZw�Oëɱ+­U¨¾›zä�Íû¯ààT�˜ ù��thL‡±Ååw¢“ õì“äC#uÃá~ûð?¿J¸MÂî W\ËGWà•Ñó·Þ•ä� žp•µÅ²®ÿ[Æ7x8_ÍrmK±ÒMW³Ìl/=ÏÇ1�G�ƒ�Ygnä7kÌZ¤ƒµµZ•@"Ç"7�i.êÈú€¬ÇIaý½ø9ÐÛö±žï&G`Øàl@JT[«T(Ùá/8ŒÙL9*QÝ!¿ØÏ›F£ƒ�ÕìÊtá|0$56îV?-µq†ñpþñÿ:Î�Kœ{…Gäú�Î]mz ’.€öÕçÈŠKÓ£‹v¢Ý(­»t²Æ[}ñ=`¼çp|ic]Â'µ�q$·Ùõ(¿�9÷ÏÝt�Ú'Ј]Àô‹ÓõÈŸRÏùû,÷ÔR¬vÓ1fµÃp2?°p“¥9š½lÃjNc‹‘íX^‡‚,Ë€!Q¡Øßà«öÌ-açúý~˜YúJc»• Y}©ª˜¬™ç†‘µøû™ºNäæ#�Ëî5Y‘ÓØjd!vHÀEvJÛ‚ óan—3Óg:�ï³Mz®ƒ¥$lŠóxÇø?ܶ¥¸ÜM§eNÈÏdjvØl=]c'Ï!8Þ™Ïê¹èã4êx‘‹Ý )ÚôìèlcÞöI¯µ—n’< �ÕÖÒ²7•¸A™é„UíFÃ|œ ð¢ã7ÞŽM-;”(¨¹VЛˆ2P™r[4¼ÏžR$ìy@ΞZÍÍþóÀi»,]Hš€>^©Hð×ìM|æCÓƒóæUIŒŠfsªðÌ XOd¥žA“š_÷N°—ÍÁ “äÀ.zhÑ׋{,«Ùâ Y=‹Íj±8‚–PÔÿ�ÈIí£ endstream endobj 73 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 937>>stream xœeR]LSg>§e|ß´ž¹%M$²Òèf&H‚Ó7¯6 ]ÐQˆdþ¬U TN[è)?µÐ²®éwzÚZÊ¿´ä¥“ŸŽH¦7:݈¿ÓL‰3f[Ì–x³›ïtŸ;lYv±»÷}Ÿ'ï“çy_šÊRP4Mo¬4[L\áÇ6¶f½}GÚJK¹ ém%jË3ù¯!•©²þÜû>þ&>ü.ÞL)iú£OÙb[£Ón®«whß«:rlgAÁ®ÿ&ïíÞ«=íüÑ4qæ:«v‡\´˜X[£Ådu”™-§›9í›ÅhÕ–Ù>ÐÖêM5æfËÿŠ¢€ÕÎ2U±UN¥*©]T µ�ÒSPvAeQvê]B¯* 1Åu,0Ò5—˜Uú1ÎÅ[q®RšÕuA÷ ?1Ϫ¯}Xnhª¨Õ<$å°ä‹zy#$‹ `üÂkðAwŠ >äB3º‹õ&ÆÄþ1¿i¬Ê#^¨u»zdê9ÀH²Ú�8ý\VÂË¢ºBðô£[ëÁ7‹Ó½Q_{Ÿf´iÈ›Dp691wùìôÉêzî“ykDï�_uõ»ù3ËŸùÜcôË;ä�9i©hšžz‰sSâ_ñ5ÞÖ º:ü]näGÞ +ÌÆšC‚{JË÷—.œziÌ»c�°#ÖXìŸéN^~Þ¢i$û’Ù±±H¤EÐ…žÞî)ÏJç$‚¿Üºùó=ÓbþBžn²1‰Ò0=!Î��w¶&4‰Ö>ç 2™Q§1ƒ÷(3AQÍñž°gˆ\•²·`=>zIü= E2Ã�Ǿpâ�«ÛDzÄLÌ[° ï ß Éø3¬žmç�ÁWV¨vytëÙþ$‚’¨k °q%±ŽØ/:Â^Ô™ƒ<nÿÙ@ò:2ñéz²÷ñ¡¼{Š–¶aF]sÂâ4"²Ž´^jKùÒÝ·å{fûŸ¶/³s ³§â•’MûóÉv²}­3O®¤^|ŸGbø€ZÀFæWÐ$ºØeCmB_ Û“©m»Bÿ�‹ðÝ%e¦4“¯& \ö£®D :ÉU@Þ­Ô‘×w®ã ^ÁGƒO„œÝö÷¹ƒÅ�¬T�8þ­aÙü�óúÝI,Î~=›|ˆ^@¼ øƒÃ7{!ƒSrœw×ÿ#"ªÙÀ¹8š‡Ò�¤ÌÒ=ÃN¾¾:/¿”³…E²q7`ÚF%c›ùìÔ¬Ù˜B‚ ÇA¥ZŽŽG’±PXPmâU Eýc%»L endstream endobj 74 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/queues.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 75 0 R/BBox[0 0 825 521]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 76 0 R>>/Font<</R10 77 0 R/R12 78 0 R/R8 79 0 R>>>>/Length 2744/Filter/FlateDecode>>stream xœíZKsÜÆ¾ãWàÉ•ÍûqŒÉrìJÅ$]9¨|PQkJ –²H9)ýû|=˜ž™]`Ée²GK|hôs¦|¥P£¤¿ò{½^\„ñæ~P#!w7ƒ 1çG§œÆ�»2qJH[´VãZ[\»–1 ­Çë�ë’)³`ÀKaâÈ,­3Rb9 åëëA'©…�™€˜$¤ªˆN> o*Ïv�…‹`½¦†Í™%[ÆBùúzøõ›AESÿ3Èñ»¯þzÄ_ï‡Ëa^lX\&$)¼•´Vè0p³’‰\ûñnKþgmµË¦¿‹ïNyðrÐÊzá±’�óB†1'L‚¯”1"êÂýªK¦ �£ÑèQÛ˜tD÷�˜ßI*¢¡hR×ð*Tm×Ú�ËàÖ‚(¥¤°ŠÜʈ Ðî+<ÙÜ"”/±>("¦`�PDR9Ʃʱ^™`QÖkê�YóÂ’ c™|½¿¾:êG½/K*o<$Q6ˆZW"„Q±>h[!S»T^82³�Ök'4©È€ƒ*i£ð³Î%¡ð[$òõõàbˆ”A¼’³T—,YÉ,ù²ˆ‡`¥¦ÌJ3?¶‰%òu^O_�sÌ9{‰Ô‡äòÊëóaÒGé ô—Cð*�3=�êrpÉT=Âéq¢ËE!Ñ�ú8ÕYYÕrd•¦(a•*Z¦"SOœ©'š�ž¦åM&j‰³£RèÌUA¦ÎÀŽ*APTëTM"Su?!_9­$nÓ’›†¨]÷O¾5aMš¤aŠ�1©äQà&i©›”"¥Ë¤<µŽ ¹båmÐ|¨ŒìË"ùÿøf¼mEÈHp½§ Uœ B¥ŠL1†ZÛ‹Y"ŠTÒÙ?Á 7«Æ.•\r¨6u!¨È¤ó™˜¾BÔl@òxØç&rW�½muαI ×�òÐ:BmÜ«áp—Sí¾¤eÈt²¨¡±[ŽŒ`Ñ£ÞÆžíÑ?”­˜µÔg©ó�†¹ �ƒE¤¥à’ítD�‚ ±¼”J¸T‘©åM�´/´é‰ Ò)›D°=QA:"ÌŠ*P#b¤'²V ÕÓÌ�‘påhzÃL“LJNo. UŠŽbÕSU^-¸‹=¯‚ìñjTÌ«£ª¼`ÐŽWAöx5*æµBÕœÅT½³j mTEâ*û´5ŸVyµ|Ty]ù8y3{tŘΌs�z‹Ö2125$|î�ÊS!AÙœˆlʓ졬•œ(ÉûZ?w¡ÑÐå"d�N”Ø–H'‰w\Eò_±õ¨ŽK˪Ö{ø\LŸ’�]®…è=1ŒÏŪ"<ò£W4š <³Ž8EyÂ:‹77š’–!³�zLÓ…Œ‘ æ»DÐO B¸ 5»–-µ>Ô‘ÚÃ3±zRX‚ ”¼[1®Hm^\Äõz ©Åx Áb6íŠú¡¬e`Ø^^†»Æ¥.ÌŠìu+kv,ä¯èx¨…áL¬ž/Cv-ö¡,¡§c¬2F¦†xƒ½  >tp ­¯£±,h4õ=Ie{Ÿ<<m»ÍÁH„T"ó1?¢«\Cš¤:2@aZ³ó¨Š ³ªÎˆÒ™8ý/ArŠá» 1Ò‚ä$Æ•;™!¬º“˜Ó}¯iã|'”`TÐ.Lh1‰ÒÂkH“ÃSyú(õ†UpiVU¹ ÓÿËŠâôftžNÃÆ_œwCÖF*gXy&¢¶Úæc�Ýdè <¥¹ÑcÎpÝî¯HMèÊ‘zìRwÿ"%5«-‹ʪA~SLlCƒ×tþ[ÏpwÑt†37.hÊ–ˆñt�§z–È^:]ñÂRû¥… {°Ø–Ö~œ‹ù|È(a­4Ê”·9Ø ý¤Ø �ŠC„8 oÑ2‚B˜îÑl+ß.eh~è<­ ÈyôaZZff©$"æÍÈBùúzPÆšÁ‚L@¢¤W õKÏz]¤‚GAX³©!³êÌ’-c¡|½‚ýÕWûê)µA%¬O”ÿ±A•´Å™â0Ã+rM}êDK?¿¾±t†›zšÊ™kƒE’0‘cR74“ªˆÂùzâëÆJ+š²}‡ðÑÏŠAÇYª_UÛ<ÎÅôI® 2�ø§¢éÚyEÕ��©ù*WE~æ!Ä¡+B*Vù`*ö4•qMçXS•í «+~Û‡<­„©gë;´LFH²˜�z®Y€Nº—ó»ÕŠP(ëúŠŽ°4»šD ¤ª}&žOj¨} ¡�Š´jœ ½†´r²‚@gÙwù‡²–MX}_«•O×è‚Ä\Ž=͵qi嘕X"‹ÓÙ¥+–&,Í\…�V;ÎÅ“BZ´£çwkGs‹ó»þ�Oòrþ4¨ùÿòs½¿½^\ÐûLaÐŽW¿–…ŠO|�8è`J"8W»áÙ8>¿úç`°ñ½¡�(aéÎ;Ü¡/.À†ûà-±Ú(«†œq£-Ù¥2é«ßï·D½™…šqc–´œïþ°½»ÝNt_cz´&îßþË݇oïæÇåÌSÂI“æÛ{ÓñFjÜ wK… Ewÿüöú}¾­à.«òÉ 6Ü|óç{æ‹ÆVü•L3ã»�×Ûû{" çlÈK–μé5=;à¡7Ï~xyñ·—?>ß$8'%óìç˗Ϲúkõ+%#ÊË(/›�Üú§û/·×Y6›JÇŽ ³hºùÇñÃíçíÝÝï¿}¾Ÿ=éM8Ú»@Ž6ÁC˜#•QˬÍϽÎqÇzSÕq¼Ê>`àG"ýšGaü|L¹O¸Œª¡AÒˆmh�;YG¢uÂç7!Îz¼å›Ê9‘�3±&fŸ¿‚wö—Â,Çϱ~»Ý}¼]17ÂuR#ÔuXÝÙ¤<v›óÒémà'76k¼^{äuõ‡Âf¶ˆý¼ÊË‚±˜ø�žI_}¼»ÙÎÁÚ ^ äö‘Wt· >ÜÞÌ�ÈœœonoßÕ;%�*w¾}{ý¯›»�¿ß¾Ë;«›tÛä=àfí¿?X)ÑÃx~ö¨¶óÍÙ0£g>Éê¶áööóÝ—ßß~|·]“´›¹� ûÛïåU_d�e¥}Žu×9‡�àÌ °Ø\Þ@wÛߦ/•ó£ùÛ¯ãÌÓQK�|ÉÝifÜù%³>µàFE6¡õȇ(>O×±è -%æD�-æô¤<µ†D˜-Q!!.C5-d- ný,ŒHužõ F:¾Ýëݹb®Ø²ÐaEÏ…V¨˜çbõþ”ª¶eC‡$ž†y´„!'íƒS×Pþ´‹ÏI´Ä%é͇ªMMˆáïfr´'�_6ƒöˆÂϨ.‹]é»Õ;�êôfRK¥é4\Ò¬ASõo®"S‡PZ5y"ã§@TN”@h$³{4̹¬m:Â@󎶸aÌd•Gwí ¾Êlÿ£ÌÒ»�ò ï„5Ë�k¼´“mØïZ7|&îO ´Fµ§/$½¶¯]CjVÒÆQ•YCÊSë½ç¦·±:Í/¾e-ó'Œ�ÞÎì*F:¾{yjÅŽ¥ü¥Ž �(2gbµÿ^¿~OS_}×ïiºWßõ³¢ÚÏ3UßôW*~y\‰ÚËãú-P“Çßuò~þ ‘S*& endstream endobj 80 0 obj <</Font<</F39 35 0 R/F57 65 0 R/F40 37 0 R/F38 34 0 R>>/XObject<</Im2 74 0 R>>/ProcSet[/PDF/Text]>> endobj 55 0 obj <</Type/Page/Contents[13 0 R 81 0 R 14 0 R]/Resources<</Font<</F39 35 0 R/F57 65 0 R/F40 37 0 R/F38 34 0 R/Xi2 1 0 R>>/XObject<</Im2 74 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 81 0 obj <</Length 5191/Filter/FlateDecode>>stream xÚÅ[IsÜF–¾ëW0bSŒ`AÈ K÷I¶¥¶fݶEÇl@ÈB””Øœ_?oKlLÊR»#æRHd&r}Ë÷–Н®â«¿½ŠåùÕí«×ïL~•Gy¢“«Ûû«T_¥*Žb“^Ý®~Þ•MU´—ó]ï]œïþÞ]ï�Jw§®¯°”ìúê÷K5Œ¿=ÖMÃ=Êî$=îûîÄ¥ñXqão×*ÞU}[5׿Þþ,e¯T”;ÇsÞwýõ^kýë�KC5 u×òKѤör7àôíˆïÖRäšÆ~ýÎ¥‹í©$�l¬aFšéõ¡úøúþ2TÜuu{ßwµ6Þ v1L6^ú–Ëñ ?Ëâ2Ôí¿Ðn±p(ªS'=ÇŽŸÕµr»Ö#¿=ôEYÝ_šæé:q»ˆWb`ri¹‹Ûã¼Î4ÊÓXÑ–ò(I¿£÷×ûDïþN¿·ð«vo©ü#•ÄÃÙýD5ßSÍm`çNE‰v~D¹`¸¸Üíð>ðY�êq¬ür÷ÄO¾^(,®—¿º§í3éÄ®´hñ$`�éݨJ»ÝǺ» �Ô |½PšIMgjW buÛñ³éÚ‡ª—ºª:àò°üKìâ*zˆnB´öx¬ðfr½+øÄÐséÜw%�¾¨Ý]Ó•¼­·vÓg�+1Y”+€?Òq¿¥ã~Cåo‡®“ȨÜCt£�UªÛŽv¡˜0€0]¤u¾ÞÈÛ¢<âíêùÂ�ŽÅÀµ¿_ÚZy~/9#¶‘Ë2¿�櫲ú�ÀR­�T<õ|<Ö0óóC€ eÊþ;ér¯R9%ûNx`¸/:+Ǭ…Ôv�Š©¯Õîþ‰+>ÖåXŸ¸ìi䙵v÷A¶É�íåtWõ2ÒW€` D­§‚»'¹'âu(,IŸÈƒdUîÉkš¡›HM†¥ˆ îšË @÷¡œ›Š8�eÐÄð&´¼=BÍPÎEYù¯ÎM] /‰™·‘#«¹ZÙÿC-/«Ë®‹º¤>DQZE©›dmÛ*þô}ˆþ�‰â‰e~Ñ:Á@½/­¸Ð¾�RN«#IìþE©I’]ÝŽ$[I˜$r¸"¹Œ=XLQW^tºëÆ£¯äçJ†A¼ÈÀmxq!LtebÕtíçb<îÇn/saDZ/Ú¡)FÖgPÁÌïÎUªïT'"!kSZ}€Ùr�þô¾#úqÿþ7ýþDõ߇?‹l¶ø°“$Ö+j°Ù©â…Ðý@�h²aä†Þ+]W’Fi¾fØZ$jÓu+�z9s=Šk�È4ÜÔ’Vx亮•£õ2²µ/Ô°‰•çFõŒù½:¡õ•OtAE~R›�ãe[ ·‚SJ]ºûb=¬íA×ã‰|¤ãÀOŠÖ�äg/v'ÅžB¡ê@sà®t<×®HºŸA&Á-ì†ùë€NÙiãI«¿›¨C‰‚úÛBM…¤¯I¢Ô$3‘ðfö$‡²j½'/1Œ%ÑFOZ=ˆc`;{‘HXÇ 1&êHÿ%¡?,�»º7ÃÀ'Áãd¤wªŽ#3Ö¡*ëƒ�‹Z¬+šYܪ�Ʋëûj8wí�Ñ´бÍ7Œý¥$(òtsê *�3þоB@�dð-�ö×ôû-~øêíí«ß_!ÇWêJYPñÊ]ÙLGÖåWåéÕÏ¿ÆWh„D&Ï®©ëéJGy†¸¡¹úðê‡ Ñ/.ÞsÃp(�Ì·ï%Ägß¾rÓíãÑK" ÚtÍg(¤:~"’WÈb¼�§K#d£€l’x#Æ”ë(â3¯×jÎX*D—Á­4ÕJ>SfIÎc¾iCÌ`¡8íæ ÜñVpJ� ¹(N³g¨X»„%<ª¶êQ‘9��Ê£)*ý¹GHB+'�/]HgÓ‰8°ºTº>ܯ5^ÉX�gPÝ¥×ÐÔ�«v�6®ù%ŽuƒrÉÄ^.a5*}Ö�øÆ¤½…EíAv¢]âZMB³{÷Ó‡·X²³ac<Є‚ô*�ã*#³\,.¼hÚcWÂRA”…"/õŠý9¶0€f�Å[æO`ÚC²ç€£25Ý9‰%�Š<®Äƒ$ƒ*§#tpD·,† Kx0kâÈmÍþMXR ËÑ^ä) «s­ýüf-Ô¯£9ÃMLÿXÉÖѬ�µ™1 U»².-&‰ç£Dv�U~×Xž Çå` v+®ñs¹÷å”B°%*;�¥ø2™*›NŒ+;®Æ®—æ³LÃ+Úû³ÆÞu‹°ˆˆ> íó-w�= Ó�…q‹ò·âŽ/Ë..šž†±:q™VËýÙŸ¡½ u ~ʾ>�ˆEð½»4X5Ïaã™– ž„�玗öPõŠØ0¨æÅAù ÛÏE?rMxÈŽÿyí©ãæñ ÌgRL™‹Œ�¬³wc1À>ÌJi«â®ji£â$“Ôã×-�B•€F(­ÿ.JÌ5Ì,¸äµ|çù¯l:°˜þŠx<óx|+Øc�œ. ™Þß=3Ã?ˆÄÈ Y“­6 ó³'Wô(\Mä-vâ^Ù<Ry²áÁ^ôT+Žöœ±æº‡oAHk×�(¹g¾7–=»†°ƒ^Ùt!‡åo¨ü^€@ð ;�ÆÎ<Œ£¾ìÈÙ òé¹] Ô–l.ùŸPÛ °`*ãAïf7'!:�’|#˜‡êT€=X ñC`GP›V_ ²$ùƒ“J—°ã_%N0ÖÔ< >@W«r¬gæ›`†dr‡Çu! �*ãTçô„êêzòÀ²üŽ ¬È¥Ÿrrù_5]²?H-6ª8Ï7™˜ÈЖqF)ÞŸÓl bí¼'øÒ¸­Q@LgÓîžø87Š/ù®©Y Y*‰L–}ÙnƒW—Ì>1„U*�ïTËS¼DXӖͱ°€¡[§ô© ²Oö*ópæ¬1¹Ž\êX¨ÈMbж.îf²�ç`Ÿ%ºÇžÄZØ …ôtH1þ7z| ÃX“K}M®*,ˆ;�"š¸\‹¦ÿPŸê¦è—ã�ýûðш’ yÀ”õú[M”$�ïÃÂåäpéù±–ZìPù‚†«ÏòéêÉ·|¸xUð³ýuáßÕ G²•ø÷‚ñxÑl𢙠¡FÝ´ñÀÕõ=w/ø•- ,MÞm|!ðŽÝÎËÛÝ{sjIj5bð•¨,x¥xÊ«/åÕ‘¸P5Tz¨à»m3�ûfÆöoÈ5ü5�î×ÓÍzù<itdçϼYÌ>9ìÅl¬¬¯(Ò�3Zb)˽i”å~Ü‹waµØAPšì ,÷PË ŒÙ°‹‚#€íÊ OôLº;£«ßG¹ ­éêR̸o™—ÐêºÜˆ÷t›�­*˜ú°ƒ®‘ NŒœÌkGæf£�ë&¿ÑÊÒÊÒÈÙɃq¨î‹K3Ð/óUe`׃øý2‡ÅÚoœÇQ'4”5rGóé !˜’™®œÍL¿©bä�“ë!É"“l4Ä,ñLºñ°¥ZÀçC_„"™ð<TÞq„ož–ü˜-”ï rýÓ8Aû—%�t´dÚCÑؼù©­ÿÉõÅŠK4G%}ÉsJÛ�.ŽõYl¢öÀí 9˜aNB{»?…êÁ7‡Ë, ©þ)¶Í³ì9Ü#HìådkxÜ›­âC�EuŽ7k£4—}}Wßõ["™œÞ|ÿ é®!ÿõGºðfáÃ[Ð#b§'õòu�ý<^ŠfFX‰·ï`df-º^8»p„õyóªtža,e¨y³ðf=ÇG\TÇR§Yð~CQg}”!óÔË¡ˆlÝY¤VÁ4-s”/D·pn“³&VH Œ©3U -Ùlõ�-,€}:H­Y¡tí=Ú>>†fκ ùp^ÍóÚX¡Åu?:i¬3ZÎÜÄ�‡¬N|•˜Ö †_rÆøa`פ£ê¦ Sv¾48gÝ 6=\z�SØ�7©0â ÇB¦z\€•óƒ×c}xaÚs7bxªhpá™î¬°â� Î}¶-Ö]5>V•ôXÊ*ëI ¤ëQPÇ›¬ÿîÅ·Q&Ò`qåQL²û÷W€=bg©yQ¤&ÿ‘T¼~ÒWßt ˘šö<à~ÑËù ø*±Äð<g’D1hñK[·«á¬¯a—k7ýÖ�LìPÑQëCÑÖÿ;9B5s��¼“P”x©Ä7z*ú9Ød½K�= UÝO7ÃÍÈZ^yY±3 êž«¸4ŸT\ÙÔ>SqË­cÒ†…¡\ö�ÍW/:pÀè6°˜[ƒÐûŒ5 8uŸZƒa©Íj EÝP@Kü¸šs�wBXQ¸<ç“åæCGDÇììÆÖcñQ ~Œ0, B4^´‘sý]…Y3Õ'rf˜ˆ¿}p@Ô‚ö ¼zd©è)¡�ÀJ)Ψ™è~#ßñÞÁx÷�z9EÞNª�}psÞιë½j £&”øZOÚ¬é÷¢h*I:…ª¢çZ'SØ5~�_AÉÚ�‡é6¼�07줳¾­ŽË `ÖSáäôù4C�º9 ü5IBƒ‘ž³TÜóSô`êu’W�ö§еÖSF+ÑËZyQªVÖ(†AË�P# Ü�=ú 3~#ࣕwå*†â€ºƒh|œ"ñ"DD]=?SÀFÆ\ÇõƒÎ+e'4t*ÎgàJHðÆú ôvcfs�nD9¨$¦ÝÔ ƒÍ´œS��‚æP‰ç@û�NSPž_‰a|+ŽB+˜ÀÇL“ª ÉkóY|>*Ù†‡ªÍ� �1Ðxß‚*-( †™{ä€^Áùa !Å-,8Uã±#ÒKü^+~a‚jjŒMÊ<á òd�Ø¿=Je`þÀ®™hIÚ ”Ø£>ðËÂ-e)ñ¤ï/çQ™€¡�¸…þ»nºîÍ„�6Юã%µ5û›€�ª 3¨B§ÀÖ—€Gš†¹¾àІSˆÁsÈœü$Q�MÒ¤{LM&`yì[Ä7o‚.ãl6oãå�ÒÓy¸Swø£á–.³$3³{u5®¥ª§�ÇþÒbxÿcƒ)òTÛgÞ4$¶ŸÌB,AÂûÉëÏ…x£×äAm³OAÿåy2çØ�hÆ}b� åÓ<›•ÀÞ!©}àQå9´oÜ^u–•ðÑît!É/R#âX2ù¨H”�=ÉÃS"Ù ;m(å jî¼A½áÕ¢-§XàC#¢èÑ·(ç�È�¤åŸË Q³`k†L¼˜l»XàÊ„ð¢pŠbÏɇ•3Ìö+YÖ㋎+~âìÐJEfÅs€¥E„�Q ¾:õmÊ+{ÔrKÖÿœwÈ/„ŸhYëÕ0ö,Ũ¤>§¢–»Œ•ùä8ìá.– yU%N Cj$ž‡K/_ ²¶.Y{�Ù#s2ðBÈ,ø|‰n|\Ô[tÏ×q”Î }Ô³ïQǘ¶²ñÒ<Ð)'7Ã¥v-Ïf` ¥³»â,†f`SÌ“<0°ý¼�×ð9@©:JõfxIpg3Ò½0�q�÷g|V”xx¿=ð|—Eüi1Wå³hŽ}¼ñy\qdólÍË3Õ‚q{WaJùšX.`e×ÁB Gb J¬¬+Fo{™¤Rr¡`Ð�U|ÃŽþwJ±‹£Äæ§ÆQZ~J6aºÒð:Ox£7Áüo.³³�k ÝdüüPÄålÁ7©Ò��j,i ñ”T¨©ZÒCv‡–¼`tÈ<µå±ïÚî2ð÷S ÂyCi€„ÚÜ" Ÿ„�Y‰�dJ¼õ Pð<I­^d& †%’$»âeOÎ~râ$ÙdMb"¯üI«_ú“ˆ‰—®ÌOýI„ôR:˜<�OZl6L—¥›p2ð=�ç‹$ÂXþlâC6PšveÎqpm“y„à0^»î ã÷}TÓ]OêDç7¤j÷°ˆ·ÜÄ>lµ$ü åZ^#U,°o*´óW´v80OÌÊPÂc��¶>ªèäy”| X’D$,ÞHA[©—ªÜ,j°��6?•ßFª8ݪªu"g¥é*{ö ó'Ó(1«ô� •Œ¹6Äï&‰2“ÿ‰\ÝÕlK§l"¤…ab]—EY–lmóRÇ2ñŸÖ}óôÅü-háp²Nò]Æ/ló}ÜÔû—òO�y·;B}™š�JBI�.fÈÿ— Ö¨U ÆdÕ0i¾¤~qèúã¤Ã ìáBŽ_|†ËÅÓc=Á%JˆÜ„ã)& —Ùc["SQì²?•¼þ•€-Aé{0ùäÀa³�—Ãl‰Åµ¬LR�›Û¤àŽs)`Mät"–<TwÍ�ÊòŸOøR·« K½Ð'ZO E“ø ¹…–Igò÷¢Ìùø¯—HXåS#3'Ð ëêÓ¥‹¶šþʘ¾“X“Û…ÿäÁRÏÿÝ� ¥çˆÎ&5˜Ytˆ_(Þ‘šM·ÙA«óOÊ=òÜZ‘±ەØn;rˆÅúQ9ÄbÉðÃ^ò_ˆEÖ~ Kx?·†�?|ç”_žsü߬ªNgTGŽ-7ÒLXÅF’[ø…±vsqB/«ê1DÈz€Ú³=o1 Ö4E'Pa³¹ß¬os_’Ý 9ËzÖþü‚*…ÿ#–îAãÊß RbëI£,6Ÿ�;ùÏò×—|«ó_&)¯¢$V[ÇâÃ*�^ü냯\S,UrPoå¬_’¾ •.3ò7k Mô ”`¯�­Bïžj§|b), cñ ä ‚s C_ÊTYüÓ/byß28+ø!9^Ž—3…­7hòÔ“ÉÐÑÛC'CtÁèÚÛÛWÿTy³Ö endstream endobj 75 0 obj <</Producer(GPL Ghostscript 9.19)/CreationDate(D:20170131180940-05'00')/ModDate(D:20170131180940-05'00')/Title(figures/queues.fig)/Creator(fig2dev Version 3.2 Patchlevel 5d)/Author(Bharath@Bharaths-MacBook-Pro.local \(Bharath Kumar Reddy\))>> endobj 76 0 obj <</Type/ExtGState/OPM 1>> endobj 77 0 obj <</BaseFont/IJUPVV+Times-Bold/FontDescriptor 82 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 0 0 0 0 250 0 0 278 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 722 667 722 722 667 611 0 0 389 0 778 667 0 722 0 611 0 722 556 0 722 0 0 0 0 0 0 0 0 0 0 0 500 0 444 556 444 0 500 556 278 0 556 278 833 556 500 556 0 444 389 333 556 500 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 78 0 obj <</BaseFont/UMLCRX+Times-Italic/FontDescriptor 83 0 R/Type/Font/FirstChar 70/LastChar 117/Widths[611 0 0 333 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 444 0 500 0 0 0 0 0 0 500 500 500 0 389 389 278 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 79 0 obj <</BaseFont/YJRYKM+Times-Roman/FontDescriptor 84 0 R/Type/Font/FirstChar 32/LastChar 84/Widths[250 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 722 0 0 0 0 0 0 0 0 0 0 0 611]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 82 0 obj <</Type/FontDescriptor/FontName/IJUPVV+Times-Bold/FontBBox[-21 -202 806 678]/Flags 32/Ascent 678/CapHeight 678/Descent -202/ItalicAngle 0/StemV 120/MissingWidth 250/XHeight 463/CharSet(/A/B/C/D/E/F/I/K/L/N/P/R/S/U/a/c/comma/d/e/g/h/i/k/l/m/n/o/p/r/s/slash/space/t/u/v/y)/FontFile3 85 0 R>> endobj 83 0 obj <</Type/FontDescriptor/FontName/UMLCRX+Times-Italic/FontBBox[-72 -209 629 662]/Flags 32/Ascent 662/CapHeight 662/Descent -209/ItalicAngle 0/StemV 94/MissingWidth 250/XHeight 448/CharSet(/F/I/e/g/n/o/p/r/s/t/u)/FontFile3 86 0 R>> endobj 84 0 obj <</Type/FontDescriptor/FontName/YJRYKM+Times-Roman/FontBBox[0 0 702 662]/Flags 65568/Ascent 662/CapHeight 662/Descent 0/ItalicAngle 0/StemV 105/MissingWidth 250/CharSet(/H/T/space)/FontFile3 87 0 R>> endobj 85 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 3609>>stream xœuWyTS׺?1�sTL•Ü( Mx8ô:Ôáéµ­Š ˆ80 Æ’`&B˜²“�æ� „Á0(" (‚u¨óXímõÞª·¯Kßíkë½}í>¬Í]ëí ½¯w½õVþIÎÙùö·¿ß÷}¿Í <¦ cúAaº@üa`¦(Ñýs=—AÏ›B¿ÏÌCÑãçÇ7x/&ðòèŸ÷^«7ìŸÓÞƒA3 &ƒ±õ¨h[f–<G˜œ"ñÿý¡ðˆÅK—.ûß'ÿ¾rÕÿxù¯oü· ÄÂä ÿEøKž@”™•.È�ì¦ÇçŠýÃ3Óã2ü÷f®÷ñ$ sÓÿï ‚ lÍÌÜ–µ=(g‡X’»;/.8Dž�¸W–œ.<�vH”¾l…?AûˆùD±€ØO,$ˆˆƒÄ!â0±„ˆ ‰ećÄQb;D¬ v«ˆ]Änb5±‡XC„k‰Pb/1ƒ˜I0ˆ…ƒH&ž01¦L›¢šò’Êlö˜â¡õøÔ3Àó¸ç�këéC:É©êêÔ…SÍÓ§�™¾vz©—¿Wí bÆÊOÙóØ«Ùk¡‰=žìpëú;c|““ 4u‡á{(ƒ®ñÉd¡ô‰ž¤jåq­¯s’ûËs«A¨µ¶ÛGêû|`«{sM2ÈR•VXZ Ôze%†É <Á}µ? ­'›¾ì4ûã+8Î…ó˜´ËÉM6ªê }äóÈKöÅf‡%ñž }rPgÕâ(4@êã µ±:Nã$SÊUõà4ëIP^QUUéhvÖ4ª§!ëiI}’êDš{ç|’=¾tÒ?œô† ¸ .ƒkÑ\øÉÎ�–Ùð> n„ŒÇ�9$ïKé䧸RëvÖQœ7гgàì~oV]Fëx芘u·´QaŒ &2ȲH…z‡Ž‚%ð÷$‹óúÍÈaÿ¥ G?Ž9a;ǧµ§êjÏð8otÆ-_˜–‰¼JùlºTé¢ÿàb¸à¸.`Âr:�‹f-]€ü�ÿë â0ð}Èûð âð éÜ«M‡ÐÐRYdø~éEü§-�£×ù˜Ùyú]ŒËp+sœsÃ÷Š$G¥QQ&ØöödŒfŒ©‚({ó8mx@ž4À´¤öl¥œPžÍR¤h ¤@ ”幕œÇª� E Eh ŠFÑp> €±ÐãÞ)Hü€“¾¤ú”f^f<Å­† ™ðÚÅÝoÌoÔß§ �<Õªd~õ7¸¾ø 1„¹á"þý·”Uâ© ©O(ÔF¹)³“›é^.¨¨´ÕÔ69šÝ\�µ„¡ß!vÖþð´Ì–^…û„ ‡~ÕÍøÞÑ 71³á-L†ÿ†E cÐ<ÈFR>³n7) QÔ„”1ÙÒƒz êèûÜ–¦ê¾‡ÓvöðÚ"ë¶�u`¹ì£´˜Ô¨ã¹Á€ŠQ՞㻵ࢿëf`-¬f¶Œ{sÃl„RTD‰é‡dŒõÌb‰vK3S2£“ŸØ¨yÍ �¿€³‚Ä¢Zá‹–y$&((#{k+Gáê B4»•ç„G&n²ØtVùF;ã%V8vrÃLêp“‚¡ähû@W¥U§¨æ5e×k[ÕÛÚ~æ\jWTdŠx×qþ3*!Ïר “²O(PÇáÄ`-ɦ!Žù3ΟÀù7Oæ�‘ø5M�êŸ�äj“¼¦ì²;¯õ§uÈ à…˜%GBábL›Ô�ïÅo¯å ]<GNuN]Õ‚“ÃIû*»é•] ×÷pÞ2á·ðs. È%‹•EÅ*P´ÆfQUn¹P«÷ì[·§?úû8þýŒö ¢ÓsbvF�{™ÇËBk[YUÍK%°€Š²Ê—zDÓ¨ÿ¸y㛇‚�%ýü�Y­ ›ênwžikÓH<‡´Z^K±áKõCøÓ ㉴Ët$wÜ�à û(1&ø •=Š‘! ÷îžu=ë㉫¥…*øfiúøðÂ+ŒÏ%åí#vïoËN/Ý1À�3ªjÁ�FG$ä…’�!–B�dZšT“¨DEÓ(¾@!ó -Ö-äš‘È?�v×_¼Æ &ê�å·*(NÖ� ܺ|��IŒ>ÍtrËeõúQŠÎ cÛ##åD߉É%v…1Ò͉þˆL¹ÝMÝw¤» Ø´ } a ”U뀨KEùÛÑŸMðXa“¾Tø‚ú*‹Ód«�jAe²¹ÄRf)0†ÛàT4èÓÆ‚«h߯Ak…«Üw20½©ÓÛçC/8ùA¿9œ´ð·  ´´L_ |•:«�+ɯ·Ž"/ÄÜz$0¾E|öl{KO–™�WXUjÊÞn;Åã¼¾Úš½�¿�DSSŽÉ’sbÓ¥© ŽÚ7sûÊ�}äS^Õ‘fÙ0\õ½ý¸Y¢W¸Y"™K"]ÚÞw¥¿ÿ©Z“'6ÆiÜèäŠ j³º�Ñ, œrþÕŠ¡:-&¿Ò™Ë0 'Jt""¡�ÆGõ¶‡åøýs1yçŸòÖGžPïtËûk'¹Ãz¢V?BÁƒd›îD9�³h|�ZU”ªŸ:z¼ðÏ“­ßõ¶ÖǧÃn&+u³L$%$Ìߨ0yí�ŸŽ'�¬«ùÚ„7ü«˜¼]‚7|Ë]¤R³£÷ƒ[nîPÔ†NeÒ™ÿJ ¦LS˜» …ùÁÝÒ‹��«/¨«±¶ë�>¿%œ[Ö?I^~DþQ±H|µ…V« &¾Á Ê�™ê�Ø…ÉÙÙÉQ}iWz:ª›í<GsÓ™S¯á"ÚÏÇÖ_Ué*§pWQÞ¥g¹'!�I/û…›Ÿ­L�ÔÚC/ ß��7Gmu:µ…oÖ�ˆ§Ž5äžéom黾ûüZä·x @óþ²¾÷Åe×ã«<wµ\Ž·Ó>—±vÂ5î‚¢Û¸Ñ&\0ý}%I0"V�1ŠB;ɸ¡ôúh<3ˆ�8�ß“¥?�uÙF†ùÁäPm«ù:.‘ÈVOÎ:ü-äkTÒ\©F¨ñ58 z·]»ÚÝ)N®uwz¹½ÌŽ'ò ½qp' Ïâ'kk¥¼Qÿ�¢ù$®Ûà‰NÏvú \©­½U…ÉI“�tö<°ƒB—Hô½ÞÅ‹YM Q1|€šH$õûª ÂI€ÁàÓp•‹A@67ñxº<@Fƒô”¬S×]r› VÑŸâ3i½ÑöƒøD3Ö-AóÑügBöÓ �¯nóQÜÈ5Ái }# oa•ËLÙXŠw=ø¿{?á1õü˜Ù<>s²6WV–=¦àúºMƒ O;?_RÐsÅm´ž‡î‹Y÷ŠkÆ j"ˆÔïUæÅ—‚‚²‚2 Ñ÷¸-¶êî?uÇ„h’²ryiš.PnÝEwÒׯ´.ïî—› œ }’¿œÃÙEçÐ~Ü1Ä!9'm±™æÄ¹hêúàå)5"gߑӤ–}’•(�G@Bƒü–„âô…êÒ²ü§™pÝ‹Ñÿúã���#/İΠ0ƒv_ÐTck©®1pPœ«?ݽüMŸúdVŸóhóD(÷RÛ‰Ô¨C9KÖD· Ú+j:šùœe¡eÜᦤ+å)Ç�ËO½zÕxú<ÿ­µ›q›ªwÖ®ÕÉ” à,öLäóˆO7F$ËÂ#y°…IÈ!­¥{»‰ÒÿÏÛ™°·«r8~ãí ÜÞN‘VúÎÛ%½›‡Ó1»àFæx¤“+*‹¶�]>ךZkÚ[;ÚlgÁ9LÅÒh=³–Ô)�ÛÜT”j ¶à2‡Ï�ä–*mUÙ#ÜWÚHl7®{Â(ÖD ý‚ ,åu&‹¥ªÞŒgõ·½q B”‚´<~v~jÑ=žY�8 #\æ}.CóÝUô�Zð±MêzÐKÑSÝ',´¼çñºÂ-ÞPEr^ r|=7N(Œ‹íJ<×Ý58(ì‰s£(ëg»dvï‘_ N�ÃY‡'‡€ …dav‘NŽ]œÆ”‡+îK[´È‚é÷ݰÍ\; ©ü»¢ Î,á»ëXÌ–ýÇZ/$ó2O«ºóïS™¨¸ƒUÑVaµ+¨.uèÎç÷êÜ>ná÷_Ù�cž„tòÑ‚Ï?îËu‚ ¾7ú{ïõË’Oñº…õŽ`j’ÝÉÑL›Ým0IÂ:YÒPb.-/5¹Ý®y š…¼}è (XBv•Õå“ô&*ä"wSV9É(K± SЃlq¾F> b‹új”º,žÊ�d�¾Ø¤­AáÐæóýß[nZ)·÷½Àø;\  2Ç÷Œ/á¢41ë‹bGØN¡1-<¸M]{ úòà3ÒøE]íSÓÛr¯¨Z…‰FÏH°Ôqìzì°ð–üsðÜw ôõ¶>¯(x‡4|Vg»Qù–IÆ·õÀü‰ôùvÐGÑ_¢½²»Ì&7$M%Iž'“ü±ÇŸüËEÆýaŽŸwr“ ø2sö×ËLxRnH$/㦰%„€ØÁ>jòf3P\­vÛ ·ÅÓ¼µxj'™úV6nõ[l�µÕöz[E ÎÔKö»o6�J‘â¾Ù`¤R�*Û»¥f[Sm•Ãf«hÄnò×¥‰*e²{©’dCS‘]WzÃå÷æpb?CÛ¹ÐóÎÈ𜺟0v4-í(�ãˆ:)0[€ÁÌãİ1Ì­¶jÕ‚Ô„À>ÆFfŸ�‡úèø:îj:ñ�`ÏoX80[ÖDÇ¡ÐÀêœyÓ;Må&S¹¹Êdòò´YÛ,­Uåf“× ƒ› þŽ•[ endstream endobj 86 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 1605>>stream xœeTiP[×}BèñˆÛ¢Q,ÕŽžÒ´¶õ$&¶§ñ¸©±».bõ1†Hb‘„�I€„Ð.}z-# $aØà}!àÔÆÛı“ÖcÜq»­�Ô?Ú$“ÞG_¦í£�Ntæþøæ»÷~sΜs>–ž†q8œçÊÔríÚíºUÃ;K�Uô ½2�~�»�‘/>³˜Ãƒ,.d¥Y‰Ë²‘ö¨ê{Hú}ŒËáä×ê¶iš ­ uõ:ÉšŠÒÝ/çæþô�¼W×­—Ôþ{#yS®m¨k’¬b‹6¹JÓ¬–7éŠÔµz­¤T£®i’i^—ì””ÊëôªšVÉýÿ Ã2›4Í­Z�~»¼äX1V‚•a«±r¬Û…å`X!–ŲÃÒ±0öWŽ›ó$M›Æpp¿N==Îk@=Ëh�í}Y‚Îü ÍÍS–óÏÓZ”)(+°Z�@Ø¡H :G^Cò`*�‚¨hªùˆlÇŽ"fã�ÄŸ Uamsç™D¦Œ‹ÞCNh;x¼N‚ß±šA¼y|­�¤.|rãËfO��X ]N¥­‘|›Ùl.óÚ [Ä?$0½0’üâ·bŽ5I¯OrF>GŸsÑgt™ dÖÝ‹ÅùÌ3 !^›ÛõäöGcW¯‹oß:óæ‰ÏJ®lwµ ÎŽÖ•ä7ü¤ª�TTÈZ«�x[9uéîøãÙ;ä©«gÇα4|ˆ&ÏqèsoÑkÃ~^>D%Ì`«‚yIÁ[óÚÞ0Y«,Öj/aB²hF¥ß–wôÖáG#–¸û0èe”‡~�6.TOoÛ^©ü™”ûÊð÷�%ÊÓãñ1¯ê…(¡œõµ@¨×ïÿåé>Õ. 4íÑÔ±ãH8>OŽþæÚÌE K :7ÁA¢ç/£mñÓîM^�CzݽÝacØ•�b,>81Ñ‘Ðè4fM YSSSd’™Â9Ôì¡¶Z¬Þ­]"cF*ð‡�Hê6Xìµv5¹‘™á-£;ÿÛ£œÅ5‹9‚ï(>íîõõ;®`t�Á­s¶2Ï}W.49�%v–u$–! Â8D¨þÐðuÔ.<é†$œ„�/âŠ:Â�¬ÎFŸÕ©Œ»„wQwGoõ:·—yÃ+úYƒ©�àŒO4‰#þ c‰l>é³òlI/‹EdI’tÞpG"ûëOÏß[Î÷�¢5=³�Ãñ`oôà;á"ø*Çá¨'¾âá�¹{'ÛÎU]%åÓ¦q%Ž¥’“—Æä›#âÎ_™B/ò̸½Óá6³Îë¦ ½ìÏpK'Õ±bë¾ý…�ÉgÊÉ“{ãuÐDT©”ûËTgžšÅËиuýs‚ƒnÒ‚Mø{ß,©~QÐp‹½¸wƒÇãrÊöìÜÝ`oµ9œ`%œw3¶0&©] n‘>izwúØèŸoŠ-¡}; FˆlÎP?@ÈÇè1ï!¾ä·K»ß§…‰ì™´åþrþº‰ÍVEa§…Í–Ãì $?% 9Þ¼˜Yç0Uæüó9E{÷4®°€í À>¥Ó=T™Eá�:D�§}�}®^O¯ `wµv×Ë™ Ûó�` ƒ†©;¿¾Œv£L1�’áš õ?T ǧ‡‡þÂÆ =„ÄbZ‚|ùq_¬8Ô‚÷XûùÃ}“(‹®Ư…‚×ú|1!Óc¯Ûû ³ÇhWÿÛ!¬œŽÒnÖ±ÅÖ ´h˜sê¨ó6—Î@\ÁV©ÒĆ®T1u9FõEŽ“£´6‰°x$:£Ùˬf60›™µ›.•Ý¿³púãb¦å &ÿ4¿pˆä€Yר¡PªIy�Üøš~)«Œ<…¾H¢½§RÙÁ¹©û(÷†êwËùÿ õô+‚_ápQö f°±OÃ{åç¹»RMWšIi­¡´Ð¶™WíèhƒJâ­[Õß þÃëü°ò\Έ¸ú`K ¢DtøÝŠ_�8âí÷‚ÿÕ“§¿¿÷ ¹ä,Îÿ;3ËüM€8õS-PE”×nÞTuâæ‘à`lH<0xöhü@ù(Áÿ­¡_ÒV)ºªÛëIvaëë��ëG§¿¼úà6¹Ì0H¿Eµ)üè³ ™Ã==ö‘¬, ûCÇ endstream endobj 87 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 382>>stream xœcd`ab`ddä ÉÌM-Ö ÊÏMÌñU~H3þ�aú!ËÜÝý3è§k7s7ˆrBß¿{ñw``fdtŒÎuÎ/¨,ÊLÏ(QÐ ×ÔÖÖAˆš($UÂd\R‹3ÓóÔ€Œ²Ôœü‚ÜÔ¼¿ÌܤÒb°Õ ~ù– > A©é¥9‰E˜2 Ì! š ¦ Œ ,ŒŒ,å‡�}ïãû™Ö=ÿûîíß×Ïgüöñûá�Ìóľ¯šÇæ0±~z×eŽïIßÿgï2kj°mã¨�ʰCe~°÷\™:õÆ$Žy¿WU°ßh�ÚØãÈñ;ì÷áïaØdþ¸ÂLáûñ½{þ�7[¿OúÈü#bž¨eÝŒ®+?&dÿÎѹ jáoFŽÅl­ßíXÿœ`kýmǺ˜mÑwÆs¾³÷rüÓÁÖeÚÔhrÍv> jgþ›ú=n&ÛF®{ÜKúû'ôõƒ�ÏÆ óûû'MèïŸÊÃËÀ��|6²( endstream endobj 88 0 obj <</Font<</F39 35 0 R/F57 65 0 R/F38 34 0 R/F40 37 0 R/F8 89 0 R/F11 90 0 R>>/ProcSet[/PDF/Text]>> endobj 56 0 obj <</Type/Page/Contents[19 0 R 91 0 R 20 0 R]/Resources<</Font<</F39 35 0 R/F57 65 0 R/F38 34 0 R/F40 37 0 R/F8 89 0 R/F11 90 0 R/Xi3 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 91 0 obj <</Length 5104/Filter/FlateDecode>>stream xÚ¥[I—ÛÈ‘¾ëWðâgÔsB.@ã“Ú#y4›=Vyú îŠ‹x6–Vk~ýÄ–XXY²žu!™‰\cù""™ìžvÉîϯyþððêõ;S슸Èt¶{8íœÞ9•ĉq»‡ãîc4ž«»}š¨è±<|z껩=â{ý2USõÇ»=|}î뱸ÝSÇÏñNEž ôñóÿà öJÅEšòPÔãÝ^gE4v�w:‰¦‘_º¶ù”K¢ú$íÎòÍ�»ç×Cyð5õÀϪ-›êßíM–GïÛÐ †ép†z­£C×þ”$úiê˱îÚáŠM1/›œúîÂÍÂhMCÕsѵïÕ0ø¶e_…ÆÃ!úW粨<¦ËÔ”cu䂺å'/ˆkù$”_ŸsQÙJsü²ÇQ^¿KÝêDU®b% �ùx<5Óp憛£ßû–›9Žç¾*�¸ ë¿SIT~ÂߊK¦+?ÇŽŸ°$ƒÝÓ˱îÇ/LâÜ¥“�ùÏp Yâ¢ÏuSm¾Ûo¶)ã)Ôí,1Ïe'ò¹7,{÷÷o™:uýE ËáK{8÷]ÛMA'Ç•}œ6ŒCèDx7s8Ài˜‚A/LÑ�äÚOc+XA k³IýÍ�B5Ä,�ñ˜u²dÓ¾‹0 ùÔ—Ç©l@ž�ý±dìëçFªiçñ黺Ví·ì%ƒ æÊÊÆY•GM}©q¢HS/H´Óå¹Ù*¼—m·KújÿÂ8´tÒ;ÔÀÕcÙVð-�:ì«¡¦9R ÜW|ò  Ú¯€JýNhZê‹{hòµÐ‚¨D!Ëc§ / —ò7lóêíë_^)(Mvj§Ò"Ö¶Ø¥Egyº;\^}ü9Ù¡ŽM‘ï>SÓËNÇEŽ�5»¯þ‡UéVð2k“SW6^ÞªÀ ÌL¬ì,©×²//ÕH*V÷S*T³züB±W©‰ Ìr³ÇêDb »ß(:îd­jù4OÕ�N£Ït¸´ëeËöŽ nŽj‚"#+BÝÆš¶]+e·0"•Ò1Þc…]º£V¤øÁ¬Î¿ÑPX?¸�.Ý�J£_ñ‡ô'��<ÏÒf5;‹‚IMôà[ÔíXµ¨ðå5¨#¼ª#±Á<ç¢Æ«šR4Þ¡sp”zù¤¾\»daä×Í>c» Nš<~‘'YÆ~.G¥òµNJ—£‹©cä5³íœ_È ¿ç—¦jŸÆóÀ/¼Ë@´ÝÈD…ýÛµ©õHF¹�ý kÓ<ú·Ž¸Œ×³_�+|C\ÈÖßÙ$ºgÿL|j±{HxUd’”–‰e[Å’…©ð­^uØÑ…r㕾õV{®àá:°‚`s® `aþ°ˆ²!v„r:„ܾ4ê8µ/h&cck¼àƒóFlø\?eYœ'fgs'yþ}ú©ˆ]¡¡+çÐr6÷ùkBê)Íã¼(ê)UšÔ“KçõRg…Ú®6'€N@7fúë*9IâçéT¬Œù®%'Z(è º4öT2˜ç2??Ô_ÚF<”cQ„ç�•FL ¾n=4�ÏûBÅîlýgÝN¿¡nÐÑÿ¾ûÀèç‘©Ú?~ ŸTG€á&/¼Ú|KÂDTß�cS /ZPT `‘ZXM '�”R¢Õ¸²–fh~©¾ÀÔ.±ìi¾ÚSÝÆ`yô¤FPæ¬IY­™ñ ±ª;�ª~ˆG¤ŒŠS“ú3zßòW i £Çr¨\6Tãt…ó±¹Z¿Ù=3*:–Õ Òçr`‚‘È3îÒq⬟âf” ä‰À´­ŽUª—Æ^{a÷l‘*=WnF‚ý³±z£Qéh¾6b»e<Øu<]›»ðj`„DÏ:éõ±úõõ ø#$#ôȬ@ÿÃFèè­èö/8F.¾Žv(›FvÆHµÞî<îDÝÓÔàû’8ê èCwEq£78Ýjü\1´I=zM#vQú¶j¤â* ˆÃC®ßµ< H]½G9·–ä žÕp­5Ì-»vÀýå45\ ¢=o‰‹ —(b8]½@ÍÑOŽþF¿ïé÷~Uô6°›€gážóV®tÔ2Ø^9gÙ�.áÑÞÒ8oˆþ×Àh:‹ «žq…Iqg Âð î,lî@ŠVx$Å’Î6“_J~4ÝÈYkh,Ç’à¼öe‹@îòcªiÔåHÞ@&ê+a,0ŸrƵˆ(–Á>]^£M6†Î�OüQ‹¾ ì½…½Ÿyþ4µÁ/D[¹›y£….›]\›�ÏO´>"ìÃ’Gª¸€¢ß‘Üp(¼4ä»Ì- 1„¶›†�n‰·HHì!K™•¥¶“g_¶Ã‰X: ¦fáÁïFòî勺 "Ñõ¬É{¹ÔnVÓ8;TÕÜàs=ž; àÀ‹—\X.õ®‚ŸRdTÜ?T“ä�]ÉðØ4òOø $óž_ªø)&’¥”ʆ¬=�0xµ‹ÁÂ*2XÒ¼p,±u2e¤@]o¬¢7ªí±êYôËF2ˆÍ½d¤à,Tåì7ûÐ)*Ô+:R),ƒ¢‘g^4RtЯ KÁ©¸a-NÜ>0Ú³4Ö2�¶�mÛŠ H¦á¹° ¼Àùàä±£J&ˆªJþ¾'ýñ45eÏåžu�¾õ{„ٟȳ`L@¦À/Ã�#ÙÒŠe Ckü¸vè»õ\WËW,w@€� "®ÕbÐzi�>ŽAf?ö¬Ø\Î\‡ÀA©Y Ëp�ZÖ ¯¸NW¬$dï*çÅÍS=rsñäoÃP´š9¥�&«†C__G&ŽN–Σ÷'®”ö$3p†~d¬šûÈ á6.WT)1Æ ˆ0�plìô¬G >‡ëÊ�éÓ;­‹8×ß×uk°qØU¦=\ŸN_Á8FÇvF`àžœ»#ª€4,¬S/H‘Ø0ÆõqV H²IHr°ÅöÆ�ñ¡¼›¹jXŒÓß—À%óKŽøiÒ,dz3QÎ�W1Ž^Êˬg¨MçÛJ˜gk\¶�-o†3$~™‘Èàe–)r[ý°Hl5—�·1–u+”¹—™¿p‚Ì£AY^WJŽ@é|Ïa ¸{©J¿¡tB»`Tì„R…OG–q1ˆgÅÅcxŠŽg@0U„!‚F‚À•н-h‡,ÿ‡úR“ÆÃú¦{BGÉò*@‹âÉœ*Ar`ØÈÃòÍ®$žüg�^‰y¾)äÔ�•fŠ÷A\¾V(¯éÉ1”Ðû*ä4£»?x‚\œ�·÷_à%Ãhý�Ê#p���²Åó ;�3Ch1i°§å‘�’éL:¢2oé¥�íb¦Ê `�ÚlêáÂO[‘àMH š•+Y,æ\¥À‚¢I�pì=^ã”—îˆ6#Œ8{oq |ì�Jı�IúQÊù �b{k´$`Ð5IYác-Hj8¥Ä¡:³2Ï;ë¹PN×lB°P_¢¼s, ؕёaÛ¯�w™uÕXÑ Èº‡ETNcw)Çú ÞA•Oüs;pº޳f$Íõ’p‘ÉW^dÐJaÓ�ÂÎK*Û—Î åÒr\ù) êõ¡d¦MôæÄ�ö4õ=!‡)´òÐbޝ"6ÈL„AB߀ç†ôá\>I(S—ÒA/]”L(>žà:)D¯L¤öze“þˆˆ+å>¡vèp© W*š§qжÆX0ØŠ#¿424«nÒ’Ê™óÃþ¹ÓVÅz²d†×!`ž>žG`G²k}žAV9g–4«Ìe·Ù. Ç°H!ê3¹¸çÞ�`QS?ö%ðIF¢ Ú2zÓr Bž%·»xR6„Ýkx'/{õ˜ÌmèZº©Ú`]ÍÁy|®"‚÷œ½áܵ‘, &‹o"Ø/eYæTqš„âÆ±Qî«ÑScÒ8±ù.sÐ�ú8fäø±+åô·$´�0&ù³ˆ1or.yîH<VÂÊô.` P刞qjÓ�@B;I !I¼_ˆ@å¯*` “AP¶BïÔ„Ç[’ ÔÁ‰ŸpRAm°J1•Zˆî,|ö©XëÎÂÎ), �ÖÈWÝê« ˆQMj ^`ÏG¦Éƒ©xÿú/RykŽ¢`pKžª¶êån�aï ¿�€/”Ìú3­�žýà•5Ÿ•¸Õ¤Z–dΗ�jÉS�Ò3æeüöß›@˜Gw Á'û;•ü•JBÁLô.6(:…Ëb—Íì÷ŽúúË GþyœBc€èä‹¿ãÏ÷^ÐaÒ�éçøÐº¨å+¿xŒ4Ç)0%€)¯_Ñìvì1ÒÍ”„á¶�žÆ/W4žü2ûo@fåͼ�h4�i;~’‹ÜO×QÊç¾pLÏùáÐ~jgy±ÞPMª¾uCÍ:¾&³`ÈÄÌ£~‡38^r6)¼, ¹ÜU`PŠe’>�Êc-úh¶3I!F/a}ï—nyÒ·ÙŠ•ú4¼ý·VjPMÔ¼D?3 ~?C]DÞ@Tý‚ð'Z�ðZàö*7™E¾ÕT=Ÿ™Ê@µçóX/yÄqîÒ%8€éàÿÀ£››Å&½þ#çy øÃ|¯ )¹wDPŠüV(C«C_Ž fhRðßçøá<wL™™ùcŸ<äÖ[Ã_�¤Ö¤r`Ùûp³7Ÿ3»§n›VÇfmü†o�eÿãþÈw3;ýBchâAvÞ“¬˜`%Š”g5¤I7"�Kƒó$ÏWKÌR‘½�È‹÷C¯Á itØË–CJ™†üF΄ƒZõìÔb!£˜þSÓ VÄ+lœÄKd�}èâþ”ü@'Ì'¹ºi¾Šaæ¨UºM["Ŧ+¯ûPX)EzÖ³¯ëöõáÒù6¶KD 1™Ãó�nru‹Ô$(K8câ\&Ð[[EEÌ bññ)Á]?+~2¬kðø9à W/¼ØxlŠ^ߺ@fíšInœ¬˜Ù-ñ92Ù°|÷N8:|ê²\̓ym|NDR¨0Å"Ƹœ9Š\P² «I÷"õøað™³?/]™3*ñÉfT¤Ë<T²\š¤ù/ûsbðÇ;àÊú}�ß¹i@Àïy »˜ž³¬Ñ%Šá$�Ru�†3EŒ í?É‚�&g¹åÄDÇž3Ç÷aè7µŸ–8H }ªât‰ò…¡¹3±6)°µ�}4wY¬µ¡®2—ÝhŸÇH�›­øPÿ_åi"—x¶© £W±¾SæÍï‰&;R¤±MPo ¥Þ fƒÁ×|ßc?!?—þbËͬpƒjä7™›EÃ8)QpÃÓPêÒkEt´p[Å-�+1oº+EŒàƒRº$ñ 1Ö:A”;ŠÊâ݉ééÌK<Ý«´Ÿ´vߍޡܣK�CÎ.Úèõû§Ó Ñ¢\0-ö+¸÷4�óTÝ*i¿©¼<u³?Û,#Ö_ºãÄWn•®UÏÒøaSÍ»Ø|ë¹óW¥a金_8ÿÆô@¡ëÜëúàïAÓ�øq#¡Hu ge�US¯Nî…hAV±×nµ¥èR�’_Ä̘µg¼,y},ñ“ÕÚ'5bÒtÁÕ“CIñÒ³HÆ —‰B�¼ ¨ÑÁ‹Ó×nǬäÕ ¡™ä;L¬D†�yÂŒ³•ߎB]”;O�OÍû9 íÝ ¬¥‹�4Ÿ‡HíÈ3ë{P>…ýaà®9G§m¾NŒÂiëoq±IŒÚ¨°ù¼?dOü�Þƒ t!Zö�“ÐÞtâ‹ÄvN]ƒ.W–ÛMøP ó³ò"i#)ë€Ú8tÇJ¥'– ¼åB×éì'…l0ÔŠÅu~�PEÖüÌEköÁwÙž È Ì5Ý®-Hjg`/ø¨ó§‹ù8DÔ¡:r)�bG ˆµt†ö§Ž«ø>˜$­®MG8’æI‘k|"N¾JÁ‰ :tTýUOº·H(Ҽߨ*cN5žSÓŠŽùT,˜îY¡ÁÀ¥hHAø,�R@| ›ïÇqÙê2qæóªåµ†vç^Ö]Øoèšr¾)çï<ïx�HYko|ßܶ@½â/õnb�ë»&N¼ÞøSG&˜ †ãt`ý¨Š%s‡uóݬ�sÁò¶Â}ÃÂ’ Î5B,8Vûo<õíd"gOºÏH¸õ±¦;30÷{¾õÌVÁà6Q(ÔÐED$n TÈí—}³V¼\õæ¯ïƒÌñFl¡ü»Ç.+§R¿r’Ù^J»©áíš^ØêYªÃDÿÊR�š¡zX!zÓ¬×I£Ï ÿo¸�4ðþÒ á…VH{‘†.]ð¢�è8¾�¤3³$xoùpàzI­!IÂõ'xò·“Â<)¤~o‚,} Ã{ON?ÊÛ°öÉ(…ëËòÅ|k [ƒ­?ŒÝÄ÷2ü7Šh¹Ùöë|rçuxé–ê*ò¾  n˜,Ε^<êÚf`äÇŽ/2Ò¿rcÍŽ ”]ª±ç%ãø>ËÖ¿ûw{dsÂ2ÔÌ;Nó'BJ]Ù7NáÀbä¾bK›,ˆãkø”;+AÔHXù3ÿƒKyÀ¨ÅŒcn„Ç- O ›PìZBž`p¯e/‘lù/4}ìºO_¹‚V]6øëÕ¥K[ç†óûA±S9‹U=þ£ŽòÞÖ 8Y}úÄY!–<“¥â¨à6×üg¯l¼‰ÿ±ÍÃ`�ü×€ã»9þkḔ‚:Xz �‘|s(äÿx1Ê endstream endobj 89 0 obj <</Type/Font/Subtype/Type1/BaseFont/LRICUV+CMR10/FontDescriptor 92 0 R/FirstChar 40/LastChar 50/Widths 93 0 R>> endobj 90 0 obj <</Type/Font/Subtype/Type1/BaseFont/NIWRQN+CMMI10/FontDescriptor 94 0 R/FirstChar 78/LastChar 117/Widths 95 0 R>> endobj 96 0 obj <</Font<</F39 35 0 R/F38 34 0 R/F57 65 0 R/F8 89 0 R/F10 97 0 R/F7 98 0 R/F11 90 0 R/F40 37 0 R>>/ProcSet[/PDF/Text]>> endobj 57 0 obj <</Type/Page/Contents[5 0 R 99 0 R 6 0 R]/Resources<</Font<</F39 35 0 R/F38 34 0 R/F57 65 0 R/F8 89 0 R/F10 97 0 R/F7 98 0 R/F11 90 0 R/F40 37 0 R/Xi4 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 99 0 obj <</Length 4919/Filter/FlateDecode>>stream xÚ­[K“ä¶‘¾ëWôm«ÃS|{oÚ)¼–×O+|�t`Y]TW‘e>4jýúÍ/3ÁGZGlÄD˜� ‘�/31áÃËCøðíW¡þ~ýôÕÇo¢â¡ŠÔ¦OLJÌ>d& Â({xª~Ø=�êǽ-âݵOÒjù�†ºúð¸�ÂdW/�6ÇNz»kÝJktŸ˜ÚªîÏoMû"Ï?†¡=kß— ÿééhY{c‚"Idþ’©¼È,(²Ð`‘Æ&Ži(ùëã>µ»¿Ñ_³ûÄíÿ�ßY6f“ 4©{§¯ÿ9ÕÃHs'áîØõÒ(åçóX^�ƒ<Ì‹Dß7�6ÙýòhhÏC Óä«iöQÐ4{6Ée²ïºîuºžEÅI�f¹[ÔO=ó&N¢Ý™ß!ž&a´,=ÄöA>•d«O±)Ü·†± “ÐÒã›9 ¢ÄºÑthàýÞš$ˆãb{‡S}x¥Ã�’]sį)ë#E‡ãújpé×f‰Qû$�wŸ„oý›~¤¹èÈòþåfðIñ£ ‰)6OW§”»ò|îåX»GùikœÖyhÚ®ªµ»­¤Ñ×ãÔ·ú’È)S÷¾Éÿ95}]©´$4—rl:'äÝ�°¿>š�öÚÖgÚ}›Õz©·†æ¥Õ‡ft�v;q*˺‹Ô}<ÛµÓå¹î…H’\ž…,‹˜Ç¥»²ªúz¤·;Þô:ŽPß0öÓÁ»kbÆÄ` ü^êK‡3´q¾ƒˆ=¿ }|»Ö‡rI t„úåÔNú�A~_¦²/Û±ffâÅÎ7ñ3+]N"Ö�®"O'þH"'Χ;Ȱ•ÒæÂDGvx=¿ âÅ�̃ÄI…gzæˆl>²Vld�Hˆ!ÂÖÀÈõ,ƒåV%A$QjˆFKl›é™Y,g”Óç1gn�2bBÆb“™^²ÑH=J¥¾ý¬LÌÂX ��·Y;~ñž:më {±–Ò\V½�Lº«¦Z‡tò{*ûêÜ´¯Û&±¦ñ˜SÝ×ÄD}Å�–GÚ‡‘FñŒ¹l‹Û‹h¥üœÊá$­±|f«Ác*±:�&–ýòÉã˜ma¾6Zž­;­ S«j–$»@Îû'vj öÚb¯/^輦ÝÓwì˜ÄIÉß?óßï™þ7�mŽàªf¯�=Jâµ|Çb’…{{“�5öFkEê2Ç&j96Y±øj%�÷Åi¯{× @€ÊA®½HNÓM)—Ïk«9Æ ¤!¤�2“çâ@hÛÎ�3­=ôu9ð9Ó`¶†h�¼�Ì´‡Z^9Ð+#­Ñg*p±Ýu-ìD’'zP •žÊ 9?ãüÍê€þο忟˜þä; ,‹üKðt[ˆ D1äJ]söƒž_˜ßûÜÅãG᮪gÅVMÖ@*µÅ(<2£d(«Ÿ|Gâõ.Îm¾Q«.: 0ÛöêhV}wu/wòû[Ýw>dnAÑ7 ¤1Nè`ûG“ïjZž­.:aëÚúP“ ã ŠÓ{Ødf!ß­Ù63ˆ²“³wŸØJmUa/iÊø!MVø!]¼%5y«Ô/!‚hw‰–¡·<Žì£Ótxèz2n×®­ö~Û¯AïÎPˆ`Ó¢{Ô1L‡yôãt†[C7oS4-#éV†Þ @[>ìsxoÃX_`èXøxl–�¶w˜ñ[¦AZDÿ6'^ܨÏÀ°n “hî¡|´á¬KrrÖ\øÌ�ɾ™‚d~8ôÍudå£>àÐçÁÞܼ̌4¹ÿËdü½ÇW�alaÅE›b9H´× Â3  ~GV1´RéXj´é€•ʪ�Æ—¾k/V\!Yñ8  FùÅ^Ç:�~àpîhQ‹BË~­Óh:ÕB§ŽK‹ Ã�Àû¡=€Élš4²) h·«{zÌâ]_\h³‘ÌC�’‰6!i¾Qæ»o¾ÿüIZM �w©Ûqéù¢I:bâbׇ¦f“Ftk¯jî«úŠ8"l!¡Eü>Î{¡lËóÛÐpÐCHç�9ñBºÖ ÈÜÃýòÄÂÝAé¦È¢9+¿v½Záæ‚v)FÙìz2Ï[¡o˜Yø&ûL˜½a”°(d!Ø+ngbé·WÜÀý’¦Š­±jkhºš¬Z¥Æ8Óc!Â¥?¤à‰ù³JR¡¡ b�S9 MYL´�ü@5µÑ7ÁÉ•= ˆË—ZÉg'�›CÿŸ}ÂsÇiö�ò»r72KʪyƒáJ’+ì…ÔF2]®žn‘€<ì»j:0é¹”Ÿ‘%³ÛWćv ö0úFß—o"-_�ÐŒ%}±—hCLãjîEj ¦H+cþhmK^€c¸¾&@7�À 2HÌ5–$ Žˆ¢;! –�9yµótiýZ³ÌŸÄËü‘Ñù‰¸™?q!4ÁHE Ó*uÀø·>Ÿ¥%§ä\1„c^µÒ¸"S‹ef¤Ad©ÉÌì�¶ÔR.O=ÌŸ˜³(#ôŠãYÞpüÜÑŒ'ì�m¬‰mß4™( L6çi¬Œ0áCJ.˜¬129$iæ!"û¨óªËÍVc¯&3^ýƒñbª É ­¾ƒsº_‘L÷ÿ°ž9Uõë[}&K6ëiË–\‘f)ö&Ï‚¬ˆn¼Û õn½òÓ˜õòóÀĉ›Ú‡Nè{A¸Í'ëj"Tº!¥Æ¨gÂèÙüÎ-«¦X-‹î°ËìR¾¨â®‘�šT5ÁbúÎÒÅâI¿Ô§‚Âñ›Ë Ä/á h’Šñi)»D2Rm7½œ¤ÍŠ•sV§9H‚ivEÔêqºÂÇ!Ì€Zkf†ºÆúpâœ�~tv²^cÌž—S4y¢®d�_é9¾´¢nbUÄ‚—{36È8¦ â"ÙÈê6Û�-}X :>jšáÁŠhWc÷Ò—YÓ&ÿ)Ó›t6íè]{ŸAœÜÇló³±/[ 0[­A¨|„D³ÿ¨$±W³±çX“©}]oÞ÷…âlzŒxÎØ!Ú˜PìâØÈ÷Žò:ºXjè¼3ZðÄ£4sÇMƒpëlÓ�³�9;34¡âP#"Ÿ î¿ôšˆcŠ7j¶­ü”j0f7aˆÇ¥OHÈ ÄùqN߸ÐËlâ~æWàõ]’Da#/¼+jl nCç÷o‡ó$)ªÈšÚ¶Žchr–‚~Wþ%RE¿‚&¢(rhbŸ$)[¼œâ;ÁfØ:E‡Pbù¦¿�Ÿ%¼ý:¨û$d±v»7ž¸*ýHê"ÈÚR¤\³Ú R‰¤ü–‡R~të0œÌ­Ý+£X»$—©=4¿ùcœ#‚ N£‘«F1Iõm ¯ ¶0/ ÄùŸ›¯u DRëÞ£‹öùåVÀI½§V0ðm�]–‚L–,Èt­8¡�¶ìÉ¥YšÛ¸KŽ0EšñCjN oZ˜•Ä¥ÂW xb¡§,d²À†™³˜G‰Ãxö„ròL³eu‘ œêu³$(Â[F{NL¶¤äåÒ7 ™Ï#Èþ=˃æŸÅÓ•J,±•Q_ÃAƒˆÝk‹V1W/Ýïƒ�M`Ò(_ê–ÏõIrMç¸&&À,n*5Ù²EØ5Ù"Ó¥?§åO1ñÂÉÇJzÖÝ3úF>>Ò'?éqá#m›Ä„eé£q$y 9!2›<Éì òPâ''<áð�¾´™•üç(ê“¥ZÖ̲ݚÏÚ7ïýêÕ³”¥‘l 1àuÓ¸ªéëwŠD�õR>á²ázH´:ot õ‡�ËgŽb¹9¿£ÌB$šäZôØ�?ŠÙ~Ps®Œih9 tOϵ¸�jÎh\kUÙP£úyF?¨ÇœüÊóü97—fª|ÁË88éáÔ�•Î3 —þyÁVÂaÐà½|G)ˆÕ®4²ât>º> ÿäÁVkGéÃŒXà9“`P¤�9á™ÄóyyÏ fˆ0àcV…ƒä a+gµg³m²‚èÃ:DÏǾ»ÈHá‰TÙ¯¢n¯õ…™‡�´¤ÒØR'šõdxfHÛÞŸWJp–>[[#É�˜#+š£b0[ÑÏúöûÏ÷…Q{7rz6/Ñ£¸Ì…#>ðLy´”žs8Zò©8«"uÕ&ô÷ÍË … RûN–Rõ]&2�3‘Œ ã�DÖ«¡á0ƒ)d †Ëjx<w/Ò˜s�¦÷‚�£bÎNn>ú; ÁU+€“éü{F�ôŠ €<Û  Zá°éõ% ,”¶“÷.u9L=çÜ}•ÔU(uâ$*Râ�æÈW^…éÛL^ªH =e¯Ùt Ä�&› |¾/Ï@`Äå;Y¡Ù㯯 Àã?wÓ¸¤÷fþ %µ,ãý2JFá³$C5qŠã0 î/™,ŽÝ) B;ÎÃàWò¼YI^l}(S\Pxáp­JÏ|/³l­DÙpYõ‹~‡îRÏeèQª´¡~Ô ³@Ð"2!ÔRþdhÅÊä*ÖøEÎŒÙñjv·ÉsóÜ zËI Îȵ¿I�Äà>T~§f3'Ô#ì¢Ä¨: ±ŸØ+*þ‹8%ÿ öNúþEª­HB2y”op~@_ôcÖ h~È? 3 £H€´yböï4Zߤ7i­bâ2F-ÉktpmÂ3ýwM;ýºp*º|�6ÖT_»FRÓ„;Ꙭf¸Èã&üIvòKXkÝJzAÀ<à gx!øqÖó)Èa‚šQ„ØÝý #]ëd®p!ÏÇê«ð¸øØj¢�Cw¹ž]š3¦p’«3äĉׯB!³Ú8ÌŽ¹œ3h[°žÍðÏz,)’�6ŠÃUu¾�ìÿÓ#ÅQîÜ1âTŸ¯¬R1Ô@T$âuÙ·Úí�:ŽRߨÁ�¨ÃÁ‚<Zl?õpÜ…†úݺGºKjy�œÖï]8Ù�Á²´ü}u¦‘µÛÜÌCôî TzLn²ò_N�HÞÜSƒ#ßÿZrütoŒAd·n(R˃ŽE·"½aƒ_Q’Ø]Çñ]¨h¹%ô^^~[ºŠrwS&·¢é­£\R@ûçr�«;ÑR„ÄõŽY¾”»;AÑ¿**Íòn$[�;ñkQš{m‡+ù<VÚÜq!—ÌxÓ×ú^Ûy¯�~¿Ô7wdÝ{Yò~†wŸ ªß-0æ�Écùt¬åÅ¿Ôã©«:Ò©·wª…i` »Žœ­Ü’†BA¤Ïba*é�NÓb˜æ$‰xcˆÜE"4ÞH±ô›Â#4„¼»×tîâ*ÒP'mwWr�Ío¢ß|Üç6�-É+†PlTR0„û YÄ÷,üÕî Å~Ã+19ïRÃõÜ$±–¤ZÅý2�Çf�0¥¬ÄMš0³»?µÒÍ*ŽÆU‘´ó¾ ó•%À�”’HcëÆÝŒ Ö<DY¦|ÑÅËD¦ZY?ÖŽ«~‡íëýÏSõ¢eù  #H»BR?R|QÃtÑb?A™Q5ƒ<_»Ž÷‡‘^CìÜJÉÍ7Jª„¶¥á�›Š0º~ô†~r%N](]¤Ì¢¥>«Ñ’Ö¥ät*µ¶B»\$,¤tªy’Íþ\¸º+ú*ÁÕ*2¨, h\V Èð¿N³8Ý%zŽF£"KTŽ^_·¸ ~6¦¹H¶è\î¶ÊDíA.å¦.’ÄÍ ¹Q›R$=0)83áå,ôýeZ.MDj¶è·kkuRËMóoîs2 çÈ]ÃzÃ…„A_qŠýn1ǃ‹‰3ÜŠcXWeF Æ –F‡øÜx{ R·•Ã+ÍpÄŽ%qâÊ‹w€Fï¤ØÖ~µüN-b܆G¤ÈÎÉvL¶Ð…în çDnpÅ*wËnš Þýë¹0´ñá|SW’oR¤çò°†T“ÝÁßçõÍ”û)_»€˜4ív+þÛe6È­½ ˜ðúZ~™ UŒhãR¦q.÷¹om£R½�°1WÛÀ,¦¸î‹âþksXnð"ß%Ü“ÎÛ=ya®ý�™  `hxõô$·*˜~įƒ´†Ë rC©Þ÷gNÅášSiäsÚRTÍ{ÛËDs=u^í\ÆÅ ¢ä&�Sƒ‡rUwS\^f³‚$¢tŽmqu Gðz¾&Ìä …³ *ì’äæ:M‚:¼´ÚN~/åψp¶N|,+²[w˜�€%[áž½7ô>rèñ=öeI—ÿü¡FÂms»lC±uvÇBÇ&Ìõ»lÊéœòüŽMn+E$·9ýãð×ëè;Mdi~ÃA\ÑËIÒ1ƒ�Ù@‚ªL¤Ö�·sŽ ƒ%Ë£ÞœçœÎ^§Ü&�‰¸B€D§õAbR«ÿ_nKN$%šoà ½d)!UKSóžyÔ�àÿç›;Þƒ(÷FÑýI¢ÛÿÀ¤º°'dçuBI¨Wbâ$YÃ><2ì“f3È/þß ûejwí¢Z(×{ìò•Kùks™.òpWL[Y#Þ„\¾uHzf‰]n�,K°ó½íJ÷Ç®1WÙ˜�·`óéé«ÿÅž² endstream endobj 97 0 obj <</Type/Font/Subtype/Type1/BaseFont/GINCXO+CMMI7/FontDescriptor 100 0 R/FirstChar 78/LastChar 78/Widths 101 0 R>> endobj 98 0 obj <</Type/Font/Subtype/Type1/BaseFont/IPECWW+CMR7/FontDescriptor 102 0 R/FirstChar 43/LastChar 51/Widths 103 0 R>> endobj 104 0 obj <</Font<</F39 35 0 R/F57 65 0 R/F38 34 0 R/F70 105 0 R/F40 37 0 R/F72 106 0 R>>/ProcSet[/PDF/Text]>> endobj 58 0 obj <</Type/Page/Contents[29 0 R 107 0 R 30 0 R]/Resources<</Font<</F39 35 0 R/F57 65 0 R/F38 34 0 R/F70 105 0 R/F40 37 0 R/F72 106 0 R/Xi5 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 41 0 R>> endobj 107 0 obj <</Length 5193/Filter/FlateDecode>>stream xÚ­;Û–Û¸‘ïþ åÌñYvbq€ ÈÉÓ8n;“dÖ³nç${<~ (t73©�T·Û_Ÿº€WAv²³/"X�q)Ô½JÑænmÞ<‹Üóåûgß¾VÙ& ³D&›÷·#7FDa¤Ìæý~ó!2ýsùòj+•~ŽttõñýŸ¾}­ÍìeB)`:È?á�g×ïŸýóB£�ØiBÓÄ&.Ï>|Œ6{èûÓ& U–niäa#Ã,Í Umnžýoo±–PQhd¶Üãc[ö–7¶8‹’¡”Ù°³cÞæÛÛŽ!~'Š#:‘Âw>ੳ-·ö¹=45·ÛSÝáì›m…™N7[!à©yÚG¥qÐß[nNU_nûûÖæ{»w°foaI Z2vK¦:èŽUY”W"¨ïPvüI^ôå•ÔÁþäý0ÓmÓÒ^¢å.òª‚é34GÛæ}ÙÀ–á]]º³D†I$ÔÐ&¬çÞŒ£$Ù$i*øð×\œ‰ÃHÇ4�¯‹(òÜ›Ta&FŠzáÛ~h`®¯ì^Æ"©úÿؽŒã�±Üý%²“Y˜¦é´ým,Ó ¯÷žsle$-Ùò2/^G”†q\*ØÍ¯¹X/Ö’¦Àó̻̓÷<&ŒLrÆFqxµÕB»J£�è_‰4¨ìmÏ-&Ja‚˜£e¾e~J’PË?áÌ@ê:¢ç'|\¶ÜÜÛÛ+=Àb `î¨NÖ}CÜÏ,É­¢©Ž"ywrlº¦³"3Å@RoáoWFMûKÕäûqü#:¥Á#ïñð \³J‚®om×adHy‹»»µ­­{¡èxdsË ×½¹v�£C‹›~�ÇÕ0R"&jÀáö§¢ ø”€¯¦mNw÷ y�2ã�×@QüÍ=\A±õIÀ}ù™ÖAª�uðˆßDp,[Ù‚d¾åøÐÁ®ü ý=7èTð|ÄkPøÝÕ6‘28”ÞE‹p§ŒâSaã� wAÛöù>ïóíj Áʺ·uçĤÐ�¥�âiT^u�oM‹£?jÊÜ žK¥*x,‘h°•ãC`oÐæõ�kâñù÷oyTW~ÆK¥ïj7�ù•Œ‚å�“QVÛªì°W-€]¦íW@mÛ ø‰H*ßU–ÇH|H þ®hËQ@‰½°±@6ƒú{àÏÁéÀ«‡cÕàgOvk&Y6’1vw%ô—·OüFªM™,�tÔ}‰ìT8jÄnFH4nÃ{ËnoÒHæQ¸Ö˜�èù:z?:((c×Íãè¾ 6 Øz,I[Bß¡F=]@cçÒUF:”‰ø´­}Êf;ŒZŠà®q)2R¹Ô�"Ø7Ÿ>J%HßQÙú¤¨ E4îeœŸ©yåÕs*„ƒ�ðí_ FJÏæEÕÚù¦Ü‚J Ól%u[ÿÔédÙñÔiÊzÏ;w ‚+?(þƒ9 Ø/MºÕñ%e ƈ•þÞV~$›,=›ƒÆbQç6 v±DÀ{¢q”— À- K²h›V1ÑüVL˜ÅãNþÛ·Õ0ÊÆ T<xР÷G¥:x±Ž0a<?z×r$�[Ï2¨î‰0O;ÐOÀ;™óë\Œ8L�%fÒx)¾jÐßh=' ›s43elXÞ�¹5^ª�ÚªÏK6¦×GÕ¤Ù §«£�iL8%ç•üØbŒ½ÂÞŠõÃRÊ%% x«ˆ•I€�º£MqÒOW‰PhÎFÃGGôá'‚J€„°ëÉÍ M�’´Ô“´d(šé6¼ _xÕ2Íš¦>vdH�jHØ„û<'‘ xRê/‹šd$×…6aG…ÖÉ�—¢äÎk†âÖ˜TÀ€ŠÓ•Ñ2œ;¬%ðÙ—Ë­²æçL¶Oh®Ÿ×&‹F\ã�Ä5A0�[Áæ�Wõ”´m ¤‰Ú íÅ:¯ž>[.ì#WÀs¹‡Ž?u&‚$#óK÷éú&e Às@0êúl²�±ëX¿`/YZÆ�¥àîD–$)ÞÒó­æöiû‘ÆÐuSžjàÕÉgUK$ÐØ>ß•6h rßÙýZöRcô‰ý$ ¹R gš·%y®ð¾³ý£µ5¿¤ü { 2Â'Úˆõ©f@3°smÞ*4Æk9·¯†û¦ûBM³à¥-r²$�™on^uÜÊ[jÚ=9ÔF–¬ò»ºìO{7„]ŽŒc?s’Ý™à�¯^ud7§y"¸¹†¨z×Ft>º®¹uÍw�X�à/ÝùW% n´mxÎ$Jæ¬ê>¹œ~»Ë;^':£o�2Íèt H5Ÿècôª^—•Ý�štNÖ!áäBE�2�×ÖðóÎÖè»XçÓ¡Í*gâoácù|²”—¾wšW¸Mò9NGŸw&¢¬€1¸Á~± rìíÑ¢™ÇÌ}¶Àó½Í‘ÎJ�ú`)� GÆÑ#º>GKHqÎÏ¢ïTqUOÌ58¶oÚüÎ~‡<”ÎéŠ>Û[/9?”¹0Â]YCô ïx´ÿºÒ: ~�d×ÜÙà`'Vï-aŒ¡™Ê‚P¤[À‰�ÏïÝÅÜW’À,±ÕóUòKÑ8nfÆÓâ ޤ<ŸE:fÃçä%_t˜Hâ)¥×ßñ1H�× \Ç�¨Bol~wEá2î¼áÛ{(#ôŸC¤T¥ ¶ßýô£WáŠ8yóÒÅè2çNÊLÑš�Nb�®ù ¥bøß¥Þþ8yÁcdñd!÷¼lØ \/ºÄ�ŒA<à½H�‚Í„d�Îâ~€ð´ƒ,7Ù9+�=pÄ+K¬?1YØözg}+¿3Åo’¡ç}_Ö´�$îàñ¶ "Aèp^�ÿÝÒ]ðZkåæ�a½ùãgßBøé¯¼9 ë„%ÃaƒHÃ-q�ìÝ÷?2€ï‘4JY±cŒý$dðyï�ðö†�Ì[>j¢XÊu2Œâ7/—€¼(@"³ÐBx»µÜÅó¶‡Ó‘»ÈXÀh Y3·¼l4¨&KçrH3Ã:¾µDÙ2 þ�cñ<4üÌüå'ÇC[³G´^ñt¼k] Ú™@>ˆC Å@¦oh°¨ÄVUîÚ­1ŒL�!êž_¿Qi²»«8 Ø£BÑ«Ð[¥CÍ %�ÖÀÖõ§>æÖ!>bKà%„�\>šøÎö8·»'—nï†(â°ü<¦ät>È4´QÔ•N†²„B %™9•u/¼�!÷¹“§9¿?+!`ß''½Ü•wdƒ3u_÷a9_€9Õç=GŠVa9Eò ŒÒ®Dâ0‘»…IJ7vµ4—�X©r„El\@É÷CÞ³}aœ%…#FùŒÐ¹ôñY’Dx1PßaLfôžA­%Ö¥fŒ�mL!,�òÍáéRe¦�)’Ú ž|ÌÊsÁƒ5IfiÿÄSò  “¸g6;ŽztSìËo{Ïox§;}áªüó�ʺÙÛ¡Yb Æ…HôÇ�ƒc?¸°–-ÙQÂÞÌ-TÐM¥¼Ý󠋺~ÊÝd,\2Të[°—zÜ4ýHU`«¢ð3¶zàØ{ü2ÇìÃäó•qˆöØg¬bb‰×-ì±çw7…`ä ¿ ‘…"•³°Ø¶ÝoE¿¾PE*ÂDŒ£Q³&ÏQm¾ðçMÐX‹—»¾£´Ã5”ôÆ\Ò(Y6_Á¸Ø6õF�bš)w�õ³ílû`}Á­$ 嚘ì[Þ®ä@\…R$‘<¹3è+4D£àú�¤FubZ;_ o,�ó¸ÜÍk¼¼‘iØe�¯¨xÁÆ%ˆv ƒkìOH⸜ºž[9?Ž-¦ɆÀq}ÓTÜ�zŸ;Ôç²Úó€ÖæÕðe³÷’ô©@"•™¡ÝI `Ú7ýÓ‘c,Qæ&íyTݸFÎ Çå-9ðí-`2dµ…Žâ¨…¼Çäöð¤D Ü$*�RÆN_cøýZr�Ep`KÀÖ¥žÈå$GÒa$&ëzþÜÅÉå ¢955DÊÍ 9ó ™Û0�x¸Á5)Ñ£ã@‡jaÌ?”4ÿcÇcXøÁE_fDxŒgCž�8\ü JþÐ eHAÚûöTq»¬Y—°ôN`c¤8zc2Âaà[‡¾¥^Ù8ið&—ábEV†ü6ÅýWY¾Wø¢Céå3XYª,SÇ`ˆRb±Ÿ�ì`eœy±úÛ¶¨ð�ýx�ûÒ0¸vÌ�˜h�k$ °Š®šY{º>´Õ† vîEUÚv½ß¤Ì»SËQ–!üªÐ ¥$à‘øJ%$�o¨/�Ý·�-†Â°�Á��Ùn®Ý¯ó9øÔ´3쀗�•áF(¼Í6èàÜè(ŽŒ-V%0ò¦Ï‹_n;†‚s>¦¨|çž³Þ«tTÆ* ¾ï´ŸÑYâèÆÌéÆ1?(íc†‡™9¶ÚŒid¿ŒK.d,Ùy‰Õpšïð8/Dà.ÇHKYðÛT�/¢áB…± N„´ “½ƒÂCޱ AÏ�à­°e 5Ǿ<`8ÏÅ:’(L…^¾½›Q¡Ƴ•·ÇÞ·Š)LïÂÇ 6P[t{4pBÛvÏV õ’S3½€Íw¥f$/ä Á³Lÿ8 ãduŒ[÷ºÑàr-�B(RF^³¥ùt^°Ovò_¤(Y¢9W§*¿`þ�Lk«%ÇЦ—¯äšãoGGÄðEy�U9Q9Ú{„PY… ]X�§Á†cO-«éˆ<ðe"m=ÊjDóô3~¤x`w?a_@r×5Õ‰Â|Ù\ø8ÝÏŠ"3n+¤ß9ªb<è"�>C—g=žãŒ—ÎŽï«ü”I».¡Ò`ò<7¯–®-ð£Ñ+K+Ñ)µ)~‡í¢ÿ]“ĉæœÝ¾kZb?¥`c´>h®§‹þ¬;× @’t‰ÌËMXY#`ë–ÌlÁ6»ÎrÂ|�U¤>á˜66¡ð„8œJÇÞ´WèwÙÚ_8”¥££uy^\æ�·cªaäas$af@‹³Í®Á¤Và¸=þÎ'uÂXÉÍv6j:DYïËÂ9Þc¦’[Cî ÄÈ:!¾òϣѭCWoâ\.‰HUb�s¿¨h"wõú9÷ë!cýéRaÈ“ËÌ.9�µƒ1g ¥;™®'ÓT æ°þ¿Wè»�ýôè¯TSQº¾ !fª`qRS~Ñì¶ü[_Ù% Sóe$‹Ë ”sQ�¨ ßòç[Ðp‹Fúâ¨Ñ�t]GNTä“£.·=}·�fm"é. ›êy~‰†’Ð4»Ä2L“Ñ“|Ûâ`F¢gFTMu(Ï8ûe<kPk3rþæËx^=N<#z|R~Ù�òËÎäëè&N“³˜ôµèJ’Y¥³„�%áWGϱ²VÊà{¥‘áL-Q¶sFE²¨��FF\ázB3Qç;{¡z‡G-ÃŒa±¨]b8¬Íü{P©Ê9‚q^v¡¹—��d%`kA Ø[,o!»?AY�`ö6±E²‚.Df¬V¥)€T´JŒ ¾¯ú{®ìSj°¤UÆÄÜq›<40ˆ}ì�WÙE}š\¸i wR~Ìå–\ZÉÙï)&c ®;{�ƒ�@¾dí:Þ5”oÎí35Ö‹Bsgk‹‹p^ƒ\,Yôâˆ'6ÎÐÃzá¾?¹¯‰h“þÒÃá¬@°w3 ¤sa~¸:GlúÜp×sËÏ…Ÿï3´{á—Ö¹¶L#ûžUÙQœ ,›ÆðZ~9äA³Ã(׆C1(·l¨ò¤‚N{ÑXÅL‰“Á.3ؽØÓõyÛsó–lvN8¹^ÎëºdSßR•S5µËQfØÓ5>–SKhaÎH ßGóÈ%”ÇÄN»ïÆÚ`nØÁt#ïkÞƒ¨t�Ð.KÞ„Ñà¿%„E¶2 „')­³yÕ–7ù,ÃX�áÂ÷ O=6.B×&[,Í¢l‚ ǹ‚¤ƒ¡Ž²/„j_`)g:æÄÛ 0"§x°un#”nÚ§Aº§àÛ=çl…ûÂ:V ͩֈñE‹!_˜Ã*ööΕ³¿{söçMõàîûíȰâ7XY0ïm>œ¼<xþ. å7· VñnV±»Y<÷ë[Ld(“ä|‹HißÄz½ÅÀGy[7 Ó_ì¡? .¶ôÓ_fÄWéo´¹G_'œbtZdgt£Óe=~�Qçi˜W®<íƒË„�e­×F+×åU0 Sd®„¸îÇZ:�%Á5Õ¿Q¸ký/—Y6È“gÐà�Œ,·¼ÐóÛK&�£€’õzp´0¶VR²>SÇÐEõÑÖ˜0‰Ó3÷t(¹½½{â'“(¶ïËÊuº%)²Cµ\3ï¢ã!TáÆó|Q~²ÏAÁÐèùz¶¡Š�ÿåF_ Ù8U�òÓl2™q_—™“‘ƒ3ºÀÕ@g‚Ì)|‹'/(4ZWõ.©O§.N2ÔeakÍ*å &sŠÒX 5�] .X5‹Uµ«ü£'Ú5¨j‚8zO’hAvšH€�è-`Xþ£“2OüTèÝ`ƒ)[®:m¢lGf�àµL_àªèBnMxSk&¦BZc9­\��•ÿˆ.UöïIT·þ¨œ¾ø‚FÏþ}âüÁMåòÒXÕØõÜr×Bu ±’ký:iðx¥‚¨.46Sð*ŽSò[òCC“M}D ±«�Ÿw൲s‚½M]=}!Ó4U®VvË•÷®ºu•ö•ìª5˜CÀ~6rÇÚ×¾¡b<ì‰5ƒÎ‹‡}±;.Màø”Ì†?ƒ�ˆ3Ð ÛÝ—WÎ8ªâWXàûi�•�‹ú¬Œ¡ÌgR$I(T¶äÏqGCúë[Zf¦×<�úyà,ÑyýþÙ¿�a�� endstream endobj 105 0 obj <</Type/Font/Subtype/Type1/BaseFont/ZELEMN+NimbusMonL-ReguObli/FontDescriptor 108 0 R/FirstChar 45/LastChar 119/Widths 109 0 R/Encoding 44 0 R>> endobj 106 0 obj <</Type/Font/Subtype/Type1/BaseFont/HQFFHA+NimbusRomNo9L-MediItal/FontDescriptor 110 0 R/FirstChar 48/LastChar 118/Widths 111 0 R/Encoding 44 0 R>> endobj 112 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/diff-ops-reads/diff-ops-reads-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 113 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 114 0 R>>/Font<</R8 115 0 R>>>>/Length 8953/Filter/FlateDecode>>stream xœ­\M³dÅqÝ¿_ÑKˆÐ´ëûc)‡‘,KŒÂ É F`› L(üï}Îɺ·ò6ožÁÓýºîGeeež<™Y½…{¼þ¿þýäíÓ?|ÔoŸ}óTo{Ê÷qû×'ý~ûèçO­Õ[™ãöö©Ív·Ï_<}¼|ýÙÓ_Ÿ¢}^ÿ|òöö�¯qÃq›·×~²GÄ[­÷Š«îþúíÓ{·ðþëÿ|úàõÓoõ„^î}<þñ)ß÷æùžo=ÝGÕÍc»Ü<†8ÝÝ××pû2ðÖsܧÝ>Õ‡û§öÝùå‡Ü»àÕc²;—0n]Kð¯n_ÀíóÄ«ÇïÁžÐjÍ�!îð˸}j|ûÞ¡IüOB?©}?a´z?h}níÿœ—O ÷z ýöêüôÝcÜ{©ùÉþË÷øÅ¯ñú|…˜Z_o`äÀŠßTÿÀ¯>üð—¿ûÍ~…ÖÆñ úøc¿Bƒr>¼Â‡¿ùà×ç ¤Ðæ¹Ç—ù%R˜÷X®/ñÑ?ý§ý¥‡ýëË�ýeÞÓÃKüìW¿ûøŸ÷[Œ÷[¬/?ö[ŒyÏßů>øéÇœï‘SÏë-ìã�ü9Í{yЉŸðú§¯_tÝÿ3G31í°î¹ô|šú˘—^.¦õv° ¯h æ½·2 Ìù½Ïlvÿ×ß¾ýÓ›¯o_ýùö³ß}üÁ�o—Ð+®ˆwZÁO!©7ýöÍ7ÿýÍíï}ñÕg¢ÛÞŠ^n¯ò½ÛÐtþº^oçoxÿzéa³bm÷2Ú 3Òëñµ^ÿÏ_Þ|s¾Õñ¼þdæ–o°¡E÷�ü3Ìvijҽño¿/—÷_åÃ{9½ÿï¯ÿR»§ÛÄ”tI©ñ—¼ªêªWÇßÏѯRÛ—õF!¼:îkÏÒ"§À—‰sà+Ö£Ù½ÿôÇOþ볯¿úöËOoxëoßl£sûì)ç™dÖ+®™fn_¿yú3Öñ¿Ýþíöåøô¬ÖÐG<°€¿Z[g²Ï_¬Ïj÷Å9ʾ}ŽïðúsbèHR¢\0�ÓL!u¨ˆ.�Ž¤Î»•{ŠºyÂÓ _ jlJ ”X¶‘*VDcè˜ù\‰Ec ,iì³ß›žUåœâ,é>£†4à:-ÁÜ8¤…zÏx¿Ë Í1p*WõÇ©¹¶œï�/8àñŠfÛèм>5¤ASš$BoûÅ»'{î°R~â3†u›câ�Þ2ù‰O8sÈÔMÛê>¢ŸølýžýÄGJ÷0ýÄá(î­ø‰�îy¸‰ceò+ê'Þǽµ=ñjZKuL|†FˆDöÛwjÞÇOX®´¬K BL9:ùŽß^ÐIw=[ÎËlé#M0¶Æ¬oŸ?ŘMÆ1]�vVã”pAÄ\lW´;C(àÚ)Ž0$ð—’5¦B¥¨�0½�ËS¬°1à±j.’¨"—‰# äKÂ}P<A‰ç»¶PL]Ö,ºæi¸*ø·su1£@ÕšøCÒîHà õ1šc‰@³žø"7aæ�O –Ý&ža¡Y¯ÙS×¼{ ®ar3k „oßK‘l$�¹]h•ô¨35kà0·ƒ‹*fա̹i 64k@øÃdœq�[æCc°I1óÞ /æìãˆI5l-›8–›{©ã9HÆÈÎ7¶ˆùjV8{©ãAϸ>7Ö ©iR–ZÕà¹{–VX'N¼R½µšudî%ê;=*Ç ¬ám¸I4©7†­Ä]P¦!¸ˆ{ r³i9ö1F·€'ݦâª�å,سڬ@‰�{ P×}ý¡C£bÇ»Óä(WzG¼N¡ ‘ŽöTø‰6 ¬1¸ªcVÜž6óŽ�Lt¡ ºM£‰ÂÆ·Í å�,øCiºGC¼•°–9W® Æ `?L®à0\ƒ«*¦”C7ÛG–M.°„ËÓqqêØ›QgÚš õîy�T2@ féâ˜ÐðtË´YI Õál9m¨ê½jJ“Ÿà�aú²ÝAÇbäÅšÕ¬2¸Ø+Øú1œÖ:ò%š™ \Ì÷D¤1@‰Þ˜s13Ãùµ”î;o�rÊ\GÊD‹ù¼¹IÐÿn;ê07X9 v›ˆo0¼¹‰ÄÍÝ™›]Îò[‡¹�!c(|š› õor¢§¹IPn{›enàS°½‹37�9î–œ¹ÉPe<™Ä>yÈenJŒk¤)Ömm Ô¿�ê¬M„‹»_¬M�&›í3cu÷eHÌØèq6%_Æ*Ýè·±©‰½;cW:Áml*´ê⌠b˜|7ö¬M….'{�embÁŸº36PWÀ”ጠ6<n7œµÁ«Ü{÷Ö†c¬‰/kÓ ËXWgm`©“ÓÚ4èp.ÅY˜±r7K²¬M‡.·4�µ‰ .ݬþ²6;@�è06P|bÜmk:÷¥�el`šçÝìÚ26úoªµl ôwëÎÖ X…næÑl …pî²5£èzw¶6¤Py¶­0W9'gk�~•gÛš +×bw¶è'rÓl[3a-gHÎØÀ‡jŸnc3»íåml°÷úšöalB QØÆ.]fà îóml€àÊÝlÖalBKÜçÛØ�ÁÉŠ9c&M�36ÀS²†ÞØÀµµ¸°×ECqK {%yRû%Ê.Ôz=ÿÓ ÈË]ÀÉÑóÅñeP!øÕ_?‡b`Ó@Ðt¤¦ž{@[`*y\-OC4› ȦÐÔa²h‰0”NÔf4)Á€ºW- T§PÆô¡y½$¼;,Ï`¬Ùì.4i]N4š]˜QJÐ�Ù¡z}š4øâˆ‹“î36ð~hÓ¦H¢­È‹Vƒ³K :^³D Á†‰Y~”p¦#À 6Ì6&»ÍÔè=áÃ9‹‡lM÷§liÔ¦Üh›ÂßôÐ�VøšSò{N¾…dÝè^¾GÍ^¾…32Çfòí±¯M¶ä[(yÙC¾D^Ñ`Õ’/ LÊÃÉ—ÀgoùV®“�È!_ÁÖ““oåj/ßO:Íû-ùÒÆ2ò%.åÃ�|!±Ü½| oùp'_&™¨C¾“nQä”ïÀ³Ë±Çüv ͶØ÷ Æ-˜?9T:t"ã"·H:â/o¾üô?¾üì…€¾sc¿# øÍoá½9€:.=¯8z~>úa‘ãÊéÛç;Œ¥k‘9;#Ý>l��5ùdšo[Œ ýQÜ ÝkA¯H—î§jCœ4€Õ“µ¿#M|S´Ž÷Wl> ŸBOg4Œ­hVqSŒßÅIÔ–äÛé¦ÅâÐl1ÕBŸ#`¦³u?bêA¦Àf5ãŠßÇÝÔ§”J'w‘mâGLMOg?âîANBoL@ˆ‚hkâ‹o4�`…"ñ#îîÐ:›øAJLò"ZéBt8ÆÈ@á+}üwP°þÝ¥" ©Ñ-UéCÀr/¡‚yØc©h´(¾½T<{©J™¶ çRU,Ì^*ZÎs©ªv•_ª’¢ çR ¿T… Ã/Uµíë–*Ø_—ŠX‹øä\ªLxýR0Oí¥‚Œ fÜRÕ¨�Ñ-C¢w·Tf”ÜRáF´*{© §_*Oš<îî�ÊssÞÙ1&ÏüðÂŽwÙÁ<§½¾ cLlØ8åM0™, kϘþÅâL%®·°8àf‚bj–,&n^Í¿@ö³hLeh ç]Ñ�14$6¦Ö#†®ˆ¡ºƒfQE6/D;5f0Œ†ŸUXÄ!„Ù „d¯3T ®Ç‹æˆæ¨°5Å…@1b‡3cè$|˜±–R± a“Œ´#æÌ‘a[½ æÊiw ;2ñ£Õ†TE&�†¤[D†ùºvWŒ‰ø“Ü!£/ Lˆ0†Qå3¼  ý Lî[Nl€¢À@ô�™Ð*ªÅ*6$EÅ7ƒv¤,Â¥˜Ë„P^‘"s|ôþÓ0qá¶±hÆø•Ì1Ü€¤oaR6¯Š­<ìQUÎ á²b nbF<uQMÐ2ÅI˜®DÓɫޑCióÔ;Íë�à×Uï°:T†­wäXð›Ó»D`Ú½ÞFóz— )ÔÍ­w4wˆ§¶ÞE†HÓë�`ÜðzSÈÀÊ鹿H¶Þ‘7rzG ×½Þ!hä´�ÞÉj\ô.2ÆNNïH©`ÖNï >FŠ[ïhêR÷z‡ÿ¸®Nïhꈱ¶ÞX ÌÚéY!ÌÚé]€¶F¯w9ɳ:½cJúæôŽÄQ÷z3÷‹ÞM¹y§wšÈHÛé]\pzÚŒ«Þ vl½Så «�ÞŽ¢àMÇùí(êùŸ^2ÈÇL ϱͱ}9‚& Û³ÈtoÄôK äM›k˜ŸW@×€DJ K ÄM‹Û‰PâÕÃÕõé Í�àŠ ’CW•²‡Ü€7¡´#ô‡ë'ù @�1ÈâZôÀÐV¨o�¶˜ T›ö6“kŠÆ @K;, ¨ˆò^pv(æV¡¹À]’åhà/�nÚÁ `Ö /Lj‘£9BŽ�²Â`T<ÐT¿6© iðšNB¶GH··éR¿#JᘤìK…œ�O�uH‹É¸E²""0oF)F„ÇähŽH†c°K¡úÄâMb‹t5£= ÁtbQ ³T¿emÍ#Øá˜ŒyƱÁÀh‡3��G>è ;ÝLT«2G@Dþ¨uQˆ¶57ÜqņÏhßĬÂEû˜ëŒNû„ ­óÚ—Å·9íŒ�º×¾†µÉkßÀZÁô8í# F =µo0|Nû*¡MqÚ7 7x¤Ó>²mÅk߀ö%¯}&êª}:.ÚWáÞcôÚ×1L×iÉ5¬óÖ¾Îy÷ÚG +æ´¯C°-{í«ðÝð…Nû:ö7VÃiÙJÌÛi_‡•ÈÅk_~*^û:Œ{òÚÇJ xA§}> Õi_š‹é¢}0À¾NûÈÁÒ2:íƒå†vÚG£½öÁóµì´OÆy›Ùy'’ý û¤â3Á Ÿ£Éi‡pPZü¸ˆq&W5�Ø|Q6�Ý’Q„ ½|=Ùô vÓ¯"aåЃK˜� Ýß²Á®jÄž¥ø$Òó-a½ðC/�!U”$‡@o˜°`F Ø£ê™5àr툠>eEQ–øbT8[2›ûjÊGàM“‚Ø•Zà2ò72÷ÝÔ8ÿ°Ê8<BL[yeb&†Šgî�c¦Ö?ÓùWtqÌ+qŸCä=bî!NÃ2Ätgz‚C’Ô1CˆfG2‘!³FMÌ ‡0þ�ÊN”ac bŒÜWƒc�WáÍ–ìm†q �lÖ”ö˜rͰÌ4Îbå98fh¯sŠ ƒÄ�² <M8 ‡z·4Gµ1 lê™ Á†C3‰p‹ÓoeA‘ÚÄ)­Ð,¢ZìCã,V¾„c� qSÏÒŒ²È¸±=¨Ê*[’ìeÚ¤3£Â1M&• ³·åâ ­pv¸Ûa@ÄBfTÌWÆ6gÒ…C¦ < IFYP¢6oD3*éb5xy žWb†c’Ü Q'C^ŽYA8Q|ÕRQZÉ3‡—·XÞr7aå"ÐÙV€±(�B~B§´Ê°ÜMµ·™ ŽüÇ0)’„:ÇBrFPP¤Q+Å€¨›W Ålߢ9V ˆ¬,'Q<c4m‹.¡Hmâý,s@ÉÆ,Úe¥‰8âŠ�<~›fC³fN$ߌ!fú4[ž(ؘE­\Ç@^t£Œ,«=ë`“¸Dšzeª6)—dIÝØæÏòMb›Ë|Xв�9˜?.‘´´±vÄNÃüÔâý”’­„(+^òòv‹õc�Œ aöyZFª-¯i¬ßÊZq “=ð£¸[³øJQé/ÖÒ¯ÍLw·´U1¯yð~–Úâ&„€ô(|Ûäã þ R{0>‘ù¥·ò‹ø³ü é ì+«kb7ðr\!#¶™½/–[ð¥t«ÿ±4™øñBɱ§ˆ�cUåt®�æN‰AvJ“- ÄÈé̤‰CW—yª^l'òs\ -UÇE˜:3iV¾8‰6³l›xöÀ©ÏFH¦×!íÏ©Sª6u¢'L]Ù6¥pâdÝ[?3r�aês–Ðd 9é_ÜÚÒX+#§%�-ˆ[[Y;Ž�ÀX™£Òo»O_Ü$nms§ÀX/£´�Ô @s_©=ŽÁUBù[ÁQi)TÍœ)–Ô(±§dFˆâL�äÆ,³Â'PüJ2 Aþ’Bµ™S^!¯äŸ†���3=È�k€"ÃVËö×iœ"WHjJi±2‡éA+  ½59WAÅwð .Š*9ð ³ÎÍá—4áÀYÒâð ÝutøïŸ 8üÂj?ÕÆø%�9Y=³ñ €¬ Ή_ Ϊª—¿àÅ¡ÒÆ/ªá Ñá,\aúwã—4XiÐ~��¿དྷj‚ ¿Àå6N{ã@ qãU²åÄ/PX-ÆÆ/ÐŒÁ”öÆ/Pü`5ÿ ¿DÊŠe/~I}H16~‰f½ñ ¶¡lã—HY5�_R¯ÒÓ�_¢ê�£Ã/° ŠC6~A<ÚUÌsà íš�_ éL|ã—Ô£v߯/°SuC'~�vDNüÄ/‘ÒšÅá—Ô†B´�_"¥5~I G9ñ¿DJkqµ†_Rc=Ípø%RZ,„:ñ <AÑF=ñKdÛIî¿À£n÷¿ÀéÕ\�ø%µØ4ï¿00àÛøÎ-ižø%RZÓã—TÇÐn>ñK¤´†Ã/‰ MÂ�_"…ÅB²¿@¥¦,ˉ_¼3ä?ñKª¥jâ'~ @êàÄ/€‘?ñ‹¸„”~I5v™Ë¿ˆ“`y܉_€hä­7~‰×ôø%•!Ÿ¿ñK¤¸`š6~Idœ8ó¿DŠ &nã—Ä4§~â16¬ú;ñK*¬ôøE̦¾ñ `c¢{ÛøE+ Oü‚Í=4÷¿ˆˆŠ¿�ÄÍüÀ/‘âb%ã�_�…ƒæ}â—Hi±öòÄ/)÷¦¢Ó¿DJ‹E“'~IÌ«rÞ'~?±ñKÊ¥kÞ'~ÏÇÍ¿ NÈš÷‰_Ä&�_RŽTF‡_Ä:bôÆ/[¨Ó¿DJ SßøáOÔÜOü)/Ì}ãÙ®¹Ÿø%Rbø´ñ ¢1lU‡_"Æ×¿$èÁçÆ/0-âE7~ApHËá𠬘®�_cMýÄ/CÅpmü‚!MS?ñK¤À ð�_òÒ:ü)0‚¹¿$X4‚ü�_"¦*á¿ ü–uÞø%R`Õ'~A¨?5÷¿À¡dÕ#Ÿø%2ÂH¿D5Ð4�_àlüS®Vù|â—äº6~‰”CŽ�_69ü)-=nüÂ(�_"¥ÅÈÏáqÑácœ Ï*ßO" ßAÖ¿ëÇ—Ø¡}‰ì[<ø!~< žl�+x"…Ö=aš(ÃéÓDn8º>±ä5xºK#4¼ Sl�ù£M˜Â, oÂiÈÄ�„)‚H¡á“0Å~LV½Søaá“0Å®–�Ý„i"ÕÙaš23YŽ0M$L»'L·Ìô„i"í:<]�½89íM˜ªZ)8º>±69yº^XXx¦0�1›0UASöt=L°ÀÐ&L!ÎÀyo†¼râ›0UÙSs„)¼›,7ašH�wO×'šÉééúÄìÌðt}bawðt=ПՄž„)„&À¹ SOEO×C×g¾ Óg´�ag½h_UP·µ�Ák‰í+V໵�Apòt}*I!¦Ó>ÓÑÓõ—BÕ­}­Èoí+AïÖ¾½ž®O, ž^û´¯{íË=>h9†zѾ\Å;í#WQ<]}°µ�”Gòt}b«]öt½¨“èéz˜$‘Nû*}zº›L‡Ó>ˆÕ—½‰\$Qâ´¯&¢A§}€ë´úNûH,UO×öˆ¶ñÚó\<]Ï)úÇkìsòt=¬˜h$¯}MXùJ×_ ­#ìYôóŽjÔgzÉ0ï }†tfR×—Ó8Û@gœVè(Ž”²uW<©�¾©¾…s00Ь2×mŽÉzø]?)ů¾ÆR!}±ú–¡×R|ç6£EWe©�˜w¦Búdå-l±H0ô‡ÝÁØÕÕa*„‹¾V“cX-ÂÒŠ¾jŸÛ¹Í1zïBM…“ÁsrÌœVßÂþ—ÕŒQ´�Îݥξ˜S¡ë📺U¸°Õful0ºÛ›#“bØõž £Ûuod2¬oQ…Ö ÙÜíÝ‘Év¸šÐ·V¬ìêF9f«paÿP3n@ÑÝÞ@sÃÕ�rH˾´C") +é·ûD@‡‰;Ó|Õ½9§æu�|sº‡s?zÝc0®—C÷r €‡×=ãµ;ÝËR¥xÝ á³Ó=”àmë¦a%.‡îå�Û5�´Ñ­Ä%že¸ä¬£×=2.[÷2ËÚÙ�°u�¡¸j\NÝ›Sö×écqÕ¸œºÇzfú·ef,®"—S÷fÊv–¹3‚/^÷&óÞ0÷�¬Èåн™û5‰>Tã²uo&98� ÀG¯{L¶³ŽËáFðý¢{Ì™ä .`Ÿ½î ¹mg˜‹«Èeë^Qñ`˜�™ý;«˜+�¸:óðï*cþú«OÞ|óÍË•ÌMáÇó•Ì¿]ÍÿílHp•ÌÍ*ëU½ÜT⿪š×�õ•úæZ“Ûh×]v.^[“É)][“¶Îµ5¹¥ùКÌÜþµ5¹…xmM澸¶&מZ“Ù¹xmM&‹smMfÂýÒš¬.­ÉÌ¥‡ÇÝÇø˜!i¾?[lúÌ/,оêËÎê&û²ŠMmØYlÈŠYu©²½ˆç¹[­ ,2O ûMr#Z’¶is²v¤„U!…­ÃjÌsÀÞZ ÕàK’ †„�eÊÉR¨7„,“€‚%#7dIy2"ê �´êª/Tùœ²˜ÝîÓå÷Y°a´«ËØÒ6�Î\=l a{‹±t¬d³# ŽJ¢lþší-ÆÊ²f®2ó|t抻¢ êìi(F[Èx(ßl•äÉÔ“¹VÞ/ãci[Ÿÿé¥å?.P&n·­/gi‡¹Ò¶‚+dS.P” ûƒÂÑÏ»êŽþ Ü2sO²?hµšÕjÁÓÑ ¤$éµ¼€lØN·Ûƒâ Âî h2oQʶ»ƒâ0‚CÝA&s¶Ý@æ»;HY5r“ôÇ«¯KÛvw�Rf¤éúW/{rŠkŠ“=9EíAÁŠ-9œ€álŠ“]9IíAÝê:{e%¦ëR‹­ÍŒéU�.Ø«é�yT5Á3�ùÏþòÂÚŸãEU탣֗£’†£v[~R#àÙ'�etmùI]€¾-?ƒèÚò³º�}[~4zеå“Þ›¾-?‘ùómùY=€¾-?©çÚòI ”K[>)¸viË/ÖèÚò³‘q»-¿X  kËÏÆ´¹¶üb-€®-ŸV¯^ÚòY.Ù|[~6ŠÌµå“É—¶|ráÒ–_é±.mù´zùÒ–ÏÆâÛòiôÚ¥-Ÿ�¤_Úòiõæ¥-¿µU%z´å“EO—¶|ª|i˧ի—¶|¸zi˧Õ¾-ŸXq\ÚòYc.mù�¥Ü¤®-Ÿ8+_Úò €Ë¥-Ÿù•æÛò‰´û¥-Ÿ‰œyiË×!—¶|ÕtiË×I#¾-ßNEs�ùŒ'ë¥1Ÿ™°~iÌg´8.�ùDùáÒ˜¯ãS.�ùŒ(²oÌ×),—Æ|&›oÌ·Ó\.�ùLZNߘŸBm¾-ŸÑnòmù‰¡Wº´å3–-¾-?1®ª—¶|æ{û¥-ŸUn÷å+ ¾-_øw›µ+m Cö</ñÌ/™Ác¸wœdqÛÅÜâØˆT7·{7kV_ÎîŽÍYq®;¶²–ýÒ›Q¸îXfÅÂ¥;Qåêºc&_ºcKT™šëŽmXÝvéŽ-EE°®;–•DóÒ[º*Ì\w,9‹ä»céõ›ïŽMtûåÒK·?}wl¢Ûï¾;–^?úîX ÁwÇjÝÏe¼D=ŠÇÞ™-xÇ�/-ÿ¾D¡ç<))|<À9èf)· L¦­=JÝ,¥Ó�©œ´C@©›¥ÜJÀ“²C@©ËNnÈ<÷§9”‡ƒG@0æÊ7n”†™É­9]{”è5›G@9*½ëP¢÷�e"€î$!;餣Áë�€`1ä`\‡t$¼~D@—õü»úw-†`kW\‘ï·ß¼ùúöéß¼ýêËgƒÞÚÊ;ƒÞ‡ßœzá‰ðYÁšðaúùɿՎuRÀ[W�­acÐŽxOß\o)ù¡�WQÃ͵è–Zt[lG‹î u™�º¶ßÒ®ö[ u¹�¯½µtŸùÒ8[Ywsiœ¥ÿ\�³+Ô­¬ï¹4ŲDe5ű.k‰,Î^'uÕ…¦|ðû¸ ~{¸lsþ>÷Ó÷X w¡Êx�¬¡>A°†œA0s ÝŠyòêùk*Á^Ío%­\`6IÀ‡†‡¾¶RWš/ªo]…çƒéÔݳV†%ñ¸©¬ª¨*Úµ£1¡¨ 7•â’Dh¾Ý¬–•~£Nè>Š0«o&ã™J­D&‹ì#À®QŒ™¾n¹¹­¦´ ú‚ÝÖÖA)5êLUi³ÊØuxµjBŸ:ÒFÁ}Sé�¡gÝa°[ÎkÜß•—xþ§ï£Ý;©þ“3¶/;î×ü@§çˆ#ÉLŸŸˆd!/¹‡H!_rBœ—¼‚ê[\^Axó’3PíÊ%gy(Â%%YìsI �Ê=Ðý‘…<º_ˆÓsù*(¹pùBœž^¬Á…§OlCö¼ÎûpðI]ÆûìùÑŸïpDÃýy4ÅuJç3ñ3¿|E8¯SÀ>gs}9#ãž]�I êf?ŽŒZ›çˆ•u±ªÉ�ó¢Ô¡¤¤+ÀLU•âÇyQÚ9ʺî�Dû<0J;‡‰V×÷‡K;}œ%VL ]×ׇN;}œ%VÌ£ÛM¹«6Û΋zk´O¯¾£0Û°Ï‹R³€Œžëµ ¬çyQo�öÉÉ÷QÐ Ž}`Ô[#~|�a*CŠxœõÖ˜Ÿ1}D�*r>΋Rå½àîöÚÁ¶Ï‹zkÌOi¾u�vpî£ÞóÓ‹ëK¨s¸ëGoM?΢;{hë>/ê­?9ú†ÚÁqž¥f4ñY®W Á“†}^”jÔEžº>�q™Ïó¢D‚;„ï,ñïøKÛF©ü|Ø!|G?�ga „�¥ÊrQ§®8Ÿ§v¦}^©«TíðÁ³ðž§î#£8D‡»’úÁLý>1J˜’!®\ž'r†}b늂¨SW Ï#9ó>1Šc²r<®Î�À¼í£TŸ¤l’«aŸM§_'F©J™+WŸNdžö‘QªºÊ®pKÀ¼ìó¢8 *·Ë²„Ìû>/Šcº²~»èJÈ<ìó¢hƒ‚2ŒUÛ¸=ÄÅ<ÀíÙ¸ø»?|cx\¦¼ûi ùqÇÇâ‚#†3ÕçëY}Ý|¾žAQ¿äâYY=/¹xŽ—<;ïèK 88_rè¼a¹äÐ9º]Rä¼aï×4¥Î�q)HÞ2\S�]ÇÞîü"ïxiÓL].ykÞ±]ü!‡wŸ“&˜ÈÑÁûÃÄ;ÆG¸—ó!>îõþîøøù¿�ìK-§|DÍ�;NîõŒ2wÔC]Ó2®‡.àå¡d®/ãzêB枺”à ³­§.dî¨K­Û�eÝš�¹Ÿ®ulc”k[ŽÌ]ŠÔ¦YVW{}(@ã1—´L0p-/›Ë¶îÀ‘‡Ò±¹Œë®OH¬}&· u +ü¯ŒœtÁ¯ëÖ…ÿÇÙá¿}ú_gõrq endstream endobj 116 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 117 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™k¬à’ÏÈ�JUˆ endstream endobj 118 0 obj <</Font<</F38 34 0 R/F57 65 0 R/F70 105 0 R/F39 35 0 R/F40 37 0 R/F72 106 0 R/F14 38 0 R>>/XObject<</Fm1 116 0 R>>/ProcSet[/PDF/Text]>> endobj 119 0 obj <</Type/Page/Contents[25 0 R 120 0 R 26 0 R]/Resources<</Font<</F38 34 0 R/F57 65 0 R/F70 105 0 R/F39 35 0 R/F40 37 0 R/F72 106 0 R/F14 38 0 R/Xi6 1 0 R>>/XObject<</Fm1 116 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 120 0 obj <</Length 4667/Filter/FlateDecode>>stream xÚÅ\[sÛF²~÷¯`U*µP­ˆÌ—“§øØòf³gm¥ö!›ˆ„$“ €V”_º§gÀ”‰Î–«„Á`.==__gh6»™±Ù»Wlðüí‡'›ñY*f)ÏãŒñÙbýê—_Ùl õŸ±XæÙìÞ´ZÏTÊb!”W³�¯þô�yžÏR–ʼn’��­YœëÜñúòÕ72›eqž$jvy=KóX0$‡Ç¹œ].g¿Dÿ>Ku´i>­6Åòl.4‹~,ÖåÙ¯—õöÒ£‚'IÌ4? <•0– èxS¶‹¦ºëªM½?¹J“X''™[e† yð¡l·«®ÝŸW+3)Ÿ1q¸ýÐ]=ÞýÉíOò4™žºv�Žl?c±NíÚÛò·y³œãÚ¿¹H™×Z¦q¢3Õ´û‘Zã%±Ì”kÐÝÎùõaÜ<“þ€¢7þ,a2÷Ân‰dGXSË–Àý¦?§²ðÆ© lØ–uW«ÕÕ`'*]7›5• Û¸ªoV%•ï ÝjµY]i›'ìÝk7«2>ˆçé<¡îÍ�çÃ;‹ð| á>—~i6gBG÷– _ñÿ‘d¿ÒœÊ…þtècw–%/ƒ~¦ã\d§€~’Á“ë�úR�t¥x »Ï# ؇݀)`;xæA^P„ E(¹Ôñ4tð‰@ׯgsÉXô¶XÜúsPco¶ª³ÂGíòr'sd r ‘›#r¹8º“‰ ¡ ÝS‘¿ º©< rÓ4Î@ž4õòÏQÚÏ"TgôŸFg7E½Ü¬ÿL}=•“@ï3hO]KD½`Ç ~*‘!è¡·L_æ©&‰ñ•'A=�6§¯ï›9 ´Ï›~\[ûóô`ÔkS(/ Ø•v«�“‡<Šû¦Ú5£G]šmž ÄÉKœ„DÑC$ ã9u 'SBº3®^EÍA¨’“@Që˜+@ñ×áyŒƒÑ§Àx=ÛG1çTçæD9ã6ðÞm�Ý0ù PØù Ç�w2;&×gÐpµîQ>ïd*CàB÷D¿ÐçU,Vùi|^%ã\ðÞs�à~yÏáyô�»þ¾„ëà I·ù2žÃdvL½Ϡ=܇Y&Çà~2•!î¡»È_è0‹D˜Ÿ÷RÄJX‡êºå6_Œ"_e±âS�ÿìŸGþ8ì}úO{òT¨¬è±®V+̹QÝ¡5pžëè3þ)Û©¨ñՊϲjÊE·i*4%`2g&I€Ï«¡ÈÔHÀQš2•¡ M‰—I�OA˜Oã= ³”û05žRžGþ¸øôŸHñ�D‰|Dö•ý—”�É<›$>÷dÃXuT`9™ÊP6 »Î^èγÄü4î<Ë㢠O6–åjL84×üDÂñ<úÇ…Ã_Ài„P>f6×ÿ á˜Ì³IÂásq(Êĺê¨\ãd*Cá€îB¤/�ë˜%ù)„CçY,u²Žy[6Ÿa"û™“�ƹÁìnvF÷g£‡–åz»ÚÁñÊ ;_•õâÖ†µÅʵÙÞ…¿`ìœ16ˆ†¡rúz§ 2à€C¥¥<ŽÓÉ à¨sgÉË<y kIùI<y�%qCv¬‹jõ4Ÿ7ù8ýÙÿéfÿÒpä±ÑÀOãròÂ'áÒgÅ—Ǥ§“âéà/ó¯5<¥V'ÁeªãDYÏê¾¼z–Ï›{–þäÿ>Ë�tW2Åó 9yñ“ é³cM} 4'“Bá¥õhšÅ(ß·Ãqt3f#Ù˳\DÅ•É@I0QÿC‡ºþ]óÁ8f"�îíV·TMg“¸eÕPq±iš3™Fe{·©—U}CÕ¶n»êh¤æLéhsOÇÈ*º�á5!ú¸,ºb^Õ]Y·ÕgK[?5ú•R�8P}y&Xôû]ÙTë²&Üa못¥’úáŒG¯Ïq€1sË`›âþá5Ž–Ëˆ‹¬/Óªrñ¾¦šï¿yO…¶úä°•ÌA$€w%µ¼«HÆ'”C´ÅE´eçu´Å =»Û¢£ÞWC,Ô-ŠJ×­Ã’"£zSχq  îR51¤4U‹ª-—–ÞË[K¬¹�L¡ IC¦,6«íÚŠ\¿—«Ýùlu[:w¾‡‰ýhÙ®ýývù|;¦9 â@r ³ð ®.àiÓYÚÞ_¡þ),.Si–d^ a ìé¸\v-¸ˆ•îã©�]±øtÝþåL먥aM×›b‰R™&°Ò»²^Ú¯muSW×&’›Í6@&Z‡ªZu‡¹_Åx„¤*&�oT±­—e³z0’�ïKs\ò¹Z”°Qi¢¢·ñM|N{v��½w/ýžá„ö %”Ê}ÜZÎuÜìhšúÁö¤;Ã{08’’§ŽMÔ¸½õú¦€Nª¾!øæc4î*yŠ‹(ß4ÅÒî&VšÕJžD?¾¡ƒS ‡H(`úzo”Ñ9ihäŸe¤ŒþöæMLU—´!(›Ý¶Ø5­Zz6´/dí@Œ�ŠG¥Ýh¿-k¢èƒö»-C·r_(M²X¨¥O8C°§ã渲â·5Š€’¾„Íí4sž˜¤ûr&AQ'cr¥zRΤkñ]Gc­Ê¢5ÅÄè¬ÚÔ%z�á×ŦF›³m %¤Âç`ã’, y[¬V°JèâZ°HTi“–ðÉ4# :±1¹Šƒbƒíü^íyõú†G"v�ЦÜ)K§Q;‚¹Þ1=1¥ß‘N-ëV‹4f<w-«¢µûn€o<±�SÍ ƒ« o£ØàŒA”÷8T–Fé8rp–òã•0 # ¨^•eÆõÀþÆá»Ñyvj޾“ávx'~Pß™�f�°p_"´d²Û-¬ß-.ó˜gùQÛ•Å\¨ÁváȤ¡`¶Ë�ž'i,ù`1´‡™ó �{ø-•¬nöÕ×h+ãÝØ°Y¿ˆ@kq î®ìÓz#WK™»� Ña3”…f¶û+=rqÔ6%Àe¸øs®�Ò}Xov ««zl{r¼îÑ«£÷ ö,À £Ï6º0Û!`¼Ù+° 9XîFe� t&8è`4‹�wýû8sœº‘5Ô1í]�LIRÒ�*É`ƒ· UZ�¿š'2ºØ6À®f½iJàžܺ$I݈"» Ó–…}’Wl±ÿèomÔxèÄ—(öˆÖI�ÎÙˆÖIx Òr¼IúÞŽuSÖeS¬€-©ô<�<0ˆMÁ惷l8ÔRûÏU[YÿTt"Bv]¡ë'EïŒ!7ð•d ë²+üg'¨ø=·^6,Àz¬Ç;vXãÁÓžSƒUTy"Áp¤¦v–Î$:L£>ÖÑÄavdŒ`‹Ô𾩌l¢€¢<|rϳ�@³\x7’V¾£Ô#PÖN…™i”�GLë‰Æ k0� X‰µÿûÓÏTØvÕªúÛœÂî"]Ä¡Yr=›zƒádš÷ÎyM¯ÆÅH3’v¬¸Ä\F`ö`Û´ô¼­nnMjÊêYØ¡ Að|û{§¨„XÙÖÏHA�/xß[\Y" Ü­[4ƒÂ·¿²˜Ë¯©Îä‚àùWÉcñ56�R[­«U±ÓY¢�9Â0od~)?,è¤Dê®´©… ”zç½¾²i“®‚j˜”v•+WUkÕëtNÇö|&Éûs±�‘� ˆÁãÄñªµ[ÓUiuÏ’8a ÜÝ£ë1—:±»%µ‹§ jçhà ¢Ç¸6Ђ45ÖÜïÑB™L%T£Â|UÞ�~®œØUýÅÁ²ó�'6 YÎz‡6�~Yu´M0Ò˜ey�¡ '!œÆƒ¾¢×a¶!ã1Ë“�#N 2p¸Œ.‚eþû»ß…•´±&¯�)u_Æ"\”§T+0ÿ·�àçߤ)¬ ´4lÏÀì¿ÞvÔÊ̆ÍúQ\ûÑhºWõ—QâmDßa^\}2ÔÅ8Cd{±.0ž³$9tµÌ‹ùlUЀ*ðKñxj�)¡ë‰Þï'‰Ëdœ‰t„¶tÖW’û5š6I™ö:@�TY©µã†îÜví<©kºEëíd$0'çk6²‹ö0ÜÁ2†Vv„ˆs—ÀÖ à0¼cÑwu±zh«vD0pÿ³X[½3�pMbzý�jß.~þøKIh¥µù%�Íj—ÎÁÂTC07†²uQy “A¶+A*Ï�Y_Y3O fAš¥cÉ.çh-ÞhÎq—{ Y&˜�8ð±È{®ÅÜòíCÑÇÿ…k;<p|)DqðÌaPiÎñ{ëŒiÓ`W2\/[ñÍÅšÏÞl^ý þ¹Os7âÜr?ã‘#,B¦™ù‘�xcê½½î’ÆJEÒdþ³èMu}ÆÁU‡—2ȸK&yÒ=ÜÈAc›3ÑQ½]_^C¥±âð¤^«·�M»P„¶ ¸(E ÁÖŽ¤ŸQ^L*Ý)?™høÉÄå¡b¹mÌÆc¹�cÃ[,€\XУqlÀ(Ç<í­À}¯ç‚ àÉĽvX¤£ {×kU^wáqV& ;éÎK \‘a=dݘӜXû`õEK’Ì£»¥x�[ŒÛ Œ“ôX–k0ä]c³ùIj¥>¹í…¢!žÍnMKãB=è$kñܬ~¬hB)Úd!Ý�€Ò )ˆT’Ÿm�¨ƒÅìwÉ3oæ ‰;%ÕgN¸æ!�Ûv4픜@ýrĶǀXÊÄ$©%òí8D©né²Ú2!^cÁºUŽJ†¹25ô¤ÅÖÀßœ®U-E†an¿ÝÒä,¸žíö ë�}ÀÂÎmó#`ûÏæJ Û·¾—S‚üp¬ÝtÆ�ÁâЧÈ`�¯‹¦¥¯”ƒÁ¨†ËÑàÀÞŒäÚI çði¡¢qÆy²‹Š»»²hlØPûPC»nIdRD¿‡.�u’ݱaLÚ�5%¢ÿ‹(I76½!9·ê µÔÖ~0sÂs ê#hÜûé·mQ8œè*3†¹F¦æ"Ï‚WÄÜEoyîvë0ç4Ÿã·ã<¹iî0-‡¯¦ïe£L˜®À§¼À©)³è”J–í~Ý`*‘\³,—½5¥§ 5 ‡6µ‰ðA~Ìq��©·9ÒdŽ{IMA—c˜€®eó¼×ÿÀ�&z�¾˜ù+¢ÌߟMÍO#¢.5ˆzoGÎG¦Ð1ßù‡4èOf¸·¦üãXþWÄZè§í³°H63DŠè£ùû·±Qpðòݨ†m½w VMÆI–…ìþ`†~kˆÿ‡Wþ®Ÿµ?±±”ýr¬.ᄨ ÏwÀF�h¡”?|p^öØ\�í¡NcÁzuûa�²7ãéÛ<N‡+Ü© Å™=Ö5ºŽå”^æÌ�Ôæ”àÄLpR•q}‚FÅz³EYÇJ¢~¨dì9}šÔ;²@äßîð÷6ø—Ê—c›ÍbÅzžï$¦¡lzÙ›åvaDj ûÕÒ‹EL&PSs)»v.Ë$ Ð澩§Ô¨zÐO/—ôF– ¤7±„™Ks¨�es†¢IÌo‘gÂ¥$è¿UµÉíísMÈX¥=*Þy¨¸<“ …¹.zÇoÆ�dŒ�™…® Î1Ë‹~ÓßéÀWå5™Y)¢mm9‰¬‘çÎÈó¨Ùl:ËJe.kr7“™�^b‚�Æš#?ŸIGž~£�]Æ©w^¡Êxè*X�¤G±ÂÝÇ’¬/Ý•(\p?-û¬¢’”aÀOž@aǃŽ!4Ûš³4b¯­i_–×fÁ"Ž)Á4�Õîüó8¹GTpñ˜jU†8ö2•'3�NâëZ!èZÁc½“Ôã¤ÿ?§>çG'ÆÀ®¢}¨ûœ_ ñÍ�U‹ÛfSo¶(Z"gÞéŠ8�‚…%™a(¯+u WÅâÓM¸¶ Ì®Qå³i»xLÅ}G‡O¼÷¡è!Ã�¨*0b°G¦ýbTê® wbѨµ)þ“aIÄ"Iå‡cÌ4hsÄ#ûÿâDò�:'�Üø#†Çš�“t4é|™¥¾·‡õ& Õ«¢Á0ü¦¤j²�æâY†W¶†nªîmƒeÕŽªÎŶ\¿Z–]QYÕq`Õ) ÈÄE çL ¬Ñð ‚wul_Yí¥cÞ^¾úìÉn| endstream endobj 121 0 obj <</Type/Pages/Count 6/Parent 53 0 R/Kids[119 0 R 122 0 R 123 0 R 124 0 R 125 0 R 126 0 R]>> endobj 117 0 obj <</XObject<</Im3 112 0 R>>/ProcSet[/PDF]>> endobj 113 0 obj <</Producer(GPL Ghostscript 9.10)/CreationDate(Tue Sep 27 20:51:22 2016)/ModDate(D:20160927205204-04'00')/Title(diff-ops-reads.eps)/Creator(gnuplot 4.6 patchlevel 4)/Subject(gnuplot plot)/Author(bharath)>> endobj 114 0 obj <</Type/ExtGState/OPM 1>> endobj 115 0 obj <</BaseFont/XTUCJG+Times-Roman/FontDescriptor 127 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 0 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 0 722 611 556 722 722 333 0 722 611 0 722 722 556 0 667 556 611 722 0 0 0 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 127 0 obj <</Type/FontDescriptor/FontName/XTUCJG+Times-Roman/FontBBox[0 -218 775 688]/Flags 32/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 116/MissingWidth 500/XHeight 461/CharSet(/A/D/E/F/G/H/I/K/L/N/O/P/R/S/T/U/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/q/r/s/seven/six/space/t/three/two/u/y/zero)/FontFile3 128 0 R>> endobj 128 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 5365>>stream xœmWPgÚ^YH»n$FÞ¹Hœ“ØIÜp‹qÜ .‰‰M3ÅSŒè :B¨"Q?ª(ÅH4Ó»qÅØ&qlÇÛI0—r©—�äò-óñÿóï’ËÜÍü7£ÑHÚÕ·oyž÷y^fµ�c±XK<#bD‰ÝÅ1A±Ì÷ ÔJµjµš Pìlõ¬3g5æRË^ –°Á«ºU¶ö6Ôêepè¨}c³XÝy'q\ZBDXx’ý›§Ü½ßZ¿~ÿÙ²k×.ûà´?¯Ø;‹#Âbí×ÒRDÑâ¸QlÒn{'úîèèˆsöaÑiqá‰öA!!¢æo^AÑ¢(û#Ñqqâû7�Þ²ßêà°e#ý¶ãDDLpr¢ý|äö'Ä»ì]ìÝEaÉÑA ÿÿ †a[ÆŠãœã'I<št,ù½ ãÁ.içBNˆN†º†¹GxxF�ŠŽqزuÛöïØïtÜõæ[0l vsÅܰ70wl-æ�­Ã<±7±SØ[˜ö6vÛ€9a±Ó˜3vÛŒÁ°£Øì¶ {ÛŽíÀ\°w°°Ø2ÌãaË1û f‹±0;Œ�­Àb‹°¥Ø6º˜&ž²^c5-.гװÕ쟬²8$GÂù7€kÀ÷àë1·ÐsáÃE‡Õ/^½Xºø—%K=–v[»[›^yçó+_¼ZúêoËö/+·Ymãkó�wˆw˜Ïû}ù¹åÍË$7R9Ö³¡À}ú¨¿šX³^Fòl¡º<ü1* îØ¥rQÈœò8Z«L÷ËåKài#î—ZiÑVW ‡áB4pûÖëãtñ@Î R�W!�¥øœ–“‡H ÇšÊjÅuÖ‹)è<Å®¦Ö�%…åù€°”ÉN Q>ÜUrŸlBà ¸O‘L: x¿8T¯oÄhcô{B$Â�‹BêËÜbÀO+õ`”€iø·cý£¥Ç� žãÚ‚Ói*Ït>ýDµ…Úja5«¾bÃB*�DqX�hå7k¡ ´ùþŸP�m7‡– brêæz´qÎ=ÚØ›"_Iÿ< ¾™x  ÏB15ÒÚ4£n£¬oÙ<™‚ÉÓ¶¼¬2j5Y–¯e€¸ SŸÎ…ãÀ[¥rÍ$xk¥0 ç�­Åä+*À‡Ü‚wD6ªûýZÁ7ે¿|Û# áT€pÏ,8•®ð”òáÛÈ–±ÎáÇ£û�ا8�qïl0 2Jº¨—]£Í¯3²lyù¿B œ”ŠýY/Z»pH€ßÚ'ÆîÜìúü�¾Šyæyýè}ÄêD«�¸¼Uü¹¶,¤ïŸi'[+Jû¦ï¤G\<;Õ·  EÁ;ß=ãë¦Üˆsʲ6á|îUòè~›²±Ø4NÃô)[ž ÎQ{IsLY}ò²õÈ ½Žl>Þúíøõ¦‹ƒBäŠ�4™3רªªpO½¦ôÔw*üúœ‰Ù µ&Y©ŒÑ ®<ÕÕœr|L׿êã—­‘ÇèšC&c8Ð˺é¤ÿ1cËK¢¾…{I1×a�‰è5@ÄqOƒ b­.«0·ÔÀMøgÀ ¨t$ ,‰« Ζ©ä ©Xs†sLàZJJ̸’ 9 ^V³…8ÏÍ�¯qæ,\^¾œY)‡‰9:úÃrÙ!:zg Õ…[Ãi¼{M¬§Slµ‚¬*,Ë×â|Yz€âÀW«=®¤A©5àG ¥pƒ€ÉxÛÀ%sIY–ºBP-¯È¬D£¡ÆÒžbŠŠMr>-ü;žUà•¦p•ÐH½ ŒðöäN%Ât’N�WîN“í¦Cƒ ½˜ }Õ }òß¡Æ�£Š„¶ñ}Eò*ð�€±ð üSP#Ó¿KXS|u½ÒDm2)êm.OÀ]ŸØò6À{ð.™ WqTÜÜÜ m^^6àgu�ª˜àÕ”&'ůÜãîãäÑvp<²#µ&Dó¢Ä>Ñ•õAÊùŒÅ "9TruåEtux.e *·�fBM¦Åœ]»rò£ñO.%¶Ÿì"ì#qµì<0ó{[-Ã7Z"¶60�—÷R¿÷²Ú —²ÿ�=ë 'Qiw GŸ£×2J’@ �ÞÁ£NÄ9¡�ë žøÖòõà¨`ptÂ|Œ�QIOX‹¸:îü ¢�«�aœdn¦$MžÔ ½0MwÖà_z–®äôZ‡ß2sÞ=ò½.�Ó�.ëèí `�nê+Ç‹ kت¾B-i³©„Yèð/a)åEò·<¯0S ÍÈÌЪEž�~éÙï¥J›©ÍZròs s Þý«èwgKàÍÑîÆ+íEEJ‚T� ø¡2ó‡B؃ó^þÌ�§4„]FÖï3pl† E‘Ð +*&u„µJðIm… 8Í÷u§Z¹—ék«?P¢¨¤‡ †cÈû¿]¡\ÿÛ)È gÆâ¸»‰z·F^eó` ¡s«¡/‘Y\UŰ~�¶â¼v)>‘£W_)q Î’ËUqÉÑÊ@„D]èòjàs´VŽ_Ì©’ã{.ú<êê©6›GœçR”{ÉÔYq¹ŠÏ�Ç8kedAœÎg&Ö…rgî%#¾«0½ <š÷QUåTî% þ2K¯¢g”5媾á>NÙ5ÚŒ}ßüÔ–7D�ø˜”Ê•Y2@$i«…�ÎþJV³¬1¹3Ðè ˆ�O»$™RëLõEyÅy:anY^)Ðæ¶úÞQsì)Á mú@ª %§Ê#@$Áóq ¸=ØWwå¶€Wé]\›Ò·ò¨ÓwtÓ—ÐfzVEge¤(åâŒ@„‹/ ‹h”ôuÂ¥ƒÄ|ç“{u†Mm™µ%õyå ´äê5 $'Åxú Ãh‡ ¢¬¨ø´„N°K‚?ËÔ+€óŸlÝÃô®ÃˆïeíOâMuÿ\óôÀ5g�Èr¹Vœ—T@Éë¸÷Η—;ü€ä°ÐºC×{wªKïó�È0ßÜ6jñ‡¬ûS0õ 6Ü8»—Ì*’ÅiÎ(ø±N:^’_t€è-ËÎUãÑ/#_@»¸�¾_Ùÿíºna§S^V=#�Wž]Ú‹¬Ûïø.ï³ çÿ5�{¨ŸÿQqÔ'ð)É“dÒðÏ4G@ãR”t©<¨ªz^L§ÚñŸ3•WüçTu•PøExˆ±(vŠºmbQbš^h¥ŒÛV�‘ž�—™£¾�šK2«²+AÔt„Ëñ¦ìU©rQž]¡Æcñ­2>�%¹HcäñÉ9Èêb‰NZ$¥‘’ššÙ–Ð÷â|ýšn¢6T¶U”7ò„=¤8ͬó“lj t ý‡%ºÂáø ˆÿrýÁ§�•ªÐraIr©¸6­ð›ê� c‡GvžöI úˆ�‚=úËóM�=Ô[ÝÚ)07Í-7 ¦W@5µÈÂ2OÃÔ)6üAMÂuW8ÕxZ^.ÈD˜†&õ­~Òpõq)?/Í/¥€è*S ‘.j‹«8G,|â 5hù“ípÁX·iä‚ð8Í"+ Õ*Õª´Ôu, =_ÀW gôñÓ«£g¼„4,U¦ ˜6�5Hmd˜C©Hª·Ê»Œ•UåUEÝ Ù”¼;§*Û�a’—…�ô>GRÚ/á€*Mïbîœç^—K3iü)Q‘6€Ÿ jΫ¤NÌ�p˜*Þ‡±mïdQ #é·?0ö8p�ͱ7Òºµí¹· x›«¹£nNh‹éô¯ó¾àLš(âLpœ3ØE ÁÃÿîÉMˆõ Ð3¸�¬xv¡ë6¸ ŕےÉ;©ÿíd] ¥aä²áÿÌ:’È­¢=‡ÿÆ6‡knÂq—/C¾ ­•/\í¡ÿ?b_zÞºÜßÙ¹ž.µÕ0N댺vºu#@‹�«âHªwF‚4!))<ülšðgkÃ[½‡#� f,?ô�=£õ×ñ‡ô¯kƒAÖ/t'”¾BkÀ¸±µ»®J[+¨Ž×«k�Ñ`¬mè h:ù�Wœ¼0>@–·›ØõºË‡TJ'ƵVè�§ª�OxZã}/¼Ä¸ºŸf`:ãê¢áY8H6åÖä5�gàZù@ã­¶ÎÛàcÐ/ïŽk>7¸Ý²‘FE —WC“KS®þS4êýÚ?TO¡Œª¼h*Åʬәáʉ3¯¿íê‹ðTy~AÒ¼��½·™ íyÙSlaY>�é“f ›Š¤ìÈž}x*�¦ê’KíâÊãŠã±é “ƒ‹Yôq¤P’–&ÍÌŠŒU¤Òó-E¯ìKuöŽ‹¡„׳€ïž<kê¿"èn­iÝ`âLÿÁBD–Øy$”�j`jï0—–åéò �1·2¯t�^C«¹Ýbè�—@sVƒ¼�@Ú¹d»öEæ( ¾nW„¹íAœmn̓ ºÊþKÂbø yÓÒ1ÜÚ$�©Ô†ëýAáî2èÎ÷´…Ø ŒÔ/L-gf ‚©åäì:#)*L-�½€‚a‰ÝÝÊ}»¹­ÉØFÀ€¢+¾YÔçØÄÔ³™Ë’àO4åª?ç²Zy€| øbZSiå‹�À t›wpy>s~Ô4i©(í…ËÆ7ú¦…Iþñá™ës÷@£f±¡Ã—ÎØ<›y‡Ùß ³�löäÈh¦ë *óË�¿qÞBÊpà¤Va¢6àïkÊ™§AœGùÀ2.)I,®O²47Ô7[’biG~UÞ™l¢P_„ÉæÁ4”ÿlË[EyМHáf'©TRÚñÐs¯”àµW…†–F­ ÒÈØðè´ à vz@+ׇ¢+ÁçEeŠâ�Hóõ?´Õå:´ö$q[P8§žËs1æë« +iW�mÔÒ'ɺ{5½+!þåó_>ó¼ƒì׌ ‚kÄõþ~IX‡ 5ª*¾Ú•¶¥óRAýØÏ‚:Zòu³9—ƒƒwT*GFè†hÕ/’W2ª_z ‡\PŸÖ€�ÜL¸�3w››‰öq¹��Õ`„V€øcst4°>£Í÷,›¤ë–_ˆör…Ÿp.…^·rrœó­0à©ùç häwð¡ íÑÉÂ삜‚œÂ~©º0d™J�Dc Ü€ÂhcÐe´zÙ5›|<1Ü\Ê7UÐD.5 @9·'¯"È�&C.WÒ{¡µåˆgˆ”±·t~Œ†Ã ¥AjÖÈúuþÏ ›‚”ž3úêÏÊé©*c¾:¬£—.ÕŠÒcâüŽG�ÎàtcÜHZ›¶‹ÙÍ{´ŒG뤳LÚ£"ÐütÜYO:îõûˆÁä�bý8Å6Ò5(áVäëói­h+—ÓKg<NÉ.YtTÜ¥HY®Ô·t¼ÞR‘úˆ”o=k¤k¸ú kz º0/¶‘^À+ K™¼©,ÝOˆJ˜3dyô Ü«@VzØ�ƒ‚Òr�î|Ã@M ëà ­ï*•;×$îž/«,Æ[Úk‡q£6ÎQˆÂè…^£qÓÒ7‰ x|AL�¢ôða0…ÜÚçæïvJ�v#Â| �±ÜÑ…xBïî>zw—1»»¼iÖ¦‰Õø=¬üž��#é ‚¤¡án"„´ V;Z8âÑp9q\5�ã×»éý.%`�ü+²äÄ“SC´xŠ�(À~ÇŽ€ßa ‚ìiá ºZõÀÄ‚Ól8ÈÊ1Ž×WÔêjŠh�Õ•É¢„s¾8ˆÔ$¥gÈ2ä9AL�š øžüôrp‘ ~`<xJ5<fÁ¯§Ù”®&š³€�4\¸:ùMÏSðŒÿÓ»“¯yz'Ÿ DEÈ¢¤ÎuYv½?v¶ÝÄÔ ÷�{ý7íÜ*DG�GI­`N¥5ïë[6ðásÑC[Þ}¸~NÞ ¹�É=îà±Óýýƒq©ºÆPAL­TÇØ™<%| ù“ÉçM}#‘¾¦qp\N‰mM­—èŒô–rä|×µŸÛì � ÄÄÉâ“O²íú µˆ;C.a²°„aLŒXv4qž}&¸î#zûµ�CÏöMÚò¾¡¢éåô Ê-€‹îιqŽÃ h7Îûyîžá¢c‘HË…Zø=cîä]Ô�ç,8û ¾G½ ¡·꺿´ËÐÉRÔY)t•D\ÄBjÚå�\~VQNi[¯VÑ'€xèÕÀ›Äúö¦Juõ1‚¨†¤rÚƒÇÊ• ¢‘Ä'SÍ—/ ‡‡ên€§à¡dØ÷RÀ {ZTÇD-·PVì ßÀ¢¯Ø”ûìqÕn’C>Û犸�­�ÛÍÛ|»®%NоáÕéï �.?ô)ÂR´"¡®‡Vƒ[šŒzÈéKNhZrâð¶SßÂÍ—K-&ƒ°®ºµ¬ƒ1 …ô5&êÑcujömrŽËuEëj4÷j+¯>Œá¢ÓsßpîpaøìšùºXf­-6cO?†âûžOi¡‚NþãjG?¸G|ætkb½{Ìá}cìo›¼/¶+9ú芷Ÿ…¸dòã_¼I01Š–~E¤½N>òn ÄûgϾ¿ßgüoÕ÷��F'É­ãaÃ`ŒêûðÞ@ÀwñYw‘ +€ì¦DP=@YYX-gßL&¡Uåuã½Ñ_ŸÞ†¯¸’€»6Ã…ˆD‹·®E+‘õÃw!v½¿ºïª íDl{´!ž€7á, R³3TâÄPE öû=�‹oTߪkÖ˜ÎW4âoC;Ð!í¢f_7±.ÒL»H3í _L|¨¿óöðuóLæu½õÅ}~MÉW¢ôÕv»?wÄ=I¼«z ~¿U~fž°L´t>'þuô›fw£Ãäã‹-M]ÃþÖñ€ \úö™à‹ñõÞmÊt».æpË�ÆcûÁ:ðšÂ1î„Ø%&ÌÉ�iU¦)ýWèÐcË üý•¼Û>tÜ".…÷œ OLŠðê¢$�%ºüü/°@@þÊÒ’LM”8ôT¨Ð:ÕDy™ §‰Û²èåâ–Ò%K^Ö.YŠaÿ<.ÿ endstream endobj 129 0 obj <</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R>>/ProcSet[/PDF/Text]>> endobj 122 0 obj <</Type/Page/Contents[15 0 R 130 0 R 16 0 R]/Resources<</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R/Xi7 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 130 0 obj <</Length 13311/Filter/FlateDecode>>stream xÚÅ�o³Ý¸‘Þßϧ¸SS®’<Ñ1ü“}—7N6©rÅ3UIj½/déÊ£²F²ï•wjóéƒsÑlð‚h°M¾Ø�±Fçéìnü²yøËCóðûošÕ?ÿþ�ñÿlÌÃ`ã.ÃhÞýüÍ¿þ[óðÞÿù¿<4—v~¹ý­ŸçÿÕ<|zøá›ÿ}úö F°Í¥ñã哽t£‘ˆð#ŒÃT2Bß_L›¸éÒ˜Q¢â:Dgú’!ºîÒõ]b Û´—Q¤Â6ÝÅ–™áìÅM&5†ë½¡"n¸Ø¾LEé�KŒÑšö2ÙN"£5Ý¥µE¸ó_Ö ©1úÑ*RáGèûQ4%�5ÞP‰Šë½ESÒ ãÅO‹H†b0²)q­õ'aÝ2“Áç[oÇìÆ\&oÇ}ˆæ2^K¨ÿÿ¿O”Áe¸ëŸÏ%oþüÓãÇë�/*°/_ýXMJ(†±”¹ðQR®5Ìš¡š¨‰±š¹þQj®µ¬©ç ”ÆXŒéýuæ“.­æ·?~ó›ÿê�›.SïðǾ¶�7õCãkœé~|ÿð¯¯þÛï~÷ú�uÍ«?>>ÿãÓ×ç×ÿöã¿|óÏ?®ª@×׻䠪Ȣélçs¨�£ùá*šk ŽŽ37ñÊü#>¾ÝôoËþÐóùCàKŠ‚ì¶¡Û¨ »-_tÛT·¨@yÁ�’Ðmù* Û ¦º­@Fè¶‚)�nË—1wÛ~˜|@S¾XX¯Ã”4[4j¶÷�“eïjíp�a?¸ÿ·ª÷ÝË2woÍ•tÏ�y¥{îÌ…º§Ñ—Ý!Öý¿_îÕ—§¿~úòöýËBK¯Dèè«(æŽ^…é�ÿâk±ñ¥Ïv ã¿ÿæ÷¦óÃÇÿ÷x�ÃøÍÜ:náO�kþÇoýÿ7/£œ— •‚ e}ä\/ ƒ´¦¹øÚþÐOÝeìÍ=†þ??vQlýÛ—¿=ÿæùñÝF€¾Æ7Õf1tŒu€÷RT _jØnà_ß¾ûë‡çß¾}~ÜŠóW¿ûøáC:Êk 1¶­fèHë0葉0ÌÖW–6äþö•㼬ãÜïD×j;t—¾«u­^›_çªEz©èbíìpé۪뵹:Síb ½Zt±v£ŸÈqªx¹†•þî(£…þõÓFò #=�õ#_jÜFöó"_î»Fôã"_n‹FôÓ¢@ê\FöÃ"_î+Fô³¢@ªûFô£"_®ÌFö“¢@ª›Föƒ¢¨JÝÇW€©w»~Üé¦ÿW¦ëÿxº¶üü½ÿŠ¿ø/HÐòeÛ¿6’ÃǽdzÉHýÐ\œ³÷fa6é�ÈC%Ž#Oÿ¸Yy‚• JzMúÇQÁ<ÚŠ&²Ûf(…à ÌŠ ˜ëU=€Ä°­çg»ÍY*&P#ÑæVÖÜËhEkÃakÞÜ9Ü/›ÜÕ ÛG¼ŒáúƒÃ‡ëÏvíC{éÍ æßg@îd¡S¯|¼w‚z>Î�ˆ]üþ )ý_ìI)–‘°¨PÎHàÍ(#O-š<ùR‚ÅŽrJ©&RÒÿIâb2~)éY/1­žmcX®)g$�pÒÆiËFKØ8¼ÛƘ‡ýLJ¾l| FÀ b&ù*p÷'† qR 5ZJ ”|¸OQ2(¤¨@åŸ;%*ù*p¡åN `¥@*TÜ)°äËdé|93æ ²\¾L•,Ýèc›w±ì&Yy Ë8òúdyH0PàãhôÈOdk·ÑR!z-côÐ;Ð��Û&Kd¹rF�,±3°þ²Üõ€åÉ6BÃ^Ù¨– í¶‰¦,ËGXY(ç#€eT‘F“Û¥<ùJ‚åŽrBWbk¾ 9r¤�®<ÛÆ°\SNHàʤ�-×FàÊÝ6Æ\é?Þ±w9o\É/;:á&%_ný�p›R µÙNºQÉ—�ÛT'ܪ¨@Õ¿nVòUàBÛI·+2P¡ê¤–|�+;¿ŽpãA\¹|™*Wvî2vó½ìí&WyàÊ8òú\yH0Pàãhô¸O¤±ã6X*„O€el�XFøŒÝK`¹rF ,±3�–cŸß²ìi²<ÙGhÙ+•È2á¢ï y²ìi²<,!am¡œ�@–ذÉ5°<ùB‚õŽrBXbg€ˆº<õ4XžmcX¯)ç#€eÂFò&‚žËÝ6Æ`é?Þ¸I–ü𺃂K¾ Üú‰!H°¨@m–RA‚%_îR” ,*PñçNI�K¾ \h¹S`)�� wJ�,ù2XZ_Úšî °\¾L,ÛÖÆlÞA9ƒå!‘°Œ#‚åËÈ燽_t·þën‘??þýÍÓû7©Ã$æëOȯÌ)ÄC¼�~›£Ç©øº0�ÍÜ\«?ª±z y�ZNU±€Á©+cÔ8#¿ 0õda°²Q S&ÖØ�=,a¥¢œŽ€©Q:š)ƒ©'_H°zRÎGÀTìÌ÷¹öížmcXý)ç#`j²¬µâûjwÛcªÿøÐ8âœèG·9•‚:(J�@Ÿå«À«b’–ù*ðúƒ‚¤e� Ôì)$-óeàfIÉ hY õ î”Zæ«Àõž;%@˨^r§h™/#в.îˆ>˜áûTyÙOµi‡{Ñw›¼|Tì¡<G±×ߊ=*¨óQ<z�‹'3C¸G… & _�oqøÆÚ±k2Œ«aqckÔ[³î¹&BÏŽMTâÛ„…í¥óíQÉK ÝdºÅvygºì>ì¹×¬wt“ð[xÛ$ùÖ]\וòíÉ.†åšn6Ý&\Lß±ïîÞ½&Æpë?Ý:#Ùƒå�€WÄ$UòUà¦O AR¥@ꯔ ’*ù2p‡¢dPT)P�J?wJUòUà*Ë� J� T¦¸STÉ—¨²qþŸÃ�X¹|¡*W6Þå±½—Û~“+‹>€e}}²<, (öqDzl‰'4w€ô0 ÑÄèá%vÀ¸¶3t©â/WÞ¨ñ%ö¦”/ nô=ÙFhß+•3abWáFßÃ2ÖÊ Œe¤5�É1æÉ×,”S(›”9ˆïõ=ÛÆ°|SNIÀÌ„�–Ú‹.¸×w·�1gúÞ7M’·rFX–ä$gòU,ퟂäL� h´´ ’3ù2–FEË 8S ê?JgòU,…–?%À™P¨øSœÉ—1s¦»P×Ç™è 59ÓMý¥›«ó°…™Ç?cæ*øê˜y\@¡Ö¯"RÃL<Ÿ¹ã¤Ç9úÌÊ5ÌÄ´c×µ›�©ãÁ~È\;£™Ø`Ì^º‡y¶‹¡u¯]ÔaÌ„‡Ý6§—nb—�a‰¡��1£llÚvÜ̳/¤°îÑNÇ�˜Ø8é¤7éžîâ¼lÓNÇÀ—I§�»ør¿�_^?Þw�€/#à51Å—¸ïCP|)Q�z,¥‚âK� ܤ(_JT âÏ�’™/*p�åNIàK‰ T¨¸SøR #ðåx½g:�/—/TåK_¦›aþ=oÜÌâ€G¯v¦ôZ9únûL© û�Ä¡Òã ‚æ;¤¬øÉ,=Îh]±zÈŠ=È>ZWDz®œQCVì 0«3ëÉ6Âr`e£³&LìäwÞ—�°nQÎG€VlX;úÉÊÝ|{öÅë)åœnM\N µÍ^�®gÛÖƒÊ9 àš´±“ž.Ýoc ®þãv’.¥G ΖÒ�GKùðòÇŠÃÄ×€—Vô&�Ôè­ìL|¸MZјPï±¢Ç/ñ5à oe_ˆ@õÑʽÄhÙOŠiûEÎ<øOßkuø×ÜÓ–ÐlÒqzHšˆsìü¶®i“ˆÕ" U6Ž0IÀù”ª&Êr¬:I¥{çHOLC+I ghr©»7PÀM¨1¦3Û¼YmFý§z·ü‡ð¿Òt¹ >µ’Ý| J|8†Ø'Vôò™ºße�òP§ 3®œJ-V÷:5CcÂ'+ñ)P£jú@·VH CìLkGç2lX-Z*d0`âêhø·ZžaWX×(¤°^Ú.öƒ¼övûÃ^?\¦v�ìRòGXZ:9‰Z|K¿%‡ aK ­‚Ä-¾Œ¥«Ð2(à¨€Ο’€\|KåO @—@T'þ”�vñeîrî2ŒV‘»–/¨Î]¾Þ´ý6š6ÁK-Ä�^qˆuÀKM4TéXu]ðÂ3“9Y+J‚¼âHë’Wt vS¼ªÍè.ðZÅ^¼pìajㆷe ähð:Ô)h‘+§*‚W§vãµ{E>ðRÍhÚ Ùà…�élc3ÜU-Xw)$pWâ⨱÷v†]ae£�IÀ] »LòE ûöØvÛc—ÿ¸[ vñGÀ �‚Ä.¾ Ül‰!Hì¨@m�RAb_î)” »*PçNIÀ.¾ \D¹SØ%��ŠwJ�»ø2vuí¥³£"v-_P»:¿ž 55õ’ê»ÔB ؇X»ÔDC•ŽU×Å®hfrg+…IpWj]î¡¶C»ªÍè.ìZ…^»pè vµbì:Ô)h‘+§*bWÂ';¥_¿ »T“š¶Bò�vEu¢q&ƒ]Õ‚e`—Bv%.ŽØu†]ae£�I€]I»¬»vÛc—ÿ¸µ’÷; FÀ Ý o,ä«À½Ö o-¨@mÏJo.äËÀ=Å o/¨@Ü o0ä«ÀEÔJo1È@ÅÉJo2äËØÕ¿&tŠØµ|Auìj})îÃ˱ì&v©…°+‘�]›‡ë\ß]\7•®kmît�š Pöcêr\4ÕÙt•â$@.޵.ÈáX»~›ãªÍè.Ž[E^•ãpä Ç5âûu zîÊ©Š—ðÉŽïÜ·¨š;° PÈศN´9Œ«+ãr0.qmøžÛroÃŽ;ï°TRÈ$à¸T.mc¯-½kq·]1ǵ>{†^tF�‚:¤F�@ŸRã«XÖä$NòU,Ÿ‚ÄI� è¾´ 'ù2–ÖFË pR  JNòU,Åœ?%€“P#ùS8É—pÒ\Õ”ü|52V)—/Y#å(EJë¿¢ ¿·›H©f(¿q˜+Gönžªp¨Ø±rL‚£˜ñ e0P5Ph q x);Š1js�ø¬júO=h4Z½ŽbÄAÏ«±ëß*Ú¡úu†�òäÊ#´b…ì—vȱ ì§š0вØ/ª ƒÉÝ:Yïr(øA�V ‰Ø—¸,Ú�WÝ•líöëTXÌ(¤�_Ê)Á&8ßn§bâ3WÃE;wüpã&† Q‹¯wUbµ*P›£T�¨Å—�; %ƒB-� T·¹SP‹¯Pî”�j d êÄ�@-¾Œ€ZMi{«ŒZË—TG­ÆÿQ7†sB›¨¥f@­8Ì:¨¥**v¬¼.jáÊ�YS�ºBi]Ö‘Úd¨3kU µ˜µVAWe-ô¼ ßÇ—C­ƒ,‚¹²¨"j% rE€È‘–jº@ÇVH ­(]š6GZ] °DPH`¬Äõàg~,ÚZûu†±êy´‡±ò+á”ué7â•lPcív*f,ÿqÓ‹¥ñGÀ›‚d,¾ ÜM‰!Hƨ@í�RA2_n!” б*PÅæNI`,¾ \@¹SŒ%��ªwJ€±ø2fÆê&¿Àmœ.c¡/©ÍXÝä×+Sx žÛb,Ý0gÆZ…Y…±t…‡Š½R^•±âÊPÓ 5´…U¨U!+5ó\�Z¡–BÖ:èš�] Yô~ÖQ…¹¶¨d¥ rdÑÛYºéZ¶FºÈŠŒ]†±ŽºÂA#_c¥. ÜíÍÀX‡y4¯_4&ÐUÒ#›,*EºÚïQDWÝäá¤ét%aéÕä] T,m”‚¢+‰ èk´ Š®2–ÞAË èJ¢J5Jfº¨XJ'J]Id@uâOI +�Œ@W£7¥›”éjù’êt5º‹mÃÍ‚ý&]©†è*“AWÛgÐŒ»­9oa>}~¿uÍïwÓõ@lD]X‹&<w M7Vh3q¬ui Ç:ŽÛ°V)ÒbX[Å\ÖpÌpo]#Ý«w1ìûÚÚ®Šà™Õ¦�̸Ë0PFdSÍX(ä [TR÷4�²”5°îPÈ@¶DÖø‰o¥Ûbg¤ ,�Òð-ò+ýtØ¢ÄnÛmTÌmþã]'zZÁÄY³‚ȳfxõ@ Aâ#_îëÄ$> T NK© ñ‘/w0J…�¨mp§$à#_.ãÜ)|È@Õ‘;%€�|{ÏÓÎÛ&twõèô9tL I£ãp/{÷•°‰Žj!†²‡¸…�™œ§&ªt¬z‹ñvM 0ž™ àU ’�¼8ЭÅê®@ðp nؾç±Þ|¦þ4ÑwVAo¬U÷=¯Uû¦ð§óo3ˆWÏ£²ý¸•GëÓ]ÍX9t5!åMsœ-ÝŠSMhÐ ©\‡=±Ý4�²;([`I �-@v‰lmáë,¾Í�]E�ÊoxÔÈ`º8k¼}[YSzœl¿G1Ôù�7“äVGÁ¸OC�4ÅW�›(1IS¨«Q*HšâËÀ�ƒ’AÑ”@*ÖÜ) 4ÅW�K'wJ€¦2P]âN Ð_F )êTôšE.M-_P�¦üÎÁË~ÇMšR 1ÐTbšR U:V]—¦ðÌdŽ�ÕŠ’À©8Òº8…#uM·�SÕ&´§VAWÅ)t¸y¯/<ç‘éz•áÔÊ£Š89d §èãcº©Z!U�§°'ž5Ú M”,°$PH ©T²8êÖÆž¦©jcŸL!q€©âÔI¾–}ß>Ùn£b¤òZÑý�üp³&† ‘Н7Rb©*Pg£T�HÅ—�›%ƒB*� T°¹S�Н×Oî”�R d ²Ä�@*¾Œ€T>ݰó†Í´¶Ájùš,Xm LãU7^L߇ƒ;›x¥n€¬8ÜMÈ¢ÂM –r�PÃã6�kÿ„vE3–;UV5d‚¾â°7—”ûÃÃaÛ!sÓbå™Þó�ýµ [KL† �ʰ á g]á&Wæ1úÕ]+c³•_[KÌý~Í„¹åÇíÄ^$´}µ¤Z‹j‰¿2´vBZÁÊC-­€ßie'ù#k_. ŠSK1`¹È;›ÜC,G¿'m¿i1Ëù�·£åØàU@~äØpKÎ�@b_ꇄâØ"p“!DPÇ×€J9s2À±5à*Êœ À7¾TŽ˜“ðÆØÍdm»£¾Ð…w›à–/Û$8zxšãZw›pK³Éq‡„h.=Is’Ðç3l�£~È3l·÷¨e±bôˆØ�$)JÜ^ÄWFþ`›Bü6Æ$W¸�±]æé$*WÀ.‚\9’ZêŠ ‰ 9È_Ǧä`M®¼K-u%ÞÍL9ç¶�x×ï°¼ƒåˆrÞ_FµÇö¼<áº�…‘rÎd&rÎØÂõÜa:•ë‡�šÊùÀg`…ÍÃÝÆÀé?Þä?N²£‡ ÙÑ#Їìø*𪆂D_¾ ¼® † áW õrJ‰¿|¸-R2(�¨@-‡;%�ù*p©çN @°@ª”Ü) æË¸Õ,oˆu²šEAÖ,r„‚šÅV±Ô,rºf±U,5‹‚®Y|P³htÍbËXj-ƒ¬Y|P³øS5‹­b©Yü)Yj_Ô,þ”,5‹-c®YÖöÒšE QP³ˆŠjS®YÄ%5‹©×,bˆ’šÅU�j¥¢¤f1eàšEÉ(¨Y\¨fq§Õ,¦ \³¸S‚kWªYÜ)Á5‹)#ì7Ÿö½þ½bË×(Ý+f¯Ž„[pÌæƒr¸¡ÇáÖ¼WL9�¨áq÷ŠáËüð_5`â'ÿ8h�;ÅpÐm?¥îj ¿÷Wžé]¿ô¯ŒP¸W ñÆöÛçSŠï«|¡0žy·r­úc‘g÷ßh›ôóï^<²<÷ü»2 V�j?ëGf'7e~د�be?é«%ü˜Ÿ¸P2Ï“4¥Ï2?-Ã`ͤ–aðû=¶îû\Žù”t}[zÛØnëbº¼¾îk�Ü6Æ`YP#�LÇÖ°ôgj’èø 5’Hžc‹X: )‚¢9¾(åìÉ,ÇÖ°”Röd�ÉñE@QbOp[DÀ¸¦÷ZÚ ÏuÝ¸å ª?Îüº6žÂíavÝÔB ЇXçEQj¢¡.Ǫë>wÏLî) •¢$è,Ž´îSÇq¤]ŸzeYÀ²j3ZøÜñUÔUŸ;Ž£7} Ô‹E ÞUíz`@ØÊ¯ŠO¸å—†}‘[9þRÍh× ÙÌe�19ä:áÒ€Õ‚B*r%.[ø:±ï3Èu†]a]£�I€YØ®³’?¹‹ëºRÎÚíWÌYþãΈž^Çwtbµø*p·%† aK u?J‰[|¸©P2(à¨@%œ;%¹ø*påN @—@ªNÜ)ìâ˘¹Ë¯’/­ëõ¸ }Amîj§Áû3¿_)u¼öÎ]z!Îܵ ± wé‰Uz¥º*wE3“{ŒB­0óൠµ*xÅ¡×n‚W½)-¯uÔ5Á+Š:€Wé¥àUïzØ^k¿ê�WÊ-¿XtRðÒ͞е5²'€Wœ=MÛlƒ×—FX2h¤R�¯ÔÅaù›¢¼N±k^ÚhdR�¯È®zû[û트ëúqã$\‚pG'† ¸K 7[bŠ»$*Pó£TPÜ%��{ %ƒà.‰ TÁ¹S2s—@.¢Ü) Ü%‘�ŠwJw dî}-™&EîZ¾ :w�îâÆp«b·É]j!îŠC¬ùêÞθK7t÷Ÿÿþæ—§×¶yÅz}¯žPøc#ꢞììjÅI°\k]–‹bí¶E^oJ QntU”ÃA/{hƒåª] ”[ùUå"·üŸ˜¢‡Þå N5m`  �6�qQÚØÌæÙ×,?r.‘C6ù"ß} w†]a™¤�BÀp »®ëîï!�q»ýŠ!Μûè«°ä‰t×EØ6r Ñ(:<ÇV€—"¢gó±à‚èÉ||¨[ËžËÇ–€ è©||¨áˆžÉÇV€ ¾ì‰|| ¨ˆÊžÇ'©I7Îì§[�¦K¢>þ(Áå ×Üé*>’¯|chçw\X·É ‡…Jp>fRFø ˜<, ¨èqD.]ÍGéE3š¡Ìà €†€—ήæsô"Ú®šmþT1¡|‘�ne ZS»šÔ‹¬¡oN³Ä£©�QO¶ºõÊF´Övõž­™XºsÒÓüzXBÂÒB9!�k£„´SêT6�íÉ—,z”3ˆ7y15.ÿcO#ïÙ>†•›rJ '}´Ü¤ÞmcLÂþã]'ÚÎä�€Ä$LòUàîO A¥@j´” *ù2p£¢dP`)P�ê?wJ\òUàJË��L� T¨¸S�É—0óz�½t½f._¨Š™}³¼ž>õˆÝ3 ?`f~}Ì<, ¨öqDz˜‰g4s$ð8 ÓÄèq&v ³S¿�™*00såŒfbg�3‡<f:3O¶º÷ÊF%ÌÄ&.dÀ½A0ó°|„e†r>fFùhRGw�2O¾’`í£œ�@™Ék‰}³'@æÙ6†µ›rBdÖµ s·�1d^›Ì$9«(/;ˆ!HÈä«À­Ÿ‚„L� Ôf)$dòeà6EÉ  S Uî”Èä«À…–;%�™¨Pq§ “/#@¦Ïĉx9Y]È\¾P2;ß–¬ oßÝ„ÌÃÂ�‡_2 ª}‘dâÍž<Ìh5±z”YÐ Û¤Ññ€A™+gÔ(;”Ù‹)ód¡}¯lT¢Ì„‰¾<[ñ‘ÊÃÊ ˜'dö6Ý“/%Xý(g$`fúbê¸pæÙ>†å›rJgbK73 8s·�1gú�í$áLþxåA Ar&_nþÄ$g T FK© 9“/7*JÅ™¨üs§$p&_®´Ü)ÎÈ@…Š;%À™|�3ýHntræò…ªœÙz‚ÌÌ™ã&g~àÌ8|!gnžélýÀ�›ŠÎtÞ^gÝÚÜ©ÎÃ\‚Û¤¯ø2ÉŸø<Ìh`±zôyÐfN‚ªXÀ€×•1jðŠ�xíÄwâžl#¬ V6*ÁkÂÄæbÆ¢wçàõ°|„Õ‹r>¼Fù˜eד¯$XQ)'$°kúZÊ=-¸÷lÊP9!]±�ïÃÝmcŒ®þãíØKΤÒ#�§Rù"Ð��>™ÊW�PÄ$ƒóUà% 1Éàh½@© œ/÷[JÅ਋q§$08_îÜ)È@—;%Àࢺucp_•lkªöŸíg%-_¦Êß~17úRvçïi“¿ =”æ8ôú{¼‡>ŽF‘ñLføX!x‚�côø`š!È*0�yåŒ cg`=.¿‡ød¡a¯lT䄉†ÿ<àãÃòVÊù|åcßô}†�O¾”`½£œ‘@ÈØ@»I|±Jg+yÉ-¬Ô”sØ8‘�ÞÛ¦h{ü» ïv0†ãë:­µ’}]þxÅA A2%_nûÄ$S T K© ™’/·(JÅ”¨òs§$0%_®±Ü)¦È@•Š;%À”|�)›Á_énÇãá$L¹|Ùæówk0¥±ëçß-S�ÏŸ™ò�ÐSÆ¡'ŸË+bÊC‚� G“|¸n¦Œf2s0U!z*c’Ï­•Ø�¡·™RÅS®ŒI=R´ Sbcè=žâMדm„†½²1õ¨Ñ L™0‘dÊ‚=×ÃÒVÊéL‰ ëLc3Hyò•Ë儤L\K6¹[¸oÓU¥±å1K4å$˜L¥aKÁd¿ù¸q€ÉÝÞÅ0é?Þ'`’?^jC�0ÉW�Û=1 “¨·R*H˜äËÀ½‰’AÁ¤@*ùÜ) 0ÉW�«+wJ�&2P¥âN À$_Æ “vrgÚ D_¦¹Ai§ébšù‡¾ÖlÁä1¡Ï0¹ ½úå1Á„ ¿ŠFmƒ2šÉÜT�ðó4¹²@m‹2¾˜Ý´I“:ì§Éµ1Z;”‘1¥4IïPžmcèØkuv(S&VØ¡<.ÃÒB;MÆ©é2O9:ûJ ëí„ 4™¾–éÛcN·q^¯i'd Ët]cßyÀr¿�X^?~-K|°Œ€—ÄX TàÎO A�¥Dj³” ,2p›¢d`)Q�ª?wJf°¨À…–;%,%2P¡âNI�K�Œ�–c{1ýpX._¦ –c\·½·5ƒå!¡°ŒCW;ujü•ÛÍxúü^ò&Ñcü�¦¤ÇªøâÈž7ÕˆŸ€ÕØ=XÅ VUq€Áª+_ÔXû²<™Å°ó`õda°òQ V“.ŽbX=,a¹¢œŽ�«QIÊ7=ûB‚%”rB«¦ÒJ•tº�a ¨œ��«I[1¬î¶1†ÕÑz¥Ô;L¯PºM«ôÄiÑ‚ÈÓ¢Ëò‡‚df¾ŠeBA2³@´{ZÉÌ|K·¤ePÌ,PMˆ?%�™ù*–‚ÏŸ`f� ¨—ü)fæËÌ<øƒéŽ{búBUnöë‘@Íí&5|(Ðqðõ·d j}‘ê.ó™¡ÜÇ&‡¯G¹Kø¦ÚmÊUq€A¹+_Ô(wñåMî|Ú®»{Ï6šöÊD%Ä}a¡¡�—¾·÷¸L„µ…r&à¢Lì­i3€{òeëå\ÀMäâ ½±WÃÄ}gEµ³¸ö…}¶O>Ûüåͽ™“¢ûý‹±Ö¼'>NìÁòGÀk b’'ù*p«'† yR 5VJÉ“|¸5Q2(ž¨@5Ÿ;%�'ù*p}åN ð¤@ªSÜ)žäË<éüÀ ê <¹|¡æiQ¿z¼4] Ên“( ?e~õ£ÇÕ>ŽHíÔh<£Û§F�s�:Mì€Ú©ÑÈ�¡Ù~ÏŒŽ ª\£uj42FþÖ?àÊ“m„æ½²QçÔhdb)l�–ްÊPNG KlXgšZž|%ÁÒG9!-×yj´`ëTÁÆÒS£ÚIX™°Ž>5êÈS£û½‹ÁÒÜÿŸ,ù#à¥1 –|¸ÝC�`)P�z+¥‚K¾ Ü›(X T ’Ï�’�–|¸ºr§ÀR U*î”�Xòe°ì<Ú4í�•˪nTvÓ¥ŸÂY»M®<,úÀ•qôõw* Š}‘ÞN%šÐìùÑÀF; ·Y]ÒÛ#Òq€�•+_Ô6+‘/ßçn\ÛG•'»�{å¢Òn%ò¶+�*ËEXa(ç"@%®FMêÉÀ”'_G°êQÎF`Ê—WRÿ’�)Ïv1,Ú”³ð2UÓšdQsç9´ðnÜÝ6ÆtÙ¹ËÔˆ¶-ù#, r’.ù*–¦OAÒ¥@´XZI—|K�¢ePt)PµŸ?%�.ù*–:ËŸ K� (Tü)ºäËtÙ¶—áÀ÷–.ß§Ê–ípiÛù&‘¶ß„Ë£‚l¯u|Ôö¾ôØ®èøèí¥¥Ùó£GYÍ#òHVñ’?Az”и"ô`;�;?ª?ƒUcWÔP»RºZpgí¹&Â2 6Q‰T±…ô9µâ;k�ÊCX­èæ!€jT‰R¿›¨ž{ÁúI7S“™8q38õdÃêO7�R÷å¢-|GéncHõŸvÎˆŽŒÒCPGFéè#£|x¹C A²2_^rC�¬,P�Z<¥‚de¾ Ü$)+ T îÃ�’ÀÊ|¸Ös§XY UKî”�+óeÌ5Ë8+­YÄ5‹¡¨f1UàšE QR³˜*pÍ"†(©Y\¨fQ*JjS®Y”Œ‚šÅU�jwJPÍbªÀ5‹;%¸fqe šÅ�\³˜2n5ËÞ"ªYädÍ"G(¨YlKÍ"‡ k[ÅR³È!èšÅW5‹VA×,¶Œ¥fÑ2ÈšÅW5‹?%P³Ø*–šÅŸ’¥fñe@ÍâOÉR³Ø2žÄè§~Ƕ·»�—S­EË—lŸÚ–Ü}°ÝÅŒíü û°¹û f(¿q˜ÉcR{à û 8Ì?5�ýôøüæÝ}¯Á|ý)³§ 8Tü8òäqª½‘Ãî=³u (4•8Ðä1�½�Â&At)7Ö˜í}‚JÁ¦ÿ4ÑÅVa§Ž`ì;ìà°çŸÍ\ò�» Ct‹Ì·™M€ƒ‚»r(uÒb¯CóOü FSx¶âÛÌoüª -_!aà×ü(a\Ûçn<;èz€E†BÆÀ¯õ‰+¢OŸT*º"àçú£< + …œ�ãSYÓ¦o„-ñ~�ßíQŒ‰×”ž&ÒCP˜H�@c"_^4C�˜ÈW�;:1‰‰¨ÁR*HLäËÀ]Œ’Aa¢@êÜ) ˜ÈW�+8wJ�2P‘äN `"_FÀÄÆOnW¡3l½è�Ưˆ~”цÛÓÆM@Ô 0ÔÜ(Àªhˆ\¡áõ–³ jÅ > º.â¨3TX'D £0ë2atõú\n¶™°Öl"atU"ÄA"l¨õmO3á1A3�ªH„)ºôí:Eþ"ÔLhîõ“x0ª þËr÷ws-Àb¢~¶� ¦®†¡ð¡~9<È¡°Î©Ÿ-À‚ ‡</³ÜëPŒ‚þÓ�lÃ��Ar�šÙð"Ax€‰­wpáñ%¾ÔP¥‡—Ø"pÏ]âk@Bxp‰­×ké±%¾T¥‡–Ø"fð3“ó)Ö÷¨Eô…š�Zô±]¼s÷uõ´E…ÇE?WäUôÂ'-n2#Ž> ãÓûüNâq^„ΰ2Cí!�Ø�m”<.þЕVñ«=¢ÇßwÛOhÔq`ÿñ¤µ/ZOhľ,ÇÎ¥�ÒÐp‘z\hïkçtʈ} �Ïh¨åööÃàž—€a%¢�€\±acã2ï^?ãâ k"í´ @›¸|¬ã?K0ð¬’uEp«�w�tÖõ�|Ós¿ué^?Þ�"Ô-‚`Ý‚HبÀkb w*ðÊ‚‚^‰ ÔÇ)ò dà¦HÉ  W¢õî”ÌØ+P�k<wJøJd zÉ�’€¾�}Çöâ젷뉾 ö¶§‡‹1á®ÉfpÕB e7±æÆg"¢Øü¦§^ÄPâã�«n{ÆÓºÍª•‚$ø4´êÆg¨ñD¶M¥Õ&´lãsuÍ�Ï(êeçÓIw>ë]ûŸƒ±ö«Þ>hìV—´ Ý4L?öB7m Ó+¤ �$¶Äº¶ËÜ{TâÀÚB!q€‰ã-1ÒMК•¿ N#e�#§Úvë­Á•¾ým¿G1^o˵¢[b † è��¦C¾ ¼t † é�¯÷ub’*PŸ¥T�tÈ—�Û%ƒ¢C� Ô3¸Sè�¯Wpî”� d òÈ� C¾Œ@‡ƒ¹˜ßA·|Ÿê¾¨ïšƒ ›af“� >Ôç(xµmQ| Ê÷�Ÿˆ�Ñ£¼€.™¡·-ŠÝx³ÍšG…í) _oW‡oLæÍu*0¶Ec_ÔvEãËâ¶Ôî’«Hô˜³‚mÑú&ïŠÆÆ)mŠ&l3M᡽ܮèQéKÝô’Å~ í”Y•K§„׺H7ó�r—Pk 7Ö¿Ë@®ŽE£º©Лp®O¿'r߯è^çbò|ƒèÙŒCPäK�@“/_Ų¦!‡ É—¯bYZ�C�ä+P�œVA’/_ÆÒiù T@»áOI _¾Š¥Âó§ÈW Ê%J€|ù2ù:�K¦«Ü0¶öH—/SåÞÞÔ™zí&õx(ÌqàjÌ»މ—ØD=Äè ±zÀ»X‘Á]…Ð Þ�Ã×Þ%|�»Û/)Ðq€Á»+_Ô€_ó[¡GîS½wU2¨�wWÆ)ï ÛúäÕ—/&ÈÑîaÙëåìÞ]ì]Ÿy-»Ò•³w•x÷ÅÔÙÂSÎ9ÚUò¯w•3x÷…s®Ây×ýΟë?ÞÙmÀôîÒ#иËW�—4Ä$îòUà•1‰»¨�S*HÜåËÀ]‘’Aá®@j7Ü) ¸ËW�+<wJ�w2P¹äN à._Æ\³¬é¥5‹¢ f#Õ,¦ \³ˆ!JjS®YÄ%5‹«Õ,JEIÍbÊÀ5‹’QP³¸*PÍâN ªYL¸fq§×,® T³¸S‚kSÆ­f ~™&»¡Ž‚¬Yä5‹­b©YätÍb«Xj9]³ø* fÑ*èšÅ–±Ô,ZY³ø* fñ§j[ÅR³øS²Ô,¾ ¨Yü)Yj[FØV蜟š=¯cÏýl‘¿—nùªÍW#g'·ºébçýã®ÝÜO8 âP�㈓ïCæEöPÄ÷�„7Ï�OÿþÚ¸W�O™�„,€f{�|ß1ÏØA@&d¶ˆZOsòͪ¼˜aÛ�Ål†ÜmrUÃ.ûÉzßʆԋT™6„]‚hêïÛ}áÑûï2û•¯Æù­•u©×§ò¬›÷ °qæÒ½ù!wˆë€ì‚U„ZvÁ¶�rÇÙ&wÜ éëµô‚½€—éՙ»'s›§¥¬½ÔÒ 6âs܃m€ÝžÅxê?~í»<¥‡ ð”�ÆS¾ ¼"!† ñ”¯¯ˆ!H<¨@-šRAâ)_nw” O*PcáNIÀS¾ \Ö¹Sx*��J$wJ�Où2ž¶í¥mzŧ�,_Pýi ­ÏÒ)<6¢ÛäQµCÙ�C¬ú4âÏo?~*ÃOµˆ¡ÄÇ!×}Ž9Û•‚$H3´îÓ@p ÆuÃ6dV›Ð]x¹Š½ê3AâI¾/}KŸ‡—#ËjWƒ)W~U|&HäV—¼éeNª&ô{…䄌’ÇŒMŸ�ÈŠéSôL…ÄdL$Î@>L‡~MÞ±%A )„9åWL.ÿLG?d·G1#^ßÅÞȶ0é!(F¤G ‘¯/ ˆ!HFä«ÀÝ�‚dD� Ôg)$#òeàöEÉ Q õ î”Fä«Àœ;%Àˆ¨<r§‘/#0¢¯J“Ó}™úòÕ)Ñv׆÷'¹MJÔ 2ÔÞ(ȪœˆƒüåñÏe˜¨2ú(溠ˆƒÎ€¢f˜ÐI¢0ëb"Ó M·�‰u"-~fdsU<Œ§ö~³¿IPÚ÷ÈÈZ׃c·*Â!öêû>¹}dF}ØÒFj& ôùú h%ÌÔµC �IXWÔO�ÃDÊ –ÿþD�ÃjåßÇ–<õÓ€0rÈ éû^<$ò× ÜëM̃·ïâžY«&b„y)µM”|hUCŒ@%_^hC�DÉW�×Ä$Q T ÎL© ‰’/·<JE”¨Óp§$%_®üÜ)¢È@å•;%@”{eÜJr×<Œ¾$ûü»²Ùîü(áµ.?¾žì«·þôèû–ÿ·ö?¿~ÓNîÕÿüøüõþ'_>\ÿÙ¾úåËÓ_?}yûþùþÇo?¿¿ÿù»×æÕ—§§×íðêñùo_>¿ÿøù/÷ÿò·Ç§_ž~~ûùÝ<øü—þñéëóÀ"ÍvÃeh¯Uâ¦ì÷O��Ÿï-ŠàÚKü•1ÿ­wŸÞ>Ï’þÔ¸æç·O}mšW�³º_>ÞŸ;qÃù^3Ü Õ\šöº*› ­ÊVßtmZíÃô·üW˜û—}ô�¾{ûõñùþ=_z;ûõõ§9Z¾Û�ãã­{xc®½kñÑ ô¨øÆã«÷�¯»æÕ_ž®øøöý-ÿ§þ�ë?‡WŸo�ú?ñ_öùþoîW÷~yºÿ�·ï¾þãí§OÿqÿÓ�?ÿíéuç^}¹:òï�ïÿ)aúõ?#¸ùýßôæ}úôåµu¯~I¹ïç¨Öîû/»ºŸpÚ¯x:ïòð׉Qý_ò"N_£øüîÓ?Þ?Î_ƒ®¡{È·žmy¼ÿK|á½0öí×�_>ß?üñóòÑÛYw½ºl<GîOÖöö浟êû(þ"¿^f)K¯Cø?˜-úÓÿ»�)'ï x}·'}�B}·aä�¼dÛø’íà’mÃ%Û­3¶Ý0î:Ö<ÈŸ¿þrMÓÛÚ›Q®ùÕ?ù"â?ñ_î5¢»ÝÀýùv]:÷ê?ùÿØtÁòu ð—c3¹àÊ}¼ Ò\™»ßç\]ƒß¦æÃ[7mY÷|¿<:߯Ʀ�/�·ìó‹þ_~º9áÿ-6ÒÿÁûÇw÷+÷íó-¯ýÝòÚÿóç/÷ÿrÿ_snß^Ôð«[•„õõúŸ~aüÿÏS�� endstream endobj 131 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/diff-ops-writes/diff-ops-writes-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 132 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 133 0 R>>/Font<</R8 134 0 R>>>>/Length 9243/Filter/FlateDecode>>stream xœ­\M³$·q¼¿_1G)‚7¾�£ì dÙ’e‘«�#,$jEÚÞGJ¤ ÿ{gf¡…áÛgÒfðÀy;˜n�U¨ÊªÊÂ_nÇ=Üþ7ÿÿéóÓß|ÜnŸ}ýTn}J÷~û哾¿}ü³§v´[ŽéöüÔR¿}~÷ôÉðÕgOy öyþïÓçÛß¾Á;ÿáÍŸžìáVÆ 5÷Û›ç§ÝŽ¿ù�§�Þ<ýZ¯¨zøùû‹¯ùÎO¯üÙq/a>?Ôíù½äëéüü½žø£x?ιDz?<u¸ÙÏ?¿Ï+rÆ?¤{ E/Èãá±»ð�ïóø4ð›rÕ_Ë%=<¿‡_‚ýù}Þ)��ë½ÍE„ŽÜ?(íáE-Ôõþñ½^BQ„Úïq.%ÔZkD'îÞ�©±ü”Fø_‚9¾å¸c†“üðúôíã¸×ºœî *Í9üüŸ~þæz{ˆØè2'0ÿøÁç a–m¿øÕ¯þñ7ÿ¼¦QZXÓ°?~øi”�áÛ4~öÑ›Ÿ¼yóñšÇmÍÃþøáç1²&àæñwô“7]Óˆ±¦9 }üÁ§#lÛñ¸ÿ²íE¤ÞÌIH…~ðIÔt/û$~ûñÏý6ŒrÊBøŒ~û ~ú‹ß|ò÷× R’a±9Ì?~ðY¤ïuׇ�?úÅG?ùä£Ý�ÌæM÷î)å–.'·�yÕFÅ»MêCš* øŠ|ÃÃêuã þé›ç?¼ýêöåŸn?ý�M¤Þ;õa÷ˆŸÿ“|û—oÞ~ý__ÿîGï¾üŒ#–¬å98i06^ßÏ—cÏï~÷ãýǧõ F·×V¤éqZoþûÏo¿>gu;gÀßXÛ=$�@>7ðŸS¤©ö¦”õOùeú°Ü³ ‹óëíü§dÿ„Þ>\¿Öób»Ó �{²+¿ä¿â�‰{sèÿøâ_ùŒc<~ø·7ÿðô!¼Ç}t¸¶€mÖ�ÿðûOÿ󳯾üæ‹?Þ°ŽoÞ.3tûì)æ=zÁ¾ zè<n_½}ú$ûžïn¿½}ñÄýý+¯”£õpâ"ÿ •ìó»ùy@yÞ]£ì¯Ïa[¹L¹÷(µŠ!Jüˆ}¨úÉ‘!k> ÿ“1£Ì‰�{Ö+hx� ;ÁÐq­Ý{ÄlJ8!‡6Nƒ&yÔ;§†ÍACú€ˆ1€%U �؈F€øxb€ÍÎøUËá~ØZ+Ž'Øë=e�Éå.×ïmh¼ä¨Ú‘ûÁ³ýÞ…‡–Ú=f¿ðŽù˜sá ê_¢_øHãŽ=u oÈ5ø…(pò ï nø…�Qî5û…÷rÜSw ‡dÒ}Ämá­ßk] �G‰STçÂÇ!-§Qûõ{5ï“§X.´P¢!»~éäËß½¦“Åa�XZŸ†L!íŽ�™A#k>¸ÿ�­Úδۨ±Xcá�P·°ùÀ§ØNcúq?¸ÁØ+½ ÔQ¹ùá€èòtpýž¨�Xú xC˱û @�Î1©Þ©$�œ¶3´’¸ùÿëÕSó�G¼CRÓ˜8zp̓ߊš$ñ†~ î~‡æG; ÓÈ|¦Õ5«ÁÜ;4ÿ’nƒ²5*V'eÃK+?uìP‹Ú�†]9¨l¸VÞ�=ú­CósÖætH>ñ¼PmLõñ '§õ ЦSÖi1±ªJõÓª¶ëk¥À)Øs l8¶¿™BB$ƒSá�9Ž�:TÓü£q³+t,Òü`2™!˜y:°é1Þ*ìÄ¡u� Ë“è UÉPf43Ñ’ÇhUË.4IEC†Žz…™ÈE¾œ§—O¡E²³�-Ç…ÃÁ$»†ððbI™ÉÎX–á)g¸Ûcxx‰ÁóøÎ8Îh�‹(ÞÃÓË`&É”'�v°ØEÅI§ÒÌ�L—éà Ç!¥‡?RО^,+A2Š uÂq€r†&Øc¨ Ñ¥-›Ç›Ç*Th“ž�³ ÃHeÈä'lùQì 5=$&h”œ¨5gÐ4�@»‹ÆÀRÒ5GÈESI0˜DªÀ‹Òá�1�˜¡ïZRFÌKŽ�ÅYËBT¡ð�bï3m Ç`Óá²ñ´#é1 ?‡Š¨7Ý6‡`Ïq"#ƒ7¹³”èZéY1«¨Ue,§ÁÔ…~ÇrLx‹�&}÷�4 öü�·»ÃÎk `1Í5 Ã]�)Ørèôp9j6·3h†\²Y(Â&Š…qÓ˜^d®�¬ÿ¿{¯ÕÂñÁD7«…#‡·ZËo›Õ 8 ¥9«ÝÅB†³Z؉pW>­ö ÉÎjaCÊgY­ˆ9Ô8œÕ ð<÷�ÕŠ˜ƒœñi´0™:íì4Z‰Ñž™’iµBÄ ÆpV+a¹;£©¤ûf´¦ÐÌΚтÎ :£•·¨9£žß³3ZS�ÀvF+$¼ $g´2æ@Ñ-£2Þ0 ¤Y­Œ9P–Ù ohÎjÌ!ôî¬ÌB¼Ëœf‹’Ïu,³“æÂ§Ù*�ajvf ÂÔýËlQîÇ47f¶BÁó§I2³E¹§˜�ÙB\]ïr§Ù¢à«�Ïi¶BÅ ²³ZSèÃ[-Øïx7 )«•n|048­ôù }YV‹‚§ º¬Œì ™šV«áý-GgµàóÛ]y°ÓjQìGôV ¿,´—ËjQìI‡î´ZXY¦Ý]V‹b/f¦Ù‚6Ç{òf«c´ñËlA›�¹îi¶(wíe¶ Guf‹bÏy8³ ‚\f‹X³2�f ˜²ÜËf¶(xS¿Ële!Hg¶(ùäÍÖh�/›ÕbÎq8«e€ôV sèíÄ‚ÕÓ1#",ˆÓØÚ‹í8�àK_¼‚¯áÜ{e"glkÀîè ²�ŸC5s§ù,füé_ GÄ8Y®<Ð¥Ã\0³{ÃŒ”,R;©„)@™a肳½ÞšDŒ3¢c]Ø ì,Ç�§f{ ,'=°!ÀDç E"ÆIÚédþENØ`¢‡#¨�G7ÛòºL'¶Þ`"ÀjˆrZ×sÌßÝDh0P@“sʡ缸3Iy–ìw¾Ô2´çÎ0©1ß3w†XI^æÜ™�sºsg¹z‰kg2^®Úv†¸ ×íL†:wÏv†ø/Çèv³=…0w†(²Íï æ0e9w†htLG>w“0� .;ż™rI‘¿wi H¶ÄÌ803{üç·_üñß¿øì•8¾Õã½qüÃwþ´Üx<bŽ=Žç/Î8žŸÏ8¾Ï€qFpúëó½R-e{®�—0ß@*Š(«Á¡xn�~¯—#a€Ë ¹¯èßbiŽ�¶U!8†"T<[ï#�ΆA0›LØÊd¹3Ž�F24m†38†b¦�-t1ï®8™§Z�ó ¥&%CÀPZ Û…D8Þ`È '[øJÓ€háW¸Í€ÌÃL{Œ­®sá¬Xôσsº5†Û Èlág.‚Áß0×Ö Â5!a¾NÆü ?{÷‚¨ðàz—º]¢� Á‰*FνyQ:pû–¨âcKT0Ã&†KTѶ҉Š(Eâ¼D)�ìEu °VÞãUàh/*¢ìE&Â\¢:b|U°¹/QÀ=!xQ… f/QAk‘‡w29Q åõ´‰jâæKTa „¯Ã‹ hsxQù\Éãéþä Øù¸¬MËfmxè_úâ• g}¦Äéõ±Ž¦}Ñ�ó�ÏYÆ�+¡6Já€m&<­‡……�Á� N¢2Ê™€È“'!Øã3Wb~HÆà€õ&~í<ö„ p�î"D{Q#f:åAr� Òat”¢6è¢ÇTxCŹ�€R†9èÖ�AXÊÜ”f“˜` ‹%*a`8˜–P‚|s_‡}O×ÂC¤©$f2Ü4SÉÀ`›«®�*$ôϰ`+ãü�Ö4¦›Ý*qO´1PÊå¢B°1Paü¾JÔf“éŠTJ`å/j Îîn€#8E`ÂÁº _>l «L˜ðé] ë.0|À÷Ò€@ˆ×2�‘T93o3$Ü*ßGésé�±°ebô�?)›>à`�/}à{a¸œ>àÈp¶K8ýؼ>0R¥¬—>pBòúÀ­¢Î,}H8¦xâÒîx^N;æåô�’ ›>$fû¼>@¼>�#P"N3-Õëµ «vú€=fìâô�ÚŠ';}8h•»×*=–íô�"qú¡E›Ó0¬ÛéCd^qÓžÓ°ë´ºy}àa?®…K_úð‰ê¾§ éy-F>‰;òe¶^üê5õ~Àšî8Ó»ú8Ãmb|n…_B\ƒÞLW‡eÓ ‡ñè´JQq ¿g˜…݇Ùò¿‡ò& àán4¦4ÚônL„@lKHp�” ¹‘0�mÃî x†•[a�Ÿ‹½‹¨™§‚@Þ²:‘Ø”¨×R}â!à4F°Á¦S˜~a ª*ÌAÂê@_ºåm+´«&0¶¬b(x7‰ }ÃfÓ•¢a²à˜Ê|'™(I�[ù!ÄÄÌ*–™ÁÄQª\yÅ9‰ÍÒÑAi&’±ö+¯„Ê1Z©1»B€ÍÐõÙö�9X*’‰ð[‚âƒqœNAaËkð‚âä '¨Ñq÷– *^ã´Å.E/(<JKPgˆÂ\‚ª¥é(]‚b”G�X‚ªLJn‚¢t‡T�̵{AQIvAQ‘˜GY‚Ê8f — ¨�t!KP sÛÅäf÷‚ʰv)킊riKP )ÃØ…·''(upYŠ:ŸÐGð'ÚÅð/õÚa_?`ä€yÎÃÎ�¸Ï!g/vE[Ñ)u(*^-Å@ZR™”˜Ò.±öÑ3©a*4`�¼rHQ8{¸Âq~+ye¯!²#L9Ntt+Âå˜fÙ� ‚9¤+ÍÊoÉ»±‚™ÓNÌZÕAGwÁÏO*ß„'sHP¨š«•UãÃ’i%L�€”�ô&sL²” ¥9&3=%c¢Ìžcœ'È |è¤ÏPšc ÊŸá¶€¤“fuR¥B,›‡Ù±PãºÏh›c,²8#rÅ#�Ås¥Ût�”K°=ÏâdaÚ÷ŒÇ9Äœ3f÷‚>Dºh§bœ9}ˆtÏÁëCïCi”K0ýdi”KzSzcéC$ÿ�²^úÐ1ÏéL°›¦3—>ô¬LÊÒEª·ô‚‹4)—>¨jNI^ú€(¨{}€~¤] CÙ²P—>°®N­ºôªxР8}ðTÎK ÑUeéà \�Np2¢ Ê¥ƒÞ«;} «aiéëóÊ­�ú€sŠMßô�ˆÓx rN6}y×™.o†|Î&–žÞW†~á›×*çx•JNCùîüã*C+\œEhÒ¡ªÎú�Ü[S5öP} /Y2è%%ó�Aõу˜8Û ”Þ> <²V·œE Ž�9cô�§�`6�±[c‰JHšcªRàgHF0«¦; Es†}fh†�© G Øs ÝpŠ8¤+*<kIÒ`ÏÈþÀó³E m(,°—ñjQiô³’DkžÕ&Ž�9+éF”l˜š¬.›¼¸(sÑ`ÍêUl’ THxÖ£8„5+XæPË4� w•Izg…¤±êQ²€M‹ž5+ŽaYëÆØÐ|CïŠ �½�¹æ~(]?+V² Ï¢‡À–302¬ÑÎÄ¡�AȰ `ìIœ�³ª¥C¡ŒþYùâ˜<¸l†VÃBŸ�°†ëNG›ëîUYÿ³ô¥3Ê�ð¬Žq,ä Cž¶}£*$D”T¬®I~¬â˜ Æ¡b÷, a 9!8 ™yuÔ€€¸ršh+ŸŒ¨êÁY@{¶M_E6Ža!ŽAÔ1˵¢¨ʣƹò‘EQ9‹lJ6+š[!ŽcX¬ƒý‚m2ÎÆ½d-›fÚ*ì �Uˆ“m/VWW­ŽC̈™`œ¢ �ŒTæÇºeÉáâªÕÉÓ$•Þg=�cÌà^‰%¬˜È¬KâØ,«w§v°¬‚žÒLñªø)]߸ìB.ÐLœA3Y4'6´$ùÁDúUñSÊëвgQPYý"4?Xª ªÉ²:­´Š�€�ë£gQPD¤®*ÿ,*ñŸ¹ìŠçç:ÓxQµwÚi[6Î1—}'Y©¯â¢ª‘ùÊÚäÚÎ,5¡ö¬«�µÕUYTj²hÕV|Tõ@œ*ø¬Úž½äª µ‹�a"7_ÅG£ÊjÙ³@É1�ä²0·l ¤ÃeWL–™É]J±¢‚–=‹˜V~bµ1·mú™ VÔªŠ�#ê¥Õ1õ*Ö(™bŸ…N*Äßj#̰)&ÅCL�&ã�ÀZ .ý¬urŒâ¡«Ê1Àmp`=3tŠIñ“§a.ž�Nü¬‡r ã¡U3}GB«ˆ`pÊ“™àaò´ £Å$lW~–LŸYÍZù,«r K¯·Þê �bV<ÄüjŸ+‡KáÊϪ*Ç(º*¯ƒà+G™¡SÌŠ‡˜²®ÆõI `o¬Ê+ÇC¬ê,Ç�²’ùN>­%›³"¦¬ó\yd�«<Ë1}Xu¡Ï•g`VèÞ¨ôzU��T^`EPC"æUÀ}¶âìXE^ŽA¤‰™qˆ?Ë1)›�ô­œжм“ë,/”¹òÌb1ÁA�Kà˜zÌòÂ0ZVb {\…`‘êò,/L¶ab†‚OÁó³Í†%g’ãšñ¿iÕŠE3‰ÆPT9™CˆçI0r”ƃ©“ù-Œ„_}'F*£XãÄH˜[“fa$’`DÌ<1ÜST}a¤R뤒NŒ„­¢[ó©Y„…‘R®ôŽ#•$˲0Är¨Ò¾0R‰4P #¥ ËBnÀÂH%;F‚–õ'FàåºF‚26­{a¤Œ€å¹0�Šà‡ÃH¹Ên_ GC Æa$œišÿ…‘R"1Ûc¤œTÑ[ §0hÑ #åH^ô…‘pÜõJ‡‘2Iáua$` MÜa¤4äF‚ÑP’Ëa¤Ôå]FJ�ZöÂH ÛÖ“ÃH0t‡Ö½0RÂÞcÝ #%–ТÇHØó{ñ)±„Ƴsa¤…<F‚…W"Ña¤„`F“V¾0’š ¢ÃH‰4®|a¤Ø5za¤Ä �ØÂH ðÖ…‘khiÃH‘å ‡‘Khô¾ #ŬŠãÂH‰54®üÂH1ªn¹0H×Ê/Œ—.‰,Œ„­È2bFŠ,ˆa} #%ÖÐÈ2º0Rda£F‚ɮޥj±ªº %As¢šN”PÄÚðBI€M] ¿PR YJ¡$xðlÔ©%Á<èè,”7ÄyºP‚^U¼J‚-ÆÒ:Q  *ç %.-üBI‘…°1J*à-œ`*›âpÒ€špÝ'N–er8i@KDÀ:qR„&ÐÂ9œ4 %\ø…“€È™ð8‰UN‘½Nœ¸"hƒÃI'„ ¿pп,·ÃI#Dê.œÑ<JB,îØ`JÆ©0ã@R‡Ž¤ê@‡ÈÝ$u( Áõ’˜y!l�¤%!IðIˆ¯D�w ‰UmV·/�ó ÂŒIç£;�OÅ[ ©³ÉÃ$œµî!Rc±88ˆ$TArÚ‚H­‹E¾ Љ²è"5(‰Uõ'DÂ�"ÕÜC¤VšUõOˆ„O¢=9ˆÔØe‘D•Ew©ÅnUý ‘01eÑDjlĨ "a}Ê¢;ˆÔŽcVõ'DÒ&aå"Uöjt‘X`W¶ Rmq–õ'D‚Ì”Ew©²¡c8ˆÙ+‹¾ +ÃC$¨“è"±ÐD‚"f§"a\÷ ‘€jŸ"a-JÀŸÉøuWºjc×ál�E¸òòßþç×R[ç`YŽp&¶øÑ’ðpæã­ÃŽÉWËxrÃK›ÉW™QÚ¤ÔE ­ù쫬S´>Á^lLßre_eäD˜<ÞäÒ®2’¬ óÄNòmóJ»š­ –v5~3U™Ë¸Ò®²Ùb t=X‡Z|Í•w¥í·¤«Ñ?x®JsiWùѪ+ #FçJ»Ê ‘.ÀkTê4Mö•v•7›t�am9Ôiþ+í*¯(ºÀ˜\¹H›C;zå]Í»ZQ.6“Ä ]yWyiÑÚäÓEÚ@Úõ+ó g�/ôdyƒnõá3óú  ‰¬¯œ.M€cYàÔ„Dæ˜ÊmKb5¶À© ‰¬¦�7MF 1Ç>È¥ r T“KùLxí¥ r â œš�Hg¢€VA†N!xMH"]7_‘�Spš�Èe¢ª¬‚ =‚ˆ§&$±»·‚ =‰—&$²™‚×¹„I0MHÌ•±Â¸ 2ô " ,Mò ®"C¯Ǧ M^ÁUdè® UµUW“‘W»&cŽøü29b ¬|2òÒËà—¾zÅT¹(z¸\ùñ¤�kÈEf3îV.‚ÕU.J)ä½|<¶ò!>öò!T9ïåCñ¸·ò!žÛ÷ò!"†¶—�¡âV>Õ{+¦À\¥/¦Áúòa"r+"¾\”HÉßÊE)³ïˇˆyÆ^>_|+"²I{ùámܡ�Äm/ŠUîˇˆ˜Â^>D(~ìåÃÄÖž­|˜rÏ[ù0±À—oõ½|é?”‹^Ї<ŠÓ‡Øë^>L ²½ÃÔâ^>L Ú¶ò¡Z¶òabð·•±Sy/&‘¾|¨n…­|˜ŠnåC®låÃÄ€v+BþaÓ‡4êƒ>�‰íåÃÄ({+BÓ^>L Ó·òaâå [ù01ÚßʇjõðåÃÄœÁV>Lä»nåÃÄÔÃV>„;¬[ù01�‘7'@¼•¡2íÛåÃÍ ýÿ(ßD¾,Ö°¯ó¤|õå§o¿þúuÖwe^ç=¬ï‡ïvóx»ú$ë»VcòZ‡�1ŠÅ�ŸüƒÉE={eOŽ7ÑôÖÄLÌ´wo(ïÝÛÄö{÷6aðÞ½ÝZyèÞ&Èݺ·‰É÷îmvžìÝÛÜ{÷6)+{÷6ñôÖ½]B}èÞÆŽX÷¶'æ> €ÄÜÒvç´‘s_þòḟ‰ð¤¾ðã¢èj�#él4M' S´Ád] ,#)VaªAy2á�QÉf%�7#ˆ •ñIÖš˜Ø‚}"ùxZ#š8›Ì�§ÉÝdêQ<Ç#ØC°Aô¹™¼r[{ ij½ˆCÚ”0 $ˆè)L ²+‡Í¥êp Ì>õ,’hÉF«+âx1Çl�RXe¶<`<©�4Ã4îl./Ýø‰NŽŸX_ÝwìľxMfçp±ÅVÕþ1Ù‰tq³õ…‘à6Éa4´$L“4´Eü2\,-zJÚ²IycôbuªÉx“ï(ڱɬ„µe6†ÔtSM6ŽQÈy6ïiˆ87ŒíQ­%,©Èg�iª©3 _ÇEM¤¸TO´ç Eöʱ_w·µ{läñ"ø{é‹×Dq¶ôÑEÀ°?&wŒƒ.æXSštv9ÉÊmý_jMÝú¿ð¬´÷©ûÞ÷ÁÊ…½ÿKMü[ÿ—¬œïÿÒ]�[ÿWd÷ÜÖÿ†%WÿW¤ƒÛú¿t5ÁÖÿ+—÷þ/]q°õEúí­ÿKâZÛ¿1fØ‚ü¾«^þî5‡´~ñ¬Þà‹53.žÌ³Ü�³k‚®µ>\ÝÐzz¸º�ÒØ¯nèäÑlW7�5¸_ÝÀö«H Ü®nè0�ûÕ bümW7tØÀýêñù¶«HâØ¯n [o»º�ïØ¯n o¿ºaôðpu§º]Ý�ûÕ \ðvuCäÆíW7 zsut¸>\Ý0ÄâuW7Äcäíê`ëº_Ý�°_Ý€ 8?\ÝÀš˜¿ºÁw|¸º!´±]Ý€0?<\Ý�öpuC`@ã¯n`©j¿º!°3`»º�•¨ýê¶ïíW7`G®nˆ3Ñ·®nÀ?=\ÝgFq]ÝÀúÐ~uCœÙËuuã�íê†Hå[W70ÀدnH–�uW70zدnH–ûuW704دnH–g^W7÷ïW7dËg»«غ°_Ý�-uî®n bß®nÈ–¥wW7”V®níz»ºîæáê†b•wu+ûÕ t­ÛÕ ,JìW7«§¸«jïW7T«Ü¬«„%½}|HÓ Z¿ä_þê5›º~`…§3Â�gÂVC®”-Ù£ñj÷=B4�y:B`­ªtÆj„&IõðŽ‹QÂ5B“›¼#ŒdÞ†­úà¹rŽ0’¬�¶FhvÔuïã(Š]#4�‘AÈÓb� <]#tèÑ äÕMuÜ¡#¯`zt„›�¶Ä/\sØr¥­^øâ�¹á³uùê]·?fâʆ]‰+’³Žv �¤—)³ÉŽªm:™¥®H‡2 VØUF]2#W…T¶]–Ù-Þi§œÌHDIEB+³ë¼©8ì„F’IÍZ´Í&Ï©x™e˜ö”Pf‡e^’zpœÌÈa§ e67¤ªºîdÆÞ Ê,_mI^éÆï³3š¡$¤Ÿ1û7_¿ýêöÇß¿}þò‹ÃõRó{Ãõ‡ïœbà�p»‡Ýj�¿ÃO>l/óÎ.Õ£gC±Õh“ Ûí/׬M�íÍÚ궳؂tÊkoÄ®¿[A:¶7Y³MÎòÄ3H§¼öj5ÁmíÑ”×Þ­·ë"é¥ç‡Ög5¯]·z(Jgû¾e#æ5l–zØÃöGA|ÂØ÷½Aû‹_}]?|¶¾Î+ ´?®à=…-tO9˜Š'»;�ä•\KeªÆ«á¢uÉNÐõÁ7L’Ã{˜ì7Rv9kõBfr‘–Oº5ïíÌÝ÷9æ’íV…2ÙÔ‘Lˆæ»s�ç¥ ‡uKF6áß¡HÖ’.U€ñ9»!ý§ë>,Ö‘®ÖB£9s#à?Z —4|à^à "]ØþøÏßEjç�¬íì”?ž�;/§8÷Š] ÚšzÙø&Ö§ÆþK–7X9°l³S±ú´fü‰¬Ò€õ—F¡¹úËš! b­ntj•Œ“oë‡È]Y9ýÙ¦&b�k ëÆ?QÓ×ìSëì›w=_ä0°¨d|>óÌ-“¿xœ÷¶¬�µ ¯°=Ê¿±¼øÕw²sÇB.l<ºBør!r!š¢½ùKwE�ÙúHÖóÞÙ¥‹¢¶ "íÐÞµ¥‹¢\ÙEfhëÈâ=Q{G­ÐÞo¥{¢¶ò©Æ{/•î‰Úz©xGÑVé°{¢¶F)fý·:†]õ˜·Þ±ñ£ß=u!ü ß|Ñ­ß=[ßÅ•±?®`~tÌG¢cwžòl¶“p¦ £mNéeãê/Ú&¯ã¼ÌhNéUá%“‰ØJñ-g“Ç0’ýâ[2‡³�rÊ/‡~Ñ)Óà ‰+9åWŒ!¿È’ÔX5–#ÎÆ¦nì÷Å„d*þH<Ç)?2XË‘y _1­6{Jy#UPHìÄ™3¢·©Žž˜¨:)÷ðìu3¾ùÅ=DX ««Ä+L–3"Bô¼B`y]]%ΠÝõÆú?óÅTe=pÌ«9Ä?é€V7íFõ³»Õ¸kÃSýTÅ‚EãӺɕ$YÍÄ#G1ŽžÑC"kÒÅw2°ž™’ðf�`çzµ)°V [-r�•,È6 Ñ· °9Äœ3’hd’“˾: TcÆŠ3rw�~¬î�¤ÔoÆáá®ñr‘Õ�æÝC¤CXw S·±zÚ?/Ã![ÍrVÌ�ëÆ”‹ÒŸYÍúR¸sê:»èú™zÍÌõÈl®.D¹¸øY�¾±È fÑ•éªØ‹hÏ[ÆB7†˜^Å�c›ÙâÐåŒüeõîÜyG®•‹’FíšW &+/]ä÷¢ÈdmÍRƒnÒYÄözXKŒ,cvõaŒî‹µNwZ�o%q²b!½–6»ëú½O>›šfÏûÍÎ@~YÉ`‰ÎuŸÙ1›–¿Efxá‹ï`Y¯Ÿ]”Ö3œËjк׬þ¾.qŽÊ™éÖ/»¿«K\¢ìïóÒa­þ².ñ„¢»ÏK¥Üâîê7äð×y©jœü]]"�uŸ—ÊÓÁßÕ¥Dó÷yé¬W—Åß祳Úý]]"ò$Ÿ× —ö`~/‹í…/¾‹ØÎŸ=â›ýq†ôãXbËg>âbÄœØ_obKdÎïbã՛؜÷]lŒö½Øš×±éº„�üÁþ¢]lºša'¾‹�÷=ìbãäw±qb»ØÈ|[lK ^lÿ‡ íýô?b�8 endstream endobj 135 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 136 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™k¢à’ÏÈ�J\‰ endstream endobj 137 0 obj <</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R/F57 65 0 R/F14 38 0 R/F70 105 0 R>>/XObject<</Fm2 135 0 R>>/ProcSet[/PDF/Text]>> endobj 123 0 obj <</Type/Page/Contents[17 0 R 138 0 R 18 0 R]/Resources<</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R/F57 65 0 R/F14 38 0 R/F70 105 0 R/Xi8 1 0 R>>/XObject<</Fm2 135 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 138 0 obj <</Length 4556/Filter/FlateDecode>>stream xÚ¥Ù’ÛÆñ}¿‚U)•Á*ÂÀ�ΓeIŽã$J¬uü`ûK‚$J$°À¬6_Ÿ¾wV¹JU‹žžá=}÷(YVÉê»›D¾¯oo^½3ùªˆ‹Lg«ÛýÊé•SIœ·ºÝ­~‰>TŸ.U3Ôåi½1ÆF?Vå!]úº90Rñg8vk•G2ÂFmÃ#¥û×$ѧ*^ÿvûGX´˜-ªò,Î숖¼=V2_;À²0|µ‘¥â"My\s9ßUÝzc�ŠÚý8­‹ —(œÖº8Í•ŸöÇõ&ÓÑ[ø«¢o~ØŠv±São:<}?ô¼Èp,„tôa(·÷ý벯¸ëP5UWÕŽ·ëÒXz¹ÝÝ¥c‚i3U <Û“€ÕZ¥Ñçûª«Ï@pÆíÛŽ�]½_ë4ÚWÝØ÷ý«÷ ôõ?«~�H–KÿáÍè/TT6x5àƒ`ºê\ÖM%èòþ¾k?×g8Éé‘Q¼UÙ—çJF5»Ð*@+æ’nŽ¿¶P?Īèý¥c\Ù”§Ç¾î¹ÕUx®àÙ«òDûÀߥ ÑÜ�<Âæª¦_¬œñÊwÕ¶¼àUè¤@V ï»Ÿ>¼ýj�¦Q�í<ÚUûµ‚å/§�(�ÿðzƒÔãvŒ[‰{±ùp¬·Çà9å*¶C=í�È•¸è4;Ï©gî„!á'nø{°AzÁ�ð²4â˜�Õ}h|1Ê� ÒOT†×wª·åP“ä)Ï#ЃkÁE¤@€ÛcÙ|칟îI¹éè/YbûjZr¦ € :ôÂDÀ´Àyç²Ù ‡à`ÇBN<ëÌz‚«ôïïñ†Ò$z  ë¹á¿‡¶Ý-1o?–!’îÚáÈñ>�nägÀû^ Í5îÂÄVŸÖFŸÖÚ+>DͨIóõÜ�0Àº¯*¿T›±^å¼¹TüS¸V}Ò¿ Ñü´UÌ Ú¢3 ôúQ›<¬•6q–æÿ¥‚LcW$®x¥•-bk‹åÎ� ÂÖp¨|º]l”§¾h©ƒŪ!º`®"¢ˆÙi8 Vb­oP¢²! è#731n5€ÊÚ„o�PÇŽ¯—~�g0ÎŒ­"Öí€Ú•CéW êÉm lÕ\ÚKOJ#…�;”ŠÔÌȉh’Nøî‚‚‹qW"¿yfDz”€<¶xÌlY Ñ¡©‘)·e3à6pÈ©$.>ÓÀ …Xã€Ù¨CWnBZx'ŠG;6ýøeé`Ûžï�j;náÉðK¢P½Ã™Iz=�ù;Oˆ¿‡dÕ§Ó ¯Î´(ÀuÏ_”S´®óõÑúÐ]�‰ÜàïYo×ÛêjŽ“ Ö±Iô2¨¯ð0&]ÈÐJ°M;0pnñˆÌfŒùt©·‰ø†6Ø^GîqN§«7@þ÷Íóv�e�å‰ ´�¸/’«Ÿ™&9ÍÆXUKö׸<o…a™^Ì @BëÀ^ÈVgéHy„=å_²âŸ±xvMÄ,NíºñÓÈ�O’�ŸS«Z Õ‚wm’‘IÂŽ¥ëÜ3({noO­ïB6Å.rGÏs*2@pGv÷3¶Fビ¢6Aõ|¤©µPÇxÎE˜÷¢£38)õ&|Ûž�MâÍ)� Æ �¡91Ì$�¤Ð{BØ$ 2¸ 6´û–¿L¾µN¢à.¼N�kZŸA]O—¸»2Ä£ù�)€”Ĺ-&c–‹|ß -yÚ~¨ë4 ƒj6§héà|ž� ›!COk_�,8ˆýHŽB�7DÖ)°"‘3Õzyoi‘,œÉTO—†ƒG;†�;^œÀGþŠîzõÎ&WîÆŒ•ÎågtóööæÓ š×d¥Vy«"]™<›�­¶ç›_~KV;胉M‘¯häy¥ã"/�:­>Üü�úÅj…ŽUni&çÄù+·xÁ@Dн¶#Wæ>…X°C³ ª(Oä¢ä0[š,Ýj iÎÝkèV_?A£”ÎsÛ#Iu~zCª�FJÔ”Äâµ]DNØÕª’£€(K+‹EÆUxĹØÝß—È6ØÄxí È%Xé­›-ü²¯va£½?�êsM ûɈRIÂ6 €éÀáid)mÀ-#¹þköí›ÑþZ÷?¸¿ Tê†aý‚¿êˆ<†:О)¿/yºÙSO7wÞÓÍÁ‹§‹Htƒµðt±¥�¿ŠûŸò¯ŽyK��µ"?m÷ñÔâºÖ!à±¾«ÓÃ] {B�¥nÄ�Nà®çß²Ûüê]êž¶¾ú´év57jتs±K ÏôÀAÊ€;ô‡g­h–Ù)MsÐ˨‚Ó\ÙAlÌLÎs”:jç<ña@û®=£')fQ„Ä„F³¢XňC ]wà†c÷°˜æy/ª?²b6¹‹îËCÅжÜ1ft Â¾é‡ŽmžÃ{w\[£ã 棔ŸSà#Œf²*»ˆtT¬´'+î0©8KF…sn;Þ2øŸ:vú*$‘5Q�ÝŠ—,â#½H`C‰ÆAèr/i¹]òǸŒ÷‚ÑuÐ×ñá•q9Ûåã.ÐW/Ráqì8·;ŽûžMWëGÿ=L’{'];ƒÉ¯›†CQÇ!7vÉ}¥…Pé:7÷õºG?)sý¸«1%Aè6äñÈPJöU p¼ƒP_�…§°í÷Þ­U]î-÷G£6’ñÛªJ:4îÛº‘‘ÅQX€b:Ðñgôôµ÷7Gu¨Ž9þ¤“�à·�·“WAn‰f‡O{§W{§7°oÿ Èöñ&_77,÷ˆkÉ7!œ÷WÜ1ssGâѳu=wwªžcSXŸ’³^X…ÕBì¡4¹›˜3£y96…aÌÖûò4—W=Ðè.MÐ$ —å"V{¼¤ÜÔ÷Œûö¯?1 ï‹QO�CØ+„þEn.Ÿí;¯8Ïg݈�‰s·—ŸI‘Û/’Dé‘„tBòloõá80 ={L*úôdl_°û€­]5Ê¥y"ôÂÿË�øY·–‚ky7‚tsæ­.BþgÎ3½L¬glsÇnóÅÄ:º‰£Êý©9ÕÑÚVüCo6~Ü2O!´`?Ãè"êÏÌà€êu¶Z=]J2ƒ_tþ„~ˆ�ºú^+›D-,4Å‚4gl�y0à} ”º~À]({­êp4åGƒ˜(îÆð–Î�¸ÉK( ÅíŽ IÁ]¬8��Ìæ�}f"˜Sõ*ZTf#Ç 0E/“¿³øª“uêÄûsdÌðËÌçÀI%÷0÷A˜óA˜w[°0&@ú…U©$f¢j å]ßž@ò¸Å9W«ÆÄÅ=êyì!·ŽÆ·¥“€7 UÛTýw`ã‡-“ˆ לùQS¨I5 MJ� §ž„¡Jn€@1�'0Aâ7K6Hùùº¯šò4<Šÿ-þøB�¥Èé§r^xâ•/îƒà±,ç¿+ØK¬ JÍL>•ä¸>¦3’³µMÜq{ðRJ#.n ªî%Û3ò®ÕuR85q1¥£ÿäpgÀÊ×IaÉ_'qš^GÚ�8hSʘšœÐÈÕäñú«Fx!ýй°K¹ §‚�gb;J¨¢¯Žš¶ÞA”ÿö%Á` ®½¥v‘IÅö§°qÌüJŸ' A ³D*‡®Ü]@«<2þÐqLÑs/ë9ìøUë ˰/¤ÃOdxÍŽHy yR)blóHýù5ÄH‚Üw‹—Ê( °¸1\¼B„&Gô¹Ð¡qî1ó$ºã"“V²UøöXœ¢„.x…‹ô´c:ùÉ]Åu0ú9K³’¬LP}OùðÜß[>¥³¹ÉB‘ãé3p1Ç´3Ž B͆2¡Pnr/\€«ÏÁ-,²`RÁÍ2Ɉº({Ám6Ý¢’Á€²/¸‹‡d¢ƒó}Ô�‰Ú„½Â°S–F/Ù}bqþº]á �ˆ‡Ðk%ç-v¡ aŒ‚? Xœ)F í‚#1Ôf|Í£&]oRx'Ñœõ~Ò¸¸R‰®͸¨DаRt%œî9ÇÊŹUKÇÊ‚ ÂŽBâX!ˆŽ0~é DP&¾Š?_p­ ç£Êû â#�ºž¨ª|0¹1ú�ŠC{é¹ëú�ŽB¯u nœ�kvô­pbÑ“ †K³Â6rÓ®¥²s–‹¿¨cuºgùnœ{÷åãl*UÃ�T~_¯7©M¯<¬gË3Ö*ñ©bŸ !Îÿ€—6ŒŒ J¹û‚&Óc¢ÜÊCž ?3Û. ¯Ë§:—¬¾fy#? %¢e@Õš›Œd�€(® (²ÒÆ›1ì€ItŽ“�7ñ$€�´•v Ûtì ž7•Àw�_(÷ñTÁn~™ „iø ¤õƒ®2•Œô‘�mÇÈÐaãK¯L´7âK æ¾$�XÐk̪K´”ìó$0—²<*ö÷Õ¶ê¼ÁD£ãùY+%±btáÄ@l=ZÿœDat_‰ùáœÖs%ÈbÄf /wœ=†Ž2àfå.N•ú¯KïÅ”‹ÕŠt�ñFñZd¨1©Š5ßë&ˆ?Ó$_ŠJSsY `­O=sú;ñí Xˆc­´™ÕU)Ä�hŒz�Óºª¾'Ca±`\±C3>‘Alé¿üŸZEç*æ„úÂ…€^ˆÂ/[Þ‰ýO XYz­ 9 ë3I ¡E^Ö¥AÞá ”á‚n.õÂø2ø`ç|¡Èã06d[��¦•àrö–ɉ-åâNz+4Œ!æîj>O¼çës+;ÉÚfùÊ+®y6casyN-FWÛXYY!�u fU%XnéêAVùyíRŸÞïaÎÛÛ±Òet��¹X¥–º>ÝÄiž¤4`‚¨ÃÿJ¯Þ�õêM{ó7øç»6~ÆÍlJ_ËA¤2‹G0 ËÆ@Gñd°V.ÝÚ8J”€ËoÑâ�×úüpöw’“aÀðx_Iü@©øò€é5Gêß´a�QMsçQB¢ dC‰„0F™Ô|/&5OE»Ñã5f|gÉ�úŒh?ÄŒ¥G7?´JLl“1+„Õ�‡6áÏ~¬UN?ÈMœåãø¹Ì—>wäâ$·Ë}xw޳†3–ê81G®`3º‚õÄ‹@ŸÝÈšâ,^Q „u6_©K_àÍâÜ?êòU@,áŽõ¸TcBªß^z)î’ŽCì]å¨HPì­`ÏÂÜb‡·K¡²ò\Q¥–R‹ôå*�,-Ίa=£NuO\‘BØçz‹áÄ*6�Ð9¿;ˆüøÝ͵øeŠ7‘�§Å�Ùo :JÍK)½CA¨x´å£û‡D2 €«YÔGrñÜà ›Ïß×ÚÜ¿¯èÐz`J`Ó¿¡µ¶ˆÄ�Ì=õêu>‘ëùÆ×Ĭ³Â›ÖÉkô«™7Dr[öÚ‘7l;âKü�P²É:ü&Ý©@IÒ€vr_Á%3ë8Oýp *u"À�¥KÁ”üé*º†m…ŽVÌ—ñ}Ã}”ÖeVÍbuý¨Ú?\ìUiÊByÇ£ÙÁf{4EìÆQ F~z��Ç&•Ê·äõ,ý ¸ä[߆Ãá�wˆX}”ìò×ý©ÜŽïá7…º ÌXÏ^'Álì²qoïiW•­ ü—ðËñÄ=É�!¿�a¦ÇE©c6„‰oßÞ›cƒsˆ„‘ycUœ›ü*…v:µ[±ÖM/L7Øß)¯��(//· Š;+ì’Ã×k´zæ~7ÆA„FÏŠø½SŸ�¨t)ü’#·–[|ÚÝÈ»mÿ‚ §<‘ ûÎYœºq¿ßÍxævmŒs+\<LþÄ—æ Ìrýf®€°o<˜Îb뮲ÒÛcµýÈïmá:Ïuß×ô`ýf:�ɧ‡ºcToð1kWm‡–*²¦ð ÆÅp¡JHÁ<Èè„ JO^0¦üSÝ\>sàù÷w| ›ì%F†®–p0pŒ[±~Yí}õýé“C~Ä[Èâô4·ò%©ƒS6¸Ã½ ýÞ¡‹óé¿�p<g&Öǵ¯£”P–ÜÐz÷U endstream endobj 136 0 obj <</XObject<</Im4 131 0 R>>/ProcSet[/PDF]>> endobj 132 0 obj <</Producer(GPL Ghostscript 9.10)/CreationDate(Tue Sep 27 21:55:29 2016)/ModDate(D:20160927215541-04'00')/Title(diff-ops-writes.eps)/Creator(gnuplot 4.6 patchlevel 4)/Subject(gnuplot plot)/Author(bharath)>> endobj 133 0 obj <</Type/ExtGState/OPM 1>> endobj 134 0 obj <</BaseFont/KPWIKZ+Times-Roman/FontDescriptor 139 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 0 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 667 0 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 139 0 obj <</Type/FontDescriptor/FontName/KPWIKZ+Times-Roman/FontBBox[0 -218 932 688]/Flags 32/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 139/MissingWidth 500/XHeight 461/CharSet(/A/C/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/q/r/s/seven/six/space/t/three/two/u/y/zero)/FontFile3 140 0 R>> endobj 140 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 5716>>stream xœmX TçÚž23nT‰S‰Ú„Z«­+nj]Á¥Š ˆ¬" „E–°“„$$$¬k $,BØd_q—jÝÜŠÞÛÍîôööúqïù'x{î=çï99œ„™|ó.Ïó¼Ïf5c±X3<£„ñ+ÜEQAÑ–ÏËéù,zÁú6@Ñ8Œ;sÞÁ\ªØ3Á 6˜aU½ÀvȆ^<ž~ jfalK¬=á$Бą‡†%Ø}pÈÝëÃeË–ÿ÷?«íŽJþ¼bç,Œ�¶[̼IFŠb¢„Ñ 휘»##Ã�Ù…FJbÂâí‚‚ƒ…Á–¯yE #ìv†G†ÇĈ’ì>púÐn�½ýêÌŸõûãŽ&ÆÛMFn·_ähçbç. MŒ ŠûÿW0 [¿-Ú[ä»#ngü®„݉Ÿí=ê"9¶/x¿ð@ˆk¨{øA�ˆC‘Q^ö«×¬]·þ#» Ž|¸Ãb0GÌ[„¹aîØbì ¶óÀ>ÀabžØRl;¶sÂV`¾˜3¶Û�­ÂvböØ.l5¶[‹íÁÖaë1ì#l¶sÀfc6›ƒQØÛØ\Œ…Ùb<l6›†ÍÄ>b‚YaBì1+†54eÍ”örv¿ÕÛVÎ|N3>Wã¿«ˆ»d 94uöÔ¢©¯§yN{8ÝyzÝ Á ÙŒßfÞ°>dÝý–Ç[5³f5Îúj¶ÎÆÎFes“»�ÛÌýzNàœÛsîÍù7¥¦~y{ýÛÒ·é,ëñ`‚Þ=ô»&Ö¸§‘:’¯Ò…=DyôMÛdO¤îE‹SSü²ybèk$ü’õæ²üòB½`�Nå@Þ³¬,F ä<'U{æ�bXLL( Ž‚4C™9Öt0Ðó.²ž�BçQv½�*Ê×å–Ò\"ó \¸+åÞ™¤ †ïYh'áIâô©š²V@ÕE~*@B¸(¤>–›‚ „oaj"¡„xpi›¤tï.þSB“ç+ Wz¤ð&SŸÂäã2¾”BibüBv…$�™RŠ8ˆoteÿËø>PÃ&Cqk®9×Öˆ.Љ›YU²‘�²Ð:[´ZónF¦w&“ºÜH¸HŠA-0Nt ÀéðÛï�]«oU8�ñ€$Ež“ ”9©– œ1žE2]à0ò€ ¶p1Üsó‰©ìF�)…ÊL¯1³¿‚å_±a>H¡·í—!>šÿíbhm¾ÿ'äù«¾Cs 5zezqŽìÚR×�$�K¹ î‘ß ^¿Ç·_%ï§íf1Uf�c´'•“8IxzRJj2H²|Y‘o…Oñaà"÷yìØ'\ а²iýY÷«{¾þ ü4pí9)©Úæüi”เƒ¦ÀN�¡È¯�d“ðÓoáTøþåsIǺù-‘qÉd€¢*¥U¥j¡­¯Ú<…‰¯ær3Jèw¨’\-(äI­ê°`"Œ�^J¥k:É],…÷H±5WQ >#áj¢íx�ª�pÚ7Ð ¾gíøréÁ€¸C‚"=ïPR˜ÂCʃK·RM—ÚmA$bûnu:ìÞÞÄŸŒ \^ ݯÑ6f›ºW0et.W'èM”CTI0 ÑìeÈ -B6Ÿ¯y=|±þt¿�¹à DæœAr‡¤PYNx”©‹A/I§$¶£/(Ÿ©P©ÅÇS#A$ˆÑ%›"“n‚Ï™Ï?|y½ùønæ¹Å°¯–tŠ�6?�Íå&Яá&J„û ,0½ÈÜj´ùÙ¥ ’„�®$^�ƒBï@ÖBY®9š)SÊR‘ú0æJ‡›‹Šøp>Îô¢FV¹š<�gÁ÷8fœ›+&¦ëå`9ÁD¿C.ÛÎDï,¦;køŠaÔ&ëñ([KÏ£ÊóKrË�y¢$%@€ò à£ÑìMe˜¢1»ò¥p™„‰DKß™†¢’ U)¿B^š®d�¡ÒÜšd ŠNpö|Cdäy&†*\Å JÏ#¼ö?y†Ññ0…b R7Jd™Ðß·„^h }Á_„>òßÐwÀA©Ø’ÁТÕHl.�—ƒû$Œ†ïÏA¥¬ìcQ<UMª‰^iRÔØœ½ïÎå.‡·á-*.à(ñìì4MÃ-^:På) IneqbbAìüOܽ�¶{é'>Þ–\"y"ïðH}�˜Ÿt"­Vq™LAöz\«+ÈcªÃu)åÙµ +ÓÍ ™UóGn ß=ßz ]€°¢ Ù ÐÀën6\n _SËÐ+DÞMÿÞÍj�8m÷{ÜþN¡b Þ—U–U¦6¤%€@}DDì�qB–@îmþºˆß?t½á6¸†Ä]¡M¢Š˜ûÉZ\ C9‰xºX"O*�’/Ñ1øa*y½‡– À¶^rÜÚù½N¯�œÝÖÝFÂ�\)Ó’Ö°YuŽžÑb£‡hø—°˜¡<÷ÎbH⺜üt¾&-=M£zú¥d’Ü—JMº&cÈÊÍÎÏ&¹wΣ ø†¦À+C�uçZùŠÒ¤8©*ðBd Ÿ `Á}ù nQM#ê‡FÖïcðÒ !¢ 'î—–ŽhI#j#šR%pšìëUê&K_›�ÄÖ"…ž&x^B^u…vý«S�'a‘Äawýq¥¼ÜæÞ(ÜÉäVIÇŸ¡2peé€�~�ÖÜV)q=«L|H”J�Q†\®ŒIŒL�dpÄÉ^·>E‹åÄé¬rð'Q!ñÉiï] ü¾>ŽÁu)È>cj/=[γ�Ç8nedA‚É�€, lU¤nÈz£ÛŽù)åàÁd¸Êõ£L¸gÄÄËŒ2%ØÆ@ÕUuÙ}˜¶­³¹ôüàù\î)zÿç”Tžš!d‚¦¼_�™ìÏe4ÊêÛ�®€\±Í×%Á”\[Wmª)È)ÌÑ ²KrŠ�–lh©éjˆ>ÄßO •û¤ê@ab²<'¹Þ.ý×ú{ªÏ]ãsõ^…UI=óO‚ê²¶NæZÅhUdFZRj¼\”–È0ÑÉ>Aƒ’žv8³Ÿœìádr³ÆØôêñ¹TYŽ€¦ì25H‰ QÞhZo ƒ˜KKŸ1 vˆ‰'ée àü'[?±ô®ÍHl²ŒÙ$<@ÔWÿsáã­œA<ÈåQNP‚ÉY7l$¼rå:û�æÛBwèzûfEñíBž&›ÛBOÿŒug&ÿ� WŒo¢2ò‚d1êà ^´š“Bå�- »KÒ‚DäËãÏ íœ߃omy½d¿[¨o2ßÓªk°ýÜ“3›�5bûíuô:R{â?zÜEÿòF¢bè»p;%ÊdÒ°`‰ wãÛEm:Š�÷ÊËŸ2©¶ý¯¦r ÿTUW1ÝFœ†Û-^E�Ò×L,ZÄÐ Í—á-i)™9éYÁRÔˆX”^ž©¥<PeÐöå‘tTNÔgV*‹¥G9¶ùjC”Ù§"Ôâ d .Ò(yl¢XÒAZžªP¬•H¤$'Ço‰ë½uú\tA�WÒËõ-¥ºº|ža÷iN#ëÄ›^í)¿¡ñßû ¿^¼÷¼]¯ Ñ Š‹EU’jÀ«¯1Ö^Ú1¸Á×;9ô¨À'@´ |B¢·Ÿ®„ìSÝÍíü†:cCÓÒú�™ÿÁ«Ÿ®c�Dߥ&|˜n§¾é6£ÍÛ m~ÃÔ{zýC 2ü;‘‡Rè<òã/2ô©`;9±”�‹äb‡tæ{©M—Ö‚_Hz  &9帥ëç@=ÍÌjx“GÙð—œãT’œl�ÈP5Ãlú3rü¤aª½R^ Qœ[ŠÙQ¢:*@ö„°%¦ô£ŽÄJÆ®-Ds­ƒS.ušO ö2”µMªJ)IŽSEÒÁã| r†>>?tØSÀp@iJ³dkcÉvm¿…¦´’¢k pU×aÔ—ëÊ :-ÌN�Y噆4“¼$ì#ÑWÄE‹9h‹ïåêîÃäÄ>‚ëýWÙ. ¸zz?“¯¥ew`t $ÚYôrè@ùm ŒÞ ÜA`côeI§¦5û ¯áꛪƸ–¨vÿj/àK„á‡�Æ8Gñ﯇Äw�®@¬—�žÀåTé““×À5P'Ò¯³0ZÞNÿ»�u’™C›!Άÿw ÐA´€18þ+Zì/¸ †]¾ þ;ã¦|àhýŠ~éqUàrgCû2¦ÔV`@ÒqÁ·y@Ó�«bg²WZœ4.!!,ìˆÄøƒ#UaÍ^Ça<3ÿÐ;Hvõ Õ\䟱¤™Y¿2m¼n¡Ä[ÌÀ66wV—«¢«ø±eªJ@Ö«jÛêìóŒñ�ĨCs6’Ž/Ð-lW¦:Y|»ÞÀ¨«²<"á-hM¼q5ÝðLã2~ƒ)�5— �À~ª>»2§<t}uW[Ú¯�ÏA¯¼3¦ñXÿ:ó •8·’a²Z§ús©U[4o`üI¾Ì¢àÜH:ɪA«m€ó¯^´ÔÕÉòܼ„Iÿ}®5Á¹'àñ®B3Ë|¦Œ4˜ÙôqÚ–êÚL$3Þ9Y›Xl£‹)ŒäÊmNö. ÂÏ� ĉ4=ãx´"™Ó¤²Ôždg¯˜ã „ô|ðÝ£'õ½çø�Í•- \?Ü»-QE¶žyq% ˜ZÛŠKr´9ùÀ˜­Ï) ÛÐÜÐj6´�3 1£VÞB"ÍÄ<ªUó,}�_·*Bݶ#ÎZ·ÆþZ­¾÷Œ ~K]1· 4×K£*øUaeþ ˜<æ èæ÷–u�é_-µƒ K-GÆ—)a~².ú$: ‹loé›ÊZZê�½`ô):b…=õ–z6âÜSbâ‘Z§üs¨R·Z�ßÄ�¾�àŒeó!.åÁ4t�×ã\ï ?úe.-‡Wø$…Šùþ±aé˲-V…AÍtC› γy2ö3уN–Ug•GÆ0½,OŸ[xu“~UF�'•r§!*ñi¡Zgy$¸´7L¢bD¢šscmM£9¡6ZÀÀFÞžh¢QO¸ÉæÞ+(ÿe.w}�áDž™ TJ{ňl1Ém- )Ž˜¤Ç£Ã"%AÀ lì?­\ï Ï=!,Q&�xr·�ÿö5.¡µ?oBaœœëbÌ-+7Ìg,|¦QÜ$ëìVwχėO}áqÙÞ,êÈ‹½�×OõŠCÛøÍå±®ŒžœKô�½,¨eü…v£&²ð‘Ré`ÑÙSŒÅ(�ë-£øqP#©ESÈ:<næL\ÃÓÑfN^YµFhÈ7»³ƒ�õ‚qúãlŠ©[®�­:…Ÿ`"‰Ù°²²œ,N_a ’s�å1ÈoãAÚ¡ù™yYyYùY¼bU~:È ÓÒÒSùbŒ6àù‘Æ ³hô´ml¸÷ùõ�Æbž¡ <�!r±Êñ®œÒL ê4¹<•Y@­mi"3O˜­vKáE©9Qê§Ç�¬ŒÁõ³iH—Q`¬¬â…ŽQU™ÅNT$‚%$bw—F˜ã·7r+p¾u1ƒ’M‡e |0iŸY a»˜xšÎÂí$ºI mÏáfÈzÔv»‹_×[2�FÞ@Šõã(ÛÈÔ /Í-ËefE‹NÎì™±8$W¸d0UP—‚T¸HÒ¯™x½¤BÕN)ÏzÜÈÔð�s¬W£ÐÅòbé…”>¿ØòD}IŠŸ�YÎ�ÌaΈ3žy²RÐEÂ6äë´Úµ}•m€ì¯ Û!@Œ™8¨Tº[àš` Üse•à: ‰¦¾Öª@^®Šq P¸«Õnæ&‘�ˆÍ‹ÊST�.<JÀiÁW7»yǺâK.‡7@$wp!š<oq¸ÒCƳþÃYiŸibýá`ùõ‚™»g3ª” $¥ÇªDh6úÆÙÂ×Ù…i59ù¼´êt#(uµº ¹L)MbârŽ.íäÆVG[;Ô†Ñ34U™•¿RS®=›ÏÜ’-&Îf$+ࡉ“¶œ±ẉ�þ–ëÌ��çJKÎë,ð“×�ÛԳ꾇úï-hv <@�4$Ìí �MˆÕЦì8? ΂¾Êö¶á‹��p& ƒìá»h.?+–=ÅÌq!Ø­_ð; †a§ û•à ¾Ï—ß3±`ø+6ì·Ì¶Ýö9QVXZP�W¥­,`ð^]"‹XìÊquBJš,MždéU£�ø$7EN“ô¯ ÓµYðëWlZß¡…!#€‡Ô8ü:ùm×cð„÷óÇ#ïyx% áG„Ë"¤ÎÕ¶Ý?¶·Üäèe÷ ›üWnX#@;‘'•žg9•¿__µ�÷Ÿ ïÏåÞ�+àÔP›]—v=±Ëì$7¸ïÙ“¬­ áGUIµ{'“'…õ%ÞyZß3(ì©·ÀÙ”ÁèæäqY€‘ÙÎî žè¸0ïùÞK«|¤¡ü¨YlâC¦mσS­Ÿòæ©�—PYh\œ *J$Û?)&¸ä³õÛÀSO6�Ìå~KG2Kùû´[�ŽnM¸qö“h#ÁýenÃÑîÒàP¿·˜Zy}ù) ŽßeÃOégôÆ+@A^¾¶óKÛ4­,I•‘ÄTIˆ#R1-dó2 ²Š[º5Š>$BÎï�ËöoÝ”,ÕÖDñ#jtÌî-O�Æ?½ßpöŒ`àTõeðÜøœ èw¯EÓª'ñc¦­X'¿…_±i÷ñ­ÂUnâíÞÛìŠp€æ�u kû|:.Ä_g,̬WßA>œ³ý9"’4BA\­ Wדè(ê¢^�qb(0%xÿ޵‡^ÃUg‹Í&ƒ º¢¹¤ÍâWò™'ªMôƒ‡,úCž wEK*Õ}·«ôFáÈwâ[ÎM†�/œ¬‹yÜÚlséñއPtÇã133aMP?�oë·ÉNW— ÖÇ»í÷£[Åç~‰0ÇÄÈ]ó–>Ý9pÆÈç¿ò¹#`$|ÍüŠ”,¢xÕ…‚ƒäž#GölñþÛ�šÞáAþеf8t�\"‡Oõ|v»/`§»èˆ»�Ÿ‘@f–¥DPÕG[™YMß°¯$RÐJÑx{è�¯ÁY�Î'¡ã*8QhúšÅh>²¾ÿ1Ä.öVôœçEÛ-�%á8N�äÌ4eš(>D È-~�àôËW«ë•¦¥�€üÛ©õècèÆ™X§¦�f˜¶Í/*6Äßy]Ø’I&s;>üûû=~õ‰ç"Ê*l7~&j‹yKùü ~Ó¿h¸n¾ÞÔ~˜üÏ!Ðï»í žnªï¸÷·¶Ÿœ àœ�ÖŽ=[ãÕ’šbûÌ¥!̼µnwé°¼§pˆÙ/r‰ ur³´*Ý”òhß5—øz—ºÕzê¸Jž ë:ŸÎçVGÔŠÛ‹´¹¹E|n`ž€ÜùÅEéêQÈ¡�u²‰ö4AÞ4íåô¦â3^V͘‰aÿA~ÿ` endstream endobj 141 0 obj <</Font<</F38 34 0 R/F77 142 0 R/F48 143 0 R/F39 35 0 R/F40 37 0 R/F57 65 0 R/F7 98 0 R/F14 38 0 R/F70 105 0 R>>/ProcSet[/PDF/Text]>> endobj 124 0 obj <</Type/Page/Contents[9 0 R 144 0 R 10 0 R]/Resources<</Font<</F38 34 0 R/F77 142 0 R/F48 143 0 R/F39 35 0 R/F40 37 0 R/F57 65 0 R/F7 98 0 R/F14 38 0 R/F70 105 0 R/Xi9 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 144 0 obj <</Length 5605/Filter/FlateDecode>>stream xÚ½\YsÛÆ–~÷¯`Õ”k *é h yÊbåæfóÄÊdª’<@$$bL‚ �FÖýõs–n,d“¶,Þy°Ø8ÝèõôY¾s`1»Ÿ‰Ù·/ÄÁï_/$üŠ™œY5³2�3!g‹Í‹ßÿ³%Ðÿ9±Î³ÙµÚ̔ұ‚ÒzööÅMÞŽežÏÒÜÆifÎõ fJƹÌ\_ݼøìZg³,ÎÓÔÌnîf6‹µMa2ÐLÏn–³ß£·]q_¶Ws•ˆh{wõçÍ??»¶vôŽNc�dÐ75hª®üC$þIn=Açq.¤o½(Ökîz×\É,Ú.ʶ­ê{|ñÅë›Ñ"•±�a.±JeÒ8ÕÉd™78|µ)qdèa.Eœ'9×árx)fÒMœg©_ÉB¥�å&q’(ߦõ{r°´ÔÆV_feVÃö¦OZÙ˳ʓXÀI=}Z¾Æ×Íù×?Ä×6‰ujŸ¼/ù1_§Y§ÒðÚß4=·Í�H£ÛGüµÑ_¿u„ònÛ”\Þ}K•W2‰ÞãŸr±Ÿ‡öµ«¶5óu·åßë_ß¾æÒ»+)¢²©KÇù‹í²<ÃïX½ç÷ÉòelN³â%u¬8TõœöäQ§œ¯Ë4{§¥&>/‚¡1Ÿò‡ öQÁ{´èáè›ò¯}Ùvü�¢o»(N)ê%ªºêªb]ý‹+O³Æó§ÛsÆx¾úg\`LÏã1ÓXœaŒ§:å‹TÇ™|–fMTœ&ú"Œ‘$qî.ÃoWœ:œ5Ê™§pðø›DÀ${T¹H#®ÀÂb»CÁñèZ'$Y°bß– —Ú]±8'J.°ŒžaFë€Wìi†¹Ä žcƃBõŽyò¨S–�×Íù×?Ä2šëô"J˘8Éô±ÒJ¬ ¥•X‰VÚâÝ]ËÄeQn¶õ««yšH`ªÅz¿v ¨©×ï;Ã2g¢Ò> v.°´ž�ÆkS&NOóÑ%Fõ|4Õè³:éÉÃN ^—Ú>‡‘�Ñm~Ù£T »yÌH¬švëG.Þ>>Ód¹À”{ÏYêXŸf�KŒêd<*œOr†Až<ì”Aàuû,›E€y®.c´`3‘‡ùÃ3YÇd®Üu¨wžÅ(˜{Ï(ãÉŸå“K êùd<hggØäÉ£NÙ^7J}ŸÐÛB=ÇK`Yš>yÓØB’ç±Lzß4WѶ+Ö§™äS‡1Édì$=c¶\dTÇ%“Q¥çLݧ�;9i|==ÿúô¤iÖFŒ� zÉdœÈ|tDÅía•¦‘ùüj®�޾¼J’èo��`2xëïéês£uÑ•õ¢"Ø(µ¹à*¾;‚‹¸Us¥ÁµöÔq�µ£+—!† •“t¥@ݵ_mÉÄå¾aKI‹¨-ÿš?4Ødn¾ÿj.»Õ\Þq³‡món½-–üT,š+“DÛvj29Ge³_wÕŽ¦Ï¨6ýCÕ“¶UÝy¼Ì¹vÿøæ›˜ÎÜCÄ)9ì¹JqÏqŒ466q.ÜÍ©3N§y„C\)Ør²Ñð Òh»+ò[|N¢{Ü,Ú(®®Q£cŶvo8ôs‡Tå3 Ê Øç+“Ã<À–IÜ<~� RF?Ã_åþ~O%ú›¾“a!¸XöXà«À0`ÁëþãNßPw¯©üS SPƉJ>ºÓ¯©£_èïkêúË+“ó(�I«8ö£û¿Æm´ *zKÿšu ¾Êh+æZ±�Ü=ÜH8bßt<ó&«ðžXFË´Ç#¿€µ‰V[dš©ÐIŒ3à²É)—[7 œª²*êVt/³¨ÞonIÓCÙÀ“égàÿõ»óÛh÷¿£¿g6Œciü›Ž7[‰î@áH³,›¶ŸýnŠ{¿*¸Ÿ¨7^UʽÕU^7]U÷+^�u( —宬—åÒ�P3Õ­Úm¶ûºiÁ¯ê 7;[ð7ÚL�{ñÕÜhX6 I�"½ÑvœK0‰ê¶ZÒtrÁwôxK%\$«³ó›ªNmª62°©0öê¬Ýž¥i,ìÁ}p"lYµ‹}ëdXY,V\‹%�T¹Ê®¨Ö$âh&úÜ©¼_Û}±&Q¤[aᇪ޿Ǣd›i^€µÁ-ɡǞ¿¿Ý ÞŒÿ9¼ë7n׎÷ÈÀUIúïp^wC@ýMxi|C$Æ�d½e𽆃—VñÕ¾ãF¸=ø»Ý7ÜtAš IÎ_'U`#âR-­o÷ó®ãçeå*ê­£´ûÝnÛ¸vã;ÇØH)º®©nQííq_™V/ƒ¼KG“؉�Ï `êÊݪÂ^’,zW³lY—Ë{÷¢ó °È>–š²ÛC_NðÁ¶OõÞh¯úùí¯oÞüüËMàÌRvÉÜ™Á‰9|}å˜d¦Ã1ç°~¥¾ ã˜8KúË÷Ÿ¡Å\&\~‰…Ø8£á-ÞÂA]Ø’LE¿1÷èLG{v±�*™Ò­(Vâ%C2Š&¤K~d[#LNæ ÈT¯GnVnˆî X°×�Üfzð4/X²õ:ÕaQŸä±µÙ'Éz‹áÊ b ‡íVEÇƒŽ¯U‘D £�矃¨× Œ-,éí=,3£b‰/ÜÒjS’H¦Ô 4€“²?rÑñU¹Àd}÷ÙÏ\h«•m<¹8©ßiºYùßÛrQìi H¤4‹ƒ ­Xb Kž5uÝîk»[WcÁ`rlÀÌ +<W¬Fƒ§ÏO|5±4¾ú°ªp>XQ4®m‹;’[¶,YfãW�$FA&Ðç—Î4-¸US¶`?3iºø"Ô}S,Ë |‚„ãÙõ©�¦¨ïI.Aù®Ùn¸ô‡RÀs/�ºÙÄü%N*I£¯·›¬pÙ7 6š(p“NE±Qflmãc[Ý×^ÎEQw¨í�xG§ñ�[ÂÁ&¶7ËÛÏ™éoËî¡,k®K„øžKlº )ÕŽÄF ó¼E‹?Äž|F"aVÖÂ+£™b�“y¡hIÔÇÆÐ®“¸òÖÏ� �(¨øÉ]_(ë Q´fE�·Í2ZôŸè=’A—O1#¨‡£é¸D±Sh±£�‘rÄÝH\V0�¦{ô¯sº‚ÝÞïN±¯ rUöýWXÔ¬¬²ˆC ‰Ó#ß,lP0Áy¯!Å‚åõ©ÂÑ$É�p„²Àv_î¼èN3ðSôÁ�h¶ï« p¡7#í ü4QZƒ§Ÿ©™ŽsåчcäA"�[ðWÀ5g�LX«9€ÆÃ = pØÜˆZ…4(ƒæe´[ZØÁ ¤ïMÉ¥Ñ]eéøJÒ�� 3;Ý¡EÙ \}:ÌÄŽ¯7ìsn? q¬k÷÷÷< |£[Šß¶Ìév"Aðëć�ø0C(°u³C†�¦æï@êµweCKR cŠÛíÞÕ9vF*ù,*ñ> ”ð6lYÍuÀJþ¤À#&ÂÖ|Ÿã"‚§)b¥{³cC9lšÎ?�ýƒ7*vŒÌíÙE�eÂX(£LRG†ÚÕ 9¤v¶nAX½[r]Í$Z¯‘…™.üò޵=qé=&åÓ]À˜p®ÊhNÒàÝ£¾JòªB’×Ìé(Ž�mŠEƒXUü�S*šj»w„–²§Ð̬7ON˜ÞÇæ±4±2«ÀƒW¡£Ð±}ÂÑ�Ç&rösá—)*ñοóƒi§Óé1’¤”¯ûÉB‚b¿¡€ǧÓSv̹)È²å ™¿äó©�ª® ê.:Îqp¼ï’‚âÀœA1Š•'κ;Ь§<Gl1V:XÁ!÷/Bgc4NUç<U�ÑT‰àx JäC[AH¡X<ް↋5h«=N Ó訫®à¹Õ¡¹pÆß(ìA:5ëGgõê>¢«]â„�Ç 'oÒ)}�åħžPmÍ%«L�÷@‹ÌÍW‹cEªÏQàš¾íÊ5ëo·­Éܲ³Ø€îlG qÃfÙpnÀ¾iš8û%Í s`Èj‘õë7¿raßU}F È@_2¸Ê·>c­0ñao§‚ÉÄιM¦Î9TTuè gYþ´[œŒ- gÕ¡$Áy Þà"ƒn2Šl6ct”ÆÙK¦Ð<‘íåK.²tÆZ–ÎH«ö k‘�^1TÑ”ó°÷Q.Æï­‘™rÍ[®l†Vb=.ÖlŽåh¿sE�˜ð#«ylÁÌ ¤¶Ø8Òݶù€y~�=5 ØüÖtšTì"ùZ­Ç&ÙÄu)°ô{¸iHÃM›âü#¼?;Ó©Å,‘,Ú@0H<H ò$Pji" (AËâkøõ 'hC@�)å»Å½™xؾr²Ý#¿ 8¢kX�kŒ 5ŽØV›j]4LåË{xÀªGúìä-ÈdœŠþÞ8Ëß§©=‰c“ “6´¯·;�Xàõ,¹æ€}¤÷-A û&›=ãžݱX/a]½ŸNlÎ'ÒÐ �íK¦²ÈpdA·ɃÇë4!kéjëDœÂëÞ¾ýæ{Î(Xo#\à„[�OçØ™t„O�ñ¡êVdBŽz™ ÊBö•00øŠ=}ä;¤±0ǰ(³'>ìp€¬�–@HŒ}|"Gë„—ìÝEúÑ'ÇÃ?²ï5o?ÖH÷HSpޜνH$ذ`ß ’Ùu£Sî‰O°ò)5yìòS¢1jûxÊ)âX:N|üò˜êA%¬¿ñ áMÖêð$¹~Œ â3s}õdЂc4¹ðý…f›ÏÕOváˆ9aðZËdŒØôà2��б‚Äg�º�ÆP…¤¼0ø¥�.¥ƒåÐÄ#X ËaÒ#Âr\DvØïÝÜ4kÎn§Nz¦WÎ ðvãŽÃˆã§=aªüe{ ›lk¦°B†)d¨p+Cm4éz°ÌR›ã¯31� _ k¸x]­Ë[°¸WÜd»k?kËE—¦@PžA€¦ä€ 1(ˆ¤ÑUb 2\r�ÒK2Eãõ•‚ŸÝL¸9K/(€t|¾ƒ‰Üð•ʦûŠ„Ûm×­ÁÙ_¼CÛ9]T÷<n9þä£vPÀÍŒç0\áÍì±½0$/�Wº*}Œk4 ¼@xü]µÕ­»i³€ù] ª$:�$pîÒ±5\TÜT_xžîúK8?vYË×3M0ìÉ%úê#$ð}²„ s¶ÈÝ”á'Þ™·‰wæmrtsB™ÖJ×ÚòHa-­<‰9H]Ÿ'V;›^g“ ŒÆ �ÒÃü°lþ•ÞVƒÒb߀¥Â’'À£cP“Z3¢‰ÅÛ¢ƒrPN [#&&Uœ+52m¼)Œ!I›L¾—"Îc�X*øç$Ö¶‘LòOB–llŒ"X¤“G±j§F8àjH�‘ŽÍdOïxK@úbJ‘ǰ(‰‡„k�ÿ4”@{°%n°Æ R9RMx,2Çr¿`Ö§jç%åiœd*€€KP>À…åp€ËÆÂÈO„ì`VÇ.j°QðÉ'îO0Hš{Æ졬d½*qöeCÐ>�BûV°Žä'n²’– Ae4ÛÞcÎ=ähU\ÆdKBGKŽ+§”�ÙC/Ë=Ì v È󆦲ї¾b°/á�7úœ]§%b5¢®lK2vÊvµ]/¹šÉ3i:PžLži:'ŠÓb·[WýG7Âza%‚Ñ+gxÙáE£ ²"¶›²í-2RXË“ºàùž¥­Ó» $ë]$‘? ¿(_q¥Ïå—‘3œ4\µš›ùPˆÏÏ�:4>}! XÖªÔ ±TðÏIñ‚©šúSSzÄðQäÉÐpÐCØ 繘1æ2—"‹�<ðëú B.tüœ� X”îÁ9.ùÄ}°: Ô˜$°ýÄåå:Äæi';m,ÅÁ²� 2ïi Do²pµ�æàÈä¥s@Ê®ÏÌÙ'’b¥dØ#ÁH©óH°è0,’«‡Á”1‘$ì�`…äŸÓ‰˜a‡TážûŠi^ÒÆÎûuµü„W…ÑRõ¹8…?d±ÔLS/Ïã"Nòt¼ùn†YœI0°á¸"³X?¶•;%<“Íømå=BV¥>�œ1L%"ú±ì 'z “ß®lÒç…f,è@#Gß—•ì-Ôƒ{eFù]¹„�z[® ô]ÿ®ØÙr1¤Ü a{â7tQØ3ÑÆÏ1àNmªE³�OòYÝ~¸ßuÕºì��“DZ xÔQÃ`es¿|ûbö;UÿÞ 1"xümÑÒ5êÏ w"[çÀG ½ÐØŽ³»0‚¶�¬¨oª;œÂ]ÙPÄ ßïw$˜À5cÜŽÅE¯x°þ~ëÞ¹/k']÷SxËÅ?U>ÆÜʼnБ•±±=óÞÁºÚù¢™»ñØLKÀÔËûKñS¨¯X B¯[…ÄȲ!Øìë–çY4!í¢�GO%òé�LÄÒ6ÎÒ³9»s6¹Iÿ?2šÅ�¼ûoI>õÿ”LЩ©ÿÁ®¯ysx+>�לt¯—Éf¦£9•>-ckz‡êº?\ä‰ }Çó ç€8ÖÙ�ˆŸòi°_+ÇŽUžfìÉJe¡$;“ö – F²>É)}xPŠpƒÃ<8\Eš†òà ø¯= €œþV,8) †@a®9kÕ‚Xÿ,L ×í¥ 4¡|Þ…5‹G¦“KJU›Ø­Îñ›|Ö€�˽û?81gŒá#¦Í¹ÿª-Ý€`áxe?—»¶+ºbÞLòQA8¶=3ùA0Q“¼' -V%åMe”Ý­8Ó,–ŽÛñùT¬€¾uõœá›©þÿ¡ Î0àŒF¸4RPÐ]X´oÜôlýïVIlm0 ¡åI.@o;ÿµJ¦{X‰œ�-ò  Èÿw‚:Ä %¦ës\ùÌM™Ò§w*ÄW\ Ä|“iÌW�ˆ™H{¨ð�ÆV¸kãáëÉÛo)íÂäÓgá) '·ìàu¼�;ð…cæ‚ë vâÕ ¥æYêìfº/­ ºÿF ÝIä"BT3qøeQÀŠg„™+°fËšŒú°ª©0¿?ôQ‘”øŸdÐõRÁƒHÿa¤�.¨ã‡qªã/§a>`)À�Êô¹I‚W«äó1Aô´]¨,ø©’Ï3¾pß x¬¨ ôSz¨I®JÊ«%¢»˜¶—äÄa.ø‚Á¯WŒ~¡Pá×é›’ )âqûµûð‡¤,~mxë>üá�Üûí–‰®²-°»~ØœV™��é®G ÉÇò!‹Ø2ÍTàK!†ˆæÂf¶à:ÿ¹–Á}ß´zê“»s‡ðÑjþ²m*öö�SR:;ЉBa¹ØÖ¸I˜�×+=hÏ’¥uxãCœ�ÕðG@þ™ètæ�Û£œ‰×7/þkçó2 endstream endobj 142 0 obj <</Type/Font/Subtype/Type1/BaseFont/PIADRO+NimbusMonL-Bold/FontDescriptor 145 0 R/FirstChar 40/LastChar 119/Widths 146 0 R/Encoding 44 0 R>> endobj 143 0 obj <</Type/Font/Subtype/Type1/BaseFont/HHRWSH+CMMI9/FontDescriptor 147 0 R/FirstChar 22/LastChar 22/Widths 148 0 R>> endobj 149 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/file-reads/file-reads-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 150 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 151 0 R>>/Font<</R8 152 0 R>>>>/Length 12549/Filter/FlateDecode>>stream xœ­}]³lÇmÝûýó˜TJ“nô÷£R¡Dzd‹Tå!•[¢Ä$<’%Fåò¿ÖBïÝÀœÃZ¡X¥;s¦göG£W/� Ø|¤g~$ü·ÿýõÛ§ÿøËñøÝwŸÚã_>•ç|üÝ'~þøå_êRuÍÇÛ§Þê³ñõ·Ÿ¾Üþô»Oü”íõþç×o�ÿô•þà|ŒÇW¿ýd‡È�&Ï©ßÏÚë||õöéß=Ò¿ÿê}úâ«OÿÀƒŒ‰Ÿ¿cïp øû¥=‹~­?s¾~¿%ü/$§‘ÝQöÛËaæs¬ŠoÖçÌÍ”¿þ©Çã”vnßü[ŽQž­âú¢öëÏöþ(½ºkÁ›¿äJº<óuyŒU³·ÉÕ¬t\ÍLy[_õþÿ>†ŽÐ£¤çÐ9Lãñ“ûÕûSW¤>jzö©ÿâþæçóÕ}øœÛضýv¿ù‘O"çùÌSÂIüì¿øÛ_ýý9�–ëu|ùcŸBÓÅ]â)üâï¿øù9�9Òu|ùcŸÀ\ÏúrýÅW?ýê«_Þç "ýž‹ëÍ�|"í™^æâ—_üô?Ÿ“h°™ë$ö›û$:�Nâ¯~ö«/ÿË9‹UÖu|ùcŸÁêÏR^oÃϾøé—_ÜçPdµûN\o~äó(Š)ëõNüâ—jßE{OúöS©£Ü›Ró¹s˲ONáé'À©õº+ÕǺ‰ôÂøùŸßþéë?=þðÛÇ_ýÊî‡è/KÓoðë¿Ñ{õõÿüõwÿç;|ÈßMø²f™ÈÍÇ�~õ¯ÿüõw×o>ü÷2êS¦»éM°ŸÏø»Â§î›ŠHÅþöwücØüÌøßñןH/þÇWÿõ\˜(èLÝs֭İ×~á:I‘„ßÏ}Ü[�¸CüvÉ#çë ú•Á›‘ìtÇLË+ÑOæzÌÉ¿ÿÓ?þúÿîOøóïóÐËýó×m¿û”G……¾¸·,ÎåãO_ú-¦ïãÏÿíñûO˜‚Qëj-�™/²â¿¡¶*la¿ÿö~¿ô¦ð=G_ï¾ù”»®=„¢T%êðÑ’ÊzJç¤>`¬·çÈ%Ÿ©ê˜œž4Â<d“Îú,zK Ǭù,8’ÂH_3ó³T“槪8§_Zj35c>RkС:A�Cô3½«š Çè!–ÚPrE¾¡‡(ÏLœO59ŒÑµªÇÆ™Ë�¤œuª÷]ámøø²õî(C¨þ²—ˆýÈuÙyèŠIâ/{©ý¶á/{&¥fÙ_öFw.{‚$,wÙ’Òxæê/{öüœÓ]¶ÎK{ê †ËVNÛÏeKêÅ&ê¾lL÷&Jÿð½Ö÷å§‘ UZU˜j—E¾ûëglñûöiôµj¿¢½íÏ·í�¤ë\OÜœY+:1S0Š.3ý‰ª§º:?× CRZÑ„?žouþ:�‹_ʹ—ZÐÀˆ�Rõk©ww�†=·øƒÔ©SY§;HìÈ9HË:‘¥ìûê¯}Þø|ý×û¥¢iMû£ ojkû6üÑgîµû‚Nµ®ó}¾ÔFøšcö»o`±jjY=�Æ/)œ €ré"5«Ÿ†7ZŽlc°ûé*Õ~33½ì¬›�L[ëÊW î‹âm¦Á!µÂðFRÓ¬Æit¹êªÕ3QÎ!C°âº:#Ø0DW½nø:ä‚®”Ÿ©<zÕû1ø+E'^g5§–ŸÂ%¸daÁõÜt•ògŠžÅR£Oºp!c) ÷GÓKKY8D¡L·Üµê³s†u15\wkºüepÌÒ£Êcéš*?£«©bÁµ’žjnSuwÔ YêVèÌpL¬´–ôj[çņ´K×øXƒcÔÀtr±‹O[§U±¡LÝ;ª3ç-éÂTŒQ:–ÔÖúcªmèVéÕG!¦fý'qªZ©ÏÕ”ùë?TÉ�ß/“¿†!Š ð; #EaŠšø(•C¶üŒ¸ Û2>2šÞÀsÍÔýV¦7šª(hÚe4ÀY"åe4UQÐfiÛ €i696SÕWÓ q6�Íe8›©+“ÄVg2M!‹ç˜ 0V¹˜3™¦žº¡Â6l^kNg2mÀåg2 L¦+âô2œÉdì¦ÛÌd:ØŸˆ3™œ:·¯c2]çDñÞ™LN‹Ûà1™® Uçt&“³p;=63ôÖ�QœÍ¨·§7Ò™ÌP;KÜŒ.“QÏ�›»³µWâòe3Y¹¯|ÛŒú±Ï.×FMï\±=EQP­øÚR<¾ûóçÐï 7Agqc^^؇7òé åý—Ï™6ìqžš,üÀÞR³‘µa�7¦)Þ-‡zK�¦ C=.¶¦6\< ·ôË š@½Ésjj4jäõ–M®õx{»®# ã {%©Ñ`Ó&ì5ŽQ£Q.r`¯¤º°ëìqiw5µóƒ{%éš]Ëp�·«ëJêõŠZ!¦”¨gwtèR2Þ¨W²ÚŒ3P/““ÉP›2Þ¨W`QcêM±ß™ì8Ô+JK`ÌD½Êß™º”€ŒêØ2Q¯Û¤ªMoÔ+:³Ïa 78™È•è=?˜2Aoqª¦¾.Þ¨WôþáÂ�z5ñö½7Bž]Í6yÛ`yvWÌ`âmƒâM»·Ûbäm‹æåé ÆAÞ6@¼—c0ô.ƒ!èy{9˜wÙ 1¯4g/ô.{!èɱ—y—½òȉ/{9�wÙ oÎáìå@Þe/€¼l«wÛË�¼Ë^ym8{9�w !¯Lg07äm{!âIqörï6 ^ZÎ`ä]Èk«^�wC˜Q¸ò~@äøÅ‘uOðsôo'õŸ¿þýoþçï÷½åù{=ÊwŸyl}€ß®©@â<ʱ£Æ—9vØøö0%9�òz÷Íñ¥zã¦õvœ­±Œ@6Û9;Œ�.ÜPOŽßÌÀNÛêÍÙêc¯â㇚W‡1³b•èÏx@£˜çp¢ô·Ç!S«Ç$¿9_$ÙêR¦6°jxÉçA‡jlÎ@Ÿm”�LÇ›�Œ%ð¶¤íBê¢<”éF ç`¶S7zÙ—}ù»€I»ì¥P�àëön—=•'™ ¨1âaŽßX²/ûò‰Üo#'Ë6ú©ëÓüñƘ…žB3Æ·^§iq§8Ó¤dA1ÎMÓRHœ#LS¶Uz¦ia3)~šÆ"ßrÓ´”êa5�iR”åTžiZÜpü4Á�éßÓ´2®ÎM6ðå§i%Þ#7Mj­/Ó4'ïõ5MØá{Ó4ŒïœiÊëêÓÔøsnšÀJ Ódûš›¦>Ü–Ÿ¦Âk;Ót<ö÷«[=öq¥§^|ö÷ÿÌz?£ß>én}û®÷kóݯQ{�ùnO^¯¢åq´õëì_ <¢|Üt9©tœukåN<•‹çl÷ ‡\Ç(ÒõGzQ—0_ÒžŒ x:p›^OfêîÓg='¥èÍ?'3¥‘wœ“ÞÃÓ8'3‰ÂâN¾PÒårNF½:=Ät'Ãh@¼§W4`œt"âÊŸÒ™(ÝgoÐþàƒÏ!öŽ\Î<GÙo”^r�Ù¸ýî›+íb“wpdñÖ#Wƒš:Bzƒtº¦¯°ª»…íÔøáÔƒúpæ49¶è`µz®5#ü–¯YÖWÀ˜eqFu=�=K³YÆ« îBPwO'Hù¡Ò†ÂiÖÄ«©ë^2OF=,DokÏäƒ0…ÂWØQ¶ë¦. n§Â#ÕÉWØPª�Ÿèèn, ÌSÇÀ ÕWØPÌ»ËÊ-ôÕ*�DÇè/â6”1lŒ_ÆÄ”ja \U}…Å<À¬ ;R+êŽqVª|…�6™�­œ—Þjg6KÇ0Ê 7¶Ñ 1F‡ë¥7]‹Ð¶ôñ »Š…²rÑáÕ(]&­Zz3ñ »Šy’êÐp[jJ …!ÖÕ3_aW±€W.“Ûˆ_¡Õ-�Ä5�Úµ—…ÉU'Em¬�ŽÕ`ùJ�”†OtLE,ÝÈa'Ì \¿âƹ¨‚¸fWôD¢C2ý)õ‡t1s„ŽÕݸ7D ü 6)æ4¯5W„™ÕcÖ%¨¤’c*2ç:F¯Ý�Ú1¹¤˜\úõÄX¨MD�˜[õò€6fÐETÆ–ö…« a? µ˜¢bZ n í´émÒ y”d�Ký¶ðºõ¶á Ñ»$ÊTwÔQÐ-Îwˆ æUÝVµ±Î]ëÁ/iì²[ü’Ëf:LYï/[7ï}ÙMG«i#¥r«ÊmíÈ`{Òñz‡ú¥†]ñ …´.ŃzèŒ=Ñ#…Â=ð…z[¢‡ Ý5�7Tèm`ÇA…Úá䆊Ütk.*’î¬À¤*tRöaIéL÷P¡“›±Ÿ;¨Hm¨ÈÈÎé¡"UFFTè P*IçEû� ½[p¥R$�Ý4R¨ÝW\¸CŠ¤Ûœ:)tý$\øA �¸¡7ç …Ta<H¡˜ .)t= g7R,µ�#R(.0Îw�b©%×n¤P|)¸ôƒÈMŠx¤È›³Š¥Ë™é wͼ¿ (@äÔt@Qôûà•7P€ÈAJá�B=ì)¦®Õgô …èå€rßH1õ®´Ü=Rˆ~F§öBŠ©w·(ç<H!p­=RèÍgØì�…T PL�k=€Ã ¤þqÝ7NL½mP¬œðq81ôîO@É D 抡s¨,>�…Úoª(F·°¯Ã „%–É¡‹©è¢ 8ÑxÕ7N�¯:ò²S—¬+l|ú{ÿçÏ‘�k0Ö}ÍÑÁËî㈓ô€¬äŠÝhûØ!ÈN�zÀV5ƒP'ä°• ¶ZÛ!ÎVÿ!Î"oEÜ­Î2úܪ†[m$â=–#ÂP 05 [ ÙFÅÜhƒ-eÇ.FÄéÎ>Œ¿BϘUö*H àLµôe˜Õeø Íjù@ÆèY‰Ñ›¾—�7´Ä@«·æM´ñácQÒfMkAVSqáaÛTû,>…1zö.`ÅŒí *@¿¬¾™-î„ë^Xœ¶‘ér+`„ž¼‹iѽc< �Um)dG;!+¹zf.ªEÈø¢§YqာaK¡($�¤mïŽyÀø"‚&£ã‹°T×ï&±!zî„#�©¹Ï݇ƈÕˇÏè†3tÄ*f pKn“wŽþŽ Ÿqï>ÄÆ,3Ã[À¬fZ�·YváˆÅº†Ôæ£pLD¤Ù�Yjs¶#.ºÐzî;�°ï Ãaˆžü Ô1tÓpyð¸²A3\xî}_8\r©#ÍcìFqÜØM­6FO¾nÔÊÆ¤"D,ÉÈ lˆ¨ ÉdƒÛ-WÂNå!¢Nª#D(^�:ˆ¨ƒËÜAĤY"tj#" »È"ªò,€Ñ�ˆÙHúDT¡Æâ@„r ì "jn"¦�}:ˆ¨‰" 3‘Ä:ˆ(`Yâ!b,’aeP¨q ê Qt_ªÕCÄè¤æ"Je<ÉAÄPz©§ê ¢¨Áå�£ÐSpQ@³²ƒˆ!ô7DeYsxˆ‰ÉšU<DtDû<D¿ÓCDŸÙ¼‰"D�[¯ÜADïÜ’",ËC„R7óm.ˆý:Ë�ˆ^àzˆ�LÕŠƒˆ®ë¢/’ßsÑs¢ßr B.Iý�ˆ†è®‡ˆ<Þs1¡tYϵˆhN¸‡ˆ ’å!¾Ìš"”'âÂDÀ%Â…ˆ€5I€i¼ð9óeD @á ‚Äæ¦)/áýŒUûˆØ|ðÁç¨ÍN'Žco.‚cãÅ�ÇÒ<‚aéÏ›äÀ[é�ä`é¯@r°¬G 9¼"�,ëHNÓáÁ–¾L�ä4P ‡`pV$�œFÁ´G08+Å#~$gQÂä0 ë~šW¥šƒu¿ÍÁ¢�æ4ð Os(¤Zžætd<†éÒéWgcX×ÑÅÓ�§"�ætÞ<Íx*%`V~÷4GàªTOs°ò§§9O¥šƒ•¿<Í,êhN³p&XÔ+Ð詆©?Ò®ÎÆ°�쬧9gE<† HVÍø*%Ð,üîi¥'5ЬüéiŽÀ[é�æ`å/Os(O�æ 0 ‡a‚Dß 4gêhñ4GD_¥€aP¹OsDô•x ›ð�͡ʥš%L÷4G½Â~q6†MÝ2§§9”Âô@s —Y�æ¼Â„:ædTL´~…pŒèè�+ب‡ øBžèè]X^þCª9¯ŽÁ„Þ†öâ aøòDGo'¨æ� tx¢£“BÂê`ѧî`B§¶ÐÕ90ay“º.ºK&¿žê¨¥5z]&h—§:j±$óŽê ¥]ÉQ�6$zCÈ-Outù�ªCu�9žêˆÚ7]ç )óê&Ô`ÍÕ9T§ƒy9ª£ `Ó¡:½Aåå`B±Å¯Cu:˜—§:ÊòT§«Q'Ou$•ñâ A«²<ÕQȤ;é¨Nór0!I—aõTj–¨ÎRë.�êpcTg)(ä@uš.·¨Îêt´Õiºj%P�æå©NÓ«I�ê@3Õ�·±LÀ#é�êÀk™&–¢zªß§ª3YÉà©\¨¨ÎÔ©Î�êTŠYL¨Å¤wTÇ—²#W’œFYÚ8‰Çïùì3”Ç}ƒ’¿SÚ°ß Æ‹æ=ò~ÿÍU)c$º™K‹8KÜLøÂ˜[}�‹ñ†ùÔ(Bàa*–ÛfôthÅî}¢�ø;VæØ�Ã|j u+uGó/,â<çSS˜[?ƒp¤ <,m¡”N+}ú3Ô è†5¤UNr^Ë&Çä¤.æ5Yø[Á”Ó<Ò¾nÆXáÓÂù²h¼0ÒÇÈŸ]8cµóaNÜ0’•íÊeÓ™Ã1gÐÆ4†úÔ¡  c&s8‘{ ÍôD�˜ÞcVç¶AÇÔÆ�uHÍûÂÊÖɧk|_áKRpHÁ¢Ò-�Nò4’e.8"çŠ�u„¿ò–Ï©£c EL·ˆ1�I:í¶ÞzeÐ�ù:2!Ð�+§óocƒ~êBʾræ ”ô!u™LêÒ‰ýê˜ô}åÈ; ƒ<·*PW/A¤Ôd¢|aòB÷ì¬s™/iXTZµaDU3uü›Åºä-�Æ”AÎÇ(£�B?£ûsKÎt·8£¹Ñ…�?fëìÊ‘ÙQ›´8£yõÍ�ºælµÒPÔ&·§�½ ®ºâxüxaZ”Ñ<èɘ_®8šÉÍ¢EíL·][»2Bºp%Z”Ñ4™[˜ÂØØWÝu�U{d˜Ñj0„!“9¦7£Ä`_Èȸ¡2Sg •‹^´E·¤ƒ1¿–w}…Pä¢@Î £�M·˜_Ã!9dq!Z�ÑÎfZȯÆ8 lƒÆ~-ê ìl–ÅüšÕ´PEÇ…hQFÛæ’ýiªËÂ…hQƽ¯XГ³•v• ‘QÆdÛ\± _Ã1i È诇…÷.ǘ_·BŒ\‡Œ2.;›n1¿.ÅT>B™‹²@Fíl†ÅüºAEg‘w‹2Ú˜eA¿½‹éõ,únaÆiÀ¢~Ç4莾3Ìh>bQ¿ÎºŽÙÑw¸ËÆ‹úuÊõ }ÐVF«ÑšD}ÎHÓt>º%pZ”ÑÆ¨™@ç3¬,ˆÒ@®C‹2Ú�Pê1KY”%s‚l^£v‚ëV9„!Ã0õ6DÃ�.�^Mݤ háwT"6ã…j&[-fW½vø¾ÀÚ´ñªÇ²3Ù±w½ïvAºL‹eÅGb¡÷Œû¾‹KPQDMW6q“, ½gP8«©@ž‚Ú0‡*ÉbïTЮ‚k*­ê²«Ö ÎÖ!¥]¶ÞaSlYÆìØ»N¿]5ê÷p6c˜¦« ‘?¶†º›§ BõØbBàÛ÷TAVoZ  H¬õCJMëž* ±¦»ØM JàèÍÝT�‰µá¨‚Þ«íÞT™5Љ›*(9*9U`fm9ª `öiyª�Qõä©‚,DÈ<U€âßSÔÔšãxSÔIÂ뻩‚,Ⱥ§ (.P:TAí5Û•ßT·I�€C1+\ù¡ (d@¥ÒMnÜêCR³ÔýMÞ\öT5ÝSÝAÝ8T!A¼–U W~¨Ê3ÊpTAѧÓõ>T!éå ôö¦ ŠÙÂÐÅMÔ*˜º?TAP!†ÈM -uSA»ñT�U'ÓQA-ZvT!/½âÞU –~SÖ· ¹SÝ;TAÝ‹F¿ï¦ ºã0¾v¨ki¤8ª #3Lw¨‚în6y¨‚ÞÜÅ+¿©Â†ØÑ‚>0¼©‚E26UàQP�øM, ÒUÐÝŠ¼nªpÅUU æW}S…+<sSå“}S‹òG¤ëŒá¢oªÀ`êsnª \&!~S‹9yª „©óº/ªp…®U�¦7 ~S…+v¨Kû¿©‚EÒÄQõg cà7U°€ÜtTAù$¡òP ìUG¤e+ý»©ÂŽª Ô5ãÂoªpEUPŽ<û¿©Â­<TAP‚ØÿM,è9UPÎÎíèP žO*$ÅQ…+ë¨B…’b9ªpsU¨PdÜTá ;ªP·éC®À²£ er·?Tá P;ªPs“‡*\qîCJcŠóP…+Z~¨B©Ì”ªÀ�;bχ* ßÀpTáŠÜ;ªP2Ó¶›*\áÿCtËäEßTáÊ"8ª “äC,!ž* ¼"G2b|ÔüÝT�"pÕ7UP8°uè¨BeàãP®CG Â'‡*䊂•¨Bf–þP«];q !ôRwôCqõ£âµwþ\ÌãLxIW¼/¯â5Œ8Åkê+û¨mí(X”ÒŒ¨`¶ñÉýé,Ê¡JT°(¶¨`ä CÔV�­,‚Ü£S°(2—¨`á4‹ Çé,œí `6 91[5*X5%AÁ¢¦7£‚EPV,jÂ,‚²¯`°²³T•‹€•‹ AP°pQ‹ ©,\ÛAÁ"HŽ{‹"D‰ AYIP°(ÒŒ¨`‘iuJ.f[S AaIP°XYˆÙ K‚‚EÀÊ‚‚E�' AØ+X † `!–‹@ ,VR;S‘((XtoéQÁbex>µc¥z>µƒŽAÁ" eAÁbµz>fËj¾ `t}ð î»^ÁbÕ|>µc!µƒ¾AÁ¢4 G‹•üùÔŽ•ú˜í+DÀA»,‚ÜzP°ÐÉ Awƒ `ÑÓ—¨`Ô8‹:œ3æµAÁ¢7³z‹ â"(Xèü‹ pÃ+XèB‹ ¿ŒƒàwP°G ýù `QKlQÁ‚~4QÁ"h.á,‚M)f+®?¤u°¹‹.¯,Œu‹”µ¢‚…1“ `ÑÕÞ‚‚…¡— `QÐHQÁÂNP°(öô¨`Я`Q“¨`��˜ý-2£‚EÀe‚‚E!µ Ã[^Á¢¸œ¢‚…Q² `Q|ïQÁÂh[P°è>‘£‚…A» `]`QÁ" ‹^Á¢[V‰ ë YQÁ"`¯AÁ¢h 4½‚E·á,Œ‹‹nç#*X^ Ý©%*X¡}§`94å5©³²<?R°|ôÁç¨ÍNé'�co.‚cãÅA\"¤¦‘Z», l‹ ;,‚ ^P°îAÁ"È‹@� › `Ñ{9½‚…aŸ `ÑY“¨`aôÈ+X”ƒõ¨`a*¤¦‘G –’šD‹ ,)Û `ÈÛƒ‚¥ õë,º.JÄ05­,JÂFT°”œVT°è:ÍQÁR2¢ÐÃ*=ÍÑõ;‚‚E�: –’[Ž A >(X ÒôAÁ"�¸{KA¶?(Xô†Hİ’…4gÌ,E@,<†M…,¯`)",ê²×¨`)RzT°´AÁR¤¥¨`h.‚‚¥@—,jÞ#(X ¤AÁ¢»_Ž –"C ›º¹‹RÝ,ºÑ® `)ErT°èâ.QÁRJiQÁ"ЉK)º­‹@),ï`B¿4Ž‚…‘Ë `Ñ—¨`aä2(X àAÁÂÈeP°°Þ?úBÈ­K� Ý)XØY (X díAÁÂÀ¥W°èÔJT°0péaBÿF ã–AÁR Æ-ƒ‚…Ý‚‚…qK¯`)(xñ†pTOuؘ!(Xô*WT°¤‚‚…�Ë `)H3 —^ÁR�­ Æ-ƒ‚¥ ã,Œ[KA�‡W°0l,lm½¡>kT°¨%KT°°‰†W°$ƒ¼‚…¡Ë `)È) C—AÁR�› Æ.ƒ‚¥ Á,Œ] ;ƒx C—AÁRІ.(Xèm =’ `¡×â,‚ôŸW°Ð÷ A1(XèB‹ , ]‹ §ùNÁâ‰Ë Ù)rwhC—* í€ì|ôÁgÈŽ„¹ÉÎ~³¿ÞÃìÍ7wCÑTv)¥Þ*˜ê¬xC.ŨϰRJ½ß4T¦| º úB(¶” ÓicQ%3¾–+h Q¬�N³1¬ª|0ãKSXfÅ$ê3, ¨VCeÊ×н›rMXI©HH;…Ûa•”¥L“ṉ+)Õ¦i§ÌøÙ) U`ì$v2,ª|0ákd§¢WWe_=«¤Ô�¢Ê¾Fv…HvÐ"í…J;eÂ×ÈN-”n4´™¨Ö§&ÓN‘óµRÊR›I7ÚÜ¥”br¥–ÌùÛ©húø‘]JY2«*ð5­”² Ó ØÎì»”²dVU>˜ó5¶Suµ¨¥BÝ–w/›aÞ!’¾FwZ¢xƒ�š�Ïd Nf}�î4¡x£cì!Ù³¾Ã†L²yûTñ@Ð0!ÙÕX0Ù±­ýްªòÁÌ/Ó)êRÀ�E}í9ô¿™ø]6d˜€àÐm?A¨šáàjE…¥- 8Økï9ˆx“¡M«*,=QJe¤Ø^+VU™™ùåeu¡‚½9¬˜²ÖU>XÄm³þº¬ ú"Á'º–• gKwËJO�];ܲ’N…ÖYVÀ>¸‚gYA–†%s–°¯†eÙ/–ÞYV�ílϲ‚xë÷,+`\Á³¬$³/®[VÀ>(Ÿe•Ñ™È/+³P |–UžLl»e…˜ ”ϲRD&98Ë ±5”fŸe…æ¾ gY!FWò‚Ðìà,+ÄúPš}–ã`gY!d¨$Î-+ô?êaY!oƒ 峬J"²_Vˆ`’ÐÜË*)[Á.y–¡¨P>Ë*)[=8Ë Õî—UjÌm»e…¸,ÍYVP÷ƒœe…ð.ÍYV¨˜~Y!J Bs–UÒm üà,+¤nP½–•n“ÛäYVˆZ[7½¬ÔÓerÛ-+,™á—•n<Ln»e…¥GFs-«/Ùûl‹ÔgÖþ—7¶ZÖ###šs5¶úÓ~ýõwß}ÜÛJºU¾|Ü/ù{?�ÛöãîˆEø=šq:&Û»«Cò5ötLf(hÝ­ƒÅú¿¸ŽÉz³’åÀ®ŽÉb½f\ÇdAâ°ùŽÉhÆ<ÙÝ1™�´é;&ÓåÈ®c²mK¥Ý“Âáâ;&ë ZÚîî˜,H.vß1Y�®¾c2‚5ËwL&¥úÞ©øò“bÉ�ˆÞýõ3Ór�}C!ÿÕ‚È^ñÖïϯöCÊB_ß©f{š#+›Ol§¡y0r¡y0„æÁ¸hZ§ëúëÕÇg¥»ø¼þù3—~CÉßõë|ywïYéôîA5f¿[õ¼±Âx WPñ ÷¿ ö4z³:BkiÙL3ÁÊRŒnVo»d‘=-·E¬•�†ÄV¹o»:’M-—é!P,; ÀDÂÆ„ˆT-Qd�Ljƒ\‰ÒÆ‚WiìNs7µ“y Rv/ß±vWо›ZÖ-£I ™M-›i�!ùfSË¶Û *¾é_Pø‹Éš©BW˱»fôÈÎÆ"— T)ÛZìb…1 "pkí[¬ ��nhÝbŠ�Ì�»J•±»•Lëj)&¯b€T‰™»¼ Â4µ¬»�cÎtíIL¦õ^ èæ¯>ïÊL*QùmâTèžÙÓ-9ø#B‡üQЫÇÂÔË §åÚ-)­9Ãe“¯­Z½‚µ/5Œ|ð9;>ÃY(—î5³ß\5Œ6îÔ0Â.çÕpÓŠ8\�ÖŒ ]ö=ZY-2|�ÖŒ\==Z­.ÅõhÍŒ­ù­Vã{´fÎ|�V+¶ñ=Z3ƒb¾G«öø­!¯æ{´Z ‘ïѪçEÐ?=ZY®T]�V%TÀüÓ£Õê¢|�VÊŠïÑjX¾G«I,|�V«öò=ZMÎá{´Zá¨ïÑj²×£ÕjB}�VÓ§ø­Vñéz´šÆõhe1gõ=Z)ºI¾G«Ujú­´gg�¯U¹+…nœÇ¢?øàs} §6úd4ö›ËžWrý†(æWÏÿµû¤\�Öá„ßi��Sè´«»Në–ÐiÎÓ �Ö!jì¾Óz/ú¸žÃ�ONßi½«¶Ði²Ø:­ë´<gè´Qh �Ö‡@¯è:­C~:B§u<a¡„NëЪ&ßi]×�Å_®Ó:”¨ÅwZWRÄÎÕ®Ó:ô»ÍwZç#$tZG9Ðô�Öùˆ…æ;­Cš}§õ æ0C§uÔñTßi�ü0ùNë¨Ñ®Óº®Š]§uH6“ï´N{>¶òsÒÖ÷”\}ôÉçØï5žZ—ë¡2|yJ­0ÆZeÜÂq‹¥)¶aWÍzµ*K ÷¨Û@¯èÍr¾` uoÙšÑâ”ÛΈ1¿L±Ø¸:‘5Æi`ç;õÆT6Eik7=›dÅX-;ËǤ9Ì‘vs5i†Þ>]ÙD&è!´«Û÷É0v #o�!é:‘¼l1c¶ˆP!Á¡à¤�ûwz/¶,ó@oÏ:¶lRx�pÇî9c" 5 l™5 )(ŠÜ+8Р¾Ô½'™`”aðw9ÙÅ®lð„ÇQt±ŸaŒû‘áJï.ú�Z+ìæ¢Þ¶ª‹æ©y�Ÿ�ò$LÞVÓrv Ø�x�e€ŸÊ¹c&ÐæUˆûhîM.¦Î!‹)³×ËØJdj^»’$4²ÛR*¨ËÕL²eµô•èF¿m•”^9û�$+¬t¡Çþ¶%P4F俵 }ðÿº;wš¼éÁ®<Ö%þYA–´ï¡T.QòœIÇ0D8�ƒ xÛº$Ö…±Â•RxÃk]Œ¯¼mÍQ{X_£E÷ »£×¿ä­ºçô²ƒRÛú~†ø±»/Ùú~N/»5Ygjļ�õi½3!Åû,)ýÖêÔ�;¥³½éŽð³a�ûR˜"Á“ÅÞlþÍ^ƒÂbPŒé”üë�åcŒ®æßL:â )³˜ùp“…(¡¦¤àY¹¼Ä�^”“X•J >øà³îû=œÚ�uoÈûÍ%1°qGb€”ØM0-Çâ ½D‚ÉdN ˜z ²'˜–6ò(yE‚i ªð�¤,Á´\Xx@=LË»…‡�ÔT#Á´_x@- &³‰ž` úz‚iiËð€:W$˜– hyD‚iÉØð�j6<Á4]Gx�õŽ`šd#<€b‹ð� 2üC�¨¤ð€Ö"LŠ$Á4!Å+ÁôÖùN4c½>ͼÿàs}†s·Û¢÷›[4c= �.Ï—¼-šQAoÑ�Þ`ÑŒ?F‹&€‹¶H§·hlÁ¢-¦,µÁ¢-~,[R°h‹‹ÆÖ,ÚâÒÁ¢±E‹f<X47ZÿX ±Þñ΢±_‹¶°~°hìûÁ¢-ƒ,E2Á¢-y,4Ä[´%æ‚EƒÍD‹fÚÍ[49‘·h$Ô‚E0«hÑÌ–½³hg�¯™Ñ²{U¿äEßýù3Ö|f ]îŒ(²G–Å€;Ьu¿’Ÿ š7K¨ï�þU—[v« õ°ìäýŽªãÃ+xw€ tÿ)ä§%[=-k…͈Q]¤Ë}†ì9Ô 5bÔ%›£°KÐ{šDɃ½XýlFŒ² jm¡k3mŽU¹²ÒÚÎ5?#³­lî¦ñ)ì��ªn cô,Ò[‹Bl¤m‡±J›Œç€âY«ˆÕž²Tݬ•8­3(ha¬‚©BÍ6w«@§HYòØa,ŠhÆBìØ¬¸÷n)éI=ÆXY(‹ýiÅ}1 `°8S·¥üÿ& Ð|”øŒ?÷õŸ¿ùǯßþðûs?ã{?uF¬GU~—ìCÏÆW>Wp= ò׳0væ`?ûâ�ßϸ’ç! wö`\«±º p²×îÌÀýp„“=¸Žpeî'œäÁõäƒ;3p?ØàÎÜ6¸3÷C îìÁýЂ“�dÏa¸²Ëò1WðÑc 2Z}Øöþƒ~À$¹¯1@}zˆì7W�ÝÆ�ö÷�cù¦Ö“=è\û{ª¾\k{ô\‰­í©/ómëÙÜ%´­GH6´¤g™Ø’°ú̓õ¼ô›ÇîzÉg´Çi¡C4V\èÏš*å®O<¢Õ¡|N»Ýâé�M/ôwÏè/´Õá—?Ÿ_Z·gk"éZ·³ÍNhÌŽ®I±1;[úø¦ëÙºbº¦ë쪣Tl¨Î6E® 2ZN…néÈOÄNèPQÆNèl½dOõ)ÖËLY,W ­;!êíô5ŒÞÓGõaïÿüCìúú’µx»Ãèý®ãˆt„{ìš�â‘ϧÓqï/5`YÚK  <c‡bPß¡¥¤¡ûpÉ/µ[yÔ—Ò,]$/¥YOÂ�ƒKm•…RÜØ¸¬—’*Vý††¿U^Ê¥ød–ØÌ·¶X Å*æØ¨—)ÀШÓ± oK/EL|®Ml±Ë„dh±‹gèÄþ¹�ÚÄê#Ôœ‡Þ¸m½T¡º=T å.¯UC© ÿ„*&„–ŠÕ¶åÛ2ß…Ï»|dÉïþüC,ùúÔýò×ñòŸwq–¼�Ê:– ês*ñü‡hÉ =±š1�mKíñ•Ši”hÉä<¡ Ïdˆ–LÒŠ Ñì<X2ê}£d6à –ŒÞµ±8zˆ`Éc¬—Â?T“DKF%n(êcáJ°dÔ!Å‚=ÖÈKž½¾”ã±'Xò\òRjÇÊŸ`ÉKÒ‹%³È(ô5«+Zr�¨6X2Ô�Ñ’Y9å-Y v|oÉ·e¾úé%;YçKøüãÏ~5<ßdœú¨?÷›N·‘¾sYáK×¹ I³Ð¹ £Ð– 9³Ø– Uè±ådбådS±�JâC;1(´b¯0è—c¯0¨Áb0ˆ“c0ô ˆ=¾ <=¾ q‹ ¼Ð¾ 6ð‚š.6ç‚d86ç¢j94Þ‚86ÞêÖé͵ÕBÿ‡ØV«[7×2 ½&bˬn-Ú\;,t´ˆí°¨0÷ý®VJ/ý®†õVs½¬�Œ½¬¨›�ªÐ$6ª¢D?t¡Â“hCªi Ï\Û$c‡)ÖøîQÌ ÆîQ¬pðíо%t†‚"t}Ò9_º>AR;:!+;:-k æZ0 ÿ�ëÖ´¬7˜k¯€§Ð†NLVqå»,!#º,Y9Uh¡„Œ o¡ÄJ©Ð!‰â7ß!‰UP±û‘à…îGy÷Ù:í �Œ��òî¢uš %_è[DWÊAÔkH}|ÏÓÄ?øày»ã´áž·ßÜ�õáƒ�¨�ç�мõÊ}3ðG¼ºÍ;ñZXŒ²­r? š7‚B�³[£"«ßƒ&àR¦áëd2ÑÊ�d�‰4| L%V]ƒÆ8ÌÅoÖ¨’ªçaÐc" ·Y£jœ§Ac Un³^B¬º�d�ìç›ß»5ôå< šyÁý€ó{·†Œ³�‡AcŒ%\U$£ó< ASi¸Š±T­Ðt? c,åÊÁ „­çiÐÌ®d+Òºj½ ¹÷à™IÖ•ê.ãÊÒM£lƒffpZ(¿[; H„¤Þ³Î÷þæ|‰AëSŸ·ùrÄmÊ Ó— "js³Î‚GJÅ}ÌÈ: z|Åþ W:Šî]¡÷B6�u<s/¶¶@È&°Î‚€Jh[�'êÖYÐQ+¶¤@Ä&°Î‚vY¡ÝäÞ�u<å.¶’Àcî<ë,èrÛDà v�uô°ŠM  À¬³àÁs±ÁäÕ�uôžŠÝðT¹À: zKyÖÉ6sžu–jO8¬“=äë,xÒ[`�%Ùƒ ¢Ë|K¿õ¢¯Ñô÷ük>_£d>ßð¼ß\Ñu»ãëÐG†²ˆ}/ï²´» •DûFº’ˆ#c•�ÝÉSÎ�id¬�Ú7Ò•* m,ïá� å=è.Kw�½Ž¥;GƲ1é «€>2–ÜìMÉÕ çk,§)Ô:Ý?ʱTfoLNÓ�@g¬ƒáÖê`Ј5Ö¸ìÍÉÕ¸ É*‚\ÈK[Ñd5!ŸB¸®Àª·ž—{G ÁU,R�7—yŒ cð{ÿ©çšl endstream endobj 153 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 154 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™kªà’ÏÈ�JcŠ endstream endobj 155 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/diff-ops-file-server/diff-ops-file-server-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 156 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 157 0 R>>/Font<</R8 158 0 R>>>>/Length 23133/Filter/FlateDecode>>stream xœ­½]“mÙqö~Åy$#€Ö^ßk=R6(Ó¢@ †aùA‡3’o$`„ÂÿÞ•™ë£VÏ�ëAÄÁ˜îÛ»OŸ½ÏªÊÊúÈú××ó^þ7ÿû»÷Oÿæ7íõÝŸ>Å·òúŸŸÒ[ý‡O¼âõ›÷©åñ*±¿Þ?µþØøúó§ßÎ þøÝ§ýôõüÏïÞ_ÿö{Éþj¯oþù“þHxÕò–í·Ÿ·\s}óþé¯^Ï_ó?>ýê›Oÿ‰¤=cÿ|�?òS_;½µWíoe½t¨×K÷ñì—Æ×ÉK?oñÕë[]/ËýÚáiÁ^v½üüö/ø %¿ ü^~ë¡ðOä_<ãÉ%ú?¢oÿ’?ðôCŒocþ‘Z~QÒ‡¿’SòEßþ%GûBoÏü#áOî¿(íÃß©!û¿£oÿ‚¿“†}(¡Œ·°þNýEkíñÃçÚ(þéÛ¿äÜPkoqþ¡Xû/r*¿ÈîôÒ§…à«<êÿÿß°+ì¯<oÍNËÓ^¿Ü_ýð‹ÞßbŠù•Ó[íö_¼‹¿ûõß}³ÿ¼]Tçßç—?÷áy{R¼ÞÀßÿÃ?üûü�ç-Ä‘×[À—?û[Há­x ÿîWßüÍ7ßü漇âzøògÅþø‡÷ð¿üæWóͯÎ[héYo_þìo¡™ýðþá?þê×ç Œ¼Ž"¿üÙßÀh8Œ×°Gð¿î7`X&F¼¯o~î7Cý‡áÿ¸NCL=�7¢o~ö7’íËoä?ÿæïÜ�ˆõ ç]蛟ý]Tƒ‚ïâoÿþû¿�wÑÃ8ïBßüìï¢ç·Ô?žŒ¿ÿÕßüö<�ô¤¶ßÇüæç~é©oáÃûøÇ_ÿýßýúߟ·Ë9£ó›ŸýmÄöƒ3ú·ÿð;¦ûm Ô"F�4ã‡h}þ”r[‡÷ó}Í×ÞŸýƒC®^,Œ³Ðâ +$Â_Æuƒ—™!¿Fz ©Ä×7ÿd?~ËÿWÄÑÈ/ÇÛSøï©f>ºhøõËô¦«cyø¯v– {Zà_Ë£Å_é|VöF~‰wÆÃÀ#$;&3Œ:×ÿÆÃˆöš!u O ÅæÞ@3ä׋ûïÿØßïÂnÏÞÓ/y—öïÿç_5ü¹_F»2ƨïþ¯oþ÷Oø|^¿¬öʼŠoê—9!°úWñéÆùñ¯[oÍBÂüjý­—ª›úõŸßÿÛ·|ýáŸ_û�:øöÒ o$¬·ý›oÿõÏßþéÿùÓù«Ïøn=�}tæ-#.¶`ÖÝ¢ÿãåµö_þúþåýø,`­Ý ƒa�¼oþßùöOë]½Ö;Àïÿ²Ú‹%¿Ï ^ø¿ý×ßýßßýñþý?½ìº?{Àåõ�=×Á@ª·øŠ t›q€o?ý3Îå—öúϯßâíÿO³�RžÖÃâþWÌ5=5êëÏóë‘ñõºJß}oßú`fi@ºXñò1<ö�+¡Ø¿t¼–ˆÀkÌì6£Ho£ñóX¥âÆ�’$^Óã›Ùl´�õ­‚„n¾ãáXÜ ߢ}’Á.13É�—X´BKãM•—ØñIxwv�߯W‡<ìºÓöV�§Æ\ìàƒV ¼yÅ8x‰Åª£Âôí—à›ì>í_쮌™Y`c~3ï‚aG‡×Ø}ÚW¡ZÀÛ¯Uˆz£óοøøìeíaeÿøð§ùfÖããÛ{’|¸ƒÒÜãã]¦àßf»îñña•áhÈþñu|w��ŸKŽþñá³ õ<>~¼üÀ÷ãÃmgÿø"˜Ö÷ã«xXçñÅ`Ì'6ÿøð,žHˆøO“(ÿ˜1üoG‡°mä ?øª�¬ëù9õ ó{›zŠcmæ‘ìC2§:¹\öÌÍi{áù$R­o�]{ ºÆB™ÇžD6ÿx�Ò0Omìö"ë0~m¡_ÈöÌõ¹d³ŠjwsÉz‹£öÌù^a×ÚowûpSåi|ì‘wûtùò4üÉ_ͬÅîœ×X¤ôãmòcÁ[·§ š?ô2Ýð (a·ÚxOTm¼¬%ð�3;Ï!Ù3ߎyDûö)™µÌO×`Æ>Õ`Q‘… ¼ÆÞGª¯ kÉ22{vžÉ¹;wµû©ùUíîj¡ÍÛÄ�6~�ß*Ͼ=ÜzµG‘t"íÿðà‚=Éyë•ÄòUì—™û0Opžƒ™/>˜™}Fˆ ̦úCŠö¼@åíñû¤íÉT¼ód7hçÙ0Ìž’œ�‰�!µ=Š˜hf)UÞùc¡qËË& …:ДOÙ°ßÐÚܪŒìÙ>éôÊö jU`=|Ú%æCª|]¶ƒL�âA¾J¶§ÕÛk ;?IÆj<&‰·w0ø29ø×Ñì>¾ñ¤7;SÉ ½>âlËü´}(vÛ|EÍb-{%ñ{ZfŒ#à—ùü¾l ©Ø¯èÉ,[0 lÝÛBê�œóØÂ°4]¦l! 6e.ÓÂc�(•c 9Û¯ÊíNc0÷SqzŽ1äf¿«·;�ÁBH{äÑCAŒ#P’1+O8<ÇJDl”�1ðæ<œ1”b¿+Ÿ1�! �Ò¼1„ÑÙB½ãô[@ÂÆŽ…³…`?zÓÉš¶P³ýòð¶`î6¿É L[¨ö�Wâi !6¤¨œ1T;7£4g fÑæ.�-�Ðâ d !ÙÃÈÝCCœ½1XèÛæ�Ochf =$g öHê›ìNÆ�H{ôyNkÙFJκ Ô†³†�íaÔè¬¡Û ª5k°�Þ>ag ÝÎÏÈÃCÈcÀK9c0Hƒ=c0¸j°yg v€ AÈå�ÈîðEÀŠÍàtý3Éò¬/ýàk€µ¯Ó|ž WüÒ”2£¼f÷=0¶ãìØù†qÚo6þ¥�ÇÈd”ŸþÆŸk� <âÅNdÅGc€›‚íëácPÞ†&‰+2}]ï0;]Sù³P�㪼¦ÑgZHoŽœŸ*>œðÜá"xÍ ëí^€¯3"íÕl<½ñ3‹öx»qû_NxƇƻJ…HÐ\OÇèA'|vqM'¢4{뙇5= Ö<p×ä@dj¡Øí‘ë®#Ž£ÈûÊ™gÔàmЖ�)ÓbÍG�yyM%RVû8jÔë Z¬á# —× "nM�Ì=)§ xTnÕ`’°]{ÙRxI�½Ú…À]^RˆþÅh®î)4š«acŸ÷]:bˆ’ =9ˆúCk5 ÔÅ%50)`yOâ5‰Ö|o©&4Ù<Ø"ü•æjؘáøqMe`”Áœ’^gÐ\ ÁŠp‰E“ 9X{]º•”@”��æPùa6;æC²E—ödyI¦¹8uy�!gz%3x˜ .i´Vc°¤°¸™êñJÙ~0ø2v pêʘ:î;ù��/“�VÛa�†C?fRÉ®(½z“²'þ$oRÉþPoá˜Ñ=EgSÙ°ygS ª3© œº3){š<¦Ç¤2°žÌ4)†,¡9“ÊpÀúœ¦I1òÉÕ™T±·§¹È¤,‚jøÀŽI;…ôf™±':“*v´zΤÐ%oR>˜aô2)c†3©é��E™ý𨋪f--gQŒSê,“ªö‘YálŠáLv6ÕìmÚçælÊÜBó[FÕì3+:92*Æ3ºñiTÍ>3 ã�Q1 ñ6Õì]ÚŸw6Å€¦x›êæÙrð6e¨ÖwǦº}díIΨÐ�†L£êö‰ RŒeT hèE—Q {›DóiS†é�Y„eSÃ>¯R¼M!žñe£®ePŒeÈw·AÙ;´�w±¾�…à††ÂΟPý�¢±ãš hp2笺ҿ|ûûúï¿ÿî+)—–~<åòág@¿ÌQÚ™y\)—–NÊ¥¥“ré�O¹è»ïO’ Ô.»ÚY<”ÏŠšAÛqĺ* fqÌŒ€[åÅ®‘E(ƒY„÷“i@a.*Öªá³XŽ 4³ÊÌw6dU;ÓPc‘qždNd6â³ÂoðVZŒý�Ž Ke¤ÅÌdD-Iæ{Ò=…ù \¬F…r¹û •·ÝeQ+[Q{˜·½B½?ºm†ðF¨B]þÆþ@a–¦›!*@Z�9��4³Ÿçwø$^ŸŽÄ˜ÙjÑÛ™Y�–ú¼ë™W©Î»F9/²œ9³4 ö�™1ž%W²SO£2wòYd!á“[ž�'�7>�CÐçôñÐð•yò硱nNð¾»Ôü¡Á à–ö¡±›¬$IçÐàAð@lô�Ö<Ý<O¬uhøÌGö‡Ÿ è>4üìº;4üx³;4<µºCc¯×îCÃc„ÛÖ¡±s–xÛûÐð(â¶÷¡áiÍšÁâ›;4<õ=ùC3ìA<ÃZOîÐÀÀ†?44B%÷Ö¡�¡vwhhËù:4öaã®÷¡±?Б}½MUêl{£)QhìàíCC’ò#.ï·æ`Ë*e‘Ò[�°}áôUWx~¥sûç™\׆n|~ºf~÷=+ìx50F��J û‘ÐïÒ¦òÌH1Û•¶óXd¨ÏH{à`”™�HÚð�>Б�~05ÄâxäÙ®î`<�Á�Ž´±\{ÐÎÆGŽôÁgŽAG:dúÁü€ˆâ0fT}Àg‹wõéšÝ¼!e èñ§�ÈéJCèÓEéÙn;'P ^cWg¶¿('fÇ÷ òJ^�Äæ"M¡»¶Ç7˜kš!}±kH@Ï'Ý è­Ù)®A‚¼•™Êà'Ý`A䡨#z˜53² 3Ý 0ù¼¹Þr¬ð‚%*áôþ©ÚóI°Ù@Y·½`±PÀŽ9®AÒŸ©·Þæ�Ž�^°då¶ìš¤�Ûî6N/˜f�K�“Á!Òàþ‘3QJ"ÙW.Z�Ì«Váv·Ï¼ïd_ud ŸÉ‘2y`NÈ«èÆßÛ{­Hq“åÕ�Hï§�ýp‰=ûl«±‡‡‰dU"\ R/3kfÁŽ‘±!‹µØúÍÛ ×YE@~Ìþ¥QIŒ%�zA!šéÝ:x‚Ýz­ �8 -+â·.óÖ³}U‘pµÿÐw7»º ™Ãá§2î 2÷ÓD ì~Ó,ŽdûjÀQ¤ÉíáCPûTš‡—Ø#x@“û¤äýo°û o+qçæyìÎqH‘åɤɽÌ;%1gÝ2¨¯Iâv¿Ï,ù _gwÞ*úÝ`/È5%¤‹tç -vçÍÎYeþ·Wñ»ß>ïÜ<’Ýy³cÖ ÿ”=¦‡™zðe¾í«�L Îiï¢(öÿu²�÷³çÕC›d)¥Ø‹ÒN]Iv{vë=%PF ‹±ÛÍóÆ‘DMÀ¬‹Ÿ8«Òmæ¥fÆp�èì&fžfdðfXÒ,ÎUû e;c•©µaWwÄ1Ì]ñû¢��@qŒG²› oÊqVûÊ>»aG¬ÓÈ�2Øm#š0¯|õ(¹Àž(>OdÀY,Ðm#Q ·�ŽœpeÀYÀ¿øIUt7Tñkíc—ãÖͳ¿%9*2£�C·>v5,¸‚£ "í+ó¼dòÂô§ zŒ ¤¾)-Ûì+»õag¬e]ƒŒ(BLð8Åyf’Ÿ£OoŒ½*X¸0ì#N¡# DnáTeèup* }4<L™{€=0ÚÈÒL=‰‘×�){VM¹“ SO`äu`Êž¹š¦ž‡‘×�)»"É�)T‘J?8e�¤(ù°pj ‹Œ×Ù8e±\`NH8…r¥aÉÁ)ûx”¢Ý@5�­n¨rYÌ=- ææ»}u€ÊN‹ÒÁ¨2ã½ 2 ËÊr- Bá±ØCÚ@eç’yµƒTÝžZFV~C•Ù@E:m#JœÑùA*ãËQ‰°…TÝ>D”*Rä͘¸[HÕí™ ¤A6R™c†î U·Û™º[Heþa(G¸� •[ÇTæe”¹ßHÕQÄ(Á!•*�·¾� Eb;©Ìé5&P5”K�¨Ø³úTT(GÛûw@eN¢3[»�ª¡4ÓN¤ñXGX8Õ³¦Bï{ÃTC è»qÊ€¥*Ÿ»p Evd%N…d�›¥†‰SÕâ{ ‡Söë�©ã�S(ïÛÛ:0eÑ�Ê9¦ªÅáÁLòÀT@Æ�¡í‚©Z�iɦì™Þø†©Š ZΦìUƒ2â ¦jTRçà”}F¬Rm˜²_µ/†ƒ)‹ÁËK¦ÊPþèÀ”˜¡¤ù‚©bœ)6Svî ï|ãT©JUmœ 1Êan *>5: 23¨*(, BÝ�I±T�½Iù�U1RÕØ£»€ÊlŒ…ù�S¨, ûvpÊÂm¢ÉÁ)tŸe`ÐÁ)³<rÜ�S¹+Óçp*$¢ÛÁ©lÔ. PypÊN>ï|ã*@RTá!Ú B�ÙÕ h B Ì ¨þ¨XâiNUF§H÷<s3Þ–VUj¢U~J®.õå}•í�ß )œY†ù�=NU¤ÖÙ]߯¦æ„28±©"«òíê>HbƒÊ1¡ Æ …ÇÜUMæÌ î¼iÞÁÍ“ô:ö‘šÉ'£úD'oA4`'ZuR�¶=S<Z�l—,ê±6ëÕ•‘>"�l—,ê1w¦^ˆÄ¾µWfŽJëC4 å ]2PëOB¦xÄOsš÷œ‘¶5¨E¯� fK…¢ˆX!°0i‡Wȳ%‡BT£æ`uV¿¶� vKõØÙšåus†0&! — Íê6^7pº<‘ †KÅ„«R쓵»†i ™:JÛàP³gÅœ›}<ô¦|,UU%5Ht™l›£2ÁrÉ¡ìÂÙÀ¶7XØYÂxøe‘–Z‰Ûn~OÐ4XŸÁÛ17®[bÛ_‡ÿ6áH‘CÙ)š·Än/xaa —*¢B,¡ ¿Ø0÷cgŠ e95c°ƒÈd ›z€ÛavH™'Ä­]&8áLÅ¡ nˆ1�ó,tzX r?óÖÙ†•}@º&3 ÐJ¬¦.@6±²/tzX1²kÐLÂKзñ"ò ›0~ƒ³ƒª¦î� ŒC2KØôð‚Xçm¯ívLd¡ YåSÝ6M|®,d ,:¶a[ ï;A¹Í*=Ïîšna¶'DÜ5B!S`Y °�æMÓä�¡[KÈ„3…cL¯ÀK*szŒ³&0«ŠêY¡17ˆxm!é^d "“‡ìDзp‰¥-ŒýŒy×4zŒ?å…K8PàOð ºkX½á%‚ЉK8PàOô JšÂê_e',á<‘9v6V2¯J€ˆxÂRd‰  ]Wš·�H0°,EÀã¬ßÏ4/ŒÞPÄ,kÂRd  �ç­®`eŸ¤ˆ¦“?Ñ1(Ëty|e˜½ÇGëI¯Îã+Á|yüXyÇã+Á\¼ÇG—‹ÝïöøJ0ïòc"?._ææ]~4Û·‡t\¾’ÌÉ»üø°±ä¸|%™»sùpÒÛå+¿œ½Ï�çìø|æ—›wùhjѹ|å—/—ϦÊî\¾ÌÁ»|ì(—¯ óåòY¨Îå+ܼËg½Ã»|cêƒb»|ì —o.�>ù|_šsùæWàzœÇG=Áìæx| sËRÇã³Ô�Ç7'—h-Ç㣢`w~<¾E]ƒVw<>* Éy|ó¹ôËÎã³¼U�Ç7ßýðÆ·ÇGI˜ï<¾/-j{|Ûì;�_ìƒlÁy|Ôìbçð‹Y�ùrø¬ý ïï‹Ù1aù{Ô8_ 3qãËߣ¤�P�>¿  /;‡Ï¢R½~A y;ü>Øçæü}F¯_uþžæŽvÒãï1“A/¼ü=ì�×ñ÷qlsþžænŽäøûœ‹ aù{š{IÞßgó–D–éïaíˆ%�¿Ï¡ÉU/Ok7ßèü}FÃÀö÷m¨4àü}2 h,O{hŸ FZtþžönçÕùûTÙpü= Ør~Êu&§Ã§ÁÛÃrß ‚÷½> ¿ï~2Œ ÞáÓàÑæv~B Np¿¡ ËîÇ;|ÃüÞœÃ'q¤‚%þ4Küö–Šc®Ÿû ?ø* 9׿+¹»IH¹:ºuÝééFO3»VÙ?9Ø‹’f_+™F€¼}{$Fæý†…Pu¦’ó#þÑHkív«œÞWæ‰i“ÈÛ­fÒHþ ¢Fœ]Ô] Dù»--öÕì�e¢˜"ÃzåÁ 4e£ÞΠ£Aƒl3HT'Ùì¡e i/O"„ÅÈr;OÒô3k¹  à©cˆl5›=¶Œ3‡ÃßEAW^qf‰é�Ùb;¯™íh³ —qfQCÈbĉyEµ²œK¢¤ÔbÖm÷ê2K\H@2£ßEЃR‹ºiŒw�€(C¶ˆþª�Í,1a)û:CV$ ”Z¬ Sÿ@®î¼ÃÊ-*bµSBþ¡ÄßL_0E‰„»BV;%à,݆�‰»-˜±äCþ¡<äJ¦Ì*Øì'a(�¦à,ˆeN&ìÆaF›]ô£²9{¥vÊL-*t‹ŒjØ8,ŒE†(ŒÝ\Ìh³‰~d¦*W¦)ÍÔâ¬ôÑåzgÂ*·Ý€Œk*ƒµ”2^‰/¼gp'…­vRš�gÆù³ºz”qÅ`䨲²×+ §ÔâìÝ}šHa6xeóòncÆ51Š€ öŠÏ¤`˜50õÞ£^Ân]ƒÜbܭθ¦<b �ýä+GÙ”\Ô�£`  È2×v;4®i]¤2á¾R¦efÕËcpÂÖ ‰[�mu³g+ó´áÁZdpWvQÍ1f#¤!,‰Ï<0n}¶U³‡³_]�A+›•\lê�±ƒ’ÕV=q¶12ž�×lÂIä œ&Î"· bVô¨™ÿ¡Îká,säewg³ 'ˆƒ vÀ¿+×Þgr1©Úv9ôˆNS ¶CGS èÅvè‘ÄÖûóÜ“ØÅòçAx-ÞŸ£ÿ°4çÏ#Yvðþ<—"z±üy8óL¿0"9þ<’ô'ïÏsdßñçì„]ÛŸgT^Ž?Gî 8ÛŸ›��^ÎL†÷çhÞlÑùsð-t¢žãçÏ™V‰ÞŸ£O”ìbûs¤gØ‚±ýyÊQìbûs¦y’÷çèI ÞŸ#[„›>þ<…,v±ý9ùçåÏÑþ vqü9y¬÷ç±±‹íÏI‡«÷çl–éÞŸ“VGïÏ£½°‹ãÏÁΙ—ÚþM½Éûs’üìüyŒlVuþ¹Üøñç1pdÎùsæ.މ\»qçÏ™¸ÞŸ£S™ìbûs&@š÷熈¢ÛŸ3�’¼?LyO®÷ƒ~îáýy@êÜûs&u²óç!±ÙÊùs憼?Aã$ÇŸ3ÅT½?{¿œ?gž*zŽª.FWŽ?Gº«vïÏŸÆF4çÏ™5KÞŸ#¿ž/Žìnüøó'³-Îùsfñ.þ$¶×9Îl`pþÜn«áÞ�?gV±:Î"¼ÝûñçLNFçÏQË'ËØþ)ÎÚ�?-O’±:S¥ù8ô�²8ÆqèÈ¸âÆ·C(�‘c‡ŽÌ­wèe6rŒãБΡ“?86@þplNÝ! PíÞþàëý»ûúuȃÐ7ð�üŽ×Íï¾— Š+4�¬ï�Ù˜³êy…¥‰¥=LäÁM+¬ù£n°ÂÒÂÚžùX¶’0éU¾ˆ;,E6ˆCyŽf÷*Dª;,EN (âjÃ|Õ/ž–Ž<U«#±‡¬úEYnŒé-ÆþÏnÄTCÚ J#+{á)3ã˜T¿H,°¿ÏD�d¬ÞÓÂz?ª+"Eº®hlRO½· òEØ©Å�h¹|F›­[½³à�2ÿŠHëzœw(s‚™ÿ‚àpF¤ƒu=û¨Ê¼i 7±|‘WDÊÂSÐLDŸcÎ,ùÃVHŠÂq"Ͷµ¡ÖlØÔŠIQxÒàéìÝ-Œ%a™+&-,ëÙç×°¹:³aà+&­¬ëq´B·>Ô™�:ÿŠIQyBŸ•Qʼn¨øWTågHjˆi¨¯2¢Rg6ëüò`¬>±?®Ï.~œ�¡†4!:‹OS,k(0So6¼è HíüX3æ5ê͆7^)ŠOYCš9xÔ› ¯>Òšxß‘l^¢ÞlÖùg D“{g!\a" þ mU�(=%’n;¨5›eþ鿦ßá\+o;¨5ÆÿÁ%V÷yM~Dží¿¦Lìà5}üjšVª5k�ãò€V—vÜrÓHIž£zQõ‹8'w�wgﯬøw´Þ(÷s@"ª âxtÕù5%,°Aºªª$q<XÂ(ÿ\˜•5š¢[�‰^±’æ‘…}LW•yë±$•0GD†rWs�ha¡_£Ï‚b6¿%öDV0ì3›( Dp)ºfÐ5 ´Z•°÷-¨"q@È,úy­ ›oxMLª`Øg–®8¥°‰‡×$ºÄǘF]á›ßòlZ»AÁ~…1æ{—½P°¿X�v ð0åq@�ã¶ù4„±Â±@!±% ìK8ÙËróôƒ±Â±@!ÂÏr„}ƒûÁ<(ØG«q¦ Õ÷…ˆñ&´nNP@7  8ª\=(°,:Pˆña`é@Í`¥;PàT4T(°,;Pˆ@ÂÐ<(  dƒ'°‘Ø= €v°àA!¦ó=(°,8Pˆ!q8Á�9js `®ò8Hu“ΕçêA”™d�‡R8“·A�Ì;;Pàl gé6(�À;Pà¸î|�‚²�Õ�‚ùî9µ·@AÉ„x@!bŒ¯yPPN¢9Pà\>Ó< ”ÛH ‘ž9ÙV÷à”Ù…!¡‡ JµxP@q…9œ ÊØxPÒ‚Ø  ¼Oõ €1HŠj,PPþ(zP@ìÚ<(0 E²A10³< ”ÍJ†4%(0)r@#;H·mPPríTX˜ÂY  $]ð € ‹2A”ìkjþZ£TQÝ  œaô �¾ÒªæA@(t XPP 3{P�­oPP&ÔƒB£ÈÅåS«Y�¯Ü  ¼lô Ð(„á@�éÝÐ.P(ì=  4qº@!«_wƒÓÍ}\ Õ¯»AA8‡•�Ép¸[LFZd‹°ØYLæ ?ø*“9׿ϜãV·á7A³ÌóºùÝ÷R6L%®Ä ìµ�2»·:›Áeª$|hR†a¹ŽãhU¥�gÒæ�Ý+s†ä©L^tÇŒDýÓifÎ"’_ä2}ÑŒ–‘ì_ž¸vQ™¸èN³¯Q¹BEŒñ�µ¿Î (Ëö/R.@É9Cc¶ÜæÙc��\i—)‹ìÀ}²UùÌ\‘™±R6pÃ,¸@&K²9/’™´O:ŠBrŠ˜ã™iìòePª#�r‡T�ýb)$,ÂS‚,P·MQOàVY„( Ê(b�µ�g¥l€v,> ›«IÄúˆÌäEx€š&¯ijC„–Åfú"<@_¼å6)Ù/’™¸Oér?a¹Å'ŠÌÔ�´yäÆà-¦€D¨¬…<lgL*o§£WI�ÈLÞ)›$§SV )"ûE23vÊ&Ë9ǼÒâ± ±™´S6ENš�S£%±™¶S6M`!•Õ¸6ÕBµa” s"eû”Ñ™2Á­= ¹Š2Hù/Й1±­Áu ´±™´6I�ŒSš÷�äÙL_à†ÔA Š �Íy‘ÍÄIô�šh³aSå�h�ÌÔ…mHM#!¾ ø¸WUBž…m­+ÂHˆÉ5›�1àV¦N ÓœaâVž÷�ÜÉLߨð ²’ÀÈLÜØ8QRBZ9ŠÍ´�m”'4k¯óÎ!˜ÀBHØØVÆQ¼‚·ž1Æ2cï¡ëO5…ƒµ|‰�ôB236´uE•ÔÉàcˆÌ¤mãQpŠP¥ä¾HfUs(ÈE(©R:¥IfÂÂ6(—!X.È:Kê“< 3KŠù ÂV‘~U,…´ ½ mÈOP< Œ©¸u½*çÓ,¤$63aÁH‡Ü<,„¡ŠÊ„…ˆ¸M¼0§Ò,D8¿áaÁŸ 6³`!‰v ö‘4‘™ ö±U•1,Xô“Df&,X ')º v@†ƒ;AšÉ^°:ÆTªƒ…aƒ˜,ˆ³‘Î,X D‘¦?',Ø¡¯¢3 "€nxXp#�Y°˜=8X0#쪨,Xˆk¨ÍÁBhˆC<,CÓüü†…€Ö–T,DÈB°†±`!@ ŽtfÁÙmÌ,ö â3 Hqƒƒ…�±8Ò™ ³HUlXÑ^v°!vÁׂs»ƒ%• æ™»jŒØÑ™ ²,a,XhÔ"�Y°@‚ËÖ‚»»*>³`�7zX�¥#ŸY°@šË|Ú‚ƒ¶®’Ê‚…µÜù†*4e FsÓÌrMX0}Hh&,D¨’°„1a� Nä3 ¤�,´æ‘Ï,X ÇekÁB€þùÌ„RÜèaÁâé$:³`�—ù´ y,¨,X°€G£ø˜çÏ"d]”ãš°@¹(Ò™ \=*a,X0¯ÝDg,D(Ȱ„±`��Wä3 Èr³ƒ»¸«ž²`�,)ß ‚|¤3 ÈrY»Y°`oì!�Y°¡‹3Ú�êR‘ÎX¤ì1EÑ™ =0!¾a�ÚU¤3*{½,°ÑŽtæÀu, =ŠlÆÁB"7;°@6㘠٠%>ƒÃؤ%ï²Ìþýk\Æ]þ>S Kúl~#é¡yYSMÉ6¸N{g*×\V™‰T6¡ô8ÉÖ™Æ ƒ 3Ù:Ô�›Æ²u¦qñ'ÆÌ¿);eN®¤eëHè˜í¸-1™o„n+í7RØRïßÈ`Dá߈2üi”5ro$Hgãz#è_uo„2;îÑãÑåM=#ä ÷‡¢éÑý�}ùg_ýÐί¼ÏPo}hú†$A±-¯ÜßO©æ†f)ºx)ªP‚f¨"z@Cãî E70jÑ U¦ÀCÓê EO1'{Û˜c{.ä¡eu�BÁ ãnì?Ó›Í Â{œ¤hxŒy»¢Â’ÚìR4NRÜ1²è@±*Ž¥±[H›z‘XP8ÜÖìRôpVæŸyÓh[�»�½ ˜'d’c(lÔLÒÓŠ©‘îÀ]svN!aÔLPÙ ¤­kÊ�)Å„‰3A¹îRô¸RCyä)ŠÅhšÎR4ʦ"Ø�ÚZ•3AyìR4ÜrZyd^Ò5D�¨ÙW¡HÎ'*š Šp׺¦h”’‰­-®š›ugŠkp¤•â­¸&j&ø¦ÌOÖHëóÖkâLPáN]c§m®î¼ŒÁúŠòETZÉÂ]IÍU `ÁúÚôžqŽ«&pM×HR;Ê/ IÈ%o¯ ©[t¿K?F…qÞ9šÁCq’ªÞthˆ¼uÞy‹ BD3›�³‚�gjßA€Ú`¢¢&‘õ~g‚¼úKmùÐï�ú<AcÅú�ò“lGO[Ÿ‡›)ÍûFS7xè#÷¥óŠ”ÛRóš Â<úDø¢qiæ®ùI¡§‘ƒºåm^R5u�Ü‹nââࡈ`Ÿ)èªémvŸIò/q„ È9O}ë:ÓˆI÷ -lóÞ IBäÔRÊ‚Ý!¡³Ê¡ †‰ô)€5’Î�^G:á'IÂÅè`†0×yçèiQ˜bË8nÀÝúÌ;§&¹E(KH–¥‹1�(Ïèˆ ÂAz7]³úœ¥çgEõs»#éiF˜šùg†ŸÕȼ�TuQŒ‰V� �gûùŽ)´ž°ü‰³s xs.Ôà�C<�<'iÊÔÚi«œh-S¹’¢îFDA ÅñE‰6êàÃJhi4wÂÔ˜‡JÞrSw_‚Ú¹9C4óE ZC ª'd^“(„f¾œ&©ÈL=°è6xMf šùŠ”¦Ð€Ôů©¤"Céaˆã(ÍFAˆÆkš(Íó,{ôàΑ}!/Khj êÎæ�,‚F2ɼmÊïuó©•C$�{á}‡ µ4 ³Z SSŽ m!ºoH¯—ÙŸ= ×PŽ�m!Ê�]à›pˆS½À·j:‹àKE?°á€oÒ|ÙßÄ1 æÁ7iLmƒoB™Šø¼Á7Iëñ€oâÐðà›BRºy�o‚£ rnðE`ðà›àp<ø"Š:à›8T=øF ðMð}1zð�EÓY|#g€šߘ5�µÁ7¢LE€Þà#§³øFÎ� ¾Q’|#p¡^à‹þ¿àÁ7_Jpà‹ö?�ý ¾‘S@Õƒ/¬@ö7øFÀný€o(ÏÚà9Ô=ø†¬ñ¬ ¾uª‘=ø†Èñ¬¾ Þ=ø$�øF„µzðEÿ_¨|#BŠ<ø¢ÿlƒoä(PóàûP­Õ�oD„C‰¥ ¾P™Ûßà9 4<øB­lƒoD¡j\à Ñ›ìÁ7"rë|!�“ø"ú«Õƒ/zÿ¨ê½ÁQ$ÒZ|ºÿÀöør¨;ð ¡Û?à‹€÷½Á7@Xtƒ/�†ß�}"°ý¾ý|Éó¾ÓÕØ!ð »fr|ìãÎ7øRÅÛ8¯_�†øpo�ý¾ýcÏÆßÐÑ Û=øbö�½ |”¤ÀöøbùTpàKiòêÁ“Ão@^Â|‘_LþõàÀ—*è)zðÅè[|ò$HsðÅì%1øRòlÿ€/fÿ(­¹À×p¤�îðÅð_Ì|ÔÃÚ¾'î€o€Y |1þG­Ð¾”‘Gžã€/Æÿ¸Ýd�o@J y޾YóÉ|©XµÚ¾�Ä�oð H°=Ùƒ/�qç|íÍW"é_ŒÿE¾zqíßü(³µÀ—*ü€t¾HëT¾ÉGJ5ðmJl|Ç¢èŽlãÕñš“¢£?ý�/)ù/þè«ýüOù™–›ßIy]éEå9Kîú]%ß¾±ù ™+}š#K¾VšÜ*çñ(b3#Æþ€¥š�k4ÆŠ1ŒiŽÐ»Š³wiª!kvÉf“M0•5•µq‰fjs(Ë©°u‰£Ì±j6wIk¿«î[·ú6yº›Ò²EÔ|‘�{jŸ·M‘ø#½ý®šï8òÜ$b𙣔ÂlóQ®ðsÿOl[^òܤÊ9N oR1 Í=ϲE(Vf5/%©¦7ÍÌMo&¹”�*߸¦kf.öeŒZr¥æ%]¢‘î%òý®Šo?Bà - /¥.[DÉ— ¶}®Š]#æKœTBf4ÅÂqMÖМ6ÅiŠh\Ò]cu@9Bᤲç)&N’Å�¹ >\"ùv.I]¼kø~j‰¿«Ü[�ÜøgÅ/,­`bµ—e‡:Å!€%7þ®jï8’ä¤aš—«Rý!‹˜Å€1—Å!U‚%IŽk‚Š S¶×HÜ éð‘EÈ…£wiÒ0ŽËMÕr\1�` ›ã)-@šHïª÷²Ç´„yãˆYÇQ6WÁ·õsð• �¹"‰¦w|Ù^Û†f™Ì/ùszMÂäTH'ÅÒ¼\—`�¯Ðõ½ ÂW8/·$ÒqÍDm©¨“…i\¹ºi¥I�KYŒ¯k\nª¨¿«Þ[�Òúgq°ó4æë½€dèÃêÎi€Giý]õÞqÔØqMÔ¼\•¸arÆF‘rŠ;Ñ·;ÑVÅÃ)ØŽK Éf0æìX™‘j|âN°@–‰ŸUx�ßuÇ%]sqÏŽ•8¢sIwÞ?ެ;ƒŸSùÝ.¡ ¢ãu��,(†-�ãt¸&2?>ÅßqÉ …ËÐk$æÆ‡ò^„…Ó¨îIÏûF–5 �ld)R8È’ ÊðD�,EjYV_`Ðú K‘œÀA{NYͪYŠô²$îÇðÈR$'p�%A²"_ÈÂÊŒG–ÄÁ!‹ÅºYÄ3BóÈ’%'p�%qÅFòÈ’%'p�ÅôPd³‘%KNà KÂp${U7²°ö•²$ŒGV�,YjYÆ#Ù«º‘%KMà KÂx${U²d‰ dI˜Ž Ý#K’˜ÀA–„ñHvénda�19dITEY(8Ö²PYíBÖ:³G*´�,¬™zd¡Ð[õÈ ¶‘…zqÑ# Ë·Ñ! eçºG�A<²P¾.{da19yd‘ žGî¯Y¨¦w! ‹Û²P”/8da�Ü# ¥ýšGdPh>ÈB…Àä‘…•¯è‘e dQõ«{d¡`avÈ¢êW²(âCïëpÈÂâûf7²P>±:da),_ÈBÆx�%²+"xd¡šcsÈ‘f;ÈBUÈä�%²K#zda‡ñpÈÑíÁ¾Ù�,©ôÈÙ5’=² Ý™)ï…,‘Ý'Y(™Y²Dô°€{d¡ôftÈÙ²PÀ³;d‰h§A¡ù u@³C–ȶœä‘-åÑ!K@wÛf7²P•Ô# %ì›Gj›†…,��FÁ! õQ›CR+Ç’®5#¶?¬¾ø£¯2«óﳺ°Wuñ›Ã¬t¥gV=>ÿXƒ¾˜³žY±}3+å<³B>þfVÊ;xf…|üͬ˜w¸˜òñ³bÚábVQÂÿ˜v¸˜P.f5ÂðÌ 3,7³RÊÁ3+ÌÂÜÌŠI‡‹Y¥Ùwsð�I‡‹YQÄùbVL:\Ì ùø‹Y)çà™Òñ³JL9\ÌŠBÎŽY%ÌóÞÌ*ÍÞ¦�‰I‡‹YQÇÙ3«Ä¬ÃŬ0žw1«Ä¬ÃfV˜â¹˜UÂøþͬ(ã왕ŠýfVY¢ÿRxâͬ¨âì™UÂ÷Ŭ0És1«„öå›YQÅÙ3«„öå›Ya6ïbV Óû7³Â$ÏŬ¦÷ofEgǬ”ž/f…9ž‹Y¥ø„ÌŠ*ΞY%ÌìßÌ ^êfVè_¾™=ÝŬп|3+8Ì‹YaxÿfVt»³ÂðþͬªÚ:³‚Ðóͬ€7³JÏó�YL.f™†›Y”nf…æ›YÛ.f…æ›Y#/f…ñý‹Yjof…éý›Y²/f­ç‹Yùof•ÆøÀ¬@\Ì*‡ô�Y!¹˜ú—ofÅpæbVè_¾˜£¢Ã¬0¹1+DV7³º‘%!Wz1+æÅ/f…Téͬ˜_¿˜”MnfÅ<ýŬò?0+¦û/f…téŬP5¸™²¥7³bñábV�K»˜U‹>g— •v3+B.f©´›Y± r1«45g²°.s1«„�¾‹Y©¸ã™¤Ò.f…ÑͬâTÒ9ÌŠµ¦‹YÅ)ȳ™KV³ŠSÖç0+•¾<³Š¨]ÌJ%4ϬâT:ÌŠ¥¸Å¬ÌæÌŠÅ<ϬŒ#=˜‹‚YìùÖÌJµÅƒ,)Lý¥Ã¬T¢<Èbn§`V¬tzfeX“?0+L=³bmýfV¹?7³b‰þfV*à:da�ÿbV¬;dIÏTÊ:ÌŠådϬÒ3·³Ê1ßÌ*=s?æaV,o{f• ët3+VÈ=³b7ÅŬPh¿˜[2nf•´ Ð!˘²f›Y±ì1+ˆ^ÝÌ*i¢C–1÷‹fÅ.„‹YA„ëfV)<˜Õ˜¢o‡YÙK`VcŠÇf{¼™ÚpnfkÿÀ¬ÐÎs3«XòͬúTÄ;Ì*æç³êSYï0«¨µ•Yºôù6²ÄÂfù¶‹YÃh7³êS)°Ì‰´žnfÕ§ÚàͬKº˜• pö†9uÇ/ýàk¬j_ÿ>s“SÍo¦š#¯ÚÊŽéÑ ûµ’|F¬}K�¥GÓÜ�›ƒˆW!¶µÀ¸xÔí,gÀý^sFÆLáP Lƒ“ˆÑi�q;©[l>V¯–ÕY¥¦¹ Ä«h\ØZ`\`zvŸÏpÕ­GgøÌìÕÀ…SÄ|5°(кףÏxÕ­Pgr™‰6Ê�ÅɪYR>z`܃êV¨3^-~Í:³Ë´uê�=›à³©hé�qYªÛ³>Ö³Š�ÙåÀ­Å»Ã¹ò3rr`)R¡uobŸñªÛÖÎè™~�r`;\eÎ’ãÊÕ³¬—è:j`)R¢Uj`¬hú„Ž·²º…î3ZuKß= #PÓÞݦªïRãÞV·ò}«n-<®IB,TÇ4WÑô 5°”(к×ÂÏhÕ­ŽÇ5U�ŠòØìêÀ'äÕÀ¸Ö­Ž—í»õòŒŒa-­±Š®�èˆ�qQ¬[/?CÖ³�ž±³¦E ¦æ$äkvr` �-nýÌMº-õ žèPl6'é3:r` ó_nK=3¥Ýo²Ç5MÃ4(�©9iðC:j` Ãhg‘ýÌÛº]÷v fÚ a(¦t— '–0Ðë–ÝÏ42;d—XBc vµÀýŹ]žy‹�%4¶Ø�S LÍICŸÑQK¥¢ËGj`ÏLŽ $¶˜=Ú”Ë3ÁN¬Yj` ó¼�© ”%œYz¶/1°„q^»qŠ�¥�ígkðK˜ç-]b`MÝ|YR°[ ì‡N=a5isN�ÊÝΩ'ì7-õrêÒÖ8N=aÓ‹ÄãÔã�¶Æqê c¢ìål8þíÔ6Ï„tœz”5wN=A-x çÔ# z8§ž :ܽS�CâÇ©Û)‘Tørê\ëm7~œº�GI…o§5ß�SOØí‘ôíÔ¹B<%çÔ>çèE{c§½sêä ÐÍÞN�ëÊŸìœ:x¬sé!Ùp.=Aè²WçÒc§¢¾sé¤ÔÜ<²\zìTæ?.�Ì·½]:÷¯ç~\:ù=D³·K�MÊÇ¥3O‡séÜô†séL7„ì\zl\[à\:ÒÇ¡ÇÆÍΡ']r¯årè‘|kΡ3…ÂíË¡Ç&Y�ãÐ™Š¡0ürèÌ"wçЙÒÉ^®7“c±úvèÌ qëÈrè/�Cg‚)x‡«t5ŽCgž ZáË¡Ç*Y�ãФ.µQd:ôò†­éÛ¡3mÖ¢sè°&çЙ~+^¯—¥e,hß�Y¼œ�Cgy"óÛ¡3èåY1ˆÎ¡3¥¼C�8vöɇÎÔ$n|;t–ܱk;ô©Kˆ¤µ^�u{_Ç¡3SÚ’Wëç¯É9t&\¹ÖrËõ"w�‡sèÌÛfïÐÙ��n‡ÞPã;z½p1x‡^Yásr½ð3O»zfRÀÉõ"¯2âåГ ·º£c^ÙѺñeöð…|•=¬ëçéÞìAß,ö™ö]ì�KR.öÀ¥Òh¸!åb×¹Ù60Üì¥oöÀ ){€ùͰ‚áf!¿Ø–0Üì�;¥/ö€- {€ùÍ0z³J�{ö€Ó›=`^çfØÂp³ì ¿Ù¶0Üìä7{@qìf ±7{À&†›=tJ8ö€E {èµ|`˜¾ÙÈ/ö€©â‹=€ßßìk.ö0$MàØ¶0ÜìaHšÀ±ŒŒÞìY‹›=` ÃÍå {À†›= ©8ö€ð›= ©8ö€Aò›= ¥s³Lò]ìÁð¨}`XÎr±Xþö€å,ž=0Qu³,g¹Ø^{Àn–‹=0ov³Œü_ì�ù·›=@:àbÌâÝì“|{0·\?°lg¹ØƒYôs³,gIØ ñâbXÎr±æ8oö€å,{`ªôf�[Ñ/°‘8�c�[Ñ/°‘8�c˜å»ØƒAqùÀ°¡åf‘ú‡=`AËÅ¢Ô {è܉îÁ&J�À±,h¹Ùã7{ø�SOP‹qìËynö�É™›=p ×Å ]s±ö¥Ýì8{HAoݱ‡ÖÒÅRÐpì�é{`[ÚÅÐÜÞï”Pù�Jh’÷ì�]i7{€ÊÐÅØ™v³h]ì��i7{€äÑÅRÐauì¡¶|³‡„uU7{¨õñ.mi{À4ÃÅØ–v³LE\ìA Ó³’PÏQ=ì�\Ö³ñÝ‹=LJì\:7þ]ì�Äúb“|;öPjpìaxÇHò/ö0Ž=0Yp±&.öÀ¤Ãņ®v�É‹‹= ýUçБ¹ÙƒÒ$Ρ3“r±f[.‡ÎŒŒgLÚ\ì�‰�‹=t}Ρ3At±‡®�Õ9t&š.öÀ\ÔŘ¯ºØsZ{PÚ˱fƼCgòìbMçÝ9t&á.öÐd7Ρ3™w±&ü.ö0“‚Ž=0qx±‡™\tì�[/ö0S”Ž=4¹ïБêtìa&C�Coý{˜9UïЕvuì�©Ù‹=ÌìíöpØ€gFìüú‰úzþçwï¯ûͧó¸¤×7ÿü)è‡/è?¨ñw˜åõÍû§¿ú—?þáwßþéOÿý÷ß½þõÏßþùÛ¿þæ|úÕ7>y}GŸ‰«ã‹Û!^íÙåK?ùÀP^Ð?{Zd(ûfŠ£è»Ïû»‘ãtÓëkT8šÂžñLæÎÜXä¼ðœV@ƒÑs•ìñyÚG9˜,ŒI V0æž÷Ù1ðŠ‚ž�æZp„òPй@Pa—ÄGB¤‰¬¿sØ*a¼uSNv+'>7A' lãCIžSäù53ô˜KM³T´sƒ9°.pmÂ~H<jDhêcæh¼èÐST¨ê u¦÷z¢žÅX’¿üþ–› ÏÞ伕8ðÏ_ûT÷Õï�Kƒ3p›¦$Js}žÀgã ÿù+�쳌œ˽)ÄZ��Ÿ¹\ºÂ§¨Ÿ#–‘Ìb¨Jߣmž Y´RkjA(�"ÆÄh!ë�„¨{£ýOí!Fq%Œ 2À¶ClÃF«aiRæ/Ê©c$�ss€0T¬1L©^†€ jœ²HMD¡ �3u‹pa4ãYsÓ¼iÀJÍ�u͹Ínfº�ÔÜŠ‡Î�9Žš§ìhÕB34�s¸À�qcµV›ó†’Ôhá )@õßʰô@£Ðh áÌ*thñ¢UC»v G¹ ;_œ…7Gámim;b°�®mâÂQCÁ®¨²N¥O­C\‹gl§´°‚¯U‹I!:ÂgøWÈ‹v HX³*üF#5o{°4ŽﱄQÐÕA½Ð59Œ5Ù̈¹3H 4eÍfCqAjf»…u2—m�ë$-å�üT–Ás ]rws] 冡uµDl­È�뺵fiî,­œ¤¦pÅ"=Þ‡ T›bô:•"Yè&Žs;i¢ pbÿÍÜÉÊ>Pàq¬¶EÃØüŠôD‰¨/,Hÿ¾êÖõTÔm{5:=ÖbôÄE›{-:2ÀõìAç¡—nRÊêú@—àØÔ&bó…K*Û,›�\]I‰mYM�Z£9®�Àin)EËú?µ°Ø y ̈§#OI&ô™²M‡«Ÿñ$Ý)Ú¥H“Ç\lj҃ÅF/Œ¯m§SL‰jZƒbv¥ºö\)Ë>'æåæŽQô*Øu/„!s}-›˜ð4Á O+ªÐé…(#L%]„³…T«rQ(*�êäk7mï¤ðˆvÓ�Q�žkp‘¡®ÔœMs .¬=TT¾Ó\%4´xp”)ʆʾyEô]<EŠUR‚pË\î›È²PÎ_;y«ö¦>e8Â:HÏÚVܦõh´Ci�¡G!>R¼žJ?”¾Ñö(Ø…ø‡ŽÊ#”ö*k1@¸uÊý×$$dи`IÄ!¨{Р޸뒒K ¿0B¦XúÃú'¥H´‡½1Hv¸)¨^w%´>ÅÒ9*M9$6‘ÑN·ÕÝûC�Û|i{èþù«º®–Ý{CëÙZ¨·;sÃ\�´—„¾Ï}êÒŽpîa*Ú(´FƒE’8×^îGmÎ]�ïÚÂñÌÎYm�ÔÁ œ­zÄ\±QÔJ¥ë\eE˜M‚k®ÏÈêÚ’·œ�Ç@Y¡5WcDÉÑk{rX]ň5tn0t<÷¡hgy˜-ÈÄְS¥ÝÆ\�Ì­c™(…Ö /„­æö¨^_ ÃZsÃYU3Ÿ6>s—š«ªÐš»Ô²ÚuçQMº„Y¡5÷¶%µ'j›sR.qV{»T¢ Ô'?Àet’üêS ¸ê¹”àÞ»L -Ú.�%î„îNy.Ø‹ÄY.ØãbVéñž‹ü¤™6[¸È¯¨cU~�;Ó ÎÎvî Lꎭ{?¡ýŒHÛõ:…²åhÄ•€œ‘V©~îA䆑¹�[k �v¶{ wãDNúÜH›´K²3SâÓϹ.Õ‚cn?XÎUž/®æúøÏ_5Ïuµ¼Ù^ÊÕÓYÉeWœ…\AlxèàpÍ*ãÂ:Ç�%Z gÏPõ "gZ+¾£è=VG幯 )–~Ê:Æ™ugh@Ï`eg[‹Ë16ntÚžÙŒ¥QS tæ¹!�áh²Ï+”æÎRvK®eìÀþŒí£u…ÒÜGÊžÿµø�àoÈYú ¥çÐ8kZǸ³"[˜Ag¾y*•²íbK-…ÒÏÒ%þ›q"[Y¤½–%½L˜çXÒØÐpX­ 9Ë3Ï1[¡û zêÞqåæÚ×9Žì‰ƒrÊÏAHÊ•'yÂYQr-ÏTC‹2ÎZ&œü!P–4N˜bˆgU[ÏLñ¡8ÑmêÆ þ/�Í©s„h�¶Ù•ú öÛG�)Z…Ò1Îá:ƾSÔ˜Ýc‘-S³/ÐiÊ'3ë=…¢@@`›0è<W sdD\ÁtLOD<ßô§þñ…ÑUÓT&¡ŠËLˆi'Å2Çl¤°ÛüÒ>Š�ÿüUó]WËß­i¸ç ge‹× 4g„µvâ}.:E�-ÚXvÊz¨†¹3FŽeÃ"«B' \¹ ŒàºP \1•‚ è\òjÿBóݨˆ*íõ ®Ü,FûM³‘ž ‹œžÐUb³N\¨ˆåßPÄë©ÅQÔ/ˆ†ê07{'Íþ¤‰®Ô·¥oTD«ì·Lpå*/ÚoÔÄ—rÛìLÎiú/�©q9‡+¸q{`vªOlå .šïE¼€}š5?[µ`‹’Ùsf„«² ö�Fa«vgqñôBE” �ŠÈ¤Ê|q3Üp½@Ò»LÚê„>2ß�‰(3Ç×&¶Æ<Û�ÃÆD”…�‰ÌDkölv;?Qô°ßga+ôÛi¿í™Þ'&‹E†]œg÷£•/Ÿµ1º`¯o^àŠþnŠ¥éMP‰íP…- \)©ŽIM�I[!|%V'4X¦&xðõÛ£„š`—c•xÑx ûE+H<2ÌË  Âì”�ôæ/üäkfì~A¾q2¿œ"̺äˆ0kErþ,b å˜ëþ,' 8�‡¹¿q3ê…sÝWÞZ-гÀêr`×ÍxYãìÆw§š’îý±Ÿ~õ1d?ßkgl C=nËë*'kL™zîK“”â»¶Pkj,u”€9 „.| VÍÅ«­®õÖ¨ïb Üȳ!Ï%€--ax”n[fWÿêׂ¿öÌ$>³´˜îâ&») ¦Åµµ-¹{]¡6vø\ÌÇ1%^‘Ù£Û¹ŸO¯2×ñÖ¸Väb!Ü¿˜›êZ¨7Ö¶€ñ°·¶cëàœ4ÌUóvu¯rOìœm\p8µâ´Ïa¹V`AÑœ`™ÚÜ�\žµÏx v¼6.nT·ôÜÒŒ¸\-…ЙBB˜SmîƒÎeÖᨠÕ9�´û´y Cu R!ªrØhö&Ï×È;ª“âO(÷Õ¹O;ö¹OQù\Ô“8«]°ÉSó+]›»”?sy$‹¹˜ÓZ£2�Zõ‘N•”kè5^#9ZDΜ¬fWBÓèYZc¥C;ÏC,«O•RJ¨ÿ–5Â:´\�)â±×ẩº5Ô²¤2G›Ò³Œy‘)ìk|êÉLu#a�4D”8°œ¹¯vÎF)ÝòR•eÈ«yDhœ¿Kò„½6a)ØR™hpôq�ŸÅÕ?´Är9eØ^¨#Î1·PÊÔ_º¼œ"¬¯È�‹ê†èjýyâ”!¤#ò.Å‹·Õ¼«¹E~ä‡_uCçwÞÙZ¹åÛŠ—ÐU^b�…›&?ߥx /T*}V¨”*i 2‹Ô³.”A\�Ĉ•�Ÿ émŽýÎ5 %Má<†J¢ yæ)CÍ6«9ðmG º^J-RcZ[¤Ã:¸E �P?ÒÝ¢ëDÆém úG¤« ¤§Ôbìs¡FŽK_A‰ùÊ¢Õ9r ‰ÃÄ`‰×$F€T`“‚®³ìqé&#VBÍ òC}Hº1å¥ÐŒX ez>ù!Ì“QTÁg×Àc _§Ì"Å–á†bŸºÓ•P€O�‹”Q®L“,…kÄJ¨õ?q&Ó3×ÇĸĴ†>@å¤Ì"õ�#³$K:¡RBò±ÌÌ"µ�µÝ~I”"TB£üÄ3†¨E=£9:Éø�;-$ü‹Ñɇy’¥¼ ´‡Þtæ’Z�²”WŸ^¶¶¼ºÔ±©C“²$Šy’¶tìù.E„4ô=¹A}Š¥]‹Wt_¢8(_“´kŸgÉäÖÄ�@òE£Þ/êÿh�®j—תÈÅÎL;Õ}Æ Â.3öê"iü¸éÿÈ¿júçw4̲õEXïßê"9v¦±¼Ëôaw·éG©}:Ó‡ùÞ¦¥åyL‚À·é'Ét:ÓÇ+^¦Ÿ¤ÀéLïë6}zöËô‘[¾M?Kºú˜>å›oÓLjøeú¼M€u™>EãnÓð]¦OíëÛô —éSìí6}à°7} ¹]¦O(w¦O�¶Ûô\¦�’Ämúh•¿L ÖÛôžÜ¦� ÉmúsnÓG¥å2}ÄJ·é#o|›>C®Ëô1Ÿ|›>C·ËôQ@ºM!àmú(Dݦ�ÂÖmúȪߦ��ô6}ÔÅ.ÓGd{›>Šk?4}oÆ~üµ´Ëºý�ì—~ôÕ‘óêBÝ#°c½Îkv¡B�þ»NÁ6ÿ¸ _ˆäW§P¡‘‚< {E:AW¡BÓ q*t^»FÄv¡B“ªSè v%œ:'2Òœ.ŸJ­`ØÑ*8ýAífÖ ‰«Rˆ&é£h,l´X {ªhɳJ1u!ØÚxªž‰³J1·]pÃÛ©RhP'Ì*…Nt§0Ñ©Rp 虲9U]`�;ëN•‚ÃGܨ6¶�R’¢ÐªR°é§ÎÑÏ\0!µ ]¥HÈp�2Ë:ÐHÚôS¦ÐàVše 5ìE ýì2…†Äâ,SHJ©hkê.ShMU ]ÑYº:E ν±»_cIkÆ.¸"gì8²€}¥jòħ抜å«EUŠ2ç¯Y¼:UŠ„×HªRÔ=[��~W)r[˜ àÐ Î/›»Mš×Oöƒ&?üÁWmô\?�ä5Ñ7{Ô„×;¥�M=†ÕK3ˉ¨ñåD¶îE_N”úŒ+'²K°ør¢”e|91A¥¾ûr¢¤c¼™æGMª«œ(ù?_Nd—eöåD úrbâÖ\_N”¨¡/'&Ã_N”~¢/'²O5úr¢”}9‘=±Å—©9|91!3Ó}9Q꓾œÈ>ßàˉºtåD6g_N”¤¦/'&îŽuåD©wºrb‚<úðåD‰„úr"Û±£/'J�Ô—Ùù]|9QÚ§¾œ˜¸®Õ—%³êˉìg®œÈ¾ùìˉì›Ï®œ˜»4_NLØ Z}9‘cL�/'¦Þ¥={•½Ù}((þå]�ˆëàµ1Û7»:ÿü§oÿøú§ÿúíû~ÿ…†Î–~¬¡óÃO¼'°?gþï¡#€: ¾:��-ùÆÎ–|cgNc§¾þ~wr²þ:µQg«g«³½QŠ EDï§Õ³¡÷E"Vjã UúBï®ÕSûâ>¯6ÎPKz›©�ÕéY¸Cúóiã¬Òz?­ž]{ô>Ÿ6NL·ÍIÓÙê‰ñ'µ®®>Î&QŸ÷Ýê‰bfÓ˜ÖlãlRìy?­žlÚÒ¬ùlãlRãy?­žlþZý"_þ,‹F›xÂ.ßÚù…ü”Oxÿ.Ëöøó›Õ踶x6zŒíÀX��àLJ7Œ­ŸlµsE —ÏâF‘hC×Ç0jc/šXÂÅk@F ÝßÊc«G�K/„Ç?^¨5um Íúx†dà!TÁ}ÿ„å¤ÏФEP¿Ð  µü˜¹†ªu£àí¥ :­ ¸vI•G$TÄÎÔØAâ>p`ºZ­å‡–`6~¦Èÿ‹„a I¤»—÷CM ¸$sÐ €pt¡¨ˆ�(SD%QŽù@–¬A6± Z°R3m¬àâu°Š÷цUF7l´`ß:%í8¡ÎÄ€4õ=,Êà¢Ö4¹.Ä5¯à%9k[Jdc”]‚I*¶žö¢^ä�ކ!2”p973È9†ºüãÜKa Vpñ2˜I*OVÑ*ŠÈa Äq7â *êÎïªí*bP¢—�˜%Rmt¨Q›«Ïc J=1BÚE8µ\–d$;Ìî ±O¸­pâÆ*�þ"b›žÔ~n'êw}mÄô £¨*FU3†Ä% Ú¬-‚ÍÉÜ_òh�÷ rVIêиœ×>D‚ÜÅ:Ù±ñ»Õs·£¨·Ì7{~éG?É/¤Óµ’z:~A߸ÖOö®ìÖOFQœQˬâðª8›A?«s™cÅi(nC§ÕÞƒBG†Ã<P= cšŽTEë2F†Ç<P½ ªI¤eI�CΙá͘G÷ᦱÒfy¶¨j•Egprµ) #\³¶�ª&tó<NX=[Ù[�SÄ¿TT´*$W�'7ó+ff­]U«ÒwO/tV)l׬Ù# ‡ÉÙg÷£ÑŽzø×ÒÕ­*‹ø:—…Ás'j ¨ª[UÆ´m�Ý')£ nSÝ ¹ï¹QCû� Äà·Ú„нÌaÕÝ8�^»ª|Pžõ:•­¨�^F®Ì+©i EBøÄûZóµç*`#›n½³lÕIø2è´Ë\4ÕÔôÐU·Â¨äì*�ÚÝÅlYQÙ¯ ~æ¹ÿ)@5‚£9hVM…+d¾µÜ 활êq¶7Õ­fŒ´(�ve( ˜U÷«Ü�>òî·G§F›�KlÛl“k;�Ÿ» åN­|é?É`ËîS¡§Ý«ov'h퇸¬A¸JÍ=N%€mE—@Àö¹K€mE×tÀ¦;?ÝϾ"?¹žQîÉýPG»ÇòÖ_cùì+ºFîÖK^#÷ì+ºÆéö%ûqú�ý¿kV>@‡úš•gS±„�˜¾áÙS| ¹èG_Cîì)¾FØô¡¯öÐG¹ÇÓ–Í_ãél*¾FÏq¨îÑó€ÄÇ5W ÚìçÊÃÐ8Ñ1 d¾fƹÛûš裾æÁ#2~Ø; ûöŽ�†¤ÎÜ_€Tò5ȱ-ñÒ6ã÷�v šÙ:ózlWvØrp×t5»•¯éêˆ%†0U&ÞÕ-ÿ¨±—ÁnÓ.®5Ì÷�öêlÒw‚þð?ÉX×ï½ËímcÕ7»/”¢«/ùë³OöP›ègõ3cÜ÷™ŽE�Gž{¶Ù_Ì©îºÎtI3îˆ3âF棲q~éÎ߮իŒP„©ii”é9þ\ÇŒ¹�õÄÔ°�tâ²qŠÎ*æFâ†Ê͇:Òµj¼9E݉�¦±‚u¤™Õb‡º"ÏkáÆB�i°  *&¶t^Kªæ}¦Á6ª¤^‹ ¾½UÓ>ÔˆŠt\»:Bª†u¨=ÀTkSÔÍc˜*×îѧ<µ½çVôÆ…‰�;�õ:ˆ$®ªÚòàjÆÆí~z•Á‘**§Ž©¢Ùªyj¼Læ�íª‘S0sî‰EvdôTîI¨8ó>ƒ‡,9Ó>eH¹G“'¨íÑ'ÐVƒª¹™+;y„Ê}ÊS†Tª¨•ÛA lꈮœ©¢Äè\œ:ªP5sæ]+�Á~ :´æ%ªÎQžmBÐÁGU•Q·ÚB·mú¦P;SÙ™ìi ýÒ~Š-ïß{—_ܽ úf6†òªÝ$ÊÁSÚrœ LœFBí²Ì(z’‰¼ÏÂLp\T.¡ë"‘7ô$Ó »š©@aeRmù¬ždt�“ý¯â¾ÛTw‹N’AuviJ æœW£O�2gl¦Ò%K“‡R~z<ÂÝ0h�‚›M»lgNèÞgÓŠiœ¥€òY=É4ç>'åÖÊl ~�`£9WVºxbÕ´%]òYMÉ4ç<Ó‹�sݰæ<î“ÔœP �ó4j€<DiŽ|VS2�7ÌÑô0‡Õ™WФ|’Dö>v�iÌÁx®uU WjX-#;‘ufÕ´š¤òY iÎuŒ‡9íÏÄ‚î<Sã {3ç@R›+TÀ�U“šVtެd =²(©æƒ8»œ²d?¾zVYÛTyViX;:‡eF™;h@�yI¯²eå&Øé<zC[3ð~_zæâAIMVl%á†0»)1ÁNç©9Üæ4+”Ç6¯þМwdý±9ò ?ùIÖ¼~‘­‰»9_ºöH»Æ5GF¨ ·x:´0å÷âišÁì¥ÒÜáI@ÜK¥‹z›ÎÆh®è$ î�Ñ%sFãlƒpëgtQcÓYõºv6ºUÏHºš­œ5ΩnІì5ÎU­MgEsèZ¶èV4Wµ6�ýËHåì_®�g·2¦ÿYm9»•›Z›ÎÞä0¸ÑíMn‰é½³9 ¹ÏbË^ŠÜÔÙä?Ú_è·ÙÙt–?ÚMè–wu6íUÅ�öºUÅ]�Mn 1:öì5ı«µé¬ÚxV Ç¡Î&·>8hà^l\�n5pО¿³8u6¹µ¿Q;üÎÚ߈Üòð;}ùù�¾éQg“Û×µ|ïìëM�:›Ü.Þ¤Ízgoâš§kÏ.C?·ä>¨¯ÉíÐEàW¯ö\^u/§Gàw-§jlÚ»oõÝ‹ç‡vŠ�ŶŒú®­òÜý5å}æFD}¨f„ÙV¤ÎÈìfL|gd9„áîŠüá~’ÿY¿Ç¦Ä=nRéäw_$_üJ[º"·zi4�M{™ýÂÚ¶gîÖò 5X¹•Ihº[µ[‡˜÷K+Ô_å¶q éÚvQªqïˆe>Üï›èê°rkŠ8Ðt-€íê°r;ˆ8Ñtmw Ñone>Üo�ê°rûƒóá~Ëú‰“_4GšÜ ‡¡+·ù‡#M׿Ÿg5X�}©ir[}ž,É¡½²'3îWö<ê°rëx²òá~Ñ©Z¬üS$Äýª� +·ì�áC÷ktÐLœ®9…ùp¿"'¨ÃÊ-)(eªvîõ7h`×ÒPfÄýj›¨+·¶-0"rkk¢¬üJ¶LÕS·ìsÔëÖZPânLMò"­ð½ÄÐlCUWÂê‡,~(åôC¶úeƒÿÂ~’Á¯ßcßûK\ ´»!y¹Mk#Þ?G ŽÁ#qy<' .ƒGËîmð�ò�žÝÛàIYœÁ³e÷6xŽ@yƒOØj}<G ¼Á³g÷6xŽ@Ý{ÉÆóÁà9u-úéÛà9u-CÓîmðä-×Â04í^?G Ü60ôìÞϨËàѶzüœ�r�žÝËàÑÖ{<zvoƒm¹ ›—oƒm¹ >åòÁàÉZ¼ÁC<ð6x°–Ûàqdnƒk¹ gæ2x°–Ûà¡t<Š<·ÁãÈÜÚr<N̽¤oð� º œå‡¿ øÃ�q¨‡ï€üøÏ?©Ÿbý–&9VwU`”:{ Ñ ºe|“�ÌÏ×9çÄæ ­ø} Ø9ôyŽ9±6îÔa°óp–1��J�ƒº)ÈЯu˜Q­AG† º0ôvv]f¶‰EH�Œ¨ýr¾ê :ò‰0 &Êÿ¼k�žÀQGD»ì¼¤Ì)'õéÃ$A!fè“^§²:î„ afçLÑÏi©ÁÞ ¿ÅbP6)ú9u…tóu[eÉ:Rôó0g.¯v ²HÏÀÐALÚœtbw�S‡…uDeèËôø™¡úV~EzvZ2—ð&u´UWäg`ç &Q£uîâÛŠ­0�§0E?•‡K‡pmsNaŠ^"”Xꘆ×ZE‚–^gŠÉ‚–Ç�Œ*ò3C ú:ûtÕÕº%R+$‡2ôy.œb}ÜéŸ";ÃéÑ´š«Ð§‹u}W†þØÝ‡Ö*tg}ÉNðÏ?ÉN×o±ñtAæÓ‰+Ž�¢¹ö²S”¡¼�¦R?Ø)ªP·�¢�â¶ST¡.;E×Õm§¨BÝvŠÎÚÛNQ…ºì”Óã—�¢uÛ)§Ç/;Eê¶StÖÞvŠ"Ôm§E*?ÎNQ…ºíý—�²ÿö¶S4×^vÊþÛÛN9?îí” ¸·�r~ÜÛiBê¶SÎ�;;åâ¢ËN1=~Ù)·ÝvŠññËNÊP·�b~ü²Snºí”ä—�bWÐm§ ÷vkú`§œ÷vG¸íÓã·�¦9ä{ìÓã·�²S÷vºíîƒ�ÂìU“ðÍ´¯ÜN£Éu ^ñÿ‘�7” endstream endobj 159 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 160 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™k¦à’ÏÈ�Jj‹ endstream endobj 161 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/diff-ops-mail-server/diff-ops-mail-server-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 162 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 163 0 R>>/Font<</R8 164 0 R>>>>/Length 26324/Filter/FlateDecode>>stream xœ­}]“mÉqÕûýýhGHÍ®Êú|´� [Íu�<€<žî•l …ƒO®•YUY}{.£`¬pL÷íÝ}Î>»2W~¬\ùO/Ïkzyð?ÿï¯?ø¿ê/ßýþC}ùçò:^þæþò«õ¡—ùRóxùü¡�çµòëO¾ñ ~÷݇ú�ìkÿϯ?¿üùGýƒã¥¿|ü‡öé¥Õ×¢¿ý¼–VÆËÇÏþäåùÓ�ÿóÃ/>~ø÷|‘þÌý"ø/òcÿ¶¼ö—6^ëúÓ©]zÌgÿi|ýÇüéç5¿ŒöÚÖŸÎõþÛééIÿìúóþíñ µ¼Nü^y©ò%ÊÏžùæErÍñEìÛ?æE>ý”óëôiõgUÞ¼J‰¯bßþ¯R²>‡TÒëã/’~ö”ñ³Úß¼NK%¾Ž}ûG¼ŽL}(©Î×´^§ý¬÷þ³üæ¹§>k|!ûö�y¡Šêý5û å6~V¤þ¬„S0êクÊlÿï×Ð+ôUž×®§åé/?ß_}ùÅè¯Ery)òÚ†þïâ¯~ùW÷˧§&·ËÏ뛟úMèÿ¿Ö‘¯7ñ×û·ÿöïþÝy¹ÊyöÍOþ6ríoÞÆ¿úÅÇ?ûøñWç}”ZÏû°o~ò÷Qúë|ó>þâW¿ø³�¿8o£Õ¾Þ¾üÉß‚º»$÷[øÛ÷‹_ž70êrÜüò'c¼Ê›7 Á¿Üo ?-ùà—?õÈ�:|ùâ0üÇë4äÜò> þÍOþFòÀ;¸ÞÈøÕ_…Ã�óλ°o~òwQÆëxó.þò›ÿôË¿8¶Þ¾üÉßA›¯Ï›ò—ýwßüëóFëàËŸü †/Îä_ÿâϾ9ÏBž¾Ü5¿ü©ßƒ<ûz÷Ë¿þ«_þÛór?Û¿ùÉßFž_xì¿üÛ_©�Ü9Å£ó>}�Ò—#ÿt_óµ÷–²¿9EÍŸ>çk×�©¼t=–µ ßÀ/ÿðù¿û»—ßþÃË_þ�=’ö:zÕ_H¯Yýïõq}ûOøö÷ÿû÷ÿåO>ýö;\Á?þàOk™q±{vmÞ?÷¯/ûgÿåOï_^ˆž4 k£½$‹ö¹|ü?ÿøíï×»zYï�¿ÿó^qµè§�ø 8­¿;ùg+‚7 +dÔloêopARç¨o5¯ÛÒðký»F?×Ûæ?kTÂÖ¸LÕkõ‹ÿf½Æ¸>Ò4ô>3üu>s¿�u—C^ÏéQ´Ë^‡½Î××÷û„»I ÿ:û«Ø¬7…Ð÷ç}ßB¸�ìóÖ¿¬ÿ\ÃŽ×RŠ}÷_?þ›åáýû}þg»ÑŸ×j—=ë²ó|~žXÅ©G£ÇbÏÿo¿þ_ßýî·øÍß¿è3ù÷Ü^¾ÓwÝq£|öiNÚÐËï¾ýð8¥ïÿìå?¼üæþíŸÕˆj}úH+͉¿Äì íûOçûfÁ½_íß}¯ßg½³‰Ï½ã×»^ÞñÒúÄrã/h@Ô�šŠZú»¸Fß×SôýɼF¯~ôh"Z-·¡�ú’4õÏ7¤DI�ûUô·ºžÈdoU?Tý¥¡Ï¯$^"ŠG¢—dMå/Ñã0ðîÔC'á5­i& Ö€ˆ˜1ÂÔ[Mxƒú�Ô.p�þL_»5=“—doþ©ØÇðþm·™^{¹nÆ;ãmw=^OŽ·=¦ú�o»+¦IŠ·=³åxÛ½«ßœñ¶§æ˜©\·�ÜjÄÛžê•J¾n[s�ÔÎmççiþ öm7&QðÑÿþOß7ú²É�Fßù|pBÖ¡|ç_;‘ërÜIIî�ùe*ðîüN¯Ùßé9ÔƒúÚú î¯ÛÇ”«¥X ÏY#/—…›òORŸ‘~L/)EaôeªWJöòxBú!Õ¶žYîú¦51žø„ýüÐäSU°èü3òèIzÁ“o‰§yâ éC¬�Ø™€RšêëñÑçmO(#®þ<¤ê5zpnìïà áS(ÍŸ«z_ÍÐ_`8½eFœzø™ÒªÃ²óQ’Ú™â\yï¼Fs%N™�³¢¬ÞyÏåUoˆ×èŸÄá íÖ \Az�åÌæ•“Ú4§è²c_æÀG Ói™Gÿ�O§ÀSò¾ªòg¼4Mf¥ð� q8³æ›z$q‰žqi/Máñ©•×讟ƒ=ÞUÕ3®Ÿ©Bý«ÝTV )€Dµ¯Æ›Â¯O…°Z^�x¸F�7®æ;Ã5zÆ3ÎX{Í�ð=B  ïê1[F…E�¹æ><YÔDDï)!M6 QŒÞwQ?Ó„F¤èG ×hi÷ÝõDêa*%é}ÛßÑÏ–…”‰ó†K*OìiüˆE=JVè±5k ÷-£¼ÂfV'E;¤ªzlíÆqdô,ImzøgŠ&núNç,<o¸FϤ^¢!|NögÔ¡èýâ>…OálJô#›)ÚTzô&ŸlJàpç F•ý°$«8nó¸nUéiúPƒQ}ÁÞ�M¥G?Ž1ƒM}¸O�6•À¾›*úz"Ѧ’-žÊ±©ª/ˆ{l*©ÓÄ©>6Uõ%qò�MéKUXDZ©ª'tl*éQ€•›ªú’ÅnËm*e ê 6Õ2"ºl*!È#ØTS‹†g86•aJ FÕô%ý‰»Q%QïQ‚Qu}ÅfèèF•¤ø²cU]_q̬*ufvënU]ž 7* ×ô¨›êúzð½Û¦R©Ó`xÙÔÐ×»LJŸT×X9˜ÔPSÐÃL*U‹ä¶I�ülÁ¤RÕcX$˜”>É×fžÍm*U=†=›š�íÁ¦4ŒNÑ ôÀê»8¥‘Á4Àß5�ž²àsc!â*ECÃN}ÁU¼y‹žïÿè+ø~�o´í¤Æ¿Ù¸éWFÅ#JÁæ³>È¢x>%¢hÆ#ÌEŽC@ÑŒ'X/Åóy"Šf ïßÅó‘€¢O0](ŠÇS#Šf<Ár¡èÔ1"Šæ¦®¤_(ŠG”.mêgDÑüàD\(Úԗ䈢ùÁ¡¸P´©/©EóƒSq¡hW_2"ŠfÔÄó…¢]}IŠ(ª> ã‘E Z"Šf¤|ãBÑWP4kì‰Ïô èP œEÕ QhŽ(ª â# (Š´FUP"†N}W#b¨z€Œ»Š�4E Uðà( �êHJÀÐ,‰wÄЩž¤Íƒ¡Yô@¦ˆ¡úÒê-#†Ò4JÄPýè)áÁP5'ô_†Ê£Ž¤^ú®=u{:ºì) ¨ÔAÐeQAÝ¢6‚.ƒ:jöttÙS@P·§ƒ Ëž‚º=]öÔí) ¨ÛÓAÐeOAÝž‚.{ êöttÙS@P·§ƒ Ëž‚º=]öÔ ê è2¨€ fPA—Au‹:º,* ¨[ÔFÐePAÝž‚Òž~º=mü\æðÓÍéàç2§€ŸfN?—9ü¤9Eü\ötðsÙÓÁÏeOŽŸÛ˜6~º1üÜÆtágDÃAGš×òú?üŠž_áz†âKýÜ­jéWíï¿× þwÀM°†ßÕ�Å5ãd�N?:=.¸ùi :ôKšZž}^YKOßâx‰~Âî_vHBU_?cõ2ý L”ªú\ƬȤ?ð�É=jge êiôg§¿£G‡bؽNµ(Tôã0(Ö·Òqø†:ÇÊ3 Ñxai èŸ.v”qQõT�µ(;£É°8ý-=€8æ“p£A_¢Û*ú§‡ùTý-½ï®˜Þ¦;Õ ëWœ-~ãµL6Î_ 1TÔÕÐs‰z^Ãâ¢áÈDs\_œ*úFðгê*y_U+7z"›$µZ8.Ô² Š«þR…3A‘�J4°–²þe¥Ú¦WÕ.2ïJmÏüV‡b5}ômÓ^*«åâÎÕÔ‹›þ–ÀGêkDÕë 4©8Û”ZEÇE]­¾4aT$±Ž•Ð3,nCýMS—­¯MÕ°YÜe?ŽÅ]K'\ÿ(öw:ËjIÿÏýG×ßR³+ê¾*qTQ‹å9ÍPä•è¦.R�Ž‚¤zÁl@ZÔ²:p¨.W6Ð-�gÓp´Tm3,ÖC‡»Eôn ZKfsn§:Ôº4uìúvpMM,™MuÑb·ýCf'�Í2‚Ùék?x¦Çì )ÌNcàÎŽÝ!k˜©»Ó�C½Þ1»М3Ø]BuXf°»Ð$`/»S»ÜÛ±;¤ mnvúlÓ«‡ fv˜Y£ÙéÑ”«³«ÀL‰f§f0�e³«úƒìev*LE³«ú‡l7;�0ë+9+Ëì0sF³S Ò—Áì0³G³Ó;O¯v²Üî@Ó ÛíN£Ã‰ ñ»Ð4Èv»Ó„} Ñ>†×�šæ­Ýð4�o~ïnx]ÿÓžhxš¨9»ë�NCl·»„Ñín�8G0;õšé•EáevÀi�íf§Ùº¾v f7z¾­N“õŽ,ûX¿Ç\›[�f\êpr°º™ç‚m³ºM8¡ÑMý›ŽØnuŠIIv°ºQb»Õ¡à‹$ûX]zô¯Ò¯‘#¶Y �MêMƒJO© ’CI¤Y—ç¿ýÍßÿ�ß|÷ƒM�ÎÛ{¿ òÅÏ"Ø¿è×ÌS?áÐéþa­¦GwzÎþ¾Ih‚¬ï¾?åÿ:ÅâÝÝèâE;:y ~º  y{€ï:L²E…»‡Ð­Áª·°Ø¾¤²I�Ú)JV Z=„V šO{=+fb—þv±@–Õ–üÂ*G·¢µZVïNÄ@wÅ>õéÖõÈë&d¾¨Á±äÆûýi~Û«W1ÐűÄe�õW“ß6Rlk�è[²üÜ{]ªßöêg tŒXR˜™È¯žd¾Ú{‰uÜ�°ÁJA_<¦™,yX�©hÃc‚Õ:ÃcR‹áG·“š Ñþ<¦ž‡=‚ý˜ZË3>&.>Êý˜FµŒè<¦þ<v$öcê%>&$D3>¦!–{�Çû½ÓPŒØÃ¯–âcñð˜Z!æÇǤ^·}Bw”ÅÃcê–PžÇÔÔ¦“‚J‰�é4™¾´îoԗȪg¡ÆzÖ2ûwô5«?¿�Yë»Pæß¨¿w`Wîï¿ßLc�kA‚Œƒý<ìèóO4�É1E0P¤}Ã\£Ÿ r}}òV+H¢aAJrüäŸÉÄ åÃ`¢d”-PÏ Ç× hŒz€>’Äð² цµ>úl?yp õS-Š6¼FÏôÓ‹17'-…eÖN«_ gÏëQ¬á�Ó\ñ¥(`6F�Eϳ°d GÕî;!‰-/�SV< ¹‡W¿i=à80‰%¡½êin8 i­•iÔ€·Âk�Í#ÕT¨„¦¸yt»Õ«2õ2„ÁH†5„y’ÕMjµv ÆnXÓ[Ü0Š%¥Á +N3=ûvèn£tÌ~øVP`\¦'3[ÿB TÏAE Ë¢HÅCC8�ã ö8Ëx LlªŒ¹ÔcWë.N–[�G?t ð2HJõ]$¿mÊQÁa² /33â;uÙvã,�ü< ôMÁP K *YÅtTI\ н¡SM®¡‚£¤AâXo*�gë“Á´¾Q†\¸¼¼0�`g¹áÑ¡R.êµíÖ¥³²Óð`Ì¥ë£CÀ­o´ù­#¾FµÁ³(xšÎ.¥¦-ͺ.÷ꟗ˜ÃÓ �¦a"B76f&î\ŸŒ­ÅË ‡ß9ؽÈT‘MT¾}z([j )~ç…DÇ—Ž'3a,xgÔÜì΋¦Èf‘¹0Ôíxzp›%1d‡9aÇ“aœ5P5aY½4ë«NÖ™€Nô¬\K„Ö1}H‘A¡Ž—Ha2’`ÃÖÜÑ)±>á)EÑ9B‚ OžÒª1>JDú\ áéOBÿõ½ÇþNaµ E+âÉÐG?š–Ý6’T‘Êch‚üGõ?»éªù�Æ÷Ï„.`êskø´»ØiEÄʪㄢDè-"�ôÕ"ˆÐÅ5úà�Š$ØqŸ'.aaitšŠ Þ�×+c(�•Âkðà=T„Þ±ª¬Wá¡�:‚d éSB©1t)R%Tdô�ò„N<8<)õ…¯VEƒ² ³º„”­±/´‚ÇÁÐ…¶'I}v!jd<™¥¯�ìÀ®¶ŠaÈÝù0V…Ãs™öJzfðÀ�íλ<L}4¥È%Â/ŠšÖ�cÄw´ÂŽé»Ò�äàX‚õr�àà¼s 8–àÐv 8žS8–àMr 8†^, nÃï…4ìcSY&[jÁ#(øý cd=’Ɖõq` HŸL@2t¸ó�dè0ƒ·‘,ÁcG(›@bµŠe ŽÇfC:ÙU_ú@Y€à¾7” }ˆŠØÊxz‰T ËÐ3Ï 3,,S#°>ì³f´>Íf �ˆê3˜$ݳ`åm/0z¾qv˜%�t X@¿°,åq߈šx˜Ë‚âÔ²Žþ>Ëè­#m,ëjþ0ífêô2ï|ƒYG¯¤¶�f �5ÍÌà‚áj˜%R­0ë €é9>`–�Á�l0ëê»,KˆëÀ)ØXÖ+´ÊÂCÜù†²¦/ | Œ�õ(k£Ð•,Óë`cYÓgD8X¦¸>A”ØP†7ŠrÇF2}ŸÆoØH¦AÑé ™Þnâmo$k˜@��L?6ãRl$k(€i´�L?}!bCY�“oô@Ÿ"h ʪ~$¸ßezlThCYí‰Û�2=T$ˆl$ÃÙT·t�L�fã}o(«%ón(Ón<”�e…•’–©¡ œ„ƒei 0sƒ™Ú›q^6˜Uqôd0£Ýâ¾7˜•Ñx˜©ù¿fƒYA½•ž f cG#‚¼,î€YÂüH‹`†f Ê<ÌÔ« ï}ƒXp�ÌpÇ34càG"˜¡ŽT˜•'ÑE0Ãã `†þ‘:µˆezjgÄ2é(¥· ËðøRÀ2fŽ! d§GoÀÇ,ãn•�8¾û£¯%Žçì�¯´_Â=Yjá —l #š¬G#"dÀ�ì^?ûÉÁ<ý]–ˆÌ ‚�¼9CËÂ3N7êÕÈ•…ùu�?�!¬ø�'K’‚Ž3Ûðf°9ÆV|œoÔ´³×ÿá%p†õCm^|�ÌZsyZðÿÐ=hñxõ­T¾ÂÆà³àô ¯>Hei³:œ|;¨s‘fD>´lXWÏ@ú*œY2$^EÁÙVœEÉ�Æ w&${¡–lI†žm–ÏÑ8â5(r!NÑÛõêCyXÓ.è�ó¥0%…+JõQÕË*ìÖ¨¶Àñ%ŒÝÙ]m}äè¦Ú��Ð9è{Y5ô¼X„G7¬17t$ÕY[¿4Æ+z°d83\�B·Ñ±Êx¬LÚ1/A‘‹Ýîļ‚Ùk±µƒã`�ÿCŸ˜P ·Û®éÄUãÕ!x7pgp $çUge²¼Þžâ½9„p z�èq3hVíŸÞRCP¼$ÏxµÒ—jrçm@x³‡Ý‡Ñœî�þ$;ÝÛwðf‰4õÎDë¬Ò7tõ ƒí\é*ïvë¨ã±k€é`‚0G‘ hœp”òôí ñϰ Î aIBu~q¹Ój,LžPÄ�ëÈì–Bðœtô9'# ¤µöäwÞŒ¥Ñ (¾5ćˆŽ�¥�-õªÞ²¥;ãdÃÃÞ<S29P³fkB3�)£:»s”ò@XR+k(?j‰ä䱨ðä{ J7,N~0; ¼.‹Å*ºúRTû¦ÅÉ(Z¡}‡~¶óîÁ ÒjhjQŠVƒ½_'^SX Dé1W{-Ë*‹ßwwª—'ë¤ ”9ý¾5×G-UÐjq²ž`c–%ña‚b Ú%bMq}F¥�ÿÑÊÉۨɲ}‡z•QJòDý o¨X÷�%+c0$›³cqL^PNƒ j5Ø\Ÿ~×ìE-AçÍ`Á8”Óªì ‡D!é±£{$JL$^Ó°Èì Ä�`SöôkL²úgG®`A•š!™p|FÓø-s Yh1±LL»ë™ì€<ÏcÍD­:a¸ø]Q ä‚r a\ ÅÑ‘ ¢2j¢éó‚¨d-Õ Q“@îz *MæB¢Ò }+ †}�Ãm„Òh̤B¡/>B%���„Ò£q#gUX„5„Bßsœ¡Xr!”~šø Bq˜%]•�CH@(¶1È5ßõàd̃P©#ÍK¢žAJÝ�¨²ií¢¤F¢8Ó$B:ôúYˆJäSŒQ2µ| Šc3R"F=°¼0*�r‘#D=‰‡ä@»VO„¨ 70#D%°28° ­I”vD©_¼ñQà Bt *�¹�ß5kc¥é@”ZÛÂƆ¨‰Ì<§�Q ìÎ:,ˆ‡Hoü T‹2€š‰§äà“:�aC Ÿ&Üþ¬ Ô ‰Æ Æh¬ä€J䈌P£9á�”zÄêTn¨QyH>%ÒHfÀ§�BLžŸÀØ”ˆOoåÓƒO š�î½ði 0²ìÁ'°:9@¾ði Àô\�: ™å  Ð�Gñ6�TA®6@õžY�Ê n}TÇñ¸ªØ�Ó†¨^ +Ò¢Àj‘ å4T¶D�BŠ[ß…²*䢤?ÆQwˆBmuöQR™äˆB‰åú�QäÇÌ�Q­ «þ¢$w£±/ˆjð#Eˆ‡¦�BáSSµ ¤&ÀR( ¢™qj0‘<8…B,š"§:ÒƒS(袷ráÛƒS¨ ³àw`Ê( ¦˜æÅ”M6±6à7< «8jÛ)Þÿüµôn]ŒsÒ÷�¾Äç×z…ýý[�,Ò„Qz×';=£�ŸÙr6«Ê ÒþÉKÉb5X¦f­,&žêÄùò”b²½@´²Ü�Õ ù9jIÕÄWa#—Q3‚ÀAÊFvÔ$I;­.7A‡Bëœ,ƒ�jc¬€D«Ë�ÈÙÈëB™¥Z¤Ïiþ2½,‡Ê;žjr21|tšxMe÷IúH›Žšä�"¢Õä&‚@æ¡ð)–-Lâáh%ß‹~•�=(zW9q°æ©«(÷€z5ŒÏfÏ” Nz=«* 2*)×ÕM›¾½*÷=K�ê\íôjÃ@Ñô€ä.@4<·µ%ÀÜ‚¢—åPxŸÕxzœ€Én‰›æHefµ6ï8¿âÞ�Š]<°~XY'Ðî¼ @ÞSVaŽLÔPQ»ôÑ3=FDE«Ë%c‚‘|hL±©#‘U–šCTÁ­)�ÑKÛ¼.—@3QžçÛ`F‹‡ÖïÕ ŸÀlo-PJF'#¡2;iÞg—¦×åõ P©­žÝpžÃ0ÑërÙgänÚ "½,â5n[Ю°0ŸÝ-`¢Wå²qÒ’ ëaéBµ ¨ÒVUäl‚oòÛæ�Š¥l^”ÉÌ*µÍÓDÁ€_0†ûÇb_´ìíh4­÷Mf…ÑlÔ6r_íÆçÃQ*24¬(¢7ë°èN�£7“�èU9ý-ÏÖòº)6oºˆUå@o²ožápÊgó´ê2z!¬q=~ï³ùP–¥Þ„³Á{G}Ãî�Ó�˜ˆVA‘D:ò‡Íu�¸iy[ÏöRú% ¦ Ÿü¦¿�H�’c™J‹D*0ìšl³]àõ<ô¤TôµHÔã…Sñ>�éxj¾Õn<?ÅÆ¿0º8<îðYa°lð�¤ÑDP,âñ‹Pß°ìî 0d¶ßÆF†Â·��¸Å€ Œ€ )Ò˜2`Ô¥dÈì(Öˆ fô½dÈlL¦ˆ œ‡™’u8#2 ši’uJ#2Éð83bC¬öó²L@†Ä®m‰ÈÀ¡š�!±û�Aíç�C²&rÄ2³D`°^tÄ2}F``K»G`@,Ó.``c\"0d}ü5E`°þz† ‹�Áúôr¦³ À`íþ ¼Õ{À°X2B¨�ÁÈB±� FaÀ�:a �ƒ1!"0¤J4 À@FE†„ð²G`0bF†$„¶ ÆîˆÀ�ò�ƒ‘D"0¤‡@€ÁÈ&„ÞÈY„ï-ƒQ_"0<•áC�Rh"0<…QH�câD`x�”H#ôD`xàÉgƒz†IÒ $I�†‰\ë¹€ÁˆJ&r6´Ö0á)�ÃDî—%ƒñ¦0€'h®` ýª`˜ÈEÑ];À@WÀ€º"€ Æ;È0‘ƒß|�Á(el}Øæ� yºô2�Þ��Ê'dd E. ꂈ¹/dבpd`³sÊ3*,‡ià€½'¤ñξÊjöËy|eå1øòi4ŽËž`�AÏŒ¿GÉGà“ñI‘Р¡n†Š i&jusÓRƒ €ÉA*€ÁídBƒÿb§dF‚ŽâŸŒ%¤<HrŸŒm‹„&%/<Hf£ 0n0 gOCzŒ|>÷¸6_- FˆŒ@SvßhkÅ�‘�(Á'ãy#Ÿ�/Ÿ;Dfܯ®÷±øH|F*#§(\ðÉxÞ� •ÙADŒÌ°_‘À;†kêÒƒä mðÉhÞHgà̭ć ™)�~ÒvI­QÚÀƒä ðÉxÞÈfpˆ­Ò…(yØÐÉØLï ~àArPH`tKÓFŸZ¬Ô•1ÎDeú�ƒé<J* ŸŒé­h O;HŽ5÷5^ž(¢àArZ`pK®:úÔóÙA2ù úaû zQhÁƒä Æ€klvºÁ¡[•Aò$à¿u´‚‚ƒä8K¾zƒC¶Z‚d²Fô˜YXŠvO›zŒ$ݦ:àÁ+]t 8Ïšd¯%<F² n;3 •Ì$÷iÃ66òXëC«#e\2‰àعj|Ãê€(×Ù {z¢6k.9ÈGàÔ+´õÅZ"WPR ¬Åk�ÁîùWBÀ&p…対ÜÎ(˜V(¿ïÔZ”˜ ØŒ(CÁ߇٠|y·Úp1BRÕCöpD'!ƒÝc´Ä¾•*8�ÆyTq[K+‘Dk”äœ@®Q[bq�rœXc Š*އÁ$Ù°V8üÖsMQÎx�$J^pª­2ŸA<ºbŒNœ=kðYå>£ê®Q³d18ùƉ”qÄŽ(ùG 7¦j¡}–gD] ‚Ó¤3>} Bñnò€é@(#JÄg@(“_x@(gï;J$ÊÙû„@Ô`å­o!ï;Âg„ÜiƒPFÍFÓ!|Ö-€PFÎ>Ó!>±B9yÓသ;r§ B9Y×á€�O ”‘[<á"wÚ ”™£¤B Îr@(#ÕaбAF�ÔiƒPFÊÄ>Ó!W‹ ”‘z±Ï´@ˆ6šedpl°m‚¥#sÚ ”™ F*IÊÈ'ŸA~‰Ó!ýQá > n)’Æ B¹-ÓŒ Btƒ„2Rdö™6 #é�B©6ûL„è•s!äìr�œ;r§BÓ»„�È�¡†ÀDcƒ�0’Ž 4kµDc�Ç6çB�‡q@È^4‚Ðô¶Ã!¾wdO„¦µ6ÙG�# o;lâG‰ìé€Ð&€¶AˆOÙÓ¡aÓŠ„ø`‘<ÞuØ ¤„ Ã�BÃÛ „윥B¢$|,âqÕXù€Ð°¦ B<óÐ�; „IMBÙ!ÚŽÞw�¡><»Z DÌ%‚aD˜BfÊ„ú*P-â„òl„ú*t-2Ï’#õU0[ D…$á€f]ÉÃ_ D/W%‚P_õ»Bt– Çò2à!:Ý|ƒ�W „Ìs§„¬$¹A(Aå-­�Bœþ= dsh+Ẵ&ôp”H1ÌGéðË|-A[—óÜ.¥äOë40-Œ/ëëïmL0ƒ¤‘]‘€:<˜°Qý,8OßÉ�cï̼Ò"+ —®hI=N2À ”%^k„éedë;É�£RL¼Êaœ�˜ÉŠ�s± 0+%Vèóš"F’¡F€ÖŸ§ M<óZd$ÓÈߺ“  `ÄÔk,®Riè@�·z“2Yêe1¸ ‡°.†„’˜w¥5Áˆ®#ô 0£`y¦¤,ïò ÆŒ®cëäê;Ã�cRL¼Š32†ŸÕ`ÐÝ)“bâU�© `0p×0E§@� æ�(î.n£�ã¦X<ýè–~�ЇóPÄ‹ðYhM +ò™Ô�¨´aYLû3ñJNTÈ äb.�S â¬vË>@ÖÉÌOfù°Dç`LŠl}�êLb!1ͯ˜R0»Â˜Yÿ`ÕY4Ÿ™æ7Ž�ØûiÉ3/ã*dŒ=�‡8=âMÖj‰×p®BÆÜðŒÓ#N2°ü‘à´x¾3Ëoœ)ò[zë’ãašß8>b×$K@@oµ[¡8Íñ‘iE(§ë‹“2ˆáúR˜S°Ò.椈VÕ¹ ôr  ÜYµJŸ)ºYçôˆ]Ñ-ÿ@¡ÏîcÔá‹a�Y5æ]Ó™ „y‰0;Ã�–w9Q!ƒwtÅ�‚3\ºÓ/Äïì}`4§G¬4)ÉÓ.Ô͘PüÅŒ‚!ØÄ*�êL"3ÍïœqÞŽ)â4WîÍã4d1 à¯-ïr¢BÆÐÉú}1 à÷W‘ÏîSÐCåôH^ø�øüÖäJD4³ÁéüԜ~áŠÄózÚ§G ‡äñÄ«Y« SÝ(uLyˆ»yÕ‰ Ó#ùÛ` “ð:,ïjÎTȈä´£2k¡ŽÒ+äÁyë¨ ‚ÇÁ鑾ОyZb&žÔhg“ã#cE –wu«(fÔ*1yVXâeìQ-óÊ>Ê•Qñl…lýé݇Ì�"à·’¢‘Q8íè.a|Ä‚%dZÅä‹ìÎQÕó69?âÔ<›¿Õî±<y)½ÊÌpç­¯‰ä/�,ƒ´Ô7’éaK) Ya©ÞH&¤‰l$ËÅÔ ’A¢(µ‘,“¯Ô#’¡h´ÛH–‹)F$Cñ½–€d™|¥‘ Eür�,Ó”H†VÀ…dl¥¾‘ Ý„”’åb¢ÓÉ o¢çâ YFw¯¤€dzì;Î×A²LªRH–Ð#Q=H–ÑÝK�,¡ÕRK@²L¶Ò H–б)É2ÈJ#"YBã'·€dd¥�,¡}„Ñ´�d™\¥�LÏ)JÉ2|%$K£�ÓF²L²ÒH–ÐÃÔÆF²Œ˜¹Ézk5"Y&Yi$KhÑafy#YYiD$Khõaöy#YÆÚ ’æ’%´ SH¦xSÈßÝH– çƒYì�d9»ÓF2Ŷəî�dý½<’%´B{@²Œë’%tTk@2Eãqp,¡'‹yå�cºüÔÅ[8–ÐÛÅÜóÆ1PÉÁ±„±ÞÛÆ1}ÌÕê Çôïòâ�cÝ=£¹ËšÈ|̓cÝ=ÒåŽ%t½{À±Œö^*ÇšçúÜŽeN�oKbÊéÅ4€+΃_Œptò¡¥¶Q,?(ç€b d€$Å4 ¤¸êA±Í*=hÅ2š{Æs_ºúb‚ðÅÐÝËó ˜ÆÀy@14÷RD±”M{> š{O (–Põ+9¢Ø¦K¨êA (†å=K¨B‚Ê~Pl‚�3Š©�öˆahí•0Œ y�ꆡï0Œ,ûž. 39؃a êS@,`º0)`XJÃõΆ�ðÔ†™¤ïNú^P-ñ.^Fù"N•µ#Gøî�¾’(†_05å%F˜=D²øÒ4KøÝ÷.S¦ðª§qX�\–?Ñÿ·_çìüõ´Ü ý`’õs±ñ½ŒL 3g¨ãÚ4asÙ÷ÇflYÒ­6s†ÊãîO³´i³º.xÒ?ÆZ»œFG@³á1Å3áôà¬&×@zŒÒ1œº*š&” µT»J×�PVÆ(²üB`µqB4ï­�êÂÇ”MCˆÊîX'WÃæ¡'>:C‰yx¼¹8ŒM—´Z§fmΛ‘@îHelÊ`’ÓWˆ:ÄºÓ 64&ƒ¬�/ùµF}ÜúØ�}1.K²añO&Þܨý׬)*¼ãYüÆ!І©3DQÓÃM#ÖÀ$Ši'v_�A>ŇŒ�Ëj’òAÀð|L( Ìa2¸Äé�kaî¬ Ä|6J!ÿñ;‡Ð%ä2Eb>“¥1¬~ç|Æ~D®¢‰±ÄO§c¤T›:{(CK%оK,"­$„4*㸄+üô�¦þGµ8ôû† «‘åCí�œü¾‘kaè̺õŸ�,$L]E×ô䥙M󗤣«ö¸p*OŠh@]Â]”ª�ßiêÂiš 8qÆt µ“:™ öJ�%~b•Ý7êZœ2&ëa.Øü¾[çìU'±ÂKÌ,ñ:›kFvÓÄËK3ì0Ü9ØîÉfÎ@ôx¬ä�†‰€B&Æ”é QGÛÕ™AV#ãCüÆQ:,& *=a´™L(äyD©�§ #é+ ™0ÏCah1òQ¡” F?i0ön@#e®ú�S'O± tk#AÓ�Ò¦à4ðΑkqê,­>fz„É À�—–^¥¹«[c¦§°�Ú]Å2qk�$dK-„5~Æ&º‰r1¦íÈ5²€šlÂ-AT�1w†"³µ‘0Ó3˜ >~ë¨^Sì/y ê‰sÁ⺜¬H’@eog C@Ðø¬Æ0wo#a¢‡(º”Q�Z£ÂìݳÄ‚”£I–¢¬�Á3£„±1Æ?ã}»kt0mgÄ2†È¬ï3k°›&h’óÏ #íÁ›FöaòžhUôdÚ�Þ<ë,ð3‹1Ö/�/#N)àÞ¾ž ³¾ñN8÷|ð.Ok¼ƒ::ØÞåi톀wTïô·»:x‡Ê-°uã]Få—š\ï l:ÞåΈw©É�wyX+æà6bq„má]è礈wPbÇÛÆ;=ÕƒærðNs1ްm¼ËØ1ôHÄ;¨µc„mã�Ù¤ã:x÷LÝÛx§Æj¶pðîéÝ;x§ÁJÂ�¼{0ÁØÞ©ë R|À;ˆ¾c„mã�ž1,ÛxÍ�̰m¼SG6 7ÞAClïÔ!šÃ9x÷<Þ;x—êµ3à]‚|üsðNÝs»ðN=8qäà]n-h.¼S$ ¼S´0_¼ñ.ÍÊÙ½�wŠ9æÒ7Þ).ñâ�wòÓ„DÙªñ™¯yðN°².¼S”Ä[?x—ët Zx§X[�ܲðNáøÆ;j‚+²ñNÓm‡Í…wÔådã]®ÆÔ>xGÍÂ&ïr5Æ÷Á;îê�æà]µnÿÁ; g8½ð®kàà–y€�sð®�Å~ðNƒ+ù€wÅÈðï( ‰±²ƒwÅHõï(.Ù{Ä;0-KxG‘Ê&üÞAé†ð®Ø°ÀÁ;nU‘ ïŠ l¼K=Ñ=¼›]8x§5Ý\À;éÓn¼£4éÌïÄf)ÞqULïÄ&2ÞÙlX‰x'6ÙqðÎFÌ"â ÇCâÙ Z‹ˆ'6erÏÞRD<›U9ˆÇ¹¹§Gij‰—ƒx6~'âÙäÌA<NñQJã ž˜âQ~7æ’|ï+ÿD}åVÊ�KeÞÿá×rÐó+¬¡nA||VÊ”y¯”áaîÎæñ¢3Ûï›ÌC“ ôIõ¸Õÿ‡ëJOWêž+îæÎ„¸<´O"®¬ÀÕô+6—‡vN哾onVTº äb{©i ‡Må¡ÛiÆäñ¸;MbQy輺sy<ìÎÆ¶Ødú@d¡À�æY€ ‹n6OFù„Ò'Ã݉‹”[lºdd¡Ä/â‹d³yèÚÅ–›#"qÑäQœÎC„€ø  G|ã\»é<šfl�»“Mä.6áŠÚ'c‡ÝÙ(6›ÍCÔC ä1�qñi�Γ±L‘ê'}¹!.�lB0’P@�¹!ÄVœNXlB9ÅOêrCˆ­HÃYl†?™Ë !ººè< -�‡fYa÷ct¨Íæa€Bñ“¾Ãî,¾ÚÎÙ<Œs�†zœÀ%æ\7›GC�ÇÄOÚrDà.æ@æaØ…<”ÐÃ+šÏ§oB)¢71*�eÃØf›NŠ�Â'ƒêŒŸ�¶ÈQ‰Í'E$‰,¸cHÉêZ�„R¤T>iN[Cd…»>|R„µHB ;v�ïðI‡UHåñ¿SM­ðJfSød.Þ"+ TnB)Âu1*ÏÊL×`óIóS÷¤/öB+îæ“"u@ ÔñÆÊ©-2J§•@æ™ÞùÐËg$”În"ð€o|ˆi>B) ·ÈA�;”Õ´#6—GP�¦òÉX«®\I$ó ÉHB<Öù`Ѻ2�  ]Š‘y’¯C³èr“y…m$¡�ë|°€Þ™GžjŠó óXëÑÕ \ý¸¬R .�mAÀÔØS—GÌI€Èã�¹ba·yÕ~jŸtgneVTÖ^DAÓ€Û"Ò^HÖ»+t;“ç Ò?œm}ÄF ú˜²‰#�¾±±ÒÖ…@HZ@ �„ î�K±Æ¹HP¹@§á b) ›ô½Xª´ˆ?è� 7Úø#B§áà"©ðG0!ÔÃ<㨠ô±¬ð�²Â�?z§•¼7þ �¢°ÉÂ=ÒüÄþ ’BV¸ñ'£T•.üA(Ea“…?܉�‚ûÁtÄ l²ñ'cB(l›údÁÔŒøƒ¡FJQØdãôq¸$eãB)d… ³SJÄŸlIBÀŸÑ¹Bëà8¾H þ 6I¯�? ù")<øƒ'E¼6þ  ú\ø¢gÔ}SæàtŒ¸efãO²$!àä�êŒøž/Òƒ?}&_h³ðD_J›lü�8Sœh ÏyáÆ£¹:gãh¾9àO/¶ñæŒ3Ìn3Ü:¹�×<à ”ü�hn; 4´aÊ&  }EÍç3ÏP l ¡U.üÉIáÁŸFêä5Ð�‰²Ð}À}üË7GüAƒKŽ•_�uþ yÅ禒¢{…¤ðàz`açË�Œ@þ ‘vqIQ7CNxðªi%â)¾È þ@}�5ÐÍ%EO.ü©­z-u‘IY L*©»‘LŠª""ûƒ?•àH&EÃIáÁ´=Y(ÝdRT8‘üAûôâ’rI¹ðgÚÖªÃ%e½õB ²£7•”{RÚ�@Í jSIYûM‘ªý†Kz¥\aoY«iÏô];ËÞùÁ×Ò³u9NÁÈ+9×g[Y£ÀÙU ÷Iâeÿ Ëñ-Jü}½ Ë,NtÛFø¸¬K†‰sØOÖ�5£ûÞ´ÄH�e((Á¯EÕ•gK�o±¥PÖá°_ZÇ™;êÞÆÄH�coåig àaê"´?9gýžuœ¹B¡¬�M Ô+ç,Êà峇‰cÚÀc‡™ òÞêÄ8]lÜ/¯ÃÌ Èb -b‘ïé7nu²ÃŒJ©áž˜ rFU‡ã~Ï:Ì\¢ÀmÝd�3ª:˜÷ö�„{æ^ÅÎ�u+‹—–ÀØÅ�ÏþL+6ï'ë@s�Bߤ¬sê­²–ê³,ÖËϦ,Âî@¶�¿äúÙ™«ÚÞ2Å`�sÌ�ƒ·Ý—«ó²¸êuFEÃ~¬ÛÍV¼ú*†ê•Ã~Å©ð\%Ì]Ž&,ÂH�#o\BåÃBF–ð=U¸¤‰Íúebà…n˜—=Pç”8×T�„KÒ^e…kf²Q¿g‰1p‹QÏe¯Â3€iÖñ�œE�-ÓÁ™Mxh<Ù@æ VTë«× Û¦+q^V7OuÅk�E�ˆ€:F#á…l ÷X¬ß² ú%�È\ Ð÷Æ,éìÁw6J¬®˜Œ¨SLV×LV lc–Õ0…|¶µU‹¡z±I?ñ�nHæ ]qÍk�Q�ï<Ã뜶ÖÖ6oá›ôËÎÿçåLÁ¯aÚÏ›À¤p§yÕõñ­¿bÈ›à¬ßãZ ™;šÁžÝ:fj1ëÜ©E‰ëq}….,XÀ™$™;€D6Þð {É„£~Ùµ³3W(Ì½å —$vá!äfJ ™K(ù%.� ³à¨Ÿï×ÉÜ¢Ð÷&0\RXÍíÞ´2·($=»q˜&ý°ŠÇŽ(×(Ô½- ×ôb“~B}\\“HÆk6Š‚K† ˆÔîKU¹D¡¬…bzj9é—|Ï)W(p€bXCI`ôÃJ±î� ãúÚ1\#¾ßþyÖØn<ÅV]óú ”ä%E”ªT9(%H7r¿PJ†M.”¤a ‹d6n¾QJ˜n̈RÒ9 ¸PJ�pŒ ¥ìcp£” áè¥�3´ˆRBI³Pªr ÑA)AºQrD)$0Ü(%H7òˆ(…ÖçJ Ò 8œƒRh¡ap£”0ݘ¥�–qp¡” ßJ[Ú~PJ�oôQ ib‹(%È7A ¥�mr p¡” ß �m”BÖŠ�À�R„cD”B¿“� ¥9f£Ú¦˜\(¥©¿D”BŽiÀ�R‚|ÃÄ“J!™¥ù9ž¥PÀ”ÁB)AºAÚ(…Ò‡¥Ù�l£ ˜Ü(%Ì6fD)4·9 ¸Q ùf¡Ù·˜Á8(5m¹£Tƾƒy¡’ [~l(•±6aD”b�>”ÊØ¾€!ƒƒRìõ�€R è�Mn”rÊÀA)2o1 xPÊ™¥H½ÅèÄA)2"J‘zËQÀ�R˜(|R@©Œ-óB)²)úA©Œ]Ü(圌ƒR+70 xPʹ¥4‚K6 ¸QÊ9"¥4Zäd@)äPŠô[Ì”"c¥”"ý6E”râËA©Œµ&˜<(嚃RËQ8 ¸PÊy8¥2V¬`ð ù<3 TFi£€¥È Š(•Qaä(àF)c”"7G”rŽÒF)òo9 ¸QʘN¥2¶Ø`0 T·íw¥2¶áp‘ÎA)c^”bŠ·S6_2½VSWùÁÅÔïýèkiÞú…Ͼ|¯¥¶6ÖYL Åÿ�êAÎ=Ÿu¸“󤃢�sçèà\•ªìk,ŠbUM=s÷Û&˃¢XyÃÙÁNÕUþâóò E±:gœ­ºŸm6¦ˆ¢XÀ3mÁžñ7¡£ÐsO{÷.ƒ.²Ü 1÷ì(ê�j_dyPjîr¶ó2ö·E–E±›ãƒ@Ñ챿É+mdÏmoðÅ%¾Êrƒ¨ {Æôà|^Wðß\ßÙ1T�<ϳä×ø*Ë�¡‚ä9„Zæ„íù ¨ sÎg 0c°Ú*Ìœ‡!¨—ðMk¨ s®gQ0Cÿîbc‡þÃFëJí¹ý äÎã,fèïâ^ D¹ó´ žÚ—±4ÂE…¹óY8ì5�4Œ rgà`Ô²=î?ˆ8*È�å,%öSéG¹3à8jUºê„å“í!yngq1K^FX> ’çA$õªF5ÂòN÷�9Ï³ÙØëoO‰ùHFì+µçöƒˆ¤‚ì9ŸíÇ^”ˆ¤‚ô™ÃƒuåöÍ Ë'ßCþ\φd/O¶ó=$ÐñÏÜPc¾‡zì5Ê ÿmìN÷�>O[@à%ºæ„å“îÁ={Ó²WnSÄQ�7Âô ,�Åîtå“ìÁÉYÆüÙêÈ¥ÅlΈÃ[k±;]ùd{È Û^ØLp3¾òÉö˜@OÃQ¯G;aùd{H gÙK�?[…ý‰@*pG¬>âÏJ=îü¤{pGù,~þlÉ1݃;âð ¬ÊÆpÊòÉ÷à�ê^ýÙúHé3Š©=íÈ „åó=¦Ïg…4®qÆòÉ÷�?O_Cpš*ODÒ/¡J�ž¤ ªj±ÙÀUž ˉªdÚlà‚*Avr—%±ÉŒÃ� ªÙ Ë›ª°É p¶¡J˜žÌ«,9» .¨¤'¬9žºä€\Ý�*Av"WUrÞP%ÈMÈ<=eÉZm>pA•€úÜeIô9{€*a~2b‡5fœt¨ä']b¾‡5f\P%ÌOfL÷°Æ¬–�U‚¥D¨ÊØ TT ò“X’¤úO P%ÈNR‹É‡ª³�ÏU‘¤ÑP%LPFÌõ hÄÙÀzò{ãÛž|�ÊH3@•0C™1߃ÂR�P%ÈPJ„ª ¥&.¨d(’bÆGŧ J�¡¤«0 ‡ÀáÀvR|£Üž”�T#@•0E1åƒ�‡ËIñ�r{²>bõ�U‚ %æ|ÕŠP%ÈOH<ÝI´¹8Øw~_¬k’>J|õ�UÂ%–&3 €ó�õ$øÕ‡VÒGɱaPåµ�Ç·'é�‚ ª)ÊU h=@É D¼•óQF­¨"‚ã;çƒgÛÎñ}Šb§|ÔtëªHÈ šíŒŸ$'T‘ØAÞÄNù(17T S”S>HÕ�Usôª2ï8!¸¡ |cƒÈží2®Ä�*Ð^J¬Lf” 9!¸¡ ôÂÐÎù(ä7"TM¯ý�œ/["@Õ´bHú(y€j>¶ue|Ù¸¨†¯WÝ)$9 x€ÊJ¢!å£Rb¿€ÊJ«oR¾“À�„�埽‰<¬!xï_IöÂå<µu§{þ�¯ ðëöB=½OP�ýEÖ>Áú˜÷�~‰u«N ¶Ðä¸�€Äf.ñ[ªÓ‚yô÷¨sh·ê´`½Æ}*ËÜ]¾T§óè=î# ó‘ :-˜GQušÌԃ괞©4§É¿”¼4§»‚RÜF@ò%‰7KsZ°r(Çm$²· 9-È™K\F 'ÖœèÖœ$Í5.#ÈÐWq� iîq¹—O\F HšGÔœ&÷2Åe¤9.# ûRâ2AÒœâ2²/KÔœfÍq'j\F È›K\F ¸h£<[sZ�7׸Œ CeyÄe‚¼¹Íi’/Ÿ°Œ@�5�¸Œ€ÜË—Óæ¸Œ€äK šÓ‚¬9Åeä^–¨9-L›Ã2ŽªÔ¸Œ@�7—°Œ@#l‹”¶æ´ o®Qs:CayÄe‚¼¹Íi²/Ÿ°Œ@�5�¸Œ€äË—³æ¸Œ€^I‚æ´ iNq�[‰ËIsŽËè$k\F HšK\F@WÛã2AÒ\£æt†¾òˆË„IsÔœ¦ßâ2AÒ<â2âGŠšÓ¬9.# 希@�7§¸Œ€xVâ2AÞœã2âb�Ëys ’ÓD×5ÇÏ�¬¹Æe‚:âˆË„Yó ’Ó�û 8-H™G\EÀ€!EÁiAÎ<ã*Æ9®"$Í)®"`øRâ*‚ÄvRmH¨|ëĶZ]��À¸ˆ@h{q�@t¥ÆEÂ%[$@»¥ÄEÂe]qAÆ6°ˆíü ��Þ)B‚Øî°� úðS€á²½† c؈k„KÌ₌E`=®!îB ��Y´�kÄVªHÈØVâ±Õl2V�帆@¸á-®!ÈÔR„ᢸ¸† #Þ{â±…s2ôzF\C ¶¸.@B†îO�kÄàHÈ�ªq �ؽ� 2D%®!ÛÆ !c˜H[éw !#2Oq �ØbÀ� ¹Û@è�á‚Á�  M#®!î)Œ��»Í§nH[w !w›rÝ� ¶11@Bî6+{ A¡Ñ¸rçÈí�Ã|†5¹ÙÔî�¡Àn\CÀ~ù×Uz$äf3Ĭù×°}ßã¡hp\C@@�k,þ×�JP"$EŒãRÿnH ̸†€Ô†Ô$†F„R$ž A¨Í×äj£ã“5®! cCc¸ B­è¸†€Ä�!c9l! {¤´ Ô­Ž[ÈB‘!!¥ ¤²¤~A‚ž©qm§)V1‹�0’-0ÝÛiŠUÞ"$4ãy];bBòf Kï&1ïüàkI̹œõ–~’ûf%1vÝIb²:Þ“Ä€r’lj¼“ï$FÌ¡†$DÅ;‰Á™;‰QñNb°ŠæNbÀF¾“¬´¹“ï$åw¦â�ÄÈ…Xä)†$‹ï$,Å;‰`ç•Ä€¥x%1Øt'1 )ÞI öÝI ˜ÈwS,$I HŠwƒiò;‰IñNb0M~'1`)ÞI 5ÞI XŠwS�µ^I XŠwƒ yw–â�Ä`CÞ�Ä€Š|'1Ø�“ð¯$Ãäwžâ�Ä`˜üNb@T¼’LŠÞI ˆŠwSg¿“ðï$ òbCšâ�Ä`?Þ•ÄÈãiëIb°/&1d*^I fɯ$†LÅ;‰Á0ù•Ä�©x%1˜ ¾’ï$¦YÎ DÅ;‰Ár¼+‰!QñNb°ïJb»?î$ûñ®$†LÅ;‰Á4ù•Ä�©x'1ÝÒÖˆXPÆ»’Œƒ_I ™ŠwÓ‘·¶ ±Æ|“Ä`EÞ•Ä ¤u%1X�w'1¨ŒÝI VäÝILf]o'1%¿“ÔÉï$£äwƒJß�Ä`þÿNbP1¼“˜ ?'‰Áú­;‰Áú­;‰Áú­;‰.8} ë·î$f¸àô�¬ßº“˜ašÓò“Þ$1Qº’Á¦å;‰�Ó•ÄèטÄ@Ñé$1‚Ý[wƒÝ[W#X¾u'1X¾“Áî­;‰Á4͕ĖoÝI pðJb8Xw'1Ð̺’ŽÖÝI ´·®$†£uw ¯+‰ìߺ“ìߺ’y,ª I p]I §ëî$¦yT{ ãuwƒ9¬+‰á|]Lb “v%1®»“¨­ÝIÌ´�6$1m»’ôÝI –oÝI ¶o]I voÝI Fë®$swÃ�ñ$`îîNb0[w%1P�½’n°¿’èÐÞI ›ÀW9Û+‰a/ùJb Š{'1ìI_I Ôuï$�í;‰ÁŒä�İA~AF-ï$†�ö+‰�jð�İa%1¾“6þ¯$"ÆwCÁ•Ä@ ùNbHD¸’ˆ*ßI ù 0{%1Ί� ¹½Ibœ] AR„ch\I Ô¦ï$†D�+‰�hõ�Ä8_$BB›ï$1!!y“Äh2¢ÿûÝwÐæ·¯ý?¿þüòç?ü‹_Á“¾|ü‡É~øÂ%ZˆhÀ�jõåãçò�¿ûí¯¿ýýïÿÇo¾{ù§?|û‡oÿôãÿüð‹�P~|ù=e¦-Ê£1¬nô qýÀOï„é]Õ£¼œäŠ¿ÃÈ»­ï>­ïPŸãGä×ú÷ß#q¶S¨Àm¹JxQíÁAsjü0™Læ! ÓyÅ@Ì´ºI`²0žI�„Š…nx[X1âžäUo=ç/”ËðbÀ4w�É®áUoâ-•9¼Þ’Í3AÈ(T£q™DeÉ¢¯ÐykTve`OÒ¦}*õeÑ/èQ|ƒ {8œãÙ©÷ξòpö培jr-lH »õ yÍþîû…•a’^’kÃ{ûÔŽY£Í SÁ"ßøµýîÜ<·Â’n¡Å˜z*…ô»õ>9:Žî|O¬¹´>Eò�WËaí …� °)øSü¾X/—Cáø‘|Ͱû¤²}¶¾1‡°Am¨æÖ\�?» :Ôs‹b0ª–µöÍU“=ÛMãΘÁ]¯u Éöyâó l>!õ§D†6}Ý‚m¶A‡Ÿ A`¡h˜A*¶ÄŽZñÅØ͇̉qäg¯mpmôÛ)|nM¶P€ïÉT‡§5"¦1SL”d Ê9ÁcVB?ÛIÒ*{1Ý(ì„0©·µ]£.1‘ÒL© $¨¢~!Pl©å IÃô°@Æ…J8­bëo ˆÏIP� DÛ‰ÈÕGû3ÓÄ¥�yPê fIs‘äE!ßêÃÔ–CzåˆTks�ëÞƒwd»[ò,ʃä:ÿF@îf‚Y�ÐK™ø4ùć݇gL• ÔÕÂ0¿›ÒBQnÎ� ¿%ÐRÕ ¡¤Šˆü³mœ&A-§­æü±m[ÇÒÜ �Ø“µe{‚/þùk~`]Ì]#{·¦�žRmï� dú€Fu-,œyÌXùjÅç´ÑµÅ`:tz² &©šý§j³ð�ŠXPu”ײ·qs·ÁðÙóNµ+�5êZa*=ûâ‚aÓý°$°{rí=Ú�9ðap …ª�¦Žµ—µä᫲iÀ° 8Ÿµû¯³ûAú8Pn�Ôø¾Ù2ŒQŽAwúô/A¨�~€ï¶­ÉØâÔÑÇû�¿Âts}�.O\o5¦9ø<°Uqž|eoíFôæv�î¶™cèMu×;67D èpÐ0‡Cû¦Y T¡xÜÍÒ�löÊkáq«¤_COÙDÀžL6,lͤ·ÛpnuY«ÜÐÇÃÉ�P‡+ñº÷ƒx„ ›�©ñ"ˆp˜Ú5È}ä‚Ïäòq˜Û@¥n®ÕԽ݊vEaøˆÎ°oÁ†,}€†Ó RP�7è€�žË|ˆoÀbT §è ¥F52¤—çfßê;ÄÇ0~1ÄKºë€3بUØÎ(Ò ääZvàåéŸ�…m'Á0�· y„°µÄ�á+°¦×ˆ›ûYú€mÕ6a!{Ëné%ÆŒ»¾ýÞ¾æ Öåôâa‰“}ãõl^µkÛÖVÍþl»m£‘»H� á>­¾Ü´”k1™>±Ë“ L9™;€RòȦÈ£Ü,nÜm`oð°ÐfÄUè{!bÀl’;(Ë4•ÃjYß™™+€vqsùàì'™ÃXÜR6ÏÂ-˜çt(M+†ˆÇrÜìEóÜ‚ëGÌ0 䮀[Ä\€ÙÄÝÑvQXĤ�»Œ�dÒ—&"�OAö+Ëp9§œ±KQuÜúÕÏ"¶azž.ŽÄ´AsWÀ�oͤCM†M²Œ}‚c¹.—£�ÊÒ½WD-½ùð�­±£�îíO·2yZ¾€ó²i¯šš¿¢ *àð»ÕUøm ï^—ÀÚ—‚4ÕîÏ@èÞÌÀºÖ ´ÄÝpá`7åZßÿ�™wB·Ü[\nXM%××.&ÐH÷^÷(B1imµ`½©¾`ó•÷DXo‚}vntñmú¾ ûîýÖ’ã&£Ÿµ){[ä½'»/FÜ—›²ßûÑ׬øüƒ’vìØ¾ ³yeÜ™�󟶜Åä‘ÐØ^?ûÅ´'}» DéXþĹYG¿c".ûCÊÍ1Ó}|�!uâ2õ4mþ6QKŽYuZ«á©ÜéË©Çì]|9#7¨ÅC ÓWÏÉjvÖµ1SvipE­ý�æ�UœuòQÖá6\?ÖÞÄåÁY'jß(>Y€>§ÕZžµIó±š wüš«/«9�×êJá°"RDßRM]5–�Ä„rùƤRíR!yVǽú.Rnù€ÄtÕ"Ê¡‘’Ý×òÏLéìÆm̶,¤‹  ×�¥JY¡Ì¯K¢ŒEWx\l”dBEaŸ(£NkŠy |>ÕÚgmËŠ—EÂ(KKTL$Ù…¬�ÒV(­klcÁµpE·ÍÚ=Î,yúÚ;;9iŒvÝýËFbésé°¢ã¡Ðν㦫WYæy=ûy õ¬]{mõì¼4VѨÈÔÎv™_ðôY;/<mŸlë�:.m· ¸b\£fÃòkóâ1à7»{–w/~ùƒ¯ü¹œÈ8oßì틽Ÿï¾·l¸V.©¢4(FWÚ:`]?aËÁq"'°tTTì„!N|‡ŽÛh VÊ/¬†˜F?‘Tn£éGK¡'DFúx€$Ã4¯ÓÕuÀ`a ã±Ýåø­"ˆ2îãpÀò÷€M×Ú÷êã\g _Å”VZ >4Úhém�1Ä� ¬�êK&�™¬Ì„êª2äÁšíƒ×nÄDôÇXÄL~ÆÄ" ¤”ÁA÷RñXg ±pÃ�BwàΘ¡�×â‘*bê‰~zGã°s3—J/¨‚Òâ½W´¤XþŒø€¦þõÙhî´ó6=LE–€¹F �ùt©98lû³øœËGÐÞn«u�q ÖëSö¼˜›E4Œ xšk%{Od”-ÝÌ­º…2m.Ëìý—Ú\ ›+AÔŽ) çÐlõ¤<¶"5çä Åç|�™·”æÜÚלÉ/T87ŽøðÞU_:’C ù¶MÿNl“%,¶ÌËr4øj÷¹Z·Xo*“L· pÏšÀL BcŒ‘ËÎäƒq[.ö쌣“wì¼ý篕\×Å|€[<‹eíµ]g¤³[‡ëÓ)ÎÌÅŸmì ýS¯gÙBg(»&×›.–зbó,ÿ!¡¯âíbJì¶ÇE´YŸcÕÕ|·Pgݼ…¸^7PvuÁýBus�m¯³Ê®O÷ƒÑ-£Ç°®ë�#9BqÊÕô¡uƪ³&J�Qå˜Vó”T›æ-²=u+ÏutT³sþm nºŽ;å‰ñ¦¦k½×dE=4Ú]2žå¹ŽíÒÕOÆt©×ÇÆ`Ò4aá†ÕÑÝÕé»åóÃçNXÔÎ܉vfY™Îƒ©À ¬<‡6œ'„P΢úÑcÕ9™ÉĽé,²ï �q–ÅÙñÙ—†sU¯1�^ÎÍTßW`㹬I¤ÇªsœÑi¾Á†x3÷oášdúºrrÎcªéð6a•L;—“GÓ7>غ nã%¦‹Ë'礷ìK�ÖÔX6Ñ[NS™' Pf7o‘}c�*'·\L$ÙPìíl¼ÆÔj9%æ“=Å&{ž²&ï²Í˜pͧˆºóŸ¸kŽ&I•YN¾ù Ö#Æéj\r¶DÑGbˆ¢èC® "J¢¿÷£¯9�õ ô}AŠÁ¾ ’èC®t�ƒDrÒ…LâRõŒÁð°f;cÈ$%Ë|E3RŽ•/dò�2óþ°pÛI2™Dž+ø¢ [ý¶“…Œ W¦' vªÛ2·“…ŒØ™Ù¯&ûh’…Ü,ð°dÁ´5+ÄN²�ÉÞ)ž,˜(Èà–¾�+ds²ç <°‰So'UÈäÜ$OìPØ�T!ƒOóLOìït®ý ©Þ¼ OL eÚ.Å�*�Ó<U°3�I3©y.Õs›z«†<¹Â˜¶P¹‚É—R$gÆ\aZàa¹‚oâµÅ—'WÀÑž*˜¤OáŠÍ�-`“’f 6 ØØ¶?Ù‚@»˜»«Ÿ¥3ËYa Ù‚@š˜Ù_š¶œKN!]ès®»z­•úL1]�gÚVe¦ f¶uug ¹`O’¤r”ùd %` ™#[�Ýù;¶•5G¶{£­ùÞ�¾Ú“g�B4ÛÚí› ±9Jüþ{ÛôýlQMrLÛE肱�c�àþÍ¥M`#-/1bîç®Üpá¨PMÁûÎæíÂU¾Œ̤¡-�e®ÕÎ\Ûá{O‡­ÒåÒÈç¬ÌNTŒ®3SŒ^�%úÉÖaCâ�ç´øp¤«ö%Q�m‡6ŸøæX(ÌêÒÂζŸ¡“fóCÙ˜ô%{“ÐUîsi>£jÛiÉ×°]VÜB-Üc ÀŒ¸k8]ÐeµmmB#»Î¥³L„OÄ›„¶>šÚÈÃçulâA¬>ýÉ7CnÞ©Ká›Úyyx‹Ð–>wnø1~Éc%1î–u ðF5ÝJ"¤ë›™ê]fÑý“ïjî-²ö9é¬LoÚ"æÌIÖþ#ÿ�Yƒµ�p 7ÒH�8-i(Þ!$c ØŠát ÉëêΠÄr!3ÖZµ¤aÈZ4gŠþXfeý?+0i¨ÕwÚ™X¿�ðë£þÙ’†ÜÖö¼É-6Br±éXA…Êæ*™ZØB"³ý+ìN¶|VÝ0šùE¦Ñ~È5¼û£¯¹†ó Ÿm^y»û&h2�öÆ5¨—¼]ä8Õv Xrv»†iRÊÁ5è9¾]ø2—kÐñÆ5 \º]ƒ`ª,º´Ý®Aðþ£k¸¶Û5”Tn× po·kÀÔþåîív N1ºA {»†2çíîv 5÷Û5Üíjmo\Dàn×Py”Žk€{»]VÝ®îír Í|âq pn·khp‰—kw‰Û5`±ÒíàÛn×ÐmÙLp ðm·k�íçr �:¼]C·1Á5À»]®;°n×�ïv»°~n×�÷v¹†a‹[‚k@‘êv Ã|bp ðn·k˜¶q%¸¸·/]C0óË5�žz‘ÉÂôþ{?úŠk¿@Vù\ƒ/ørÏîóšÝd2ð o ¶QöØd" ±5¨·jrã»5Èd�*E«5¨Ñ”Éš¯Ö`F@ŠšÁn 6D¶Ðd6��°[ƒ‚�#¶™ Äæ À¡¥Ød2ÐcsPàÔJl2xbsPàÔzl2�Ø\<±9Èt Åæ À­Ilfä 36…n-6™äظµ›ƒÌJh ¼ZŠÍA¦=6^­Äæ ó�'4N­Çæ Ó‰ÍA�–ËšƒÌZl |š„æ`Fº9csPèÒbs�Ù@ÍA�O±9Èd Äæ À©¥Ød2ÐcsPàÕ°vf5™ <±9(ðj=6™ HlJÏíMkð²É{|mn^ß5¼ööŸ¿f¿ëbzáEöã—{hM¯8¶‹BÔnë ’Éeº~„mNû˜.ïÍ—ï­#Lýªcºüˆ|Ïß:Á…Ò¢ÇvùIW7^›ÞM”� Æ‹'Ö|{¡Ÿ`dŒ%Z/ž<j‚´^?ÂTŒ Ö‹Ä�ÖëG˜zPÁzy§[¯ŸáFýºc½<Îݬ×éæ•ZNÁzi¾ÕÒO1rÆ­—ÖUÜzí'j0ë…‘6_Õ¹Ž1õ•Žõâjêæ=ÐX Ö‹WÍn¼~Š¡‹tl—o}˜íºî!ëqÁtù øNUŸ«¨T3 ¶ËOÒ×·Úâz¨EãÅAU�Ækƒ+uˆ‚õâÉ6_J»tG:µ �õâ„ø¾wÊän„`»<gÓl×Ô'×sáÃ6^×Nãí6ªƒÀRÚÇxyì½µŸ×úÂc�ÿ¿ÌmJ1ÂÕC­Ë™Ûøý·¿{ùûÿöíçßþæ]Òv§jБ¶¿øipúªŠÒ=FgðU$oÛï.òv_êDö]“‹¼½¾ÿþ°µ!RÑ]âÝZm}¹£j£7µV¾XŸ­9úÓ¡j£9e5ÛMçžÕ%œª &œ ¼;›3a.$àTíÎ)'«ÙY£ +VMaQµÑ›ò‘U§scœË�œ«Ý9£dµ vÚ¦Ðoòö—�ä°##ë¦o¿û£ñ ö/‚-�¶eß2w¢å&sSC�ê„ÉÕõ@h TWé£BTrë4é<Шm‹"0; ìkfÖÌMâIøJ�µ;E‰}M–Þéå10U×&œGÍ:ÊÖ/ª‚ ÐÙXõrêÑQ’V\©’FøŠ¤Àæ éa‚³ÉUè0įÈ7úÛšÅÚT˜ qŽwõ¨‡‰ sA1Âû ‰mÍÄ6‰‰ÃAC(qjõ%(ïF‘×âÂoÂWd>ÆÁ�Ç\³‹ºa._‘(Öo®Ã°"¹dÄ}ð)äÍúÖÃDgç´¡BŒóPªn5m(¨–½EÀ¤NãêÂÕü¡ZS«ë¨a _¥²zH‰}M¶Å¬Ñ 5�dû½�³Çºk6ˇ\_¥²»Y1£ŽéãƒzHö;Sð݃@¢ôúˆµ“¢×ܸºk¨Œ¬ž¡1…�îsçSsy35E£káŒp„tÓ¡»Ù×Ù‡E‹ÍÆâئvöjv[c ܶ¡·”\œ¼�Æ£mÌe7µØðC¶ál[dn‹²Þ¡s¿óƒãί}6âÑö öÍ¢w{t·ÞX«ýB&ÁUq¾7Mƒ|/SÁá´KåÀèêç@„ÔOu095Ãõµeõ…БO‡Ó¦x´¾¡†@/æ·¹Â*Pk!DpˆÇ$BÅwVA´ØHh£oçòiŽ÷K2¿� EÑmãÐä„ K35©Ówa£ûP¼¡ritå÷þê¿BFÅuh†hJá«„|Òè„Pò�E>\ø�Ú ¾Ò�ªXì’ÀÃ@GrAlå"éIÆêÌÎn„’&Z2”&ÂIâ¢f¸U$”É÷I“óE $ã s 3G§…¢ Â+�ƒ�Ö­¤, ­˜“1ã ç ®Éšž\½˜™É/$¤+1¡ŽMuF††�+…ÙÓ"RBµc÷X´à#9‰Û4P_„L0o0YŽQCëÁP=IIï'J&›"´–0õU…£}‹ µH´Î2è�™õå?4?­AMŒ™¨NÒ+iÚpŸ5º¹€--nµö�rÆúªÃúå”3­ÜÛé ¾ �¨Ü ùøÀ–hØžn[�gÙ=8÷>¤Px¦N· ý-Ç›C‹ï¤�ïýàÇ8‡ók>�sØÞÊ8~ÝN Á 8ƒëÓ0ÆæÖÉ¿¸dJ¦ãË™IO`>\$¤?21_óæ©…øÌ’'ò£¼y%—€H"2 ˆ�žr©ƒpPáRI ?\Ê”ô[ù#�þp©z¤ä³G¸S7ñÏNÉwEìñìúÃ¥ÆÁQ…K�# £ŸÉê”dödµZH¹•4Rv�ÙcÓ ü‡(“ÁQ…K&#�þ%0ôh×K#�üpÉ[$#£¼EšæÏœr’µeÍ)'p.YŠ„Úè%K‘A~¸$'J¬—äD~$ßr ¥ÚKN"cKm”ŠH(øF©ˆŒ2Ë%‘Èj83¿P¸$jÏ—ÄCNÅ„°ý£ÛØ›oþ©}˜_ Aã|“&Ôñh©ýýðÇöùU›±Ùäï–ÛûU‘Ë�ªäµÜž\à°Ü^ý·›ëIŽ›ë( ÷VzÚAØ œP’¼6Îà âÆy ü¾Ù&#¸¶Éë»)FpmŠOc¾ÝO.pÜŸf~³ã�¡ùµã]“™7ûÛiq{šýÍnvÚÁ½›ŸRÜ»N3¸÷®?òf§:ÍàÞ©þ´{a:­à^˜þÌ7ûÐi÷>ô”ï]ç Íï]穼ÙcNK¸÷˜§~ï(§!\;Êñ!]ûÇ>È{ÿx–7ËÅS�o—‹çöfqxjùÍâðœç›¥à åµ<Kz³ð›±y\ø­Ñ@\æMc9˼³ô7‹ºúv×¢n4â@ûžéÐ9éû‹þ1ƾ~‰ÜëÅöä—‹ô�+å{f[@—÷¸3*~…ptßúì‰éaxÄt²Ö°Ý¦cµW´·ñ£f5™Çò`ìѧ·)óm�´á\+ßJŠhŒŸ2jŽá¦U“AÝ’GWÏ8›Wd_Ïj2Ïôm¢Þw¦Kë.�Ò}c”o EðêÖ`»9ÐeœN2´- •áØgK§…2XÕå6°GŽK>;ùy´Ì+²åiê�ùñžˆ]íXCçt8ÇÐ×sb;�ýXL�%6%�Ü|õ&¢W7“GC·øŠq[­‰Å6…–»7ššÉ•p¨Xá�ÿìÆ`ªfh*›<‡“ѯBðjC¢ÃË l7ŽíÜv‰àÕÇ;M� MnÃïòø*Ktù§C�-‚îs©ý‰¯©¤Hÿg˨¹Üë߈ç&óýi‘ ÖQp›vÖóŠIbç˜×ç$›é��`�Î!rôÑã÷éN÷�À�¼_ ©NàñéN*wA×7v_úÅ{~ÂXU‡±|Íâ³h�$>}¶éN„6­÷Øoã~Kù–é[�ôýÎ~LÑöüÚbço x±,º,ç»ï)±ÿ‚eÝ"¤�y³Â©b’áöXÀñnÂK_0¹QNlÊ�z;ŒÉ»?HªàxÚ›î;iî ±³TLá‘Èš‰lg¢žI¾gû1“ÿç±H7¢i]xÚašLîˉEË|L£­ìŠ #›&t Š©wVÓg,b®ÓÜÈÂÝÓ`f�N´ø”‹±M ù±Æp2)ð‹Lc›&ô ÄNS1�ï‹Lc›¢$cšdU °?±È$Û”…™Å;BfߊØlX*&d„Øôeq*àdÍ}×4!/+.0kÂÚ;!¹¯2 /~ß(Ï3ãÖšQMÌØhàT ®g$b£2™Æž�–{åyÄõˆDŒó–Œkš°k¥mRE!Ã×ù²É¸¦¬Éø>7v™ÇÙVŸ�jš�”%W86 j„"¦Ð’�kš�”³eÖlÿ³HÀ”êA§B²dæ0×Ù!Ÿ�kš�”=Þ�¾i�èȱ rM’211.馵†š /!Õ4aãHÛý„à Þ’Àù¼?7úþ�~Œ 9¿È9—À³oÜ® I´e-ƒ°ã‹�üŒ“~2 [V§¯bü]jH!2Ú”¬v?¿ ÏÂ6y‘Ñídõ°z(M†p>9U€áD`·~~Q!…Èh‚‡Àl}i¼TËÙW Á=Œ¨Àl}³1T=)7>²t8ÖùEü͵?+… ^3K‡}àÌPõä\dÉÒa]'˜a‰9¡p#°\_˜J1‰€Þ5ÜL×OðSmÕøN"Ð e}àÙ'B0#fh…vK"’BòÅ©+‰@'”µÃ¶ŸÏÇ6´î,bšeásIƒÞü$(Á‘Àv�ˆ— Õγn‡…#¡éò î½YUÝYxÖ~uüyêQ® BP*–@ø¼˜$KÚWÁ­º¨Àh}Cx�F0\ 7ø²nX–Œn¶–vgÜó/‚$Â÷|$Jðy!( ‘ï•öÎnt¿ÞäÑŠ¯áQn£¸Y_Áöà‡?ÆúϯÚPÏ&‡s6jñ?íªÈÿÄî‹~må„VΈ«Î ýö\7¡¸sï­îó±úÁÞ¦Iåžk›æ�ÿ#nʤþOX?†mãÚ‚ 1´ymÁ�ô®³áZD9n¸Ô“LvWX_ M£zíÈ~m§„6ÒˆÛ))sø\«')±WOª�ÝÖJR©éZ+ùÅ#¬ŒD[¶]+#±va\ë ±Êi^ë ŸNzWXõˆÎl¾V=¦'-ÁD÷!hÎÖk“#]õkK#±®-�Põ|® ŒÖº60&¤Zq»"z³·+bOX�›Ñ™m׿D¬$×ZDh{Ík-bîÉ*k�³ùZy˜§Ñ»ÎŽ(4fëµÎ�qòµª�êgתB ”ãn'teSÜ9?8âö6¡++ׂÁbqŽŒÙÖNtes‹tz‰—±bøÌG îrïüàÇ8†õk¤e/¿<n×D§�&wÜwŸ³±4ŽO€ƒdÅAŽm¼]mH)¬öÔgüÅTƒOWÔ:Kè3þ$׺W |3+c›Æ´](Û+P›™‡¶M��ßR&,…ÍðHs¶ÚÒiͰö�R÷Ü ¿—ÖºjÙYéNM}®c?içc5‡¹mClÌå¸QÛûØ3þ"—­o¯@-6 ËÖ¹” §è\Ó-,Ro\ʺ].ÍqK:þ’¥ãè³FÜ€Ž?Wã2<¡H]�Ûͱ=‚J¢g'ëVqØ›Ëñ'©Zº\‚kæ…­äø‹%®¨jïå¸q±G—��5ã6q,ù�Ké¸:¬6…ãïå¸5N¨'ØãpüÅZ£Gp]³âkR�g3éhVpØû»ñq×Ç)¸B¢9›ªÝT'/§°�ü¦„§¼…á"•ô‹þaÿ‡–n¿\”R\q¶ €'XÃP ÇÞƒ@¢áµã�¹BºµMªÄÅ%lƒ«Õ£XµQŒÃnR&¯Ý O¶kû�9“×öxªyïGë\Nt¤AæÌ×Ú�¤ õZ@Rèµ�é¸Vˆ±ŒƒÜ?y“÷Î2ê^ûȆµÅ�ns1šqPê'oòRê/¦NdøÉ›¼dø‹©†EaÝúâGc¿R+1.›ÖßúùÕÂ/$ #jãWó€ayr…ç^Þeò�q1êK—¦=\Ÿ\zõ8íÒ«o&G„‡qæ¥Eg5¯eY(/E�ùnÚ˜qÖdN|Tä»)l9`†K!®ªÇö!ó…çmûðØåÛ�&’ßW|{ï?Ɩׯ­ œM�ëyÕ±g·d7hÙûïê–±‡h ¨ƒ}¬­ãXl7úµµd’<È-IÈk´hˆ¶˜^§ï ž?ƒ†f øƒ0hÛŽ çhÐÐ p¦µç{p°[3ªÐ æg­ðžžAk†dK6)SÇõé)ä±fH¶€<ˆ]¾ £R ..ï˜$Òš}ÔSÈcÍ$Æš@«ñì˜�Ø·5“;ÌšmU�€ž¢5ƒ ò ¬Ùñ±S wÌÌX,n‡=¯íÉÀ}Ù3ˆ±`ž}Amž6¢¶ šüßl=Lî',²@ýÅìyø¦£v ’ D[@„=›¼<€’¢=C´ôAØs1Õm€d4gè‚‚={^{¨wìšï˜'LÍyïˆÿ‰íÛž!R î àš ;âbû¶çIÑjšó°�‰jäÛœ�qFcffÍc¤¿y2nA³ ñºëÿùß¿% endstream endobj 165 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 166 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™k®à’ÏÈ�JqŒ endstream endobj 167 0 obj <</Font<</F40 37 0 R/F70 105 0 R/F39 35 0 R/F38 34 0 R/F57 65 0 R/F14 38 0 R>>/XObject<</Fm3 153 0 R/Fm4 159 0 R/Fm5 165 0 R>>/ProcSet[/PDF/Text]>> endobj 125 0 obj <</Type/Page/Contents[23 0 R 168 0 R 24 0 R]/Resources<</Font<</F40 37 0 R/F70 105 0 R/F39 35 0 R/F38 34 0 R/F57 65 0 R/F14 38 0 R/Xi10 1 0 R>>/XObject<</Fm3 153 0 R/Fm4 159 0 R/Fm5 165 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 168 0 obj <</Length 3781/Filter/FlateDecode>>stream xÚÝZ[�ã¶~ß_a *cE¼Ibû”twÚ4MÒîN�‡$›«+[Ž$ïfòë{.¤nÖì΢PŒÈCФÎõ;<NV«dõ×Éì)à²«ÌÆBˆUš¨X »Ú_üò"6ybh|hÑ@xÉ>¿=ªÕËúÅ¿à/ mü‚›ÑŠ_ÞÁT�¬òئ©^ÝíW™\›Ä*ÍVw»Õ�ÑíZ›¨|¸4k•En½QFGæOë�6zYî×"�öŽO›¨{<»–gÖ{~ò„_.®íZ?éPt<öÞ k›èa-X hÂDEçv<éþqýóÝßá;6"‰­±|¸7]±]Ë$z»o¿,ZXAfyTŸøùæÍKnìë†ÝÁá*Ÿßfã/ ¬¨¬MkîËʵ›f·Ý�gOø“fqbD˜ü¾nÞVu±»� ríäV}¤³n̵VO�\¹=|·4IÔÕülʇƒ'•'?tpeÃÍš˜³s¡»ççŒMe}ŠqÓ^‰>¿UveáÔ2ÅS#ß²X/ÔW¿vY’F?%&QÉOR¦:eJw¨/mqÚqoÛ8Bûyë¶0U0ñÞm‹ ³;�ÚcQUÜ<¹µ4Ñûj�•€7¼'¯„Ë‚8ËS½CÁö¶8qãW4*r{\fï¶]‰�wø‰õ³·‡a~¾þ⛘[w‡K{³´{�‹ðJÍÁ;ÜÛŠˆ¾cÇíûG~¢–Pãöû7¯þ¸�ô“ajƒÚ¶yKÌoN®ò«ÔÇãåTn?›„Ó²Ôà×sUŒÍ�³k@M�Åië ;šûлAº Ô|&Ôz¹·TP\xW?ðÃc500]ë ¼·hÖþÃ�öP“[îîJ/ІŒ[jŒGIáÙÃ&­÷{L˜à�=Ï£‡:4Py½}CwwiÊÓ·{3uÎ.¤Š­ø€™N¾43±±io¦(00Õ�7Lkc“ØéÑŒA‹r�ZTÂ'j™÷/â RlFŽ®CÑ›òÔ¹S;ÒTïm;e·¨õ©M€…5È_äž·*a5˜h"+çg¡½Ö`güJYU%º;ì诿œÌgsÅæ>¶ŠÆ-¤qg²M²1 |áì¸Íž�ÛªSi• ªÚox|¬:6ñ›bëPTûÉ®©7I¯>½¸A€à0³D �% P¾^oR½‚ÿ"ú‚Ú/„ïä: ïôjI»¼÷lØïú}‰p_lß>4õ…¾ോ¯g­±Vv®ÕŽm¢�m°%Á`p[ÄG´•š©ýDàëŽÔ;´ ðS%h\¿TÑR�ƒ×ÊÖ/ƒ¬\Ûûƒ;áëô¯‹�FkôHa�€¥DÊE*�Š^8Ÿ«’ýTXndÐWºBÎS)TqRØš„ Å ÂÀ«ïn×yÝpÝ(O6ïß/øÑ>ž¶‡¦>AØYЃ$–zÆ÷g*C'ƒùO†¦XSnÜ|¨É›A‹„…O4aA'è4ÑOu7Ì&�í”ÓƒNËxÅB»D©Kï§yè\ÐáLPKˆ:ÈE¢U[s+0�'a—·³¿ŽØu·VÈ3m¡Å}{½À> Ðä×ìð_¨YÍqËXÝúÈ ”¶üÍÅÌ'•Ä)…kðæ´:i¿†“M¢ fQ�‰ˆçâƒàÔÓgƇ�@‹NgšEaY§„+L „ÚüíåKn°mäÁVåCy_¹?#1ïg½á–÷�nˆ€ÑB,ŒùßÙ¸ªè&�E*yÍœJÇ�Á`I¦ –"¬“æ3Ü`x�n*à "P^8Gé1¼�±a =¶¯,N!†zv£ÌØ ëðîe‚ÑÁ¬"UG臨ŸøŠ$<vë|žÁ0[Å}[W—Î…÷À¨>š«<Îólªóç Ù§b‰‚Šß¡C*î !Y+i}=8Øzµ€S�®K¦&èÁwç®×æTM´t�oW;ò̴ѱnSÂÇç}*d}º”Oõ Èħ8I$Ÿ-mK~]K)ó6ç=H!îb£ŸÃš‰“àËÏs¤í™“ËÔ›&Í+ñ-E+•iþÂL‡¯É ñ)oú„j¤" ÈÏö tw•S^k•Êb!{×îã m¢tÎMàž†P Òør-ŠÀÙ'ÈÌ'‹r„B'§Íe,’„¶ÅÑ-…gzl|ÑÔBäñÛZðÛ»]‰ÚRTþ̉,£¦Z"eù[Ð,â94Nr‚Ñ1¡}_v�,A&°16�þo€Ïñî§ÅŒ Tƒt–D÷˜Ø\aFѲÛõÉ (‹Ã|WC·ì‰3HwókG¬ä¢'Îa+kçHÝ'Õ¸ ©O¥‘°¶™�T µ´O£ÜŽ»š3[6øHבïÁ6›¶&ÆÆÓžÈä|Ϋ£ã¥êÊså{½ÚÉŒ!6QOÎíD㌚ŸÎlYaI)¶> ¤®ZøJÆ©È>'ÛA‰ƒþ/¥˜“ÇFú<3›ä™JE/]å:·˜i¦àøµ [0¼…7æ %˜DH(a”2 AþÑôi³R!—€LIüú󧔉RÊD>‘RæÀ‘Ouçª' CžÄ™KŠÚò†>»š xÐ0Ÿ ô$¡ïHBüÿkúÿ=Ñÿ¹äó ø°þ¬7 e1daÂ÷´Ü·ôŸ7ûjDùzi5–ØG7¸íÏ.¼ÖMqæ¢×· 0¢±G)8aÒ"‹4?ú¼VC¾âŠí�{� Þ%›íWÞ©=.%’)Àñ_ð%�¥J¯€°JyðÜ×Uåž×½û¥“X é˜AžÉ?§¶·ZLÄqâL)8ÇÜÆ&›ùFÀèG�=ÙT.£1 }dRyÚÖGƒ¨íšG†Îe�ãSZlPòø�›/NeQÚè7î݉¥Éäör,»ö†óîêöp‚XºH§•:!wì¸9„vìá!ÄñÜ@¯Ó`Ôµ ÚL>Ï4õ°ÁF õWsm×��òe#]€çàÖ•Ü,y/),x¯Ù}ÞÇTÖ͆ äå=ºßn]S:;t&¢KOLºýM·Ÿ‹öï) t âpï ²8IÔ4“ô‰�°kŠS[QºLÝš­Õ_­! &ìê#·ß7eÿ&iy" ØsUoßò®ø•jvuX<RJ㥠Jã·g´tŸÊ¤xË}rˆ 9NÁо¡#ÀÐ¥e¤u˜äs³«""à*…ä'QÙàR3<ùBº&òX¦âcéš(Þë&“ø]Fd!墼ʈÔÃ'qL‚,Ã'Hæ;T¤û9dk"s'UÌáP ,/�çbKLž÷�Ø‘¤FH0wl¹‰Ð‡BΜâjsf=]Ž‹.êp0Ö²èŠÖgh“;$,äs–Ãá_‘¹n /£®çÛR‚ §àÒ6†€‹1·¾òÒVllÁ1¶~�«Ä©g_ŸXr’£{½t¯¢ùŸœ£bËO‹±oîwò‡¡2ÖO®ì¼٨ŋÆ0P{¢W ˈwfÜ¥J7®:»Ý‚›í;@¸¾Î7*~Ø8œÝ·K‰Kœ vb-ËžÀ€Fi¶lÔ'Td"í(0ÊP–çí G­g9©O�ÙÙÍ VLåì Ëâ�o'ûºø»p׌+@ùŠ7‘žc€ tâ·4±ŒÁ1‰ã7ŶÁÜÛ_ï½Áâ"å‹XìbÚkÈbú/¾æ—¤)xõðÖe˜@>ĉ;»²Ý^07‰ñ � k<¨ÀïJÒ�„KLøìÍçïÃè\/*àT2ì@±Þ<øbøkp¡?Ò'ýØ u èþA+Ξø]B\c«»¾°®€¡ 2m@¦É§WêõU¥>¬¸-y]ªWùä Ì�<ê“Õúô·Z? ó\­«ørµÞÚ8ͳqζ4ñÎ5Kµzk9/Õ_ÕÉ'ù®€wD‚ñÉÄ�¹F ¯²vn`5Ñb™ÕÆz£¡V† ¤üÕʰ;ËŠ‘¤bý¥ >'î}ã7™8ù�4ë<õ"ÃÕ\©1$ÈØ ²Î³§j®&.¤Or{~¥Î³Ÿ´Dl6µägjL_ì܃ê,á ß7ñPçßò^"T[ñ¥%'ÀqLÚ<JyZOj6Ã˾¨ã1|Ø:–tXlNKÕ´d@á KOó-ÍãÜô<î‹*(}‰ÖZ� @”¢•‰ql®7BÌjñ~éÉaHè'$A/G!o”õ#þï�㣄•Ó–;Ÿ ,\3¡:ô¦êýë½ë£V_0:ÿ®!öÓ}¤Çö²öïwd,²i™HÎËD±b3 ˜;¦â…92�á™Fx†d„ÉœhàI®0}:@5ʺº)wvœ:†áœiÄ6j�²TêCJ}mÞq/¤£ë̹š�[¼aàï¯u¥ÿÅ`-*Às“Ö‚1Ì*CúiV/BÚÏÂKþÒöºìDi³”¡�:'-ÿDHøù{%V<a€mØõ°M†rÒ %Å_'ðÚ‹ßÎZ‹ß.="„膸ýž2+A—ƒ W*à­í‡uS<O7q‹�Ã)Ñ‚°KÁuxpõjÛÑ5ŠÐþ@øyœªYJ#²…ŒÕì#)Dþar0Ĭ±&®C‹K�AC°åËŒ)WϤt½¨ ÅÀ{éjB¤��•úÄ dÀxº÷ Ë7�3󨤳»úO’„ú¡04.Óà�8jÒ·0õ;TùâÔ‘™"‰î‘�ö›#×-±6rFé…Š‡Tá‡-Òÿ.è·Uô-ý,pâè'`|UQ¸cÀ.¥÷mTØ0úîÝjÑμÝô7EüþG±¥P€Gàù©ØÒ<�-GK>…-…åðm [fÿÇØòX”Õï†-ù¿�M ,ù\l™ª8·fŽ-q� bŒ-‘:Ã8ÃKGQ*HªÏUúå'6;c”Ézqy\‰¤qáÅ ¸’g?W^qúÓq%þlé ò ¶�Pö‰Ýmçê™ 6Åû5ýDuRŽÙÒ-ò�ñ€¸0 endstream endobj 154 0 obj <</XObject<</Im5 149 0 R>>/ProcSet[/PDF]>> endobj 150 0 obj <</Producer(GPL Ghostscript 9.10)/CreationDate(Tue Sep 27 20:38:06 2016)/ModDate(D:20160927203858-04'00')/Title(file-reads.eps)/Creator(gnuplot 4.6 patchlevel 4)/Subject(gnuplot plot)/Author(bharath)>> endobj 151 0 obj <</Type/ExtGState/OPM 1>> endobj 152 0 obj <</BaseFont/YAVGBP+Times-Roman/FontDescriptor 169 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 0 0 0 564 0 0 250 0 500 500 500 0 0 500 500 500 500 0 0 0 0 0 0 0 0 722 0 0 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 0 0 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 0 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 169 0 obj <</Type/FontDescriptor/FontName/YAVGBP+Times-Roman/FontBBox[0 -218 863 688]/Flags 34/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 111/MissingWidth 500/XHeight 461/CharSet(/A/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/a/b/c/d/e/eight/f/five/g/i/k/m/n/o/one/p/period/plus/q/r/s/seven/six/space/t/two/u/y/zero)/FontFile3 170 0 R>> endobj 170 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 4949>>stream xœmW TSgÚ¾1äÞ[TÒ;—„±­¶®h«bë.­¨ˆ€"‚Dö$ì!d%aýHØI„ û"Š+b¥Õº+jä;ÓmÚÒÎô»ü󟹧g朿çää$¹7ß}—çyÞçå`Ó0‡3Ó72Vœ°Ò["a¿¯ pè…ÓèE\€$¿LxðažUÜY`&Ìt8µ�Ò9ÑsçÂîÙÐ0ãr8ò¢ÓîRYj|dxD¢Ë»‡¼¿·|ùŠÿü²fãÆ�.¡©¿]qñ'D†K\–0’Å1RY¬X’ø‘‹;swLLä —ð˜TYD‚KHX˜8Œý›_HŒ8ÚeWdL¤L&Mvy×ý=—µ®®kV2oëöGƆ&%¸LEî²_ºÑÅÓÅ[žÿÿ¯`¶j»D*óˆÛ¿+aw➤�Cö†z¦žØ¶_|à¤W¸w¤�oô¡ØU®kÖ®[ï²Ám9†-Æ`^ØAìÌ[‚ù`K1_ì]ìöæ‡-Ãv`+0wl%ˆy`«°�ØjlæŠíÆÖ`{°÷±O°°u˜'¶Û�ÍÆæbNû6ã`Θ�›‰­fj�9`bì ç-Ný4Ñ43w1WÇýÑ!“Gñä¼ð`ÜJl">'—’Jrò ß7®Nß6½m†ãŒÜ�<ký¬+ŽBÇ˳gή›ÃŸ38çOs·ÎÍ�ûÒ)ÐiØé–ÍWñkéllj“ úwÓ¬æLøÙ¨c&]iÄ#d¤o9§à(lR³-ѤÉÈa �8’b±›MåQ?|ƒ­x÷r³¬(¨ ^¡÷Ë%å°˜˜TÃR ÐIdç9ÒÙÀJÏ¿Æy> =F¹ôbªÐTšWH{‰2P„òà­Uùg‘Ja%üó•fÐF³ąs5æ@ÔÅ|,BbxªìMaV"°@c$L%¾ ܣػ[øŒ0S#µ¾iæ‰:;½ÖÎiü –Å…&ú8…þຠт¯—@'èôÝ? Î[ý-zS¤–R£7–£Eˆwl÷¶°“u]É"éå´{à>ùíùáûBæ,[©¨J…±ºfÚñS§Ç£0il?³„^D•ä�@ž-ÒMFà°Vë•Aò—(`&Á?VElËS—�ÏH¸†h�ªÓõ�Nÿ+t€ïÀ9;_-ó Ž?,!2Œ‡’#Ô¾ \¶�:3ØÖÿh`+"7p›ûQï¶3B¶A6y;ý²]nsúeœÆ!g?ïÈ¡€»F½5“äÇÈa;Ið÷–áÁ[7Ú_�ïÁW±O}¯í¾‹8mh Q-Î_('žJÒÁvæþñª©¬¸{ìVZäáÓCÝë�Â�šºáãþ’ƒš�yBSÒ,šÊ½\U ½oÒNv§º1˜6:�¯„“ôf*¨!¶$Œ9yîrä€ÞFN·×~3t­þBŸyÀ'UéÁÄ5 €ÚrÂ׬/=$ý­–Ø�þD�„,µNŸ$�ÒÄ€ +M©ŽnL¾n3µ¹òèåpSÔ¦æ�ÍövÃ’&éÆçñéoàfJŠ ìxz �2<„Š2M9e ’„�®"^�«ÚâFÖBe"nÍRjUj…T” sŒÇí…… B¸�‡<P£¬\CžÆ³á[¼I;ÎÏ“�2,*°“œd¢ß©Rî`¢÷�Óí„#cÀ»¹šód”[DϧÊM%yf@ž.I ! †½”+±Û¤°‚ë$L"š{/6–dêÊ„ª² 묕ö–äêÈI¢G è¯D¦Ñ/)\í%g�zØàÍÿÊ3‚N€i“�¡ù(Uùú;lèlè 'ô‘ÿ„¾“�nZrØb#¶ä«ÊÁJà;Ä— Riþ�t¤ºM5½ªZ]ãtin¼7�¿Þ�_PYp!O‹çä¤rs³€ èŒÚ’_Yœ””·`“·¿»Oó‰—GDCQ­)• F-õ�Œ±ÔȅɧÓkÕ×É4äjÁ‹Jó�Luøž% <§–aBe†½!«jÁÈçC÷.&´h!ìsi…ò4ht5Ùû¯Ÿ‰\[Ë\ÕEÿÚÅi†8íò=w"�þJ¡âT¼7ÛœmÖ[Ó Áq­'¢÷ËÜц¥‡û¿±ÿ¥o@Ø70Üp ‚ygøi…ìô~²×Ãp^ž!OU%H3¥³c*y½…–¢ãï5lô}±ë;1œÆ�œÛÚÕJÂ`Ü0[† HGؤ»LÏlv²ÀL´�üKXLûQü»K ‰—æš2„†ôŒtƒNì{üHZÉ©5d2çƒì¼SÉ¿{]Å7œ9~c £îr‹P]–¯Ð%ÁIeÃg"ØIð_þ„OQôÁvç×q88Î…bˆ(èG€ee#E¤ 5ɉC™¸OõuƒN³™ík“�ØV¨¶0âCá :ü{Wh¯ß;ù¬,yWÓVªÊ�î�Â]Ln•tÂE*Ò–õ‹àwh-ÁoQÃÙf ‘†�ÒL•J+KŠÑÄ2,úl�ˆ_ Ÿ¡%*âBv¹‘¨€ØtÁÿa{gECƒ°·—çFð=ós.V·•]*°ä±M8Ø8�`2$XÅÚ¦ÖlÈf½h#6šÒÊÁép–[Fó™p/ʉ—™f-£QŽ´—îº÷í\ç4ø'øî—óøçèý·)…J“©d¢¡¼O™ì/g6*ë’ÚŽÛ¼�¹r{ gbuJmÝ©êšüÜ‚Ü"QNIn1("škº$‡„û ´jŸB\œ”¢ŠQ$ßß³/øf_÷©Ë7…|ËႪäîgÁ)sks ­f´*&3=Y“ ’¦'2Bz¶W”Ï ¤» Îê#§z8•Üœq.½fbeÎ-ùàLŽYR@Rb¬¯?Ú‰Ö9Ã&Á²²/ ™ÛåÄÓ ³xüÆÖMlïZmÄfv¢=$á¢þÔ??ÙvÕ$€Je�æf-аƒuÈFÎS•º~�TÐä ½¡×�[Åw 6d�jn3=ã3ÎÝQ˜òg.\9±™Ê4†(eú£j�DÏK# óòA »JÒCD“DÌ˨çÐyNƒoÁÙ[¿Yºÿ`x`ŠÐÏ¡ó|Ûå§7#GÄ=²wãácµ§ÿ­Ç�ôO¯%JF߃;(…X•¨TD„ù¦ºr¾C]Ø*¢c p¿¼üY“jëk*¿à7Uõ’ӭĸƒµH2J߬æÐR†^h�o®HOËÊÍÈ6ˆ–¡FDÀÂŒò, (€*kQ¯‘´¢PQŸU©-V@å:›ôÖX{@E8P €2ÑS«ŠK’«@H7ê äEŠ|ƒ”””„¨æøž/. ·¯Šà*z…¥¹¬´Î$`ö€æ5rN�péÅЕ:²3<Á�®{ŸCâçk÷¿l³hO–Š “Š¥U©§€ ¾ÆV;¸óü†@ÿ”ðPQ@°t7ØD¢?<[¹çº*šÚ„ u¶†37HÇÿ�õo\púèªqîÄzú5Àt[óºÛŒ6ï(`´ù5Sï[,�Xd!Pܤ¥ÑF ”ã/2-°ƒœ\F€·Ur· æVÓµà'’^JÀüÉó¼rœíúePAO·sÆ`Ê(~¯£àÒ˼ "57d2\Ï0›þœ9Gº½ AQœWŠÙ^¢ !WBÜ,+;Á¨#± ñÐbôæãà´ÁŽêógE{Ê:�ƒA£Ó¦¦Äë$€tó}gCÞÀ£'WŽú‰h«ÓÙl�ØlßïciJk)º–�Ÿ–¶Û,å¥åù,³5r¢#»<Ëš^­* ûHô1IÑrÚ*Ç{A¹¾ë(9¹�àûÿ^¶ ¾…ÞÏä˶ì.”4C¢�C¯€nÔ‘­Ç%{�78Þ(¹žÚahɹI›¸þ–®1¾9¶-èÔa�ަŠ#�†Ê<ÀF ¬ƒÄ·�o@¬GˆžÂTÙÓ³í7ÁMP'µ|À2ZÕFÿ_ç,3‡¶@œ ÿ9áF!´�18A+›]¯ y¾ û3ããàBèƒ~�¼ôýTäywCÛr¦Ôý ?µ-új`ÓJ€f�/õ®”ÃéñŠøÄĈˆc©~ «Šh:Üõ€\0nÿ¾ç<ÙÙ;Ps �¯}ÆÒfbçüÌ´q˜¥Älfà Ùš:N•ë$UŠ8³®�µ¶ªÚ¶àúûüdAq¢¸`}xîGäÆèè ìÐjÜY‹l±2êª-�Iøt$^»Œš.x‘µ�?ŽÃ4ÖBÆÀc°�ªÏ©Ì­OÁÕÒÞºO›Ûn‚Û GÕ!k<Ñ÷�}%ƒŠJœ_É0Y_ªûméu[ ¯a¼É¤dœC';45ÀÃGß^怈Už1qÊ;K®Ã÷«á¼Ó0ª³Àα߃i# v.E;S�[ˆ 4¥%;ËJeq€\µÝÝÕ³A|;J$OMUddFIÔ)Œ˜&›5Ý)‡eQà$é÷4øÛÇOë{. ;š*›A>ڳ݄¨Bg?c| ¨�Õ-­ Å%¹E¹&`˱ä‚vÐemjh±[[ÁEИY«j&‘ar>Õbxž1�È¿´¨Ãn C¼÷6öÕYz.Š à×Ô {kS½"¶BXaa¤�$"è@ȭ￲ØèŸÙZŽ�C5[Ë‘‰¥6JlJ)•œE¡°Ðù ËsKCs½­œ½êö¸Fq·[=[ÏFœNN<Ö—j:Í6ðgÀ0œ±lÄ ¦£›<¸çûO¡Ç({Yqœ;t|e@rH¸\‘±<‡µ* jfX[«á¬q§§ã뙉þwèή;«}yJ†éf£%¯ê¦üª’�î:í.!:+ñq�¾”}$ø´?L¦d‰‰RiM¢½±¶¦ÑžX+aìÿU[R5�º#«�î�AÕOóø i†ÉxV¢V«`ì#²Å$¿¥üäÉâèÇA°"J“ƒ�ú| ƒ×ñåÐÓâuA2H ÷íXëy :ñ3(‚Wƒó=myærëÆÂgÙ ÌIÊŽ.}×H¼zöó ß[Èù¾hñPH¸J^ëé>×#o6E—ÇUx1xj.ÑëáÀ"Æ_M`Ôd6Ökµn¬Îžc,F¾ÊÂZŒâ«ÄAMj-šFÖáp oò&ž�¶ðêð:È©µA†�Skª›•ó‚qú\Š©[^) [JÕGD“ÉÌn—�íÎ:}µ•HÉ;ad�ß*€žtALYÆlc¶)[P¬3e€L2==C#”+¡ÄŠ›bl!—ÐJèçÜØpÿöpc±Àš_ndˆ\lEÇUxgnYP}ºJ¥a–PGgÚ�È2Š5ýÁ4A¬žÇŠR=aãü2ÿÙÇ¥!m¦À¸¹âE)£ªJÖNT$�¥Ì†G€ÝqZ¬ìÈÞ˜mÀÖÉΧ6ÚÙõóá”!|ÎÂ6f Ì` áÝ"Ðö/7Â-�ó¸õN§°®§¤Œ0"hcʰè2glz²/®�YØ-¦bva¯/I;"B…8¤Rúä2ň·~Feè$a+ŒÅ¥EE§k{+[ÙW±S„?à£Õz³ˆK´ÞyÊJ0LÂâLoKU? ¯WÉÜD(œ�ÞzýAs“ÔJÄc�ê*Ð)€¡œöé–ƒþq S¯G6Á@ªró$3»¾¿œÙõ•ŒÇ4i«9pî�Tl|\Œät|cSý鯦¸úXv}UÕO8Õs꾃–ïX€¸Q¾ Dq2â ��½§½qÞ§=øR¸z+ÛZ‡®u0«4œEÂWøG4O˜G�žcF£‰ƒ]Ö­ þ†Áˆs�;&z ™+å÷™�"Ǹ°�{\y*Â\P–Ÿo¬*ªÌg tªD-b@”>1-]™®Êak×h%6奕‚ $ý=kßÀºöþeŒKKá"J]pÒ[�~ �‡› Ç«¯;Ÿ€§‚?yË÷pÒ‰“ÂèHe´ÂãT¦s×ßÚšïrôº÷†ÍA«6¬¡]è OCÏgOUµÓןqàÄ=.ü˜~NA¼äME¯œÓ‹”ɺÌdæ bq�Ž1 ¹ G�™Ÿ]ÜÜePw !qòÊ>ð.¹|ÿ¶Í)Š¢šXatmb)c…%*M¼ø|ÂãÑ —.ŠúÏ�ºž€òþ€‹Á}Þµhú)–M*;íÐÏ9û5ÌÿŠK{Ol£®;(ßá�°-^h>ø áýÞ€Žà« ÃÌD�3ö-Â7w|‰ˆàdƒØSÔ�—CˆÁ5õ$ E�ÔØEw4M Û¿óýCßÀÕ—ŠíÕVÑ©Š¦’Vv|š˜'ê«é‡�8ô¡‰eÔ$Ž{¡¥•úÞ;U–k@�cq8ù5ï#&󦢛p´; >ÙùJïú>a$öÒõÕÖp‡|áþéRÄùp�ë'6ÉßW ù¯¶1)f÷üeÏvCœ9rûg!ŒD Y_‘©oS×…ò“cÇ>Ùê?ô?Ÿ×ô �ŒPk‡ÂûÁ 9t®û³;½Á»¼¥Ç¼ÅÂÌl�²²™ÝÕðèm4ÞæB#ì¤�ôc(E²ÛP¥·‘Ê>ÆSªi¿jè[�Ÿ™þrÆ™â™3_VÍœ…aÿb— endstream endobj 160 0 obj <</XObject<</Im6 155 0 R>>/ProcSet[/PDF]>> endobj 156 0 obj <</Producer(GPL Ghostscript 9.19)/CreationDate(Wed Jan 25 22:28:05 2017)/ModDate(D:20170125222810-05'00')/Title(diff-ops-file-server.eps)/Creator(gnuplot 5.0 patchlevel 5)/Subject(gnuplot plot)/Author(Bharath)>> endobj 157 0 obj <</Type/ExtGState/OPM 1>> endobj 158 0 obj <</BaseFont/LETFGR+Times-Roman/FontDescriptor 171 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 667 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 171 0 obj <</Type/FontDescriptor/FontName/LETFGR+Times-Roman/FontBBox[0 -218 932 688]/Flags 34/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 111/MissingWidth 250/XHeight 460/CharSet(/A/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/q/r/s/seven/six/space/t/three/two/u/y/zero)/FontFile3 172 0 R>> endobj 172 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 5666>>stream xœ}XiTSçºÞ1dïíPª`”¨M¬­Ú:kµBµâ€C•yT&ežç��$@€äK @ÂeTĹZ«8VÑŽzô´¥íé·9÷®»ƒ½÷¬»îY—Å`³¾ý½Ïû¼Ïó¼a`VÓ0ƒ1Ë#264yµ[|lpœå÷eÔBµhõ ¸ÚO8±À,&˜eÕ±È.Ôþ2Jß…{gcLc‡ì®ø„Œ¤Èðˆ”Åyºy¼råªýeúõ‡dü÷“ÅN¡É‘áq‹—Ñ?¤…ÆÄ'ĆƥŠŒ IM^<õòŇâ;/v O� Nú¿O0 Û¼#Î'~W‚Sâî¤=É{Sö¥~| Ä9ãØÁã‡B‡¹„»Eº{D{ÆÄzoútñf{‡�>^µfÝú Ÿlİ%ØaÌsÁ>Ä\±¥˜¶ sÇ–cØG˜'ö1æ…­Àvb«°]ØjÌsÂÖ`»±µØl¶[�íÃ>Áöc±M˜3ö)v;„Ùcó°ù³Ã8Øl:6{{›ƒÙ`¶Ø\Œ�ÙÓÈbVX(vŸÏ8=mõ´6æ{LµÕ4« «k,7Öü#¼‚`[ˆ§dy}:{º~úÏ3g<�é8Ó8kÁ,þ¬Wï Zj­ywý»âÙ3g‹gŸš>ç7››'6ÏlgØæÛþcîgs%s‡æŽ±·³Eì¯çùÍÓC�õD0AŸê}cÂËÈÐÈt£HMÝ´KÇÑñIÉ´L"ôWpøÐÏHø§—6•jÊ Ëxp: ðž•¥ ʼn@ÌI‚l/%ɇZb2êØ�€fH"3ËšÊ&Š}‘ñd :�1«æÁî«–�vž$OÕ–ž�䙺˜/x(”Pì—ýòI<n ü ¥¥Ê3$Ì ^ï8#8°—û˜ÈQûeDJ=„Q¤Ñ©ô€4—ˆüxHE(]¤™¾ùäTEÓèrœ'V°Q¿ ¨È)@$ˈ G,ĵ ¾|èEr/¨á�“A{BeVÙÑE>q3¿Jôwă ´Ñ­GžÞÏÍóÉ£+ ׂ -¨C}Ç�œ ?²ûZ|Ò·2 ˆ8 C(‹Tæ©Rb଑ð*é‚F�l´ƒËàþ›�L¥7 8423µÁÌhú–ÿÀ„*ˆ�æ¯_‰¸hÑËåÐÚ¼þò ÝÚWh./3ž=vy%záû¶«ëNãÅ ɿ \»ËµžX+î§~ëfÐ 3'0Ê›�SYi¸<M(IY@¤úUúj��àãì±û`èZ€¦‘(rÐ"èY¿ |s…›QµÃé‹X{ÀqN�31?�È$áþ—�„K/ ¥ïæ¶Fâ�ûIúö(ÆÊZ)ë+6÷Ç`ê‹ù¶e…(– s«ðí*‰Nyƒ„ë [~T{­¬w!œù#´‚KáìÝ߯pLöä=$äjÏ´ˆLGH”¨ŠA OËŽð&#à%•¹ÈIÛSp ÕÂnn=㈦sm}Ð4¿í»Ž¸µ7s-}í žw0~§pÈ`Ṽ8$Á'® ß¼Üñ=x~ˆ{ä~qïWˆÑŽÞ$ªåã�s´Ùªíä¤ ¡Ü)‘lÏ%¡uƒÝ¢Óö~{Cyšûȳg@@3B6vÄ'ÎU²�Ç$%­<K·®RsÌŒºP8Æ„“Ôç쀆ؒcôÁ6«-Es¾ÜðjäbÃé~¢ÏwÏîÎ#PZNx–æ+úHê!U±v¢gl�œ—)ËJ͈’Ä€� K7F7§Ý�·H8ãü½ç×Z¢¾àZS�Ä+=°¤“ñó8“z?gÇãþï$¡”dþ�F©]$p 1¦(“”9�µP”‚K>K6+H´&áªæ‚3 áB…I\±�¬Çóá¬I3¿—[š©ÞeAB±+S¼+�äS„5|A§½‰ñ`ŒY8æð}ja¹â2 S‰Ö޳梒\™ž[!Òç–²ÎPi>‘fŠ ŽKÝåÇû‰ÈU{¥†gºðév–kJT¥€¬/ò�†PxËåÎRš2çÿWIÉPȦ¯LH· Äô•—N]Y£1«H¸èÿ¹ònBù©Lê˜K× #ᨗ+ï‘0.%ž*+Ä¥ŸÑ/âÈj$&jS­Í¹kÐáÎ|šH·á-v|�%ÅåÙ¹ù¹@djiaŠ6¥0�[ݼw¹·{îωjK¯L1œÀèxŸ=�ã)\!ZW†ë ÔtE¶>zPª¨µPSÞØ�gZøèúÈ�³)'µóv#¾BT9=-�—š£Ö×Z8*î¦þìf´BœZü†9á ÿd#mþ(W›­v$ѧDôá„�hórˆÃC¯Ì?öŸáöŸ¹Öx ƒ³üÎðæ¸ŠÄúCd-ž ÃY©¸<=#3 È€° £(ÀpT@sïú�-GA7nvá}¹çM(œ¾pv[w  õU}é¥Ò¶È†¨Y­ŒQšº¥”{$q�B“ËuÝ'�æÈå4$ù*…FAžGðÍÍA—ÏtÖ �àfêS…Y©€&j¼Îƒ]¿o=ât?l71þ‡ÃãLã<ØbÄ·IJ•wI‡‘7Ý£,éç–µ‰¿žP.„êžN÷°˜4¢>ñP®“©v�È C¯÷dªÓS§X¦o„²1Y\cÏ“�eçâ~ê­r�„¯Ñq-¿T|I$!@|®X,MH�‘ÄòxôÉ^|Œ–‰‰AE¹XåO¢BbëiŸ{]��ܾ>–=Q 8kjן+çLÑßb�·8ÓY#î —+F-7Wß/+}¦¡ïw–O<ÏÕËþ’G‰t3m2”‹ì’ÛeWg3ü ~ô Í8êЗl�X’+dJNy?z`(·IT—Údtäê~Î)ÆôººjSM�²PYÌS”(µ ˜ll­é>ÓçÉ=D 5ÙA¡©éâHE“Ϲ?ðjOõÐU®m™WaUzÏ“ º´­“~„ÖÒ²›+M“$‰²Ó�²�W@¨®ôwÂé=ÿ²A8�½óÙWòµy ¤¦Äzø Ýh“ &T÷u%ßÑEvÐMÈÕKÔ;ß6Aú¶•mFb[¡D¯%áa¢¡úK8^Ø ’9@œ™§ÌR0ey#FÂ[%Ö­{ƒÄPcÝ Ëí›ÚÛ…#2–V¶R3¯3¾ƒéß1áê‰ÏÙ¹ê`QBö‘LN\6KH© @1 {´YÁ¼É "f,êh7§ÁàlǗ˹Fø¦s½¬ºÛ‡Ìõ2~5·5¦f/ØE"¦ÿ†)ñì¢~1YdZl¿íß*^qîd%áG–%"v¹ߦÎÖ(ÛI*–Pß++{T0åsqcÔUƒŠ§ç-á­YÂ<¥<?‡·5!ÉËóÊ�Žª Å}jÒ€BÄDC^¥T+€8RÚ•&¨”…2³oEaÊ!AŒ()�/¦Ç-‹V ŒâŒ! “ùü¤¨–¤¾ÛáÒ‹<Ú÷V•µêuuŽ…Zw)V£þ!“Z×±ýw‡'»r­óHü~ñÎ7íeÒ0¯(UW%¨œ†jcíðîÁÍ~>éá!<ßÀø½` ‰Ø�×@æ©îŠ–vnc­ÑÜ|™´þç;‚ÑOU�3'~·àä�£ÄI5RjòããOóôR5Mô„âýL�ƒ…š¢jÅo$µœ€“ƒ¬r–PwX“¾SDÙú—.ï*È,WLͼúniٽ©¢˜�/`:=Ã’v¦Rò�ž­àQ7hñDÈX�VU´€ì(‘…ðÐ:"´5AoqZb Ø– ¹£!s¸Ó4x’w€(ȇˇXhå6ÈɑȤ‚ôDY í=žÀw!ëÌèƒ §�xñhþKMY–‚m,Ò?ß–?ám)YÂÇŸä– 4ï“èb’MñYÈ‘�÷�òìî#ääÁ[ù"Â2àtí•T-®ù½¬òqñ”|ãZ!ÑΠ6@{¶¿cPÜà‚šâ.etæ´*®‘ð*ž}SÖ”ÔÛ~´Úø‚#¡‘GBœ€‰¸w7AâõèeˆõrÑ#¸Š­|²ý*¸ êâË6ZXÜNýg;ã$í%Û Î„ÿ1aÏFîhí�«[×^pã�8ü;Úð}á":9ü÷Âã2Ïù«Íí+i�­À@F{ô¿–Õ�Í.™{Ò½³’I))^à(¨ oñˆú•Î|`Üü¦w�ìê;Ss�osÁ’Vlf@’¶�û–Qx—ö�ËÆæÎš2Y\·"±TVI§‚ªªÚöÀ†ÃÎÞ ‰¼Ä€ìpåÒ!ú)º…+¶Ë¤N–0_f 4R=¸OÂ[Кx› ª»áÙÆ/ãPh s´>�f—d©þÒŸœ,Çœ·´ÚJ ²Eö ŠJex Îëúê®´Ò@} zÅ� MÇú7šWÓ\©¤-Õ‰ÝX\Ü^;òá _D¤‹UêîÔL_‚×ëaTW¡™a¾…ÍL*вcwm#Ò€X“^œªµKÐ%&rͧµÎ ¡·¢x‰Éiéi~'-U.�ª—ö¦ïòNŒa¤×ÃÀ×÷5ôq;[*[A'¸v¤w‡±‹ì<ÕÉ% ˜N´5jÛó� 5è�݆–ÆfC8 šrkÅ­$Ê™\À>™óX~�?žÈ wu<ŽXÜšúkK ݧy…ð%û²¹m ¥A[Á5FèÀ1Ò=>âèÁ�›¯-ñŸîÏxc|fÒðM,7²C5麸“(ÙAÛú gÁO /³#±)´Ç¾ÁOÍÖýÂY²íráæ)…/µ*_bX ³ÐUÜ„OúS/Øf½¶Î Zí›ÎçMŒ�¯TX¢ýî‘q›ç㟎ͷýªv”ð/ sJ,‡@"OƒÖz°DôD—ªËT%€S7• E„bG–lo>iûZM¬c'¤¤ÄÇÕ¤š›kjššRjâèÀ}^Üžj¢PO¤ÉæëPüë|ÛU”;Íù4ÜvQJžT*X(‚�–´=Q¦�Z Qq1ÁÀléw‡V.w�«-É,LIä¾Gw®?xZûrSðfÁªÁm��ªÒrÃB=¨Ì3æÐ'‰:{²»Bò»Ç¿=õ¸‰ìîò–\ îÉ‹½×NõòÃÛ¸-Ñå‰.t0�ÊèÔ›^,¦=ÕÇÈv(È,£«¦´:¾V jƒ¬Ãåpkò*.GÛXux-dTWBBM^˜ÌÇ•›²d›-ÒrŠx»¯11žŽ1‹çÁLž® ÖÐ^ÛÁ�Î\Œäjr5ù­L#¹dV–\Âå‹`œÔăϡÕÐË®©Î�V�7 ]J}ÈYY™âLzy´¶£ì‰<u¨$.ÛUȉµ˜-Ý•ŽÞ¼J2ýy“i„Ò+?ßI:%6ýe¢—+øýÌ O‹PŠøøÃ\CºúCz•"ÀÞœPal‚ÿ�˜íÀ øÕ% f´æt€ë$¼7åžX¢\;ŸxüWÈ»I ß8Àm�q¿ív·®·d�<$a9¡þC_þMÉ[1þ>Ƭž¥ÜY#Õ)‡-+SžÚ[*ÛC›B¡W•ªhWhÕ‰é51‘PzŠÅóèËièì†/Æ ³åÛ² &p•P¯ì&aÔZ]qq}m_e ûk"vóP,¡p“IÝ-r”b Ü�¸BA/¬…Ds_kÕ /U%ØóP8¡p‘ç¸ÊéŠ7‰êèB©tq`g¿²ÍÅ7ÑÕ“›q)²Ñ€ÄÌÍÈûDŽÚ‡)õqD™Fkù@¢¡DèÏCE„Â=SìA‹é?�¤¦‰wLŒÚ[P¥]ö\n•$€ty‚,ÍA?Ù!;øJQ˜U£Ôp²ªåF uµº *QŸ¸¤Ôe�ÜrÂÁn1jCR³rªò*�žjÊ‹ÏYò©‚OœË5dt¬†ž“'í 8�%¶À�“[Xü9,×™!‡ô%çuKwP—3 u‡ ¿ ž°¡^ 4*�¶ó{»¬bQz–œNþ(G $S*€(8ò…¶µ+'³— ‰°¡C`9¹òðö­éÂâšXnt]jI ãÅ’¤Ð�äÏî6ž;Ç;uªúx�îòüÎö»Õ¢ÕSo6SVŒ“/aÁLÊmb;á2WþN„msA8@ ÀÆÆOú|;/$_£=mö‹¿A.dïz‚¦¦ç„:óáJh1¸¾�D!¨‹ýí™]4xÓŽÚý‰ç+¸öœÖl2ðª+ZJÚ,¦¡ß˜m¢î�2(öIwAË+³{nˆU‹#¿É—¬›8Œ˜XšºÝ„µÙføÁîQÿ•ǃù¶aE°>ßÖ n“Ïœ./CŒÏö­ÛoŒûc-×ö{İO‹Û³àãGûèMnÖÃ/ãÚ>�"Ñ;?’²ïy×…wr@À~GŸ‘7«{.ŸæžyÈÞ0>�†É‘S=×o÷î9”²7ÐbOPÖGY™Í?1/§²¡UÙEãí3¿?¸ g¸�„ëàt4Íܰ -DÖw?ƒØÅÞŠžóÜ´1£U‰$¼ 'Ø =/KšŸ&¤£ÿ}8óRÅ•ê^¥©^ßÈoOmB[y´µO|hbœ~Á„§imÝá›vÔicÄr€¦4·cÅwK{üR‡¢K+ì¶\�oOM¾%½~”=m¼f¾ÖÜ~w„üëèÿ‚Ù‰v³GÏ4×w |ýmÛ/�NpnØ›OÆCN'Öx·J„vOœ#ÌÛëöé·ƒe`I¦}Âáç˜ð]®–ÉMÂßmຮù¶AÏÐûì['N]Wȳ]É)‘\Ûêè~Gq±JUĵ Rª€j¡¶HžæFW¢‘B&ãd2áœ_رIIÑqõIM- uÍ-‰ ±–OpÄ 6 Œº×°ì5Óåz€`aX¸«{("¦ê�v‘ƒî�ç’GÀ9ÐWÙÞ6r±’�¾CÂàuð}4Ÿ›ŸÈ;E§ÐP¸xÓ¦À?áqy N{Á›’ð‰Ù4‘4š3æÁ&¾ ôÊÓ$õ†ÈV£}ëX´$êŠK�Y]"ŠæÑ‘Yá,;*-ó�Pµ£ øã &ßcg†¹JsŽ(9(‡[¡Ó÷/»€ÇœŸ?{ø�‡wê±0nt¤(ZàT�k×ý÷¶Ö;€|>ì¶yëѵ›7ðÐäÊ’P ,¦BgƯØÀ¯‡Þ¥Í®†ÏØ—A­¢6ëzJ§;ØC~ê~`G|zq]—^Šô²*§Eô¥Þyð¸¡ç4o°§~ÜCÂ�ø–´~i�‘6ìÛƒõ<u¾¸Æ7PÎ�M%¦6äÙu�žj½È/ûƒ„‹"’y±±ñ¢½ÉSÕ™àòÔçtú>õhÛÃù¶/©(d/¥\qtkÒ•u�žD[Û_Â-ã8Úwƒ�rp˜_³¬Åå”—”ã�3žÍ¬/((ÔX¾fÍê,4èf½ƒaÿÂêäƒ endstream endobj 166 0 obj <</XObject<</Im7 161 0 R>>/ProcSet[/PDF]>> endobj 162 0 obj <</Producer(GPL Ghostscript 9.10)/CreationDate(Tue Sep 27 22:11:45 2016)/ModDate(D:20160927221224-04'00')/Title(diff-ops-mail-server.eps)/Creator(gnuplot 4.6 patchlevel 4)/Subject(gnuplot plot)/Author(bharath)>> endobj 163 0 obj <</Type/ExtGState/OPM 1>> endobj 164 0 obj <</BaseFont/RFCECI+Times-Roman/FontDescriptor 173 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 667 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 722 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 173 0 obj <</Type/FontDescriptor/FontName/RFCECI+Times-Roman/FontBBox[0 -218 932 688]/Flags 34/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 111/MissingWidth 500/XHeight 461/CharSet(/A/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/Y/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/q/r/s/seven/six/space/t/three/two/u/y/zero)/FontFile3 174 0 R>> endobj 174 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 5962>>stream xœmX TS×Ö¾1äÞëD+é-DmB­U['´Z¡ÖªhT@ ƒ a&„Œ$Œ‡y !L2¢8"­UëˆÚVí<·´}=—wxÿÿŸ‹¯ë½µþ®•ÅJ¸7'ûÛ{ßþöå6S�7Ã;<J¿ÔKÍ}^ÂÎá±s§°¯ðŠþ§ó¸›à½†?Ìàƒ6ÇæŠîÚ±ËgÁ³/@ËŸÇ“w•Ťą‡†%8.Úëµï�Å‹—üç?+\\\¥üuÅÑMí¸�¿I’FÊb¢¤Ñ k]ñÝ‘‘á‡C#SbÂâƒ�‘á¾æ)�pÜ#Kr\äú†ãJ'§KñŸÕ»Ã£%Æ;NFî¸[æâèîè% MŒ ŽûÿW‚pÞí+ós�q‹Ý·5~[ÂöÄ÷‚wrO9¼ëÈnéû!¡^á{¼#öFFí[æ´bå[«V¿í¸ÆÙeÑKbñ>áBxïó Oâu‹X@ì!ÞÄ"b/ñáC¼Il&–®ÄRŸp#–[ˆåÄV‰ØF¬ ¶o;ˆUÄjÂ�x›ØEì&œ‰ˆY„!$^"âežà„ˆ˜ML%¦3 \†�x1¼¡)NSù‹øu6³m6‚8r*i$K}N¿BŸ›º{jËÔÿ�¦™ö`ºÛôá+gÍœ9óèÌÏm_p}¡öÅÍ/ÌZ0«|Ö;½ÐVø†0Gxï¥Å/õ¼ô ÎŒ2�_¦^Î}yÜ~½½Þ~˜Í²èÛ˾já�û˜™ƒùº²°{(�½î�L¢#š�h�&5 [$‡þf* Ùh­È¯,4JáT4‘½‹+bŠc�JâzŸZK¨ 5,c ­�FV�-›Lì싼ÇO Û~;�)Ê/Ë-´µTé/A¹ðÒª|3i% 3Q¾Ê ÐAÃÔ铵m€ª�|O‚¤pW+ü¸›Ž˜(ÿBM¢a õ]à𦑊�ÛÄ�(CžJ¸Ö;U4 i| Æã>þ&ƒÒää…ì*H�JmJt( ±CðåÝOãûA­XL%m¹Ö\3º(§®gÕ(BÈC«Ð ´wå«™¾™ºÊLy¤”€:`2ï„Óá"‡ï‘c›M8PŠ@Jª.<'hs4\Θ)Ÿ"eYÐò†�pÜqý¡¥âÃN…ÎÊ®´ò𾂕_ña>Ä —�#1šóíhí~øCûåߣ—$jóäòbô ܶñHH}O’Dv.õcp›þþÔµÛb¤yœoáÁ›cüñ=P™œ<—S­ñ@—¡IS¢×P’Zã´UéÕ \j*K[ó @(ϥͨMN�ήTý‚^…öÈÛm¦À*�Î)¸l¦Væ©*ÀúPpLºúECíYÿørÕ�û[W–?N°>LL$‘éI©šd�”ùÊ"ÿ*¿’ýÀ8GîòÞ²Kº  )`Yóê³^Wv|#ý@øyðê'tJÍ&·÷¢œ�Èì±uyE~ Ÿ†ï} §Â×/�K:Ü#n�0ÉÌ;hœ5U­¨I�QºVÖöŠÝý'0ñ™½0£”}…)Í-¥€>Q¬Û/™£À>­Ö#�.PÀ Jx°†Ú˜«.ÐpÕ~´^×h8íh_‡/nùòÍ=�q{%£TzÞÞ¤0µ·BßÜÈ4w ÞÚ€hÄ÷ßèºß«£ùy®å�ìÓN¹Ùî÷1–„<{aîï�Ç�W�zC-Œ”ÃN Òà�¶kÃ×/w~ ~_E=ô¾¸íâu W��êHá\9õÈPš6áûÇÚ˜–ò’Þg×SÃO‹îí] дCkÞÙïí©YèÚÒVÉ$öJU5ôºÊÚYíêŸÁÔ'öB%œ`×1£J�à“g-F6h>²ûhåw#NH�ö¤(Ýp\C ¨­¤¼+ô% �f¿×R›Ñg ˆÏTëô‰ò£šH bÊ’-MI×ÁG87çï=½Ört»Ø–…bØß K»0èŸÇì… ìwp##ý�^t é‚ ÅùÙå š†�.£>&µÑ™®ƒÊÒp(S©U©2ý~æ2GZ‹ŠÅp‰» VY½‚>NfÁ×VR˜+§î¥U` =�£ß¢RnÆÑ»ÉÙNÊ>Ãú±ÎÂ{ð„_ÌÎf*óKs+�}¼45P‚ò)àg0ìÔ`]0˜¨mù ¸DÃDªµÿLcQi†®\\¥*O7ºÞTmmK²„G'¸ùK¾¡2ò|CÕrÌÉóÀ ¯þÎ06¦2�¥Y›¢\‹C� ½� }îß„>úŸÐ·PÀYË5„¶™©õªJp‡†ÑðuêP­¬x÷²HW«±°Ë,êZ»³× ËÇöÂ%ð&¼Ád¹-™��fÈÁJ"Jº<m!-¬.IL,ˆ�ó®—¯ëžÖÃO$#GÛ“«ãA¤(0Bæi¬•‹“ާթ/Ñ©ÈÉH—äáìÝKAevfBuºµ1³fÎè‡#Ÿ‰o{¿C‚ˆeUÊã QÔÓb¼Ô¾²ŽkpUûg¯’¬ã�üq?ø'ƒJRÈþ¬Š¬ ½)­(Ñèm*bwŒ+Z³’p÷wÖ¯†ÄC×o‚a0$ïm–UÅßMבz*H$Óå)ª$ ©ù)ÅMJâLîÇ¢´½Ñ¸qØCrcëR8<pV{O; )p¹Â8RHÛÂÝ9vF«�f ]¸áŸÂ,6Â[ M–åä§‹ iéi�Ô;( 5“>ÕÒ ³AVnv~6-¼u] ×4]êª?×&V—'Å)t‰@¢lü@»)áÓ_ÉIJáØiæý9‡ÇøP ƒõÜ)/-ÆÙ"§F åZà:Y×5:Í:®®-fjc‘Úˆe‚Ãhßß]a=þîäCq`Ä˾S­ª´»ýnÅØªÙø3Ly@[>(�? •”°MA]˪Ð?i( ËP©´1‰‘š(@‰8Ñ'VÃGh�Š:�U©hTH½{Ú÷ngwUc£¸¿_àL Ý ²ÏX:ÊÏVŠ8ò˜ÇmÌ<Ha„§XÕš5Yϧ”K~j%¸;îÝJã“î9õ4£B‹5Ê–õÐ]òaêí†?ƒ‹>±ždwÄ(Tš %  •ˆÑŸËhRÖ'v™=�½t“¿{‚%¹®þ˜¥¶ §0§X’]šSŠéÆÖÚž¡Æè½âÝZ¶K¡’&&«ÂÁQZèë>xu ÷ع«b¡q_aMRïœàXE{¾„–c­ŠÌHKÒÄ«diI€“�è—à.éí€3èç#�÷âŸ]1nÏTä”�М]¡É 1!ÊÛmA«`0X^þIØ)§¦W¨�Û_l}—«]»™ZÇ™Š»4|Ÿj8ö�y6^pñ" Rd9@ &'ûˆ™Ú—«*sú©`¾ô‚7¯W•Ü,™‘i²¸­ìôx·žÀä/øpéø:&#/X£ß¯Eë©TQn(tOiZ°d¢ŠŠ|zô1tƒSàkð… ß-ÜíêŸ,ö±é>Õqîá™uÈñvºì;XwüßzÜÍþú\¢bØ�áfF!U%(aG¼Sœ½�ܬ.j—°Q¸]Yù¨CmÿoMþ¥ªr¶�: 7sÎ E?a¯Zx¬ Ó ÍQ’­Ui©™9éYÉ›¨ Q°(½2Ó8éLÅýy´ RQ ™ÕÚ$QŽC¾Þeõ« å<�2Á]¥ŠM”«@:HËÓÊ‹ Ü)ÉÉñG[ãúnœ†ó/Hà2v‰±µ¼¬>_ÄuØVÐÄ;>ÊgçA'&`Kh¼ �v>†ÔooÒaÔ†”IŠKd5)Ç€¨¡Ö\7¼åÔßäÐC¿@Ù6ð.�^~´ òOöTµtˆëÍ�Í—iÛÎüw_ðØìŽÞf?f&üpµ5Ï«�µys!ÖæçL½m4Þã:#€B±y(•Í 9ùi†Q6ÓoR`¾J¿§á4]Q~¥Ù…,˜8%¨$¹ªŸUì4+¯ñL~‡?ê¸ðœ ŠJÉÉY€Õcf³â‘ ÓíTˆR©’Ü"PèÎRÝ! r¢¤­1凱:R˰9�‡^º¿ N:!Ù‰)k �N›’§‹´³÷cø Ý{p~h¿�s@kIãÐÚqhßàhÊj¶ŽWÊ:ÍÆÊ²Ê‚.ŽÙ9Õ•U™iJ³¨JCÁ.}EM0¬\€6ÈÉ~P©ïÙOO좄¾‡v.%4²»1^®d·`t+¤:xìèÌlŠÞ ¼@PSô¥”.C[öU^%õ×uMq­QŽí~`Š4|ÿ¡7àB#ñ�Õ�úþþeHô‰ÑC¸„)x¢ó*¸ êeÆU£UìÿtðNà9´’|ø¯qgíAs±Á9°´Õé‚§dÄýË#_`ççBGxàçè§ÞW$î·Öt,Æ©¶ƒ)ü[–4x¨·&ïK‹SÄ%$„…LñÀÁš°–}ƒGÅnŒYì;Ew÷Õ^ôsŸ±°[y¿á2^ã(ñ8#æ–®c•ºèqUl…®Ðu暺ŽÀ†÷wùĈ•ÄêCsÖÒ.Ÿ¢$جոr[ŠÑ„ÕU[îÓ𴥞»ŒÚx†³�¿ŒÁTÎBFƒp€iÈ®Îi�Á…²þú+­WÁG OÕÓtx`•u)îŠjRX�™¬/Óý5Šôº †çmün¾’Spa$›dÓX\Üç\Û?ÿM?D%«róÄ“¿ß²@ûãðhw¡•gý¦Ž6ZùìQÖ�é^O%cמ\œXâSS èe›\�Ü¥•ÈSRéG£ÕÉXL“*4½ÉnûbŽ‚Úçaà÷÷6ô�wµT·‚.pmߦ|Ä9øäÅ•‚*`iko,)Í)ÎÉælcNè=¦–Æ6«©œMuªV&f3m†ÇéC€þºMê¹á¼åÙ4PWlì;#)„ß2—­íƒ- Ѝ*qMXÅp„Þvàýàë?`¿²˜Ù߸\Ž�A5—ËÑñ…fFšŸ\}‚E7ŒÍm�­ æ>p ô«;c›¤½Î \>›HáI9u__¦ýkè4¹†oÆ _ˆ8¶l~ÔpLCWp5)ô�`Ÿ1Öò’8k$h©_Rp¨\| 6,}q6gUp×L7µ[àÌ1»‡coã‰þtå»åÞ%fzEž1·ˆê'ýª’®:íV®Ct&ê½B}÷k�²¾0‰‰IH�Éj¬MuµMÖ„ºhlÿÏ«:-,ê ·ØÝ~U¿Ú ç²{0'’ÈÌ­V�íÙZØVR1'*ŽF‡E¦ƒ}`íÀhãqGzîÐqi©º0 ÄÓÛýl^é~Úú‰Èf&¨%…îæÜŠJÓlá3Í|’²«Gß3R_>úíSïëÈá¶dÞHð�¸@_ìëºv²OÚ.n‰¨Œ­òÀxr.±?õñ`1öÅã3‘E�·µZgNgOb‹Q 2r£äIP›R‡¦Ðõd:\/˜¸J¦£õ‚z²òêÌÐÐÏŸ8›xŸb§?ÎgpÞrË�ÝV¦�L$áÝ.+Ë•súj•œ{8w~»ºSнŸŸ™—•—•Ÿ%*Ñ姃 :--]#–+a´‰ Ì�4ŸEK¡�CSãí�® 6•ˆL•y˜È%&¤"»sÊ3� èÓT* ^·mXg*3Oª‰Ö{¦Š¢ôN”Øq3ï÷1ø¯> Ù ŒUT}Z†UUÉÙ‰ªD°oxØf�¦FÅìŒÜÜ€}Ì©”VC'·~Þ�4„�9CØ�·Àtl7Óè:…6}â×CÞýö›Ýâú¾ÒA0ú¼¥x?=áãõž)"Ës+rñ¬h-Sá 7–{Uj÷ œ­‰r/Д�‹4ûŽwŸBªÛªÀ+ºçð•s¼gO ;÷â›ÙyŒ1¿„{àÒPš AEÜÊ=9øŒ8å“§,Ý4l§@^IYqññºþêv@Ô†m‘ l&öhµ^\»&˜(¯\e5¸FÃBª¹¿­fЗjbœ%(”^z½§ß$3Q±yQyêÐ-‚‡(8íÈ•õž¾±ž{Å)—Â÷‚@ S9»Ó÷)Cž¯<\ë­ÙþÓMkŸiáýÓ™{„�çîÙŒ-ˆIé±:š…¾q@ð»ì´ڜ|QÚ±t3(õue¸G9u)§,íÄÚ6GÔŽæ³3 5™“Ï:j+‹Ïæã[²åÔÙ SJçR¸w℃‰Äöc-\5±V`"ŸÂÊ2+äÁSæså¥çËpÞóµœõ }<®©¥áxSKlC·†«Æíxõ?@ã\£;3Þ Xæ¹GŠ(€¦ÄkCSOíé <?΂þêŽö‘‹]�p& ƒ�à«È^œË<9‰G¼IW¯ü�a'!ÿ™äy럯¼�ƇÜØÛî$PQ…åy5ÅÕ˜ ÇJ•ÎÉÕ'¤¦)ÓTYÁ\›LÔ»¹©eà4ÍþÈÙPð€­»Çƒ_?ã³2ø £. ñR§"¤'á»ÐíËo»€‡¢_Þ}Í{_âáqD¸2Báv,á秎Ö[€~rÉkͺËÖ¬” ­ÈS ags§âÉüõ;xç‘ô޽ð\ ?c.ƒºìú´k‰Ý^`+½ÆkǦ˜äâúqT�¢˜s~JURXâÇ£�zOINõ6Œ€àlê©è–äZyE /n·Nï¼0û“�ÃËý¡â¨elâû¦L‡Þ»'Û>�ôõ“�î¡Êи8IT”L¹-~R#,pá‡ì:‹<ùpý¨½ð[6ï믳ž�$º1á)Ø O µ”ð×Q¸vŒDÛ?d��„øçwU�ì¥G<8þ1¾Ç>f /Y òò‹»¾tH+V&é2’p–¤$â!6o9 [”Q�UÒÚcP÷Š!r~XD/Þ½q]²¢¸6JQ—P†×’h•&Nz*þþ“;�gÏHO»€;òA¿3�^uhÚ1.j••µä�ø|Åg½Æ72ˆÔyÊ7û"b½"š V5¾Õï×x!þv7/>ûŠáK›?AT`’Aê.i„‹¡ $àŠBÝ̳3®˜SŽìÞòÖÞïàò³%V‹Ir¬ª¥´�³2ùøõöî=»ój‚$=ÐÂj}ÿÍãE ‚Q$òŸøVp�„aãó&ób·µÚ ?ØrÊny?Àãö³óóùö>p“þÔõÊBÄ{g»ÓsôËÅÂ/á’¹mö›�¶Aœ1úÑobá( B3¿¢Sæ3w÷Õ‡‚=ôŽƒwlðùüÃÚ¾‘Sâ¡QfåHè ¦GNö~p³?p«—ì —Tœ‘@f—"¨ëgm¬¼æoø—hc¼h¾9ôûƒ«ðE�çÐÐe9œŠ4}å4ÙÞyûªzÏ‹¡5ˆïˆ–ÄÒð2g@rfš6M¢ô†€ûpú¥ª+Ç$Õ–ãåM€þüäjô®{½ñùÞiÌ´Ó˜i›¢bC¸­ [8Édaç_¼ÞÐ�x.¢¢Êaí²ö˜ûñ7´À/àã§�׬ך;îŒÐÿ><ãw¡-̽ÓÍ �ƒ·?oÿÀ©�¾òã[c‡NÇÖîkÕ¤:<vo ³n¬ß^¾,¯©�cvËÜ£B]=¹R¥[R·ƒNÝö ÏЫÌ�¶“WÁúLX÷Á°ø„p±ðXD�¼£¨87·H, Ê+ wNIQº>B²7Db›la},ÐÛB6O{:½¹dÆŒ§53fÄÿ¢‰I endstream endobj 175 0 obj <</Type/XObject/Subtype/Form/FormType 1/PTEX.FileName(./figures/diff-ops-web-server/diff-ops-web-server-eps-converted-to.pdf)/PTEX.PageNumber 1/PTEX.InfoDict 176 0 R/BBox[0 0 360 201]/Resources<</ProcSet[/PDF/Text]/ExtGState<</R7 177 0 R>>/Font<</R8 178 0 R>>>>/Length 19438/Filter/FlateDecode>>stream xœ­}Û²l×mÝûùŠ~”ªÈ�y¿<*ÚQ¢‹MRåTÙy°%JLr¶d‰Q¹ü÷ÁÀZè³Ï Yfñ�»O¯î^—910€àÏ�ô’ ÿÙÿûúî?}9øî]üÛ»ú²¿|Ç÷_þí»Ùö£—õx}7Wzéüûý»¯ì€¿üáÝŸßeýÛþ÷Û×ÇþZ¾p=æãë߿ӟÈ�Ñ_š|:½´ÑÖãë×w?y¤Ÿ~ý¿ß}ñõ»¿ç�Ì´ïÁßø‘ïûÝõe>Æzé×Wç¾zít5þþ!_�^Êc�—q}uéñ»sšY¾öúz{ù~¡·—�ϵ—•;¢}–öÓ�”^ü�èËò#w?—ò²íGFÿ¬×§_iµú_Ñ—?àWZ‘ç�[~Iö#ù³ÔÖg}>ýÎÈÍÿ޾ü¿S·<”Ü÷K¾~g|6çü¬<=÷<w÷?¤/Èu\М/Å~¨ŒõY«ý³æVÁšËöÅ«ýÝöøÿÿŽ!¿”^¦¬˜4Ÿß}øÇ–E¸J{´ú2ðœÉÏõó¯ïSȹ.;þùcŸ@Îã¥ÔNà¿þõÿÍß�S¨{Þ·Á^üè§! ,¯xûÅ×?ûúë/ÏyŒ>¯³ÀŸ?ú9ˆ�ÉO·â×÷ůΠì<Î�Ð?úIìö’žnÄ—_üì¿Ü'Qòv üóÇ>�RÒKª<‰ÿE‘�rß {ñ£ŸHë/ûéNü×?ÿú‹scßç€?ô3ƒ¿ŸnÅßüâ7_ý×s»·sôÅ�~²áÖ+â_üì«s'jÉÍ΂þØçP‹øÏwâ×_ʺˆVyWCLs-Þ¿«mÖÛ·Ç|êÜr±“Ký9Lö~™Óí!FxõQy¿úëë¿|ó—ÇŸ~ÿø›ßè½/kvù@~)òñßÉ}úæÏýæ»ÿûÝ?ýäýŸþ€#øå _-^KÁÁâ`è±å~ß~¼?î÷þé§ñÊdq"Æ�LEïË×ÿþ¯ß|w�Õã:|þóYä.ÊÙ Æ7ýâ|}ïÆ×–üRò¸GíoÿãOä¿üéçuoY[^Í_þô~ýßÞ5¹ òtìKä|‰ï¹ïV^ 0ÚæËVµÞ¸€�_†à'\•¡@xÕsêpb>ÏI®4»“3!7?¤ÿ˜p¦øw¿_R<·Òð;×)ÿ£þûçK>?ç’WC/ìœáç‚4b ÷£ÈOÐE“oû—þíÿùÃ_þô×?þî!·õ¯ßÓüøÃ»R&V}^|€Yî6ãã/ß¼û½,µ�¾ûø‡ÇßáßþMöBïi®|yÈñ3°tbpíÕûëÕP¯ð>Ö^+ÿRÓË–¿êć«PðÓ«Èñ#âè±ù+ÉmÈüq{“czãÇc–lTù8:­ª¹•U!�wË­ð¦KÍýEV_ž²°²ž¨œ…<Ý%‹©eÒš€›‚�<xÈÚ/g76ÞÁ1²>5œ)Z´že1â[Âàše�*‡xN›‡ÀL_wEoÄÛ—=d©Í.{pûËž�Ÿâ/{m1Ó_ö”Å_³¿ì-ûfùËžxÛ_öz"vÑ_6Üòå/{‹qi%\¶¸ÉyœË.) {P÷eúß0µÿ‰øÕ»¼ºšèŠÝn«-Í·ßúĺ¼? no�ÙW{‘ÛZ\ƒ<î~õ­x�[^§ÄM‹ÏNZ8q|øé"$BžÇž›Æ�>N*/I>2ä‰ÍÌcäFÊóØB;†ºAò´ò³Þ*¡‘~lYiuë1}½ ËŠå)‡Ô4ñ8–,4ñjyˆ01Ùì¹Ï†õ‰cÄ«h`hò†â«p�—<a¬Ö'Ž?Ì�Uå us$�¨&¿ÕóµàYw²WW{ðñ‚ÈMÜñ¾¯ªÉº“)·øeO®6Ø»*Ïwò²Z }LÙ™²”yLáJ$›j�ÇÈóJÉÎl‰»,w.ÅÜR×¥”;þª�![3ýžÅ¥˜±SôIt|£PTñHWmÉ\‰¹â$xY'ö kƒk¿4e‚U®…'Üe¥Ëý² ¯Iœ$\K.»è.~¶ð^_°6úC{ñº î,¿fànË ë˜ïq-ã_S».ý<ðÐ�k°6|T® z☉‡/ĆµÑ¯;¸À@°^xÙkèÑ&Œ�z–å²b„ úðYˆ²îšÐ…>Ԍɦ‘GŸÁ€+/jŠéØB„{–¥VU¬Õ”‹Jp®yQ+Ó(Õ%»xë÷`7'±HSwN£Eª]>™uÇ „DêÄ Ã1“©9ƒÂ/é`ï[L®’—´“\�ÐMü¯ñ9u1ä²Â7þ·ù[oïÊZlÛ¶”8¥³-«¬­¹ºÛ–r §tö%®0M·-å&ȃ8»²ÉÊ‚»qv¥ÜÊ yve“¥5êt»2Ëæ�‰<»²ÉâÚ¥¸]™A¯õæÚ®l²¸Šž�íJY ò šÛ•]WÓå`»Rš<‹âve—Õ5î”õ*ÏÂïJ¬é¤[Åv¥¬ûüÂPÔµ+‡,¯ª;×ve®Yàa¹]9d}�ÒÝ®”M(ð0ܶî|v¥ìdzAgWqȳ>mÛ–˜WªÛ—SX[n[f@ž^¸mK�üÃmK1P²ŽÎ®„ Kmº]™�xÉïÊ%«³Ú^Ñ]™�x׺+¼Åß›gWf ÞènW¾·ÚÛ–b½Å�T·-—ì¸LÏáÚ–‚²œ‹Û–²jdql·-L’9\²~€Ý³7·+�ÄaÚnW³RÝnW ¨M¬ü°+§™Û•yÊÚ­ÃíJÙdr•ÙðÜ3`Y�¼¬]<Zß0þÖŸr.¯ÃÁɉÄí…l0:e8Êþ†K)‹—²Ý -Ï‚.»šð+ÞÕĵÑËTgp HÅå�eõÀÄ*àšúõ¸¶ �¢øPøçªbƒÓÉTc,†RQ|)úÊ¶ÌØßp2Áj„{&yDq¹›E01沿ádÊÅóùQ¢¸<•¤~œ,î.kENsnýYÅDqñ!&ýA1°Øßô¬2VOCf(Þ}Kˆ’ý=eã"ž\Ã2Ÿ—#'fAö÷”CwË<F Eñ……ÿî_Æþžg£#˘(ŽÛÎëêò�7öµl%z„fš(.7ž¢Ë=• >¦Y�*_¬ .ÛP½Üž^Å壩óYÈŠâ]ñW ›ÜÓ#©¼nXiEñ©ð[†ÜQù…¾Êk<F£¢ø¶ërGeƒwYòÔyŒ@¾®=ç”:° åôíjG�(.w�ß2Å*XuÙ>uñ[`£ ârÓÕ+û„ý ÞŸèþ‰…݆âCáW.R®& ® 4Î;Ü+Ƨ±„%÷SöxC˜­òÃF+ŒoE`YÆ{¼‚†6~O¯M#õ„_a¼v¸´ú%ÃÐ÷œ�rË ‚¦²íÆÔ/Ù†¦rÓi dOv씚àÓòAÁFÆeõÝTÙ›òLñmgkŠ‘¹Ì—mÍ*Ëq{Ò­)H~™/Û›Uîp62§{Sn„ÛÏÞlòœ1øÚ›r?+.îìÍÖÕq{Sž‹[ÜÞlò‹{·7åùʱÙíÍ&˯Ìéö¦`¹¨íöf—EÜu¿ØÞ”ÓŸÅïÍ.?¹lÿêÞ”U+Ç·7»l©¬öÄö¦¼’c›Û›CîzSëf{SöÜ·7‡ü¤ìX·9Ë÷ËÎnwùIeÞ¶9ÌM9{ô¸Œqö¦@9|·9Á²{ÏnsŠyivá¶9§üÞª~sŠ™‚Ïr6'8&_›S¬�ZÝæDì ©5±Ý)�.‹Û�ò3/Ã6¹îNAs‡Îæ\òƒ{úÍ)`>^òr›첨é·Í)` >Ët›\¼ˆ¯Í)˜R° lsnù½¥Æ6§<dø,ns‚‰çä7§ ùÆ&ð›Snºþ�mNAsø,nsÊFkðKŒ�|tnÊ¿¿Wºó9è'7H¶O· Ù¿~óÇßý¯?þáQ©ÉTØÇ¢R¼ë‡‡xòkËÝ�Q©i¹6�CMKµÙ«QCTêzýí‰ÇtyšS9Ÿl¦ÞÎ*7¸òÙ"ð¬N¬:Çà¾ÙÂ@æˆRÉ×Ô™Â1òà§Èê.Ou á¤ª³ru†øx4ò'Þ… ”šñt7—I{Q 6Ű™E%®¸Ï˜dǯ'4´î²ÛÒ- U°Cé0«#¾êRë£�¡™†]ö<Z«©eûßEËvÙµ/‹eÉ]U³aÁ£Y»]ö`Zá)î ÖÀbNÙ Æ…Õ›‡¿ÜÕÿúà1ul­|“앜ýcê‰N¼{L`*¼u÷cjØÃÕ?&±GúîÇÔàLoÿ˜ÀŠø(ïÇÔ`/šLº$îÇÔ:¨‰{L `Í?¦Ã4üc*HɆÇ$€F3l� � ºî÷cjbç1ɳ$Õp�i“l¹ÇR vä“<\öyLÈ…�íÓ ¯;�ÉGý>Üá_ ·ÏûØœíb~o¼ñ‰=Ž4p_W¼æÆŒì{=æ~õ-óÅ/p?†¹± y‡³˜‹…9ÄæïC×v¼ `^ËPÿ(„ÅÖÃkU—¹­Ä˜øP4Ü8Fþ þÜ|ÆÚnÌå$À¯¡á¿ê¬É $ñíisÄ×ÙFÌŠ¬•�(Î �˜Óªv),Ê-O “×ö:‰KSÃD²{ðÀ]è4w¨$àguÉ1ɸrðT%bÊD—©Û•ÃÒÒH“°ûÄ>€Ë¿Í¢�ˆ{ÐeR‚ƒ ‹€eFREtAÜI\&R2,|ìÙ�•…œ3Ýæ\ÿÉÌÜUnìY€ ÜÛbW^ã&{¶`ÓeúŒÏŒ&ßø¸ ¹e±f‹|Šžµð�¿¨Ã ]ü) !l_)Ïp@&øBQ†ˆ= P�•Ñ(�ü �õòS±caGŠú�ŒñT\v3¢L{¼Xnì´Ënr'äKèÈòÙ²²fä�e�õÜŽj�‘¶æ«òË£ñĤĻ£«‹ÊýŠZÓ¾£·×<daLƉˆˆà}Ìmj¼ q«ùt‡±a朤rW—]5\¡�é%&Æ€æÎä0rW‹Exâ«â'Âeæ­n'fq!ø³n’'ždcìMŽK“±@a„ô²;â¸í1éTó±X±·ª/#R MYƒá›…äøŒ¢^y—opÒñæ1•š‹¢Œ7Ãï’÷¦,Œ�Uí2HåÞN»r¸ƒrå“Î9–Ä?a›zÎ8¶þ˜²' cÅ;5òM¹·]¯| Ð&$�þ;~jçM¢˜;Œ‰¿)k£ÑÆï Ô¢­«úƉû ŸI¤Ý€~>¨ÎÙÄ¥/ˆ}&É9à�°T/Χ<âE€=µÅQp9;üt.Ò�p]äÄ­)vYø:~ i% �o9¨„`¦“ø Øw}4ËDÌ„`˜¸ÑE©‹ØáEÄéÈ<ñŒ§ü‹\ù&¡ÐcÄCâ«»Ïx\�ϽN1Nâ!áî ¤§4 'ÿ"®ðéà2›££$K°ÌÁîX2 œf#�ÊKš“„q“”è yg¹­[�V<„�«Þ²)2iq–EÌ«ò)½ê…ãzlžŠØs^öPZÁ¸#srϺ)Á®ÌËFÖ�þ…à¿Æ„ÒÅnÄwõw@=ø žOL§nâÉ¿ "p#^Ff!‡x™d÷ ž¸9$:ˆ—ä_€f7âÉÍ( lÄU*Þˆ'÷|7â�ç]oÄ£û†@ÒA<Ðòá> ƒ_7â%âeä †¼Të<€'‹Mïè¼éDq€—‘¦ªÅÞÞ“@w�O0L#z7à!ö¸!V»OÖÃæ…߀‡¨Îã�žx—=¼‚\μŒ„â�à!€‚€à<Yá\ûð6"ãroàe$Åpé7àmdÉŠ<Ùp½o!¿â‰÷Å } o!‘Ö²ƒ<ÙÛ|½!¡Ð%vå`^Fn ~cÞê�+øÂ<¹³æ½Ao5��á@/#ý6<è­2œ< —{®°ôÄ€3Hyc^F†×}cÞܤòr[\áòrÝÍCžXsî”ò&²z@Åódû ¢8È›�j\y‰>ðy³‘ Ä[¼ìñ&@²¥âeä›G<øêˆ•ÄËHñ×êo"Ù$ç ^M£“}!Þ@Qðí ^ÛKý â¿�‹ƒxYÅí�oôI´=€—k«¼ðð†ü ë�^�Åžü;ã²ð2ˆp[ð†ü¼ˆxtºzÀ)’âeÐòìÑfø4ñ@ï“G¼ŽTLñÄMØÄëHB"ntO?œ‘ƒxYÙ;ñ²Õ!^GºS.Ð!^ÉŒÊÄëÈ.É®?ˆWO̯§BßÓ!ž)©nÄkHbXâÍÆ«¾‘o1ð:ƒŒðòex¼ðZçU߀×äzíð*š𘤺™äbÚébžâŸ¿™¦zë�O1Ïëpn£Küþza©)u§©(>‘ïWn·ç‡3,¢Ôš^ǦÅ�͉†\ýþácãpë«r‹ŸÓ­O°D@aÍãOÙJ…n‚r#(ââçpë³Ò‹±Óõ_ÀD»U30WWz�hÊyÌ*.ÆþJ»84Á0<=ÿ�ëÆ™«<æ•ì Ó’ÃEÎɇá_i¥I,TO׿,qâKéäÑä¯4åêúoª—cúPz`á|#¸$×€¸ºj.ÖL4äôI]ö1}8_ŽYMé�…ü™²–u÷@è]å@B²ƒLc®ž÷ÿW*}dË Ðõ‡Œñ�3W% €™ì Ðœó˜Ò|V�n}¦¾2tý.g¾•È!=€ B/]ÜŸ9€ë¿•Xv�®ÿ`åŠ<4¦ ÷ªt‘AéõKVò©…W:?ä–~ ãß`|qÞ*Ä¡p¤1W¿ùìëúb.C�cäáËuã´Íïo�ª´åê÷O— À!½ùóðP�"��� ��UZrõú»ObЫ/.ÏAÇ㲑rPÏ¾î »j€™Ës¼ªÏ|R!ôû'g­z)ºÞx’�vœÇh\òJ…ÐÄmŸ.¡ßϸ$Î[µY²À5†ÙÔŽã9ît ÓgTpÂ’æš5]Om´å<f.ŸRyÕ˜•K»à LâÌ;3ŒYaÕ”S]0|ÖåUCV.3ƒcšÌœ¸ªÛd}ý|Pe2¹>‘×p©ÂgqÙ"�^–72)&¤+ð·�:Ř àÌeoæÉgxpŒÜyÙÓì!fEeðNvå�4—áyÕ˜•˽W€gÈŠBE¡ë1+$g�’Ñ\j*éÎá€:}šTXj°ék§¦èE“¶©-Ÿ)Â1£ûlŽ‘[ .æÑ”U ûA:¯éá„ÈíÉ%½jÌÊå›pŒÜ€I`J&¿BÌj2Sp´g¼›—.»P.ÿ�žœå\ð€b�¡ð @ŒÉàðð&À켂÷;€‡(Þ€Wð9�Nàz^�fmOxULøv€'+ 3f~�º¤�xy/*Cà•Å$ú<Y�“W~�¯.É:€GtóxWÞd¼“í±¡£vxW�“Ûá5ÒÐ7¼C–>5‡wyË3Úï ëÚïdÓ^øÁ;„ùYˆsá�xŠ…É‚ƒwb–°ÛÞ‰ZLó¼«qðš#f‹ÞÉ>Å¥¼£—~ð.Ã7ÚïĶ^úÁ;yÆðÆ;1€™°ðäkݼO ý4íÜxÐà!Jz�o®JÑÛ x e•ÅÞDŠ#�^BRl9Àƒ$‡êºð’p~oÀ›²°á™ÀKB Š<ˆv¨ã»/ 3Hð&Öõr€ #B›7à�Má­¼„”ãô€'ö�5‘àí5IÌà fˆàm$@!>€'4Ÿ—}Þn�Q¢<胰½�O¸6é¦C¼Q/üF<ÈÈ@Þâ ¬ëí5l ¿ñ:jM<âAl:#âõÅêÉñPÆ1°=ˆ×Q,;â-¡I õñ F‚Ãz#Þ‰Ù!^—u�dÊ…xK�‡x,A¶z#Þ$A¤Â!^ÇÂÞñq„\Õ!^—…½<â!r‰¸‰C¼¶X�pP"⵩rÃñ¦à …ŒôZ'ÿ= 7µ r u”J7è͆rÕìA¯UÖ5Лr/QWzc^û¸ñeÄyâ5YÙÐJ܈‡0õ¤RøF<aÖ¼ìñH<‘ôzŠ<êÅ? žo¾õ)òy>Àí4/ò‰?/ê©Çò‰hJq`¼gÓàò…ŃüÏa±XU¹¬@>Øéž|Ê+Œ3,†øoxò)?Aþç°xfÓ­í±6k{ò)f­k˜øÆbĽ²ÇâÔ·F›o,Fø¬,Nbn¼½°A¸êɧü´ð…ňåuO>å㙡ä‹'øŸçž¤‹¡Ô\ž{~×>X ˆÚž{ þ4 ßXŒ@göX,ÖG£Í7#ZZ<÷“Höç°Q×ê¹§üİÊù ‹—ò?‡Åâ1}p°b×á¹§8 �—~°º¿å¹'�޵<oe€‹K«*Ù¼°x+tXLùàðX¼•:,FÍjõX¼•:,†Â°,ÞÊ�—Mè°x+<X âôä³$2@‡ÅØ�Ë“Oú¡;`qmd€7—¤ð`1ª²'Ÿ%)ÿsX %cuX\’ò?‡ÅØ�͓ςÍÕù¤ØÑ“Ï‚Ý5ùÄœž|–Lþç ˜zHO>KVþç ¸±—‚ƒâ’•ÿ9(†f2{(.�k”�Å(»¨Š %“�|b 6O>KVþç ˜ªO>KVþç¡8“ÿÝP\ŠÒ¿�ŤŠ v×nŠ«®¨5R Ÿ(ðÈŠ ä%�O*8ù,Ê�c ¶@> ) Cbª<ý,JcÎ@?«R@‡Ä”‚ú‰ýµ=ýTÕÝä“:Ð@>‡ ·ù„T£òi•—Ž|>ã]©u€×¨™rä³jlÕ°ž|V�ÑzÀÓ0®#ŸE‰¯¼‘È|ù,J}à!wÐù„P½ò‰ÜAs€'+ 3?s�¹ƒ�x¬¶Éž|"u�=ù”õH⢭$¾ðJ!ñõÁÖLâ{�O¶Çb~Æ[�’ž|²‚hò‰ôA÷ä³de¾ð�>hðX¬TùDú xòY²2_xHdO>Y•àÁ{Üž|ŠwY™©8€ýýòä³$¥¾ðZ"õ=€'§Aêë�ýî��õ^Í“Ï:I|à‰¡ŸLÏÀ«ƒ%aðXZV<àÕFÞ{�OP‡¼×´þÛ‘Ï’”ø:À«™Ä÷<qÈ{ùD5Àô€‡b€ÈgYä½ð¶òÞC>Ë$ï=€·•ö:òYy¯¼MÞ뢭¥‘÷:ÀC`òäS*y¯¼­Ä×E[K&óu€·•ùºhkAð€·@}=÷”µJæë�U�ÍsOùì`�ï¼ê¢­y�ù:À[ ¾>Ú*› Wî�J‘ä¹§¬j_x¨4Ûž{"�úç�o�ù:î)f…y7xÌ×sO±<Ìß9À›d¾>Úš&‰¯<hqjˆ¶¦Aâë�šžâ¹§Ð2_xÐ%Ï=QÐæáùí‰'¡!Ûw€–é‰g¶ºwwཞxæº'ž�:lÕòú@=ñáê©'hd‰Ôs�ô>SOO$ùÿüðK à)²ã�OQÏëxn¥qòžúBŽUÜÏëïoµ'âÀ¬ß´ä@Q&g1t%®lôa(�kÓDUî 4ËOõØkRõì€ÆýûÖ¼gºè ²æT1Áœèo)ûƒY½èLWÿ6Á*©[¯ôÆù¢3bŸÈäR5Õv"ýk¬51”ÈÁDª_ŸY7�”°²H 4_©®6¨Ÿ`#$\¦9È”]Ëî&ÚNJý˜öîÆèۢɊj¶“R?fÏ•Ë@&�«F^5ÛI©“ðúK"�ª¢eÒz„'‘òD._¹ÌÌZR‡ o>= Î)0.#€F8TŸ^yE&‹±žVOñ^!—Ïd¶BR8­¨À!Êû¨qPÛA NF *èõ³ˆžR µí�ÅÀ¥gA…ºôà}Â9µÅŒ²í<`tûµS”FfÄû ‰cA½~¿ÁúX=eЀ=­¨x¯EÏÈxBHbd !Ji÷ÕµD©)W\1³ùC¶¢ ªôIý(l±¸"K�-»ò¢Ü�ú‹+¢žà¨5ôèÁý¨²¹ÂŠl_’­¦‚5uÜë—AÉ54é…¥~Ðü\\f±S ™^xUêGí�qH€ŸpžÕ©WîG ’..HÍÈâK­­6YOH™Ìʧ uEÓ®~8²ž�D­[ù.a••’ûQX¥Æ:pè³ôÊ«r?ê³ŒË öšá3³î1Êý g¸�{Q‡à•ÖédîªÅôkh÷ʴˆð)O<@•Å@\Ȩ,<S-áUâGåZµ`=ÀÈÖ§)ñ£þmj°Þú;@G§¥GÊû(£S¥cg‹ªñºr{P�7T¿94€‰6ôŒ7›ˆ@Ê�“¥1,ŠÈ•Vð‚÷ NCØôl´šˆ(é£ÀpÝbRR¸Æ s­F|P¥ÈÂ*R Ki(cÇÊú(vœêUv¢¡h²Z¹"Y‚9K—'ª]:±³ÚUw-סø²ëÉ ‹V#he5�]QzZq.«]«W°�pÌÐzƒjJjkôÏk[á£nŠJ#ÓÖ1�O­|„ð€ºTM×ÉGX †˜=�в°‰Ì<h©!׃–âO%�7Z®¥Ê�- ÛÌl�–K#À- š0¤€–È=�Qo´,hEC•Ð�–H>�™o´”ç’”^hIçs;´,èVCx¡%ÕÎ-e‰('P´¤bÓ- ºÙÔæÐ’ÊkdLo´6FJp£eFÚÓ- Þx´ÌH; cz¡%ËäpÑ7Zfd�0½Ð’Åv 7ZÒëÜ-e«+!¸Ñ’ÂväKo´,Mü-©�g¾ÔÐR¬ÎVþw¡%eöH—ÞhYÐX§8´‡“tù eA¯ð�-ec‘.´d¹‰ï…–²ƒI—Z²âŽ ÐÐ’5H—ÞhYП‡ ðBKÖ2 ]z£e©UùÀ�–¬‰@¾ôFËÂ&>-YZ�|é�–rߙb"I—Zvú-ø@—Z²àn‡–b±·–¯\hÉš;êû -Yw„酖æÊn´dý 2¦7Z6 Ú-Y3ªCKq²RÀ -YMƒ—- š �Üh)˜ÈýqÐRæÁZfT,‡–}‡vuh™Q°(·ë eA­ïÜ-Yl$÷ë eas¢æÐ’Kré7ZŠÇ¤œáÂKJHFuxYØ¿h8¼¤-Žo¼¯”5b/©h©/ {̓—ÔÅȇn¼”»·yÝ7^R^ƒœê�—…��¶ÃK–!}{ã¥xãY)à…—ÔúÈ:9xY’æænĤdÁÕ1ÅŠT%�bRzÔfRšRŠÃL*˜ê=˜ m äS7fR %î0=—vs˜IAÒ¥3·V;Ìd1!ã¸7fnTMz̤Àkn�™rÜì0“:±Ñf¢e:̤ެÔD)Ju¨©}in.«½¦Œý${oŽËtÖ]hþæ[Ÿª2¿>ðªÍîö4ú‚ ^-¬Îã¼úV»ÁÕÅr™ÌV¹j€µx Á`£u_N‘<0×¶ŠîF¨Ã5Öå ”¡€Æ*º—ÊœÆåÿÂ'R™q±;Œú–Š¡2ÿ>[}aj1vR:FšLÊ£í� ÁÔF#0frˆhëѵ»‰®švF�E¦·Ji±9DÚÈcÙu£,„T`øDÔ€­« ì3X𼚑ÈBš*%ÃúS·t’ÂnY¯¯ÎuÈbm´� ÞWßY×Ý‚tkÔÔi€äFm±í`½ú«�¼¸ .ÿwo.CJ0õˆÊòtX­k?£›¥­W'„pÀ‚AH-ö‹xÓ¼ÙšÏ�‘AƒÅjé†.hw6¦Vúh ;x0©¢NB@ÏJ}ôÂá €Ë2Ù&ÅC@ÏJ}¬CMR:˜¯54‰Œz/k©w<Xìs©õ®l–Âí|TðzÀƒÛÕ GÎbZ“aÍ{³Æž)…Ï*2^wß�A:Ã¥}w.:/Õ>ÖÚc’Âp-Cl"«öÑ?p µ¯ànzȨ¦2®Ú‘Ž¥\ôO�TªÊøj&çD¸\Í„Jµ(¡WDX¶G�Úæ, Ó_m‹§îWï6Ó«Ìx[Ÿ%¸ÜàÁc]íÔj3�ñÕ ž;hðº$±¶iµ�^6€œ‹¬’­mÐ —�bž hè ìŽ´Æåô¨ÊxXï(vóF9i¿š²m-@„OЭ/ƒ%«^-ŸØò@UÆÍ®qyð`PRë*�iÊé¢èe#v<®öRlÁ0¬ØG[b!v,ûC«ÙÊai­ëo BwàÁûêd%þiV•q1âSº“ëˆh‘"ý\Uñ©ˆÝAú[®®Yl�Â’SYb¼ôŠøˆ°ì-Rd\:ì p*1àÂØɺ7.“O-À‘û%?4†Õ(²û‡jŒõ&8À Më"× ŒÓ%ü�]jbï‡.Èòd‡.5i�.IÞºÔ¤}HºÀûbÕÈ….5Y?“ƒ.XÊò×A¹áÍD½º`G€>ÝèR¶õW9è‚,ï>è"ODt�óÐ¥lëþqÐÎXã�.e[÷�ƒ.ð¾Àot)Ûºt�÷Úx¡KÙÖüã  lXã�.²ÅºIz/t� LÍ¡KYÚýã  rúÛ¡‹ìöÑ®XãA—eí?ºÀõk<責ýÇA¸^ �]–µÿ8è× ¼ñ Ë²ö]ð�à�]VR÷AœY è2Á`<º@ÆÞxÐe"8<º@ÞxÐeŠ•QAï….(¨�o<è‚ÎTôÞ肺 ðƃ.h °ªGÔw€8tA\úA,¢âÑeÊê]°S@6%Ì] Ýq<è2¦ö :èçÄñ  V�.ð¡AotA› Õô^èW¼ñFö6l]2\zÐÆƒ.hº1ºd�âÑ…íºdX!�]ún&é5t¡N äéF6Hœ](÷g<èÒå9«¢×Ð%ƒ5�5tAcí�`è’A¾Àº =Êj]2H\ èÂF‹]2ªÀÀºtðŒáÐ%£š äé  {1‡.ÔæíâÑ¥-qßèB‰h£C—¡*î]2˜2x£Cl¢íÐ%ƒo÷ˆ/˽ìÚì7æñENK弆/ìçs¨ˆ’Q+Mg¾Ù÷óÍ·>E­Î°�òM­f>}?-}zwþÊ8\‰I.AÖÊqAÖZ€B¬…¼T>e*áð%&-EY+ÛÈYk•O™Ê8|‰ÉXQÖZ¦2_b²j”µŠ¼Ê8d­lGU>�"/k-K)‡Sù�‡‚¬•났µ�ˆ¼¬µ,e^åÓk”µ–¥ŒÃ«|ÆŒ²Ö²”qx•Ï*QÖÊÞw9¨|öˆ²Ö²”q8•€(ÈZÙ/ÈZ €(ÈZËVÆáT>@¢ ke ½ k-@¢ k-[‡Sù�‰‚¬µl¥G僖^ÖZ¶2§òYkÙÊ8œÊ8äe­5)áp*àP�µÖ¤Œã¨|€CAÖZ“2Ž£ò YkM$GåC�.ÈZkRÆqT>ÚKÌÉZkRÆq«|Ø‘,ÈZkRÆqT>ÚÙÌ©|jVÂqT>ìŽd­5+á8*vY ²Öš•p•{µYkÍ$GåÃ�L�µÖ¬„ã¨|´uœ—µÖ¬„ã¨|Ø‚.ÈZkVÂqT>ÚÊΩ|jQ¾qT>l‡d­µ(ß8*Ÿ ²ÖZ”r•OyYk-J:ŽÊ‡A™ k­âDYkAGƒ k­vYkAGƒ k­Ð‡YkYkeÓY/k-èhd­µ²ÿè|ÄÙiQÖZÙßÖËZ1U%ÊZkm=ÊZ— ²ÖÊ^ºNÖZX‹qË|*2hAÖZÐÒ ÈZ+özYkAKƒ ký�ðjÕxß¼¡aºxl›d­eh¸ï�^­}t€74lx�¯Ve™ð††àÕª<ÓÞÐ(æ<¶ƒ ²ÖB»ç�¯ÒêyY+ûÎÀcãY/k-´Á^ÖZ‹ÒLx´å^ÖZiÊ=༬µ¼¬•Ítƒ¬•Ítƒ¬µ¢¼¬µ%šðuðØ·7ÈZ ?ïe­5+Ñt€Çóð²Vö²V*‚¬µòr¼¬•Bƒ k­Y¹¦<ÜÞ k­Y¹¦<>%xl}ìe­…ÏÚËZ+µ—µ²Ër�µ²Ë²—µ®</k­I‰æ< B¼¬µ&%šð¨+ñ²Öš”gº:î'xìd­…›Ò^MJ3OêC¼¬•-ªƒ¬µ Ê$ÈZ ›Öû:ÔªY+»aY+@AÖZ¶²LWÇ!Q�µ–­,ÓÕq¹t€·•dº:ÔñY+{|YkA=P�µ6Èu¨+ ²Ö²È3}ÇQÖZ–M_Ç1s”µ–¥DÓ×qôe­…}ö�¬•´ k-(Ì ²Ö‚â­ k-K‰¦«ã@X�µ–©DÓÕq –,ÈZËT¦é›¬e­e*ÓôMäZܱŸ¿—µR+d­ÕÃAÖJÉa�µ–Yf”µ”ëy]k™d™¾‰�ú Õx;êZ ŠÙuþ<¤×?е*éu­pÐß&Ÿo¼ñ)êyÎ(c;Y=}q‘Ï]=õÜJÿõ,3‡v>Ü”¡�7îÔ‘”ÐÎGœúäÛáÓñŸ±��˜‘»Ô¤ìÏQÏZ–o™OÏ¿Çv>¥6Í8ÝH\韣ž(4žz²~ènÀ–ùËQOáз†z{êY“²?G=1Ð/;$®IÙŸ£ž˜ËS<õ¬YÙŸ£ž­h¾éF⊈`èæSå‰ÙxßwóaFwxêY³’?G=Qg¶<õ$î†n>Äæí‘¸feŽzbPòÔ³"îºùˆ«P,ÕfH\¿ Ý|J/ÃÏ À1ÊÿõD¡™oçS‹Ò?G=Qg6<õä€Ð·“|;ºZ¡�ݱÐΧå‡zö=c;ŸZ”�ê‰iD¡�O­äŽz•8ꉨhçS†jõ¬Jÿ£Ì,´ó©UÙŸCb”™ùv>t­C;ºß¡�OEð5´ó)˜{ÚùTäUB;1&)¶ó©�ìÏ!ñ4¡Ä¡žMÙŸCâi‚‹C=›²?‡ÄÓ„‡zB‹špB‚oçSñ£¡�£V¡�OmÊþOÓ£êÙ”ýy$6]ËM=»’¿€Ä5¶ó©�"´@=1«)´óÁ …ØÎ‡ÃB;Ÿ 5BhçS–‰~õìÊþ/êÙå):$^¦?:ij+ýsH¼MÇtˆçPúç�x›êOˆ|;Ÿb•‡zBŒÚù”mÚ¬C=!Fí|Ê6�סžÏ€WÇ¥Á¸O£¦ŽzŽKÊq�O£¯ŽzŽKr�Oƒ¸Žzö[YrQOJ®õì—>妞ׇv>كзþ£oçSÑë4´ó)ˆÖÀ«]y¯‹µ¶ÛùÔ®´7ÄZglçS;i¯�µæÛùT²C;ŸB�] ž��à©'úô…v>µ)ïuÔÞ£oçS›ò^G=¡ í|jSÞë¨'ˆ¡�Om<ÜSO(C;ŸÚø³žzBÚùÔªÄ×QO*+õ¬J|õk„v>b¢WhçS ó í|*Z‡v>jÑÐΧ²5²§žÐœ†v>µ*ëuÔ“ÚUO=«Ò^G=!�õí|jQÖë¨'”´¾�OEåFhç#&oÆv>µ(ë=Ô²^ßΧ%½ŽzBÚùÔBÖë¨'4ÆÃSÏŠ¢–ÐΧPªì©g-J{õ„ä¹zêY³ò^G=!�.ðjVÞë¨'¦¸&O=+J‡C7Ÿ÷öÔ³¢v8tó)�ƒOO=k&ïuÔ¢òá©gÍÊ{õ¤8ÝSÏš•÷:ê �{õ€WQVå»ùèä‹§žÅY¡›�8Ô›êÔðjRÞë¨'‚ŽÛSÏš”÷:êIù¿§ž”¬„n>eÃSOJ_B7Ÿ‚rk¥‚&4ó)(i¨ž|R‰šùû!ïõ�§¼×‘ϲSèæS8.ãPO„˜w�€·b7Ÿ‚âá¨çVÚûD=‘ôÄSÇk½I=ß~ëäÓ}€¡Æv͈ǟF7혛|bœ}Ì{bvŽÏ{Ö¢ôÏ‘OŒª yÏŠØNÌ{v”ExòY Õãž|v›�|ÈgQþçÈ'ìQÈ{Òfż縊@oòYH�ùWèM>«ªÇù6jù&Ÿ•òqO>Gk1ïY«ò?G>‡Nc>ä³*ÿsäs\E 7ù¬ÊÿùWèM>+õãž|N”�ò‰»òžÓ†:òÙ”þ9ò9ËŽyÏÚ”þ9ò9­ô�ϦüÏ‘Ïi¥ ‡|6 È=ùœ6ú�ÏF¹'Ÿó*½ÉgSxÈçºjA/òÙ”�:ò¹®ZЛ|ve€Ž|.­=ä³+tä½�cÞ³+<äsY)è!Ÿ])à!Ÿëª½Ég'täs]cªoò ?4æ=×Þ1ïÙ•�º0ð5Éú&ŸCùŸkè!ŸCùŸ[è!Ÿ¸%1À1ï‰[óžÛfbò9Èÿ|xÕ§¼çPþçÃÀW!èM>‡ò?‡Åé*½É'îJÈ{Ö¤£µùÄ] yÏJÙ` ŸSùŸÃâdã·ùœÊÿS9èÉçTú°¸<å=Ñ8ä=+…ƒ�|â¶„¼gÍ6Æû�OÜ–�÷¬ÙjAù\Ê�g«=äs‘:,ÎV zèçR è°8[1衟K)àÁbF®bÞsi¹Ð�Å‚T¾³^]Vqtcq-W-èM>·U.ÝX\‹M¿±øÀ«Kƒ¢ð4nêÈçÒØª¼¬ñWG>×%й/kבÏõ,ô©¹Ï§¼çºC7àåVŸòžÈ„¼gEþ ä=‘>yÏŠôAÌ{Ne¾ð²Îmväs*ñ ÑÖñ”÷œ$¾>Úʺ?O>‘?yOH•ŸòžÈ„¼gM:ŽÚ‘Ï©Ì×ò!ï9•ù:ÀK,Šôäs(óu€—X\éÉ'1ï¹µDÓ‘O4 �yOËcÞs(õõBVŒzò9”úz¡ OùÊ|�Ї嫞|¢}TÌ{n-�uäí£BÞsë„rG>»ò^G> rùìJ|ù\¬ëuä³+ïuäå!ï‰Þ£1ï¹tèº#Ÿ]yï!Ÿ‹ÅÊŽ|v¥½Ž|.ïîÈg'ïuäs¥óžõ·1ï9u�¼#ŸM‰¯#Ÿ¨ yÏÚ”ù:ò99³Þ‘ϦÌבOÔ�‡¼gE먘÷DçÑ�÷¬hóž3ï˜÷¬�ÌבOABÞ“b‘˜÷D‘OÈ{ÖªÌבO …¼'…+!ï mKÈ{RÿóžÐÈ„¼'u41ï ­MÈ{RŽóž�센'e=1ïi*TxE©¯#Ÿ�²:¸+à½�zšÖÁ´J1ïIY­§žÔ<ż'幎zR9òž&ò €·žòž&ö€§´7’Ï@%ÿCÃyQ‡¼8.¢6œ÷/úí7ß}÷ö|^\׃ÝJ?œÎû‘÷"Å’Û{BŸ`P\÷ î”EÚë÷çõȆä<z\µ“•=I1‚´Îk©Ž)‹¸�ƒÉÑ·”n1è§ó¥¨yP6Ý8v1cG·zí ü Êu§ŽüAB$÷k³b+¦Êß•Ãf´ÕƒÙx$³(�”ƒm63-4A: ^²ÜËÔ­o¡;pTÞ•«¤õc�á+ö�óA†0Dõ­·>ñxî°3S>M�ô…¥ ´;£T¡kÇ”­kŽÜ«N�˜T»lºz|ÈËAÁµkÖgÃ>àØâˆ¸³ƒs·ÑÚ, ©œ0Tlfžóˆ+è1ƒ�ðiã™[�l ›ú°õѰ37v2Zµð õ‚!�Å£aÛmŽ�B¿L´ÛÆ‚i:.ªë³aOm\;J8ØÚ O»ý ˆÌ~Ùì��F—uðú´kPâð0í…ÍÞÕ˜%6{¢…“51ª:SËJ'„-mŽŽ¾I{ ߇ũ3ØÄFÑoÙEYé²!X~…éMcÚ„xV,è„ÎmãÕFåh¦�N[6‚­meÑÕ&{¡Z ?�ÀŒ^,«6K*×Ì8=ѾÖ5» &\i¿Í+ì)\/…Ø€0ÀÊoÚ°Ixèƒ71�5_³È€L�ݦ–�™EaIÇ«¶ÂXt5·ÍuM•,�-<lÐðÄ B]%8ˆÅhÐaÃÜ€í{[¯¹­hx‚Zvh?j¸“‘§v�HdØ ¥‚M{_/�9¬ï[• š¦+žܦ�iËf²‰�”Z¯ásðÁ˜Á+Éúé±ËˆÐ!´ÈÐù~ðö€pGÒ¯¢ g Ü ,d‰?ÒŠüÍ·>e:θ0ó=‹ÃçöÝøÁ/±ØO¨òU»þêtëªõ1Ø2#Ç8)Q��#w­IÁÖCÝ"-|Õ5?ï‘Ý´=ØÁ™É\Ü%mM…ñð.–VÙÀ4z24©®0‹F#©í�A™ðá 4ÓÙŽ ƒF£¨ñÙè" ®]U4l�»i4¬Zæ­ŠcAsžuô�†u0ÊÛÕøÀLö­­©´2ˆÁRÙ1­ú ævÁŽª�ˆ4‹.îUð„‘œ”«à)C-@ÑAN6'ã6©’¸Š«|TR,+ãBcj1m�ø¤J¢_åb¹ mXv•‹†Uøa…iœ�‰ÞhV—$§¸�ru®/jAúf_-�ËÈ»S¨2¬ØŽÀ±Ðñmr>T¨J³º>Ž¥dåÐU×—‘1O4Ŧ`zà­–f¤Ã+m†U+²Pž`ûjn�IÏ,Âf{j!ðþµì .ßæ¨ìyÏ”ææ†¡¾šv`N3+K÷5%gqsSümíAµtÈçdë‹Â½M�¹u"Ù–¾hVÄÊ�²1¨g×"Ö\Tˆ.®Ãš½Ð7¥tÞú«4MÉ,æÞVÃ[�8Ä`å�Œ0øð�OY�ëp.Ët}q�0XùX ¹ŒéäulÈ™Ì×0³Á‰¿ð#ŽÙ�j&o68ÎWu› „¿«7œÖ;¦7mg6¸¹�ÙàL;o68ßPî©3Xç͆,9Ô%{³��sófCV.7·3Ð>Lo6Øçåc6à)¥`6Ðò³�Pp fâÃÌÇ¿³aáöfƒE¥Ë› t—,Îl°ž.³�Ö‘Ý› Öʵ`6 ö[Çl°"w³�–�É› Ö¸¥`6Ðαz³Á¶êÍôwÛ Ö4wo6€Û› –O¯`6Ðc±x³Áš²Ì(ö`6àȶ`6 y›ÁlÀ“�Ál ña f£Â¢£�–†5 Î FB´Œ‡�£ÜØÁh@ˆ¶>0Ç“Á†Ei>ûö{Ÿ2çÚ˜ån?+^Ígõ˜Ó~¶pd¨¶ÏcË—Dožm0Dÿ@cRSú˜1úÞ<EÝ`pobáCÙ#õÍô6ö5æ½rØ*ç¨æ¦ÝQСíA¿Õ¶WgÙ5\ä5ôkà�# Q¯éõ•#d‹“u-¯ŸZ�kû‚Ó‹³U­ÊVgcÚxb¶ ë:å=e+Û\t6zÛ×þB¨ûAöP¬"ssYE¦mÏ8î÷Ab�ëáx©a¾æÛs´0§çnç«úÃI³9—ì°É�»ú=à`KëÁõk8.ùsn…�`rCëÎuƒ¡}@AS±[j4ȵ»ŽKN6Þž ‡,6óÕ©ÅöÒ[èçŠÙÈZÉñžZ¶oû ¹+´ÕÁfòÂíÒÙЊC;ç=«f=L­Õ�î0Ôâ¤m1YZ¿†#7µñ�í04N±ÖïA›­®=¬ûafΠq^¶¦á‹ªXE«MuÚ9F…¨Õ€+[ŠvŽ˜6ï‘ÑþÆ!àú5‹Á–Û,ò+Ç�k¢>k¨ŒUÈÚh¹0J_9ÚüÖ×ÒÙ@ö€‡tà+§¨[¿‚É8k«‹íZÄ'a·Öm 5&̓˜iñv⩵WßÞ‚<5÷zûÍOØ÷>…}·÷¢¤ènîÅ£\{¯Œæûj·òªŸ…¡NX€÷:/Ã8d ƒ°˜³3ª:¬]Z`3rÁw¡æbüvYg6t˜¸”fa�‚±ÒH4ætõìL‰ìö°BÍ­óÑc@›®¡-\Eç…eaFb[/TkŠŠtâá`ÿ«ÅCÐw3ÖÞ_lâ GaP0L!1ib ÝÓv§ù˜Ñ¶¢Z„¡ln5dÞ¬ú…ÍJ©yÐ<6¢ælãÔ’µqE¯À‰fâ eŽ¢ÚñlaÀ’GWyù²0H™;©~Y�+¬CÒ0Ó»w‹²Ù"»= ƒ0Á¡þyµWn:´RU6LšdN@´FΓÝ2¨ºQÁ’6¸rHÔ¬wrÒY»Hø¨`ù!äöZ¹zWö¹€ÐMà �–Øy¦]m‘»e·‘, R�`•©Æ~µ`Fºá�ÞBa~m0«9µÙ3úŠvôíia&�B*¤s¬ø�ãk+"šÔ€‘Ð ©Z:¤�ÐŒhZ„ J¡È/šŠÑ}1H|h®�†\3r‡ãV_ùìºNÌk¶÷sÙÏo|j·_‡S³NÙ�¾¸Ê~&gÛ_e?©÷@C¨°4DÖ|‹4¤LÝ“‡†ÈU—@C¨Œ4Dp6EBÙ»§!²âW¤!T´"+~FR–îÉCCdÉ÷HC(F4D©‘†PihH)«DR¶îÉCCJÍ)Ò�ùiˆ,úiˆ¸_9ÒYô#Ò�štSÞ4DÖ|4DëŠ4¤´R# ‘Ó‘†È*Ìž†Ô¬[òÐ�ÒVŠ4¤æQ# ‘5¿" ‘ÕŸ ‘;<" ©E÷äMChî ©E·ä¡!bïk¤!â$�HCÄÞçHCjÕ=yhˆüiH…È3бø+Ò�Z)ƒ¸hˆ˜ûiH…r5ÐÙB-Ò� ‘l !4÷�†Tr? !ÎÄJÁ¹^>V+øÖ[Ÿ2ç4£ëlâÏ»Vp:ò-V}AOj£Bг`jÃðfƒº§ô,˜É°œÙ ¦)= ú®eo6*Ìø gA«áæÍµH!èY0(az³A�QztCKÞlPD‚žý«7PÅ gÁø‚îÍ@!èY0› =+z±„ gA²ô¬l´Ìšî† geo600À=+:¤„ gAS°ô¬è‚ž}p]г¢·IztñAÏŠÆ%!èIèAÏŠ¦$>èYЇ+=+Žx³�V²!èYÙK$˜ ô‰ AÏ ÿ3= šc… gEÖ<= Z¼† g…‚ží[Cг ýÃäAÏÊÎÁp ñjzVx !èYÑU5=+<ЂžÁ ­7šÑÝÿÜ]üéŸ?��_·Âûž×Ê?/…w©Ë™‹®™²Û\TL¹¼¬……0¨à¬Š‹©h× �÷޵@ݰ–¡]óZFg„ÃY ÔC¥Asa%5Œ”8s�‚_*BÖ5„f"™½¹€ð�ⓞmîËÔѽÎ\ T—­»Ë5Vgê˜`g.P‡KMͶîiT¯áÍôh¼—à Ȃç(g.P?K©PµÔ´Ü/æøœ¹@q,U÷ÙRÓ²à9ÜÊ™ T¾Rÿ´,7]�å=Æâ/ª¬”¸l¤°—·(W-f(¬ùíX ”¢R5¶§]2Ðbuo) Èâ¼�a9iYèlç,jH)†k–“®ð^[ñ¦îk­j*¬­)—;S�ÚOJü–¦¤‰b!œ¥€j›¡Ð²ìÆ^ÎPÀy…'MC¡_£sß�¡€÷J…ä¶œ4Áb5o( Lš—¥°g.xg)à½2ñÚ,)]á½¶ì-¼WEd‹¼,„:K3@HÖÌÝ-ʰ�¿è.üd9JNÊ~d«©,ç¯ß}ó—Çïþù›×?ýñ Eªä>¦Èùà=g�äíz+⯣ÌÑOe޾>ʜɄԥ̹^}{¤8ð8§ú½¦Õ™U['™$Uþviu¦*_ÞšUV«:3­ŽÎeyëpàmªô’ê`U-=WÓáÀá\VI§Z�­Â­ÃA³OózM«NÔT›oB\fShW­ÎVu‘Wæ|ø8¾Bn>x“^™óæ[ßã1Ý|ÕTÏQè´:8Î)tØ€•5»ƒJ�×w¬\ušvû·Íô,’åLº–/½Á²öÕ; rµÚÖTm슊Ö™J�×w¨ýÅ_ŒZ„\ÛB°É ÷@H«!3LÈcÆÝó!lPV€¿˜DV)<)ös̘àVœè僢kÖÐ,&2A®ÔÒ%‹ƒØ±C¡RGŽ»ÊìJ»¯8ú´& ™J9qo„ c±ɵ…›á{âçZQÚ-¬ÏXÞbXš—¾švÚ©Œ óˆq·>HÀB[�¿˜F¶Pû¶Æ�R�×wô QÕÊ@5Ž�'ŶÅÂ`ôŠ£Aðæ1Íz$ §¡sòVxœvåp¥0Hk[TÒ’L!-Âï8‚¡<$&¥:¯HÒêÄZ$4SÊPÞdbêx0L)šÖ2UÓ"àvÖÀWPÌÀntæx̦noqt¿²›Z5çamU³ï'‹'cveùƒ9Ó&S4”æ` Åü‹ÆÇ§UÜOS¢AG”9@£^CÓUNÏr: ÚtZüÐ!— Ój�´G*ŒCjvÍ(­{`ã±^ž3>V[øö[ßÇ~œB½’®CþyËtF¨1äŒ;_r±R,1Ìð¨Bù œ®ÁR÷pdxT¡4N×Úqðñˆe Å®f¸‡ï§š¾�ºÚ>ýÄbøU¡`®„;n1<«PŒ·á·•0jsÞB¥Ý†ó—ÂaxV¡Š.Ãû UtžUxÏØaxÏÀ`gÏàagÏÈ`˜U�àaœUÏÈ Dÿ+T®eøVqÊ|±,� GÈ#xèk΂q<<c‡¾žŒ³@Ãèw†}­çnıî†:°Ì°`˜ÙŽÐaœÙް`œÇŽÐa˜Çލ`œµ^ÇSqVA\0ÎQgè0ÌQG\0 �eè0ÌHg`0Ì?gè0Ì?g`0Ì7Gð0Î7g`�æ£ÙœœÃ Úqù Á„¤û,ímòÆßÇ|\ãÌÀêô:ªT22Ksæ)ß.Dî_ ý±2¸^è}E�eè}•ÁõB_+j,C_«Œ4–ïY%‹¿ÇžUÙ°Ð�J¾¥Æ†TT/t›¢Ê2t›ÊÈÍ…NRÔ:IeäøB›(N˜ m¢2(_hÅk¡Tç í�8?-´wb/ëм‰³_Có&ö©�™8Ù5tfbjßv‰CÍBÛ%ö—=•8±Ì÷TbïèÐ0‰ãV}Ã$f,B3$ Í�ØôÙ7:â ±ÐèˆýœC#Ž@ MŒØ«9t("ЄElĺq¶—ï>Ä&Ë¡³çv…ÎBl¡ºqèhè„|…·Œ ëÁø`°Œ ëÁø`°ˆ!†^>lZ¼‚õ�Êì¬Ç±Q°³êËG;o¾÷},Èùä+SËWª-q¤Š wxÌ-Ü))±ÖßÏ�†.çž]èi˜ ]¡Êñ3¡eõs››÷Œr¦äç=ËêGù½›åŒÂ©f9çÌîf57¨r¬æÜX6ï1cxɃ˜3ŠÑü”eTž•0eU%ŽP6YΡ\ ‹ÙÝ|dŒY~>2"†+Ì>î¦Ê9³�1³:…Áƨ¬a°1b†5-¯C‹3a"1¦xì0‘1ÃÆ £Æ²øqÃh�XÂ(á]N%Œ�ac‚1Zc†1Á.?Eª)Œ�†s›Âx_ÔÃÖ0Þþm�ã{·6Â<ã{áߎ0šw™.çÍ‹€áswQP\ÂÜ]ø·%ÌÔ]ªË9SuáÞúù”‹Ì03Þí ópÑÏ5…y¸ðnS˜u ÁH ³náÝÖ8ÇvkÓ×3Çv2��ù@}÷ÈÂÍøÐÒYƒªÝq&#jwÐÞç£Ú��¼ù=L�û(›ž”ËÔàÏ£áÑ£üˆ¾^XÔçGô!”ë†(��v?~aóÆï�Œ®0ZÑ÷Fë Ìqcó¶M݃�„ŒÒØœ¡EÉj¦ÎÐ"ÒáÆÝ•d5Sg øèö£ìJÒš©3l‚ëÕYÍÔ%4aÞ� ÊV3uÆÍI»ëF�e«™:#€V¢Ýuó}²ÕL�ù>«ÒðºÙ=Åj¦ÎìTŽ0õ­XÍԙ˳ ¯›ºS¬hêLÝÙ™–×Ïk»ª¦î‰:»Ñòžq9õªšº‡±¡Gìò³pªM]³p*p,ù)jÕj¦î97HVÄ´f5S÷ › $a>MÓš©{>ME�à&›5«™:“Í€d%N-³š©3µ,3¬èfÆt+™²™d@1DýUFÕ­^н׿»Øëwb�¢Óï|øÆ÷Ùñó®_,ËÕ/Ú‹[Ç£Õ‹–a›ºéÜ䘽bûÞ¥{ÎuGBê"¶æ]ºé\ç£Ü{¤'eqÓ¹®FyÕHOØ2öË-9GzR¶n:×�i�@OÊÖMçz !Å艬×ýÔŶìñÔÅ6é¦sM‚�­Šj“n:×�¨öúÔ}6é¦sí}êÊO½e“n:×»§¥ýÔ86ë®;�y�Ä‹]asÛO-_Û±åkÖmçG‰ìû¹Ýu®]R“±Wká®s­p�áŒ}X‹î:×cµÏýÔcµè®s T� ±�jÕm皣"sš£RfŸŽÑžŸV-Tôó4vyjjÚd©ûÖá%?5,mZ¨èÛ‚·ýÔŒ´]…Šwçµ9çS«Ñ¦…Їž> '΄l|úhñâÛo}Ÿ$XrEŒ˜œx zN£s:°%-Z<ö£†²F~z?uWƒ´?vWKZ³èìG…‡Îi™5‹Î~p x芖µfÑÙNø-ϲÖ,úfÚ{?õ3+Z³èì´ý±WYÑšEg? í��ÈŠÖ,:ûÁ±ÚÁ~­Ytöch]£³Uk�ýZ×èìGÕšEg?ÆØO½¿ªV-º®Ò{>5öji=uíšZØxìGÓªEg?&ë�ýhZ´èìÇÔÂFg?‹�ýXZ×èìG×¢E?-A �ýèZµF!̧X]«}se­l<ö™‘8³gka£³C‹�ýØZØèìÇ`(ÐY�­u�΂ -Zt 6RZOý¤æU´x·ÏHu>õ‹šZ´x,HMZØ-H°QÑó‘2Æ·Þø^Iô»œQVì)g´·ÂÇ—3ÖªÕ‹Ç~ŒPßÈOï'ÿch}£³U‹�ýZßèìGeñ¢³Së�ýhZ¼èìÇÔGg?š/:û1µÀÑÙ�¦Å‹¾×¡8:ûÑ´xÑÙ�¥ŽÎ~t-^töci�£³]‹�ýXZàèìG×âEg?¶8:û1´xÑÙ�]Ö“ÿ1´|ñØ�­ŽÎ~ ­^töc¯ý�¡å‹®ÃQb�£³S«]÷¢¤ŽÎ~LV/ºÎDI �ý˜Z½èÛìi…£³KËC?Ûñä,-_ô½jµÄñØx·Áÿ¨Y+�ýXZ½èÚü”œŸüqoC Ÿ–žü�­Õ‹¾=ÏXOþǾªOó�=¢ÿ!Ì|Fÿƒ(ó�ÿál�·â–MYÌ+_ØV‡²äÚ÷á|×ÿöbS endstream endobj 179 0 obj <</Type/XObject/Subtype/Form/BBox[0 0 359.999 201]/FormType 1/Matrix[1 0 0 1 0 0]/Resources 180 0 R/Length 29/Filter/FlateDecode>>stream xÚ+ä2T0�B™œË¥ï™k¡à’ÏÈ�Jx� endstream endobj 181 0 obj <</Font<</F40 37 0 R/F70 105 0 R/F39 35 0 R/F57 65 0 R/F38 34 0 R/F80 182 0 R>>/XObject<</Fm6 179 0 R>>/ProcSet[/PDF/Text]>> endobj 126 0 obj <</Type/Page/Contents[31 0 R 183 0 R 32 0 R]/Resources<</Font<</F40 37 0 R/F70 105 0 R/F39 35 0 R/F57 65 0 R/F38 34 0 R/F80 182 0 R/Xi11 1 0 R>>/XObject<</Fm6 179 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 121 0 R>> endobj 183 0 obj <</Length 4209/Filter/FlateDecode>>stream xÚ�ZK“ÛÆ¾ëWìŰJ„ð~$'[Ò&rÅr¢]ÇY�’°@�@­W¿>ýu÷€�«¤¶jÑÓ3Ìôôãëz7‡ïæï/¼«§Oÿ½ÿ&Í]ß÷o/tC?¿Ùž^üñÂ�3/æþ Åö%e¼º=%7ošÿ¦?ÛµÖ ×“¸§¡‘w“¹y’D7÷û›4¸‰sÏ “ôæ~wóѹ]E±SÎÝ*L³Z‡qäd]­c?wÞ”û•Ÿ9{#�õ€îØ[ÓËÈf/OðÇÙôC¯ƒŽÅ }æ2wìV¾GSÏ��b0;´y\}ºÿ‘ö±ö=7�sYÜÝPlW�ç|Þ÷?=ÍÄžÓÔò¼»{#ľé„޳¼ºM§;Îs7ÉRšš§|0›uoº/´�:Nœ¸^4ŽlºÏUSì\ OïÕm˜ßäôF�à�µÇn¤Dл$\~uG‚ bŽ…¤¾Ó�ÒAëÐ(û�Q@ /ÑN�‡r8ÊÂè3©›§ž�ÏøqàúIl—öëj�ÎþÿŽÿßÓßy;¾zYa�ºQ4n_¿¿1e}R…F ýIü€ŸN –ñ§â÷¦+‡ÇU;.}Ãó�™Ž$~*ê-Ž4Jœ�v¹Ã±G©StF‰ªo„êËSY�46fx0¦{ò)ZŽ8¤O мïŽÐr=­!J"ç äû`ðÿ 4‰Ž3òbèGNYË›ØÏǪN¿ò3œ[Ho]ÞŸ/)—DƒÌiÚ�vñ•µ5ÈY/I'néª„Ü•:¦n´³yIc[5¼I04KRxûçѳ�weØEÙ˹Æéä\Iïèœ={Le5Së™ ¤ž'Á¨×y’âÈw¶Í©¥“Ûé›…Ï­ý ¦U^©Ç¾¬ÌóßMÈ4âÐ~—Ž.¥Ùï!ÓÈKÉ"ж švHÏÌü¾©v<ÜwnË®h™¤ÃXæZtUgž­Ew&v@ÏÔùÍó‚Ê«œkJž²ÜžtsûXô2GQ�š~æ®9oì|Ön®Îïd†bW  ¢Õ7-¬»lê[ Õ|8–Û£ô•õ"`WJr¹ýåî­¾„uèbŽFеjÞ™mSãüÂ(rÞ½ú:‘­}åùH­Å‰èOEUñ¶¨Á¦AÏQaÆ=Þtq§’¾Ú]ÛM_BŽ��$3ç\ïLW=Šg¡QeP⪉h§¾ïõnœ¥3‹ß¤Ôó÷ÇrÏT}=›f*ò¢ÛÏÚÑÈòtU)³‰RböÈMýĺRòlfC§“‡$Ôú÷…cHÏq—ô:t“8³z}‹èid‚ r3GñO½p¯ÂXC11,»ýµN?‚ Q^bš‘³;w,rt�pf»¾Ÿ»Þó!p¾·ÈõòpÉW¸&²Ðõ¯Vwµ¢¹³Ží9–‡cõ(4éýn]Öƒ©ûòâ‚Ñ:…Ž7àýÙš-oœ}ל–„l- Óúu•Ñ©mfZø¡"Œ@O¹e½Ek ËÜÊûn[ bL�gâ¨0P”8d½d‰V›3: ^ô¡ƒ(§s[œ{ÞBÆ0‡Ÿ@Ôd¤�Ùi/ý$›F¨ñD ¨Ì•x"�4ÿÓ£ô3Šçö$·UÑóä û�<ÉrŽBýãÍ!ĉ ‹u…1ÁP`|ÓÚœê¾4[+Î2ŠRQØG²q‚ÁÖ †x=S˜‡¢ž`@OŘá�LZP�ò[ðÊ‚*OL�v®ˆè*‡ÞT{¡ÉwEY³ Ñ`2táÓIuv"|°w—¾7C@Ao9sŒ;á2–cjŠÐîËC]"8m‹z`£ f³ˆŠä�ù�@ð!� Cz)¹óóp =õgOyž{(†ž«¡l+³ŒwtÓëŒôþNøŸ�rËQ8ñf›A÷̧ƒÑè{²`"¿\ïl¾(GNòÝ‚ª‡¹‡#(‡Yô[¡G�yô[��ÌÉ yך,rêjЇ�˜AH€ ݘª4×c- #÷L09O¯¢~Y³m�.]éÂI2€ GhýÑì‚L£ÿ,ëóŸBþçöN;éPœß‚õ0h�©*F˜æy™¥]DMÝ%ê–0»dtÔ;â$¢ûÇ~0§^FbÆ%�[Uà$Ö'lw'䈿ƒ`®üF¸ÛbË[$ÖIâ91'�w 2Å’r>¡'A”Y`©L#è· ÚpÕÔæ¥Ð0Àæ<HC%åù{cĦ3J±/löhªö*ãì‘CY(9��@±³›"‘ª@yu‚Öð‚‘ÎîÇÉ/pE¾XWŸ¹~¨«IV”!.ù`*��x÷×UÃÙ-Ø…Ç™©…òúOd¤–p’ÒÞ�L× CäJs&Û�‡»RuFÓê hÒ™Eè&Š�GÿÒ™øaàäüô?VFä}’!DX>-jT%"ŒÐÅ@@Aãi\" ‡ræE�1èb8úlÔ¦è_ïÄ)F¾ÿ²ŠcäÇ��)”EÿÎÀe -î—Mßb˜¸‡O�ð‚ÔÆ% �ÉXŒûˆÓœ;a|®Å¨*³;@…£Åvë˜ÁZ0Þi‹VÎŒ:úá¼[”~ÉêA­oNF¨¢ ê¥ÁšG®�6Oiñ[W[šp…^ä|(~?¬�JËB'¨uοr±å7ü:R�ê¬ROÍoÒd0Ð%�]?80yYú6%S/ýƒôÓ¢¬__Hœª $â´™cá�<C,þVÌ��ûf«„¢fÉõ6ÄÓQÿl‰ ŠU•›®è…tE‹“âÓ ­y¡  çšqÌ]À,öÑ6êìŠzYÚ“»¦É/³Èƒ(‘:¨/�›¹ÞºíŒ/Œß¼ØëL…t'†™x^F½þ²VC“c ²{6ÌØË'B�=ë’AqI—D0²?·mÓ Âýjºf½mZlþñ™0÷ú’ÛèÛŠt•@<44öIÀå`6’?t#ÌÐÜéi<$v#) =x1úrÁ‘�zö¦Xö\”Òq±)0Å–3Å“Žeœk� ìn´gLr´è¨ÊS9²Ëš•~=«&ÚçMùn@‰%Q¨•Yëñh‰bšÕj˜Q—Ć«H3�6Èé!\J.¥ bà$Ê€ y´M_ʇ¹7cË%4˜=Zѽd©º•+Œí‘†PÚ6q¾ë…e\Êiꈚ»Òz®í¢§�‡Ø]WšáQŒïè9³aÙ€²p¼¬’~î‹J‚(ê¢züj¤ÁrA'Kp¹—ÆÇ0ùÄN’¢ã¹ƒJÊÀ£xáDù1tæ<ã�8F•õÅÏc:R�ÚôIéÁ€¢CÀ=œ;Í,ÁdýæËž<7•Ó.l|èàÆIÖÕíVàS�#T@º»…À ÂŒÓt©SÍ­z0óAÌ76O7ø¹Æ?³²Wv?­ê•0Uïið•$zég×EÏ�¡¼®ZÌåsb9Û®ÜXð4 µÚ>‘ ìl&•gÍëjý‘\!-ß" ¾Åd;#Ȳ=äFŸ7¡ý m±„ë)"’0� ZcòƒY« ©AÞ¬9¡BhþQX´Ê¡è†~IaÕH)Q½TUãI¶�ð�©à �-¹‰£�Æ“�Œ-& ŸfÍÂäÏ,U/žG®û=y™G¤yùh3È“�šš|™äYV(«2y*ºîQÆ”õú³”új:á…�öÈ .ù¢c7zÜ8£è“P%$p”† ¾4 ` à@ïŽg- ñš3qœK•äfÇ5Ö/™cT�àâeéÜOãÏ•ÖÖ%ïO.‰š° ŒTtÞb7KQ2"ïQl·†«ED÷CÓ#��è¶ÑØótd¬?Ôúè§¼Í(FÐìõ¥«s^/—ͼ„YˆûB#%qŽMY8�´h²¡±w�™"$ ·/R²?»b�õ’Vo«óÎ:‚²¾Š¢\U)kól^–ri‚'J5/{ÝÔ4'ƒ¢åd,vãH¯ é5FömÁ¥¤øb\ /:Fx´è”Û6í™ïÓÐлÏd” ôáÁ9È�ÅÃb~°3…^>¨ C{Àâôš–Q/ A¯Ä˃¾·;o*Ћ£S >»îÅK>¾<{?áÙê8—Ã8ò�É78�*uҲϋꓶÅ�ï|_!Ó?íKšä.,`æˆÃĪ\ƒ¨K£|‚Æ�Bñ“HŠƒ“ãBßņßÌ‚¹"_ÒZº'i-5/im=Ik#MkmjzÉ^¹‹6âJõ³ ï´F—rœ=s8¥çILUR_ÿr‡†BÞ¨�è`COË’ó„”\�ï±dŠü<·ØÌ#,|©ëaN@5ú‘eà-[AðÂ×9¹¥ÕÁkBø~¢bâ-öƒ°.¶d725ÇÉî1Xv/ü}Wœ–=™¢ðƒ”iÚÂb ›¨…�?ëÍFÎà�MÇÅê�ÜÈü¢ o0¨~F¿ºò«½pÐ’g0¢ÇÀEÓ"+]Û+Or‘;Órðb.�²~¹t+5«1»Œ¯€;ºZ¨wWs½-Œ/bˆ�éÏÅ2{7gÖ‘åËÆ›<½Žêù?àÕCbÓ+zoL” 9;ârO ¤È¥vÄß=¯AÞ“Ê1xZ9òä?E�ZÕÒ ½r• €%.�ˆs½§”¦Þ-cvö…yjX®×4`]×Ðɰ÷òÅñRníËéä’Š]]ÎÅ©²û K~0�z5r=T?Ñæ¥Q; ¿ƒ'ö"òÄ}óRrkI-#è'#DÏÙšé+ˆñú_¿,}ø<”•êôË« Ü¡ð9?ŽÝr™në³Fcy© >ô¿{°�ßnD±¬ŽŸ\‘#bÛìŒPЉ¸%ç³15ÀšW§�\8â'èݦ€—BRY)ÊÄÏ™ôšóÕm6ûmRîf—_�‡¡ýëj�&ΫWä Éô³â¡é0Èa‘I‘ tÀžüÛ«P’ç®—&—_i<½2'ÐBëˆ|¾9÷s›œ) §Ƿp«œ¸ñå—U÷GFjx©ÔŠU!Møb,Y .]Óœ¤CÜC–.^¯ÈµŒ|b&aAtcögóš-ii2ñLäÅ*ö…q¦DòÌ»�cÉjæ¬Æ_¤\ޏ8€[Üð&? _mX@MäÙŸT %\ÅFú$u™¾Ü�Q ½x©ëRØ=JÔ§°{2§¦{ÚþòŠÓÜÁÏ[IõÁ^hÞ/R†åˆOÒ8�k +þÔüýEoxG½% øŸ°y<±P/;-9þ¦¤‘rjν°nW)¹¦»{iušÅ4f$„¶Aýlÿ ú£i×ËwBÝN@á=~?yÞq™ŠÒ×ŸŠ®,/Jí*‰Ô¿rÿXPÖßE,4ì›äP.¦¾+Äc�`Q~Ä´3B‰–TÚ*5$´ôV½\ 3­Qå�©ªõÛŸ^¿\ ¸ïÍð}‹_˱�Ê�|çÝ? ¡Fñ7‰„ïïn…]@ú²ÄŽcñ^¿¿ÃOÈ|?L«3ÜzA%ZÚUN&žrÆz.w%A�…Áßp1à?wQùóûZ¹™.IX~àÅqš„îbEöíý‹ÿ@ù¥‰ endstream endobj 182 0 obj <</Type/Font/Subtype/Type1/BaseFont/MZCEPE+NimbusRomNo9L-Regu-Slant_167/FontDescriptor 184 0 R/FirstChar 2/LastChar 122/Widths 185 0 R/Encoding 44 0 R>> endobj 180 0 obj <</XObject<</Im8 175 0 R>>/ProcSet[/PDF]>> endobj 176 0 obj <</Producer(GPL Ghostscript 9.10)/CreationDate(Tue Sep 27 22:13:37 2016)/ModDate(D:20160927221437-04'00')/Title(diff-ops-web-server.eps)/Creator(gnuplot 4.6 patchlevel 4)/Subject(gnuplot plot)/Author(bharath)>> endobj 177 0 obj <</Type/ExtGState/OPM 1>> endobj 178 0 obj <</BaseFont/YUTIPD+Times-Roman/FontDescriptor 186 0 R/Type/Font/FirstChar 32/LastChar 121/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 0 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]/Encoding/WinAnsiEncoding/Subtype/Type1>> endobj 186 0 obj <</Type/FontDescriptor/FontName/YUTIPD+Times-Roman/FontBBox[0 -218 932 688]/Flags 34/Ascent 688/CapHeight 676/Descent -218/ItalicAngle 0/StemV 111/MissingWidth 500/XHeight 461/CharSet(/A/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/q/r/s/seven/six/space/t/three/two/u/y/zero)/FontFile3 187 0 R>> endobj 187 0 obj <</Filter/FlateDecode/Subtype/Type1C/Length 5740>>stream xœmXTSgß¿1$÷ºP‰·µ µV['®Šu ŽVT@dŠ CFØ„� a>Ì@ HØaÉÞâ•Öºj­ú¾]Ö.Ú¾}.}ø¾óÝ‹oÏûžóõ‡pŸ<ù�ßï÷ÿýÃÂ,¦a,k–kh„(vµ‹8Â?’y½ŠZÄ¢O£Þfù§Ý„çm̱’=ÌbƒYU‹­_XQ̃Ãs f.Æf±$Ú:{qTRLhpHœÍûÇ\Ü?X¹rÕþ³nË–-6I=±qņGÚ,£ÿH…‹£"D‘q[mìéÓáá¡'m‚Ó¢BbmüE�ÌÛÜüÃEa6ûBÃC£¢Ä 6ïÛ`³ÞÖvÝjúצáñ±6S‘Ûo±q´qLJûÇüÿ'†}¸;ÒCå½7f_ìþ¸ñû pL:y(ð°èH�S°KèQ×°cáîkl×­ß°qÓ‡6›í¶¼ÿÁ* [‚Á¶`N˜3öæ‚-ÃŽbË1Wì}ìö憭Àö`«0{l5æ…9`k°½ØZlf‹íÇÖa° Ø'ØFlæˆ}ˆÂcvØlf…ñ°ù‰½…-ÀX˜5ÆÇbÓ±Øll3ÝÌa�XQ¬ái;¦ °mÙg,Zdr„œ6î<n—Â7àˆ@âÂtrºnú�3¼f<žy`¦yÖ»³T³¨Ù·,=-ûçxÌ©Ÿ»mnëÜWóʬ–Zí´ª²zÍÛÍ�Ï™¯œÿÓüqòm²æ­9o¹¾UöÖc*Ór"˜ Gõމ5áf$Oä©u!P.uÃ:‘‹'•Ñ2e²w_½Œ¸w¢Þ\šWV Âéhàö¬,�ÒF9ÄHSݲ ,Â'PGBš!�ÌK*¨…—XOŸC‡çìrj Y˜§Ë)„¹Xæ%D98pQÉ=2 1àù²RÐNÀÓø™�êÒV@ ׆,D"8*¤žÌ¡@îU ,ÃLÂ_ù^Þí.=¸_ð×äz%…ª\“ùS)ML£óqœXA¢ ÷bV¹Ä™*)2q�ÀÚÿêá±} šL†¢Ös޵]’à72+e?"!d¡�Öh:¶þ�ô � :u¹wÎO*5À`¨ë„3áûÖß#›V¯ÊP ヤduhvPe+™ œ5ân…2�ßr… ÖpüäÆcSégù|ºj3µÞÌjü–}͆y”‰Þ²]‰hÑwË ´zý/(€ Ö~�æ bòùÕ•èmÄ9±W`Pmw‚P|>ù¸K|?4zW@ß…"*¤•I0BÝBY^³zøÆ¿\ÀK/¦Þ&‹s´ §µêãÂɸ«TNio™¦ã¼•ø®E ø”€ëð¶Sµê^@ÀßB øœ»÷«G}cŽù Çð´Üc ! W)®ØE6]n|0¼ˆíµËþ¸K{“€)³QÒA½è�­~§¸�µ€—ód‘À^©Ø™NðÂ%°‡ø½uôò�«_�À×�]/í¿�Xíèm@ .o±¢)N»éóã­dsIQÏËÉ¡g��õlhFÀæ�Ž{D:+7⤲¸E8•{™¼º\§¬ÌVµ/aòó<œ¤¶“> Å�ôÍóV" ´Y}¾þÕÈ¥ú3ýB䄃£I2:®a)T•ᮥ©E — ¾Wá{З$ˆÍP¨Sã%§”á DéMa� 7Àçtm.<x1Ú|ê�]sÈd ûz`q'�ôOã xqÔ+¸�s=æ‹ÞD× øh´éyY% ‚€�®ÁŸƒBoGÔ@YW�!SÉRqêq:Ì50†k.,lÀE\ÈÕ²ŠuD7¾Ë™4sy9üAš^ö“tô{å²=tôª·„/iVm7±=gk©…dY^qN) ꊓ}…(žÍA%Í�ߟ'5€+ŒÇ[úÎ6§«Kåò’4= j æÖS¨dœƒ—ð[<=×->Xá$¡‘záõÿÊ3„Š…É$��®Üš$ÛJ‡þzúâ¿ }ì?¡ïÅ��Š„¶ñùò2p�€‘ð=ü P!+ýˆ°¤øêj¥‰ZcRT[�…[î,à­‚·àM2.樸YY)šlš_ü4 ÎU¼Š¢øøüèEÛ\<ì�¶œ|á-9Õ–X Âù¾ab�Ðp}µD�P—R£¸B$#[=W«ËÏ¥«Ãs,eY54*ÒÌ •‹Æ>¹s6¶õH»aŸ‰Ëeu �ßÝl¼Òº¾†¸¼›ú£›Õ¹”Íì Oø‰Š’¸}™¥™¥©†”Â8àG ñ°ÃQöhórÈ…‡_™¿éô�6Ü—Á°¤+¸I\Uw˜¨á¦Â`N<7M’$O�j�œ—¤=að):AWò8z-G~4ìºì$¼¹ïµN/œ×ÖÝF@_\-Õ�–°Y}žšÕb¥‡éè ø°ˆr#y·—A‚«ËÎKhRÒR4j‘«ŸwrÁ{¡Ò¤iÒ‚Ìœ¬¼,‚wûºÈÝÜäwu¸³ö|«@Q’#UÇ~�¬áS!ìÂy/~áNQ÷Ã#ë�qxyœ E‘Ð ÷JJÆ´„5Kð1M‰ ØOõu³Z¹�ék³ßU¨ÐÓâàeäþwO(§¿»¹áŒ,ޏ˜¨�*äeVwŸÃ}tnTìY2�ë£*Â×h=Îk•⣙¥jàI %Äér¹**>\ˆÀ°Ó½B^|‚–Éñ3™e2àC |Û�û]å ‚¾>ŽÎsÌÏ:kj/9WÆgÈcœ°0² Ngˆ3еK¡ÜœùF»·ä%—�ûSáÞ/Ó?ϧÃ=+Á_¤—ªh�²¤œÔW\F(ëZ«Ë_Â÷¿XÀ NJåÊt â4eýBHg>½QVßîgtÄêÝ^Žq¦ÄšÚ*Su~vA¶V˜Uœ]´DCKu÷pCä1Áa­9$MõÅ'ÊCÁ)‚çáØï{½¿§êüuOï^P™Ð³è4¨*m뤡µ´V…§§$(cåâ”@„ˆO÷ ói”ô´ÃÙýÄT§’›;ΦÖM, K³u 4e•¦‚Dáê�ö¢MÖПN°¤ä‹B:Á þ8­Tþbë6¦wmF|;3jïð^_õ¯%�v]t�±| —kÄÙé@¦æÝˆwÏ‘ël@r˜g ] Ó­åE· øFd˜jn 5óSÖíç0ñŸl¸zb;™žë/‹J=®àG¦r’ñœ| DwqŠ¿p²qê)´‡Óà»pÎÎWË;{% Ü,º†ÚÏ?>»Y"¶÷Á-î'jêþ­Ç]Ô/o$*Šº÷�R‘<N& tM²ÄîEa›�ŠÀÁݲ²'tªmÿ­©¼‚¿TÕIBµágàƯ ÈçÔu‹ÓôB‹dÜ–ò”äŒì´L�pjD8,L+ËЃ>¨4hûr  �ãõª")ä¢lë¼TC„Ù³<˜q²8Gi„<:^"i %W] ÑJó¥4RcOµÄôÞ<s.½(„k¨Uú–]mŸAØ=ŠÓȪcSK -é½78Ö¶ŸBü×Kw¿h׫‚tÂÂø"qeRà×Wk.ïÚìå‘ ôôïÛôÖ“5�=Ð]ÞÜ.h¨564]%,ÿœýo\°ú©ÊqöćÔrÒ“î¶òM·imÞS@kó¦ÞÕë0ÈðÆQôd.J¦r9ÈKÂ}–®W‚=Ää ,•KìÒè÷)M—Ö€_j9ó'‡8e\¦ëçA95ÃÌjx Ÿ³áj.?Ï)Ç“²³@& ‚SifSŸÑ#Ç[¢>(å'ãE9… Åê�!²ÅE-Q%'iuÄ×Жm šÿp#œv¹Ó4tZx�¦¬Ðh”jURbŒ:v®OáÈ~ðèÂðq7!Í•)…ÉÖŠÉvC?CSJER58¸¦ë0êËteù� ³•¼3³,Ã�b’ƒCúŸ$) í”pû@Yj÷qbòÎóø»lã<=u˜Î—iÙmÙñvµ Ú‘Þ;ý"à×y%©SÓšu�€×¹©7Ô�1-í>UîÀO…ˆr�[$¸· âß?¼ ±^z W‘%�Ow\×A­X¿‘a´¼�úßvÖizí€\6üŸ ;E‹iƒã³ºÅö¢³pÄñ«ÀÒ>Î.†6Ðç§È®×„Ž·7·¯¤Km1“ÚÃ.z5¯h&pRìKtO‰‘ÆÄÅ…„œHr>àDeH³ûà©_�dƒqó½CDWßpõ%@¼ñË[ ¿™õ+ÝÆQ†sè�3blî¬*SGV Ê£KÕ€¨1VÖ´ûÖ9äå-ŒöM ÎÞJl {†nrÁ•Òžñîz­®ªð�€7¡%þÆeTwóŒ…üy&32ž€ýd}VEv=x .êúj¯µ´_Ÿƒ^ygTãÉþ�æÕ4**¸¼ šÉ©:õ_£(U½SóÆÛòdŒ‚ó©‹­¶.=¾t…“'Âå9¹qSÞ9ò Ü`‚ êà©®3Ë|&�5˜ÙÔ)ÊšìÚ�'Y^¢6¾È:JU ˆ5»ímDŸŸJ’’¤ié§"‰´˜&”*{Ü£N� Âí±ï÷×÷žt6W´€N0z¼ww" ­ÝrcŠA90µ¶5gk³ó€1KŸ]:@·¡¹¡ÕlhgAcz�¼…@šÉ…d«æiÚ0 ¾iU;ï Dœ Î�ý5Z}ïYaü޼jnl®—F” *CJ}@ q42Äçˆÿ�×´_Y ŒÔ¯L-ÇÇ¡‚©åØÄr#)ÊKÔEžF°Ðú¦¾©´µ¡¥ÞØ †@Ÿ¢#ºQÔcWÏÔ³‘Ë�àSuª¿†€Z¹‹| øz€Ó–Í¿œ SÐuÜÄåyLzS/IsIQ7œ7â·Ú3Á?X"ð‰I[™ÅX53 m&8{Üêñø‡ôDÿÚ3ëÎZWŽŒfzi®>§ðk§üª öjÕ>!jþqAªŽù4ˆó(˜@FÅʼnÅÕqæÆšêFs\M$mÿ/ÈÛãMê 5YÝ} å¿,à-¦ŽÒœHàfÄ©TRÚ^Ñ"[DðZË‚‚ŠÂù_é©È�ð$à¶ö…N÷DçêDÅŠ‚KðôÙ³Þñ´ôÄq›P§šËs4æ”–Ñ>è¡o’uv§v/‚øWO~}æzYß.ñï‰K½�£½’à6AsXYt¹í�§æõc/ ji¡�ÀÈÉL|¨RÙ1:;@[Œ|¹ž±EqÈÕI5hQËMƒ;8“×¹ih§–[ Y5FhA3pj¶3°žÑN‚MÒuËÑ¢U§ðN&л]f¦=ãô<1çd.�ü6>tÄ¡ :’—‘›™›™—É/Rç¥�t"%%M)�È`¤�ë›nô?‡VC7ëÆ†»Ÿ�6ñ ùe¹4‘‹ ÈOÎíÊ.É�r�š"—+é%ÔÒš²Ã3rEÊÈTçd~D*‡¥~jÂÈúmþO?›‚T) ÆKËŸéhU•1v¢<,§7<ì׈’#¢¼†ïÀ«6j(©EÓÁ¬Ÿ÷§ áSƶÓ[`m÷èŽv±‡m·ºµ½Åƒ`ì ¤X?>gérKrJsèYÑ¢“Ón4ŽÉŽétTÜ1_©—꯻T¤Þ'å[Né¾}žõò9td~ØFj ©Ï+b¾†¨/Nö¢BæÙÑlúŽî–++]lÃAn‘N«­«é«hDuÈ^!¢ÍÄQ•Ê…�kœwÉ‘U€QàM}­•ƒ€¸Re'DÁ8pIMuÖЇÄ<:7"WQ ºø0�‡3¯ípöˆv>&HºÚp ø±ÜΑxˆkr=$¡*WßòO•ib¶‰õ§ó =wÏ¥Wª@HH‹V‹Ñ<ô­5²†¯² Rª³óø)UiFPjktsèRš$ø•l]Êé­­[¬mPZJÍÒTfT0~¥ºL{.�>’%ÁÏ¥’:VÃc“§­ \Ú~l…'·r ܰLg†,8d<_R|AG×=OebÁy?“1Ñá‘u1�Íõu�ÍÑõÌ.¯Ÿ°ªgÕ¾†ú× ÐíHWà/ q>*B8@Óbµ¢éCG;|ÏÅŽ€s ¯¢½mäR'$�œM@[øZ ÈŒ&ŸÐ#^„D¾6›6ùþaÈ�d¿¾�þ…²»t�¡/Ù°Ÿ{l9r¼´ $??·R[‘OS¡ªX&dœÌ©Ô¸äYŠ<ÓŸic£ß–“¬gêƆ‚GTÍüæ%›÷IEA�‹"åà£T.ܾú®ëxÌÿù£±w]ÝãO ÂBeaR‡ªtëîÛ[nâù—ÍÛ}Öl^/Dû�3GI-dn¥'ó7׬à½'¢{ x·ájø%yÔdÕ¦ŒÆw¹€}Äf—OvG%jkƒ•R-ãüdò„�¾ø;cOê{†„C=õ#à&8—<ÙœX-)õ5Ò‹Ûí¡ºŽ‹ ¿8xy­§¯4,X%‹Ž?bȰî¹?Ðú) n ø:Ë‚cb„bÙþØ)�0ÁåŸQÛMVpàñޱ¼ï¨pz_�rö墛“Μƒð4ÚŠó~ƒ[ǹèÀg$Òp¡¾fü®¼ƒºò„'î°áÇÔSzpËA~nž¶ó+ë­,A�ž@WIÄE,¤¦Í[6Èâ§çgµtk=ˆ]8Þ'VÞµ=Qª­Ž„ÕÄéèµ$R®Œ Å>|~¯áÜYáà@ÕðÜ“ zžõíw©A3ª˜¨åfÊb�uú;˜ÿ5›r™ØE"®ÚY²Ça;œ …`cÆ>ÏNß‹±£´»™ûò{(€ó÷|�pß�ÈQØ�WB ˆÁuõ @]ä˳ö4;¦Þ»áØ+¸ö\‘ÙdV•7·1V&�þÄTuÿ‹:Fój’ËuBË+RûnUê/>Œà"¯Éï87¸0dbÉT]Ì–f«Ë�ö>€âÛ®�èq û(œüéB[/¸E<³¿¶±>:`û‰1ò÷µÞWÛ¾áŠ'û!ÎûüWo Œ…£Ù_IKÉûîµÁà(ñɉŸìôùÇgÕ½#C‚á1rýHð ¸LŒ ô|z«ÏwŸ‹ø„‹H�ž @F&S"¨î£,̬¦oÙWãIh¡¿d¼5üÛ£ëp.€‹¸e-œŽH4sý2´YÞûb—zË{.ÐfĶA«¢ xN� 1#E•"Ž Rb§÷C8óJùµªza…©®¤ÿØ„¶ i¯7±ÔÄ:C3í Í´ÝÞÑA>C–O1™×ñÁ?ßëñ®�?VZn½õSq[ÔÃØ›ªGàgð»þYèy´©ýÞñïK ÷Kv'ÚK>8ÓTß1x÷m?8ÀùA?l8]íÞ¢L¶~êØbÞU{ d'XÞUØE;FÛ;3­J3%ÿfm»ðü¾Dï�7[®ƒkÄÙ�®!±q¡^UX�¤½P›“S(àùåjÈYTT˜–&:$´L4Qn&èjâ6Íx1³©hÖ¬•³fcØÿ€÷™ endstream endobj 188 0 obj <</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R/F80 182 0 R>>/ProcSet[/PDF/Text]>> endobj 189 0 obj <</Type/Page/Contents[27 0 R 190 0 R 28 0 R]/Resources<</Font<</F38 34 0 R/F39 35 0 R/F40 37 0 R/F80 182 0 R/Xi12 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 191 0 R>> endobj 190 0 obj <</Length 4349/Filter/FlateDecode>>stream xÚÅZÛv£È’}¯¯Ð[¡µ,Š$¹ö›Êåkû6–kzN×錰Å2@ívýìÈH��wÏmÍ‹”ä�ÌÈ;"q&ÏgröÉÑÿ_>}9•ÑD;ö}wòð4 ÝI(Û‘áäa9ùaÝgOY=‘••iÖL{¸ìGch<‰í8péÙq$&3áÛ>þÕàâ·ÁˆÉ�™ï8Öµ=�ù®kÍÓ4kÛäOQlÝëÚ¯I]•T;Ö/ÓØµT½°¾VEÕ¼L…o½MßÒ=¾éQgU±}<¢·MD`ûq„•¨]ém ›'ë>iVùc=?´æºòa:V6u}ëwúIÊ<)U—å%÷¹Ö}ÿ1±ªmùŒŠ(Öu’®~Rïu†¯œOgRúV©&~¥‡ÀÂòñ¦ºÌ n|ÂDˤͫ²{®¹ã÷›‹ÿથ^ö�Õf�•­mzÝEIµ_N=gïL„kÇ"BWÕ实z¾U¥Y¶ÌËç <«z¢iµ«Œ+ÛõG®Êß'j!Ôá�Î"Ki!«2Ÿ©5Ìô +IÚdu\•*ððò� ;êWwDûu­Mò œ©ñ±ü§ëB¸ªIZó¶HJ…êx6?ân—Û2ãÕð|¼˜€gqà¤\ßé7CåyÓTi®$o!:ëáØŽ£gùá�ü dæøÖ|¨²g�’„úsµ¹Ãy²¬ª �Ê“ÖeRn“ú�[\êÆ²‰œIÙž::ŠWm»ùi: ëË—)Z\k¥æÅK ‡D-‚Ë•ÒÙgƒÌcaž× ýÝæ�Èv=÷`÷Ò¸ûK¼*tbë+ ‰�E®g�骳ü±QJ¹rWYçKÀÁs,Ýû«n¸N�‹¬˜�*/N�TÖ±uõd�7«)dúç[Ù¼äºÛ¥êá[7€ÆŸª.b FÝ]U´™îGêmÐ%Õû… U™Â(´$ÙÏwÅSƒCBI*NÝ õôeSåeKÏÂú§ã¸EÖ¼5m¶æ¤×†÷l’:) 2®ëàü6Ež*Ô4ÙØÓ–)…¾)¥¢^÷Ù¦ªñ"Ë¿šÏ¾ßsµÏLop\!BÒt¹šß\QÑ�åÛÔ9)©�NlÄŸðl? ; ¼‡^^6mÞn[�8RÁ¥çŠ4à÷/ÚBèy†‡ ¿À‰Ó�½` œRÚ> ;ĦgÄ&A‹Är ù&Ï+eÏaKúú;ZbB?¯£ˆÁã*û¿ì;1ØèaÑ&ÛG(˜: ët1Š×W㲺QvÝ�|Kòß]]µUZü´ØdiNXI{K ëþô˜›E$äÃà&k‡§«7ÏЯ_ئý2�ÔVUœÕÕ–l••‘T%Çþ‡6Oïâ‡o”ì¯$€�Æ=©hê ¦íº±¥«h€uà ОÚŒÏu�ûdÍÇ�¡ßtÝy^,³Çšõœ:wŠ9¯Þõ‰M ´~…í{A9€¿¼-¹Ny1r ›¬†ÒáMiÆ-ìÚë¼÷¶ÌMëjiT8j2®Õ´U ·Ä~°i“ô…T82q»‘ó‘ßuý®k ¿]i•ÑËé]1 qàXQ?^rÛ)½+/2~bþB`kÉ%(Ì;ð DC¸aß­¥P‚w©A9ùe öÍwàå0b¾xÀƒ0¹viGrϵӸyo.À�5Ìÿñ\·Ÿä¿\'uªeÁó �þ•KŸÉÀ±ÚŠ[`X³¤žú¾õ·|}`Ä=1H7À}­@ î ëìYºú¡ù¬ô!еýˆ\kѵ‘N¼ÒégÊ ë[ÖäÏ%·öÝóõ¸ Ü1? ^×�~\W#ž*š,­Ør�¬ÓqþÑfå2[r·}ŸDâ�7B÷À¼ƒ.­XÉ æW£‚1WJš–«¾m[Æw½([ #¬Rí@ù2ÐÛÚ¹MÕäÛ5žÚ/þ¯òrû‡ h� ¾²õ]dIÛÙQgì÷\?}ËÒlýHWCï‘´qŠÐÉäé*!ÿíù1iå2O[E- �¥�!·@t=ñQmÉ+bNÏc¯ó,¢(Æ#éÅÖI²®Ê’Ë×é5¸$£�ž«©«AˆA]ªåÊ–·o&I¿æ0:`¡:!ZÐs ª³äºŸÉfvsÁ{ÞíŒ*½ìÁlþÄ€~`0]Ô ; –¢ño  tÐFÅ!¾Pèô(¡!%¹ÝdlæZö‚ª'a¾1í¾SCÁ[JéY롲Q#Y¼ÛÅ· ~"ÐŒ˜=º¶+öc/¤3(»�ëöÁ2 Ù~\KÀ<îðz£)aåcÜ�Yd¦îÐÁ¬ˆ ÖqU?f­ÍþàBW.ø—MÆêDðOÒrg�Ëœ+^¬ ´èe¸‹lÓî­|Œo†Â†C§›�þkɳÌZ]=¯Û<…aÓ�ÒÇ„‘ZRb"–cÜÒu¤ ªu ½x”\z¾ ¹•JgQ+öB4©ÔY›q îÀóÉ\ÂèŽ'úÿ뼚EtzL’Šà%o$n’�'T�Ì|oô¹ûÉj dTé 8e‚Ðk‡‰\ª\„ ·¬,¯ÍA”QßýЖ®7Êvh ü3?ƒ ç%bà‚+µW ¢çì{˜yàHÈwY�pXw¤uzÒÑJ[Àï³MHIF/&løp"A4ð"²ËDЫDL™­Âºó�“D:xøZ�,r´áY×J‰!6;Qü=›£·ž¼ úƒ|„+?ÅÀŽÙA«ól p@*°n¥bno8}Ò›X„€Šµ·ðÇtTf慠Ú�(<©÷ Ø'…Ê%ʤNÒLžÍÛOгÀ¤à1N6û Þ 5üõõ• køÎ� ºë²Jux©gšõ*Ýö\�PëÜ/óšyòö�Ö„ )ìÐ�GS%¾´¥<´·Âœò<ù£õHѽáâÌ�7ÊÞÿ—œöybgT5›ô>–c <¯äC–R ËœV#ëô�^QÆEŒ"J çQ=ƒÞl‰yñÚÓj=اzK'!Ï>LS :±ìó—ܰ{1¶ùгcq¸usN�BéyÖÙ*[sz‚Î7!R)Aoλæê1‡I…½yR-QGe?CœPù*ã|u€Ðƒr–cZ}VUÏÊ1@÷yï\îÆؑc¯k;a<ñbñâŸ#^—H G¼½zaÛˆ"£ÝUÄ|*Á‹®a0½!ÿó4ÿÃ+ùŸ·ãêá®ÎË4Á3òA¢y‹ÛŲÀúìÈ–ç…¶ïìG·^Ô» é*wáIÝ‚ e& C‹ƒÂÒtËÍ?Tî„ÉÓLO;XÒmÚVûÜIêÈwN V xçâìön1ê8 úŽ×áΜ/;ψÖc�,øyREKŒÈõ!Žj©Vëm»ÒM—b–ò=š4ƯòlÙ²}"„°ô2#Êé…®ÎUí.,r»Ë´.@)›6ç΀tºªÊG¾†z6^~p"Þ�‡iªà4‹sÍð‚lÉ]´±û/ݪ¸ÂźŒ¥z-ý3ßAAÊÝòÃxUç’ÿo7ûnw¦_3Œ×ïqM{¸VÏ;$ÓÓç8‹W¼Èî`„µHT.›†^'E¥áÙõ,è´&YëXe�V„(᬴Ë: sÚ±O2RÔyŽÈD‘¬ öÕœ°#ºÃêÀ:Û.u�‚õüU7}­9õËnØh�WÛò…óýŽ×‘'â=ßrÅ´óe6ü3pÑmiçŠUü�H²Þ‹ÞLøb".c§#â3IW¡Y‘'�yAA»jdë«ì’ëTÖ,rÂÿƒ�œº[‡ßà�‹.·„Ju'[Õ/ͪÚèî%·œW-W(Â^mò´á†\[gìјïÑ÷$DY7¦nëTEHÆÄhágØÀ`̘3Úeo/D·OiHóˆÁjÌ7½÷¿i{{h›3‹g7ßyªóm½4†Æ® eê¶5 ÏåÖÄûšê©eæPw¤w…É÷Š<jÕ® £ ];ÚeÕÞoηOzsŠl brѬòçm]i.sÙÕ_oëä%Yçº^ß°£ó*¯+îrû†ØøhTKu 5°n›d½å"_D´`oêb…¨A›¯ó?™ CQq$‰bÇu¨œ¤iÖ4f~À×ó°2§ˆÝ:BÏ˼iëü‘Œ÷¶í*õ­EÎþh¦LØQÔíyþ¼â±w´ú¡7Ð]ctíë|¨ÆqµÞl•ƒàX8pbº:zÕwB»Jãe€/£±ûÐy™oM®Ò¿û–ãcRÂ#®Aw¹´8æZJRRþÌm;ð#Á~´G}´�Áaàì‡ÛÜ{° ö‹uæâäää¨ÓPxÌ¿Å�ÌI±›¿¸¸¬¶Š( n°$Žp®;<LñS'œ.í õ¸×=.Þöªq0ººOÑÃ/5N»Õ;Á›Ð}¢.ÉDß%cæ¹à”QæÖÎPù®®¤ó®ñ÷<áÂ4¢L9ÙhÈùtMÎÅ#Ùžh?Ð{Ïôf?ô)3}T„”e¦šóálÏ5Ø®ò&¡|Gå‰öTý â6�¨<HÞŽp|NåvV}Ä›PÄê RBb—r¬Hq|Ä=†;qpç0ð(ZŸyúÁÒþ7|M�qsêò ¶í©éî„»ïPÚó.ȶ £÷)Ôl}hmblþhÒUPÒWÝèï»Iלۢg#6îUÍwºÅ²«^VYS~&GØêšm¹ü«TVÓ*ôürÛ%R›MBVUøÒ¦DŒ"Š<ˆÈæ®Ùxé–Á »äD�-WI»ó"Wæ*p4B� «‹¾˜Ð]��f0æXh'X‰¥®Tj¹¬d£vOÏþnóªUI€ô�YõXÚ‘~Ä<'8À¦kΑé[±|É_{]'æY�©Ë-7äÏéPUUñ’Sp‚pT.'wK?H€KuwÃÎ�45Å«|¼0S#†O64~<ÍH}s%»›+Iš,¸Ôg{QÖÉo=ë_'¼�¿þž.Â\appJKxÿ™WhG¾x.îèçš.ù³úw­ëôgZÙ¶ÉéÚUAÿ�&u»Ñÿ—œ{îî´Ðkѵ艮2•ÂÂÉÞ]R?¶æèx¯,Æ4õµ]òX¿i«DäiÎWÞOŠ�« C7Úq<´tŸf©^êšè“KÛÄÑ<iËÝGI»,ï].”M’vTM�Æ8ôY�H¤¯´#ÍרèGû÷”‡JæD¶ç‰ýs p®äÉT†ê' åŒâP·Í·ÏÛ¦í¾&áчŸEzË�¸#yÊíš”�‚⛤NÞ»qdÕªkø™ÿ®³•úf3�DtNkUróüƒØÝ»sõTø­dx–6ϪØ}›CŠÕ¬jHÒ.®éÜLéõ¸#vvåC3‚*Àm]êsãÑ$¨oRŽ'†0�J á__„ K¸»Ï~xøõæ{2 r£/idè2HhQ_2¡ú¶m“×d$ÏÆûßI-뾵Š"Ú¿âÒ½ 숶ó÷ÀcN6ÞäëÇ"ûLºC_Epgço�5~<ž¨#UMó:¤²´ÝÖ™Éûš cúZñ©ÒwÇêí·»sµuwç1èetµùš¤gê®ö|òðé_ŸHg�‰˜xðƒBø(¶}H']úñ›3Y¢ ÓÚ2Ž&¯ªçz⢠ÅdñéßøûüÁf=Ù2RõbnéѪ¨žß /ó`Šþç/\[È`ðâ=V[ÿžëïÜ{r¸Y>™Sç�7Ê€1ÛWß{ `dN Þ<œ.fòÌ„‰€2é�‘³¶P!µâä#ފݘ—ÙýCÐÿ <¨?û endstream endobj 191 0 obj <</Type/Pages/Count 2/Parent 53 0 R/Kids[189 0 R 192 0 R]>> endobj 193 0 obj <</Font<</F39 35 0 R/F40 37 0 R/F80 182 0 R>>/ProcSet[/PDF/Text]>> endobj 192 0 obj <</Type/Page/Contents[7 0 R 194 0 R 8 0 R]/Resources<</Font<</F39 35 0 R/F40 37 0 R/F80 182 0 R/Xi13 1 0 R>>/ProcSet[/PDF/Text]>>/MediaBox[0 0 612 792]/Parent 191 0 R>> endobj 194 0 obj <</Length 3569/Filter/FlateDecode>>stream xÚ­ZK“Û6¾ûW¨j¡ª,�‚/ïIž‡ÇãxGãl6N #q‡"’²=þõéFƒ”Hƒ³®Ú\D°A‚@ã믛mflöê]_Þ>;» ÒYê§‘ˆf·÷³XÌbÎ|ijÛõì£÷QDÌÿ¸}Ó¿2û¸ó.Ô\0ïS¾ž/D(½÷Z5ú9µ—uY•¶¹Ëë¹džíy{ÈTCÍ_æóò¢Pxx7Zæ¡Ð{YçªÄOÎ÷Ã8�-8÷Ó0¤ù¼Ì›‡9gž¾«êÞbæ]çÙVéndèÝÀÍ®*×¶O•k”GÞ²mÍ6·7wÚ7Ÿ`ÃÑo·z¾�LxE^jUc›{­Ú[é¶›Ç¦Õ;¾Hà£?š Ÿ]Iv¢JHÞ‡o˜±ãŒ^ýñòò’†Q»5óXt¦³zÜí«&?ìàix¨U)¥w­š†$«¶ªç<ôªdcôb;ÌììSFøâí<žÎð�íµþ²**3T®Í>1XrÈ®W«[¸rZã�.Qä‡i·Âçô .Ôbf‘$>�p+CŸ…²ƒVì„Ör�·�ˆ žx7ê¿›9¬¯ÞæVb#xê-a7›- _é­*sØ ‘rÀb}_Õ;UfzF‹�´�ÊøÒê²ÉQ½A�j¾§®C£kj5{c™ÎFLJ†ÏF"˜À@ø)‹{ „ý~ÛŽ©ý8÷~Æ qá-÷û"×kžW»ý¡ÍË�c7¸>ú¯ùôÆ-ðüú9 v­ê¬›ƒ}|0×îõì^âܽw¹±ÏªP„P,`Û-LEŠÔ{›7- QÉx½-Së·6æ½’QÜtHÆDã&o'·u¯6‘Šk ®…û¤§„ÍÐS$QOaè'iЩiÛ¶ûæÅ|GÞÙÙÆ€ÿv{¸C½ÁÄyäeÕÎöùNÙy÷9ÈÏHµö ƒÉ]å…îVóíÞÉÀg"=nÝp"éG,ï@êÜ�WÅ>Rß7®¥Ã@<NO—>\ùçÏŸçQh—½¡‘æa'@¶I¼Í™cþIè§"˜š?™Ï™° ìæ\ÀÕ<1аù!{ ²Z`ÐÛûZ5y 7!€ëÕû«Õ ’/éÒlU­×‹5úŒo Ñ$zƒ#ƒµ9÷ôŽn�E¨Q(Z·y,D4X4½iÉð@Oó@hÕó¼bèU‹#$fwOÐ’i½†O4ˆdIœ$Ó¢ƒBÁ�ÎL M EV—ï~ü•ž;¯Ê{ظ öt™ÙW ¿õ¯Úå�ˆ]�D�ž;N}ÈÈ]¤ÜèÕœCçruK¢˜˜pŠˆ''î#�Ÿˆ6lGÿ]ˆÈjÉ>=d+)Ñ뀡^W%l‚¡óGD°].±zx£Êƒªñ‰� Ÿš�Ö°½lšÊé³\µà¾‹îõÏ{]®õú°·^ò8r™Âe­<€IDa§¡�qVÝ€Ót¨9})ä”e ûA’Ž-S¸£>ãR"@‡]ã†Ò{c…?¹º‹÷ÐY’½òØ»îÞSàÙKU+ü5vÞåýâIëÌr]Äe’K†¸sè¡÷ w?ì냳Tz™ÊL$bˆ�P»~DÁ-ɱÓÍ¡$#ÿTVkkï9"ë�a€±ò©ˆ�q_Dbdå'– ƒKCkÉÐXvØ×Úaø8•�Œ0ÏT�b6¶z‡Åé(^Ãø T[�ïÌ3c#Róì`2o¥&Äò4e>51œý>Ëœ Z}6ªÝå% ª´¼(×€“ZÁþ='ð¼U_v]7¥�ÚíUQäÏ'‚e¹®µÂ ?öÎ鲬!šËÀó‡¦Ñê`2Þe 1ä"»¯95__qàÅŽ�ñ 8­mã™$öÚ ¯‰—ÕÊ„© ú a oôâ 6_‹Ó¿ßeˆ8±VB@ÃFKο˜À]6òæ•’®càá{��sé� O�Ä|”t¤Í8FNïÑsŒN-ò1–�‡‰CIºST(—�)­Ë�/�à¨/Loè]T‡L·­6âÐû7“íz}°Âs+���k¯Êiˆ!· Cà É®j+ãp„u¥ÐñÊ>ð^g†ò`²ê./ Ñ¡¾¼¤+m4~½Z¹tÞGÆ�Íõ(BÔ ¡,XðI:ÂA JàJ†Æ²¿TPÛRE´4Ö0]vÑ'°=ÅD.ÆI0`¢#J` ãø¹´+´{_äfW7Õ˜­ìxç1p±@XÑ“,Õ»¾Ð -ãÂ�ª«¯àùÖ˜kF0ê1¦§^ÜÇ�ÂŽà¨ÐÞöà›1†ò2íôï‰ðã£Ãø6G:ñ­ÉGÜçÉ(§hªC�é{ëü5…¥n#?8~ÊÚÛ•¾«OÃŽuÇ~*ùØüÜE¡_æâpTÐÆ-Fñ@àM…;ö©³CNVŠO¼:ì[…2–z?YÙ D¥¥“Vý�AèÕ˜ëÛ´±)»Dr À’~Së í.b! C [×èD»•U›2o(]F%Ü�âûZe-Û*v�½8̲�KúJArR)HN+RLÐ=|É{c}]µÎGû�‡8á$;;Ä”S€ sçiÇ3ÀÆÆ€¤/@h±ªšmµ·ï•ôL‹Æô«ýÐ1X»Ë3Kõ†ÕàêZ‰ Ò—2,¿UÔ<‡4LY1…õFŠc ý-x#HªåØÀã§Á Ä3^ÈG ¬D++³T šëVï‹>q�ßHwÀ…Û˜Ú@ª1‰[ÀM@U©üÎàsq�‰xM¨;C,C ª<&Qx¤#á™/îT IòÆw€nãvé\‰³L$ÕC9$µ:°}MÛ¨¾æ¥3ÆÂb@4,ñ$ÇÔø‹Èp»°=§)ûê�M°¯ßIÜî‚Ô[Ü�«ÙÒªþ„jTźqé#N ÉÙ©7û"ϰžÄ&X‘I|ZnK0 Âèº4ió]$-…yŸ45)H¸® �}.ƒ¡'°¡ØEwªóT Ç�µð‰Q‘Æ<�iŒm‚à «Hal2?ä ëÀ¸��p—žÞæåá •Ø­º)¶7ê^D¾�­� ïã^µ°ïæYv&iÂkn˜ÖÕ…z¤nBw†ºŒÿ‚<r­ÿ<h,‰H +c R a•¦KáÇ^X0hó'ê�Åîp)ågvi�q1•wÊ·×Ô^e$\È!Ö�¨¢�¯3Å~'³(HNl¤»¨†m&Þ‡rs€”¨4i¸�—V¾l�$Œ,$�²â. ¢•}xe;^U[Uèé D®¸Qª1 ƒQt® ª>krËç¶ÿâp±¤ÇÄ­(_Úþ—Õ¶VÎÓ›×�ëZQ ZÑåu¾Ù.n·uuØl!©!¿ŽlLÝ«Ž-¡Mtjý¿küÿ\Ü,ôe‹(ˆ0ÌmuÙ.–kÈ1›F¶ŽÀØÑÝ©�¦§Vãì)êëÓÙ—3˜/d4º3ëËñ|ÊørS7=Þ¾3 çRúA<ŽÃ]g�ÂgžR :íh@ºk]+³zžJˆ$€t^˜b[jø¡¡žOöÚG¸ßeà L‡Æ™ÞoÇÕù5•…@1!0_«›³ci%2‘ÀÉ~8|6ÂÙp�šTÐw˜&ó>YàŽ…d?ÒŽ»ˆ¶¬ ÐÒЪ«ÇÅÁ”@Fuˆ4òÞTT Ù…*s]4 ò×"�%.�jÒüîk�å/L¯!�4�¬À2*Œ6œ˜K±FLbGAÌáÕ`N†¼K�’íûƒ™ôE锹ÒE�ªVÜ”%ZéÍåé˰¥Efj?¸Ð ®ŒŸ€™¶ž„ã{gƒ) ³Ôû¹.€Cq±÷#Ë b¶Ö…À‰OÍ~9‘ÙÇ*Ë•»6òtµøwIìJùLŒb€¦•z§J³÷‘ÄC4�+z8FU|ŒêNزçhØy<¯Ž½““§‰°3dx€…g)ñéAZœ ì9ƒ°ª4|Âqê’LGÞ�”Ë‹žœ›Ù'ÎÍŒª.oŸýù �5›ñYK? “Y|™²t–íž}üƒÍÖÐ {&™Ì>›Gw3#C£˜­žý‹þø0XJ�‰n(i¤˜ÛD¦t|+ à¢ÿ†/&‰/ƒ`ðES7Àò¨æ]~Q»=Õ §骟�øÿÿiH<Ãé`�&gi\À±žô�‡ˆR_†#|»ët&‰ %QÔ¤ å�í{—kä÷ Bw½º}A½Kê,„1ÆËà�qÜØhZ•=LŸ&�‹Fní& ×cržˆ‰BÀ2¦ i8¢©ë§]]f¤÷ÝÌÈC'3Bû×óºïÓ´ ?@ÃÂS­˜Ùž•ýc;7¬dŸ–Ö†)vWôèʶ}¹ ì‰ð»9Ï]`û =gwÓfÇeN:‚Ê�Žÿ¸—}½o(, €cºN�j˜xê¸,eÁhEîrØKŸþëôÛö`ÿ�õ“•¼Í­À¢^z¯mÏ{ãáÚÖ�}:™XÎcˆ—ÐéUùÚ;ã“öAãÉãí»ªm ]j<B—’ ÍRÚS¬ÖWL«Ú©®Û,9.;’ÔZ�ëØ¬«EË©àBBú˜L"¢?Þà•V�•=®€f�·ÈnÛŠ—tûœžjHnÿ6×þÜÛÜÑŸ¢øÔ¨ cú¤{‡'Ý•üÀ’©soüÓTòm¡Ë"½²ÿ¤c˜*å` eÞ•½>¬–ýA KÜé!¸‰¿�ŠyÒã endstream endobj 44 0 obj <</Type/Encoding/Differences[2/fi/fl 33/exclam 35/numbersign 37/percent/ampersand/quoteright/parenleft/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon 65/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft 93/bracketright 97/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z 150/endash/emdash]>> 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 <</Length1 1632/Length2 9261/Length3 0/Length 10320/Filter/FlateDecode>>stream xÚ�·T”í6ŒtJ#È €4CŠtw7’ 0ÔÀÌHƒt#ÒÒÒÝ%-)Ý"J7¾ï{Îñœÿ_ëûÖ¬5s_»÷¾¯ýÌ =­š&›¸Ô ,u@°q²�’ÊÊòœ@�ÈÍraÓÓkAvàɱéuÀ08ê ð‡…$ B<Ȥ@ˆCe¨@á­€“ÀÉ'ÀùJ�p�¯ÿe… �¤@Î €2;@ê�†cÓKBÝ`+kÄCžŒæL�Îׯ_±þå·à æ €2a ¶Èh²hBÍ!`„Û…`²F 88\\\ØAöpv(ÌJ„‰àAX4Àp0ÌløÝ2@dþ§5vlz€–5þ·Bj‰pÁÀ€�Äì�pyë`†²4å•�ªŽ`‡¿�•þ6`ü3�';ç¿Ãýãý;Äá/g�¹9ÔÞäàq°XBìÀ�U%v„+‚�r°øm²ƒCüAÎ ˆÈìÁà¯ÒA�qu�è¡Ãúƒ›Ã Ž8;b÷»GŽßaÆ,í`! µ·; àØ¿ë“‚ÀÀæswãøçrm .ÿB– ËßmX¼uäÐv€8½ËKýcó Âþ�Ì Œ�ðù_qóóÀN�°«¹5ÇïZnŽà¿”œ¿Å=xy8B–m€½ –à‡l8È @ÀÞ‚½<þTü7ÂæäX@Ì�3°Äû?ÑÄ`Ë¿ñÃýà ®�àý8À߯ŸŒfu°sû�ù_WÌ¡"¯«¡®ÂòOËÿVJH@]lÜ\�6.^ €ÈÃxõpðúï8j È?uüá+ï` üö»Þ‡Aý«fçHÀøÏ†0þ;˜ ô�º`�ã˜näš?¼qþ?óý/—ÿ?šÿŽòeúÿV$óÖÎî/=ãßÿ=Èbçö�Åuß"Ö@ú° ÿkª þ{w•Á�·öÿ«•G€ÖAÜÁê�Òlœ<ì@ž¿å¸ Äl¡A˜[ÿM›¿åÚ¿Îâ�VƒÂ!¿1^@àÿè¶ÌÜöá1àæß*üaå]äo ~Xªÿ®CÚÁjñ{û¸xù�  ä†ýpùˆàÁù°¦`×¿Ø à`w€"\�={,¡0ìßýŠÿ�P¿E¡×Èìßèw}@N�øÈà°ür8¬þ€¼�Èð!²Ýð5€Ãþ?ð�zÀ‡DÐ?àC"Ç?àC"§? €ö|È ÿò8ÀW�Ž·Áÿš¢ù[ìaÌÑÿaÄÿÂ=ÐÀ`W°9öÜ4Ô\0À¦* å¢BœÒ…mkDí0éB�‹m$×Ñ#=n²£™ž6¯X$3×Í)clÓ®"át‘±<sì±YMSãÆsÆF#³cEcöaúþìÑd¬Ç9Õóiü¤�º Ï `=HjÔáX¢V=šôøž/«ºfc]H e^)¶¨´uT¦)‘Q½Öù¾®�h4ë×Úâ=!™¹nå¿aš¨’ò\Q¨í;Æ¥œ`µo ‘°›ús¸¯‚³ßÖOº ¡´`?•F¹Îböã›Ìçý"3Yb±}‹žâ¦„‹*•#ëÍ£}#ZƸŽWÖ¦q–œßÝ/© I$’`Y9Ûa Á4(õ}"±çp�®dˆ\çré:µ­Bp ¢ÛüdרêÍ[ÅDyƒÑÞ�FVåá»’Íï^µô­‘ΖAÈM/+7¥YÈÒ˜ö¼,ý³{éìÒÏ'u¹ ø“¬[´Dò_4ùèrsã9C’Ê´sÔ~ëÃÈÓ?ópç¹Ë>nk“`˜w*wˆ$Šp_­^ôLÉýxuÈÉñ¥Æ<¹2BÒÝÅ~í̳ÜuÍH©ÏšçUêÞbÏ{°:Cø>*� Éø´×IÎÞú¼ta£;äôY ò ¤B•¬â«_²á^h 7¶s¡oÄÕ¾ûí>r @۱ƭH�TPg¼ÝН/»YdŽõþ—HS¢ª��½8pèVƒ»nº‘™¤ß£�%›¬i“è5áZ äíÖ¨rܦª¾µñã{<?õ~ÿݘ¨ˆñÕ“ÆÌp¦‰JÊÉÜ–Ba_Löן¾¥íŸp[Q>=N~LcÐfBsov5!ý)A¥“»rÕë7ˆQw¤ûœæ€y³.=µst´ }#W�f ˆË¥?´à:jt‰Pi.��9•ò:ý‰¹�Ý£ÿ¸å ¦’ÓæM™¿UácôvN³¶Æ4…"�§i›ud�Ù;¦Ï.úþ‡æ @›¸ŸUzH¯Ü.¬°‰“¬)4ë³ÐÞy9Þ±�ïYN@×Ó&Ø=”v<î:»Ç;Ç«íÔ&‘`±òjfdwÏ„èx]{ýë!¦÷}É©AšïWàÜ£QQ¶Y¬Æf1)?Ý1A8ƒ�<&è{ÄhD‹×½#Wœ‡,có„�ð¿ëÖVq 8BÓ¤®ÓŠCQÚ\E,g䪯 hŒ´¤Ï>Û¤hô‡ys°\ãln’íR’–ìø7Ýõc«N2SÓåhuÎ}-êhë|-x²s´òðçxX7®œI^˜+F1/N ²¸�’bèE”¹ãÙžäªO¬¸ôˆ€œzÍø¶8#å¯G EÁ_§Î£…Cö,ë„~Ú(Þ¼Ÿ ³m°;[¦79±§3"H~½ÁÖퟵõĤ4øîéâe’Ö¨§ÇW_â§$Y¡ï§2dæ=Ì´Z‡Z,уÖ²J=B•Æ÷B::°ôÒ_o ä¯^�ÿ¨]õ%žß¬ÑÊší‡þÐpI™XÀ~– n<Äæ8 mÚ¡¦úLNæv}ÐðØ+ +±=¯—íßôü•Ï‘"`ÕòÊ«ƒh{,Ž©"ˆUScB/Þí ‘P¼†Ë&^Õ¸eÍ¿‰€¾7J;½)pÕCd2’#«¤ü“¤=te 8B_âõÑqá‰Å7k2‘0¢0 c©üŸb`õ‹ÇÝ({ ˆ…þ˜ñªX{­(¦#.„[�ªÊW¢§Qœ|}ý¬ïäeìy©¢ùî¶ 6ö‰ÈÍ—-è˜p.3q×Á+·\Ÿ¹ŽÄètÉÚ#T |Ÿ*Ÿt^u®7Üäéõ”ýBú²cœ÷æ:ò(|Œ&0å硈@ ÿ¥"•ý .#shíŒçø^ø�z–Üìì¶PnmÌüYNq®ÒÓðdV?Ô…¸ö©ò~7+smw˜3¯{QÞëü'™Ïù@-5„�Áú»)^Pø>qy)ú˜èT��4G`, qðux†�l%bBzïì~ˆ¸Ä,ëí ­ËéGVô¢º:µ{ùlʰѥ>O5#¡e¬u·•R×0CV÷=ÞµÉmèN·ÅÙT¡8ã)�@ç¹L>Y©^¼·gN5µV/ª¬ÂbÌÿ&8è[¡Ž§M éh¶3,&xÑ%‰ô¼Ë cÀŽ�}xùá2_t„<†v�ÔÒdrRˆA8n©Š©»üy£0³ðí%pé<:Ò–#¦Œ¡œ÷÷ËxáeíÔ,–o%ÛŠ’¾Î›"³ï<zCÀ·C6d"Ò“¶U>U´z=JÚê.>öEk'Vœ¥n�”ƒí®´ä¨úÆïÜR»ÁÚ½½÷7ð@qÔÅ´0h 7͈§  Ü(ys›Ò½ÑwI¥Œ!þiœì”6§Xm;ÇkdÁ¾1ùG{£2îqtùm>Ú³ŠÈ(v3–|®N«YÔXnØU.^•~rrÕÌôW fñ¶±å7ú•nPׯu6e?]sª4[“P Ýj™žˆ6eèìø)ÔQ<»Dg¡é§´f�¹/Y&Uú%ÎXÊ3/XR#+‘qO0Ñ·üúTFëTTV§ÊˆÖnÈö†6‚âYƾB¶LýìC-µ:ïYÎ;-r3%/‘^[¢ïäçÂê.Ùªw¯ÈxoB^P Äϰfk›�)©‰F×ö <Q‘,ÛÖT>›‚NáÍ‹Ä?&ì=ÙÂÝúÅÍ<cóB·+]j�'œîhÂó(ƒ¶^&le`(¬áîéî¼R¬ É;l õyºº¦„.ý~ÆYr2{ §âóòoËi”׬ Å|ÕëOL8¯r&¼]�8ÍûŸ¨4YÑD9£Dý1qާÅ'{VÜìý6”5Ž"š³hPµ?ýø¾ƒÕAQl/6ÎLvýA‹äõ‡éFä<]U+¶ù„éÏør»ŽÛä�ArèÏžcºçÞvpŒO< �¶ÑAóHç =æòתŒ×QºçuÓUôt÷?ÞHüé9_‡Àȵ‘°Ø Ô.sŸãžïКVðnÙ6¨j«½›â6½uκst€ùkã*ë襞±#ÖgCì$'íV”Vq¹§OýŠÈC ÆÒäCpÖÚu/™6›¥l‡!e6!Éï“�Q›0¥¿I>ž4H?ÖDàåi›ó~–\ ÷ƒöðô¹*I ·‹'…Õ½»íQɧþª� P ?H³ìuÝæ’bLðrȪšŸN[€,F�Ž}Š€ãu͵Dú¯_±Ã–1+PžK|bC)¹­ÿ~úxÇ¿Ð×½5a+ V††¿·:N—'Q„£„Ìöá›@ƒÙ)`zy†ÁG–2c|„ó-Ðnê‹sï™ÒËXIÆ“¹RÀ¸ûS¢ê–�ж¥¹1£7Á6oíäºYñY™}ø’زI®øË홎7MD˜¬t`,ûI)”ÒÈŽHGïÁŸe?CqÐõcÅoùíÅÝçN¿¥¡Z´©>ßLö&G‹)ls\i9K$m �”Íì«ò5³â}÷Ч @ãA‡øÊùdŸ©éf›��ò¤7ÕQ>÷wÚùôÌW|”†³ÇuÛk±óÑB{[jtŽ(6¥>½».]ˆ@Há2¤,W¡h2£þfЪ�×3ø¾£ß”nè•�m؉�“ÜÃ8¸|–Ì�-µ¶hÀò€€»7p“QJ„>–S¶í�Þzv²{$šWÛ]�ßç„0�Í¿“ÄLbù1LÕ@5÷¦áΑÀð‹�T€_C']##i�Ä´òd9—­±¢±Iµ£Ò»ÚÒÞJ& ø¼Þýf2ÂÖìeë­4&öí ¤oPV¸Û¸Øzv�ɶ<µ‚Åo6}!7~rá*{Ï„‰¿O®z”ò&ü‡Mù† ‰ÖbËW<V:СÿS�…Š+¸e\MN½�¹-'´’eûfðÐö ªÏgé½`³ÃpVÉ2§ã.† [=â}ùœÔÞÉ$TX«áB]§ß—ûõk 0ÔÔ9f­ fñÄQôûèdYyšå”ä)zå§éF]´3Ç Éc[ôlÿ‘~ñ,Æ9#åMŠB|,’³Åƾ¥cSªñ•vK£_Ý„©N �Ýy¥#|)ÜéîüÍ–�ƒ¶šaŽQ­â?‘­ `pœÀÖS4…áØ;Ûð–Æ!YiëI†QRÿ@@ñj¥i|ú†ØëpÚ$¨¡˜R,H+ÑH�óß½½üåSæÏçÚ‚AlÒcO·c¡ÍZfëKí¼›åõí7­\qm"Åß]�¸»òV¿˜ ¨KSw?|õÓ�¡æ oKG‹•7űr¯Âªó2©åDJÀ;ójCKÕ“‚åç³}3¼ìuÓvÙ~Õ*¯‰�¸ÃMáf^2"æn»à b$&±ðäÄŒ ™�ö�|ÕéÎâD»áËÖ†²¦f�Î@ÏøsSêé—�ú�µ¹‰Ë�Rj&O7Ž%Ñžß;·‡7œÚÜ"EŠ&e^-ŠSOÔoó²ÂÚŒú(å¸Ê[«DíÚkªÌIˆ6ï�ÔòÎOhÁ˜9 {lÎ÷³O9ú¢Í„‚âcom¯9¶<VÐwÇâ ©#YÄQý(ßóøeé CGZ¾ì÷Ö+ÿ˜ˆ¿r¸í¤3×ôÙ§ä¥-ŠÉhƇ­Ï‹Ò&ÔyoJaM¼àÄ}÷ñ¨æþŽJ�i¼W!l%ù3;ºÆwIôrgÆC0ÒÄ(¶æýðÏV.¶<”qƒÓu¼Ã'ù镬ÕûƤË/”ø—¯éN1~õí“Ó¥2×óEŸ^õ[ÃðOiý±hÀ%‚;ƒ�}Æu{Ø -¼Ïeï€ÒIk#XH¹Ëbœ›uy‘®�Š0�"'Ü衆òâ¸R‚iÇoV¹*�\ÜŒV¦ Óá\Nö?îD3Øgóë®Î=NOµyü‚:2;£ T²' VÑÛl÷W»-V]?Ë[K ÷ù„äÅÁ�Z1^xM?äý®R¹–(Ê^àå£&ßíõ`U$bOŘ¿½ukÔÖðµ]Eùðð‹¤v ”²xØ·=(À³EOm2K§µ‡q×}ylÏÞùõ}— ‚9sèWŠ9’TråÐÓA„íä2[jú5}AAšLáåa2îÅÒAÕÓG(⪙ŒeAð/–•ôŒ‹×Ž#R rϹÐ’ØÃp½+BÍ6N¸i…ßJ«ïÆ%b2îK VÛTtÔ_­ÌÉo]rÁI¨³ëV®Åk¬‚dc‡U4ûÂÌ{¹&ošf`DìAK¯¦$ßKJd­…ïT�/Á>Œ™&‘¤Ù9•2r-µ'«€)Ówâ€ÕÔßE Æ9ÎáG&=&!%4UóÖ¼§V\º•¾ÜV¤LMe¨f9Í�ÒqaÑÌDp¸N;r·!í¯ëk,qòG«eF6Í‚>�‹ã”Æjó÷öõ@?0;Âq©.ñ¤óÎìl ÌÄÔYއ5¢#2bB¹ÜFƒÊÉæê¼ž5ï(îÎ*êhù¿(溑ï(-Ðæ2�ž1F&mN„›ÙUÒ%,ºZ ÐgúóKœ“†ëárÌî”nW,Þ1öyë˜MRr{™sÀ~dóZïÏ�d y¸A ‡¾yN¨d½ýÖnŠK5w2‚Bú÷™_o¼»<�ŠëW°& ‰O´8`í·ù4å‡âÝf{-}95×›v%ôvî'À�7ü[¬”š¤ �¢aÝÒѶ¨ô‹_ãçñÏ÷Öl_,ežÄˆif]y*à0ÝŸÈ¢R¢“x±Æ�;k‹J 1ù &å¦ÞæþˆoþS²¾¼+ûµ�ðs,R}ŠÝ޼òÙš[8R ?‡2µgE}û‹LaS¾§½hÈhÑ<â~Û�g�ìt!³Ëø´ÌÆGØ™ä!,Ï…ñRQeÞ½sç'x¥ sdª¢ µ=ÝÛÀ¬ÍO )û„t&<!y1Pö¼N:1+_–Œƒ‹P æ«&„xŽN쵩>cZqúºE �ÀJPÍDÎv­ÊkêA ŸÇ›Í7Ùî¾�%¸eI,W}½$î5DþÑgÍÍŸUØÕ$âs±6ZsTÇÊG>UÌ`‰ù ~Ñ@Ñ€o[RhÍ‘HÑTïOܤâæÚ1ìuóM^Ę…ƒî<]˜åMWñK» �'¨ÞÊÆ®�®åøœ»_\ŒaÛM¬õ€l}Â�=¹#Êq…{ŠãŠ|Ê2DÆüªîPnÔäB]脜Ó®êÓè¯õ¨zÁvŠ7ÑB~• ÷¾ÒßÂV×ñÕ–“›Æ¸Pß³5Wá¶4çÔÙQ¯ ýÆîæÉ“'å£lLä_ö:Ó+Œ%J) ºVáŸÝÁF„9*ñÛ8e´¼¤�~µp\)Ф§bPnp‹ÌÑ—Ì�Ã2»ÜhÈ�dÁw!UÌÁ>oP•F§aåHómRÛé‚…Ðyî.”Lži…${¿Lr.§¾UwöY üš‘»÷î3N’'[…¹jÀI�*aæwï~BBä´{J¥«§A¯&óJeYÞt fJDT®„µï 7`23 ùj½*æ÷~üáEÒøjo»]|'? iMUOkƒµÂu}þç,ªlF›È{³-f2aOD%«ùx,�¨hWXQ3 ÒirA*éã�;ÿHÃL%Cá”ÈVصP}IøÎÊëߟ·X\mQ‚B ý.öz€¡‹Äo½· ÷â�R#»(°f‰mjc^ÓTÉï•X+%—¬@È,ÇÑQU¿<^�ÐÒU5 ¢ÿÉîêJçãú�ð×û ½Ь’A+~EY“ÀjZßiè‰{¾®ÿÏ¡Aˆ@ºn Ëj¢buKûÍ´ªË·Op§`­’6k?>ØüÞ‘R,ƒ€®~XwKr4`ê(·VÉB$"4Y#Oìš{Êð‡¦Š�ÿDz—V¨»ù+˜Ú¢ËL›“fôc×óЈzŸ¤‘0>¼�î>o¦$,ÕìâO}z.¼ÃÏ×<m“ ÁtäË Åm²8 «±ÏúN?gP•O¡/¬Ç´vé»�¶±id1Šä1�\a�~ïçâ ±nÙ9lò”gç}ûÙT]-ç|Ú�Éô×§Duõ¾º]ÆŒsžX^òøjãÿå�?å•rh5&¯,³©è°†Œr!Þj—ÏÝÔ�ÕÆû=ÇËùd”;¤6Þ^N|‹’ÜÆèÅî}"%l·'¬‰Ž:º.±—!|»´ºû«Ø#®¤Iëzåù.X¯åµ>ÓGÞ�¸¥Îÿˆ}$—àiܾ×1·Î0"·cXXù(Óµ$ÐØI š»K÷¢? “VJ )œ)�ž ƒD¾‘ªì{Ûß÷ÜD)ñJ”ªÓ‚ˆùJ xxÈeôÊ•ñ{�#N™ 3;ª3/u|ÐLèô}µ‘’zð�ù¢Nñ ~†¥^LÌÎ6-šˆÚ¹“¤(£ÀGMøØëc7@pØ;fèM¡ÁBJçÜM�ÊKž· ZÁ¼só½ÜËÚ/x:dÆ2‰p&|¬xö)ÃäÒÓÚ9\Š·ê9©âÅË£ ­¶ÆPöG²ÙÒ?05Fu㇊žªà‰£¾Yƒ^®oÐ~�4�}Ï}žé¯w+3ÞÅvqÄ”…Jg¬ÿx­ÒÐøÔ+ŽÊ{/L¨jµ7,é�âwg.áßñå.bMú=Ks<6©i(ð¬b�™p'uPBÅ{w^F/÷QË�Ÿ’?¬ý&xú‰®Sí�<1‘:™}ðót‡Ôqø N§±ƒ¤ûÍY€a„2zœØ¨‹ ;ã¢Ñ×Bç€/óéî­ãÝ$ ærb _&_·Ý2 uÚz«^-ä¼£/Ó`AìOàRæ´l¯€ ±ß“{0o'ϸ­Bü(K=a#ò�/ù—q�ƒ^ óÆ¦Ôø–LJ^½@༠q‰÷­ÙvUÛ¸}_[A®3ê�˜VZ?$ q‘‚ÓòŸ¬ZñWÚ:÷æ�øÛËg¸í³h;i.0,*8Z”'ô�†|ç 62ðÏO0ò?nÃsÍŸÿ2$á á¿gMÁ.óœ€i~úÍõÞQ‚8aÝj^õÐ_)_‡ Y¯ÞË%TñR¯ïI×�HMôõ®N\~DAØd+Mšr1`Ûãk€�µ”YeëÂ"[!Œ¨¨· 9C0Ùz¯ÒŠÇ—3I³“š$"ƒY>ºtÓǺôÌŠ¡pÒËf þät¼¯Ïp¥êu ’¹pÓ}ì€JÅí[~Á§êkv&�¯wÈKruC拚) 4’›ÈüTK ý˜ðr±Eç¦aºضŠj¡­J“…ž¬ïœóCnßÍúi§.çí&^õh¸˜ùòÇ;÷«Õå‡Qþòê4‡Ÿ§š5º‡ëáì:a"ˆ$TÛ É›á&£"‹Õ4Ý®´I*¯÷¼¤×Ñ7¿ºe»á_í‹:ôîPÊ;©9Êe t»‡’»r1;áÑ®B²÷£fç�£þªÝ´‹ ÉK#þÉ?žÂt¥Q{Áˆ-¨›%·ÅI:ò–`}T�ønnç =+rÖUÍfÿ:ée™")KÁ@¶1,ó„ßÝ[>ªz@ÆrÇòæ¡M#£Æ%¦á@§VyËè³5M|âçä�Ú ¡ëoܱÄÞJ¶úf˜ò�EcXŒ½Né¹H< �öåT§q˜öÉcJme=nŸú¦Ê%CcV™ˆô&޶ÑÈyƒ÷î¸t` Ç£*†/[ùžØž²±;Õv÷‰¯QrëŽÅ£�.5ნrî˜.[ÎÓ1Ê‘ýëëL&µú‡µ5o6x/œ4b_n+:ôøi�Gøx.èö²Q›Ñ‘øb43òÅ(ÒÆžrE––¶Ö ’ÝS|;[á�$ãyÿ™AÔŒ䦹�8ÃBRu~m?\MP<çØ»xdçO£z›T‘Ú¢5ù–áe�úÎ̾þ樅ê¼ê)‚üGתeÕ!Ñ=}yìˆ7æHot‹BÕ2µï£[«ªx — 2•#äCtÖ„–äþ)™}�£Uýô‹Ð‘éf1™Ì[[Ú¡Pîõò¨éŒrÙ>£è.MÇ5Ô ¤àCyŠã¢'×M_¢izG¦a)KØ;—nMÍ«û.<¥»Å´ò-4ð­3FÜv×7‹x†el‰ˆ‚ 1ÉO}Ș5Çy�ê‘\?äë\7Q{:®þ€¬?x¼\&ì�{µW¡••ˆ´)ÿ’b­�ߤëèzq^%![zö£¯©Û†3•^КÅ-ÑÊ*Qtƒ1�Œ†C‹©û%ì̼Ùì§`ÑI] N}Ý_uô¼5Ffƒƒ¿®Å=¾àHûU%q©–v&íI;îÇÙ�ñá˜é“÷œ›å›by³Áµ×û“A—vë¦0“„ûT –Ð#&¡'Aösa²óê¸3C¼¬#|Jм2Ýoð?ÿ�;ƒ=Ý]±eãûÒ5¤v»ŒÖø �ÌîK,SOzóÍ+ì·|¶ó£¿*€^òe*õnJ7¸l@R´5Èa3ÏÏ£‘¯|�êhýÉ*:¿Ì%ÁËñø„ƒžt ïu› µàºŸ¸[ô%4ŸUGáF±…"Û†¸¿ $r�–»¹•[!Çi¬#’·Ï»ëzÑÕi罺ªù#âeÚʦÇòHmU;¢ ¬žÈ?‹SñeƲl~ EzËSíÛ�1-öë »;žç‰›ÛõÝó…)ír·�qFÅM’hÝ] À­z}J¥1Q¥U©·kfˆ_@–„yz€{íÐÌ“žYúÙ£×c.#M–öS}à!Ú/ìÞbÄs×�Úû,&@ŽÏJ2]õáePf™Wè˜éÕÝ‹]´¶ò°ù†·$SWP\rÅËà À™gvâùÒø!bÆ}eë )QV†+›%â`’{“®�¯'¸­\�µb¸øõâÃÊê<u(yÛ¬f•ƒ&bŒÓÎN7óB.†o-£¹4¯Ã-Ûó"ÒbEUîŸ}yW‡oÞý<—ûúlÖÙE�—â±e§�.0ÓP\.̯¡žF4\ºà’t¸-‘A[ •ËW×äc�z(=îš�e¨±a¦JÆ}6M¤Qèñ^´;~±¤‚f§Ã´›mÖÉÈ@†T ‚ÎárÄ��ÿMZÙo½c€½ß`\3ÁÕ; C_¢Á³_Âs©|«Ñ�£y•“Ž+z�ÕÇ1Küû[BƲ/É ²e»‘d×Ñ/£l_hó¬ž5„¡“aôLOp[¢€šërÍX”«0iÍ~ÙèÐ�ÏÅÇgJ›ä—ãÌŠËžf”:.̧tU“¨ Ü°¬Opï í�Ù5”§ µÑžCX.¶Û>¡ð@­Ã� v?¤^h³þú"_›uØ”‚“�ºEÜmãù/Ô'QëT�7Þüâ·˜Ðؽ‹í´ü.©SÚªI*- ;ÓVqDëË?Uî-4fº0…í À÷S ÁÛªÙ&¹#´Yü±éÛ…ùu ÏZ±ÌW[CËs ÅP�/)›M˜…Ä,â©Oyò†ß–E-fèÈfbã¹k›÷™ •ÂüÁpÈìRé,Èû0È%§-6óð§p¹?|Ç`�«n÷#»ŠÙˆÄeLÄF±‚‡wßãË…ÿjívWarÂßÑ?œI5ò”KDtZ|«›gçþ0¶²:D ÷Iö0×<"Vd‹À˜ xA~€>"þúEü×r–‰á“…�ìcÁ=Î@a6½Dš-Aöï$;ãeÓ? ñ·6eë.H £é÷³îl®i¸íí$ôdÊì–ÛûoýËAaõ)€Æàv<õŸ›éS–ÒðSç76ÇŸ(P[µÀ(R(}öK �”Ú TZE=Óv§Î׌WÔÍÅ’èöí/Ùoà‹’1gÁ�Ð,�N©¸‹ª¥~.Té¯ÛV®¤šådôÿ±íaŠy ¾ K?_™M –ÉÅAÓÔ¹Jfñbý…ñø´³|)ÃHßæQ᎘8uUÃèØ¯¼v# EÄA6¡¬Ê�“)¸ö-¾/èÔ’ µQ^£3C½îU%�<x±LÚ÷ÑO¶� ÙDÎþ¾muò±K„ØŒYÕr×^:­a¾n±!ÎR£c Æ�×-4 ù,½l£1øA£:Š$,¨;´?u­�Æð/><“ÛúM`¹�—�Q†þåxêdzÚ)xŽÕ(m>ÿ8¯l«!}<‚¥4Õ ÷lxý=° Ù³FÍþàU¯ ÝLs¥®O»±¯(ó+¤Ë(¬¨ƒ”íÅ&hÎφàæ>Ö]Ôí¾5”5BšïóÅÆsK?¿¦®�~ÉÙSœu6Îu/Y�&»ë¨ÔÀTÌ´%âYÎÒu’aᔊì5.PW«×Óžò'¢š²ý´+Ê„ck�Q²Ëâ¬juåî„P៌é ü´å9x†Ó…ÉLŠ^pM¶Â’é¼�Š:í=‘ww\©vá/8ë¾h **OLmW=0Î ¦xßw2gQY\ºaM±BÊ¢\`—~ÿê ·Ú-7çãbûð¶‡åÙŠæ™2ªìß¡JИ .O¤H˜™�–ýBQë8Q�·|BS8ÕóxªѦH*5|áIÐëšo+JŒ.2YQR:½U.„3S¦è÷áƒ#Ðå‰úVÈå)ë Ä&˜½* fžžÞ¬ÍFst;ÿKÕ\ímãØ´Ùù(Â]%ÂKr¦È*u2ÝŒ@‹kC–“z5âK•c4À•¢Z8¨ü.…pF±Oqš^ž%R”>¶Y¾6j$k°²›}=A®ØZR1Hn\YÑò¬6¢v)ì•ó’ëËÚ®(J‡YMÇ»�‰$�NC9–‰V�«úN¤’xÜ5ÞϹ-‹îomç1vôv¶ÕäEM§ü;œ8=¥$äÇ–ßB¾#ùIŒàedÈ£2®Í r¿ù¸îÇ:Ê�˜/DŽôi%ÈÖD aΗmzº‚«Å§ž‘;üÈÒÔÓ��¶FŽÓA=¥�¥±C7g[Ÿù¤ñ-þ­]ÕèsæûšÝ ¼Î<Y‘¤r¿� "pPrßzŸR¯Æ–À%‡¡")}sa ½«w¿z5Ñö�•¤þ8Èn-oQIêúÒŽ®t¿œ{ eNÒy�wc÷e@‚5‚:¿j ÷»¿V˜¦ ù“ý¾ibŸ›À—.].ZâºFãÊÊ«1Déj{kŸAnÌ—ÝGqÒ›9õ(\Žšî+|ªm¡¸à±'lWÁ0ß9 *DXÆ´<…7¶niã]Ü_¸wiÜ|#·Ò=ªø¹tU;y€¯=­@¥kÁ2y_ÆRÁ·o=m­Ùv—£@ç@—XÈi.‘S˜úw×U�M{¨ (ê>0¼x)9ùˆ2™ØÚ73¸‡Øç¼~ýšÙeúó~4>h#:¦¿µþKÑ>}o¾®·,OO‘ÝŸ¸hµ²}L¿ÜWàIaZ=¿ñÜ.ú?Dð · endstream endobj 94 0 obj <</Type/FontDescriptor/FontName/NIWRQN+CMMI10/Flags 4/FontBBox[-32 -250 1048 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle -14/StemV 72/XHeight 431/CharSet(/N/b/d/e/f/g/i/l/m/n/o/p/q/r/s/t/u)/FontFile 195 0 R>> endobj 196 0 obj <</Length1 1384/Length2 6102/Length3 0/Length 7057/Filter/FlateDecode>>stream xÚ�tTTïö6)¡€H—À¡c†îéNE`b†$¤[PB@éN )iDBQ$D@R¤ù�qïýÿî÷­õ}kÖ:söÞÏÞïÞï~žb30P²GÙÁÕQH´�D, ¨èêjJ�`°ˆ ,L ™ Юð¿nR�ÜÓ �BJÿ/€Š'ŠÆúT¡h,N…´¼]ˆ�—†HHƒÁ€0,õ/ ÊSP…ú ì]A@ …„{‘‚TPîþžG'4ö˜½Ü0�"%%Áÿ;Prƒ{"`P$  E;Áݰ' ®€1 †€£ýÿQ‚[Ö �v—òõõ„ºy ¢<åyø_Ú 0‚{Á=}àöÀ¯�=¨üÏd‚¤ ÀÄ áõÇoŒr@ûB=á�ÖኀÁ‘^Ø o¤=ÜÀkê�úîpä°Î�?ð÷n�ˆ äßåþfÿ*„@þN†Â`(7w(Ò�t®p@_]Gí‡æ Hû_@¨« ›õ�"\¡vXÀïΡ€º’!�Åøw</˜'Âí%è…pý5¢Ð¯2Ø[VCÚ« ÜÜàH´é¯þTžpöÚý…þlÖ‰òEþ5H{‡_CØ{» ™"ÞpMÕ¿¬‹ô?>G8KJˆH p�îsúUÞÄßþ;ùåÆNèŽr°CÀƒpìi Ô =½áÁ�ÿ;ðO‹ì04`wD IÿSë†;ü±±Ë÷DøwÁXîA�ð¯ß¿ßîaée�Bºúÿþ{¿B·5õT,ôùþLü2Ê€�Âb`�‘€�Ø—àV1€"þvþOª&Ò@ÀºÅ^Ó¿:öùK�î¿âàþYL…e-àþÉ­Àb`öùÿ¦úï”ÿÃUù‘ü¿R÷vuýæþÿ?ÂP7„«ÿ_�–´Þh¬�tQX ÿjÿ#Z]¸=ÂÛí¿£šh(VJHG,™ ¢‚`Ñ?~„—:Âno€@ÜþPæ�ßô—Ô\H¸Ê ñëۂ̓ÿ+†ÕÌûýðÂòòOê…ú÷Ùp¬œþÙ‡†²ÿ¥;a1q�êé õ'Å®k‰�¬@íá~¿™  "Qhl €�9p@y’þZ³„$ ¤÷ËEú�²0oOO칿ـ=ó_öomÃá~péì4 &á\ÑvT£Ää+°2&K¸�yd!,0V`MŒîS›´ùœjœ›3§]¦>Û Q·vîÔSö8zúqf?p¹žµÁ_ôP€Uý«#«]Êôå!îTZàOföiŠfœçæéÊ7¥‹=ûp X⯿&Q°wì3QqÕõ`Ò|9©KÔ%´"Ûô:^×”äèÐ2K™m.¡[ìLVÄè¹ò–Ü’|I°ŠÍÐ{®-ÛqLšê[}ýSÿÐÀe/KW|˜–OøÊέ(4¥šÌ�³ª(QµÙB>ùY^±ÏÆ“�v·©”5xîNò¤•¤¬d÷™o„DW¹­&®z¿�éuÞ(;ËQúÑÀ"Nážck8òfå{}í~Ø‚Öëå=~Ø•¶ä*‘ŧ77 ö4ÚÀÌÕ®½åä€é³œñ "}ð„d†5ÀT8‰­bf¨šte¤…¥·p“R|a›sË‚ÍþÑݲûñ=Žij&� ã27î\˜ØÓ)4óÒÇ*Ÿ¹¼+�ɇN¨ Ã"Gb”òuu1­’Wl©[„¤¤ s�šX¯ºî:¼¨8°¿NNRq¾X©fÚÇtÞk3Awßákîï‰óOêÊã‡dÏbïÛ¶r»<ôRüÊMü$ÅRãå×ÒÆ˜ŽÀõRù×^S˜’‚<©ú�?Ç3 ¹�º ¬®Ž—6ÆrUÞXÁ÷xjBC2¥óCù!(²†(±kîJ³Ý.Ãÿ¦@G¶×À �’£ˆ»Y5zü,…ˆê+ýÚe!Áj`T Íõ®—j“Fv±;6U.½“\Ýn—üs…hq¶^ æ) 0»K;ôÝÈêš(�eB•æB<_-uÙ"À QŽ74âDU4G„ØW”Ye=h\ Tmö �p_ä“}„å“\û¡çЮ—¿×Æ]þbXŠxÿŒÇÎ<€ÝëìξTõ€D çOC¢—4Œœx«ã>ÌGgB6iÂx�§Ì"s¡¥[Úb£(¹zlSQ’Ñ£d¶:/­xdw?߈ *ÙS%�]2;­éñ½5ï‘k�çkê^_Ï�.Ω•”;2ë}öüÀb8½üN¹vâ˜9)÷4õ’Añ‹Õ�$GkàrŒYMtç¶ýªð“9ÜE6¥ws‡ pÍt S\_1'æa>S[½EÆÓÒÝÙ›�˜å7Ç¡{ÅIa[Bé1Ì7hR"¨kŸžoHöú}ðϽ1}~A—ÝÿxNº²="$ÿ.µÎeNР›Œì¢®ÐÜ´#ôáæ6Ê)‡4KÚÜg¤ap�ý²¢Ž‚Ç9óù¤aÛzâYé”oã“çlð–Øx™z"Œºµ¸F�.Q¢Ûí;—R†>xök*wKEržšßcÏ·KƒÄåÀôÎâ4Ï…@ߟ2/âœÊ“×·ds¾lk͹;švНS|„ß`9:øš­“BG°ƒ\í3Ü&_åé€'l_“}ŽCÌÝ5êyÛrW4‡ùYmôÆùÁL_U¾/c޵À §{)Çç1º=öãœ5¾¨Ë�wêmü²^êç7¾;º�2Kû BÌHØ>¥–í�j‹¢2þD׿Èí<.¨md™ð£óŒ†Ã;êûã–î/�Š2�Fcï§ÅôêÀ_úmt¾_Ë» Žx~Ýœ•©]X¯ûêB³í%¸ôÀRØóÛˆ»ºñëj‡âkx?ó§¸É‹«KÄìD#e„[ƒoí2ÓÑwS’â«ÐxÐÒX¿³ÅyOhÖàg#°N°˜ánÕ7Wx™˜tùvÇA|à½K3Å;µÚDóÏsxÅ­�1¿Íä12kߢÿ…s,¥B Ly¾âó³Ì­Ûøô;¢z¾IômŸ%Т~�ôµƒ»µ42@£Yâ‚Î?#5eç;Ïå]¿s^ÌúÖmÇDNE‰©˜3ñä'd„†�ìŌΈgùP‰ +ÇÈ“ãõ•LŽì{T€vï‘­¬ôµRBõŒ=w­î|l„Ñ»2“KÇðµ±Gãœ�¶ $P”•ñêÐ,wÒ“<¾ô¹9¯=²�ó¾òó*#½ªs$ä ~vû†çý|‰’¬¶2 ùV�²T·µ —øqõ­$-ã¬Ò=§üÏgÕdoìgûŸàeX¨ðÇ Ý¢JfeÝq¡o¿6.¥.6Ö bRZyý)üctgˆDqëà§©¦ZwòÅçŸË£Ñ—Wù¦’Š“bËïw%{ÅO—9ÆÁ‘‰dklÿQ8lâ¡Ù¡r‹·V’\âÜóˆu¸…±‰Vœ>Ò¬@±9X÷Ì ,»ÁòMІ¯p#*ƒã·µXD ôÓõŸ*‹ hrß|3·ó¸ä#÷û€çoJ;ë%¯D½¨/ˆg÷²9V™Í^—¦§][{ÿ9[ƒÑô±Uþu�C© Úl–ÈRÜ~CR ß–ð�sµìgüI74#æŒ óŽr¸�ÜPÑí‘)Q%ðGÊXÍ;Y¦Tøï�6o/ØÓùàÏq¿f¶›òŒ­;i°N¤Š“:j†‡ënòÄp\|J®¼Ñ½<µ÷�¯ÜÍkUºl5üÄÔ”¿½?’Y°%5.h^ɺI‰+†¬8Üë¡]´|“Bê^—%×.˜ŒìÛäÔÆAR Û4 �×”Î%-·Ñ…³t7Émõº±êÍWI7›ÊöLIÇQH£NR!W$ã¦u3Ÿ�"¸”ˆ´‹£_=�gû©éÌ…WÁÚØN®/•6©ð+%Sá« ~Éü¬ïú‡&¯­5øÚ¨42è%KO®ZÞ�Ù8\ʇ‡×£æVr¨ õÄ·÷«Ž¤FŒjÞ)äl¾÷ñð¾J¤Ô4ÓÐÚ¯·ªZC-FÃdM]rz8ªÙŽwûÙ“µ9ø =qOç¶éÕ3™ãô¹o—qáÒ…,íóâøqb��VJ‰GËÞ6Éîã¹�åÍQ ìHo½Jû Õr–kŠËŨPºM0Ùg�hO½tƒ=(2ûynøe7\�[†pâïõ¼ŽÎi›_”5‘äYM/Ç­>ô’6–ÖuXrÆ¿¼¾³‰áxe—â^ëÉà(á|S/ã&Wµl§LºIîÜRoÓƒ§Eèó�iu¶„Èœ9R’áü»Â¬o‚ù ®²žþXßÔ™—R_½ùÉÁìCÒÏ‚Ñ7ƒ{¢€EHgJ OýÛ]>"G‚áYúáÙZÞX·ÏÁÜ©¦ä)W:Æ-{šZOÊ“ò½.Ôº©nŸF?ê¨�+gY“–øê¨¦¿ŒSë}i˜ênFëÎ)qWÊcžÒ¥ùýü¬Ñ,� YWø´7ùèâÆa­<ûzTë0+´¤žìYvLüˆÂÈÌçì¡õÁ>ÁN îáHPo©À#wŒßí­ómürŠÄ\¢.¢µxÇÎ� ­k]IZôÑÎ7þg+LcõÍEOZ”^ª¨Wf¥[º=�´¾º©˜ HU„ñšnMÙ–gr`»ÇŒ™Ñ¢|6ùNåúíóoúÖõ÷†´I“þ*ÉmUæ^³´_Èzj–8cëÂ4M˜(ÕGCµ¶:àÃû_9êà·Ìž�»€èêHzh·Ò}\9¹Äw³¯Æ×K¥Å“i,v(…c$²_Ü«AÌÄPŠÀ-‰çü†G–Wb„üîí�~“?Âõ°^±MÝ ;©ëÆ¡\½ÏUŸŒo»/rAе¾7Žº )Ÿžg½ß½0eä¬ä{ä]•ä@ë Õx<ß&œ //¸u÷ããÔ�õsÞêÓäS|XÙßøŠiÙŸ’%²¥ÞW>B”Þó€'ÎZ];,4XKðè­"Ë�h�Åâ¤ãÑU‘[x. üaà�"š®ìFMè´$Áór†¸ãjfæ‡Qî =UºY—{Ê÷Y9 PÇT�?}dÕd`bnÌÕ*FþæÛu N%/ 7.»ÍÝò�æ5!³—K~ÁWÔ.Qƒ[ÄF�Ú/b"cI­ñQãõÊ»�¸=K©O›µä9?±Ç*‡ï’ÐÞÌÄ0Ü S [qS5MosšZ×�èò¸¼ÙÁóƒ„\)ƒÐ„Í™°öSº�´Ï&×lœ^/:Õâî&ºìeDw¶-<dy=¨ÒXë |‚"8]¸ÀíÛ™�›×’·k|,cP.RœC‘Ãzê*1aŒE¿¤çÙhÈú=ñ5¯^:þ‹h —ˆkçûí¯Ø x™ixh»N`5Ïõæb}x«�mI½áýD–C­¤ró´ÃldïB17N}u»aâ'�Ý„"}Ÿ_ªµA“¸ÒÛeoÖ²ÞàOÒ·¹ �ÌiðjCÙm�æ¦lòÑäƒ}­·q˜sŠˆ7u%YUyëŒø�–AåU”FÓ§ClÆó ú G\V <®Léò˜¡%�ë5Úo?Éê¬\µ“óñ*ÃÑ÷–7òËnøé=V2S5pFG6*Õ$SšÌJNAwbžŒ“•)Ó«M·D®ØÀª�’®g ûèÝxãªþ1Û”•«yÙ?huH çÅ!Õ¬ÓK­¥:ê™m÷=w/Ò8²ØÇ ¶ƒÁ•€yU²qÜè‚wƒ™›ŸÝÁ{mX׺¡*à®?(›4Ñù!8ë­6óå€!§éµ‚å�Ú+B×ZÞËø<~qÞ;g P×Éô=:XKÐÙ>v¬Ò›Ë}UHwŠ$¤§!(jצ?äøÖQ~|0mÓ)MC~Ûº–‡pɘò†ä@ÛÐŽÒ%'žÚo²ŒUVÓtñ «V/8SçÒ�}Z/@LÚ†ßâ–¸€Õ!µD猢R‰·Úß'Òh«‚-ý�x¸‡Ödvïʤ—d¶ÔLœMQ®ùó«}Ú=þôÞì´ïí€VH,ùèϾ}¢“e}�>§ëôM:ù¦nì"’„‰þ9íLðên�ì§“»ãË·üYúóæJùây¸S ý<ÀÚ?–ÃÖ{Ï&fÚÑ•±ÏÐÙi)Emì×…ÐBºai•Ó7†}_Íý8&…²HðÙ0›³ÞÏÿaÇ->Þ£0 ³sÎ?!½7ßnöÞIN ?œû̦ߺ,�UÚ6pT¡èR¹Óô”h†ˆóy+î••…ƒÃ© ’Y)�^Sá½c�uH¬(´Í~GõåÕ••×FGb>Ú«j'³�l'ÍkÇ- µ2�)RoR¯¢SÎôAæiû[Î÷k»·M-=Ú"V¶Ö’“Œ»˜ÓwÌG©eÞ¯!ôÛF¶ä -´“t¶…Ùû䥪oÅæ²HØ©”ùr% °Mq!U#S¯éÂe¦Wvvͦ R ›9‘-ónèОcÚfØd—;Õ”ä¡;Õj�¡Ü}û“Î6‡aõ‘J@êý‰Ø¥+ŒqSGó"Ýø�·©L[d!VÞ ŠrŒFm÷�½ä”ctK!7©û9ÏO¸¶“0!7Ú]Rþä†J.­uþ’3Ùéê'õ%ÇºÝæ@Ë¡c×Fø´��ï¢{_Tà��± ÛñWÁ¯²3EEYÕ»êzD¸§øaûiLšìcå y/ä ;Š Q öo†Ô˜ƒ³ b y�xoÍLÁ*κæfÉ(»5£1×Rz³C·ö &FØ Ñì]²3y�µZü¯½´ÖÍ$=¶�¯>˜RLþȇ°+¨gôxïàâ�֩ڴ󲨥xŽ´)РÙàKº™B-«¤‰¢D£ÿ1è䦇«oa^Ô¥ íž·�?hôm!­+»!Š'Œ¿áð5[EEá÷89ó$”×Î5ž$ ·ìJ¿|ÊB}í+xú{“êGÈÒ’¶tŸÜ÷&æ[„ÅÏëdå µ"_0V1v×¢š^èLa‚+@·;[a‹øØ¥Ï ì¥{#ˆé?;<¥¦ pÔ(˜œÍû!²'΂¬.·ˆ:ãÑ*#$œQ«{¯4FÿĨ¡b?±©°­\DùVz�™œ~Oš¼ã`[°~Å×LäËó—–n»Þ-q:¶ Mú¸ÅJeòpiR–Q%—K½!Qº­—¥z£´;ô­.0}�£ö¸pI¦bN͹o©Š©Ï IݸåJz4…xܹé=´6°z8[¼¡0Çî�Ö²ù²½@F1¡¨{�YÍ‹K�e·çÖKº ¶7ãD2}fñ‚ÄÊ©_𠮬…Ä— ›¥¢#a‚2]o¿7Ç]e† ÅW»ƒÖB\Kž]Γðz³ÓëŽ8‹gò/Ÿ1ÅR‹÷},4”wv80¢,þÁhÒõ]gm«¯x޼�j*�Ø‹œµ¯Ø9‡»kµ´<�î¥0h}Ü.ÈðÐU¨NÀsÈ�ßñv¤zù•69M™k‰îÄŽ-‚G6="šMq€W 8)˜åÏ ¥;‘%ªŒð|ýx͆>‚›sÀ 7ÔwB(ûÙQiá{åà¼ä+3‰´ Ú!8ï7ŽƒÝŸ;î•vi6 a~{à Ô’á1;üÙV{·«F01Òè•9òµªðáÙÛ½„ëÍdVHˆêƒ?Gemæc`M^KÉÑ�Ÿ\ð°çNÕÊÈЬR¥‰\”D:‡6¬þ„~?Ó| P&¹s0§QÀäóú–:é”Öîu𪂊+kÊ~“ Šþü¢c8¼¼m–Â$eK¹YU¡c‡þKŽùòƒ£[Gw+ÓoX¤ªBÖÑ4; ÚU>ç@ípàEþLë¤óÇœ¬‹ušhöAQP ÊF Þ¾c_™} bZæ†És]vY<A =SõLLZôîxLooÌã°^–Ÿ�kË�/†Ã›•Ô3¤uÛÙ¾£Öæ¾½g;e†ª÷è³{î+JÞç~Ä~qgòÜ4—F¬ë‰6;ªÉÅ>)"#ӛѓ-ÊU�ßyG¶:Ä‚ÞÐÁOåKÛc é«û9 w®¡�_y 7Ï^Ll"Ÿ_O#eúÖÑÜ Ý“µïìµßô¸EÄ@ÑÚìÄp·/)3Sâqñ msÈ2ÿëlèç ÿkûúgý¡fTxc{áv“å�­Yü{RÁ/N£ wC®F ÒN•§˜(QU¾(l:¾v3��  “Nd(uí΃˜×ƺëK�ÐïGÇ’}Ì}ì.YŽ*:Sɤï0§ì%ãiÏ’oŽ»Rsä|Ë'’¢MSÕun·{òMd²r®fàp©ÆÐbk²áUr·ñ%Õè\Þ[fâ:½êÅ÷pç%AÕ¯Ã7¼‹É® ëFŒAòœaÆ™ö% Ǩ»÷¶Ø»v6‚SÃzJoDnónÑR7úƒÉ6:ƒ¿gnl]¹(U½Ç�Ílûò)ÃZMzK×ÍÂX‚¹Ç”³Š™j%´8S¼Ñiù¨ÛáAJìq;£¢[_½7ünMy,$DТÚq%FqçÙÚ×C�I=*³¶MÓΨÉ��$îŠns¥V°;‹{HÿõW||Ì…tˆuãåNcçE©é,«ŽÔûóZ1'ÛòÓtOä™ð¢î��CUS2·1µ�SIŠ‚l�)á·˜ãÚ„ôΩ ©@³Ÿ.]¶‡Cõîýhó��–P¿ÃÜtwׯÅñ[\W›lrØYHÇ&쨴\™¨¤E¦ÕÉ�5\Œ3Äv'’tG|JŸÓºô0.nœR�ò¨KLÔ{í×$’¨W›AÆxÍÃÅôIÚQ)݇âÃ�¦O©¦o{væÄãÔuL¶¶MŽXIüžYK^k ‹ÀÁ¿Á¼ÁëÖ7¸ìô#Eæôä ôPaEøçº×U iN¤ pXT@ ;%HGÅÍM´g$ãU‹iÈ„t(ÓK<JekÞ­t÷¡{šj1?œµñäm_iLj²Û}Nî®9íd?F�“ã„óÅàßÝ_uæ—Õ<_|†Z8€aä=¾NbÚá-)éB‹ùÝ—qHÀx|$ÑÅɘù2›,�Ô6kM`7WîÜ|ež�¢·5›!¤nM£Æã•iï@íÒè@ÇgKÚ±¬Ë¢FrשY –ô¿®nè+m'Ÿ-Ì6øaa+`äGmô𒹎5ÏV@Ì’ˆ«& �Q7„k&ßĘ\Š/ lnhšH¹¿5pUaq'¿ØËÖ;èQ^ç,Ä–Ø øæ#uê�¾‡ùvëí�)#•ˆ×Ñ ùÔ§L€©axÌn+EÇ3ݱVBUk1È}{Ç÷Ã<‘Õ$/¹{Z&§0®ú#ƒkqA Fíí„™žy»|~Œ™u%£±s}2Æe‡õ$;ÿ‘–×®óõÿ„l£ß endstream endobj 100 0 obj <</Type/FontDescriptor/FontName/GINCXO+CMMI7/Flags 4/FontBBox[-1 -250 1171 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle -14/StemV 81/XHeight 431/CharSet(/N)/FontFile 196 0 R>> endobj 197 0 obj <</Length1 1386/Length2 6040/Length3 0/Length 6993/Filter/FlateDecode>>stream xÚ�tT”ïö.�’" )H %!ÝÒ% Ã�CÌÀÌPÒ‚€´tˆÒ�‚t‰„HJÇ )*ÿ1Î9ÿß¹w­{׬õÍ·÷~ö~÷~÷ó|œ¬ú†ü öp;ˆ*†â�J”tt4$@ ˆ�(LÂÉiE¹BþºI8M $“ú_�%„Âø”A( Nhzº„D�B÷¥„Ä¥€@€0(ù/ !PyAí:�M8 ‚$áT‚»û" ŽN(Ì1ÿzpƒy�B’’â|¿Ó n ‚t@('ˆæD0È`C!(ß”à–vB¡Ü¥½½½@nH8ÂQ–‡à E9B�„Äðk`€.È òg2N€‘ùÇow@yƒ�Æá C`HL†'Ì‚�`jhôÜ!°?`í?�>Àß» ý»Üßì_… °ßÉ 0îæ‚ùBaŽ�¨+ §ª-€òAñ@0û_@�+ŽÉy� ® ; àwç €ª‚�„ðïxH0êŽB ¡®¿FüUsË*0{%¸›†B’üêOŠ€€1×î+øg³.0¸7Ìï¯á�…Ù;üÂÞÓ]Ðõð„h(ÿ…`\$ÿñ9BP�1 „¸ˆ„(�â€ø€�•7òu‡ü ýrc&ðs‡»0C@ Ì‰ä ž��¿ÿø§E"$°‡‚Q�;ˆ#FòŸê7Äá��Y>ê°b¸'�þúýûÍC/{8ÌÕ÷?ðßûTWhj¨ÎûgâÇá>�?~aI�¿° ˆc^þYFýÛð?¹08&ãO»˜{úWË^ÀýW<€Ó…ch pÿ‡åV@1 óúÿæúï”ÿÅUù±ü¿Rõtuýæþÿ? 7¨«ï_�†µž(ŒtàÀþj ù£Zˆ=ÔÓí¿£(F 0G ›ù…D€¢üP¤*Ôb¯E��þpæ�ßø—Ö\¡0ˆ> ýõqÁd�ÿà ì‚ù€ 1Äü!1jCý^ã/‚ÑÓ?ûP��áö¿„',v�B @¾$˜Õc,1€ŸF¡öŸßÔ Àà(L �3s�ÀŽ ùµfaa€ ›ç/É?ê‚=ÌÁ¿é€9ô_öouC >0Éç)8øA˜sMXëI•Âmoþõiüý´3aþ‘üGD¨^•O6+‰†ÙY³Z%ªŸ{„T9·ë*zœä,N÷CײÔùŠñ³¨n:²ØÅO]aO$ù3±MQ4a噦(2K½Aôbé߉¦ì –³wì5ä¤ð¿[Ó=“äÍES¤*®ÞªÛÖQU”¥MÇ$i²»úÕl7`´.öƒþnîª[\èZŒÕ³TÝ 6-é¶S’DïJÊåþÁ�yªž;�ÑÁš^!ëß8ž¢¨T 0)‹VšÌ¿"¿È}㵓Aíg§vS~Ǿ·t‰'å¤F÷Ð }¸cÍzÏ£'§‘¾‡h·@[-ñIF^ì`¢üpBÕ÷«©²Ø"��ÐH»œK^�O%Ã�QTìéÓ‚ÁpE-¡V4𼊎cgåsÅR,ó ž+W•ð¡Oo_hY»™ãýE§´ƒ>GC+Õ®þGW8� uxxø^F‡|’!6<Î Õ[¨˜\ÜÒ&ÎÁ"`ŠŽ×WØ& ´+s ˜(¾¥‚¥wxˆN½W¼Ü0rŽ/Êk�ŒüúþŽü1sè÷áËÊÖO p¢oÍ¥HeAÄÏßDKQ®Ë¼ª›)¨ÛAá9�Ì,Ú &GÖšv˜Ì2Æ?.áȹȜ›P�¬CSBYáCP’M&n*½F»„ïáh쎺”£YÍOù¢hÉÿ³Pü’9©¨9uÕW2ü‡ˆž—Â�î.¼Eû“/Uz#Ò(«â(â— ï ­rã#¯!ŸÖ‘äÜ·TÕ{®Hï5=QHÈ”>�öyŽNŠ1«Ÿó-ŽÔªÄaŽz±¬Pv{K~³{ŸºÜ—âîiƒ.™œ<§ŽEsvz6ííÅ!kÁV²ÙŠ ¬�#®@�[ª•‚æúã’<®û™:r› þówžoÇä°�¿�¹©ƒ¨@Ñ5×S»Y4^ Ü;a¾ÐO‡%[D~1ê–CNºAœ�út™I³|nNñ)…Ó}¥|?'Bõ÷´JJÀÈØ�âÜèF~')ú2óÚÓÛ‘6^_öRÇ‹n‚6½n2Þ¢ùr�ÑûtëÒûèÈ�ütp8vHßþÌé#/Û*väMVÝgËѤ…¦š†¯òS1†CÕ‡™q"©26“|õ#Õk^,ﮩ�8•AZV´|R¹wò×K{ÕÀÏ—¿ìå* �g·ÔYˆÔŽñêqʶ)[>Ú\tQºE¥4(°¾;~®:ŠZj ¼ï-z¯ŒÃ.Ë«hHOÃ<EÊ1I6œn¿›Ðàsfã[ßñÎKJXK”šäà³²�Ûfìù?"¬âäRXú+Ê34±˜ºˆžß³\iykúØjd¥˜¿-æÙåR>xÞìGvŶŸÞ­2æ6§@Þfy' ¦‘MÓ•·?pJл�ˆ’/}§@¥ˆ­5¢©„ÿ¡é~:A_ï6�ß¼0+Û¬ý pº¯°Œ":¢´IÞ„±ùîhw´íî†À‰=Î-#2’‡�.…Ïp÷®Ü×NÜâU6ßQptâ=‡,†¿–æŠI4eí¡CL„U~Á}‹í+bT«®ÏlvÓ=3)”¿·'•èJä¤�/(ü-ÑØ¦¦~‚ë)ée€ŠxÛ>Œq;{>-”YÊ�¾{ÐφE™h’´sæéùŽ+�\”@/0™uéS°×Ði³ûí<Ûhòçû%_òq|•·Ü*½¥×‹nÉÆgm¼›áYñí�œb¾á®WDìõ}–¬³(MjÃpýq£Öí îåšo9¬ù‚òë:º­uûø.¸PF{Yò§ Þtµ�b jSý"ªY³°œÔiuñ 0Ìb5�[Üä–Vìèû~ €šÃCćÒ8´ÐðÇÅz›ÇΈÙNl[š¹ÈSCG Ï>gfç=Çù•!—EÙœ<OyO¹Øl«è²Çð5þ­¾«úØŸ°ÉJÁÕ Ô£x{Ó±åf#/ÅËÂl6b ÁW‡žËœ=rñi¥`®©ÖG½|\¯ã±¡»¾«ÇT´æòÜ¢2_Ž­oÈâû $H«5´a›¢µ×�-ýëÔÇç26dg³ùZWorÝsYy:Õ‚ ì-:™ÞOá°}y.i«69›[,mÁ³ "ÄêæIMX�˜>x?§ÐO+Áyf’mýš`?¨r½fÃy*4_íuj;‘¥±òS½òCÄ—Ré­ 3ý!o×ò„•¬çÜúu?ẻÁ^¼I ì.…*[�¨ÞÒÅÕõ(¿Üá-�É`¥È*Eô,eØ”|ÅhWkBË¥R؃’„ùüN~¹'ÁMý¸´ŠˆÏžØ¿ Ï^ãì.oË…a³~Ó¦Ù÷1³qôÍù*)P°)°ú)÷éq®w8•Àí]I.’�\âF9jâÏX¡![ŽÙì–«ÔëR­ß8—ATS—¡ ‰ÓJŸLð#)Z¼tq‰o1ð†®áy¥-Š)¡gõ?ò—à”N¦d£;»í\]øónÛr�,¹Ž‘D(,2%z<gä»è˜�˜ïbûÕŠíÛ¾ *f º‡‹�»' ÌTÅòM^ßóu%îØ¾<;ºz:õä±ÝwOx:ðTä¸BJ ;öA±”F!0˜~Û_9LuÖŽßÖ? ¼'~ÑR‘ëíØû{M)�bujwVž«:Õ¹òKY÷5�E_[µç†Ï,:®ÕÔRŒ—¼6ˆÂz, !¬³ÌãkZ4óitôn¯bzre&\7)üM�#�N‘Ÿ‚ô!¿�#ÝñÞ\·×qH„g$ß>þ°{.ÑqàZ÷ù¤Øêmè³u=°sÂÚ�“Û9Óï*‘„Ë¿½%,郊�õצIe²PÑ…pìèœ}È•õÎ_ÿ(­aèäO– �áÓÅãàX8±+ò›ë¶õ€û�ò¨O’¥xmx»ãs ¥VüPZ2%WkÑĸlõ­g¥•è”·¶…«£ÞÙ8`³Õ[Á"Jó鼑žÇ -\• TŠ]PX\³ñÌCÙêíÞ–Ðùâ­Ó(·l~|;}’G˜8hi@ÂËð“¿t 9³ôâ(ážcl!Ã;Ü I��ì�±ù,ž×BȈM„ŒÛñVrÍ�ëÞ•Î+Hcl£’g¼;…™Å³¯\<ÝÍŸiïóNýþö§­Vî.y�ƒôK—|±%€LbÍ“÷2Ö"ÀÔâ1áíÆ…„÷pú’Ê4ˆr™#y{°2ÀX¶\xÈ>nCËO{‰<¢â-$è×,x~^-@·‘䇗ŸuÅg¾óXKŠpƒþ]éÝ—Î8&ý4Gl+Ø´¿9ÎÑ \þYk×´~¢hšE¬E"Ñ�úmÐÚ˜ïì g†6ò>Çœ|õühÒ,HÁv]ÝÉq¹BžÌD)ù’!ÚÊEªS­çg4`†}‡LòºÃ †åp_sý'ê¯òñ.e×ñ¢øûº«¹rllˆ¡¯O��žLȯI�yüx®é1'%ˆÏ«žô“ê«êg¤SASÌý¥Vu‹þ^ú{ÖÄÃ.²imjG-¬ÖòšØ öPö�pi©™‚3í!…··æ<"i™ª¤S�Ô&Ð�;ºú§X0‰QÅ™„–’è‹@c‹�ËÞ(¿3�f+�©ÐWµw‘qx�Ãy4Ã¥XÄ¥a¬Ò¤{Dáq^*´óožza¿[·¾á2?Ô1…‘7‹ Ãw6�Ðø”—iÇ}ØØ˜oxØZÒ£²a_EÓfò7.eJ7v¾<ÍSe2Hy½ñг$ߟSr1óª º–¸oÔ¨ð¹sêVul+SÊÊSÑŒ!›˜câ@|Ü};Þ~I%!sËžHð­r‰�¿_"-ÃâÜ‚©]½§jòþ|•È‘6Ék6—™��.YûýÖ–¦È,§ééŸ)âݘ³ oŠàjÛuòÈëÔµ&$ œ·° �ì‚ót¦_ÿNÍáäk…¶ˆòùR˜�‘Ñ=›eCÁqYI¶#vJ�iô/–Aôd‰Ûq(LÅÖÛ�trGóÐ'sÀ?O¼x#WŠsÞ…a=œüŒvÑÏ@©Ñ94»6(Ü ÿèlÁ­ƒÚ‚Z•™ÈýdXJ:u"k¿)'~§íÊÿšþ¾ç¸MQfd™r�t¥¼ûK³—›\ú¾÷Å?¬ñUzÚi�N>֌ȸ;Þkåà„>Ã]®¦QRuH'v=PÖ!Md{pa]ñú­R ‹?î\O×IwŠ`ï«LH x‘#~FƵI°R‡©ÿe‘bj~Zí®®§L�A÷ƒŒZCÓ‹9ñ*m··(©ȃIt@¤îcâHuPîMp¾ Ïä…ÊEã— ŸÊ­É " 'Å…¥öýª{:�ƒ%íÉ»n¿‚”…H±4¤Ÿt‚5ëÓñ�oZ¡3’_ÙûÜhÙÁK�{K³rA…Ž‘¶¤¯þ&TYLý…ŽÿÑw8¬=]„O|| ´Q7z§F¦�ªï�0«”ÌýKÆÞœ‹ b¶1G ƒ/;“ q~KÊ/ òÅ�hm×ÐZšùOäLŸÒ¶1U*h#h~�ù%C÷ãî<:s¢U«.€2„xW,»�hÌãܼ bGaíëÇnÙ*ùÖmf΋¦8¾+CKxQÓãvJX£8ºfæÒqÓP“{¬§ =qÉ�Ãßz‹ÃEùSYÇ�è©<"žõNŸÜÈ>’ºôŠ×óu ñÕ�ß'_‰ôM· Ç-�Óp<‡–$#»ñ�ù™ì‘ïÎðôSÚ 3à‰� �ù7|ÜÓ÷ßœ}¿Y\·;%%¼–£TFA†3ˆ`ë|u'Ïhì¬ûÔ²´?æ%(:šaPí28Ÿº5©ërê“dvje­˜üî¾t¸—Æjª4É=¸Ø¼Û¥ª¡d�WTÌ ôitQh†™” ùá$öZî¢hµÕö‚Tr²`§cÈøÂ;ÍEyË›çl€ ”C•¯-VÞHXðÜ2ñ¥›QßÂøò¶Û·f¼‚ÐÚ‹zÇý"7Å^a§ÍtÆõ*¥$[ŠÐ].©Û} !³Ûer .ãyžL�Kº$«ÕZbµ°:rjb4kµùˆ85~ó¤&h>œ,÷Óð Tú5ú¤»¹•M_“7QTþÄ.ÞøŒ§È°<d ³84…ûóT@ØõÀLg“Z�? ˜NxMOÁíbtËjÛ3èøŠ\6H*-ª¨‹V‹S唺 ±÷ŒrNý ³ü³æÈ«OÇÆè­¸“'/ï BåÇüÀëh“ësc·ng’|J5þ6Jx`DF¡ÕØðE'¾,á œ0í­€z… ,®ºh9¹òÝ%£î±Øé:Çó¢bc‡Š×órÝ4ìís…jù+icmÆà|Rªïã„‚¬oR/�˜z™«\U†ž,ÝýLÄ{Xâ“FÎwZ(:•J²èJ5ÎK“;Ñ�¾zÿÔÞvCT·­òœîUò4‚O-@*½Jÿ<ÊDS™“3Ld·˜�l¾{îñ=±�¼üŽV»»·ñVª.jÇ"®ð½Å2é8�ìL Öxx_Ã�p²{h2÷z_gÄsaùÀ�\7Òõh-£­H�DQ�Ž2Ï}؉žöLß(þÜùÇ?}t@å¦å„�uOº…íÞç‘XRšs ¼çüþˆ±í@¾ÑxîâŠ÷«*£\-²‹wE.d§v°’ªê5j,�Ën߸õIÛýéê4ìò�§m°±é7\Dôœd—õBLr/©ë”luÍ€?�ó¹ìéˆÏ'Má0#íú…ÃÊ*xøüôžÔ3œæâ׃²ÇJœç�¹}–=nm_î—k2¨~¹©þÑRUÑc’nAbzqŠ>šŠ­êœÄÝ“ hcξQ±v-ÝP,|]Ž«ÑU¥Žö@Eá[Ç$ªÐ.ÐsZ¥…Øçp|hOÍâà ñ,6„R2”²Ü6TÁú™=”«ãäÇ_Q¬Ã.ý�a ÇÃ�E’œÍ[%(‡Ä|nÕ­iK÷ÄñèVÎ4×/à<t=òæhŠ„îëœRþY»Lk ‰õÆ]M6+óóÎŒoÏ ªí«“…�™w´üñ /> ·…ÎÏ™½uájÇ“NŒ1A«�Ùc¼¥%JBt¾êq·pÉ!{œµH]'�²[¨ÉñpèÇËÝ Ü‹9&¸¿6énõ‹gzËE›ÕÇu„ƒ(¯IŒ 4ëé`›äúëä�N£¡g¸í¤ûæ¨7ŸD´fXMÐÙ6�=ƒ%,dõ Û¶±„¦ŽõQ´*íD³6 æ úy5 = §N¯b£+NQqP)>¶n*¬«ÔÜ�Ëö@dÈzJh펎\ï5ÚpnóiK˯L–ò(oR}&X›ýÐëestð’«DM¹Å·Ž·``þ‚=Õ÷“÷ýÄ>ƒøPÐ2WæÎ- øøÒã…G ø¡ö™Ü5Oú]Ô¬ã%ûØ”œ6ãâœã%êx“ûl*-­š=­º¹Ô³�7é­Ú¶êùÌô•±"¾7ÏÏvpý”¯€µÏr„Ž•˜LÕU\‘pßøô�g¥Þçì®ëfMÈÂ=Ù÷“)5r:;į’›[B¤g$�Ê�GLbI’Ú3èªbÒåü9u•"‰î¹È .c °¹Ø©˜AæiŒ´@ã‘ëBÈjÂã�FW;q”ó;�ki‹9ùñv™:<=\qkxÊ·ë«‚+¬iLf‚ZB³UmªˆÄ»Ø‰£0)Ü÷9E ¤óÚK‘×­Ýs©,­­ìw×B0žš0d2»ô ög˜´ƒ©ý§,€=C¹™P÷éjÍô+»ÝìÏ$v7·£URS9UÉ_’=ºWu_ÿ¥]Tвvß�»£ón·-Säwõ6ϽçæiÜ£*–Úß½Þ/cD“$ÖÕwÜ\å%¼òBwC½$$�Dý©²…tZ$:ÜÏ. ß R}|'ùmÈÊÊÄþCæyfÉÕÍúÑb~iÜ]QÑ0/¹§í�ã,Ü‚¾  «ªÖ$ác{ö‡ œ_ÎXÞQ\£¿n¶þë~I¦ýùMØ—ASÜ-eo¿ºì®—-ÚA“4MÞXËY’_jMš­úÆ”pb¸„W²±ïPÕGè¾4“R¬è™‡Vtœ�ÉxI¸–ÕÍô²è±¿ÍÌËNÕð_ I”Ÿ ÌΠ4’§2jhiëŠ5ao½ùððH˜rbÇ›~á[D“ëÌÛ0š<±Vêq“Ò�B›9¢üáô·�Æ]"¿°­®¹w%#+_ŒÍ{UãÏì¸X– Müšõ6pBÕjw–žÄhÎ'v«ÙPªcU™iã< ¼cÎZu­ú¸Ç[h@ Œúœå±¬®3î·î"÷^5Æ�D½spw:¯ËŽp‚Á¹kÄ9ÓVmÕç€@¡•¬×¤âa(�6ÅÁ…Pƒñˆ½©:+·úU÷3#[�ÅÞúg}ú€\þ柵==ÆzÞñ%O)/ÞÈàŸë~ýqpo¿k)ã3ÕNHÌO›ÏKKøGoµ÷ ¦±LN¼ÏK–iË}FÖ!ÈHâ.�~—ªNU!·u]ÆÅâ‰Sªa˜ÿa>ZUþ Ëö�ÏUФ»"‘{ÒK2Wù:*”ät¸Ì˜�Mº=,ÿL#ïÙ�í8‚@“˜“Ï«,Ç9ŒG­´\Ô k7ÈGÜÔ(_Qã�©fSN)a§ÛE숡^Œ�ÏñTŸ&qÅêœ.kÇçÌ �©(/”öð›ÊwvJ·oz2ľ™Ó>´¹©+òa,J™¨eŽ-IËûÉrÉG+5¼É€Û*ï?t/¦-«÷à'éÕ¢õ<éhJ–‹¶í¥ÍqQ_P¼ÇXf.Osוêu¢Á·Y’ÝqÇiÉö^9nºË­�+ŒØen[‡3: Á¢à¬nO¾Y6Ž‹}Å/w®—4àÒZ•E©…GQÏ"£ÄèëÖ{çòk&¡û�óu¹¤j曼«Ý¼ë;J¯²¾kÑì ù@öqóE½a±JÅø½ÇÁ*mFÑy… et§å o])’G³²Ðcz/^…?¨Hž±îóØ®§´.‰P­ê‰ËºR*ءĻ:mtó0Í—d;õ}ßp©'¬T•®)?j£vLev‹Lò�A5‹ó endstream endobj 147 0 obj <</Type/FontDescriptor/FontName/HHRWSH+CMMI9/Flags 4/FontBBox[-29 -250 1075 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle -14/StemV 74/XHeight 431/CharSet(/mu)/FontFile 197 0 R>> endobj 198 0 obj <</Length1 1443/Length2 6987/Length3 0/Length 7968/Filter/FlateDecode>>stream xÚ�tT”íÖ6" %’"0tJw7"9À�£Ã CƒtH#ˆ"!Œ„(H#1¤¤tw§ t|¨ïyÏyÏÿ¯õ}kÖzæÞ׎{ï{_{³³èòÊÛ#l!*8ŠW€$ TÔ6�A !>HÀÎnEÁ Á�vÒ Š€Kþ‡�"F]cJ`Ôµ�6Ôp‡„€¢’b’ P’ø—!) T{@í�Ú|@ â`WD¸x#¡ŽN¨ëkþurÙq$$ÄîÿvÊ;C�P;0¨ F9Aœ¯o´À†;(åý�\ÒN(”‹$?¿§§'ØÙ��t”á¾ô„¢œ€7ÒbüU0Pì ùS€häuûƒ"Pž`$x À v¸Ûµ‡;Ü‚^_4T×êº@àŒµþÜþõ6@>�¿Ãýåý+þÛlg‡pvý¡pG êªhñ¡¼P÷�`¸ý/C0Ì qíö�Ca`Ûkƒß™ƒ�*òú@ðu�•çf‡„º ÜøÜ °_%òÿ sýÊÊp{E„³3ŽrüÊO Š„Ø]?»7ÿŸÎ>�#<á¾ P¸½Ã¯"ìÝ]ø�áPWwˆºÒ_&×àߘ#�@bB@ˆ+âeçÄÿ+¼‘· ä·Rà|]�¿¯ Âèp]Äê�¹þøº�= @ÒâïûŸŠJ� =Ô´…8Bá€G¿†!äëæ#¡^@sÐ5÷€ _¿¿O–×ô²GÀaÞÿ6ÿÝ_~-uEcž?ÿ­SP@x}y…A@^APàÉÄ®þÿ £†þ•ÆøªÃ@‰?Ù^?Ó¿2öø‹�\ 7ðŸ±t׬…�¹þMr �Èîú#ð¦úo—ÿÃEùßHþß ©¸Ã`¿Õ\¿õÿ�ì …yÿepMZwÔõ�h#®Ç�þߦ¦�?C« ±‡º;ÿ·V¾y¸#ìïg„º©@½ özP”�Ó¶üÁ�M ‡è!Ü ¿Ö �÷º5ÿ¥»-»'׫Ãíš’¿U�ëÉùç•Êp;„ý¯‚‘H°7àºÉ×’ÐWàzí!^¿I äçƒ#P×.Àëòü�$àWG…%€ü×ËéøGù]®7q@ýø ýÓÍ¿a¡kæîö7p�%?Êñ[þGšvîÈkoÔo"]×ð/ù÷Z€@¼ v€ñ„�Tèã�¡uÇäïxò.÷>d_6}ÅÍë;ެw?%¹õ‚»4=xy(ÿ¢³ùöÔ¢2×O¹ æ ßÍêò[5Iúµg~çÖ‰˵€±~ê¶¾ÜMùO­Œ ¼Fr+~®~&AOpª±¿h°g¹º‹“è½¥8öĨz}jEOv‡�,믔Šjž£¿ñÆÇXå±gÛf Ó²â¡xñï‘ïy‘ý<$ÓwŬ‘ÈðߊÊó}4'w2ì3]d$èÖHÇF÷ˆ–ç'y÷�‡¯ÂZŠͨoAÞTÛ˜Wµtóâû/§xoó­ ¦•B ¢á•-eÝã KY/€¡œwÚ(–’Ê +)­‘¬ºT¥µÖѨ2¡'Ƶ…éºC“&‡Ç/&$¾}º›9mV5ùž•»Nwvµñ…¿¬9î¬ìZlò7Í—m•epô¸§ìd55)™Æøò&Õs£Ñ¢Nyûþ„Ç ñó›à0ißàï §ô ¹ Ð#ñ›-ØÝ ;"Y~ßãü‹+ötæ†ÈFažä–!W!¢:W¶_^îíåÒ9 )Û¤‡se§)7=Ëž‰çÔ—ú© AóïÍSó)z3k=_ûÞΖ'¬®Ú²<ZÒeìýøD"‡oǤظ6A$GŸei+š·g­"¨C!$ #qh¿¶pøþ½‚Õ:Âäd¯Ø3R¡3nÞH,4ûYƒAà›F7ÝTUùè[lïn)x°8WÆ“š=8]ìi|wîy­®ÄΙ7®Ýª¹.á7n9¦”×B÷!PŽúÙÏÊ@Á�õºÇ\XDé·§ãØÓW&qîZ×wVš|¿¤W¸chtüö®ÏVËè·žE–¯‹l¾°b‹|aLPJ$&–ÈÁ2ºøú`öWLÔ¥CTÕŒ±§|ùCYÚPdv«£Wáî­z!¥Lï–0·�3}F+�‡òj$)óñ‚O†Ü)s|Õƒ7‹�3”?¥ÃÞ?°h4Ãf›U’�4Þ è_9}ñæ›—j¶>¼ýý�×QtKÐRö‘äL–Ñ€– M™yæk²‹yÜ,1aƒñíÖÈ¢ñ±¥‡9);>Ƨ|7 ÐRÎf å•,#ã$›»ì—'Ñ -å»9Žù¨¨Ñ‹¥�Bcq´øŠá%ˆ–î™ô·ô7n�¨ ßI:ˆæ/ì"QuôdUIŽ÷ünÉæWz„Зî]í}IH8`óô³t“�¨Ð?õJºvÝy·¼òd,}¦Óio&+t¶x=¿¢âÇ4ÙN:Ù±”MjBëæ/Ľô¤…† úŽÕ°&H‰¥DS««ü‘šîëBg¯�±nB_S—«¡Š? úzÓ2�\>µcb·˜uÝ ´¨©YÖö`1O³>R¯yûa÷Sé9UÛŠ]4=h–ñý¾¶Æ‰ö3PQw¼‡¯è,mòˆÅq ðò�kçkV!ºG8ÉFßÌ4ù¦4i7:¹›îÓ¨viú‚#)¨fÖ˜½'¹H¢49Ã[uAƒ&/KDÕõØØ`gë§EU¼I4sæ�´›C�žÎèãvz|:ÍîQAvÇdÛRŸˆ#�nºÔûÚE‚ZŸ÷ç©YC¢÷^×Þ{GÜÚLü~àJâKoÁ¬,&G3™ÚŽ›ökßѼŞãT1‡láb\æÇÏhÓ³>i¥Ž-Ë^ÇB±*-·wB÷p¤O.ÏTЋyMÜ•EËþ[ÉâÄæÓ%þ˜…re?N·Y@ϛ̲>'lÛ'ýGí�ì˜â/�Tžó3ó‚–tË,°ÄúBVÝé+©ûZ¶‚óŽ �d…� þXŠ=~a‡·èQpãÄ �Q…¸ ”V .b¸ïÉQÈ»9ø¡4SÕç¸@bƒöAçó%®î‹:õs'�Óòß%]r É+-»agª›ÐŠw�¬Ú[ιJÓáðbÚÜbç)[vÐø«›÷Nm^oÞÂd'Í&ñ;ülÉ€Õ³ë) fK2™Ès*hñ¯H£©wD(Њ™ò9³G0©߯�„\wkÆÞ„«à=gÅ�Æz…*îk0†xNÖ„1¢áZ²6Ý»a+ é‡Ð&´¦|iJ6{É�XO콤½v%ø>«ÌªþŒÊdÆ—ÓØÌæÏÀRùΜüYÈ›énꢩ¶öh¿j룋is碫Ÿ¾•�<rúä=k³†L wÌD!ÞT�ÁÕ„;wʰcJw?{7h&×€œºŠ:¯¾V%¶]¯—Á·V¯…;èuŒûŽÖÚ¼÷¡I$MûÁý¬Rb#½«Ÿ!Y'�H×ýç.—ô!È�§¤Óª$wêï ¡16<0_zü#ˆþÑH‚µœ�¨½Ú¬ØcÀ‡Î¸‡ÊúÛʶGï˜î¡—ÚcÉKãµyÚm]Ã¥|§ÑÝAÅúBÔk&&RcÙu=‘ƒ$Ää%º|º™sÐûuââïG˜B¶ZÂÃß<°x0'Ǫ2wª©rl”m{ö*±Á$(Æs,iʘ°ýV;ÍRµ†Nþj1qÖ ùÐýø^bÁÕ$¯*¿;øÜÍêÉö[7û¸48‰Obþ­âœÕ\É­L:Ë8²=4’0*ï-:ÄCG©!Z[UL‚M] zÉ‘$?æxgõÆŽÐ ˆWÑ­Ø—Ö$XÞÔëÉÕ�“—§íòO ˜ù{˱Zql¶<ZÎ9Þ‹e:Ñ¿ÂÑø¤ ¼¤£zÍ%€Žs'°Í¤oVˆ·c|äÕò†ßa¼ùöͳ¼ª¦QòîÅè "ù>>sáÃ1A[Ïd; ª0wGBOëÄ Ôýqš°•5•…ééÒ{)1‹\O/:r³U€Õ´ˆrIÏÔZ9Ãë©êÕŠ£ù½õ@.&y"X%ÅÀŽ€Í”¸;ß�;ÏÎâ8ëé�ŒÔÞý�ŸÎòv�¢¶t6Ë §ôÊ-˜l¤ƒŽÜT@Å«oghíå,ÐñÒ91¶ÂËÄûgÅÙ@«å]Ÿ§´/ó]<ö›ˆ3ÃSÇZ ø� ÏØ¨àUfŠÅЧÚ^îîQ�8Vÿ�ˆ¡hÍØYƒR9�CI° •S.<±�ƒ¨wØRsóyö—EÍgÛØÏ‹oŸÏÞ«‹’n{—ýb±•"”�ãÖøNBºB5žXQÙ&Ìdý­Ó\}'†�J?©W%¡W�Y `C'Ô³ ÕéIŒJl=Šu“ˆÀæ´Y,f"ÞBN˜žHê$çmu¸ þlO®d–Ãs!J·b4�ãö$/„ù®° šîR|ôœkÛÒ•°½ÊYfÕ}÷†¢«Ç´åž ¹å4ÿ;otŒ~Adg²…þ‹æ;*÷ÐSP#êï±kV:ÀC{ëm›�ÜpCv£O:5šbñ¥ø<©#[æÈ¼´ó³Ÿ­Ûf®ÿº²1¢¼è£1³½Ó€^lcå·[—1{ƒš!�äj1œ+d°éËõ’ª�Ï¡Øs–®RÒÍ ¸Å0 çYN½ð ¢2ºu3ΡIpóg£–C³©üpkø  ­ljB|®9ÀÇÕ¬¯ý¯Å:Œ¾š*³“{VOÒlgšáO©·m´Js,ñ'Á¹ÆÙØÕ­¾ç‘ä »Z³S5+o…“~¼b  @:Ë_í¸½ ln;؇?šÅ¹—Zû ð¨Ëíç"�ÒVÎ7Ñ{„ŸEQ‘9Ú—ÆŸÏ4àÑç­]¦ œpÎÖ%ÌÑMï•=ï€ÅaiïP‡–´Ë\ò*R‘_õÓ´rñµS¾NLÊg‡Þvï�æyë� >%]oÂÊz ÕáãÝØ8¨û9ÑòœÃ"N7œë H™Œ uôg¹À?[V!0“ó6´|ú=ìÍ�ÔâBad½(‰€9%Ãt²V¥’L4={ºS¨< 6� v8ÖóT Ë¢òÛ¸ez^.5©Ê4ByÛŒ‚UHá‡ÈøÁùÊñ¼šëà{s¼c�”ÞÔm;�c ´‹Œ ˜F­ÂÅA…?ÎNÔgG®…^Tú÷IP2æ% â=Iªn­UA’Ìl–¢”‘§ÎÞ%ÜÐ º(�ÎõÇ͇¦ÑZ+F0ì˦×'ë¬Q³ É�"Úù¥¸³+;“”»Q·(âj‹I+îœñ?Î ›kÏfñŸ±IÞÙTâ0eì@/�è?¬fÃS›Í_%íF©ç×t ó�›1|—ƒS½G¦Ü¶þ±Ÿ jÆ'nÐ=_DÉëÜäÕ"†§D¿”½i=Cme6éHù¼âi&u[¼T¬ Ó‡þíM…ˆ™=QæsÓsib@&y öEß%1œþýÛ€AîÆðÏ'yûü±R· é8‰¬ªJ.¡p5ÊËmPz½ÿ¢ÌRí’ê­¡šÔw½WØžüĈ³z/ó¶T¦t‚ëøØ’{ ¦¥(�ôé¡ pMŸ~Ë ’]Šî÷P4äidÈÑhyÊé¼a(ØC(ô^#E{¢+ôŒëû`>S ¤S™ßÙEGDS ÛôåÇÝ296ŽRK)ž{T=X*ìkìÿ¥³Úò£��Ò8Àò5ÅìÅÖÖ Ë¶:þ�ÙrÁà:Mö5»<åÒª-¦³´ ãÝê–w ñŽ€wkÈœHºÍõõœÐf¼ËÁO ‘—Þ` ¶ž™jáp¿“n,ƒ%ná��ut˜œHàóéÙ.zÀqz¢ aFKHe§’Ú㈷·ݨ�TÁ^S)€¾f™‰þ‘ÒÒì¾'/K&`)Ž”Ò»Ò«¯?ìC¸–T|Òl*Û+eß.ªÛaɪq¤H_ݬ{¾ƒ ñ€c‰Se¨3X,𔡅ZÀÅò,ÞÞu‹’ßy(3íXr¼ön¦Ûöi_Ž<›çwðšMIÛüú®}‘Uµ0…¬x•ÓAÛmàÖóCSã ÿóÊÊ*3LE¬aàÐ(ûãžvµ†Ýh]µ+üΞ8fë“ÏÑRk{÷4ª<²I>YNݰ�ßB“Nr*:ɉ¤J‡Ò^0ÖnýÐô].©˜6ƒà5¸¨<�—2U>À.*|†0Å.׿Ú�ÇCbUæß�´퇛ù>ž´òƒÝð`,±©áT‡e]Ì•±,—ŸgÿÔkîÚòM~‹§\új÷A¯ xÍŠ0hÌiS÷ ŽMFåNÚ¢Ëñ)Q±¸»÷r?eúà…;ÀÁßε…G¤Éû)ËÅ´åpÆé�ãÆ-ãûÅØ ¨,Ú~Vƒnf’«Ä¢´Î¨bÒpéÚ�G-Sä¾6‡áU•ŒœÿŽñ É KS{dÁo¼í1ÖˆÅDÜï³hE;÷U!Ö›=PÇh¡ê³ÐÚ’‡›s²uΔÏ�©y…B�¡‹£jrS A}!Oª ø6Ó~^xp¶;ó‘sö.6+Õv�üϙiÅ’¨ß™ýQüTÜê¼^aõ¹TÕ]ÄZ5íÖqŸÀ»3RÌáå\l÷Â`NøY™@1<ÒúLIÆß�gÅí(áÄÆxZЊm)·«}b3fõ­ZUóPJä=^®gûf-î’:ÒuW¾@ÈA>xÖŒ ê^Ø<½Ô²_?°»õ�Ü y{�Qéç¡d|ì„=Ó-ƒ<œi`’<ŠŒh“�pŸ’{¡ŒÎí¬qZè“0Êw¿Â7\¥•Ð|NJ†1Ò,?d[òtìLú¬b¾pÃ+úŽk{HŽ7®:WÊUÝãÛ"ZùhõF» ?'¦F¶D¥ ã¾æÏZ³Xžú‹¢G’½»«˜¾ÜÖt�/û°€qHã�vl÷c¹ô~¸E[ÌT#S‘kå¯Û¬&DïìðgzœÙ€÷²ÉßuG™—öFݶùÖЭœ™ÓìIßts Ìt‡(Ûgº¯¥!÷ÜõaµSî,'jÙ¿5À‹te×ôóÍ[©Ëð·¸W ø=_’R˜ì£BŸƒè]äÑ2U«âÛÌ.¼Z9g8»š62@›òöf›”·;Ó_:Ýв5_kÛ¬,ΟÝ{N5r¡ß5_ cëÆ3Y×0š‰`%ˆÏ7&¨ó8pÜpì/Å%¸—«d ¤J·P<<õž®Bõß8½Ww£ÃñðJXö¡ es‚p�Úëž·i£û¯­šú]µ ˆ�鯌·žå=Þ/&³ÅÝ–{�ªOȼQSP,/ƺî«n Í/ˆºÐnmÿqâ¶ü.ð쉄úÃÏr Óp®ú.Îx(Æß=TÞÊO¹ÝÁ·1ÏÒØßÂzOcÒPŒ¤qÂŒ©ŸaíæîãIbFŽoãòkD<ïW"¿T×â“O�?ø™¢“½Ì&êñÑ�ÞÈŒìÙÝIÚ­—W½ù;«²iX}œ‡[G-'*4ö&ªZ#÷yV©Ý¨ŠT/sç¬ø« ]Ë[p;±�bZI‹NN1ù„*¢äˆ„Ž ä¯ÓÞ¬i�ÉÉ<æ–6u²YÒ®‹”¹}Ûyõt2·m¢¤1ì÷²¦æ!©ÿ@¾"2ªƒ¦Í¨C¾c�Ð�öâÆ«œçÉzþR7£Xë4ïö&eU’¨�Z¬Ò_Y %á0ÒãJ¥4úm�•,0ÁÄjîC¢Wú­ý¯83ô…:l¥¼îVÅ1 0vK¢Û’mO²W¡4oñËteë^í¤3"Mf‚šé¼,?TãÕÉp/ì¾iª° „eœàˆ n›¯f÷«Hݾ¯ÃQÀI-Œ²(ÓÑoRßWêùÑÏÜ(k$¹-7¦²K³ªsExËðaÓ4¨Lºˆ»ÖiÎt/¨^Ø¡ZE©Ò)~’oì“Ñ n+Û¼LapOÿ‹û„‘�tª”©ú±”šÆÜ„Tø4î Õ}³�|Cm_^šÍ‹ØÄÓ¨<µNójŠ Á1Îô‹æ|ø¼¢="TUŽÔx䶨:¡sjèêԡ̹d§‰õÙ�N™áw÷ÔAþÔƒ¬¾cTø»BÆ>mß;Ý—TÒpºÇsÃ~êÍtq+'DŠ“Ÿ祟zr—ì9RD}¥r’œ³|7¯ºtŠ*Òé–k;a^z�‚˜·Zî9@GU,~‘µØO¿?âÆ útøhßÇÍ/,Ø?£5\nH•'è€v®Ëo–Ú�Ù3$Ä< K1ÿd_9–t®‘n1õ‰š©˜aŸÚnk‚6ðü„Ôï+ªá±À@[šü*ò2Šª¤q ä’®[ãù¾&³6Á~yXß “™„„tÀ«ó4ýÐró©i㦇’ ¸Á“²v<‡ìseÛ:µS †"áÇ!MŸ°cÑ™¬-#˜ôOŽkFëuÓKV¶…¦­øx“\ï±c<ñŠŽ×¸©¢b’ì(uX�Å-f>yÒyá4È—RòöêŠwlø#ƒü¼��Ø¢>_aû¤ÝQéšÂô÷z‚4yéF§Mó —õ¢{JäѪœ!jÌÔ)ͧþoÝÊ»‚cýjzbM4¥LÛfK¦�¼Uº:öCOâ&�5Kv´*Äeïœ š¥Y ¯Ñ¤fhtýÁÖW`ö')FF�|!® 4vA=IÎS.UV�‡> ¨Ö¹,l%ÀÃTÒÜë�ìk(_±Ti¿„Ü–ÛísÝœ†‚p%'…eE�—Ææ ¼Ì8ùF´DãöÑ�CÞ&U®D^ÍJÞ.ÇâŸ÷Zsñîe‘n‰F“õÜfzo{ÏÝB}žJ’}s£±eÃðc€2±¸]}T¥† K#( �ôó¯šØû¡¼9™1Í?£Å­¯ßÀÌ�N/÷T¼æ»Ð—ŸEÊ™yƒ{þ 鯙ÌoðfšÏÕyñÛ�%³¿ô£Ñ~+&ðŒÂ ÐPQ™KÏ<€yòéë‹x;\38¿¼ðþJ0y"µ&åÙuãŠë»ÛrÁɃKIQ.b1ø%j€~a'€‹Tƒ§�èíC@ÿ3ÙÌ4!éÊˉ'ލzì$ò³5̆¦jNF†ÛFÊå~h~Ö*‰ÅÜ™âÝ'çÿÑi߃Tô´G´I¹›ýøá¢¦3ç¼¤Ž§T¬íŽ+k†ÅÄ'S,Àƒá\§Æôë²S¥‰ãU‰§�«¾#½ _b£*Ó˜_ý@~c\Ï·ÞÆ:Ë}EÙ Ë۸˕W�äí‰~®ë±i^$5Má3| Çj æÔû5Ñí– Xïã¼™ª°Á—r1”��µx$]Ÿpm#Lr ?³Õž¶ä7Ú‡ä_ª¯“Å$½žä"±h %õc·§êÕ‹ª~„«Zw·½»en@�Q¹d–r榚b’ÌÅÒ:Âï߆Of”ræ G¸ÌZÄã…cÁ1(é´¢Hé­´8erš‚÷ÉbËñR.�Fq«a0®šLËIh'+^¾ò"ñiHШ.“4œ’$VDÔÍáÒ£Êy‘¿pN�ßÍ«¯íÚñ8R4t¯?ì­LÎ1I}GCƒpœ·ºKxchÙa@¥—Ðt¤7Z¥�º÷pÆ%‡Íï‹j§e߇� êÉ}kÝÞpÇ‹Ó+p+)ôùvŒ¼*™~\ÿF¥ÍÖFµ‹åe=—¥pcÁËÜŽ´r1ÊPŸ�—„õF¤QÁâT[”›‰;:K‡ù` ÿÍ£'É#P+kD‚_¬¦É†¶¬Oßb¶3}Ûáv·>[±H©gõ—›$¢Œ±Øu<bbŠx%à™O½øì‹DAèæMCæÄïŸ2ÖmÄš>lÜÕJ㙤ñ´^tœ9B|ÒzÏÈPC!P%hö¥Äš¾såî/ü4!âµxxaŽJÿÁÒU£±ì©~Ä|Ek7•ö~YØ�vÛK™1¦ÌøÖ¶„¥±<‚‰ª:ýdE�™ò°KtTóÇRíQØ9k�ɉY`é×6:ìÊK¾`Å 'bÍNŸ7ÖJé³v˜|㈦àévHOöÌøPë8;ÍÏ€Y5¤bôT0}1ü¬<9•ÝÄÞG· �•éùJb/Ïgÿ,Ó¡>ùë»”Ä�°¡1¤™XŒ�“—’c\xWjÒ·HŽ”!¸wSFÈn?¨5omžã™sìk÷0ä*]Õ}êãWø!ut’$Š {ŒŸ�ü|Õ8ö�7˜•Íê ×QÚÍÄ›Ïæ‰éð¾ [E„[<ÀËŠö›;<hþá} aÆ–_yçÁÚæ¹•»B¤tذۥÙI �N›`RëQm�?»y‰î*?zÇ£ìô!Þ|´A¨CÖ”®ÞÃ,ÛЫí2œµž£ó‚Í‹B½èëòúæü¨ÀÈ�¯tÛÁJAäi›ýD%™ímÕ�º…š ÒÍd* k�@ȧg{ëÝ÷g*Ã7ˆ™žÅI«ÒG.àX¸¢ûó¾ÜpÂÿ@$"Î3ÛpìÏÌsùL(‚È3~¾B=´¿dù ö¥QjÀ˜¼†#…€½dÍŠï4ëMdrŒ”²LуÿÄÂ…` endstream endobj 92 0 obj <</Type/FontDescriptor/FontName/LRICUV+CMR10/Flags 4/FontBBox[-40 -250 1009 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle 0/StemV 69/XHeight 431/CharSet(/one/parenleft/parenright/plus/two)/FontFile 198 0 R>> endobj 199 0 obj <</Length1 1408/Length2 6391/Length3 0/Length 7349/Filter/FlateDecode>>stream xÚ�vTìû6£C™„ÒÛHAéîN©1 ØctH(% H‡¤´"!- "¡„t—’* %ü§¾¿÷ý¿¿ï;çûÎÎÙž;Ÿ;®ë9㹡o$¤à€¶‡«¢QX!ˆ0X¨¤c( ƒE…Á`��1ëÿ£ð˜Â1ž4JúÙ•0p(§S†bqn:hPÓË B$¤!’Ò`0P –ú�## T†z#€:Â@M4 î àQB»ûaNÎXÜ-ÿ9ya|@ˆ””¤àïp ŽAÀ ( ë Gân„AÝ€FhŽõûW Þ»ÎX¬»4äãã# Ez £1N²|‚@Öh÷„c¼áÀ_íu¡HøïÆ„<@cg„çµÚëÅÀ�8…Gyâ¼Pp w7ÐHC¨çGýqÖþã ük4@ˆ0äïtEÿJ„@ý†Â`h¤;å‡@9np žª¶0Ö+„¢~9BÝ<Ѹx¨7áµÇ9ü. TU0�BqýýÕ�' ƒpÇz {"Ü~uú•7d”ƒ‰„£°ž€_õ)#0pnê~ ßkuE¡}PÎŽ”ƒã¯¼ÜA&(„‡\Cù/œ ð�Î ŽŠƒÁ`I)0î„ûœA¿’û¹Ã!¿Ô¸úƒÜÑî@G\ ð „#÷ð„zÃ�XŒ<(àþ-  †ÚÃ�(À?Ùqj¸ã·y ÂxŒþõùûd�Öåæ÷�ûïå‚4ôU”ÌÌ~7ü·IQí ‘ ‰ˆƒ�ˆˆPwúw}(â¯*ÀÿÄj Ñ@©?Åâ¦ôŸ‚½ÿÚ>ï_Äàþ;—.‡X8�÷€[�ÅÁ0Üäÿæ¿Cþoèþ•åÿðÿ®GÕËÍí·•÷—ùÿ°B‘7¿¿ì8¼zaqØ×Aã€úoW3øºêÀ^Èÿ¶j`¡8( œÜþ"ÂSá wÐG`aΠòGoò‹`n\í‰øõ �… `ðÙp¬‚¹â O›à8ÒüûJ íð‹]"â@(õàVŒ“Ä� ྿  £ÐX\×^Ð�üÚ§˜„{–~)ÿÈ¢@�»›—çß ÜÂ@Xg ü\) ¬ú·ü¯Z`^ މ¿±‚+ô?òoÚÃá¾p`j »óÀ¥úÁ›ãJV¡µ!™Qž5³4>¡€)L‹×)%q2ß«¬°Ì‘Br'õìŠ ï¡ü4ÇÏ€­Æ×Ä‘M‰Íg�ç¶ †Öš“# o‡Ÿo)Ôô°“² ˯þô4 u%h¼Ò¦É“ëáu›R?Ÿîا[Í·¦§læ}ÄÄšÁú+ -²ó²�B�Mb­B‹ÇxòìŸ�3qa…ØIøi÷}©Æ�Fis†/94�AÛ�E ,EžœŒûϽ0ñlgæf¶db'8¤}ÿáf€âfŠ&ã§€’Âù‚1+¯¢hÑÙv<kµà‰eRÉ»~ˆ„ÛUr}7Ö�–~l·‘5  Õ¢*¦Sž¯ÿ,¿_áŽ/¾¾q>Ìé»O½0Á^F[WÍÙvþ\Réøuúµe‰èM®,22‡·’8ö1�¦½9d§9Ô˜S*nD€(8 (T)u^÷8‚�×Yùó�x³9o J;r�Z!ât²ä=礉‚š6åµY™ ÷‡­ÃlòþŒŒ,ùYI¿Õ D¹:—Žâ»èùl¶Ìzlã“î»ÞL\·• IѻΙˆ’;*7‹JäËNLÄA×Î2ÄNPDúص+e=&Ùnç±åËú¤.ÐAœ-Y ÿ \r-Ñ}X ñjÒšY�º5a7áç8Ë»ŠjûÄmg¸çqk¥âôA“Ÿj^ �wû£Œ}rÓݵ†Éøvw„kBƒ�ËÞøþª]{fm‡J¹ šd÷K­Ù>™‹¢®ã£Ž™ö†pý~ãØI¢¦¢�P[î½ÏÔ/)ú½”è#&EŸ�¥*2[9úy‰‘of—øv.5--|Ð=¹{‘ ™dý¸œg¾äš,É8ª‘Ù(ËÃz¾4z0ykfÍ8ý’¯4ø·ÏÐ¥ÇâS} ®!ÚÄáMS_×!ÊNßžmùù7c3Yt– šÎ!{/—§eœ¦+†ÞIS·qÅ£í'¼›æéÁðV«ŸTy;W:ózØÁ‰ý›Waú¯ýzXòñdŽë 1_æÔ2ntA>µË; )û™cZ“•+ô,ãKTú…‡ãge¶yylJZ@"¦í Œ| ­,Ͼ|ìé]å]ØßAî51;61_¥e3|"f²›�®7ÖF€®­Ð=Ñ~úŽ-ŒÂ_kR‡YÅ1XXU˜µ>I*`ó¹aÂ[¡æ �­2p¡æËQæÍ¶½c^¯á«€ßÿÝìuÎsâ¾ÓqYßi¥Î²¶-ñ„áI{7|òFm>'’ŸÐOvNz'ñ|*ƒw~}3Ú\@"2Œ^ÙN•{¢\ã÷èHé¤yö¸œ�¤F(/·„ÄWegÈ}8›ö˜!>Ÿ_ýf©"-ÌbL�  +|ú³6¤Gv8*ê–Lnh}¯†æ[ÀÑú}¤§§;*¬2W$ B z*£r>íR±…/v8f©ûN€÷êP+˜ß'´IîâÊÃóÍ]®”×¹„Re,w�¯ ®òeèûQ’IFÍÚÔ"½XUw³&{ENcò’^Tú#%:‰îšÚh¹p ù›Æùý¨xΩRx›J�ú8o½gµ»¾»U1Ê¥…rãML—Qš]¼• ËeÆ™@¡u67´Çü–¾’KÒ´±\� eÁÍlVV÷ih$9m�’*çÓ›úºÓ'Çsª.™2¿½ËPìÚÀû,ëDÑÏdé&A#è³<ùXÒï÷(Õæ¬} úÄ¥ª3ê‚îÅÐâ³Üã`ÎwmÀi:‡R[ëìðä€|ãdÛ¨Ç!6Û¡ý„"‰›íæB,{˜•誡äcÙÕr*±›$j=r˜B«@‰ÌÊô>m>¸OgSÂlWš¢�fL1¶1“�+ú°Ã�™ºxãõ ip€³6àzWþˆÂuâ— �Q3E¼Ò[ÏæxÒ1Yâõ9£Àf݆›qFKrx^´'xÓÝä?ñ·S-{8*뒣⠨×+ãïd¦Z¦s{Óø¶j=_Él"­ÂBÃ’Û¼hÜlÔœuû8&‰ä϶yÙRã=)| ›O%®%N±UÚŸêD†Þ¢åÿBRw‹ ¬¨GbMnum Õ¦�Û�•]™Î!Øœ‰ ÈT9ŠÚž0ôEêŠ17¹.¬óÒãùÐe6º‰‚uN¨ËÚrfÖ—¬Tðb˜k0€ËMü× $é‡î?w±;~s¤, è*ÙÀ•€â ¨mê«z££öŽ2À=åôrá”]ì š4&•Ñ–Ý+dÑÖ¡�{N7L¿TŒ'–Ï»HšBm¡ýíß9…¸vFw׋Y…BO¯ޤ7ØìõRgî}å£ÙUù†xLÁZe«9©û²ø‡‰SÎ]×Z�b<mæ®Åòõ‰wü./F›hœ)'4bo‘s_m•Ÿ–F G€<RyÊÜÝ€Š! V +ÇÏk^š°ë©-”Z9kûÎI�½}­‘øIâä;üœ˜Ýã”ú¶Ø;V·÷Ľ‚w×îIs¨)…HT« pêRFFYîoEZ¦!™S°òFÃ�ÛGÃ9È™Ê2Ón:u"³\ý‘EÑo�gø¹îÈt0gsa«‰ƒäFݧVæ¾{¦æÙ{ÉÂEØ–WªïZƒ0ãu~�Á¹¯™§k[FÆy®õ…ûs>TÓY4“y¢?°§<솷z McìÞkñÖ]s刜9Ê6oðLzwÏ%ñóJÉ‚ôø)p¨<;7šzsÀJ\ZÊÜäÐ%ß0sÁ‰ËzßÌ£6kϲ¡$a¥9$£c�5:š«DðlsÏ�3;šd«Ú…K w¹·Ï*}" q0é¾_òFY²õH •ÞqËŒ� ü©;‰éÙ÷³@à«Às kK‡YàÚZt뺃©&·|EàÞ£ë-Œ±dü_JXZ3ý|ö~RÓ�kåP ßø–?N ®ØÜ=&ðð&LV­°e7WHÉS :z$n¦ègƒOk&;6*⯗ì±NX\|ߣ2¼ –•3øð£ÑÜ?ËÁ],ë¹N<¿sX@t\i!_rÒÔW"~ZºI] Ñòd_–î½ßÕ�°jôˆÒë¹íp™vŹ݂7œ†Q4•€'Û~ÁຳÂ*�@úýpª±Ä„œyŒý{±ð¹ƒ ìxvûþØôe½ö0$xëf¢¶ƒå`Ð�H„Ù÷Lá-±â'á»Í6<ƒü…#ì5 ÊS�{–r5;$<1ƒì_yIÎO¡|W2àb}½Hæ¯ÙJwœœ;Gôå©,ûWze–9}ÛË=ì:oð»VLr¼vÌ-XYÌa=;Þá<é,ÛBdî#$½‘,}‡Ð³ØI®À„'äwî-ß3„¬Mç?J¶;�ÔÊË£ë†PÇÎlûo„ÇzL'æT|DéærRWù Í©¸ØŠNò¥ =ýžšGsVsÙ/SùhdÃð"TCt_âá-¹�ÜÊ|›k3–€m<b;aýd<� ÞÞ)>h`M,³í¹N·Ï´ßpá:ÌûRõ @­ÜæÏ>g³À=áv þ,j¤8ùâÆ`ê·AÏùÛoH†Væ"(R’i SŸ•%û”Ï›O*¾s­½:œiG«œéèƒGÁ²÷�T¬B»§*Î&Ù%SÞÙ’5ü ñ7쎦fB(£ŸfÉææ¢¸ D쯙ve¶šqìÕÒî{ígØl7Z¿–áŠxÙ¹ÿà+I¿Vo¤ÂÐ,^Y�¬—=9²gòNZýÒƒ¼†ÚÌŠêâݵ¯k91øEŒŒú xï°w¯9_Y©íì\2ô~%ùˆJÅ/¬g½ÉRœ^†åP¶+ó$•8}¿g"‹þ¸€ëZ³³­¡BͶ¬H÷<Q8‰Þ¸œ§Ç</Õå/z‘‡^®‡b¶A3½Ù\¥äx…vºmQ§`Ýrâ0êf[¥µSŠw—eÊ�¶´ô(! ShË��‘c‰¼vš/?1K Gö ”øAˆ]ˆ‹¾º¡Rµk~Ø�:ž 3„”…1½œ,ójŽÑ¬rñQf‚Hí÷iÙ˜Ij_^á­ýØæª¾yÓsŸq[ ËÐKdKò°üó‡•tä-" N]NvÀú�ö_¯Öy¥�Ö�-›: �mËU¸#Š#€hµ-•¶Bí¿P.RÅÅ3ñsy]À 6ç‰7ùïæS#‰z‚X‰.¯E?º{ßòu=„òÅÁq²µd]ê jóáÏäõ6Jj‰è£-Xðu.»—„h»�ÅÕ§jJ1̰žE�dž�¼Ž4W^“C¨ä–“?Ë [h³*YÒ?ä)Kò¤çsÿ8ücÞwÿèR]�QÙð“óí3üèØÈšåÒR9€ªà—#ù™úøŒÞ.7¡e_JºZ³E¯�·ÚøíÆ©¹)Q’ÐÜAqÀÚ澋h{™eôñ‡' %°ÇYÑÐ À:Fߣ®ž�®Ó‘õZΤ¨ ¼(Û@Âå)±õnô�ZŠ„"ìý5 mA.•/Þá?nË…PÉ�ÜýLs‰”+Ýëz�±ÜÙðs´Íb7•±]rÜÆÙûUÇ®uÊ\pªÿ�ï_”AJ>£kQr1{FD©d´Ÿïn?10ÚÖwiÕ7uÒÃ$"Y(0¾©i¸§äu“ô'Hù1W%¼u(1pà,èºæÙƒÏË£BègL™þzCÆ)JÖ눱^ÐéÛ/g@-f›Ú¢H"hŸÒuD^@,Ñ�+KÏKi‰ØGîÜÈט)Í üp�±P_¤NŠWãÞÒœê>KLÕ«•Õ¥`P�ù.LÆ£5»“ùÉlšŠrúó¼™åUòd/›uþÙ¸áú¢ø ãç�ìÚçÀ9Ù=ÌføQfÊNLìÕ‘ëjÅ_oýle—®î)-p¸¶Í`9Œ Ôxsh=XRàëÚ`‚�Dž7y"Št¹íÝSB>º×ß5±?sõ'”ª«níŸÔÜê�½bÁ÷ªoD°x ¯ ›á]X§qÑ­ÛÍýîÉϽ�žÉÅ ¼P©n"…Ÿ„R$c·&”ì-AÄREѨ›Ü®=åºyÏ�7#–|ù&¯Ó¸Ó×AÇoXí´sŒ8·^i<L5ÂÐÌ]CS�’zYÎè´z+UÛæ_€Œ#Ð# Bf¢.S–Jëdz:&|Ž„Gb={: —„RØ£ü í#•ósŽwøÄ¼‹J8âçÛ:T‰b§R·÷ïíì·ÚMEǽÛ�cl³2s¦o!Æ~LÁæ·™Ô]�–Ò¾ÎÈ€–”)ÐöxÜ7=mømŸœlÖ€9ÏXÍ1ìq3"oZ:ë†ß!®©ãz­ &¡(WÇÑÓ ¢½„ÛÜ ¿YDp~ m[º=œJ9¥Ðr¥C½¨c×ø>Õ7 u·j�Ý·°¦ä wà´;åõÇRõXAh)l¦Ø�xòiÊø‹üiŸÀùuaš³©Añu²÷Ø¥|äàô¶ÛÀ†—I KÓ%êP÷$cLªRƒM®�±¢ßta˜#~Š+|Àc‹óg¨X‚ª\#ïK„ô,íÉ))ìÛ×^#õ5¿�¿—X. •2ÐÞÈ»êÕWµS~bE”}mÙòGB5ß‹¸ÛîaE÷")}>7 òó–s6ß»Yî•/ÝÏOð “áµ+4H#“VRˉQRDy:�³=ØÏt=FU—–©øOßµ¯*‡’}÷óŸŠ\f ­Æýǹô~66RKŒßÜ��i”x�®*yÁøíäù8e»ãØ mb¼ÅVØ\½”G¬R@gF��ë³Ã‰íx4NÂtâò½{ú 4X±à§�/,A P�f?ü=ÜU’Q�ˆÓ ƒ¬º­X1PÓ87’š|p!-T¿2Ð]—¤¡f0qþ8Ï™oó¾îÐPÉ ÃJ™–,¸[d»BÁo§WL"-þ†,Zg;;c%(!ðxÍR·Ù¤÷Ç“­\ [¨”*S²5Ú��ÁëhÖdÀÀl˜en-ª7ÐW*«)jg\êùñ·�¨~|­ýUF-F�# ò“ 8NîÜQʽy;^HŸÚd¨�É ÿ ušð†šCþ&å£Í�k<b¤wgF‚KÜF'èlEv’Ìj]ÊštôºÚ8VñbÖŒf�ðRÖNή–²a™|ä•2©ÄØwÇ~ûÀ‡‘r äkÉu� v"ùöp|ëÌÃ×Ìú"Î… Of[a|æ_½gÚ-�ýçߦÚï ´²¤´C;èb+øéËíš„CÈCª:¾¥fî1U¸ôŒ¼ŸQÿöÝ kûc÷íÈ7µvÍpG7æíµÖ-…ôoŽ޲Pqe%jîR‰Æe7§øÖŸÉuüb{ <~º4¶n�EÖò¢ ä²7qMb 7-8–¾>á& …ΞWDQð²îúˆFY}N·2Ï^Qèk˼/–i÷ÞúÕNJ`¢wÄJø´¤�/Ž,ûçÇ BaIÕ&W¥uÐ"dRSÜ!s� ž¥ÖU}ÊîV‘Ò±„çf̺о�­Û;¼(oÕÂCð–8®d»-ÛEÇm~x¦ø­á–c�ya*Çàzµ¥î[ ©aM*§(Ȱ%2O¬èO±þ9�Ñv$+öSÆFç†Õ(‰JÁ¡«ËúðÖ,åÊù”õ“x±ËH$6øÅŠý£¸C•ЇRߣ¸:TS�3¥Á�ºÊî/S�ÙŒ%,y¾ž�¨“¨Ï{°.eßüEs²¦­®ù“¨k@à&¶B)Cö{™oóE»ÆA‹°ÏbSe; xZóç¯ljî“-‰Úïñ(²Ès—é8ÔmsßæÝòL|¤ÿÎ Vdq¹/-’üA÷æ7ÂÁY±´Ãxî<@‰©…wMç[õ:¢FF#`³†L@.®¼T¢UvÙ3`ÿf}E©<…¹? ùêY5ת/­ºº€2O¬·e°™Þc9SÑQ]2Õ‡£¡YR#Wˆs÷8É9›k1Èð¬¨Ô­´�€É± Qmɸ §¬g½5©o¶ í ´nWqXïïN'‡8‚�s«€!w+.oÓç=¤ð Ÿ| �аz£¿p²­Ñhó²¢=yÿÀê!7u¥R«ªýÞw7ƒ+þ�…9š–óö5f^áUÞnpô&/šZÄç™Î.Ô U46}JȨ^:cÁ(Ðî®dXè¯Fº·j2‹F”ô[<ü Í÷$ŸËé$¬å72°ÐnRÔ·½¦nF¨HÛmà临Ûoe f¥)y²}Ï÷ý AˆßÏ}�à�‹ k�Íôgö}G;Ù»æ52ànÓÝ*ŸÎåå3rWlÅžZð*’?¨ÌýeçCÝ„€fǃ\•�(yGÝÜE'Ê<av;ΞÚpZ¦’²å5šIOL“˜8s¬‘P— }?5£­oþâ¥Ý{U.Ê…µ¶ø€!¼¸»&ó%&…žðûü#è*­®3E¼®v•!§UõÈ`‚Jéã•ppÏU·…€'IKƒ¢B‘tnåcrŒ¡ûSáÖ�ñÉǯô¼þ~3& ò½qPCØH'ÝJ/^µÇˆ$C'Õ°¬îlr}û8c˜›tÿ´Ô]øÞê®I—K0•È‚WšÀzb|Aœût6šk`·Ê-q cj/ðJû°}ÖutÚ)èW¤S[%46äÝ\¦ÚPññê\Qû í™kUv]ËÕW_°ƒØ¿Y »�á7«¯v¿[Oü~ëcdód£–’\HÙý-í¢†¤´wMÔ\ö�ynêð¾Ë�ÙÇ–f†í“ ¤´ ŽÄê®Bõ&=nä¶–§D{ôÐõY}Bv×� g“L,oL*y7˜6µ¥2‚M¥Ð‚/\Ö>ŠÂ ªªèY—ø°¾Õ^mb†æ¸I[+ïëM˜9Ï�ÂÍvW “ýë@†˜üH*+˜®¹Ì 7Ë�úf�à $+:úD9<csRvˆ�kÕÚ(ÚûF,-#/K¬â¥íÚ?4»fx|w™):¼TlÄûµbÊü ÄPkV+õÇFšâ„îËY¸€hS¶áT_¼yÖýó8N—¤$L/ô„×fA úuæÐ2‹Ä<¥ú±LÁÙ;šƒ7úQ™èücK=ÜÀ_¬#×Aç¶W#üQ_BaßE¯qç-É6sÉêÓ‚½7Ìû]ÆS>¥ àGZð-MÔΖÜj¢…?Ú j(zo9ÍîªI²Ãæu‘r¦øªå°Ö†à�¥!o'ª¾Ú@•Rdí¾Ÿg±vß,¶µüVÃÎýÎ"ßœ,árªè>ÒÏú«þ¤£¼@F³3m-ýöðK‰ùb^ïÚUmÕQ³é1–¹,ÇW)C¦X DÀ”sxIë™ó±Äsb}J¸7»ù™Úѧ0>j´Óeq3ý8“†�‚pšÌ‰òÃH ÌyÜl„õ>0C_³ÛiÁîúKÆPeýÍEý�%œl7/ëÙŒˆ±Èc²QF�-ƒmž°tʆ+kéÁ~Q—S‰ÍØ·’Z39»Ù.Èâ/¼‚Á×L‘­è·×%o~¾]íþ°$¬ô9ë«÷ôk­�Ê‘ª‚Œü ¤XâeÍQÑÅajÚ§‰Ô®×ë9ÕÞìG-•~qrÌÿ€ª.© endstream endobj 102 0 obj <</Type/FontDescriptor/FontName/IPECWW+CMR7/Flags 4/FontBBox[-27 -250 1122 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle 0/StemV 79/XHeight 431/CharSet(/one/plus/three/two)/FontFile 199 0 R>> endobj 200 0 obj <</Length1 1373/Length2 6093/Length3 0/Length 7034/Filter/FlateDecode>>stream xÚ�tTÔíÖ/]Ò%È€Ò9H#ÒÝ)Ò 00ÌÀÌÐ-Ý-�J#¼tJK·€¤€ €(Ýߨï9ç{ϽkÝ»f­ÿ<»÷~öï÷°±èðÉÙÁmÀÊpŠÈ/( PÐÒ >â"bc3„  à?Z"6c0 �Ã$ÿ—]¡Ð:E í¦‡ÔÝ¡�à#�PT(&)(”ø—#! Py@ì�Zü�u8 Œ$bS€»z# Ž(t•œ¶\� „„ïïp€œ ±Á�Z ”#Ø]ÑÀm!`”÷?Rp>vD¡\%<==ùA.H~8Âá /À‚r胑`„Øðk\€6Èü{0~"6€¡#ùGm�·Gy‚`�Z…Ø‚aHt€;ÌŒ� k Ô4:®`ØgÍ?¼€¿¯�äþ;ÝßÑ¿A`¿ƒA¶¶pWÌs�ØC `€Ž²&?Ê Å �Áì~9‚ H8:ä‚@A6h‡ß�ƒ�Êrz�z¾¿§CÚ" ®($?ý5¡À¯4èKV‚Ù)À]\À0’èWŠØ}ëÞ¿×ê ƒ{Â|ÿœí!0;û_#ع» Á nî`5Å¿=Ð*¢ÿèÀ(€ˆ   ˜�v€½l~%7ôvÿ6þV£û÷÷u…»ìÑ#€ý!ö`ô‘/ä î`ßÿmø§Dì ¶(€ Ø#úOv´lÿGFoñ˜ ¢�þúýûd�Æ–õþ�ûïå èšè¨*éóüøß&yy¸À—ï‘(€OHD�ˆ¡þÿÌ¢ ‚üÝ…àbÕ`öp€ÄŸfÑ·ô¯†=þÞ>çßÄàü3—6�X0€ó?�7´E€ÿß0ÿòC÷¯,ÿ€ÿw?ÊîPèo+ç/óÿa¹@ ÞÛÑxuG¡±¯G3�öß®OÁ誶ƒ¸»ü·U Bs@æ�ý÷%B�Ê/°�.eëø*ôF¿…ÀÀºp$ä׃à þ— Í*[gô£�Dãñ· Œ&Í?K*Áláv¿Ø%$" �! o"ôŠÑ’Àˆ¦¡Øë7‚ü08 @�ç°‡#ˆ~íSX €~–~)Ëè:(Oøoù…lÝ4Í~ÝÅ¿äßœƒ½À¶Dó³p[©P§šÐÖ³j9O¾ÍQé)¶Í§\|¾óˆ6÷ Rü4®ªœç+ˆ¹´Á÷äŸ>+qË.0_û~kªÃ�hNÑk¹ô»²JÒŸØl!ú8NÛ7öú›\m/!#Ÿ¡ì–ßµ›Ÿq°3vf‡:[¾›»8©nÕ™g�ŠWmoÙâpøì¦ÞV•¨Æ�«²I¾8£Xóàâi¶W6¹3t¬x(>&nÊ/²éã“)Ê—c·ÌêI<Dþ»q�Þøš® ÅŸÏø,U !;éÒ›Ò1aSO°ûÊo¿P¿;ç[òf1œ>CÛ6²æ’ „nsúljëŸ!v~Z²³�IrÒÓ `S«ÅÄ®4«&»³$ã ç|R_ñRû)ÖdƒäÕI†Üê@ÅjH­z&j3Ú�¢R[iïuÓƒrÓë+ýQ”^u¼�jêÑ�zžaäí~(·ÀûIt)ýi/ ¬ž9“æK®ê:*¥J(9Ì镤+ ;x™z«™Éð³$ÎàL�i³ÌÐR8˜Î€ç§Û�íšF«m«CÓø¶Rn¤øøø�|µqßçnV.CǤ¢1K 2/¬tœúŸ½Óx;‘\<ª+1RŸ]0Þsß•ùòD5§�5b˜M;®EJœÃæp�@�*δ;­3Ŧßn•IJû°²ñ ù(rD>IEæ7ô,¯…(sA%ýïßV=Ú0!JÂ%aÒò8Ã.aSÑ>hŸë½Ë;YÔ&`=uÊš½‹­ŽKž¨#ôH|!‚ˆå³PSyn»Ñf/¶1T4üShnä^ÒB¡¿!€ôæKIi·ì!!» 5íJ-¥¸#Q(ͼ¯¨N„qE3¨Æ“#�GZ§éH“ÎÖáLwýÝW�$‰wÊCÙ>4läÏËÎ(BÁ~ב:éS6û!Uôí/¿~5&,Ö YO¶ljì ŸŽhyÌ¥UÙþù1–Ë N\‰Ôð—IŒÉd•þ:v@ SƒQê/÷]tCìG„«§›¹˜2üµ¢²u‹·„Æk @‡¸áuåãÑ�,ÒïË®$éÆ þ?c}ë‹›QÐ0Š@Ôuž•=™Á¦4‰¦4mg z¸{² Iþ.†¹ÐD‡¿mš‡�ÅXº�6¶WDöšÏ(L±kÂEëÑhÝni(Áî9}d{aÓz •1ù�þ<C Êµkž·â]FÕ1/_× J[MZœ‚S gëöûö¥IÊ{=4Q„�Ê;ZÚœ˜Ñ뀙i.œÝf©VY-ªáÂ=yí• •v“ãEÙW8 6Œ˜D÷í¼Aë{“EE\3ço'± ýfû¨œ®îCªwF–ô2I'ì…¢ó†~ˆ�žD=òÚ3ÂØînsiŽo;¶vzc;è\÷Ð]²O¿Œz>,¢ôŨ™¼eæÕ(ùËÇ»­ëõ3ü–ÏØße,†3&—$�O^“œu·´'5oU‰;µûЫM-î(¤³Á[¦®Êã³t`â ?õ¼�Rl}1Ä�7N.”Ä©Î2tè7?ÑE ’“R¼=³—ó�zÕYb¡f6„úì]p�âºD`@‚‡—Ïæ‘g“ÄÓÄ31,ÿܹ¯‹�Rнo>3k…MŒ�onF¦Jïy_º^t¢æ.ã£~X]¥ —|‰N"K’#¾Ð²àMëd Cæb.ך¯Êº"&zФ–˜“ ¹B#ó#ŸÁ€î¯]íÌö‡ö Î]¸,PýÝ �ŸA1±V^a”­ÛV÷ÞÃ36û~‰—¢jz�wªQu‰0÷<~ÕšèζoU“¥Lby§[ºp#i›:m:w \!ܾ-ƒ�on±¡£VÿIëz´6Ö(Jöh¨¿çqS„¢îŠnuß§pk#Eq",ƒ“êì_õU’Ž@i CF)(¬ýØ�–Xšâ°ka›ÉæD�5l¼ÚÍPÓBÏ<¨�ˆZn8ûl¢o²Gk$åX+>- ^ÎüÒK³¹=&j2À}ð¾EH‹ÕÄÄÂLj‰qþÁ2Ù©†ûY 1ýð3̾<µ‡ fŸžñª†GS¾iïU[x"”5OÌõ-ÿª¹ôíÝŽ7u½>1^±¢E�.)a´ø&'ÊÆÑ©' J:^êáDNÊ.E¡Ž\ô&ƒmدgÆ#bÄëCú™bv^ø~vÇï&‰ ³-äÞ”*Ë,Øl®ôc@�+nüNG)d_÷LðQ0:}“³_—ø«ÝøÊæèU-!¥8–áå¢]��0ËŽqksƸæmê1mÊ 6.š Ç‘$2ÅZÚ{Ú«òïÜãvZG°³ß7Ym&‚ÐŒðw#0<ðpqR˜Ý,·Ñê¡”tÈ[ÛëêŽ8!ì1ÖùF Ýú’²PFv¿ò�ß„·Ë)ŸðïÐ�œ;öaÊ'^O/HãÚÊÛþŠsE6š°Ä‰ºñ%„j‘qìS]¿êMXXaö÷ñ6#½ÿR3(LÇÉîÉ9£4¾eµÜsÛ|”£ôÁÃ/3“§ÀÐr_ㄯÀY&öÇà÷¬©dþ5);_®™5WyÇ»<ÂÛ îF„w¸kÊ·±Ö$/\RÞH=fbC>ÇÂGôf}PÜ${„Ç•]øÄ)“fƒ¾þDDzøî�¡«Gœb˜ez"uO>slÖ"É‘×ÃŒ¿öxì¡G^ÉIô¯¶Äºª¤×é�¢O4Z >�áÕA‹[’ô“Ì0…¢å¡OÌT_»…èqûš­�·"2ŸW¯�Àn´gÛø]ÇŸÄÕ­œTw ÚΧRæõ”ÜíÙ¼Þosº°`bÊßá´A¸=s£wÇ´-WerèŸïÁ {í*–ŸRP)ùN{^OŽÆ³u/|fæYÚ�àïzΜ~4ãï­N †NÅA)ÆçlðV#¡x–ŠÝbg&G=™„ÃWe\[Ñiìê¯î3SSMñ®ö/:Xа�î*»�s|å^4ÉâŽO€”A#~Øk§R¥ûº™2Vq`Ëö¯ÚáœÁ L�¾×¬=ŠG˜·½Y„³Â¨EÃg dw%²nMü…ÁzÄÐ.+1ÙT SF£žÒv�7r¶ÍÜãT¥r]æÂLRÚS¾uxÌ·{¯®pDŽ+6:5«ºæ¥YŒEøï´çú#05Ö.™h߸=ß0ÈÄææÐ¿�Î# ’lD)cZùëóÑíÓÍ“_g)'IÿX�g’â6}ٺܕM®�Ÿ)ÅÏ)òÊ=ÜŒfLŸÝ#C¯¦»—~�ì}wi�Z�Ä'Iæü*屨†{lÖ¼.´åµ�¼]ò-ƒÕu$#]ë ôpdi+±ðÂt}æ%-Þ®J=·œÆ­?³ _ý(ïUª³û€¼wÍž²êR ê®&è›ÍÍx@êfTfÖ��ã;;Om˜«-¸ôâ(æœìaø C®ŽÁ䛨ÊL©QóÄO±'â’_y}#kj¤¯±ÕÉ”B„Ìž¾UlöUìûÔÂ$ÑuÂÀ¡´œw:¾yù�x4tJ—œ€ñãªðÎõŽñ¦ÑlRB‘7�Z—ž+«Ýª®&¨2†Y'cœdyä´§}+Ý”f›âmycj„'DUzkÉŸÃXÚ Ü�½=XEÞ-*úÍbà¾7xº2ŠªçGÂ>[Ò<Ð9ÕЬOgûÈ™}ªu^=?ŸXØe”äÐìc§YÊ€£ß¨S•ÈÆÊ0‘„zý@\Óý�ã™Ù)"ÁJÒ™Ï/~nÐwY1zÂÖ:|wZõäpaØÅ¥M*)jª/b-ð•HΫI“à�½Æ¹· ›A­Â’œCæŸ _?cÆG>î¨Ío\}Ñ­Ý$³J¤õr€x�d‡£úƒU=_–!;Ž‹‚¹‡ëÓY™H}U¦Õ,½ Å-¿»œöÐÝ÷ Âo'P²WÛoܳ ¶¬Ÿ­LÓ´|�»] :„ö¸­Ut&¼UþþZlŒ·Â¥ë³Rñ×FQ‰'iSW%bªá÷äÒgèÚÀG•¾ŸÇßæÇÉO iòºêž¦,CG_Þ±wÈ“R»i[éJ“)`Í\”Ÿš�Rô¯!ÖÜÕzB¤´ÄÛ+l[4Ûå·CtÏ?‰4’wSúâK5uýˆ��ƾÐÕ>Vkô¥åæ¾åÓS#9c±·^z`šûJêÃö"˜úBÅÄNÙËý¤uÓ0Y,e²é,5v;¿æ4ôƒfc>ج]™k�Xp¦8ÎÚúHýxŽ>:4„¤"¨9 Pá6!€KÞ@›¼üHf.¡/+ w–Šê52±:·'Á Ðß8GŒ'ù’ôâ0ØcŒ@|#bÉyíSé–�º—öü½�Òb¦?ýC(ûsêvò,l_}c™u (‹“ñg§&·1y�Ñè6QŠyt›Ê+Éåz4áüÒTt¦HéH¬ Va“GR#iúkTÊ»µó¥�e;m‡2 �ÊhóÛ v2ÆÈ\pIê_»‹c˽‹!@ïõڻ˛xåÔ‘ÃÁžm Pܽ­²ŠwyÃn@å.=û| ÎjoKLš„yÚ÷¯²ï[³¿0c-lröF2Ö[Æf1*1áŒ×^³5¾ã$¶W÷‰þlyÿNvGZm ÖA‰> Nh$!ÚJÛR°ÿŒ’t6Ü´ñÕѵ)cÈÔ„C˜]7¡‘Ä”Àg¿WGSÆcm†V”´Kì÷ZeWІI3/}¨FUæTÖ¼ú·‰°¢Xkꋪ”O�á¸%µ�y¹“âªî~<!›0÷ì|NrĞ褰D<PÕûÆ}�îX£Íº¬zÈý}<îÂ�[à$Çý¤„ŠËk<€²ù??L,¿³v�ׄ{æô1"<'’¶˜ƒ¬ï¸ÉGÇß‘ºD*ÎOë ¼ïc…mUÙØI¯×'ó¤“.ÚóN#͹öp£ûzÚG’“û†ûljÒ%˜Í¢–�ãÌŒ›×kðbÌ“í7F÷fw_\Èš!g�1O…�Õ[dÞè”�Áž©›³º ÜÛÜ÷ñ¾ªÅeˆKýë7g“7RýJc>Ù‡³½�Öî©@5ÛdÇr²joS© Xæ¯z_yecvФ¾%^œFw ÆÍÊ΂4:š[AyÇþð‡¯Êù~Q‚Œ5´�üewWH¬»ŸG¸)]3þYgwžùI©��R!©&üÀy›ÿ:²gB;�!Ž]Ö“|Ò +Vâ\8t\÷âGuøÀÄX mz}šmNvà¤-ïN?Œø(³³½mŸ•‰ûø¦Û‡šS›3o´û² ;Óz?‹“¯¥lÒéÅ…èt ·Â`VÉŠen"µ êá„e›þÔ­ý$c¦a~ìf·6UøÌsÿ„<«®î °/„G¶l#ÄÚ¿hÆãÜÓD¸;¥‘M2Îs…lFòp^b*U¦ �yµRöªÙ69àå Ãü¾}úÉ$Ü“lŠ•ô¼£µíF_7(çuûº"ŠœðR•%‡k—íïáš9÷µy:t5×¼I b‹¹K»c�ºñ`U¦ÕÿîG�̃í ܾÈ#-¥EKqêi„úDärí&"V”i¥<Pn!KM=†#Á—OZóÐQê»ËƒJ½Æû"Ìvv‚÷Üñ”1Ï*Ø—›N‘NÄLû;ä{,¤¶Èê×òI #ïW7Oø·Ç,·~=ôå>J|YÏ‚¯c9(²C"UÔ)ºÒ7Ý£6”›éÂ×ç%{ˆ5µø!9iÖ!„ÑE«Í˜ 0oó"ƒ§²Ø’]À3{V¾�£p÷_Í}ûö vß ÚJ�šªø—ô v�Ô|Ó'n`ô#™u‰ÒA„ÈäAUÊcï¿ÌmŒͰw!ºí}¦�º¢>ñ ù“ª_‚·!1+m¯�¼Þú%žôÐO=XŒ�×ûÀX%cpW/ú¬ð³¨QÔåÀú§jœpAežÀÀRßQ}ÚzsÔJ¨rKC¯­ˆŒÜì±y­¦3PE5¾ÄõÑìä,('vú�\ÌW`6ôÎ8cZ >,ç“îãÙî.hAåQ «Áö‰¥Pœ†g„Çô¹œ”Úòä¼t}h÷=,°J‰ÿ\Ï"aÈü.hRóÅ;¥LRÈŠXkã:‡¯2£�е÷#Ù[Ï\“˜‹Áe�›C‰³ÝQiV[Ù¶--òdÃüÛwá˜ò·ŒQ+Bƒ¬ß•¼^ÖȩԼUâ–ßq)eüäy§`É–w°Ú‘÷åãö-^l7<÷W4E„óÓ¼/w:ô1âħ ãÃxÆñ�œÊØÚúÖf/ç¶»n›/Õ«sƒ;kžW“uo�~8¥ßÄ?UÝMlý �ÂÀ/í˜DÃ"fv2kÊÄ/ï¡!"ì0RÅ¡”zºqR´²t./A,êð>f@Æî¿7¬¬™-‚�ú›lç¶ÈH�©öW­0éêp+ ³YM�àëyGQñ‚y€m˜!ü—ƒ�¥FFÍ 2 J²Øîâõ¾Öc�ÆßX>Üc3V<,�ªˆ‰oΦ ŸÜjòÞc‰”¤-v²æ/enHûÊy.QóiýÊŽ�¥8UP*!á…€fOÌá“nðu»x‹\�'�xÒ>|\å·åõvLgEO¡~° ͙Ÿ•”T'³Í  ·¤“¡ÉCÔMk?¾�n&º_~5*õ^•o‡5$¼×ЎʽÒaºŒÍ]-áæM'}ë6–q„ë‹x‡Ê,ezä÷4šÞÈrÔíótºxgˆlÈÞ—tÍ›¤é=Ø!pk1²ö!Z%xu@Ï.;R§�’ ‰Í¿9“Æ­¾s�°p ÿÖÕñŒ§L£o1;8!Z¹»æÓ#Ðà£ïxnáÛí–xôž½îŽe<q9uÜ­÷e{c…9Ñ«ˆ:žB“¯TÍßÜ„.°ÕÞæ“îâ¼<ºç’™Œ”>cåtÝÔk->ÉgÕ×ëÜ)6pzE ñ~ÙÚFš©<o·ðbgI£t~™Ñ,¢tUÂA|å¯ì’~‘iQuðÉŰÛwì¹c&0°Ç4:)ƒ³ï~åµGJ§óÞ}ÉWÎãtôÙÂ�púƒ.ÝÛ€éâòíw/¡Rë1§KµK7CÀëÚ#o5Ù¬èxûƒÍð£b%ÑÂ9ŠÇ!£<KŸ=sò³¬‚ßð˜h†�jîtªÉ<ØÊ¡wweîC¬:”4ƒR#iQnÒçä_´¤«nd.Ü¿8Š�œTnK=1g_„¿*œÉ¬¾¶ÿè'¶Ó¸ýÕŠ*�²Sîgÿ_BÈ'²{ˆ�Îñìa›Ó£ °ÊùëK꘱V; Emû°|æª�@QÁ¾ á-ì¢)ǵÂ+o‡§nŽGV)?›¨¼Õ1º5¨2‘(ÍãÈbWŽ}p`4¶&k{ÔÖ…À9ks-£Š³>˜”� “åu`ø2Ù¬ÅoÁj™r§úVS‡™ýè×8tl®-ÇÔ©\–5\¯KF ÅPøÃ‘´…4ˆ�ðAðõ�MÚ7=�¾G6ç²�}�S›é±[ÛC]IT"2VÕ´V.^ÂÛ¡ü¿ù•á9™¼� xW_õ´-]†õ`˜´ Œå=¾ÚʯÒ1AD3½M®&Ä«^?ûö¨¶-¿~){ü˜å?µg>åcAM]ä½þQÕ?³a|ï&Ç_5¸þjzh­–g4D¾\­%¤&ÃJ=^Dt[)þÀ¸Š‹ºN´–´Ù>§•E˜T mÜM–ø$m÷}¾¹'Ý…”{ªÈMË0£†Ÿû}C4C$Më'{@Í–LÔÈ B¥N5S7ø‹ÔRÛØ*ñ³³™9?¬ÅÖùzi…Zr«¸ï. ä8$xªîî7ä{ƒõHöH=æ5=ÛŠsè]¯Îvê›Ã Ï)ö~ÍYÓN8?S� 7 ù-§) Ê©b ?øñ‘I#�C›¥¼Ïûâ>u…ú”"ÎóžÐ‰¦ì*‹m…9¹ô–å[OQä¾Eæ >Ow›mûXêÖ3z`¨ø±ÐŒû%Á}Œ†]Òn‚·âök•ó«;1¯ú÷òŒÎE»qò*Ë-ï» IuûF½%JçzÁ{¡rAÕë”çdEì�Ú«gJ. Ò–ë`^]ÔÒe|lšw3`(ö=y'¬ÅêÇ�!Õ£á°Íg'ç8¦‰¶ò •Ы¹ôÍ|[qM…¦`�Å e•°ö#�Á&þÈ"¿VÆU�Àp[Ý&ö(DÏ$•_éaˆ§’1vy”$–£Ïÿ�ê³ç endstream endobj 47 0 obj <</Type/FontDescriptor/FontName/PXOHER+CMR8/Flags 4/FontBBox[-36 -250 1070 750]/Ascent 694/CapHeight 683/Descent -194/ItalicAngle 0/StemV 76/XHeight 431/CharSet(/one/two)/FontFile 200 0 R>> endobj 201 0 obj <</Length1 1382/Length2 6009/Length3 0/Length 6959/Filter/FlateDecode>>stream xÚ�xTTíÚ6RÒÝn�Τ¥[ºA$†a€�a™¡ARJºA:$¤QR@ZZAB) ô}}Ï9ïùÿµ¾oÍZ{ösß×]Ïs]{fmN6cA%¤=T‰@ Š�d�]cK�‰ �@¢Dœœ&04ú·�ˆÓ ê�‚!2ÿ�Pñ€‚Ñ›*�ê"À]O8 "ˆHȈHÊ€@€($ý7é!¨‚½`€®p‰€¢ˆ8U�î¾0'g4¦Îß·�„‘––ø(¹A=`0У�¡n˜Š00FB`P´ï?RðÜqF£Ýe„…½½½…Àn(!¤‡“<¯�à C;FPÔà ê�üлAÿŒ&DÄ ˜8ÃP9Œ‘Žho°Àà0�„x" �¦:`¬¥è»C�uþ�6ùWº?Ñ¿Á¿ƒÁÒÍŒð…!œ�G è«ë¡}Ð�á𠆣�˜x°Ûc�¿[êJ†�3áŸùP˜;%„‚ÁÍ(ü+ f›Õ*H77(�"úÕŸ*Ì Á컯ðŸÃuE ½þ¯aÇ_c8xº ›"`<¡Zª0Ñ¿mNP4 ’–� �¨ÄYøW_wèoço3f†@w¤;àˆs„b¾ˆüQ`/(€öð„úÿ§ãŸ+"ÀAöP'‚èßÙ1f¨ã_kÌù{À|�+†~"�è×ç_wÖ†9 pßñ°ª™Š®‘ÿŸ‘ÿåTVFú�þ‚¢Ò€ ´‘�$%Å�Àæ1�Ãþôñ±ZG$ ýW»˜}ú»e¯?àù#^àŸ¹ô�æBžý>HÁ\DþÏtÿòÿcù¯,ÿ+Ñÿ»#uO8ü·Ÿç/Àÿã»Áà¾æz¢1*ÐEb´€øo¨9ô/éêB`žnÿíÕBƒ1jPB8a-(r[tû/; ¥ó�:ÀÐç¿Xó—Ýô—Þà0Ô�‰‚ýzÂ`¢@ ÿòaDqÅ<EPjþvA1úg]5éðKl¢â�ØÃìK„9kÌJðÁ¨Òêó›Ì€°‰Æ„�˜G¤ѯƒ„Ý<áh˜;&ÆAô�äOŒÒ~³�SùïõoYC¡>PÑÂ,"îò<¼ã¼N‰É[ðã(ÞÊjWt¢e”8šk³~¶ÆÔe;‡ú‘ ƒùŠˆÉÙ�&¾ýó1Ÿû¯rC–Ó5 ÐXjýëʇ‚…Cߎ_9AY�ŒNã’ÑëI†,dvV¸VÜ)æ³—�${Ä6Ÿ}*¾êBmÞ“ÞÜ€ÒSr¶t&tœR~×.öcK6ŽUô°å}òxJ«LO-Óñ+ìǰø3åŽX†o¾ëVñYÃïß¿ÎèÏ;*Òî­•¨‰ b ö»Ë–?’<È@“”{÷ ‹KYüT¥"-‘�¡Ä-‚kÇNrùûtÑ@{Ò ˜g““žJÈ ý‡oš=�â³rù=ËG̶9&ß„Iè[’£�ê28”9k°N‡3jÅླྀ´¬�^C×ÒOÝidYù™¥öbs,þÃ01›OôçvqÙI"¢Öirp©ÁO•% à¬î#Žæ‹—wÒ�*FN*-=6—UÏ‘[B_Ÿöê,n¦ N¶Z^w ÷D"9öYh¦B-:³wûv’^h‰Ÿ¾¥0ãS“@×kÏ!»myò¦ƒŒ òq Ú»4dï)JÏO°'˜‰‘šPÌ™èlbeêZÊ<R ž&'¥rݯ`y¶X-ñæ‰\h‹\šT0èáÒÄá5UÃÏ äõë7 {¾]·I´÷8%°Ñ.èºçlW¦Ç}};Ö¼›x¹¥l9r(9»\ üÃ4È–ªüáýǸïñ_7Oš ,”¢îÁ£S»§‚ÖmŸ¾aé¼7Ïœùrâso'wÚ¦�fÓÅ)î!•ý°†Ì {x ¼ª9A¼Måý�M´©Õ�X§ã¤…À£ç�cóÉ7b«3ÙÛ!î6[Mzîß+(«”dÜó�¤ÅÖktƒ¹¤ýq‰£Ì‚TI¾JQ’€'šBEgBXÎŽÍDpíEÚ¢]+ŽÇ-1 ½Ìï©Úê™…ïúAÎpJBÕ¥¾{ˆ½û l¡/ñÚW Ù]¿ÿpwÓÚü“j¨n+^”å핲㈊"Ë„™7Ej‡:W¢ë¶¢­7jZ+�šiþD"t>S ÔC;ÜÝž íH’óÓ s½›,FÙj©G¥{Y­ ÓØ'ß¹R×3á7ÕÒÞÒ¡À6ryƪžoÿ¥´f<�?N¢rn ”–,õð„3{9Î ÃøÇésuw÷n6žÁ˜!|ËQìû56AFÕŸ¬+Ý"6ÈßÂʵ+õ‡¦âÙ´nÄ>Ÿ~þ}“þ«Å[ô´¹lV÷›/™ƒžŠ<·*Ñ|oʨ¦o˜>ÉõXÿúÕ0,öQ½Ž“Öu,åƒ[Í„_<…NÖ4W*ï©Y“m`[4[žøA¢Ò6Lf†lÈXòjËÿœ¬ÐÓ�zS65·^nä�¼@øÀzYU×}öªoÍiÙt“F{×½ŒTÒæKps U�‰H§mòiGrÉ:])iãìá›JZç6Ø• YÞ ÙT¥ZCš~®<�3±0Ÿï‰¬1C!Ÿ�‡M ´ýµÇ*FQŒ�ˆ÷G-k; ÷„?{½J·*lý>Ïڢé_¨¸›¥‘BygÙ€;þîÓ‘¥ ¯¤�ŽFvgÓ2]…“†]…Õw¾ÙpI/Ò9:¹%TàºYŠb±^²¸Í¡XZ´ÉÇ)Ƕ€Ñ×°42¬UŸ7¼‘¤$9ýiŠ“ôa¸qñE²‘ßSªãcÇmÿÈ  Uçw'w6Šü³²Ö”ÓFvf/^,ä£D¹UŽ}—×êlŸM?S´†°J¥Ô#%p‡1|º¦uyÛU_ŽnïG•â¬)�\þ.ðÞ�©öx™î“+öÛ,>RI‚8V‹lxŸÏ.^ŒÍoMßG¶‡ÚÌq¼àŠýx|dM!OKØx�jå %œ¸¶fÛÍfò±/LrŒ½Z½¿0ѰJÒiÌ^(›°•véiƒeM¤$~”%¡,G±Tä…XÊ2Y'¨ÉJ¨ï`4yVAe-Œ7*è590¤X0�Îÿ˜9FzíªsG -­7N˜ñ¯$Ñ«Å:pæD}«Ü>̰ZçVõŠiC7>V›-nŒ †uƒ+²­O¶fˆ±÷ŽìÑ…ð”Lgr‰¤ŸúQ^=¶exFÛo¤�ƒ=6C÷3ÂW‰Lg­g¯dKî¥oulxͳJ»ûRÄÓ6i&ûºË2ªÍ­). {"¹2‡FáÖÕïsìý4TØ9C ïK¼Ù¶êÓG%âFJŒ ¶8>½h•ùÙù–w¨3^íÖüV‰wuïÇn&ÁÖfâ×¢XÂLý�ç—øÀÈ…n¦ØùwtÄn#�jï]2öé�J�¿<YˆƒŒ7�#©°«crt4KÞ¶i¿;9nÎçÍüŠÿ Ÿn bé›Ö?Ú^R�s�ˆÊV÷Mì•� b>ˆÒ û$w¼~â´m\>TLæ ð¾Þ‚—Š'Ì2ìQß™«žy“åË=õù;[Ê� éÛ® K½ø+F{<‹3ã6¢óœä l¥Ë«ÏnáíX±cdÛð�·0äôëÏ· ?¶ÑÔ„úæQ¤$,zݤ<à˜X\ÀÚ—ªÖ‰û|'Yw`wN¸æ”…v=ÿçRš±` Ò¸í¥·¿É®!H\ú™d¿ ߺI¤P‰.ñel*ÀfÏF«ÙÌ—•�òj¸d¨¶#“9µß²G�ížÜw vîÊÛ#º@)O7}oZ}ăŸð»†æ¿)�Þ{á­Ñª×Xn ’}[©í¹7Ç0Þ3¾h9V\�¬&ˆjx½Ê0ߢ´‘Úúª ïªÓ¼*´Â2 ñA�é±<2ˆæk|…V$”:–vay».FÒ³žkŠðJ”'ÀØã&zB9@,ó?B«zÍ`Ý””Ñ~Ç›RýÝ%ò?]|M²ãBz›ÌÜ?e¬2<({ã¤2Ì�tœt0ÿ²-ûš´ßõö�&Q*ËAÂ}è‡mIý™×Ë�,|{Ò±ã3Z� ‘.µ¦{Ú§T>.…mB„x£çüö"u³Ï¿÷jåÀUu ïህœ5"�'G�Üw&,;Wð ‚ŸE„ÏIc $CbùÔÄoe8D~)FƧû[«TÊsüÀQ'ôsb›ˆâ{ŠlÚ¾îóVPï{ÈÞhÉh òH*¡_ÛÛÐé}œ{.Ÿˆ i¨ÐlLTÞXÏn=±ŽYôÓ×?/ÏÝH¨áà1kNêÏBì¥v‰í¶Ï _À˜ƒ7Ü_žödzã㣒±Å}…,Âp˜§FŸñ~ùÄ\dR¸‡Uzê ¢]PäZUõ&Æå}PUäGW©ñŒeõæƒè »à sÃmN¿ðiú»Ï[ç-Š‹zÄÐZ¾ ¾®§B¸Ó·¢û­Rn³„©ÞR{šìî^«ÎWUþµ~9ÓëÀCÚa !‰¸QL1…ã(ÆWËôÙBækצü`G¶ ß貋#öhM¯t28ÙE–ŸÅŸ¦IÈ;±¨”ìÔ[§Í·b¡Ýƒ½dÖÌí·pïø�Ë"/!bÿtüFÃŒIG*EoVâ’ÎØ éÝ݃£mUXù•Ué¡ êN޻Ѷ/Ô˦‘9Xé·ð¾‰›…ï:NšÆì<0 <»œ �û›�ù?Ó#®`Ћ·…Ê–þRƸñ1…�ˆ…ßÉ])X Nà•\€K•¨8…ÊP¨dÎ×âäƒôÚ¦Œyfò ¡maõr&¦¡ÖPQ:Ú(wµ-[ˆ�ÙJìÌÈÐMjüº1ëæ~´7Ù¨XW¿–òÓöpGi*H¬lÍ�f»[™Õìä!Ç¡´ZQm¢‹Ñck j+Ïßûz­-™¸ØY‰ú¾ÓtwÃí<嬭�œÏJåU”«�ž�Ž�Ý\y¹<y» ?†5²8qb_ä™�#ý[Âêc�Yãþ‰“õŽëÌO<ŠË¬’Þ¿ò²û@ÜÑTÿ=Žî¤;ÈçLƒãgSxÉθP`aëØ�7©/ÊéÞ�w©�f¥Bê곓Båèk^9²Ñ]»É7ÒY)„'¼é�×m$ÕÆ£¸°ð8Û�Òҩثǥ喑ÿþ©¼Ûk·4è—aÅ18-©ùOö)3Í­ó<©·®t3I×ïøžçêy’€SñwJÊ;û…J°Ñz�%}QpÑçä-®JZÖ‘¼tºçdAÍÆEŸ~Z¦/ šCãðð²f¸ÊùlâY“¸/!ŠXdkô—\/†õgœu±N2îÕQþÜY¨äO…�Ö7ß)|èËíöu'Ët;DÚ�Ͷ »Ì°cñëw©^ŽFãÁêõLyRìþòÑ—.Ö�”ˆc1 ù»…~ ª{Árzç�®uÚ#HXâüÐÙ[òȳ/Hñm=îu-÷;G®Åœc½‚�£5×{HT½×ZÏ­‹ƒ‰;™ivžø«%Ó —ô>öY`XÍ¢â 1[ÝtfDçžú¹r¸ºrXßÞ­¥Á=„8¶^Ô’·«àš§+�Ë;Íp¿ 7¬}’bø)+×~µœFØýøZÓñf“”]ê“R¸¶?f”(’»»T†oñ¹iÇûsùÉÞ™éÎÇ q;Z·‚I¾§mÜÍ}ú…›�öê�E°É5ÄúÓL¬ë‘0�B…¨oþȸãIkí^ÚêZѹï-žõZ;ÎEÿJ&ò2¶CÖ\ajŧõÄqS¹Š¿zÆãñ�ÚÊ�zrÑI_›9Îð)ÇÇs9jÆ¡s¹ ;Šb^rk±JÆtÒ�æ,N>Ý@Mæ^Ƭí’|Y‡§«™×‡<Ü;êD¨]® Ô)É»£ �P,è´= î³5•ûém5¼§x?rmofSñÖÏð´^ä”4ÝÐÕm#jj'y0àÅÕ\;|¦²òQL«YçªÁÛÄÀÓ?‰ÕÑ6^wn�ÿ˜_0¯¦¢ÐôqF½úWÓsöví±ˆþªŽ)Ë.¨$•¨Š'í”�æÀÄ”­Ó(ëäŠ/ýŠ’ÇRK01n÷ìë¾¬Ý Íæ'¥ M™ÆgOV-5YìERšÖÚ5ý[¼Ã�l,'³Hˆžp¨—¿M×T]82cTp?Â÷�Ìh¥6XæT—kíPŽÄ;]8-ÔО7pnx¨×hÕ‚«5l»¬BphBë·<åH¸Ixg:=5ö2äšÝm̯²šÈì]Õ÷v�F„xd¡ø‹A÷˃)ÖôD]‹ÀÇHÏ»’byAä;�G^«;Ý'AÚKæþ¹ºÓËb s qºGÖßdÌd©)¼n&>"ϼn±&{=\ùf2at™U‚�Áª–¬B›Iq tãŠö3Ω©õƳ°d¹I‹˜7®’Å_Æ{ë¢å}åj#øÖCìUpºÚ�t¢û™”<ê áÜÍçý¥i—Ç×Í 1ë„`pI¢Ñdاž~²ÚN·�'ãXe_xò²o7È^¼3NKïñê9¼üªò°A¡ûnX»p²:»„©PH~û„ÿ�¶át8ˆ�}xºjRn7ä j{y/Ìy×zu®’í�÷¥„þ{¡ÀÇùÁèÝ‘ qŠÃ"³µ‘ŠþjŠ’Õ5//Y$cLQ¡ÙÏf+|7?÷¥à›Īˆ_jx8­™âõ‘‹¿áHˆÌˆå ¨KhêŽ!x˜ö^£rc^*?c‡¤°O×ëã � º,l} ù2^„ø²—c=fÝoˆýÆœþ‘þ|c”©PìÓøšCB#«.º‰L¤Þ—[Ÿ~p‡nöuˆÔPÍ“¾” ¼Ivøè¾nPd–GfšP¯pú(b�ê^ÖmVí(§HÜŠþ­âžŠM2*ÅØ\“êT`†|ÊÎ9 `g¨ø¡èõú‘§jDnJ4ià1WðUŸ”´ÐÕlYû¦=£—2„?H­›_�xH¼4Š .}bÑj ?�p:!ÔRß”QèA§Î'â›ê�AH]DUܬJ>TéKʇ¸š_¸–Utb�XÔr‡=ßg)¥Í%£é¹cZö|NoIJé಄š##�”'κÅÄø%}Ím‘æ@#ͯ&Y¨·�G�å+åßo}ëÖš'Épcà y~û\<M‰£ÃcKì<ËôÓ7½‘îT'ÛYlYj}y’ê Húñ>2éµ£öœWN)Ê1y±cý ûñ'²Ê6† ú)bߺù”oˆ5„y"Úq8^¬h �îü,°Õǃþ°{Kt3“ãåŠ]h  4�¡p_ÉGÝhp¾Âü«Á¡�©º¦k¬äŸ�7p¬cJí» ¯¶ÛwªlwDïLž�¦ðã’F3÷TÖY�çÖG1Ü-üQ¡¯XÌ©›¤º¼M‚.mš÷ ‹˜¹ÏØ*l¿>Ù{¤k¦N3 ÿ9ÆïªõQÔ\ZÞ1=°â@>qÞ×|"†Žl®úÙVèRQÚÀ^Öøéd?q–¨`pÈŠfZ'ƹ�;Þ’’¦�w).éJ³ò#åg¾fò},�jŸ±€T-Êg¯D3ÿŽº6ÅúFäüõÑ=ç²­÷$&èa¹ ,O: šß£L Å»KÏý¢îlX®|ã�·ÞǼ0¼R&šã\_|Å`#Ü»×v"Z æ½,=1Ânóqò›ÓƒÒ zGµYwv¹ÃŽ�9¡W ÔÞŒÊÈnÈz ¡þ·/»v”ÃeîÉ™þ-+åZt*éÚW*8ÂÞuynÔøUï†�ßr<3üÎ:©¢sRtœÔBë“éMø¡«”å‘zËrÎu.’‡ìáj)ò£Ͳv¸dýÄ^ß9Ïo.ÖšXíAfñ¬B¡Ø1즌.q+Uxá¾1‡h/ŸOÃ$ZÏ{¾¶ÔÏMØS*ŸÚóo¾Ò�°ž‡×ú|à–ð>Z—°x®BÞ­ªÍª�Ïð*Ò1‡ÇIÑÛÚ±Ô,k¤Çj'èán¬ˆú·mV2%1¯jÂÁ5ý¯©ZæfÑk^ÄD~MZ–/F@ ï©ío�æ\³ÊñóOžáÀ…ŠT/¹Îˆg8)}¶ãé¤èŸ(wÝ×\¾û0jCþ"©vÓWñSÿÏVÓÕ ‚߯z5e!þé‡w|•í%+àl\> m‡×+"ߤ:â.uznìÜÇêÅþÄžtÆí¹?@Ã&¿$öÔG×ÛñÔfæY*=ïL– ÿ ý„Ö:ýÙ Qr£òžF2Ÿ×[»7£ û N¼•�&’Ö:®Œ¯ÚósØç*á9ö‡§~²­õ™Z¾3÷Õæ®¿Ù‰v÷(wÕ%~¡ˆ§ØåzùD,-Þ;�6>ûÔÇɲǻ%ìn4x¾¼ð²’�^´É“(S š,~Îß·P‡*»wÄÍH@]ßZö5óæ}”ásÆ“Ã:c8e�Kÿ)�ÈÀè‡ïÅ€E¾¼ö�SˆJÛï¾uaLøæåú­Ú¾À:ÔLtŠBN—IÅK-r2hö¡XfŠÑtAt²E~H$jîu ;Y·¡yÛ“0ý«¯“I·ùôý¾· AZŽ] ©U–\—+ïæçÇ©>ïÈíJR¦ZÒg5žž¿>ÜPG k­¨Ç¤ ç*\¾‰ÉZ%±£„õø6Ÿ›´5�“Ò‰?G›äLX§?°o¹­�¬ÕNמxTy9¼×óA÷mð8 ¨.çåP÷Ø–÷ly�ú~a¦ZÍ´ãß^0W@â:ÈW=cnæÊÇz]¥”§ÕkçJQ~‚ðõöÉaØëïïî‹+�|; §Â©óÍû‘yA|nLy�áÞ·íäÅA8üEþWzè§:Ê£¼Ói1¹Ê�®ñËÂ=.8ªW{£ß¨¿FÕo‚È|RÙ³*b"+ª6 ç¿'J¸èÌ2Dÿ”D�cÓDÜ& �œ¨Ûé¹^|2^/9kΤ‡\ Hþ¾d:ú2³PJx¦³_¢]k^·l¤v&Ÿ\¶{ø2N<ñ ¿f†»lέ/âÅRsªÅs®ÍOS'—Ùd=µ/¼x²Hp#ý,ðUõ‰hN—4.�öjkÌê±€hô µ†ï&Úhk‰+¾Ù9ÑVî§a¢|r˜±£¾G_Cyà °–T©P ´G¢8�uŠ ³A�q×ß ²�"ŠÇ-Í-’S“Yù&¯�n{CÀS°OÛŒVw5*×ã h,¶²éÖüà¾Â1Eµhn½Íÿ ‚p endstream endobj 51 0 obj <</Type/FontDescriptor/FontName/DVCMRV+CMSY10/Flags 4/FontBBox[-29 -960 1116 775]/Ascent 750/CapHeight 683/Descent -194/ItalicAngle -14/StemV 40/XHeight 431/CharSet(/multiply)/FontFile 201 0 R>> endobj 202 0 obj <</Length1 1606/Length2 5276/Length3 0/Length 6086/Filter/FlateDecode>>stream xÚ­TgXT[²%J�|ˆ’sF2Hn²ŠÐt7ÐØº›œDP@É’Q‚T@rÎA$ÈE@$H‰M�äk½oæ¾ï¾ù53?Î÷�]U{ÕªZµK€ÇÜJ\ Šv†Ý@£pâÒR*�Žtöš¢Q&âÚh å©t000ŽFé‚q0Àta@F�VVV¦�tÐ~¸«²±´ûËò+pöû‡‡p wE‚„oí�„¡pˆû¢ àÜ`€ tÌÌí Aú€�>ÈЇ¡`00÷rFÀ!€ Caa€  þ<�4 ÿUV‚€¥…À�Ö�®Á|!0�_.1À†A±XÂ?�Ç®0 Gè ÀQ„ô‚Ýý›�Mˆ@|0s4‡…`à8€�Õ\÷ÆŸ<qn`ܯÜX8Á  ]‘P4ÄëWI¿}‚†£°�æ‹û•Ë@áXØ��›�æ��ÿ¦á……£\ÿb ``®` Ãb 0ì_Ýù«NàÿTöð@øý¾�þõOp†p‘ ––!ä„à¹]á(jÉ_ƒbˆrAÒRÚ¡^ÿðyÃ0¿$ôkf„ $ÀP4 á@a.Ô’ 4Ž�ú÷T–øï‰ü_�ø¿"ðEÞÿLÜ¿kôñúžÿ}à ���‘„øsÁ�„ ƒL€_;æÿÅ‚‘p„ß¿ˆþ{ -ìO†ÿ Ä&´A åJ�BJBêO#{î ƒšÃq7ÀŒ ôè·Ý…apŒ åï6âÒRRóY»Á!÷P¿š.ÿ§ †‚þ�9Ažß¼%Í µt-ÍDÿ¾MG™TÇYûyˆýo¦hè?¿0´µÑ¾@€¸œ, .£¨((IJŠÒAÿ"Ûoé¿Î¦`î Ü&”,%ý»ðÿýþ:9ü FACM‰Œ‚럆_nˆCÐó÷['ü�óï‡Á|aê‰?ÐÕp÷´ÌtÜ–ì®ÝÛm-Ò¤]= +¬_¾¸_†nI‹œU~ítZþP¢rPå¼ÖolÍãlÁHd±§…q­9¶™ËÄ'Üú‚aZ°^Qtñ�äÝBÚôuÛ耭O&3dö R7ç,,ïœ^ଗÅPn ßçó~qÿ ÿ�]0$õ]S}%Ñå7ykë‚OW®uôvwu6ï�·.°‹fÅQ ¨‚Y‚“×x’p~N|äœüØ[Ñ‹î›HS$:�Ñmb{Ñ�ötµIuêžèĆ¥7Qn¾æúaïR¬£¸âe’[/Kj¿«VA‘4?ªm–k2ÐÿµœX¬üú¸£Q’13¸µ™ÜÈŠö‹í¶ÌÆÏ*Ô.ͪ¿7…éËK"Uû}Æa­üº�Êê­'Rò|Ød‰Bõ*vPD×½‘/WOUzwQúáh1TNhð�ÑÔûïF‰+÷ÜSæ�.ôKÉzBâ»ÍX§]ó¬–©C4+GYޤZäD²%7üeÉ:ˆ²DÛ·¿l¦ö(±w»‰!5îO¨Àpõe™Ä÷úÛºäˆÇïèw^ uUvØ]ÕöMæ�‰Žëhýèí9>Éf˜ôiÌ~@«Sõ z˜öc£÷æhܱš'þa¼µœ¾Y} ¾R•UÅ*øœ!X$À©7„Þ÷ʯ-�6\¶N�]‹f£r WËr*iEÅŒë#=^Æ!„4Ê4é‹Ö}.�ÕÁ"â^Ð;\PÑíDñ4èWi—“ ¶~ìÛåš§W½Ë,)Þ5¼ËŸhO\UV°uø€ÿ&y}Ü�™Ü�±$Ÿàu<–Élü¤,9ÐSâN÷dž<ÁÇ+X²ÝN â™{VT%Í!᳕� ~rQÖ?½—.8ò¦:R¥¾À<”dBñ9æAªª•gtÚXtfØHߣjægUíj“)ÖÀ´o1ëO¾£'#òŽO×Kòu>¿�Í»Z9­Jª$‡f®\V’¦ŸGß·€$-Ã!Ëþ=‹£O ›duc$�oM‚‹ñ~,]ˆ@ûÕŒtL ÂØÑòâ½{ž—HRÕïÂ×É­užáˆT�÷IYd_J²Å!¾pudýÁ K„Ç€>n;Î6}òžV»i>ˆµöú‰æã¿iwõÇw^>Ö‘|Ýb#\+þÎ'—Ó�„å5(W^ÜsiÙ£Ñò¹”„/34ƒßÑC³›¡Ç3Gï”#ÌÎL¡4Å¥óäÔ0æx˜}¦v„µ…R YÙf­�€;y¡úŒ'èâ£Ä½À�ño_ÏtÞU YíÝÏVb88Œnýh†Õl68Yr—Èè’Ž6ä^eé6¿<Û>—¤ã8‚/ÅøU‰"2RZ_’§läqR>‰TŸçÌ16XžUÇú¶ÜvþBä¬ñÌ¡É<b=�÷+kF·¨!÷‘¾«)X«/¤dâÞÔ©¢:wD$÷xƒJTX̦ b/ Çæ!m¼·r.F£a™}Àymô<º^�‚6XzÉ 8�½"Y¼4�ûX’´ÁÚ¾!Sì ‚Qï†'¢:wç3kîou¥Œñ�+Œ_yÜ»–i ©KUÈ©’N1ò‡·ï¶AžŸ¦b¹Ù•_&ðV ÚbóWÜY^raoTwtÜÞ7wQ§¥ Czõ…<ž(ŒÝ|‰gõN²!Þ­Ó³vañ †JÊø4â>þèN%ã¤NyÛò)=Þàè}mY$öîïLÂ5þµÞAb`pÊ®n¨5‰ö ß¼HÆ%³Gx‹=¸ýXnõÃðæp¾=Ž1v6Q²qt¼©ëÊ}û|g;e¸7k'è+QÌ»¶£òRÐ-ú™¾ÖuåÜ;—šâÄÏí‰k) òK’¿òsv‘ૹ£ˆO*"6C¶Sá-,;°´ùœÚë]ÅŠÒ—Ø‚n!ZÌ ÜŒvƒ÷Z²1%Î¥ïðç!éÃr´×:ôŸ]1:kÖ’þ| õ+¯§'«cú¶8´©O“Æ�³9©ëë·cœ´`àû ÿ”ÎøõÖ¬l.é÷/<<ÙÊâSkNœÈ/˯ vV|öÔï?Á|W”~v°/UQÕèV«ßK$5o÷)  Äáèûëø±û�²&Ã6B¯~&Ú{WXµF:w0tnp+ÑoèÉŽ,[µhÓç-N ’ißóO¨‹¬+UkÀ} i¾è}ür]?M)¥ªóìíNž‚š ã†­\G3ÛÆ£H`@ŸWeâ)A„â¼7ñÔ%*½½ÔÚáy–?ÿß�ôò8T”±TæÝ“Î`òîø'ar�f+ÚcdÚCS*:ëd!�ÖÎ¥s.“r+ŒP%D`ŒéxIû8 ¡SÎj\ÔvµçúãŸþäçè,€²xì¯Þ±ô*CÁ—Ë�¹LU h’�òï¸vlùÏ“eå ó»_$•ÊjTNfSŽ ;MÈðäŠ�âLеû$|¯=?|RÎ!¹mÕª˜­’�ÇáS¾ÈZ�6\S‘«òì¹€¾á¨áÃ…©ÑÃ+yêf0ü4 0YL_LR[°´¹Aqöt8û5â�ƹñ�á"l³pÈÒ«\¤y¡nµ¥g+þÆ!F6?ók¤,KøðPm¹ yDZ:Žp^§LódËRÎÀôM³�ç¹sÒ‰ì[ÍV}Ã¥çKébï’R"+.јiŒ–÷öåù¡ìÏE^ÍùÙaÙp_Œy‚[’×WÜ• [H?¯ö‘ïmËmû#=;Îò°nù¦-þ‚ë«ó#ño7gfe„”ŠGö›îgÀâô‡ ¼ÂßþXþº—Q:Íã4û8†ß¯É[?Øâi’Ž•òQñ]‰†Ù—Vu+2{½s éŸVÐêîÚ ßpM–&­^»n‚Ýz&)|ãÍOâ‡× ¿X *ŒUŸ ¡Tþ,“˜;*‡Oo9ð÷2_Ãg…]cÇ¥õÿáß8ËÔkæÈo›fy´ÍÙQš¶ã`):ìXK¦ÊÏh.Ê}9&„“!5mýÍû7­Ã˜÷¼€Ñ–�oq(ùm|õJ‡M�rL�CIR>Q€™·àíž«Ä*yãј/ œõOn'25•c¶µv‚l*3C÷†¯eVç¼-š,¿|×o¬4è5yr\S³ay’ê0yúúe%yW#Å@ðjó|z×™¦½ àÚ8–ìÅ&JQw<O÷ÀDSÌÿŽR2ÝI°´èò.µó}{��Ï’W3/’åùÂÿNƒ:ùöâd!ÝÃN™O‹=è¨á¥ÔÓ¹*Jð@‘ Ù4D[õ€ô­®]uWB3´iBýNî­ïä�™?˜/�oÝ ÜT@©.4‹w x²²¨?Ô•äæ¿¹æQ¿Ëù}éÕ%•ûU‘ø(7µAõÎ¥ ·çó_€8,YùôQœü^hjä¡í ¹±A2÷ýU@4?:*g�w¸ëì­§vùÅhKo‰ê âÁ|:Z&š/J+¢Å3õ¶¼““Œ†/³a¾žM ÒdŸ˜™iìYDÝ3j"²Õµjj)AÔv~ X°�Ë‘˜=%§PFУ�E=�,­Ý9ïX#cø\�ñóëM¶2û«§âÚXnu•àêxÍË“zöNlõö1¯Í¡+¤×½åxÓZŽtjlsªKW…¤½òØ[‰Æ-3¨\otÏž½T¸=zè^ÄÃÿz‘6!{ÍžU))ÞJòàNÅ–n)9èn¿êœ&ýç‘�w·AG®H‡{.ëë4ÏG »P,÷ºü"1ÚØÎ¡Î£íG7Æ0Âó�´hÔ txÆ@ûò¨^É"z’ºÍ²;W½¦Äø�–¶ýK©NW)óëZˆãM¸+‡òüœúÞ†ë8¿�‰@ôº6Âf¶fÓõ,eôì´ßô5\ÜbÎôtY›6˜jŒ`Ó#Ò ÛÈ)Ó—bÀ›ïPŽÊ¡5‘oó¶ôÖmŒî&FÍ"I‹1û\‰îßÈ>ž|P4çºûízU…õ¥e~…êÆÞoHc‰gÌþ_¾_/!¯Ñ½•;¤åú˜½UH¼;|¡J—É׋Ⱦlrb|°N9ScŸ4»•ÕUüñ€öÞiÀ×zn Ó$¸9¯Ö'€fD\ÔMîýHê„\÷6ÇÇÖøŸ”w*iøˆÂ�–¶Œ/�î–ÛY!÷ Wl^«Œi]ÐŒ{S[ùÀ“Ï*îûû”’Å,èBaÛqóÍ•G\¹þ®9· Iû`3Dª*‡GDÈv—É£ç®^u“é.F1Rz¨d`‹m½:«ykù¢Óm¾}�úð*#@èä Õ‰¼øøæãs÷ü±cå4Ü4¨è’~ƺ̛™s §éó]>Z9E´ü‡ª© ¢+Ûô½¥M "þ!u·ÎÃÌ¿Î2Oj#Þ2QÏ?´™�?Í%í¡¢<t®ay¢x÷ýLLÛ¼Å\co›¤Ÿ&»Æ�åŠ�Ûk±ßž}ÉyÒ[Ì šØ—¬Po%¸dÁMI+Òÿa†krÒ»9ü©™ÒE Ø¥QY YÎ7¼3{ì(‹Gµˆ±¹Èdf :Wµû+ÌI4dsbR·9}ñ)ßHíR`À“¾' îÄæ¥k öš_ZKªS•y¨;ŸÂûð ΡËÉÅb÷gMö¿¹Yö‹=ƒn…4ô}-”O*=µi•HÄ1Ç(û3«ur)uîBÁZbácÙÐ\ޝ“*Ò,@i>^ºYP�Œ˜*od"º òi°ªEªp&ÚõÄåK©Z™©Ö™%%Úº?^ö¹ixÒKó–Yä€dRÜÁLEVHYÔQCņæó;åWÓ‡¯á?†*pÊÇð%¶¥6%­ïŒI‡•”Ñ ¬6¾†2¾žk÷÷ê?ºe,+4T‡W]öØL�6äGÖÝ̹á ÷=}#挲O’í*£“³ãÄ�íÃhÎ ß=½!ϵ@ó` ÒA¿R ¼r)z ú’>­(EîJ¡6Ó•n#wç\òiµ¾©ðeó3E¬)\ªàÒNw±–�΄"T¯Ÿ¢ŽÁá)�4Hiþ˜70}Efеñ¤‘4ÞH˜BtSh°èýh…„¨;²Ö`¦©ÜÉäèþ*‹]ðЀ˜ëª’ÿ¶Å'{þ#Ê¡A~µ’ÅÑ.EÞ�ŽÛ«=ÖQ{X2")®�iOò2CÒ!Z–§Å²‡JjLÆU RL‹Ýøö¢Š)U-¬“ó‹b_¥(Aªé%·¨ÚŸ•%�Ø› •¦.GßNM‹02wòæQzœ)~#:Ks¦|¨µ8¢·l'¯f¢ôûçFŸ3G²·.ÌíÍr¢Ô‘Û#{ÚšúùýS‘ÑáeŸ™R=‘u¤ïÔ<ñà*†™Ü]6Ó^¥yÈ8wIwUÖËFý+¬GQ`Së¥R^%5•á®<[t›Vy<MNE+2]\a›Õ±¿™œryÙ*Ù6¦õáSxÅk‘^êCé�¤³§·¼D5f›“u™}é3òõ©®¸©£jh©o<—M/{-e(Gû0­ZšZm,€q´;¶*úðüH­2'´÷¨½åòƒì‚̸ˆ“œ�£�Ö“Š£Û".—Ž]’O®“Žß|.õüÛ뉈»2÷³®´˜˜G_m¸êéôFÐÛ•+§/–U@Fñy�Û~Ÿ¢ÿ¡ŠÌJë‘çÃYRúš"¾fÅ®™£Î’àí­¦Z·˜²)ã7)_íœE$*!—ûYkä ©·Z×c´¡Ç&òª'�¶³y_ûdÅRíŒ0¬”��äÙeíkZ¿‘ˆ3VX6¬´ªáê§oÇý4Pª¹*,-rÕ-¸øþП—k1ËÚéó61ãÔ ïK›ÆW_|p�xÆ¥#�3Q©É‡œsRµ‡ÈË/ xà3™j¬O"¶M¼4P¡¤š¯uq¦yYù2nŠH 1DÝx#±Þkñs]ïbMCÂÏ&DØxÕ¬²7–ß °‹á oñ8 Ø~ìt‘âhôÅg âד5³ ¦~Ñï߆}k½8ÇU¼åmª»F7n-G·õ¸þ>8HB»…£Dz*œ´J¢SÉjÅZ7.!ô¸Fi0pM©"ƒÁQDòD”£XðäêQrRã×v÷•uÒ?¿îRvOåºq”øŸ1Üm°c/™¾�‡âÓZ�´ÅFÊy~>Ÿª=ýŒôPÞ|£M‡PÅ�Â�f&¹ uœ�ð©»íjûKC6w©â2ž‚l&lŸëŸ¢¤°±•‚êý\ÓýŸiDl˜˜éàÊǦþÓÄVÎ?剼NH¢Ÿ¶õõlèi%,ÝqUðг{9!œñ4Ò0Äñ›µWKÐ…!>²¬G‚7#Â×b† r2›>[�S¼hËÏÆ®0ÀÊ 'ŽN^×,¹Kæ4Õ=º§0ûÉBMÕÓB…Õ4jd¼ãbòLü¬äð”Yž´xN?ှ]“ õ0‘uîÁÙXìþ¦&Žzï›ágl€-âj¯Ó´3ºýq'êaü@¬Â�õäL®õ†Ïü gÿ¨M8NJÉñco“ù#F7Ãäû…¢Šò™íçP¯Æ·ŒV.¯^U4R>—3�•©7¾µ ç@Ø#âYF”ï•lšÔÝT¨JpÒy°–-~HÓ/pÎé½,@Ûtº=‡g#Ã;n�[ÉÒ,êÞ¢’€Qh5ð¼RVZÆ‘��û,ÙÖ ¬è$ãm«½KÙ®Jôê£V˜�c1¦ pÉûŒ£êæy[,KâÆiŸ °Å~p!3�ÕÛ|àq§Ã\q¤›µeSVÝ¢IhR\ moç;¼ÖËÊOå;…gJ hÕ©PÝ[ÖëîEgF»—™¤‚Úe Q#E}  q«ÄÖŒÎ&‰œg&Ù�í¶™ÍËJSj>fŽý[)xž¦úÆ‚º¯û'Cg Êa;4ôm=¯µ qþ­}’¼÷îÈË?‹LˆÑAº÷Ó|‹–jsñ�©›fÝ|Ÿ^:*z#²ÍŽI¶ÄóE×ëñžÀå·¥a»<3ùr6釃ÆéWîκ¶‹¼7¶¤/ ÃÕˆºª �yÇçkÑÛîÃ`ðÙt!ìÝ×;z{‘Z±¸©‚Ý<Ò« 66G" ¶1mÖžh4Ý{¶ä£ÕÖˆå &Îýÿæêeä endstream endobj 145 0 obj <</Type/FontDescriptor/FontName/PIADRO+NimbusMonL-Bold/Flags 4/FontBBox[-43 -278 681 871]/Ascent 623/CapHeight 552/Descent -126/ItalicAngle 0/StemV 101/XHeight 439/CharSet(/e/i/parenleft/parenright/r/t/w)/FontFile 202 0 R>> endobj 203 0 obj <</Length1 1612/Length2 12802/Length3 0/Length 13638/Filter/FlateDecode>>stream xÚ­weTœÝ’.î!¸KãÁÝÝÝÝh·à4¸kp·w îÜ=¸·Ë÷�™9³Î�ûgîùÑk½»ªöSOÕS»Öj*2u&Q 3K)°++ó'>€’�½™›‹¢X�IÍÒÚ ðnäD¢¢w¶4uµq�K˜ºZò´--�–æ�66�+///@ÜÁÑËÙÆè  ÕTÓ¦c``ü§å¯€™×zÞoºØXƒÔïî– G{K°ë;Äÿú¢º¥%Àh °²YÄ•Ute•¤´ÒJš�iK°¥³) âf²1(ؘ[‚],é�VÎ�Ð?�s°…Í_¥¹0¿c‰º�L.Ž–æ6ï×,=Í-ÿr1-�ím\\Þ¿6.�kgS°ë{\�6`s�›Å_ÞíVrtvx�°÷½ƒ©8¸¸º˜;Û8ºÞ³ªHHýƒ§+ÐÔõ¯Ü.6ïn€ƒÕ{¤…ƒ¹Û_%ýí{‡y÷ºšÚ€]�®–ž®å2³Xظ8‚L½Þs¿ƒ9:ÛüMÃÍÅlýOŒ�gKkSg �¥‹Ë;Ì;ö_Ýùg�€ÿV½©£#ÈëïÛGýWK�3+Û{Ns×÷ÜÖ6`$–¿Elå�`ýô»…›ãúÜ-�ÿní_3C÷NÂÔ òXXZ!±(9¸¾§ÐþïTfþ÷‰üo�øß"ð¿EÞÿ?qÿU£ÿöˆÿßó¿BK¹�@J¦öïð�xß0�À_;dêü…›ÚÛ€¼þ‡ ÿ¨mù’ÿYWÓ÷fˆ‚­ßùÄüéF)OK Ws ÀÊôÞ©¿íš` Kg� Øò]Ñ¿› `býôé_|@s;ð_­çü‡Ëlñ¯äßEú›:‹‚¤¶†Š6ÿîÔ¿£TÞµwÕðr|'ö¥(:Xü×á/ 11O€7Óû dbcçp½'äaeõý²ý Ãúϳ¢©«³�'@ÿ½äO¬þ¿ž ÿFlî`ñ׬¨»š‚-ÞÇë¿ ¹ÍÝœ�ßUýûÅ¿üŸç¿ÝÒÒÓÒiiÞÁœ?Ä6-3ݵ÷ÛÀ˜„~o7+ôÀÇ’:�Âü€j‡.ÿ´ðMÞ “çš/Ìõ|¯-^¿Ž_våè÷†ºq@4])–gyD¾t=ùèkÔmÜ {A,F%Ò�µ¿zŸÏ)lÀèq}ÒÚÛSU3*~†#žhcwF8¿£  pÏÀ¢¼uDõ3Oý‹ÝŽV�Q[ptL�xxwKÓ?<8ð³ë¶g—�!'‘Šß×/ùˆ,ÉÕËÄùO�ù+ì£;·Ç¿j0Z%4óqRóWß!WÒsÝŸ¢ Þ0¢áAÜù�¶xTéÓªþ9ý®eêßp؆‹òHç¥è&zë?]ŽŒÏoë©8é6›êœ± 7Ì`³š¬¹V÷b„<Kw=£8vÀ âÝó‘\ÛÁ$ý"}{—­ä2æ|'n­Ñ ÿîeÈ3©Œ�ÄÂë26Ñ«kçvÓÈnKžbÖÛÒ1éï >]9qts,Uòq÷D« 7Œˆ¡Ê–>>œNÜÈ�Kì]ç�FCèŸX\SkâéiÉvi)oímMþ=�ÖÆ$bÁqXòt\~3”G9ƪ£BÙÓxb ËQ¶Û¸¹€Nç4áùG Æ„ˆ=:MW�‚û†òÅàÿö¼¤ëd˜îç �$=*óSéñ/<§s¢]g‰«¢&bDKçû£l‹1Ä[ýRÇF½ÅC𻩬§‚y}ÇíO–êÝw±‡QGà¬ÂŠ磣x ¡ß7[zU Ž=iÂnÍÆÝ4ÒÏ,(ú¬›¥)0h¿Æ¬ýJ|‘ i� ûu•è\Q$²ÂºJÙÐþÊ…ý~›æª£ÒzRl«„TE ÷üjLAmËMÀ¡jˆÄPïyÒdõpÄ@”[¹M³ú»FÍÚz…s‹ÈÏ¿›‹Láñý=úaÐí²ˆòÛ‡•è\#žÕd¼çP‡›…îCqQ)qÇyizð§¾\¨²¬QŽr5�…=m—w$8sä(Øž©ø{”ÇŽk! Þœ¿�ÅRŸÄ…®AŠÊ SAâÇt[Lß(f¢é6µìú•4UÜMzqüNMø ~9[ÿ+3ØÀ¦»Ç Z9÷<;éUÄ®¼pÌ qË9FËaD_Ÿ‘ Îm‰(ÃPû½A£þ‰�tîg(âÇ’�ÔܳkEQ†.TÊÊw\å³>!Aò-Xɼ¸~‡÷ ÔB*®Y‹ …¬,b`§ø)Ï­™ÌïbÂfè<j‚¯¹-Jí\Cõ$g‡�:ÉžÁ òobçñÆË‚AÏþ(YŸ¸£ü!ðÄg~—W"Õ9ûé^ZÐDä¹C%ÉÇ�Ó@›õ]�<ƒiVíÓ Œ ÉTaßì›:l“:ÁO´.;Y×q‹ërßµnËÉÕø{ÃZ_>(44È6f +Ÿ0±¹éJ?ŵi·n áÇ!/l¸Ã1æô ‹q&õà•`”ÙLÈÎÒ¶¢*þXáоs�=”˜¤²O;U0@¢n¢Ò+a�8[uoQQù@ó\> ÌZ>œ†ßdÊyû'B(ìæ:‹§EDȽ©X›Ñ‚�õr›ø·‰âW#Ú>ºmݺ)UøÝJØ"µ¥f]•±X� )1c²¯òcàð4én[–F¢�mƒöذÞR#q­Ñþ|ÆX«áŸô ðMñ-‚Oœ^åS‹øý‡ºnÀ<³Æusy×Þ¼Žn÷�kš–êgÇî��§C@9Ô^ ÷ן§2qÊ`Ñy~ûXsòé1ª’‹š•Ÿ.?<ÖLTfÝŠ�±rWœüµ‚É(– f[*D‚& ‡'Éà;R Ï™aÔ ­é8 ºìX-ÐøxmÓ‹¡…³Še½ÝËÏt_YÓ’Gë$øq ˆô©wâWîŸf~+H_&V›�ßoé5AUÅ*︈jš71ìç¸Ùè…øN¼X8 Ÿê’z[ÂvåÐSgQ•¬w÷yŠÕätÚÕ§%ĺ<|Œcäó¯ø§À£ž“º¯yùY¥É„™¾÷¦êÒóR½&²BŒË?IÁqa¶Ð¿šx”P7· ÑqÂÌm.%§w” @eÍ•¹¾­“ðG¥è. 8K¹ �?qßêúóØÔ w:ê-Öqˆ7j*(+’9¿îc§îrÉÅáúüÈ+kæÕe¸�ªÁÝ!wçrIæü<Qêý‚ƒ\A…¬?Ä;fÍÂRx- ']ÇŽƒùø"p˜ðм1Ì= àš\‹ SF—óÀKÓFP¤¾FñiŸÔx¸F&…J» Nìx^°+m`YñMTäùÙTÑÓgákÌsuu|‡‰&åKLUGgå¬gýö ¶ÝË@ |¨[*ixUpH©÷8MïnM3)Ggc.CÙýZ�ˆ�†Ø©ÀmIõÒGbs�‘ÝþYrÐÈØº«ì*t��¬ASá×41Kçò¿óo­av£f7s77/Õì'íy29†(ÕcÌ%¿&µ—,Ò»edë0�aãWgPü¢·¨šÖQ^5²¼Ñ’rÁ¯åL'V]õÊI…GȬHÊzZä™+MÍdøŸmá•â.x I`7NpÇuU÷'(ºÚi$EÚ>Žyì«h’ªîßN�‚Å_Ç Âb¬­Æ¢ù-¯r¸[Q—˜ø!lYØ…{ÑO'âkãcÉÏÆ?¹É"Ô· zûÂê…DÕk¥ñsU Ò·ŸÕqî@§p¿ö—yá¶&+øDá`lê¤}Ý„‘N´|Ðç V¹{‘—ÆãÂõ[gÀþ’i˜ßíÏf˜ººÇd÷ZŠÝ4UÃ8ÃH–:Ó7?S}ÛtQH„CŒ÷]®à�ù§¾ÿ)6Y«{ê‡uÅÂïÞÒa Ý`Î[˜»®m£†»”öX~îà'ië¨;hÉ'ß„å{Z±ƒ–Žtˆ¢ÀúÚ®¯KV +.Â�ðÙ($õ}Ó�‚+"&@ù B3ñcÙv© ýàüE™O|G�FªçÔHšÆÐ �Z�%ÖÁÞ ¬ìVÙÜŠ5»vxéò®yÀE~)–î4éªß†v5ø]"ùt eÙ‹Âù¾KO±^κÄWÀ©€‡\×ü_, W;©g¼¢²¿˜4ð°„‚ù&7)÷˜õ?¿…SaÂü~˜,Y/fZ\rÐdAÓ…P"ØEcíÆÕy^b +¸mìĹ)a}°tøCuŤ-¾ÑYŽ=� ~¬|YS¼*n\È´ì/蕃qÍx Ûç¦ ÿI´g–¦l£Ú°lê“IÓœ0Òûª¼ÖJCéÊL*é‘'=/‘Ó°L¥„I:Kfþ¾ïëdÝ®¢DK+2ª¶}È@Õ{·aŒâk…ao”•§áþY�®@p§À%yýØÏß>ò唞ph¿Â¡õµºH \šº ç¢äNÞˆ¢!à$ì&C‡3[›Ž}f�{¥Gä‰[Jlª\QKJÈÛ7®(É£Lm-ÿ œâGS‡>|1 ñjKÙHau†O²9÷Ë|_Ò6Ü/¦©³¥L‡–…3�›!H;5Œ¯ò›3Ij]â?£9ÙfÑGb³¬¡±TXtÐ/\Œ…6\:�’Ìøí«–N(-[r\¦…·®1Õ³Jˆ¡ "¼Ú|¨„Ì@´sK‘›Ä´»£PæÒË"`¨Nsºˆ*ÌœªR2DýñE‰¢öç³êô¤k0’ÂÈVßá‹¥…”÷Àq gñÞ�N¦o•¼×ÿmô{JÁÃ|Ö(Y™¸€(ÝÎÕ$ÑI~Vw®a?Y&ÇŸ Š‘´“VMÕÖLtŽÄûá*ùÌ•Ìÿ*½-;•&ô™¼ ‰¤úò± XFÍL¸$ƒŒt: nþÌ�p¹ºŠV,ÛÂîvûLr·Ñr«ÏJÖBpØÒ$µØ¢°¿Ž¢-X€>§8­§Äoõ«øÓæïek¹˜�Ö×H› ŒM¨$žË{ö»é“M,[õ2y‘’•«"ä�˜3”&QªºŸÁ¬Í�B]Éüµ¯„ëÅ´·p÷´¦áüéa/r¶8> Ž�èD:Έ½rÿ”l¾,s,7¡éË®CÓÅ/ÏaïÓI/0C@7µóRkµöûŠº½_‡I·Ép†ž¿]kÑÔíý<$Í9=¨þþÀ ›'8v8õÃ-ß*4HùzРïD R1G õ¯ Ø_ƒãPý“ÇÙŽ)ËîÍy~;pÏ![f¤³)ôõ{=®ÏáÄhì1øç( ä�Õâ°¨ã*Ô½kÐ/{ÃïMŠÂC¾…ªLC*ªD6vòW꘷ó¿Ôú…N1Éø‚"½Cævœëš� zPx©Çõ½ƒ›¦}æ;jçëœ2ª¶‘q´k01ÈÖü{÷+aT3‚<j§ª*ÆÙ>4§•"à·&d�ô×éÃ?_zæjÓZãX¢¼ùœZüú)cÓ»õ6ä­© úC"ásBðâ\7¦©Ñ‚üÚ3Pô=óvç|‹æ³vÕ7ü¡`Øm‹¶¦"›ŠÉ,ÁÚ ÇóC(æÑ5ƒ€@œ²ûኘ¬B5€îžu�RQvàå蛘 ¯"6†¼×P¶gøCÈѯˆâd¡^kõfÉq8¸O ޳^Ƚ\Ç'­Qƒ‘§^ê‰Ë|‹zÁTç’Îáf�­­F†˜*ÂÌô¿ŒZ޹‘Èw’W¹ü~“ƘêÒ¯-ü�äŠ-ÉØ˜6ÓcG‚2üÒÚ)ßÏMMH¦¯£ÛOw1�Q'4¤;e‡|È]H|²?çÄ(ò;ô(B >Í1©Ïä ð‹ `°gˆté×�O¸ÏÄt1.tr5G�-Öç«ðœó�újÍ«ÊÂÚmQÐ_+ÆüÆÂ–â¾Ð–ñ Üy UB·"ßîW°¢±±\&“”@;]ýèÍ+ß¡C8϶:hô´)˜8™™ÆÆÍ3Ï)^�u2ó}È£|b¡ì| ‡~:•úxÏtÝD�„Gû�òã²E~× âŽCR&[`xÁ  u˜ºsæà渹 Ωzk—æí�o��gô|&ûpÇw<¿ú�¸–_ðÊ1Ü¢� ©è¥ñ,ƒ�ä �BáP”¼�—›< ôÆ©áUõ›qÝÌ�µÏÒe“«Â²š·”ã¯$ÅÒ4ú¤ßç6]r’fCûQ6vÓ·åÛ~Eñ#}ÊÇ}Ä“û)éÿÄõ#Ô9'C‹—�|¤¬ÅTõGÔ�uvu=OÄà ²ßññmªï£0…a8ƒÀ³ÀÒxÔ>g�j;Ê/Ø?Þ÷]”œ1•¶ºrÏͼ±S FLå�¾(µ“æ�ž)3-ü;Ù©�D¯àæ2¹o6£Ðw2ð«¤`DŽ1rjjÑáu;¼µ®Èà•þ@*׈i_á%ü¾�I“â”jfì竵Ù›g¤ŸðèjAl®Åš®>ixÃäMHcÇ‹�I³jv,ªÉ˜¡Ég¿rÚÊÑHý~íž\¶0ÝÃOìgjR0ÝÜ í¾fÀ"T|^òµuõáž=ǧÿ „1é$b~umq¨`Â[›„µnõ/;u 7Å$�+ËeÍÖe:•­clØ•bįôšœ›"õiˆ×üÙNÇ�åæˆî[ìç×…Ã¥=¯ÛbÅ^Ø«àÑ ;ÅîÒbI‡ì¿¥"N¼òö‰ã6XÝ #5°2qö¹ýÎàÐ4X¿ÔùRþR¯2é‚Òp8Õ?$§&q¿1‘4ØÞ–ü NpÏ$êøø±œÝ¸œª±•ŒÞîpÚÅ……ªGÂ÷øëry �n”6V´þ“¡Ô`*ÃòN·ÄfÛÔÛdíQk�'>ñA×÷×K£I¸™ψäÁ¯œÀ›’m7.m›xðe—c·Y¡Ñl8w¿Fê9y—d¡[ÈÔ‚~ÛuNáUÁíø >ÔÑBé·l²@ÇǨY™©lâNß+˜ÈÒBi"õ@:7yºá•Lœ'o¦r³÷ô« !eÛŒîdƒ�UYH ÐWRnK|‡ôyÎn�þ|Çæ•Éo€¼À<»ìÃXÑ"Ðh­þ$(,D“ùü·êòe-k`ÓV�ojœ‹?åz�,t°16«c6›ÃæX¥ÄÁ¯C©8·_·MT¾çŒÜe æ/-^®‚Ey¤¤p_ÞHÛKXj‘¤Çj'Ù9us*¿eQQË”ÂkEÛ¾^{•Ïv9 u¸Q~žùN¤¥ÝD—n©‰6Æ/ÚTc %«(ê=÷vUÿüÙÚB‘mj ›kð‘Y׈dûô®áêüW–_©ã£‘Iv(/Ù{u‡º%œÙ'–­ZFBiJß&œÉh ×þ¼{uÊ[«Š�ªÜÐ{&Á@£}®´¸O%ËÖ¾èGW^0'Ö=Å5M‚)ƒ�ì*v7�¢Ò-ñÍkÞ§bïq\Ò|=yà+¹¡çô÷´‘30‹€¢¶äl YVÌW?€þ*Ã!ÕÞ¸Îb+� qäÏêëŸjˆì²ÊŸ Á¾åÔsÂLˆÀÉþ-³©&¨Ã$:ä\žPwÍæ05¾˜»¶�œúˆ´z7ž¦}We’¶*Îù7´H›·mƒÑ>S¿¡¶Ö˜ÚHÎZR)U?VéIV9¡Çq ’»q8¿ñ|µêíDìå$´ÎäÐB’W¹¯'?\]­ôé£Uû�ýÀÈd!×.~sé]~P•U ì˜_ûé��š$·¯’Øñ  ¤¾È ÑúÒÊê®Rv”³MO%^B#œ?ž+ÐÀ¦À¾ŒXòj‡¡y ½,ßz–µŸù¶ˆÅÀ_aa0!Zßg¿]mee]/ϊ̲úLnŸã­&­ƒëó4qõÂô]~ÿ¡žZçýSäÙÑÐ3ã‹ãTò�,µ?V±]Ô@Ùø ‚âsFçv³"��yöd¶nQÕŠ'0êI�fµ¾fúùÁIÀ—.“dUÁ{ìÉn@ÿFhü ðõ úKß@ùÞk!ïÓ4§²�ÄKFµy$kÖAèô¶\TX/ÃZöKæêµy±g­DÃCZü†Nœ±jް8Û§þ5¿Ky¹tDáõ´Ï®xÕ ø†’fóGe˜bΦe]šaï²oÌ3ôcÐc„¹·ÿ‚Oƒƒ:e*>ÿ»|¶Ê�ÁôÖß7ø>ÑZë~ ò ºSã(J!EÒM7’ɼMöñ¼¢ž‹Mð»ÓȽ9( ®CËéwš@ Õo>øcWڹǨY*ÕàrݺLkŸ£nò…Õ™Ë Ë÷`kïL˜ÜØåg×P%‹¿š8š†i<7þêÅtgRârĨø–¨×a¸^rÍáÓ=·—w‰Ðôûvo“éTùœÁzo,`ÆŸºÔe¡ƒdW�ö§ÚW%¦¯‚Cçø¯Ö`�ƒd ÖwŽÛlr!{×ÓV1°ZŒÁ̬L¢ã–ûÚ€âÊt‹É­œ~{ÝNâ(]ÞÈF“«ó}WÙ‡+ F­:e«¾ÊôÎ ¹iL7Þl[ßꊆSïQR6÷ˆGÆŒú�ÞXU#ò?;ëá+ðÝÇ7l�_[ŒéŠ˜Æ­,šI¢7¹˜ÜêÏ“]*Ü…ø¿|¶ãHv·§t|~ ô[ †íÿÀ,|�[ ZΡéÒìâÏ©±=‚ îºeÅ�Ö„xë×ÏMZkø«™»0pô¨²ûᑟöB1WüŠ)¢¶þáô)DÃ!{²�ï߆¯¬Ï`tmut쌇µ�­Ó.dßÂyÁmœ�ÞüÞyñÁ$®RÝ‚ŒÉoœg‹Q­¬ê bÿ�ù±Öëà&Ô¤ÖÏæ�ÇøJŒÒ¤Þæ²?n¥DmðŸÃ¶øÔdoï-~ È*ñc="’zÆ€Ô/7––‚ç<Òo ¯jÒ ÃTOºŒ0Ž8@´y-ô$¯Õ ¾·¿ÿµÌê– û u>µ‰ðaú8§Xõ.‡#¡Wa±ô“‚ÄÏóÒ¥Ÿ°9Ý G'_„Üu’¸0x8ú­´/V½›Ü†æ.V¸ZµÄ&D1 Qœû±stdêàèWÀîS‹Yª´ì¢³~Wþ“†T˜ptÒ F\³»-Âɵò}}éŸ]ïaðPöoIJc�{ÛLv*ŸîØÐ©ÊË)2ð<kàu'éΧE`Y‚²Ëåóí¾ÑS*Ä«tŸ’ÚS^ í=[ÅTÒJ 5fþY8(Ú/2~¢ð rÊûxªÈÆt[Ð$2oÿ*¥áîŽÅê^ž|j�IœáëGƒÐ'=ÊÏà}‘ZV ”Ͱ¾ÕºïÁç–UƒUÔìI9LBO0héK:+o ,“ô8g³ÞŒE*5ôJŒ Ó6aÒ[ÍøÉè‰jºM%¯p\‰ÆÇKGÑÈóAtWKs³¶œ�O4\Ë.S ­uÞ’Þ²±¡à ­Ý�ïh­!;áщi»è$kì ð¸`Ä‚{Öä4È�k°K?µát4‚ÒweGäˆr¾»¥OÌ�P„gSÏ>ï©‹æF-Œf½�u8LI¬>Ä1LÀ@Ë—8»eŽ¥ Ôå�“Ë…õàta#æ/n]?x‰|Üô ®|™T0±éûÅ2Y>a§à$‡ÞÆÐ®XYó›="5WtKÝ+¶Êz_z/‰¾u0Úí¡Ö¥ãŽòPœ:�‡ÎüXðKÜOÕÙ£üq¸š¬nV\ó Ö$YÜÿ|�™Ns2ê”áœbì4Á›“דwó.´Â´éøúöa@ݼfÛz=wÛd T/¨gæ÷ÇÓDSp »ƒŒd¢sWÄŒ‡7„N6Ôàÿ\ ±?Ìßîai8¸°0�'rº2¨]T²ÇÏØÆA䈿ùÞ3Ü›ƒ+cnæÑ9ò“Ô@ñ.gÏ\pÅÆ! O�[Ûšq~˜-¥d/šuSª¥íÄ×ÿðH‹¾G ¢“>\²çºT¼7E8ž=µ°mI;4Ù!Kˆà¨`ãYj÷Ø…öv–‰ƒ(ËÌ}Û‰ÇMÔI¢h[i?-ºüœ4ì"E®ÑNˆ½úkˆóO«&·)š½èÞ(T`“åÀLËÝmc4Ãb¤$[ÁÇ;Àí î<Õ…2;€É%Éý›ÒZJ-¢C ^pJH�\éë�8À™²ÙËv«é;zf”dÑOÍMÝŠ¾Û��~¼´½C”ËqVVÙ)9˜€ CѹѲ}º¬µˆv§�9Kæ–þB꿿ט3|ß’G¥>ùéþ˜,ʼ¼ÛQ¯{š¹ÕŠ�09K5êËq´SÀýE÷³ç£C¸×éG²)­téÍÅp�wÊžEŸ|Z7ˆ`{ó ²�„§æ@ɆŸÒc{®!Xò°¹¥h’”>??!8ßüI¯gøc(ÌuÉug4TwNR¿å½H½ú¼‰sâîçÎlsnx$nƒ¸î?½@Y[�L¨Ü5ªÍ8¸1¸½BÂvÅ[ýòªœ¼ÞÉtçaâ�Q}×uTŠ< óKºQn+SœpXóŸHåêž÷ä™û7oçŽ'Â#õFwûáGŒS™ÃŠ>Œ0wn?%â»H²4ŠŸlwá ^±ØÝª’ivÛúÀ}‰êïÈáµ_¨çf4!Žz ‡×¹Ð<åe°›•Óù¢úݺ÷­Zd1Et5Y¤œx¦ø :‹)ã=Cm ) ¬j›8£-€}8~a‡ÓM»³ÝèRÊ]šÇ<­"P›Êª�|ùÛd«kl¯Ù©›g—¯ü¤Wìi?·¶Kä�ÉÔK_zÓf•yЭÑà¹vÓ|ékñýÄëhšêPulÖÄ’œ�=YÊ?õ�9M7–¶)÷Êœ~…þeÕGú& ³%ßâôÚ(}¡£ðæ…‡¡Œ[[‰Ö¬ë±C}�Æœh ^ÜùJÚ�ƨFTÃGäçù3Cåú‘)’À.Sßö›Š²{�D ’©PTÅQdºá”RòM…7áþ#¥#{ÊÜÜ8¿ ð‰þU(ŽÓ¡Ð¯Ÿ Üg—x…¹>,ãúPí÷†ò¯|¡Å90šÏ$�ñÞµÕð ÚzY©Uod†wòŸ?ëöÅx´¿èGçÇ"ýD ç,ºFkåèᯀV®‡YÚ46}“¾‡-Ð'ª~%‚ª,×6‡´g9´C(šPçäηɪ¨*S/NRh/gxñŒ¶ ¼Þßy‘`ø�[ÁÉYTVᤎM�ƒÛGéðÆº¾^{ÅujÓ›'A ÆÓ·ãuì>š$Ù b^S#t‘¸Êï;…óñ@‘ÏÏ…Ç�dmCzŸ•¿‰ÕO•êÜ4™»£.àäK@Ë?Ÿz5]©Rø‹9J÷(|šðl.‹ó-,¡©ß¬¡At<ë5¦ †>fÙ>‘O‹µ>¬|0Ô2òÚõ#³¶†èÃëœñãÐÔß�ˆsgfsûõVr¥¸7—ΠHÏqÙ"ªÒ1r—5�¶^kd»àeW�½…öb½í,eˆ«'ÀÕH¿ba£4Ò冲Rg<vàÿaŽÂr�üýxo#ÿdž2S×J`¯Bðlj�¾GÜ0EÚ¤u5q1³ˆZž,RM‹7BóˆÌ:‹3„z_Û§§á͗©N0—¦%’úÈË6!*þ”ë—hvŸ€ AÏÉ¿&¤�ºp0n{‚Âü·˜**�%>È!?|£ÓPÞ£ÙŽ\4mÜ'v¸P �¦Ç‹$1#Rn1Ûõhû‚�¡ÕYÒ´üÆøºe]Å¡ßÊÛô˜=$ò7ª—¾`ûjZ¢zŠ éEÉ—Úä6œÓ�åÌK¾ Z×ñ¼¸–µÌ-ªÖC\K£ÐDö Åsé,ãkkQm׉1rÞ?–õÅÍ–¿�Ín˜Ù-y0>}¾Í…ÕŸÃ7öiŒZzRZ¨íøi�5îÃó{ 6¼/ŠÏ‡ÀaÉò;öÁÚ;e¶™ ÅWÔñ‰Ëœ}aížœº\Š0k®Ñ²¦ƒÞ]ǘz¡ÀXâëk^“/Ÿ]šWr8åáßN «[*ý<Ö6dUT«„‚û^ݲ{öEbjI/qsëê1Rn±T˜ÁWꆷ_5wjøæý€ÂDÚÖ¥88ö`gëËþ7Ô[w虜N­vtÄG� /ý £Ô29 éTÃu_ZnX1r A­ncíá9€�á%²Ey‹§=O¦ þö¦åsªÉ›ªv\ Æl¤–=C"�|1ì�Ì_ÐbMQÒ­Ù _޲l:omZ�ÁŒÈASîeŠÊÖÊ\.Œ*\ï ÀÃK>R�gr¬N„/™i—¢|3Ls{îÁÇ·`A§ßÐ1'®û!²u #«1aP˜Ÿþ"+â­r…ÕîυƑ诲êfú5‚°f•Æ!aÀF“U0=›Ý¨2&½‘HSÁ¼cÈßÄÃ�>\•«ú‘¥ž�¿é µlÒä¹Ú‹éŒ']”góÏfIïÕáã(g$;ÐÕ*øA,è#‰¦ñk°»Ö³D|ôõxf ½åý)7íÒÙ³ÿä¥1T ¬b|ɺÃÃÖi=nø`{ûãBtÿ£Ê9à¤ná9ÿ°Ý(`ÄÔ*‘—?ü›t7“i¯#}È·fJÐõ8O¸RvïÔê<«¦²{Ý~®©À[ì'â>qjàž4’YLÇ] ”èäü]˜aM1 ií2çÓòa¿,�KpNÞ`lç¬Äè§Ms ª:HÒ¶Þ¢¿— >wDõÌï;˜­c8$Š/ü![d Àò˜Bh"Õl=tÖ�{õ-8´³°LåAíèC–¨û¯Ê§þèHxqí~ée#ت…nÜOœvzþK+ËëåÆ×:´emú›si�ÓŠUiˆHÄì(=nÌ5±ÎîþWÔQ§Á¸�/ lø¤t!54¹½¸p£®$ñŸ”óÀ±÷þ­Eî(p!`Z� ·Qrfë%f³ßíÔýš‡ÖžÇb¥€ÇCÎ)�‡¤Ï‹Î°Ñ�jlê_¨¿ŽM¨ï“�"~XqcÖÍݖׄ×N¡ʯp¸‚ßè°xcÜ}’z•|£ò¦Æ @úâµg¾Ãoµbòç£Iê…¹m—lF6º„H‹j+_š°Ä9¡s¾c>;XBºhâc¶h͵›54áibY{ÜUE‰7 SØŽM.oA�–^ØšØSð7 Z9@Ox«âÕ“Bë1T¿J¤ö!#¦gš¦Á8õ�§’¡J�H'ƒ[>–8ÇÁîÓ—Eþ˜&¢q¬èØØ­ØâcÀ�‰'5ì§ÝÁä/T>É+-I[á}vü‚ß;oÜäD–b‘ög„É…­G‚ƒ[ƒ”jþÐ e�À$…EªÕ R­•»-�í,Öƒ÷€n+2idíë¹�P¿C[¦x×¥¶.·÷Ú¥wÆúyS‡Ir~soLOa1Nê& ú\¸„°Þ¸³e…Š�-+]ô"„(”ÓG+ÇÉXËàÙ!?ÜÏ–ÐsÕ‚bé¬ýƒ&W—y‘ÍfN‚É�jâ½"#�rü¢<7ßé`d÷Dú’ªê6ŽÐªi!…/ä)k­*®l÷Ë�Lž]À¦Ð‚oÚb{gß“÷D¬=ú)ýXeݪ6zû<¸±(Ó¦}&æ@#ÁõKÌÊa#¸©zFjãVp.ûIå¬ÿH8b´~0:~Šsòù+jž Ë÷³ ÎúuØ@UZuÚˆ†>½©¡oVça±ÏE‹Dêö�¢ì goøë"…ô¾Å{€øÓœ¨ãò‚dè†Û›UŒ7i€UO9X��¹oé´‰ôJr/QÄþ#±§p¨Æ�~¡uß5;W7=K¸;× QÙôÇ{=K ^·Æ•zö«ÛÃ`ïÌéc}æNâÀµ_�4vº*Q†–}r¨åÖr¤ "Ôâq÷H±$�G!ab =9"Ðþ±ÜvøŠEÙW‚f\ÑGÇöm›G÷¯O®¤5†=‡šÌÙÖ¾õB5r£•qzîq£LšÀ…¯ŸzÑ©ÙkOºçå™+Y2“ÉCB�¨¸ÿHÅ÷4“×ûsæÿF±3Šë¹Æ{æH¿DhÅS€w.¡I} ¿×ð„…`*•Ü)ú“ÍX–U².µ…¶ô!p�‚¿ÇŒ T#Ö�Ô!Úæ¢ùÀ«‹³¹"ˆdu‹L9ù!ˆí—g޹cù(n\÷:2·â—O‚¸‡a ^üá/œ²_Ÿr ~Ãô=‘Ÿ¿ån„!"PÖðh $ •ðhù¢.WçòµG±R~Í™“Ñ®ÃDƒna‡…M¦Ì §^Õ‰ÁJ¡O& i4fMôó: ’Ö[ðvôñ{D(´òÖz¾~)z²xs6›!í¶ ¯H܆jÇÕqeö>䈫�Eä„ð 7"›Wªø¾©KéGÞšmÀ¾Õ<b(šS†ŒL…ן)a7ÈÓ9…õÉ|X¸ÄW)IyÊÖˆ?bÍûsViæl¶ÓsìÍj�{ö%;Xø~vk¿l aY-k‚•=Öo€Jç[5-6½:WC8±v�ƒ63XE»FžëFAêx�=ÑY)z…ƒWÿ¯A4SÕ Gcô„�Ï€µÔAê¬[Ä…ÆŽiK�{åþ¸¾¯“ÝóöE‹ëÔò­÷Ázœ]øqQ­}°Î€•íGfŽhóOáŽlŒjy8°Ð‰ |W}ÙaÚ-úøžê‰³¨Øð�‰ºp0B<-wý9yêî~]ä©•·;‹¼S(# Ï´™€;yè×|AkÛïËý½™¬�D4œŠô‰Aþ;y�-"ù¶sižÕ¶b6,f0sªy‰ºÚ%¯]žäÈ„³ò¼b{ø—fË ?œ¦¿˜Œf\pz>Ëzìøôrý´5¤ðËÉ’L3b®™Ž5r¨&¤W"¡²QA©N ^ jÐXkI"Ú‘�ÆoÙ��Sb þé-àʾ«ínà/ãÃnŽØœ”†É;=À Ls÷Êa6Å;ë,|nW<Óýá7Î)83¢$c0ê½ÿb„ ŒÚm >a YÔ‰'i« ó|½äng² W?òJ4È WtÚ5fÑöÆMGcüvD–1Æ»eÍC~Ñïi½"cëá¬ÛÖë¡DÚ»u0ci+v7@Yô‚Û!Ö4¿pÞÍîø¦ø¸›ÿ2,Çt¸šž«HÇ’€OBŠçšillÊŸÊb©H£B@Vµ¨Mh‹ ’ äÀVa`Ë2š?Ør±äÏûVn�æ^À’Â⸓T~ÐM£5±&Ùß+€,¶x¾€Fý˜qð4Z$œ‡¿"B¨Y†=åå/`|‰3OÏ»ƒ'ÌÓîtuK‡f–!eM'З@E>ªò!¨î�øîkáºü¬O¦Ø A˜('Õƒ‹žþÕ#5…ç¯ðÑË«¡õÓ29€N¢œé—öa†R�òȈbE¾ej)“NGß|#mÄ<¿yŽ6z]9u= Ô`ˆ+ýyÝ‘3¨Ö§ˆí\ÁלŸ¨ZœìöEp4•Á#ÓbYÎÛ6ùÍ©nçž2Öã‡Ö*ÿÐ[±“ÚfÚìl%™É«-—¼³ÌúÝ9“kˆ¡ó[?L�vMYM×ÌÓµ5¨k\¥!Ù.•·Y>;¥µÐG±õã®7�þå úúZa)g½¾à‡F‚cØP¸ñ Ê€ÎáÕþ–­¹ÂŽ$Q>/É…øízé=?_PÍJ7ž'Ô¤Lj¢w»¯Ô…þX †9VŽrÒ’•G Ó™€LüF•÷aNíŠärv½�\¥¾­¾å5FnÝù“þQÅ܃�äçâ£ä&êù"Ç‹(/ô oNå‰ö?îJŠó\Ø›3ãO(2&2ÈÔ1ž\-UpÛ(…íŽLvb(O;£ ¡Ÿfö‚2Ã*j�úÛ‰}Î|K™pvÊ+Ï]aøÆFßZåÔ÷ã9 (L„Å"÷Oï:?𠨈:äyUÏ8í*—ëê™Ù ¥um¶ú"À,ÑÛÝΩ6-3ܼ0ßšhçÏt%Æá™È1H•ë±™å™jèWnXO@Ê$-”ÝCK Õ­‰U$€oC½Y‚2Iìmѵ;�ÛˆJn öÓ&�ûÖÏ�F\5,„yÍ|îlåó®íÚêù”#ìórê�úåÌ·aš¿mZÿ,B¥Ñî[¡Ejš¬šÒõ¤ÄA‡×J!&AŃüÝ2³Ï¥ÄA¥s•¯èzß½Q{N¬Ùí~"v[Ì\ì™Óc|R\Œò›I&ؘ\57LXíWëÅô+ÜôÎÅ%2~� íæ¥.#é¨t\4þ*¶8¦Í]à/|HlÓ&ë‘9©NV,Ú²^F€ÊÝ•¯…>DÚçã©=ò• -ªÔ$� «×(äªÂ(© ¦A­O 0‚,V:©†œ>³ü¦©^PÞÖ}ív©§!w^“F‚zkÌJß&/�—Ø )›:[y©Eþré�:rR<«ÙiéÑd¡7‹»(Ëš„{Eø¢ëþê¾þqt`¾Øhe:}e¸X܉ø>oÚœ^б•Á Ù\ì²ÇIÿó¨gËÍtîÛàÅö˜\…ŧÊ3æ]Mªbå¾³bG¶Ïã0a¹C Ù Õ¸á”½×øÓ=ŽXâÝI=þžNCòÖ›aVPÍà/§¸ýê«5 ä€è€uúŸ� �˜'ªPc‹7e�«®”¢? Gírý‘¥iÂó`M§¸ò„®K§¹ÕócýYSvJá9c²©õü>Dÿ8¥ccèÔÕý’³Ž‚ê»”_(Fœ£j»W</ýÍ9*ö·é$®™ÛC2iîåÆ�aÙå¾»êÕp,–8Å«ùdØ›�Ï[$ËÁíåfsi j‹G‡ü›ós')ض™­2Ø­¹³ 8*1�úâ�ü„þÛÇ£yG÷"\켟Ÿ5ŸƒLÊoq ¥VƨÚ8ñd‘WŸQ›-3 Ò³¿æÁSé _ɹ±ËOÅ Ñh…9,#ö#“ºsOؾˆ~F¥{éí=™0"ÕMB%S·zêK¿óo(üz¶²D;$´¤ŸŽl&­Q�¥™žß› ³��–¡?\­b:9M(ºÑgM,ÛÜÏ™óV´ì<PËxG~)Ï÷Kµaa8(N—åËŽ:Øn™µÜaµ(YѪ2{»tó¼ K1Ç4Ú|\&Té2ÛVqÁZŽíkNòè´#ðEüèó87k%IÜ//‘°ŸÉì »ÎúeŸ«\fÌÐQöˆOTQa•oXXPíú&z•.4�!Œ ÿaM¯“º¢QàÔ|‰ÃüªFÓ8ÙÉÚo»CgèG½)½Ä$ê_Oá6 PxÛm01,"•%¤Ì› y8†%¿é,©n7{ú•�ä¸|s”§]ªŠª3R2M÷Ö8�õc ˆ_Q‰ÞpÛÂYmá¡j, +ô“¦�f7‹ÓÃÝ¡?M¶ ëB …Y–ë7fÐÑËgCî?_çz¨ïÖ­¦–)6RÖTÞE�Ö©a³$FóýLX¯Zà�Ì$3˜í‹è2¡b/twbÀú�æ3¾0ðóZgçøDÞ®ÅWŠÎk†*°ÁÓ]‡æþga@Oªïq*•=å/è‘�MB‡Çéý›–ý@¶I™5ñ?;“U'"ÉÃZ0ôD^[2fëNDg/rv^-—ŠÉkƒÀ'_V4ïj™n˜“œP9>ÈlÆüo+ØÙë9�*I’@•2d�­ŒøÂëxU-îÅì ÇËá~ìs†:È´p,l 7{ãÔ' ü2—­âµŒ2fe^?þM„e ²¦Ü¶aM ¢ AuÎgõ#æCº]›Á`Ì´vº¢•´V¥ô�$~‡>7èl‹ëIoŒ]´dô¥6òæT‡Ê¸drø¢Q%h´ &‹KÝ~›O"Þ@¦ä¯s<»Ú•ŸMîü9¿*ø¹ÚÉ!»_ê?Ó6ø‡Òæ¨sÃ�Ȳ�š�¸E4Âë}¶<Ù[Ï îtúžá0‘U´Öb­ß“l—ˆMYY—÷ËÀtã¡ÿç¦ÍG°ß¬;8E¤J<ÊÇV¡꣚öšTª%"Þîe…JH B˜yW‚�*riÔ<Vù|D¥C±õaê—%p|S >$M Œÿ˜þ.1Hï …Ùu¤‡6¢šðÆ´“ñð´6…Ö�T­Ž—IÎþ‡óã#}Òÿ%¦ Ú endstream endobj 67 0 obj <</Type/FontDescriptor/FontName/LEWTPW+NimbusMonL-Regu/Flags 4/FontBBox[-12 -237 650 811]/Ascent 625/CapHeight 557/Descent -147/ItalicAngle 0/StemV 41/XHeight 426/CharSet(/B/E/F/G/I/K/N/O/P/R/S/T/U/a/b/c/d/e/f/four/g/h/hyphen/i/k/l/m/n/o/one/p/parenleft/parenright/q/r/s/slash/t/three/two/u/v/w/x/y)/FontFile 203 0 R>> endobj 204 0 obj <</Length1 1630/Length2 7362/Length3 0/Length 8179/Filter/FlateDecode>>stream xÚ­UeX”í¶FºQé:‡ ¥A¤A醙�º;$¤‘”�–F@:¤é�.é8èwöÞçúÎþuÎþ1s½ÏºŸu¯¸×»^M ŒÌ¤ƒ"�ü<|â�u°ƒ…3B Ujƒlœ5, `À= ŒËÂ"ç2G‚aPys$H`�²ȃ,�~111\€ îî¶±EØõ´ 8¸¸¸ÿeù}`áþäÞ¶�Xï\@ÜEÞSüŸu@ �Ò°C@�9 Í—ÊêJ�v%u=€ r2‡�4�ïK±¨‚-APˆ` s@þ:�,aP+ðïÒ<÷\2€9�Y‚ïÝ@n– øoˆ�99€ˆûg�°q2‡"ï{€„ÀPKˆ³ÕïîíÖ°? Á�`÷7î±{2M‰°tÑ€û¨šòŠ剴5GþŽ��ßÃ�˜õýM+˜¥óï’þ`÷4÷(Ò E�� 7äïX €‡˜»ßǾ'ƒ;�ÿ¤áŒ�Cmþ•7À dcîd!÷4÷Ü¿»ó¯:ÿ£zs8âþÇöçÖ?s�# ˆ5.¿À}LKä}l0—÷÷°(C­a�~¾¿ìVÎð`. §? bÿ=3÷I˜[Á w€È—W†¼ `ÿ¿©ÌóŸù? ñDàÿˆ¼ÿ?qÿ®Ñÿx‰ÿ¿ïóß©�!us‡ûøkÉ�î·   ø½g æN€ß»ÆÑô¿ÜÌÀ÷ãø÷‹ ¿’ýo¾¿ÃÊHóû¦È@mî…ò ððýe#Án +M0ÒÒ`m¹ïÙ»Ô äCA÷Úþië½ßß0][°¥=ô·ÂA ¨ÕßÓ¿—ëOò¼F ª jê\ÿnÃþ¹©y? H]w8ðßa Ô`Vÿ<üæ‘•…¹<�"ü� € (@TTð„ŸßûßDüCÃÿ¯³š9Ò ì0æãáããÜÿÿã÷¯Óë¿Ñ(@-aV¿'Giµº¶~ÖÎNN÷ÿyÿï‹þÇùÏØƒ@n KÜé ˜¥D�]ÊûwÈròŒ®~yã¶~´®`x~¥îÇl¿RX³oJØ¢X‘ÙuY0OÕ øm½ûøüfõçZO „­9 ´—EãÍÄÑšýhžµA”k-€×$ŸàݶA¤çþ˜êº‘ŸþÚR¿–¶IÞ5&í`ƒ öþ‡“K¶ ó)œÐÇ2¹"†´ñaÊãòœ­mÖøÍ³S¶ŽÞî®ÎæCŒÖUj®ô srŸÄ-†¤»™ÓI¥å-Æ¥‹¨ë’„VàÃb4ží„ºHï$ýþËN™jOt™®°�Ñì; –wÃZ¾éÈO:d½¹Y~ôŠÕƒmU|‡Œmç6µ¢ôl¹©ŽQ¸dѵôŠÔ*ˆ¡iit”tE¼4æ0™ïÁ1 �íÖß ØÖ–‹c)oaÔØ¦qE^Ý–‡DR)ÚˆÏ�*r•G{·1CÁBâ×Úm"K8GþUtÕXÇX�νe—�+TµÅ&ò1-~[FF€~j@ä Àƒcmîå%‡HÆ+ÝTöhÚ ®Yie•1�,£ÂåÁŠ>É‘ƒS”×Õh—K-í]ëý“Õ=#š(OìGhÆê}ÏŒ~Ðí¡×¶¼•ªD�/?µ­Hüü†^7�½ÙH±ÚѤÐþr©±•í%%=+»”nM2ãµv �9òؿڅú°`‡Zá‘W„�Naö ”b£O/üŒÄêQÚõƒ,r]ÙÚ ’—‡ˆ“s6J=<­yJ¿ÊÇǪ½Ð:,t¹z5ùƒ,5… yöå�¹IZgÕBqjzÁ×?ÝÓðð‹9Ó�=I™‡$ú¬m;Ñ�‚†ââÛ±î C‘Ê }²Eg¦—œÝv—¼Ðñ€§:_Ã6\o« •�\ ŒÕâÒ¦Õ�7ED°Þ8dòsãÆ£ë„Ü n‡ù=)CS Ùþ‹^ö�-¦‚V G3)m¡%[;G@ç�°-·Ò>‚RÒí*eûˆf5'�=+Áª¯˜î�™ïQAÎ�_¾ÙÔuwù¹–þªO�ÛD¿L¢`s&"*Xê¡öçŸÛnŸ‹�↠m…Ô¿ÕK5ZüÌ'´é´ŧkªœ¬«²°U–‡D’2Y/=tÈéZDë†VuU†êXá<|”ÑaOÑ1¡0ƒÎewŸ[œ·µ ¡j,-+ È6‘`&žðkíçžc„}z{^Ì5f=Oe6 êxŠ`·i”«ŸhHNhÄö–e ñÉ‹: ÉØÌÝ7Böå+žŒW1ê¦ûZÌø{kÓ/c…oÊø¶ØRÄY¦õ�)Œ_»•†N„Nç­ÊcÝz¦kC^ eJ!~"àCÀª/(ÌmaqxáÓ=AüÐå ËÏ`Á!~ém·ØK½Q~gC—SåÕȧ{ë8«�C8êHóÔ�}žƒœ•„pë|žÇ’| 9í#X¿J㩃9ÆW‡Ú%â§|ÕÓ<t­>ÕñRËé”»‡ú ë:a dðqž?{Ý›<É;Ÿ…l_¼�²FYV¿üˆ>·auÅlR|$=`B�YðÁœ±öHRÕžZ¾áǶ°éÀ|ÏæøR ^Oµ1�³DIYÒùóixŒ6nUï²â ÓSçìÅò«Rlœ-ÿ kÿº·ÂŒè^ÜcÖß9B}Ýn¾ k¿ŸsÈ©N~Êd§‚pÄ‹)¬£‚pÔ¢ÕÜGáù(PwÛî@Rð®Ç5ëŒæ×FÏ�°"žhÜ£†d-‹P\Š… xÞŽÎà�]mJ�R2üþ�„9rÇmÁUŸ;þE«�­üÜîú/ï"ÄÏÜ}èrõrrv‰<“¿“,Ÿx?¯Óxü‰TçÁ*0Ò¯û†uúÔÿWk#³?C¶¥L¡QÛÜ2•BØ0žlµSqQ0OÔY©†Ò^FKÀoΕþa�\ÚKiþ~,=�m4¿Nn¹jÿKfQÉá ‹)� »¼^8Ð�z‡)e’¦NúLèÛõM0Á>L0 ¾}ûÒ2—‡è^dµ-c$oëÛYÍÈjO¡—ˆð( ¨µâþp¸„ª¾¤œlM±£2"Û(&9ï4n¬bÓQ‘·mž\Dº*Ðϱ`l ãŒmÅŸ7,® ™_Ë¥Üõ"³3ð{J’§ô}Âæösìž1 ¢—|=Q_¸ j,khKÁ}’sQGº6é�ÀÉ| œhº1pƒz;Úd@¢™“‰ÓÚ…´T¼¢7{¬ë¶/Ê”º´¤�Ë ÊÔ7‰Ýü@,,5Çæ#ó�½·¶èèÊ[µ0Í( Å@ˆ¯²w3Äȼ–ɶIàgÉwp ù¸¾vŠ<-Ê¿fê3’(A’í§'ê—ÃÈçM¬^ã1Ç[4S¾«ÙöŸ»ž¯Çpš(ÀÈr¬iph€R‡ÂžòöÄ=a„'MŠó»!aQ3| NÚw{[|q2úÂñx¢Õ‡�O¨Vtßm¥}1ì/öÙôø58”vF>ÍIóÆÄƒsu9Щޯ–Úûë3/Ïy¨{#Wë)µtë À\�£B}{{ç ãXõ�¶,·�ªìcôÇà3Òä¥)ºÛÄÕäA ¡c‘q#òõ‡i�‰þšÛ¼/�àÞ¥Yôí$Ñs¥%»[›7AfÕ ±¼ìþ—Z¢ <¬´‹¡¤ƒ,µÑl—X—󣋠 –ì E¬HÆ“¥É£&â�;{·•¹IsÎ?M¢ß\7/už|z©ðÞÛÉPÑÌ.J»N�tÓ¸Çw4ÄJ_fDG…|ÔbÆK\qB‚‹ë½ài52Í–4Á;E¬„µüõΗZ^æQcf’r–²°k\YþRpn’ùáe‡7py¶é!Â8qéŸˆÌÆ*< ’çÀ8ˆÏSÚ—FuþDïúÎöÔŒ¡t˜™¥±Ùäâs3¢òjí[VŒ¢'ùJò‘ZLìXŽÅ=_ÕÂ3ú\IHW©ÚX,£hK`˜ÕØÿà¨a³�|LGðS/|Í…#ZbóEòнµ£ðæ÷ql”ÏÉᨴoH‰·ó�—úøŒp)_õ–SŠTh¥d~bZáþÚP.6A^E¯?ÇAsÂË9è¼·óp¸i*³Ð­–i…„røD·×Õ�7ë¨øÖXkÅj¯5óɺ킎°O~Ç|v4Ç«!Þâ7=Ò§’ÔïÙôéZ¥¸‡t©ºíØ–ó7á(†ÖB�êdÍ_ºxúTŸ½{žµ³GãÚª±�€gg/dó±Ä”Àrð¸Î{­ç#Ë…KäuŒ›ôD�Ì“à|Â2En(¦±l‘S£è6�¸®‘H•D%ù”·˜—‡žcŸ½ê#¬ôîûW�ˆ–“'%”Ô×ÔÞÓ…j‰”çÆ$Å�É�oPWº#±‰ó»G Õ¶nBë-ˆ}œôÑ£ô&¢Ù¦W/G—MP¢Çàf#¥¢„ç)FÛ²å3p¸æ‡uØ#^åuq²S<›Äïñ�©+YòâUAH¾Ö'k~ö’9š #§_/µöµìÅy�‚ y?Qx LÓ*YDRáåWä_}7ÉŠ¤GvfÉ—L™\Þ'ûÃõ=ÜÉ8ª.úÆòæTÓ׉XЭÞ^¬(¶‡…†:ª¶Œ?‰¡B=Øãß©P¿•üPŒ1/@ÞƒÁ81ªÒ8´0 B©Gr uí¢s¸Ÿ£Ió©\0‡ω/(Åa1Ôã«}3+ €V€GZKTwŽyEéìIð=ß5 º÷bvõ¡iµ7™‹(‹Š»Ù¼¹ºñ©%`YXyæü!R øšá@§F˜Ók=m£±Jôè×(Òð@7wÚëêØ‡Ä:úþñ�ág�¿z8ke!¬NÍ-2úE *£´…Îç9XÎæ…1"Æ/¶È=xñ3)?£[ÍIÔ*×1ÕíÝQ¾D�Úù(uàV˜šõÞéb øC=v@Aè-îðH{J¶áPt‹àépnÍÒTvΖy]3�†¿6Õ¥"ûøÕä—‘ŽbMMë íÔPÓëñò¸ví’v! Ô8iÏgŸŒ$Ýî?ß§+l»õß9† 7°O^SÔ}! ×Q¿G`ÄW2Ù+L�öêñ8Óf¨¢ò_gàÇ~Ó£9ž7-òï[°%×½3H7v¼€ÓrP„P¡X˜(Ú‡$š›?þ*°Àp±Ô»B©¿&¯â  ¿Ò½PHl>Ú@á*ÕÞatûqZ™m2!ýr2mŸ¢Wy¸«Õ•Ð�!u\üÖ²ånlà”êýݬæ$… IÊ+M«ãtÚ^ó^åC+êG"o"dí“ûû4–ÊHÑ`�—­U­œ?`Ì©‚âô�KjWø+ü¯â‚å †¶úûÙ¢‡ÇOüô©÷vóç¤åOñF²HR,äTà¨ëòò"ëÙ¦:ED,×y !„ð¤ -= šu�@Y\p1Ó&ê(óœež/Ú[3fnèK%_Z4~+/јm¡x$ö×NS_Ösa3]Ìê»’N²"™ä™\§‡Lã¶}ÉÎ’ˆr¼³ñ�r UÆa˜¯FˆÃ§o<Œ“è®Ä£zc¿p‡)‚Kñ ÊÝ10qœU™í%áÇOb<3J�dÝQõn}ïjÜŽ8Ó(ãD˜5Û=‰ÓšHzq\"‚ÙîY. ö9¡4·#àyje.'GÃÆ|û®—7›c‚†6ÿ A³E¶šR©N°’ǶÚÄÛox+UÉJBJW±µWÖ«µ=¦øaTÓ ;߆/ÓQÅϲ iî¦#ÕBK[G=,P»çÎRˆ^¹  ð€^ hì7V­¬ÅϲÔ4åf¾ç¢¯¾1Vxô †×Ý-F›÷n»ÚÌâBumV+ÖzÊ$]1¼íѶ¿X.mQ‘•G,àÏñÉ•ÕוÏi ’\ÿêYïÇ(¬ÂnÙKë� ´‘w,ežR�ÁÊÕlèy* òõ@gÃñlÑêÉ£&œ*c€úÙF «¾ñl…‡aîyxî©„þ´�_êWÈGM›}ÅÑqTà…òíƒ:aeWE)¡rË‹×øûAçŒ@„oZjem{pï¢ep‹Ž•¬Ä™HyÚþ~ÌN¶Ý’jºÞ×çÄC{~èk_|2>ùOèèlµ.éºSÍõùÙÆÑ™�RÈäc7ó*Où%D¾#©Îzk½ÓßϸÅ0´Á¦«™#ºª7×\¦6AÍ}õDE¸_ð‘œiѫˮÖgÂÇLÛ´¥?pDGFmN¤ ÊÞªõÄs¤3Ýðpq[<geÇUƒÃaû™¾*•ýš¯,¿)�’cñàÌŸlA£¿@]Q«�JøÉAÖ1§}k�$Qq@�‰’TaG€¬«ÆÂÕ›:CµmröƒY4Ò¯Õ“<ªƒûbaÓ(²r<<OIKï�wÔ:”—Ò ¾àŸj×±ò½Pb“_T«†:1ŠÙÛî½ÞZµ7عóÆx¬~¬ÙÑkóuÞ’ïJ(«¨féç<Àñ)2EeO Rø�–7g�{µÂ4)�úp£zY¡N£®c�aÄÉpùë|­šÞ©h¹á§�=ÎGÄô:ì�'Nú§é’‚çüä%Ùßc»ô|ÔòÃw•Â)>Â[ÚÛ‰ñ O´øŒ}|º¹ºÁZ€ZñðšÕðM?¶x\¢ðb gâ�(!ͪù -T)̯ɻ (V7$èUŠƒ…Ú²žñ ŽêØjíUzle œKã8WsrÎZ�ï{6ìÈs™þs@Þñ~} »µ?ÃY¯ý oá剶;¸vi¤¦$ºc\š;�w‡¼âX½Éy1ƒM3@‚Ò8s$ÛPá(£s¢ò6D«§GŒæ±cjû¶�‹v¥m ê;y)ϼs\ g‚rËŸËvÄx•Ò5@˙ӉÇžÇèʳHyÅŠ¬#q�gwD 8vëÆú+/ ÅQÃZCU6;„c%�?=ΘG¿ÈL(Ú³PÕ} —õ]_‡‡²õ�nø›Ö1n÷um’;«zruMH°ºH%/Z>É‚Á@Í#�ú+2Á-ó!¥lÔµ¡ágV¹Ü+®Pÿ«@5ê5'âÛÑ)ǰX8‚�YÏO?—8iܘ-ª#玩#Õ"v[ç<%-Aó¹¢7vŘ:r&Gì¢ñ™Á«UÁÊÉil¥g�eÏLTCM‚„øô{nQ°«0ûÛXì¼v²�2¦ —8¯¨çùLõ<¾†™,zd&A¿'�1uýÁpÙ¶F‘Ú<ùG½—SŒÕŠC•§xY㾩|s–\͈‘4ö }ö»€Át/• —€³.…1JǯcþÞtøƒzÚ»ãI0&ÜÈ›BXv—i=HÅ=^b!Öîsnt¦é9¢6]y!êU”¿ÂUëEb†Ó«�:G™„`cõyc>[%Uäd© ç`À«`·è…¹Û+Ù‘nÅOþ nÀTMNܸ±Íˆ3†1rñMÏ ¬â#pZ©“�‘®Nv—ìS^R±ŠAšRÓãÇ$E˜ÄEzïX™˜Èhyæ{VýF‹ÓOê§¿¿¥L% Ó¡ëRÁ?POc�år)™hA1Þü–Æ­Fú_Àd†Å?£šö·SÒiãT§2ν¯:k}† [ö±�Bû.�wã*¡l�X_Ðãmj§"ËI뛺ޟ¥k¾ 57 %ÃΫãu} èxRí¬*¼À•ùñe£ÙƒìÐÛÕGçõ÷Û ¬/ÿ½ÛEKõ«°¬�Ú,œÈá1•RZ)¥ë'R!=S…ª˜íjŒMU$=Ú=ß:%»ž�çIJzæªü»Ï‹O›6¾Ô®ñpHþÞL8ó­B'�ÌNÜ[濾sñÛš-ôÈ=êŒr®n’'øÚ Ò†^íŸWKB%ßŬ�(~8xªª‹É@†š>Wud$0ƒ+Ï'‚ ¶µï†³¿’Iú¥ê®õFŽy~�d1�K7Q ŠÅëòän¦hヘ;Ž�ˆè©Ï:¦ž�&õ “tãôÏ;‡3ø-„Cgn,Žûe6ûí^œCÎ8“zeÊ;º.ØZƒ|Ãr‰›¸bZ¿u^= ùY_€Íê¤5, 'a†´?lµ0øñ“ëú®Q‹³À«"cpÉŒ¬&§r+7–]÷”T•�㵿³– ®PaèÙëp³ho>àôÒ>N|€— &íÊ1ç‡<yœ„¿¥ ¼õçM)Í\�€K"mž··øøK–õÜ£æì_¬“ãQI�Ð⣱·EÕ¾sôÅq!¿©f—ë�·“zèC ³:¨ûdmf20pûõ‘�¸é2Ò®'vxè}ÆÁåš”Y,ˆ"DÍ�ú|µÑᵨdõ´NÓ0G�6A÷v?=“=•vVö¯/•oÓÓõÁñUï½H$ÐIÚ´ß0MSÞæWzè,%Es�2!$y"^mŸ¶…m@é @¿¤÷{Ûe¨¯úîGæÒíëjbÒnMvXkÆì\õ9!é;fʯ�Bõ7_BC¬‚›Tgl‡¿ä¸y Äi®¦Í]zÛËÆõzú%+xù~vVé—}qSaèØ·v&æW$‚‘Wv²†$SØ#ž²™ô­Ð4ç7ªu’�8¿ìNìzBÝ^îl.‡ñàÃ3°ÞǦÕÇÃXìäY\¼ ×£Ntó"ˆ‚×Þëéâ}OŸœ¹õÈ.<¯œÝg.9ár=m8t_ùEaõþêÁÁd½2�ÿûÉð'£+pöÏ þï‹ê¥^n@BIºüsKífT•LqVåvmåŽ+{M�dF0à®ÜWãó½‚kGk˜‡- ÒhÊj÷%'‰ë¹´©‰~zÜë«N®^˜úM¡**ÔZb·ƒÂÕ”TÞãñœ/š!'�±áê'®EÝ åï¬ØÂls„h£óÆËKìòÌšÄÂ�‹ÎñpÁÔe°ZX¡OÙ æ³�r§’(·Ðáô›< Ȭ ¡†õYyuS­ßW �ä'#¼¯¹ ƈB…ík¡ÍŘ>¿:üå¯B>o½ •¤EDj<ÎPrÉ¡{;E—â�¬{†S6üÝæAT�áµöDœêzòfaqžf¿üjH€Ö¸Ø¡ÛÓé*Œaj_M:$†ßpš2­fzåX¥úš*Ö’lŒ¨ôËkSË€ð¬þúKâBo2sN¶²pqsÓ+šH®¢ï@ÍB¸î7ç"ùU±WÈö x‹Äß0zS†Ùöh« Ó£\XLRß9)nmV3ËÕ9|î³Þ�aCî /Z£bo¥9ÅËaãÅ®ù›¼”“+F¡.ãx–.¸[ø–�œ/ÕgJÆ+^�ëw‘(ûÖ‹KÁ�j ðEy‡Gñ8–Aƒv UðÕÐæ—pÊj²‡[ûÎÆë¿pbÃzÍ>C?º}é -‘|ê³+ë³qüí5ðMš£O¦ÈQ¡FÆk!œ-¡‘Ð^ƒa ññ«ÚmCe·A Þó�cüD�î-†ÙnЋÉǪ¶ö ¡´Ÿj8hu|”yÃ$9OäI¿VÐùc‘�YS¶™«•‘~Qkj|p¾íøÔZ¡_ª m©ƒ±œ'­V…yFß}T9¤ˆ•hOã�6'Xä&î—þž´ÿ c s" [€b%b4S¯8½`õi’í 4·%^‹s€;®™ÂPîÙ4‘÷’Õ£.!UpI¥J„ âº«O‹€Ì>Woeu!íêJûS‚Ó"Ý•…î2”µ”«“ùÒí#ÖWC±×Úw1ë[ºíïѰy�\¯Õ2—£VŽ1;Jlž‚íùFd�ÜUz_ÂH,ˆ‰W©?—t«c8�;œç,¨/uk»Ì¶Ð“ŒYw$rA ^“UYÛÉ�G²cš®4Ââ©€}Ò–�={o‹·{Ð~£œ×ðAvzü›M#õS|ˆCÍÉÕðë1¤¿ŸUQ.}ýL8ãØp–ÅvÒž/ðÕ¯ý‚dž-’IG*•E[ÜàEÉ X oÅLòÑÔ‰JÚâÆ-Á;°d¦r�ÏãZŸèŒÛ÷  a6XéîmÓMr±.{˜Fû&îÍäÞn˜a4]ÁR kkRŒÀqÛ®ª6d–F¼í@�ÈçÁêç\Ë„ÂôuÇ-pø¦×:K$ò’pŠmr§²‹èº¹ÚÑt,ð¼`¿ïAE] ¼¦ƒêW¸ ¶Ìó~Û±¸Š˜>“ñ~e˜$ÖÀK¸u¾ßÐLøi)¯hïÐr{¼�19…<²IØWÅIŒ÷¾ `åºÙœcöCyl.wè7“‘ýŸéæwb\ð©E»"‡»h`�Jªå»CGAoéqíÑ‘æßMF¬˜' d¨í%ÑòN¬P_�"GÇiíÑ=žÐ%T¿G;±™¨ªÕàÝç›LÜ’Ûʧ¦i‡)‹q`ëÑ*a¬õà‹2'èÐcEØïærÁac1´^e§âº�&Œêùػޜ烘<…d¨1*¤’8FͳP²6Oýh£UíÊ'7³v­˜nÒ©,�¯ÔÞUÝ…ò5±4'ì�½ÇÆøyí9ÿÁ™üUeÈç#�ô™ú¯>[-ï%7á¹À¬ûŽ6~¹G©WÙÍ&Ib( þ¶ ­ƒ ‡½Jå†<®là©}Ëki9nîy¯GÎ pÞMý2æ`•µ™¬Èjõ&ÐL¨j š¨­y$Aå*Îq`”µ cVK—}ˆ`ÃÍÛH—cåEãg¦ UR™ ¿Sªs£¢â ú^Oȉ^ý‘%³;˜‚¦Ó=UÎ;§b‡�ÅD¼ÜºM:prË$p;$T%zuÇw¦šûØi’æ#·ÿ¸»‘Ω¶¶¯¾íÎÐÕÌsÙm*y%õ^9šÓÃÏ+M˜u¦í|õ¿�B^² endstream endobj 108 0 obj <</Type/FontDescriptor/FontName/ZELEMN+NimbusMonL-ReguObli/Flags 4/FontBBox[-61 -237 774 811]/Ascent 625/CapHeight 557/Descent -147/ItalicAngle -12/StemV 43/XHeight 426/CharSet(/M/N/a/b/d/e/f/h/hyphen/i/l/m/one/q/r/s/t/three/two/v/w)/FontFile 204 0 R>> endobj 205 0 obj <</Length1 1626/Length2 16063/Length3 0/Length 16902/Filter/FlateDecode>>stream xÚ¬¹ct¥íÖ&ÛNE+¶mÛ¶³bÛ¶*¶Y±mÛIUlV’Š­SïÞÝýõاϟ>ß�5ÆsO^s^óžÏ3Æ"'VR¥6s0J8Ø»Ò330ñ�¬ìLÜ\Tì¸åèå�fV€¿rv8rrQg ±«•ƒ½˜±+�  4ˆM,,�fnnn8r€¨ƒ£—³•…¥+€J]E“š––î¿$ÿ˜�L¼þ§æ¯§‹•…=€âïƒ;ÐÖÁÑhïú7Äÿµ£*pµÌ­l��QE%miI�•¤‚:@ht6¶(¹™ØZ™ä¬L�ö.@j€¹ƒ3Àö߀©ƒ½™Õ?¥¹0ü�%ì0¸8M­þº=M�Žÿ¨è�Ž@g;+—¿Ï�+€…³±½ë߸:�¬ìMmÝÌþðWnîð/@ŽÎ-ìþêþSrpqu1u¶rtüͪ$&ñoœ®–Æ®ÿäv±ú«8˜ÿµ4s0uû§¤éþ†ù«u5¶²w¸=]ÿÉe˜Y¹8Ú{ýÍý7˜£³Õ¿`¸¹XÙ[ü:€3ÐÂØÙÌèâò7Ìߨÿtç¿êüoÕ;:ÚzýËÛá_Vÿ ƒ•« ÐÖœŽ™åoNS׿¹-¬ìáÿ™i{s�3Ó¿åfnŽÿSçtþWƒ¨þ™ê¿ ŒÍìm½�f@s8F׿)Tÿw,3ü÷‘üß@ñ Áÿ-ôþÿ#÷?9úß.ñÿßûüŸ¡%ÜlmŒíþÀ¿w àï’1¶üÝ3�9À?‹ÆÍîÿåblgeëõÿåôŸÖšÀ£q°5ûO�´«ñß–Û[ü¥…‰�éßB+ +O ™’•«©%ÀÜØöo¿þ%W·7:ÛZÙÿòú¯–è™™˜þC§fiejcÿìÿVíÍþþ_ªþžQLKJYZŠöÿ°\ÿe¨ôw\Õ¼ÿbû¥È;˜ý¯Ã?aDD<>ôÌ\�zV6æ¿wï/ n&¿ÿCÊbþ¯³¼±«³•'@÷oÝLÌÿªþüþë¤ÿaÄíMÌþUWc{³¿“ö¿ÿ¨MÝœ�ÿü¯Ëÿ·êÿyþ×Ì�ž@S¸µŸ¦¼¡ÖÙ™®õØù£ÓbºƒýÌà£aŽåMj%E�µ}‘»ÜUFïua ͳ<Ÿ^+¿?ehŽÆû±l)ûÒ€ ñýH©ŠP·(º8i�‚ Ê3Ï5c}®–åv t8˜4Žö¦•U ÊÞ¡f»X�a®ž¨IÝ‹1È‘üMÓ¿cv£4ƒ Õÿ>§H>}z¤žé»�8Ä£ÍûKÎkŒíŸú›8ÅÕËÈù¾ÉôòÕ�ÓD}ÂÍQGfM”!Ѭ¥3KÞ¼f‹& ›qˆ¶F‹ao¥®öñÎN>U#X?VÄî±LLÙ­ît±AÒ ¢mxx…�¤)!‹¸òU=¡ÿ)®Å"bâønž“‰�±R†µº¾�*Ê¢=ê „ž⇬'[„7? {ê\IPƒ‰?»Â»€IÖQ °ç~à ”G$œûB;Ë{õ:hÙj½T«’æ†(N¼¹ë—Î e@DF�\÷º7Õõö¸ÉXx”Ð=obõ„V|Í® öxé#Iñûv>}íüéº5¬ö¬ÕúOŒÌ£í4­{‹jú­/~¼¯_!¸ S/ øË¥ r´—DŸÈ¢À*–`æ7q~‚JDeÇ)n‹ v€. Z²�“lÔ<wË�öÐVèžEñXzFÁezÆá2Ã�¦d#�ë›<›¢ÕO´Ô‚“ µ`¯ 7þìüÅhW¼r§ùÅífEg‚œè‹c†n^¡v_Ž�!òûæjË@7ôž ˜¾œ(µK|­…Yq¬DZ¡E!+)VƒKXƒ­„ Ûù¯})¯¶áúÞë¥G 3±o¼q UÒ†Fz‹Nê©P¯�! \EЮ ¹.¿»Ì`íû¦Ö–íOßvAô?uâï[|sêvÌ9%á§v«ÅJF³Ïnb,i ?ÍûÆÓ«'í²Êî›”[n¶þ°Ð«~{šì¤pxc3­ñÅ[ %^7‚2iBñ õàÖ,ÄžÇìôDNÌ[ 3N 6"H»üÁê‘d�Ç/HSïü´þ�L¨½ODu�ñÌ%ϱ< —øA”ÛË�õD&p6ÔÁ~+'X[ª2L—õC÷µügòÇ×Á NŸÖN‰™_"½ÑÝ,Ÿ¾F:øWº¥«Ìlù‘|…@?ôjàµ'doÌÚCÄ“5|¥Ã†–®:OÉY�ŽXyR ‹VZLº˦Ž�HÀ¤<—À}–Á->yEÇKÓ)SœµÀ…ëè/œ�TY•¦gí¤CT·ÏÕ_$Ñïþˆ91"f� ±õò“0]JÃ0„º…åW qݸëX˜�áS^ûüº^Ö™lܹ9úÊNüÔÍ�KZV7ý�x…É7'åo†€—DîM¡Üiá42¸_Ñ‹—‘ ³ÆwWWÓ°("`˜éL‰èžº¶ð=3ž#áÞ 'J]ľ©V¶É Fbs®|ñ0¨½Vë°n*¥¤™x,½ž0åËí_JÙÞƒ¦&º­÷B¡zûa[½ÓaØÀúl›e)†i92ýÐôu<á×£J¶;2䵟»¹„‡?OÉ6faâzß!Úîq^”-â´8Í�bÊ$z²â0UxuƒÝ¢uN5LHw�nÛJ4Vë›ã1ç ‡}hî#*եݎ etè$ÿðð^€=)÷‚ã¿`$¯¢¡cä±þ²Ü:”¿½>ûÍPXÌyøâ9/µ!Rqìx'–2«î‘œ]øò®EtËžHÎ&¹›q:ÙP1ºXÿù¦èì"6U ÿ ~ñΉBŽ<iz1áŽGì"×`i•+$K({²ÝbŽ^íˆMHwº]û¹,dw@Û‹f=Uh¸ÎK>f ‹&S³�#o»ù”eøÍCPåÀ;›Ë šêJ�­�«Þ‹°²=³øz“¤Ç»7ê»E¶*êæ]Á|ôŠÞ*Öj¦_—¯Ðd"ÚÅØ©ï *Öe±o‹e8Šz)vS@]O¬¢1wkHr¢ÊÍùÔ–-ÝÃ*;Äø‹é–šrª ;vËE帓!½ayAÇÚF&>�ÅŸAa©ŽEPfy"ÉõˆÀŸ¹FvÌ —&­ÃgÃqË>�h+äkåX)0´ƒ�m[´…ùY½¾ï¤I¤xnaYÖk»Xfr–ûã(òyÛ–ïh´…*�βáÕò»ÎÑ^€/0û®…O¦&¤ùª è� …®N¯’㈸:1ŒæZÞLÕ¡â¨ç’ýX1ú cPëeK‰ê,¡›Ö¿jj¢e]±ÅØKФWXü´à¾SÑ8j%dí�Žœ§ýÇE“ÕÄáÔ6¨% #ôZeaC¤¦–QÊPlb…`äÇš�¨Bêùô†©óibüÀnõUÖï}†š¥ÕuÃtBÒÉßݺö²r)×°"·MDñ»ÃŒ¯»ù7{ï˽µåNuƒN²if·b¼�M-óÁ[~Tú�­€û]T°±è�ó"-ÔO·7U!ñ#’‘Úºà)ʳÎu„�àÚ·.<É7å¼—Á¶_GÒ‚þb´›H©˜k¸{´¾LÆ5 øTzñêÙ.ΞjÊÎÈêl¯7Ü­—‡ÂᯢßÔHFù“»ýÃíWC†ðjP9¼“æw�ƒkç¦G yûƒ®ù~¶š²}¼òã+(kø|¤Zu@ò"8=q_™«©.÷{’iƨPφD¼1ËܮүàQͬÎ9òÍMKõ¯|G8‹0U¿‚·6�^–ÿ¦UóŽG?aU3ƻÕß6túà´SF>B§ ­¼%ÂF|?@ç¹SL……ô^-4è¥~yÄ$DH 5Æ“Š�ÚeYz±A©ˆx’^¬4*Òz|Ý{¨�*‡mëæ‰5ò£6i,@CJœ º I¥ÑlóFÇÒÒÀì7ÈËð·!?ú=¤ïëIúNü^Ce4›O–Ð+1gP4áYƒØÂuñy|6§ˆ>rÜKĨÕw½}S:2‚A@á©Ör¬›�µy­[kqëe1®j!.TFHCn¢G‹Þ~û´TSJÆÙ"a —I/�}ÞÇã8 ùv;røQ|»—ujl+H™Å T+×Ã@ö5¹æ®º¯ƒ02RKvi%òñY®Z¿ëQçÿ€M�Ó{Ðb¢ïˆÂÙSv3k¬ çÉZŸÁ}é•'ð›¿yæw�ù¸t­õÐÅFð­sL&çXö¥ØÅYáÊS ò5È\Ÿ×.*ðõ 0& 5�AI à °Æ…’a0÷wݦÏÁÕÀë›E®Õà­ÓíýhèŠÝbÑÝ÷‚=³u6÷éS)–â)RšÓ�*•õN½‹ èýo»·;ßM‚(ï7œ@§Ðäh[B=¤0Æ´'$þ¾Œ6I¯f°¸Å{‹ë=»9z\ )!’{€©TvT# ŸLK‚$*s)„Gß„´2'Ê�B_?³vq­I DÉ'qÕÄ1ô:­ª�Ÿë1]ÒæL§l•† Ž–%O†tžú˜Îþ�rëj]Búf¿¤}™¥ìðå�ùh«Á ùñ¸Hf}n®¹/)µßoO²ZÚÑgÀ߈¿€Ö<×꾜cÿ¶ð~_7`õã.f<¥7yJñg S�ÇùR†·¸±Ñ1¿pFõJx,^J•è“=þj o?½ú±å÷8òòªàØßékw¥K>ÏKF±�xTÎ-‚W¾È–EZèª/#—ðÙ¥»äïkH&QòqA1¦<ëça¢¿®(5&X>@n {TëUœ,C|È—Õ¥ö¯ äog eös"médêÚ¹Ó+wY:K ˜{y÷ ¯¹_Q¨¶Ù6úÅ4ÎX�¢×•H £{*+OM)í‚Ø�ÐWJ‘£àê òÁ4�„j²YÂâ«ñZÆ8.‰ùçê´X›ß$µÛC£ã€¶ä×iª„!ëÄÇ“ßEqÕJ§]ÉP~¯–µÚ�ŠpþÉAU ³ò-¾ÝÒü©úfNùÈ„YËŸÍküK30ØúÕ±X¥Ú¹ü©u*þV:žÜ4Gœ*dH°²/ñÓ¹ngâc¢Ÿ»´3�Žêþ�˜´|6²`<ÑÏuK¢^…·Ôk‚}‹Œ#5c×θeú^ ¢ôÐÕ¹;[ï£[èÏÜ2Àó\Éàúvrü�»OPOâ>1eÐxäús>mÑÀÉöÍMµ3Uó}R¿+ õDdë%,4JeŒ]!)©�‚kÆæ¦çcGÆŠõðŠ?¤Ð�xë-"U|ƒÏ�*Uå…0×ë âc/þ&ôýfðGìPÄ®š òÃ`ªA˃¹õ®�<¿£÷úFØú�#çÁ}’ÂcÞ€>Þ‡{òu{DæÌ³®: 7DOœ>sEÈÖ¨‰ïxÃ6ÆÞ£Ð“N8 àßêÏÂ!ó äå¹¾¼×õ \bÕ—Ü­hGæ1ZüÍ(š{šç�ßmÎûߺ‚} íÁÄa�ãANè@¿_ãd »Í¾šh ÉêÜd† ¿Å<©ã`‹O!+ö˪gîÙ}DѺ�Û¹¡TÜa&ê&ôI =Ë2.�ÖÇ´Yç úÖ§ÏV-ÁñÔ�7¹ !^ÌU5’‰�~ IÝw!�ÿ42”Ɉ vI{ƒºÅjãA½åÅœØTêu�†Õ–T'å�DƳ¤÷Ò$̉X„;DzòõÜ’ë¢ÇOްè0gj®UK×ÐpV‡Ô�Fe"òÃbƒ {g\iò”¬(�âÊÇ=ªjáS¹;„­©¬ÄéüÁz:Mxmk7‚QwyözÅÂvOû]`°ÄA‡—ëZL—Iø90¥ÍWl‹ "”ùU+ R`7 ­Ç,*ß$¤D6 P6}ír®¡ÙÔvLjX[�£¨ÍÑ­ÿ¹²a¤–&ŽEió±#wÔ‰¶í/m�M¤™fþ.S�/„tŸžZjà§Žnv0>ʰ>‹«M£zên&Ô£íÕ<ÍúéTO×°ù zŠdªÍÌ€óy  •›)B5%T�U£ Ú(Ì9j³Ø(øØÐþ<ðëg2šï29á�Ó«‰à»WRaÅkf[ú¬ #˜SåÛ~¯Ù‰FUí‰Åk§¤² Ql€âTWẗ¶0eÆÀ�€2Ïž-úc§� ä4ê²zä“Ô¦G!€(t#½ôéœJä°*ÈÞ›¢®Ê}žèŽþµxYáòVY÷>tÔ“ü‹Õª—y.ÆûK¨ý• ñ‘xM^«âÅÙÛ”a‹²kͻ㜳A´OûGñ×Lù¦¯¦ñÞÕ( VJaþL¼:˲¬ùoÔ\çÉÉLî‚If::—yÄçøŒ&§1¸\oË›z�å5Ì/â2�“¸;}ÜïhùÇKG.£5ïð[g»áf…úVšüþôÈí»ÙÍm7Åà1³=6¯•¾»s¾ËŽÄajg|#a2¨]pÿ¹ì�5-øçBsh¼“\ñ¹ChätÂÞ`_Rjœ"¹u§ÅÔ ;“V ç4°ü�°§*­-ªxóvã«"¨b~bŽæ®¿T¿IàdσѬڙãÍ´Užtêtñ€wqfï,| #YÄ 36…¨¹]ç’1þ y'˜\�ÍO˜*w|l-SßìÙY6=«Úe¿-ÌZ?ŹÇ^{¾¨¶ñ£Œ3Ý�›åtñ Ñ¸:†‰d¥aG�×O�ò4ô"HcŽSlÂÕ—00�olA½jÙÿv:KÝÎ{2^%ªýîŒs6_†àóbl&<øAR#1U!HN«wñ„ޤÄMä$^y;EB8ÖM”«fRF}N±ª03�ºM©fh¿œ‰‹Äa‡þͤkIü–Äîq$^]¡åhEÃñ¸Èµlb3W tmmö¤FVKr ,�¢×ÿ�ò>]±îã‘«Õ ÔÔ:z¤" ·7lABq (ó¨ƒÿ€.edÚvŠÝ ãiÎ�w %xŒŸõ¬pº¯Îgô4ñ‰BÚ4 ‡:r*ýU‘Sâߴ‹T¥{àJ¦þ$h®¾%w«LPê Ìlw‡ÅP»ADnD{ö(@.“n Õÿ¹”ò>o“ËÇêoü«&³/­ž—/â `£²æ ZÛ"zeo ÁË¿tòzÊw…Ú)²K¦›“»ƒ˜X¾ eä�‘,@6‰žîÎ âüc[êΉ[—äÍ}ROÇ3¨x4›á«hB(ënd<mÉ‘B^qçj QSIäY;t�^¦�îõŒ®=Rªz„ n@0«™Ñ÷í!W®RÝù‡ä²É¸ë'çHi¢Qì®ĬñúWßå•3<oð§ñ‹8òñZS‰ÞAÅ£Œ@&~½ÿ³”5º·ˆ˜6òúSBÔl>‚¡ÈiÉϲïãì¿©w+[WˆR"}fÏíEüœ?dšˆí«™Š­ L<©UÕ÷çè&ê\f,›xâ4£K%×ÜÃçâÑ Ã”jÔÙkB·Àær�¾ÃÊ o"Óà|R=3iPE|ÔU™ˆõŠn¶–C˜'WÐ̽qŠH:Ëpƒ~¨ÙIèÊH+DP‰¹ˆØë­iŸ�äH×l’µíÖëªîuôŒ¹÷õºv�m%­ oY]çûF¡%™1Á> ~C6 ]M«|¶s1«Ë唉C�2Œä5üY«ü)"¹Eb™&vVñsŸ”©O“ñÙ%.Í®WPŽa"2FãÌDxI|êÐ髽§Y±ö*AÉLmaUÿFvË®Z«XSŽL'`Á ·ßp)÷³w§ ‹éüý’�K™ûÛŒ—ý|~KÉÎ-½(»ØÑmǸÜûvOME&ŸÆ†¤/k’’ꑼãÒt›Öóšý<h“|lÀj³ Ûl÷ú![qètŽ §è±<YØ·ˆM?!¦À†j¶’ s¿£VæBÃõ¯›€œ†ÚÉÚ²ºÊY§¼Ð¹ô4ë0aEñìG8�¹æ¡-›vËÐ;&×ôÝÙÄÖò-¨A·tÂD„þýÄó½qã(Eõoö�mk¶<è§• [Æë[Þ5/ë4‚6ƒs’iLwY/ÛxŠ…Ö»ÕC�?‹ñÓ§�˜Ó"?ÒG‡=$axF-�ÇC ÁgûEY¨À®vœùÛ¥~öØ\INý‘váìi‰è¹¢ËÉ ÙÜž¸—¯Å/“ŒV93ðí×J¾`w²%ÚxD÷vÓd <öî¸vÍÀûaxÒ�¢:Ê”–é³~x…ñrŒ$å†=~1tI0gQ—¼:F•�k2Y5ɰzÚGܧz)!ˆ½Q°Ü›Þ7GõŒ=óýÚwLfÁ;y �E•aÄÄAöÔn�™ á°„à­ÿ»6§µîΚí»ams°ET»gÂTÅ¿çr)÷ûRÿÏ ¿Ð ^ÙÀZwP"Àé|TÚÏR黊Í!óÙ›À?µ¥Ê{ ´Ç+vùˆh .ûÑŽÁj“øÝ:¤’ÕTgFh<úêÁáßU½Âùw�£K/éý™1 ˜ªû�R ©q{nàÅàhZ›²¾fØõ"ÌÅÉÌRºmrå$ïù%ƒ)ôš:”3TJ1ª•""‡-[‰SVêalÓè LZ;ÕB £}ZS=13'ÁV.ß«º‰å\ˆÖ~»b°%¥&µc�QüF²l"ªÊÞÒèl&ðòoQÃþ©ÍRz'»æ¢OFÞoŒðaýˆjø6Ig^Ѹ¼ç¬|’lZù1,„­£åÊ}›ç�r4åÍI†Í£Ñ—@ƒ‹¦÷²QšÊŠ¢I�¡� vô4±ô“‘ü4”zLš~±iáÔ#ýrp¾úçÊ›Žâ¶’ò�Ðé2¤wEI’|±�EÔÕ-ûaqæuÓT ø·­ž—Õ!Èž5W�ñݪӞ––|/I®äßå�oT‘‡ŒÂ ¯¾>\�1¸½ºÍ’8þè ?aý*GI1 HLdlæsŽp8Œ|§pN2zQÅ PØrÀ󹇘C³—º^Ìg˜¹yÿJ�ÞàóJxG—É¡sôÌ„ðL&�V!HÎ1;þð·HÂu‘sõñ–òýªhÜÕè˃¬?[ˆßb<¼�(ÔX‡×Ônõö”µ_±Ä—?j­Æ©ß7VÎ ÐÔcMãRf[æT‹—S�lkþž¡@Ïñùê±hËvÙq»°œ’‚g6“öyo}èg˜�i½ÏU{ºÍqáÇö=ß3ãÊݦ¥æ7‘ Ú/­†ÚHÈ~³Æå‚[?vëÌ-;�ÈìºRÛǤÃYþª4:Ä/ɘÏqâ�Sµÿ ú–Ï] «Fü;?gdø^rRƒX.—“Ôx²ú¦ÃÇ}ì7mm“ßGj�þQÂEÍJÛ°±+]@l"ž›Dk‰‚àÞøãVû"d Èöz1¤å˜Jxûa2¹H¾¢3¤™”P¸šŸà3fÊj§qwì÷r¹i¢ ÷VçLN¤HßåÝÒs׌FŒ÷ž*çn,¦ÒîHQT—í¼"µ1EXP.Ê3Ã>èJÜš£³µÒVÁL¥GÀ*bÒª¬òÌ 9•BÒóË"ǨoµŠ¡¹Ýo+äi"S@Õ:’³>Èk€£Y.Í$ކt¿:%¹,¬‚á€#Àg¾{+ET·/tÅŽ'G½¾ñõñÏ·ýðñÖ9eYe“!𶜈¶ ‹ÈŠõþ0Á˜ZÕÝÆgœÚ%$›<Ð'Í:™¾Ä;ªäbè&°‚{amr©^“µ«q.Çjª,¢w7Yöñ~t›¬ˆhz ÚôãsZÛ«2ŸBÇäÖ°ó7uô#ÉÆµ;óŒÃÖâMâĤ- ;· d9›YÔ?íùbÏçBBmÊÚ¥âk1?“|¤âºËïLªlÞ{Öô3—I÷Ž|õ’F6b‚œU¡¶Ulºœ�ÝÐ +´\÷*—\7K•ä’i©êÇõÂár’¸DwôBׄ ¬Ó‘‹=Ã'¨ó Ð/œ3Rç™Ä´_Ž—%žæ¥iøÏ[¸ˆh;Ä�hO�çJÆ~¤Þ'wžQA¸°4ž{†Š½…š‚†îr:ÚYñ—ø=è4Ž'S¬€èÞ§ÉO;%´ ÿm…íú1UôòOg“C_Ósy#¼w?\.'Ù- ©hóª:‘ISi[7ëJ™ãéNIìÆ-î1ÉmM Ú?jb0Ò»&o H×¼óGGâ:‘8õ6Z]úÔ�Ô©ÒG[‚NB$¸xO}A¾¾–¥u³&q\1¡­âð[–Y( q>elpàéO¬¥�ÑצÜýÅ’áxÄXq²„< Ðfw¿s—$ÕÉîcÌNlWT‡*T•û°�{Ðb^2;¹XáEßœ€xuv§v(ÄÚh­:C:gWŠœ Ú*œ$¦üZ±ýíÛ; ™³1oDj5Ëf9é²¥¢Eq¨BÏdy˜õkã·¤e|å_]ut>,å`NeŒ¶Žñ€±5ù%½ç¨#ÃŒÍhÜù*BR¶Ã] ½Ôâêéåu¡0q1©çú³ù:õ¡}�ºš”«: ãÈ<ÈUà9“ãÓ�?Îwý«x�' ^A£“X’9–¸ŸyíÌ;í7²bƉÊjPU 'ú@ývm¢»'WøéþpË hqÉfáôX­||(7Õ¸¼ !óýnÜÚ2„jÅO�v\! N¸ŒNE<ïÊ9¯U»ô–›û¥Ot<ød87 £;’b’ø­qðìÅó0U+êCí~q¡C£ÚÁÏyáð¢•c«ÿ ͉çÍ3,¾ž(ðd9•JädO¸Ÿ† IC�†H5!#€¿|3‹}3!ø÷zÜo‚@Ð"iLˆž’DZ—… ‚FÓ*¸!;´døÁØ¢ú>ÙGÅÝɲDÞl`«'ú‘)ì7Ë·'u œ³w_²Ýq*­l–䑨–b#ú²ßÏU'ïÞ\G– ŽYå$JO*‘Õu_þWQ "®N[­KÅ¿kWÁ*$ml!gÔš›£ó˜l8�{TásGoÔè®CÒ‚(‡2 Yøšb×s#kýÝFÚ Á‘làT¹r˜Y+ö³hhøÚ³µö·æ¿?+ÙL'„Û…|[7n 2,_˜Ý“ÿfÑÝ>–ʵt"œ?Ï@f„Y’ µnzŒLè‚ÌõÆÝJO>C¨[?c6 #[e·Bš þÙ<Nï7¸¢Ó¼»sId”i[͇áSÞZ)R\@R�^?ÕQÅt½Ãù¥…ꚨ]ƒ¬¿(B— i9œœyè2,(pñ޶-½5»»gC¶�gª¿3yôS¨ ³A M»è2&C1‡µù0‹\±Ó«ã”â…e~=HÇñÒü‹]8îð뮼sð¥ûwáêž�4Á«À¥ë±QGAåÉß½eîO÷²Z½´>Šš�4�XÛ½€nD&soQ‡žÊoæÜìøvR6›•ŠÄyøÚýÛ ôâˆK}…p¢Æ0×?Û}¾$NöÒWÕœ;Æ/7ŸTã«—ËtèEõ›ÝȺZè ù�>¥Z ²ít8¬’ñH>øßïcL�Ô ñ û[RîÏÈ\`H»™²||É÷1M#.ÃrPèÛ&zõ* ,ÐmŠª­Iãà‰³MS*š´¥Â]‰m;ëÓN‡�õè„eùÁ-`I·Ÿ „8IUµ ?ÍÌoßÄœ%²Ç%Ž7i;0õsÝ2�Ó§v‹ŽðŸ<§OßõåPáVÐíhL ¹¥•êî’UörTÚ‹ùf¤—$3 V$ ¯ÉŽs.ONyæøÌ¨é €Ž˜ÜÙE! Q�-4Ÿçg8–¼½Äï÷þ k`;·wÆ�)1q ‡•¬Œ½ë°ÙöàB¯r#׎ØÂB(i”Z(ÖH< Ä‘2Íù„aŒ¡`›UúZN…èn‰-hŒð³6H4~Ø\�ñ·©»§öÆ–?Œ!S±(Ë@áPá›*UÑö’ë:èäC'd‚ žx æÂ–EÛf[ÐßwC–~¾(cV üʇt3p‘^bÑ[ý¾J*£ò4ÁøØÃÖâ"}¾KÃ9|pÊ/-»ïj—­Õò`Í%¢™µWý‚&,=ùè˜/m)©|Ù!L&Æ@ÝtO˜µ¯ ›*Ÿÿ<�œø¸šZqqÖD Å€SªZÿ‘Ššâ!p¤ÇB`SZüƒ‰}>Agô›%ÁmQ0½˜XF2ŠHs0ß®4ò ¤kü+lTãû²ö«u=#Ö¾?H'N…¨oâÊMýÌ­úÖ§y§fåZ‘Uh¬»»÷Kñ„±'s}½�d‡RÍÇ[Ô£�–,O²bu¤4mÖ0ˆk*¹—ÓÈ•�_]û"ŸÐD¿ARJ –g)t­Iø‘–ÖD'e‰Ï7òpoïÃrÐa Kƒ!^ØÏG8œúD9tÔ¯ur›¸uõ" ØÍÈTgØ’Õ•@ßÖ¯—Ã:·/§q€Ž&wö�{4|8h6ïqÑIcËö Ž¢‡¨çöëèì‹„N«M$CÔÔGõ;ôz ê“ê]ñÇÆ[(�b!ê’zÂ{ôãkÜŠ2JânÎ[•¬#³f0…šMÝ“p`QcwŽfïy‡p¯¦Û{ñ&I§iÓÕñ�;}þƒ"‰Û'å~o2t¥¡#žC`×LÄ–·¸dz_¡µ8a úõÜECÞ|(]K”¯ýVlâ~£œ“�“®¢ PÒ ]°<´ó£>�su~ñÓ“ý£»ëŸ±’Jµhjzó¿Sʸ6z¡(KkÚš¢ºÁU)1d1Ê™™Yw¤ ˜©h_w#VÛè;'´ˆÌU£GUˆÆÆ\±ÊQ·ÓrìêY[F©eÊ:øOnò»¦ÞÆÕ±œ°Þ þT1žXÎ�J6};”ýE¨*v»Ykµûï“rûaÕUÆùÜ�õlÎE…Þõ} é��qGÉ·Øñ1ï;ù˜j_Êý¼4ÏRÄv9Ɖ©mÊ!î,Þæ×"@¿IF« è,Àp6<kYµÏ©ø¯›¯($ˆ‘Âó#ÛŸ9¶íÌÈë?5½Qów64Ö;`œ¨g(³)a…7¾iFQƾԵ¤H+`(ú–ã060çÐtƹ)»-aé8Tÿrð©ð¢ñ�ü l–PaÇ„²�&×dÕ—e Îçè£äÀý¹ðêúÁ§X.Ê|Χ‘Lž¤6-êbbbu3d-gÆðfŠ·´í6Òî=?úŠu”£‹O"ÇòDá>ÆúKµ‡{ZžB ï4Â�aÆO�Õ�‰´¬˜¬À·Lñã×êÂõÆ(¯¼j‹!k_DÎü§¢šà–Ak1ŒMWöv1òq@3Y§à_äŠ]¤# ÿ‡ÿß¼ HM"LN!.· ËÁÃUJ:Ïe"-NÛˆ�ä!��±Ý�Ž–÷nFF¥¿Î%3“½ &-¡³Ç˜Ó'ZO|×fœó�ƒVi£yfáÛ†d¾¢Ùß»¬ñ‹}vS˜h¨]P×™Q~¸?í|Gåß¡Nqv¾ØRœœ¼‚GŠJpû~EN,ù”îÞ÷Ý~ÿºoË÷ѪR�Ä™�ßïv…«¾ýœÈõ*­/9�¾…ph‡UûérÈÖó�azVáüª+¿\ç~Æœpsº÷W�¤X¬Ûè�K ¦Òh:(z"(œ€®bÆÈî™ ­ƒ º&s·ßŽPóÉ Éþä£`Á�EšGåœ'cdäo ÈÀx`Ñ÷I ƒã½#ïë�UçxìÕ0^¡3¤VÒ°;F¸�·i*WÐÊ�: ŒÝ\2VHº¤ì{, èi´Û“q%x�¹@…¯Ž¯ßÅÞ-uÛ_Ìt`½žVÜI–ÆCN[x–ÇÝë�Šã,b½ü�«ñiªÝ_2°}í°dî…bB«ÖHY0÷£„gÃ-ù,Þ�Á ׉ëë"µ�!œ°1tìåpk0QH‘ýÉÇwhN>óÅòmg£±Ïüdnãû¯®iÅ`[�““6¾¸ùE^^øþÒc‚ѹ§C¾O»ÉvªæFgOöÎÏ1�ÕÀcSÆ©ð³„ühpfexš1F3H'¢y¨"»wx½ÆH…ÍXoÊCÍ„n¢ðE]§aïV‘¦Êwç„/†ÁA�R³ ÚàŸà°C"nNÂC8‰}ŽÄ7Ð(3Ñüò¦O­®Eæé#I¹Ÿ6¶þSºþ°x¨WO‚ðÞšRãu-ªN° _Ä $b(bSo#!½Ue¥@¼W™æ[�ßìžPÅó¿ XÃ#¢EÿT)h‹¢1âTM#’MÇœ@ÛÅ9zÝM`ù£%[sð`VÖòËÐhl–³Aüñ‡ï©$µ“m�ÞËp—X0QrM óÀ8 ö“~�Œ×–çЃǔ5'.ýý3`½('¾Ð)�dît€#2¦M’�¥6Í…Žº›Ò¡\fÕc˜„ý†´ÂYù47 'WöW¸8yçD�ìZmê8—I‡÷ƒ(ü¢k$~s‹jÌ4Ü}zKÿá^Љ”¡ÊzEqOn�¦ß¡ON‚“ñ%%ÃCâg$DyâRiPÇ÷Õ n|�“˜þî–XHðPW$7 P–Å4ó—QÝç¡kÓeí5ú$æò?à ‰F<tIÅ•�EÊòÖùï zÏÍßÊpœ ÇqofX«G,�ŸC(#˜LGÓWàºMŸõäÓÈ„n9sˆ³?@‘S®›½Ý¼Õ7Ù›ïG²Àº:\]3§p‘¿Û‚ß¶Å\ÊŸ]$³UÒV@Ԧ΂ÞÛ�þ=Í©„#S 3híéн}¿^ò¯‘;•æáaê»Ü‘{î³ÈSÅãÐãï7å¬lÇíÀ¡ÄAžbCéS>*H@`¶¸¿{"ä½…l\Qoï,¢³Ë”<wß'±üu=Sâþú¾·ØNé̱R19Šð`Tgß ŒÖÑ$ß‘,˜¦½©BnÝLuÔ…ßM®‚ôÍ- ‹EÊ Ò±áÙ�1N�3ÐÉJŠÿ ýµqy=îþ!0)ÇÂqa¤ŠžÚ´Hïî7|#nØšà÷š˜~ø˜¹v€PXÁ78E$È8jýM}ü8y};G¾÷v¯[íœÞ³|ÖsDÈǃöó Ë•î}Ë/{Ü¿øŒÊ…&]¹ÉŠ¢©Ýä@åw­Œa“£ž`/xÛ."-,­�µ”¶q“£]Dnø s#Rr©0UA¸µPÁ®,æ rª>®y]»ˆØ­¤éDÔ‹?�,†Z`N·ˆ�›*v¦LØ=qŒêL:£P z }ÁzÃÿ(0߆¿³.¸ŽÿdÔ€Ãjý8XqÃÍS¯ÅÌ·uBš /4Ù—¡¾$y”ˆvM„:óÂ;þ›†sö@ÔfÅ“›PL‡@¯CY¥êÓò ¦N*Û¨“—Ü9*棩\_GFT†šØ‚bq*ï�{IìÑ듽=<øgoå[{D'ëâ ™|¼[ãz£ e¼ªŸ3ã–õ›L貉—ìýƒyßh<~?˜Ð@©8Í}à+·¶Öv O¿s«ÔCçï¸P:xÁ’ð:ÐŒÖDlá=µ5V#'êDUµ�V¯=Ì É7>Ò+ö—�b÷ù¥/H:Ãt§BÅÌ YiN½3êÚãRøL¹¶Éð„•î1¸£ˆ¹J½°pÍ)]�žû[sw|.ˆZ~J[ËeÚ"Í­�l:‚*Aåè!�ä´.¬¯˜ÃU—™}©úÊQjä™;líŽq¢‰„ 8f"®ÇÕ.EÄV´\QŠ;…|îÎ'”éóÇ{óÑá—ŽM ð¶£¾°Á‹wßwË�N1%nß] HòërzSvÜ�ÊÊ¢{m”ëä�ƒíó޽Ϫ²A�Ooû§ê•Ê™ xö°ôÐîýùûZWD�Çx§*_¡šó,·55v½-aøeáÃÞgÞq‹³ž’m¾lç ƒn­áiöF¨ð³‚ƒñ�ü"b{$_8�í-Ô?þ´qòɇ °©¡VŠ+�]‘nqŒÈªGŸž±¬JtÉž'h"'ôcý^¢Ðgƒ]—¶¸T¾›+}P'$‰p¢%‡ô�n„C¨-Z˜¨ËàCT΃9 &H� ƒdÈuІÞë‡Qþõí/Ó2 ¸hdÜIÚà†¾qÛTšûm^ ÅÇ#4xªk±¿ÂÚDˆ=æÁU >J~¸~c ~@òrEšé3J léq¤nXKýC>¡Ó¾xË_ˆ¯Kq�¸ñüæ«pIÅÕ‚xµò§{”‹ðÙdã£'û Ù�S:zŠ—œ)7 a3oëH¥Âó»2¡e�Ï|ƒÂÔY|8æ²O1¢‹“5Ìí)‰Ž•�¹އŸ‹QzÃãì×vQ‚)þa�Mä{øÌ=áæfF{bòÁþÌŒR¤»GmÎz‘jÿä„u€ÚÄ(žM"÷1¢ž€NCãöV“²Ùºw¨zÒd�ÚÄ¿wGãø>w†h“�»—b3Âíhœ€swbh‘q=«¶ÓÙ@§9  ?HzÌõ,A¡i8óÜ-æ„<Ÿ™]ìRŒ½ JÄž•¯Ÿ 3HzFLJiíäI‡ò¦•@\=ùáT;¨i�®#áfϰÚYóÅ�ŽÌ°íì–¹8$)¾ÃD 6>åñê„´ª`ošzjÞ6nê&f'qÞÈ�ǪÐöuFc¯ÿà_-�調մKLåoeæPÖ�E§k(ðŠ…%ÚDz`ñ±"ìõó4«$¿Yæ Má„}³I[¥¸•MJb_5¬.Fí3¦aNÉ”´ð¢M´1"ñhÔ&“ìÝaùó¾G2 ·ê-7"³¢ðë'÷³Y÷@æ ³x­®æ!m5jÈn±ºzíüº‰Ã çà|÷‰^ÞQU‡û­§È ©æÑX¡^Õ±Ý@�‚ y=¸_zßK5…W߇ZF“ ì¤'˜ÂV–¬ÇÕi�ÿn„cӪ㟖}veEÿXЂ\5ÿˆÈƒ+’@ŸàªÉ¡&~¾ ã™:÷çeG „ÚˆsäW»ÉúDŒðøô'˜ÿΨsÚ²þ«j ´s�ôð�$£IÅÉ�Fëgeq°�‚”ë’H—k §‘Xç¯�—:ÙÉê�û¢Á%”‹ü–ëö˜ž‚Þ†Vã=AÁ^yåMCX¬]©%¶¦eäVêí }rqÑÏ•BFú¥ØC[|˜¸½cL`7‚Þ. ¬ÐÓl‹•W¸“>ÒVb~wÅÉ@ˆEsv“NËOÅ·Éñð),Å�h²Lޜ޴�óç ¤ÎÛ ÄÖÒi�Ëî!ÒªþêV^ä5¿²ø‚�bœžfÖ+Iõ•8åDŠÔБºù¢–_×åã†È´Å¿qS ´\1ŸeªÑ€Ýáò­¶ª´ çû¯d�Gsvìr¨Žd[Èà6”ædÝ�ŽˆZ�[~¥û�“ :;@Åèãý]�Cµ?|:¥U®Æ‚]ÛgPĈz†ÄÒDá]"�u_hèÜ.gÍÎLÌó¢hF§¤äÉÌ—JÝýÍ{Ôg:"¿¤©Ï”B?§Þ:tZ@;\ñAmT=S“£¾Jô�—χև/�ä[4Q*ü›‡çGåKÜ)Ù¦¯å eü‹W(§‘±ªXq«ßœ0O>rƒtÈBxbgaî'êóË.Ë>e9K¿$L`$jåuãbßÄ/½1êä¾g‘xá8lÇ زu©h>%£??KQ\Í„å­x-¯ ™EÚC–d «�SZçGœF¬^+M•I…ŽÍ.C¦˜Ñ™ºî¸@×,Ž_‰ÛBŒ\·ƒ<·4'Ð+¥zŠ)g.gz¿‚gú£—XWßôÞ?º3(‘@«k6ŽT’‹=÷¬ÛúšÞ*•0‚3¹”_ÖmePûUw˜ÌzÓ?št5ºKW3o4š ŸNçfúèWU´ÌI²�)òÓødyÕŸŸ£ÐOŽO BLáæ�ÃÅÿæÿÅú+Aq@<TAphÑ= uÁ»Gj"ú{"B,£brsÊ('”jî‹cØ€%t;{š÷•md[”ËY™�(VþÉóˆ •Ž`½ÑÙš_UåP1Žõ&2AÌðFL�ˆ¾C�–‚a·*1öë¹­kî†0ÙRCFÊà'5ùëWlsè7Íõ)p®­­&î›ÝâÓw/æ7ii™ælžÎZ6矧kXPŠûÈ’f×ÒÍ>ô �ÙoØQWItÃ|H²¦V@ÕƒFZm¤#| Ƚdô¨:èƒÕfÉ/ Š¾]˪�v‘7õÒg#Œ;7‹#}uøYš&�u-mKDdGΑÍ2Óý@¥âÖlÈ­²¨šW\ÓUá§€6„f~ñ§sn � “'þ Ú+L‚Î~ŽHz¢–™ZdfÝ9 Ó5†;R1ÈA*k–h¿Ðk± ήäîó#ÓQÂL…ÂÆ˜€ê·'pÒœ³ñûÇáÌòº2Ÿ©ÆÈ ¨ï°B�»;ÛÁÙ¾qÂù�ác�h¬’Jö›åäIF†§añèë» ¤åë17xì5ÛŒe˜´5â×THÑLj•Ù¾ _Y;óÎkÙOúÙÉc3¥ÐŸz�ßõ›“ ï..0¡ØYkµÏ«:æiND›3}׎‹ŽB«í‹Ã-™ô[*ãk;ûZ'5‚X …Ò»þ“IY—ˆøŽúÖ…¶Lé¢a`‹NïL:B<¯'eìžìßÝk`Êô¥4uXÙ>e5~É,e~Šê¾eô€Øà`W4LÍ2®ŠLgd¸{®.5 X–'4ê½Ø�X�Ó;A^€“ë*ÉUµ©ÙHZ8}u-/¾Ê##ƒ·¸VcW—câuÞ|FãH·'Ñ™]¥¾ƒ >´O|I„®Å35èµÙ9¤NZ{f¢¤Ü!þŽÔp�© a¿Í´Ÿ˜Ü•оnh¾õ­lN¬bçµpo]¢Ü�ÍD�hbª$Ì…´Œ Œ;([§©�«9A¯2ahJíÁ³[ u6YÆ�§:ŠŒ²ÛI zñ§eܸª[ ÊIÔ»Ë8ÒÖWA_GÝž‡¢Þz"£‚ Y!ð£‹ê×E££æßï4§ ��Eu†Ÿø^gä)QYÎÈÀ8¤C?¤il²yQ»ÍESwEŞPã@ÁXîŸ|W£û�ý#­ߊúÇÁM~¦Sð¤q›­É`èz�«†ìàCPA\ÎÇm±<:K�±§¢a¿-}7JèÎ}ÉÕÕ é²};èóôãb`Ïf×FsŽáJøC—N‰›ÌèòºSóm u‹ G铇µô'– �Y)ˆ3KÒ}Mß ½Fê§:Ø¢¶Ê&iÞbS»zÉk¹_³Ik%$4¾�ïõ2'€*à)nzú�mÏY)•’¶E´lxøsÞ úSßáQeâc“ywÐd‹On{%42Ý>pSÛæ^ö*¿"Æð™ÐÂÿ—B²ÆÛ—Ì�º§y×w²ÙÇ£iÞ-ÛL^dh¦߬0.ûùƒÎØ+ÓÿÆŽ™©W’†ÐÁ3‚«ié�î]¸³SÞ+í.—+šQ‹¤ø…<úÊ›?±Œ­M®T;טD­M.YÁFÔ‹Èé�h6Ât¬Àmhµ)ªPئ髗ä*� æÅ?^ò¦y‹a]é@“ØóƒlÄr¸ÀVnx¯¨ ÂJ)Õ•Gw5ç`cy.w`6|"=�÷ã.^� màÓˆëYÏ[ g¢=¾rKVe6Ë)š-!^s¸6þ.œtøR)�áRZ“j“Á¬!æÊÞ–m€h�Á¥Î#çH[¦P\ígÈÞkÍŒ¤gT@F›ý8<ÈÃôÀù�AªiTµðQ«3PKÙxK"àêl…Jw)KLÊI§um÷lÔh°{:[õÖßêò¥¡z±Ê®˜«œA~ïÚ@=’û4Ê��/Ù#ù\‰iÉå3¡ lŒ�øŠMõ·Ù/pI$%«¾nÚšf[žå]í³»4�E4�NØF€ø Gñ‹ÿÛ²‰Ú+óš4G|‹›deÒ7¸µ Fª¾³eTw´\ø6j†ž+ÅU™ÊÔ‡ø¡(*) DÇY Rxú¬<ªÅš|ì[Zç.ÇsŸdî`�LTÕRÐD‘ˆštú[�=Q[äJAGù9»7»no¾ËÆÏ«5Z�¡JÅÙ‚ctì3Ö1r-Ôz(²¨íe™Sfrp\å².v½1L­Æ^]eìØ–ôÓ ‰6l³o<pyƒ’fjÆåx-Œ¨¥ ²aÖévHL™5jYArÊÞWùq-Ãí£M½'á¬!ërì„¥:Žéo§Ù¾1ü5gnŠÝ³™7žáú[�]tüú%¡+ÖMµð;j=ÑAË;šƒN.)êNö¿ÉÕqPØo5@¾+B‚°u§U­—b“ó¹™ F 8fOÜ #PœùÏ~ ìëA)ŽW6"¢Ä�ê-è’Dšsâx|õEe5HºvDM¾[‰¸…züa3§³<ôþ®QsM'€ª®Ñ/:Õ�x%H?›¡sƒø U.r&-Ä5>ŒaÇ–<‰’@¤w qø* €ê>£M s@—üâ›fV‰jî¯^{ ¾ë»žoù%��rªgbZ8ŸU�=.UtAÙ2S¾]¸‡÷j,2rëHØòd°"nGýý@Zª3sÄ€›)IzøÖÄŽöeÅY~}|T ¯-ß]= "¼›Š•Ô«¤5z¦?ûüý–Í[�Ú%“ÿ™-B}ƒ1Äk>¹¿$‘°º�� "·–ØTºÊÌ‚4ízuH*sƒ=“³"€u¹—¤E–‚¬ó¹³q M0™Ú�dü§ÛÛĸ‡)êCÇ\¢/ •eÇ:ÒÅ& ­eð€G~�¾èÿZ\B™^m›±¡@v©�Hé·CØÔé`äËÈñ-þ$»?ï"qŸvÞµÇbø=à÷@“èe’kƒZT&!³÷ ˜ô£ð0°ªãê}ƒŠqƒöc¡ŽðÜû{ÐožÈf0¹�ì<\Ä�oÏÅi>»‚•7íEUìÇŠ½?¨ødc.±Ä‚ª¾úùez[µh´¿zÍÍì„3¯dúÇ1ç9µ¾ö×üy�l}¯ÞJ™aÜA2Â'£õŒÄ‘ Oƒøɤ—ÕìI\yªX…cyUN„2´Ý:%W|Qn—eãùf"o)ªØ–ãh9Ñž@™9úËþ e%gw/^jâ´Èñ£Æ§4¡M*vz‹ì\Àqå7‰g™‡¾šùŸGÛáÁê–NRåbâמ®Vk$„¥<»8Þ†—ϰ?³ O§ŸÃ1ieuÔWPC?‡´)Š{-ýIˆ½Ö�Ô �â=Q&Xžì2{s›K�yä´2˜ScaÀ¶j‰«PÈ£ ?pà–i,tàÍ(Ž~�Ц‡õÍe~y ¸;Ø./æ~¨ÙJ˜�â­Ó}}ÇJš˜ð+ÚRMŽº­øl¥u¢«© )~IÔ’j\çÑ5²†EX.Ü+‘½ä' Æ]; Äö1‚OK1ç^˜Tþj&Ó®Høió¢¶îðÈ=ãHm‚ˆÈlQ_ ÖêH˜<�HSc(UFÎ[îYy'„WÙYÁ-­&Ÿc’çæ\½­bäÅ͇óg¹Ø` l- a´fcðÅ<’2@Ù‹T·ÇÂYΪ۫;MN6î®Y<d¦hUvçÞ,*7j8!J«»¼�•F¡ÃŸtÏùÂc'«› ¿÷ðg¸õuJ«¶§!ŸÅ©2qøy¥, ·•$<OÝ�id<�„Î/q‘<>ñ5F_…!mšþ`¾o@Ç›ƒŒˆXLœº»\s¿WÙ;}L°*¦Æ¼øcO±�‚÷Ç�ĤϧáªTY‘fä�žmÚ¼p§³´ù¶¦'¿Oeã Ÿv¡ê"ïPL9g¨®¡xiœ™Ïï G¬rlzK_µÐ©ýÃM–Ó°ËDƒ} õŸ2p¨ì¸³ZÚá �Ñ Aá ÿO�ú�ÿE]ÙȬդ°åÈ‹�£*Èç&Í.ëîš4{ï�k¦óv¼d�La$âÜkbƒÓÌ/c½4ÝbØáä_€�¢ÖÒóµÂs æì;>"�õéÞr7�–¨ýH÷Ïcb•np�ìÍÇŽ˜ ×aÈ­ûQù=òήg*Ž!ªV¤9¹&ðÄ*˜�ÕÙ³ï8Ⱥ�ôt‰«3žýéðòî`Ô&ÄwÂS{ÇálõAb~T�ÑΫ\�øHú)>Õ÷çq4ãÆùŽEóÝòg�8øeÏ� C’³Ñ� I²VæÀ½™´m9DÄ5|¹‡‹)ÍaÛ×@¶R?í·°>f$O‰§È endstream endobj 42 0 obj <</Type/FontDescriptor/FontName/DXHQIH+NimbusRomNo9L-Medi/Flags 4/FontBBox[-168 -341 1000 960]/Ascent 690/CapHeight 690/Descent -209/ItalicAngle 0/StemV 140/XHeight 461/CharSet(/A/B/C/D/E/F/G/H/I/K/L/M/N/O/P/Q/R/S/T/U/W/X/Y/a/b/c/colon/d/e/f/fi/five/four/g/h/hyphen/i/k/l/m/n/numbersign/o/one/p/parenleft/parenright/percent/period/q/r/s/seven/six/slash/t/three/two/u/v/w/x/y/z)/FontFile 205 0 R>> endobj 206 0 obj <</Length1 1642/Length2 7677/Length3 0/Length 8516/Filter/FlateDecode>>stream xÚ­veX›k³nq‡-REŠ{‹»§¸%@  Áݽ-nZÜݽ¸SÜ‹)VÜ9´ë|ßÚ×:gÿÙûû‘\ï3÷Ì=3Ï=ï$ôÔªlâ@¨Hjgãd稀mÍœ`êP[¨ ›2–‡›B��/&=½¤#ȆÚI™ÂAB� 2pq81é’P{7G°¥À¤¥®ÃÌÂÂú·å· ÀÌí_Èc$ li`x|pA ö¶ ;ø#Åÿ8PÀ­@� 0�|«ª+¯" `’UÑÈ‚ì@Ž�M¨:™AÀæ�%°9ÈbX@�¿�s¨ü»5û#—8 ` €ÙƒÌÁ�a Ws�ýoˆ`r´Ã`�Ï�0 `éhj¼8�¶3‡8ðh·€þ)ÈÞúèaûˆ=’©Bap˜¹#Øx̪*%óW�p+SøïÜ0ð# €Z<z¡æN¿[úƒ=Ò<¢pS° �¹Âç2€`˜=ÄÔí1÷#™½#øON0°�åß°A–¦Ž@{¤yäþ};÷ ø/Ý›ÚÛCÜþDCÿxý»0‚X°crr=æ4‡?æ¶Ûa¾ú=/òvP�'Ç_v “ý¿0g�㟠bú=3Ì�E˜¡v7�d�ùJ L `úŸ©ÌþŸù? ñDàÿˆ¼ÿ;qÿ©Ñy‰ÿ·ïó?©eœ SÛÇøkÏ��©àq×�”�¿—�“-à÷¾›ÿ?‘¦¶`ˆÛûOoÐ_EK@!Àbñ‹ÛY>ªÃÆÉËÎý— “»‚€ª`¸¹ÀÂòxqìZv@�#lzøÏÝ>qpüÓ´›ÛØýV‚÷/düg�šý)ÿ•œšŒŒœ8˳iÿ8«>N\ÓÍø¿™t”¡À~SIH@]l\�¥°qsñ�ù�‚|<^ÿŸ¬x8ÿ>+›ÂÁ®�}vNÀã÷¿>Ÿ ÿA#mgþ! ¸©ðqêþmø ›;9:>Šýg<6þ¯óŸù�\Aæ˜sÓPsá@ë¤Ôdx9IFÏ�”~G;'RO�}^•fv¦o)´Í')tE°Èä¶,ˆ½zDè¾Ámj×þnCáåf_;1„±-tð…‹–ùkæ³%†&~–MÿWFy8É?u"='•–‘õø8´7W‡ÔÔ�roQ_Œ4q;¢^0ûÒ:gúÒ�Ûãz›'V~ j~Zý¿<k÷'CìöÅ9cWoOwÛ/”¯ä,é0è…MI¼ãw©ãàn&ާUæ÷(×ÎüŽg⾘ƒ» «×P\�X‡ª¨lú» LïØê’Ù¯¡†sR ׯÒ2†×Eæ^pc.Ö±ñ‚Ã,û¬©:&Œªa(FçXFÉ€¨N�<övÒ‚�‚KŸSw{¥&i2šõï·žŠ­� þ|úm·¯“B×ZŸ$»7¿Š�ãØÐ‘¹êÔ^NÔh�C:ýذŽ(èªFªE*Bî…A­2{nÍQW�áȵCøÛ@¤©§XnÍE­ÚáíÝ ßÍHu¹ÔùYèÄ/Öê9Xµåá}L\3–•îv�,˜1nT?©k…Û’è°UúC¨dN�“ƒzrÅ?™ë¾ËÉ}þ«7Ñv¥ä¬QUTÓM/qî³e"ž¾n‚²¹äQ¦£†Te¿¶ƒ£Ëľ<j¡>”ðBÒK|�5¶ºøL”Aí× I2Õ…Úcu*¸¿ZÞØ5Uœz„õÃO A‰aÜW½÷#kkɸÎX9AADbßë½X?(Øê½wV'6h/Í�Õ²Jx1Í�·Å‚1ÑT² šzö™S:QÅ›pÇ}6ý–WÑ jð2,2wQÏÞÞ¡Ø^#T§à‹H_ ïÝ";�vü¸’�æVÒÛùôéò�¸K^9¿Å´»¨WdÐ{x]C…äСdkp»Tx=Jî»Pà‘²Q‰ýÞ¹pÒ/'=ªbaW„ m[[ 2ÒU¶á1p àÌn4Û„ÊßMΕZÕpW¥ÐP'3” ¥¯|»¤¬M7ý�Ï|?9F·m£¦c„ò!é9æûI{aq錊ù”“Ì:˜2$&Œ”í-EwÜiWZÜ´¬,W)¦> q`ñë÷lbê!¬ËsÍøfe§Ð1.ŸÝh·Û›Š.­þ0¦ôo®»þû1±@¯µQµcó—ºê£ªaZ ÈÅÉ /ÍQ¯&?+&7ëËh·ŽSŸ®b��ùò JY~FОzq³'ƒç]©Ò‡ä¾)�…ßo�¥�ó2ª^zrvMÈ–Ïìµó†`€^¹´\ôP®GvTƒËšiÀTì+îÁofÑT{RáAIÛa#áÖéJwUM }¦ˆ’ú]zŶ±( ¡Ú}"hî°œñ­s„~h��À•0ó\{Ø—Îèaþœ®†!¨‹Eq2ò๪ò;m¤VÊl£—5qb�éæ–[žƒ% §<¯‹V²ãOº‹+s×Óç3ÎZÈó�öÁe¢{±B -g2Ӌއ Ëì~ÕðkE¢úh‹vY\CÈ¢�åvBÓV‘?ÆEÒs�m}<¡:�Áéæ­Ä[‘�x�’|Ú@‡ÝÎ6`xö ÿ‡®ÈBa\9‡„@X=ãäëª4 šÁ ‘Wv“Tdë¡O8[¡M/Kª¿—™ŠOšŒÝ+빤•ªáyâ_m á07°îå\ƈ$ÙÚ÷|co¤šlcïYô0von¤ ~q�¼æÅM…¢+ëƒýkFÄÝzÜõ%ñà ÌwÐTÝ1yl±„¨H‡—Ã<o*ŵ Ëã,î¦ã<öëõƒ8ÔÝŠKáïu¡%Š «¥ÛwLË([ÌáË.a’œûôm`­Õן«gÉA†SƒÍ ³¡j‰<W#|…–/—äâX?ÎÝ"ÍêÏÔ/­9|ã�X¸�‰ñU&Í|LjX¾–8�qUU"P†Cðá¡ ¢©»@˜Âæó–.„:ñmg—bö"æ—e­ëø´–ª¬©´çn�£h‡q߯¿%ÔñŒðSw:tÔ–}Þ¼9Z8ïa LEªi ¦Ð7¢ÚÔ^Àÿ)¾ý ½–yû©ÉÈÇ’“û³5ã%!-¢bê. >:¥]œ/»ª\¥,!1nСb¹9õ(›\ƒ£]œtúêhÉ¡5ì�Q%0TŒ)ZK}]+’cþˆhK*þRS:Û³:1×xÿ{@JëÖ�ÃåÅwö‰u-yþ÷Ú”€Ìá—oZÄŽœ®BXv÷HŸN\cÈ@Žg*1Ûšd€ƒ9ßÕTX\‡/ ƒ®'ßWU@ÆÔt›ßð2-v�JqÐ$Üaº² ij`¦/�é! Mùï ØŠ{¾¶£Â¶{ˆ•þ¥íY»»€´˜�ø<¦¯‡`¼UC1y#Éݲg·XeM(VÂaµª=ð-±/c¢›Î„‡�)é‚lD/‚¯f“îÓw«×û*šøÛÎ˶Ú^…®¼n¹%4 ¡`#¥ML/&å½L�sÙ¥™Ûœ¤‡ròÔ�d+.LÏÝøò“ ð{Ѩ�bõ ä#_í»,A'jM_‘L#â0.r,{»�GwµŽr~ÀNä&"�oÇÄåÓ @¾  Ê¼ûº+³,…d‹‹/RØwa”ë@ßûR…K†tìð”�ö£§ �œ:ƒƒÖŽ®ãºÜ.ÇWÜ®{-ýuBW¥×h¢ŠÍ,ø<z‚�:©Ÿ¯wÝáïJB–pB…ΑµœTsùµõÌ?ɽ”­ ŸbÐöàãíXf wñuyâã[f‹š"ÄXj}˜”Ú%dƒŒ-nE±,¢�Ì¿Àh�°¤˜{ÚÚuÿ’UÒ¹k`‹Ã.ªôe:þàÂ6µØâ“;c( })ñ¤â‡m¥7øl f? ¸dp†Œ=µõ q´w ¹ :ÍO¿`³…ø2AÌÓê�ÍMò‡ ®­¼ó¸ñ×£ØâBü"…NŽYqX Ü‹h�žûB¨Î\?Æè‘']�CQF�'òv‹»Ñ϶ȱV³òPT¾}|[ðl˜åKT%Ëãúya˜ö›ÔÍÅ_×ýRßš_ö4¡W–k_¡+Ea¤8ͦQù ˜K–#Å£©b÷‰ÖîD«': î³â¦j%3ßá…»[ñ·Þ>§ñ£à{/Ä9Ò+´¸Ù¾8tÈ:9ºøÐq¸p×’×2ìŸùZÜY³S°·Y•´¦>|H##«$àüi‘ý�Ö�Á&Èšo…¯–±Ñçº5¿ãšåd˸`ÎKQQâq—Ä’Ä“ðÐZ1X&¹ÑɘK%�'?¤ýu½ŒÒ¢8V‹-à0ÿL@¾ÔÕÙM-3ó…äÏ1ͪu'˜!‰!S­Ñ⃫¸¸_ºV¯�%f¨ œŠFkÙ†ZÅJ׎Ö?s:tEÖCdÔÆô aØ›nâOh£Øéq“NùVÉN×î,¿ž]ÌØÌí‘+ÚË7ÁF*j©’GÀ¦”£xaùú�‘OD=1o¢ð¼+RÌ‹oryóÞôø0teYÅuácÛMÒ�8PC}†iæ·s‡?Bœñ2i³VÅ,Y�ÒNv*’á¹ý<û*ád{OÖ»á@¢Š±S_î®e`éSÍéü’Õ{ìEN• ¦Q~59а½´õ¥OûsJàÏŠ‘)5¾c׉!2ŽèÙ†L{ÕÍŽ:’e)ý±l­•³¨¼ö<Ó�ÆQ¤Gy1[þn½4ž1ã8㉒ö¯ö7†âZ<Ž5d€<§+ȯï!ñïã]e‘à¼ó&~Ïç9Á1(:!´Cï}T�1û9�}ó“VUUÖ@óÒlÀv2v¼!¹Ò*ÐçSÝEî"ÿ÷i¾ˆÂÅr¯"bK´~�;¼FüÙm:œ7Ák<pá}8,ð%9à苪ÝÕ$Õn@^ˆ~ñ$ �z7ÈÜKÃÛ ‹»_Wÿ*›:¥Ñ:ÂP&#.Ô6­±€Æp«Inl yz·O7Z.”4Þ“yÀ\l²ÙŠG™#¸“nZpdAc®¹W"ê$-ô²Þ™õ™·’Å&ü‘õÌoÃYJ¹eŠà”ÞI#ÑÃcù:qé Û)ÿÉÊýÖ¥óýB±ÍxÊ]È~æ ƒª Ùr¥ü‰cÏYö|êÊ(Q�`¯¸…1»çéÙÕta0A/q¥¬£ë´ýUŸ„ŒÅʆæ΄ÍWMMidØ Ä/3üg8wÛf46‹ú^¦.éË‘½AlÁø´î‚<ôÀâäXM 4[Æ`<û�Ä2ãò€·@Ø›± M¦¨1*ŽYuRˆëyöœûQÇÐh2'õBùùóxñ ’¡�s�Çÿ‘ÝÉî—U¥Y:ØzO*뤥SøfÏ%ÅE&«ñõX8ú…5@øEõÊt‚­¡º6ÄF†¹ÁvˆÖW~d³3úÎʯˆˆNn‹XbH2§> 5ÂÐð"Dd“§å#^™5;k ±dÜM).Eúʉq>ÜbnǾª9QCé{Z}7‘tš˜+¢)K ]•WbØvÕi^ŠË%šzÂmÂkª¦®•¡é|ÇD[tìµJÐlÅ¢±Š·}ü¥õq5¦µ‚¯-mîƒÞ x~D—L /øëñÅ꫇à§JpþVñÚˆw²c @lÇaI‡ ùxu¤þÏË™o¬üÅXD 8éO´P¨Õ OMø ð0Å~ºœëöã$¯>Á1'�ó”£lWóq…š[¹G)%áó¢^�‹´ÉȾËWŠ·§÷S–O³@n*ÀY�QJ =,4´Ö˜çá žFËüèÄH ÔŠ Á7t×@9šüâVXÆ“ÛË=¼Ûƒq¶€î�N]¥í¸]ùwù[¦g<GOä~‘ÚÎó*U‹BœE õü��ªa¢G²ªø`J›…påCÍïªwíjޝžFÐ?gÌîí·Bt8?GÞç¬$£JÓãöÈöw›G–3¬Í¡óõ~—Œ¤ÿÀ<-ë±8¢ÂÊ¿œ¨´¶rWôµG8íǵ�Ÿxl¨nºÄž¤,nVoË”$6Œ-ðŒn€Zñiv`€õh¼Ìôµ3ù¶°6KéÃÈMzŸO�ížå+ƒ0a“¦Ka�UyãÑ»°Òþ�»¯ö®Þ3û­bÎKB¬ÔÚ…!1#‰#ÆË³™•4T“ŸºbÅçBU¿›¶‘ЉË9 ¨¼LºóM™è/ "XûßÕæìTPžëôû\Ä«‹ØÔ0ò�š&|Î�v~–¾é¥qR–ÜX%.ˆÿ Uÿ4ve +ãN*°jäùð2ôŽNs† «¬µ!# xF�Œ^x•¬~îÎÀOöFV¬kä©Yÿw¾ý§”(¯ãß]V°÷*ŒËå…¾Ñ�Ç ÎuÇÙÇ—jY.掷3û^ÉŸI×I{òµ¥ ËtO &L·ï ¤ñéÏlñÛŸq,¶&8¾ìS�t:øÈŒÓàÅ4¥ ¸LÞ©{§z®UPÐ ßw5úF‘–¯Í~Whk¿²wáRŠ[w9ô?Œ—|q�鶉þ,%gwy«™}`¹‹1ÍþŠôä>y1a‘´ñQ “‚óe–gñÉdºS–j^H“—K¾P�ûŠiÓ­ÅsdŒd]�«=Èçá—w)Ä,ç§&8«]rËÑÊŒ%nÂß„/5rgbqÉõÏɺäxŸÃ iI½¶æúˆšé¿m¦È�Z”ÆØ‡Vh™å]™ÇLûô½œ'¸•Š=Ã>™óîÛºeÒc™ ïʵå˹r»½TYTRŽ¿"˜ ’ F¬b·+?Ú“ì瑎]—CA±L•ƒ} h�¯ î¯íOE﵂påL\)ºì rÓ¾&å¶NO^4ÈJŒæÿÚU2=S”ûn(6æg¸Ÿ‡ÉÑÇñ=ŠÃkü™¤ˆ¿3³hi³k*•í)ݳÚMá ŽY…Óp¥<�^šk2SÚì¨ò7ùõYU64r¬WÐq°µ\×)…cpß©Œ‘ô“úš¹U'ÝKUrò–nÁB×Î7ø/ &‹ü½Mí`:Zž´-@üú åŸ2]%8Ôm�_QÊC^«$4%˜õj'»þzéÎS€ß̺>^N‹v©&¨ÑÿƒD‡A&*CÅmúz°s�.7{9ÒŽ�³‡Fé6è:­�tgÉJÆX‡›Ps´p_„cdäíÌhîF î7‡çl ïŠënÐî\µžOǯÖßwN¼+ÈF�Ž�#fð¿Šó&ÃðæãóH3' ÀW±'(ﱞ0ÙZV¸›k>¤õw`CÖul»Z�ÕçWIºªûFtLWd5+0ûµ¶ÝßWÑ9š�üìò Ù˜ÅnÏÏ eËió®ÇŒ„7iÛ8Üß÷\åfÚ›=¦Ç ·Û°ßÄ(µ™;lK‹Éy¾;‰F@¯¬ÝxÒzW‚µÉŽTlÅSXîT/”B…#tD©4Ðnkp”,éò d.�ZÒEr¦ ‚Äû˜8ŸÈ½rX´HÕ¼‘ôc# Má²I˜Ñ^4JɸÓPŸü‚Nœ¸•S„0Éøæ¡�œ`íš‘yâåÄx~ºKÄ¥òï�¥\žs©É‚=EÊ̲74PW€V懫Kh‡e í4©ªèO½gý~qfÄ¡ŒÓ¬‘ȸ¥G|¬ üvqTðlõ}(œ¼.[V*Êåêž@»^?j¡áŠM è¥VGñ'�D})­å·û*ËÍiE:càV 5B�¸Ò\ÜwÝÎSÿ©Fœºœüfˆ´©EôÐiŠ ”$™@èÞKiÌþ,ùš±Ç½•±;¶uÉÄ¢o}Š¡¬DjÇ€ô–ÞE–ò´á�[÷œ–ñ>“._{¥Ž#%ñ¡m©Øáüì.iøÀØJ–«”[2Sõ¼KÑ!Û˸þõºVr©»%]wzÖzòL+œDmã�±5â‚^«lM W•[/¼ŸÁV6ûü£çõ Ÿ Ühé#ÕšAp.�axëùÙ<¢£(ëjo¾ü¼ñ|2 m=âõilúº|*”}; °v:oÅn’2JëO[oãj0ÈÆ#½Ç=(õˆë]®k¯‰ôˆÍáõr0¾æ¸oì%RŸ�½Æã9"K®³Ž¦ƒ¬>A02r ÁOdž9¯Ÿ‰Bx"-„þ+ìÇM|(oÄ`=*ù'uT£¹àˆâ°{Öañ¬ñ»Zˆd}j&=‚¨¡kå¸S|\dÝÐya%óÒÐ:ç%•”gIè  à�jUsZvR“—)VYv1Æ5çûá±÷{+¯Ù_ s]!Cꃣg…ÂÒ�Bg*õ£?ÖL¾Mù$,i„Èù–ÑõGPª¦ã}Ée-·¤B¢îªkÀ„¿õVÈ+å·�ac%Ö R7g~XÍçß5·öLný¡åhñ:`-T&G�^#åîµì"µé5w§)ð ”j¼ÖŸ¤ô‡å¨›ôPaC01¹ßV´¿åþ#'šó` �˜¨œ"]%w|KØ�ç½øX‡ßË"T7ÿNÏÔú2=óB' WË;7dŒ/þ“3¸xR<,�ÁOžƒí=U¯¿žŠ¾¡¤K=yS,u °»E�µî»e¾{9ì�µΞ¯ý=êŽuÂ¥=>e)<.Sv¹YòVkËNQò#hž ¼–É´äˆÔió6ýõyZ(gªç¿¬¶:\:~ÙXÄl‹�àIΣåݰú|rIRx4o¿aYèƒz¢—ÚïJk$Ø2�À)²ð¢Bܧgú>3¤iOÝ{�ÎyílËbÖ–ãSëÕ¾…^Þ.¿TfÁ; ¼óþZáïwÌy‰ªïlü#þ £S£ðø�zgü”;–Á†OíCc<2ÆL:Dì™ÝñãîÉqN¹š¶²�úi#e㪠£\’¬IK%!œ¥h€-.«le‘ßÌoªË!ÚzÄXÙèÄÌ�¹;•‰·$EOê , b±½s†i2ËôzÄl«ß¦%£xg<ëÂ3ëffÛ',"üˆiå"Û]M†\�órd+�`Éb—Òì‘å‚ÈsC#¹eÇ ”[ä²ü´é³´GPô©ïp¹12È ö.Þ_fÁD}fùƒÈúœü†JLY9߯¥Ökíyª°—|”¨ÂL2ú¥\‹Ÿ‹Å-› »”Ë`tûÈFÛsÍÒû_2Ýd±R"r Ðü{鑉#çÎ)1„wkòMþ–÷ƒïüÌG¬G¯tM¼<]×Ãt7Öt ~¨f…uÝžñŸ˜U†-"…¤7CÓÜMªôš&³èb¤Æ½›#FÆò-t©m}/;åu ¼ôýn䙚VØe}#íí1¹«[–À#3ŸÕÝ·³ôsŒ½VeµÉh+Ln ;ûATͱ2¥‡xÀññŬÑù•˜6ÃQJ~GÔp¾¥ CÙy‹ÕøUÜóÈ–ÕvÓQ¯wÖ“ªÇµ·ü�¿þrE:Š„Fg©}$½:ÂËÅÞk¯ÃzñuK.¹Ø}ÞèvØ�ìÖ�&š�X�– |fê)õãpúÕ>ˆlÈS }t o%Py¯—ª¾×ÊG¬<͸R")*F^ȯõ*}gn½¢ÃmE"Pm‡Ð<< EºŠ‡¥y^ëtý5&Rk¹Äµ]éZ!Wb5{ç®À@Fr†¥ÍæÉe‘Ò¼/F�|MÎJF¹¨Žú ’JJ$K<Íýh½ql‡j®oÅw®¦/ZÄëE¥Æ;aÍbºH†µ^«î�ËÝ)Ž^˵ AÆ‘ûxë’à"w#ÖH�Œ4�O?™ÈŠŒãj;cÿ¬4 �B4)e¦Èg2 Fö xºñ9©ê;g‚- “¯)”BF'æR¾ŽÛ[mŸ} IQØÀ£—1¥ê¬ùÈ*ùæ~‡k¥,%,:ƒÚJšvötxã€C±ËHŠ…]àÃ%RÃNçk>ƒ¾´° 0Ÿ`º‘ˆ ŠÆkÒ‚Š�SÉ÷Wå_z=‹v�ŸÐººµm=ky�Þ»º™¿úág)»Ð´FÜ)Šø`Ô¬ 'ö³p:䨶Xw�àúaŒõ£u-¦\ã�¹3‹S›‰á³WùJqÕ ÿ[‰ÓÊë4ly&m–0ñoá~Ù„à†¨pбªP¾ÏàíÒzžA a:††ÞÁü °|¼Ó}�côŒ$=}nflF¹,Ég‘+§7§!Qí8[ôÊýÓ—¢QBRÕ›ÏiÃø“2¯‹¨Ä�’=Ñ|¾½ð³° TiŠþF1+šµ™å½§¿ü&.‹ª·Qÿ‘÷BòíÖs]ÿ :²¾¾®7ùÈ+¢60WÕon¨Z34¼° 0‘á)éñ”»xÓØlå -1=hQb⧃àL‘ž«ðJ“¿� c´ëô×ËI¡��ì ¯tÆä0ËÑM6#»}˜¢xª@ï°ûÜuʧÈÅ/~9O‘ZÐèßý”zz¦¹ú ó¨´Ô‹d‚dârÂÐ�E¤•¡£ù*%áMÆÇÓ|™'�T¬Ù±èx ü|¸[¼Ò×/�ˆ7øƒk{,‚uñõp(ªÐ#Uš]¼T�_‚Ø=�ßü„4Å�8<rAÞkç“�[ñ¹xžì„2HÈHï%‚VQ¥éX1gºžõã¼î.@ÊNÙP/ÝÚ!YoC´z1ßÅ®ÎKü%å)Èoßµï È”qÆZ¦B `¥ôä�Í䘭3Z1æoʒ̨ê r‘ß+ùµ³i·ÓÝ2yíoêTâx>ÍÄ È×þ¢åÆ– KvÔ>H©"µcr%*r—Âg;…æ¿ÒÓÏä6¼ãLF:œ+žÇß�áÒó(5#ãºcÉ'‚v%t¢Jñ�)!Ö݉ ­†XN±(XŠKñ43’´ïPµ�°1¯ üš¸«Ë_×…+dädPµÚëØ^›I.îÅŸôfó&,Ãö¬Q¬�ƒ-¶>ûc\U¥4¡o<Kg!A5Îí¦V*š CßÖÌ“¤Üì:Ê�îpç®Ì…éë,Š/œšÅÇÁF‘OCû è�=QqÑø�5ÅÛêL:üy¸d.õP´üéÐEªC#–˜°Û믎ÁƒTXì9^Ì…tþ±Š ‘-9jèmƒòÞƒö)e×]”Ì1ðµV½v¸`)EôÌû Ÿ²©Ö†VR¼°ß^âSùÌ”Ïä@ñ·ÈŒìW¬è¬£/ŽÜľLÕ¸ÚÈP~‘ÕÜZß–Vô1QñRìî'‚ïHåð†ñ©®VÙkbçTæšÊÜާƪ(�8åÜ–¸ dlv�}‰•z¸ËÌ4û? ì*– endstream endobj 110 0 obj <</Type/FontDescriptor/FontName/HQFFHA+NimbusRomNo9L-MediItal/Flags 4/FontBBox[-200 -324 996 964]/Ascent 688/CapHeight 688/Descent -209/ItalicAngle -15/StemV 120/XHeight 462/CharSet(/O/a/b/e/eight/five/four/i/n/nine/o/one/r/s/seven/six/t/three/two/v/zero)/FontFile 206 0 R>> endobj 207 0 obj <</Length1 1630/Length2 19105/Length3 0/Length 19953/Filter/FlateDecode>>stream xÚ¬¶ct¥í¶&;[+¶mÛ¶³b۩ضmÛ¬$Ûf¥b§â|õîݧO�óuÿé>?ÖÏÔ5qÍ{ŽEN¬¤J/læ`”p°w¥gf`â(XÙ™¸¹¨8Ø)8pËÑ«�-Ü�õìpää¢Î@cW+{1cW @hšXX�ÌÜÜÜpä�QG/g+ KW�•ºŠ&5--Ýjþq˜xý‡åo¤‹•…=€âï‡;ÐÖÁÑhïúâÿ:P¸ZæV¶@€¨¢’¶´‚$€JRA ´:Û”ÜLl­LrV¦@{ 5ÀÜÁ`ûo`ê`ofõOk. ±„]�Æ�G ©Õß0 §)ÐñÀèlgåâò÷`å°p6¶wý;W€•½©­›Ù?üÕ›;ü« Gg‡¿vmÁ”\\]L�­]³*‰Iü»NWKc×r»Xý5Ìÿzš9˜ºýÓÒ¿laþZ]�­ì]�®@O×r™�fV.޶Æ^sÿst¶úWn.VöÿYÀhaìlf tqù óûŸéügŸ€ÿ¥{cGG[¯E;üËëÖ`åê´5g€cfù›ÓÔõon +{8ÆvEÚÞÜÀÌôo½™›ãØÜ�ÎÿÕ?;Cý·c3{[/€ÐŽQÁÁõoJ�ÕÿË ÿ}$ÿ7PüßBð ½ÿoäþWŽþ—Güÿúžÿ+´„›­­‚±Ýßø÷�ü=2Æö€¿w øçÐØ;ÿÿbŒí¬l½þOQÿÕ[øïrÿ`Ò®ÆÇ"loñ—&¦+­\$¬<�fJV®¦–�scÛ¿3û—^ÝÞ èlkeüËí¿Æ  gfbú/65K+SûH`ÿ· hoö_;øK׿êgT•SÐP¦ýߨ9*ý]W5/Ç¿µý�näÌþ§ðŒˆˆƒ'À‡ž™ƒ @ÏÂÅü÷ýý-ˆ›…Íï“ò_@Ìÿ)Ë»:[ytÿöÍÄü¯îÿÇï?%ýÿ#noê`öÏ꨺Û›ýݶÿ©øÇlêæìü—䀿]ÿ‡ü¯½=�¦pë+¦¼!ÖÙ™® Xù£SbºCÌ࣡ŽåÍj%Eßëú2"ö¸«�ÞëCZfx>;½–Ï?ŽdhŽÇ0m)ûÓ€W…ø~¤ÔƒE(ÛÝœ´ÇAŒ则çš1>×Kr»:LÇûSÊ*eïP3ݬÎ0ר¿“º}G'{rüæošÞ�уÜ‚ÚP|vN‘üûÏåðøÏÑ‘þ[ÈÁ#<Ú¼xXr^c,ÿÔ3âW/#ç‡fÓOÈWwN—šåœvÍ:”duo¼·7"²Ç¸=4æÌKVB‹/aÐC&¡“xY�«ð0ø8–’$:¢ ÑY5ƒÆžéó5Ž�‹&ž ›ì5î8+ø_-Ñ+’¤%ì;Ÿ(TBRÃKÙ:a‰fRL\È™ÊÚÑü³œl�¸‚äâߢ…¾�W¥ì •Æt»úÂð÷�ÔªeühÌ=W¢å·§�eþåõàÄÇ$$¤mFsóýªRÉ'xÀ‡ –¶Ý‚)R5m]³0º -˜Ñ׋Rï!{uHÎúŠŽ"µm×BÄ#�O~ï{ŸjÐÞ¯ÛÛ—!΄¸(h4{2Ô"[¶ãÕ<ª-Õw R! +§PàÏ–ªsþñmɤ~¤¥…N7ú·Þ^5^N—HZvÇA /A6àéš ó€Â]P½0m1Ì3ÊæÛbÜHªÌ8è£!£“í©L�l€·['[×¼é¹0JÜ,Þdm?@î}z Zô L#�,¥Úc« Ó1š‚ÜñÖ×Ý={9¡ ¿ƒô°—pù#Äm Õ'K{¾Tϱ9ÓqkÖ*g3-Á²ÄÄfÌ´Ž@3 MmZ W¹U¯Ò3ßÝSÍfçI.GyÒ(G®Ã+ëKÛ_+iFZ­5 ÕT*—+VËn‡lVaêÙè¢�üäîìˆÎüX¤Ä* ¢hã~ÐBCº¾,Ñ|®%AƒŒbµ5SÁ6 É;P‚3+PØð‡è¨¿|JR¤/¨};ºb³gu1´÷´ÂdÛ�öº‹ß´´¦…¸P.1FfúÚ_,·¨…ÄWÐÏ;• Õ»Çë8û~wP™¿¦³¤ÐI-úm1k Ã@F�‹³ŠÞþ/·Ã©3Ù–VÀìâšÅéõŽôPð¶ØkƒlÉÙôe`óÉâŸ�\ 3Ô¦÷¸À¾âJpl%Íl°™Oc½8_ãr—G.­:LÑÒ�÷rÉoe´ {HU�•ÞÎj ‰4ØÞ3Ô5Ö»%9~ìÓÕɵ,êÌœ¼E7[]B¯ñ¯’çÙ­Ó Ôx.¬Ì›[g~MrYà`ã‘Öøts8¸kѬs ì´ì¶ÉþëÆœ€YÚÃF³Ñ’bøü|¬f“7—:eùM uç߃/¬hoó ª`�>}]E'WŸ9ÁË(˜²ª-�=IHB˹´��¢b߉žà—î(�My|ÍçÚ’>}ñÉ£OÔ"î ú—ÇGz!C3ìôÅÝ‚Ng„Ú%}Â_'*(Îo%{7 F¡#vF�3çc§éJ¢$TÓø* "Å å”ðE-U¡–nYÁÎIJñ[ªyg"!ŠQ^„aCVÕŠ•ò•ײþ¾äóN­!VÁ±ííâ¶G:By‘»qÎõò&Õ¤Y5nÝæß„)†T&÷ûÞ™àq¾�}ü(m‡_Íža}‡Ó™��å@ ¤mËüv�#1zÿDÉ_êñÞÀÅHÂ#†�×O #ýêg¶ÓŒß8Êu²°õ8?˜KÀܯvZ ÐÐûÊvYÍìÜÝÚÍœM^Œ‚¶õÄ^¹“{ �‡°Î4Úy¹DbÜýÖÛ1˜FnðŒñ_Ìä¨î×Ð�LÙcw|F»>§9}¤LùA¡t$iV€4¸‹ܵ3Vç;<µ�#ïei¯Ù|¦åÃãЇ­“ÞœhJz:Ë|±kNpÓÍžÖ‰ùÍS©“$nB¥wìuxÅ£÷jwP@B­ðψœµDþ�|^М½U²Á'ò^Å5 Ey3¤xx0)Á¬^”ˆºÝ‡°Û"¶�çÚsuZä*MÿÅemP¸3)hØW"3Åãö 6/í,ÇØiÞbz3¤8nir`š¯¯kOŒÔýY–‘Ôoãttë1‹ˆâ1Π?éÓ”qûíB&Xàd6#ƯF;É d—�ýjI=fßmÊšÜç>—x˜ˆ[KÅ™v�›�–K 8’S'¯c’¼µ ,2FŠZQBœÈ¶ÕxÒ<ÝD–�dM½¨Ã°Æžü¹à†˜�á:½„_ïÇ1½F0 hS²b{õbpánO„Ð#kíA;‘ùZGø·îši^‰ƒ"Oo[òôth�,HCµØØÉ<'QʾCY =wÖ©¹ÐaÃKKßdpw²7þ©»]ê )…–Õb›’¹˜”�Ƶ'�þrTsƒÏ0;‘¸ g!Ô7`Œ)=˜óÁÑôz*X)gFqÀ¥( yCÌdÞ­ú|ä>¶¹gàV¡Àƒ¬ïv yýºòüànÚ‡ !âÞŠ}ñEò°Þx@'mñU'�ª�CËØ˜·xÐFœú�l­#&�bâŒåÅÅÓU÷݇¼us©Ó…8Ÿž�‡##rÛùHâ"uŸ4 ?ôJ1ðÎwS1«�,*VHb°UÄÌÿ[¢‘QBuY_!úƒ”;Õ$L§*(ì\”¿Ö’»5�ËRk¥G|Åþ›Q…mZ(NG3är—c­o+ˆ¸¶š(“y ®�ÇVºIW} ân� Y�È éˆëþ�Ö!‡Ò�bëR­#nǺ Ò:¶E/1u†Å‹ù)ß ñ8Ë+DQYb<V.Á ‡°ù‹$f[åÚ\Ï»9IAØæ)qÆñ(¹U.|åΞ@]V>HKS$ï;|ÆtB8¬ª³îw~˸܈ ’¢žÅ éz J]w¯Omæf§t…´±ß—ˆs€ÔJÇÆymÀÙ*Š?Þm4 ×÷{ Þ]d:̽á¤G–N*xMwúèãúi̪ìA‚u}=ÏòmdÔ—žœK>Î'¯™Àë`ØÈ•˜+ƒòàu,|ó&J´t»G3ÝË›hT´äÔ{5{®7@ ĸL Wž [Àéóû²£ éáŦ�©J[¯š0O¶MWuJ¹jmòW拨€ÀhW³íl ål›œ,F†‹×j¾­/–ñ®¾ß°=lÚ±VPF3u)¤Ýr¾ìu{Òð‘`Aê ÿC¶=ù3qgf«õž6&›…Ç�fÞ4VkE�䃥MQÕ"„^ úpú4:é§ ²OF¤ÝÚ'ä¬8QöÇ;.¦§¿i]Àz1b^ü+�Nâøìòœ 6M„v­®Ãb‘uŽbXŒÍeLX’ª;a×ô`ûFg²²ÀÁÕ‰“OD(Ê^�› °‘< ¡‰Ý<ÖMs¿ThôȬc t3•9Ó£�‘ ú›³Ï¬µ(²C¿ö­ïéë /ÌYgpõÞuKzÉé)â¿ç�+{[å]Yàð¼¼g¸8íšž4ÌX:*JÞ=E:¡H�½‹Ž‹n¨5ƒèEîÙ:^ž‘ä8úw¾5bûâaÔB™ƒãëÁšt5Ò“¹?¥%'2�´æŸÀ³|Gî£ÞSD#µíùŸÜ‹2¤8%+.¤ƒVfPâ‹ÖG­aò³e]1²¯­j¶C‘*Æb)âõ2¶ÿ+©/‹¬oIôtS�à¬�çTáâZ´ŽÀR\‹b’GjXcõ´Bº2ˆÎCI@7,ÿÔ2˜°”a`hX“òÍ�¼÷ÙÙfj_& “v½›ÍYµ+Z GøD»| k‰L¾XP|×<dq‹o#¢¥ €Á@½ðºaM¹å»Çú1³sA´[ZãGrÕ-Ê�Çw¨ 5ÛÂ͈åÍ ™S` síÓÅ"6Ž~hÁö¼ZÀæw¯²Ý3�/B”l>‚÷Î%’¨©¢.ÕæS"ðtcpIC¯ ‰ÃÂ]M�òÝg ØöPXM÷ID¸ÅüÓtøS=?üFà‡r‘ÞÀ�T�ë>yÅÖ´„ØïûuÖÅ´Ë •m)ñœiazÉð<1ë"<5>�“°2Ûlúf ʦi’v­¡ä�;OúæçTe31‘‹, ¡/làb_låȹÇ\½™4+ç‚Ë"åbŠR�M=m‰<goØ|J(™Ô¤€}^íÃÆþý ‚1„²Ö4"_즘}¬ÜvÅ kK¹Èƒ çG•Ê�Ö ÔG÷í³ÂvŠ=WðAú.!¿óqIp~Ç楺][‚ W¢í€@18îÆ» ›yÀ°ú�v0C”Pþ@s:{†[áš·b\C%ñ†vÇ Ë…–!ú�ÎúÉZ{Âóܾ`Ghô‘�W0Ô%”'½) šO Ș•B)àç0ö…´®hÆÐ<:\³ÁI'â±Y¢}èWþJq¶/Ø)y�À\S=¯œå§‹R~:EäŸX‰7#UæÈÅø,#LU)â ìí OEcS÷N°Ê­¤˜’Ä0ïK8‘·ŸóåÒ™|Ôc;�Áý1ø” $QøÂph»-r"�ôuî—¬RPl?ì.¹v†¥üö¿±Âsª¨’g³?רsÒ�7–z‘v �éþBhÉ…lhMâ"~Ÿò´ª0¼¬#œ6jÆÃ�‹@Ï€½€Ê)†—@ÛE²àUÇÔŽoí <ÜøÀãùSæpó‚F‹ß¶-ž#ˆÝF»x`]OÀƒ«—‹)·ÔDÙiÉÍ¢{�-˜Óª IHc6Òöò=ks»ÁÝ5!6D×Õ8}OrÒöBzI¬áƒ­ý>äÙÕW‘®�yÛ·1ÎÜ>4·Óª¾@@í²)GûaH’‘XÙ‹/oqJ¨³²ªó01‰ALâ‹;.­6��îr-Š6U’U³º({¨àñR奠ًþäYz¿ÎŒÌñ~¿˜•ÒÐÄ›A‚.‘of¸é®lâKÅžkŽ–ÅOK[ÙVÀ¤^îY�ÅQf4•Áä ÅœÙ$*­\9öÅ©×�5cëÙ–‰ÛZz½º­Íì„Æ_8)V¯Ýâ,¬4—�ÖÂ]a±´xÁO“0«âV©ÃgRPGVö-Ï xÖë6ýž…> !¸¨PÎóÊ�33 v#žn•ß�Ê™[áÖ�Há}}±›<*BF%MÉõšõûÕªôMìgƼò5?P|’»¬arL¹]âýD³8ó¦øsG?(,Fû[O6^bw�Çia—†Çf·å\æ,£ “Ű˜û2ï ìHä(›BHU@�8½ãù9“Xç´*Ây†BeêmÁ÷t†v�ùtI·ýû¾Ž«Ù¼ƒG‹ GwÎ%OŒœ?†Ð·š¨LeB�ë�™ú¨§™¶ö “³ª*�^°GsïÁ>Ј¹ü£ù÷�†Ev¹xjÑNs2ÒØ&Íâp^޾¬(õ=àÃïűsvâKͪ`ňÎ�ÆU^>î:Ù¾°,²'1÷æÅ´ë'¯ .¸ø¬²š$SñÈpAï%ÿ„ô‡ §®:ä7Õ A{¡kxüÌ,p÷<�(ÞÉŸƒ`Z²mlnû‘T¿¦ºK�?sZ ºò9±¦Ý�] V†cùÞ!æ•IÕ²áè3ÿÃöEY)aòI�“§E­ÜjRËQŽÌ,ÆŒ÷€ŒTok-ë‘;žŸ ^Œ\(òW˦¤¤ÑÕ™,˜�º0~›”½”€\‹�…Šg|e2Çú÷ò²_·õ½áw£H<6CdÕ«ÐöÕegxuH™†W¡/\T|Få…»»ªìLÊ�ÑsÌÔ»¿ZœO¸µæÑ-j/gVƒrwí=½¶.9¸q Pø:¼¬$ôÍ:mT�þ¸V†¦¡:×}´+ñ‡ŽÕkEí=µ ;'�}'ö…›ãߟ"é ĺ‚:4M©x5pžhÒýQ}æ¬qò\}òþèÍuûÔ†èɯ‘ £ï‘’ ‡Ði@SÁŽ®d²GÒ¨ýê,Y/¬•€âM—•i!•ØÈæŽx�ñ]¶¶c©NX9Âþ+V%¤A$5lÓù�ЗñQê›�ènÃZìºÂ‡2ä ~{] ËÖÜŽnº«°¸¡bº EE('æ /F?+ѬýlÀ®öÙó:þñÐ¦× ½*l•ŸÅ­‚aùË^¬º˜6>Ñ9¨p%Ÿ ²¡ùVäÌ!§iý\³„ d8ú�æ®ÕùÇ3—w~Âëô¾ŸÃzÐ÷!c Â’õ¸"ÖŽŠ~¤ôâ5?ùÀ•ƒÜHC¥AuÆÉkú·Ã[/y�I®h�)ˆêðЃ)"|¨ÊìŠvË�‹ÛNA�Hº_:¿ÿ;Éøv¿t> ©Ö•wL¦Äæ¯ÓŒ-w^�®²ˆ��!Q$ÆÎ»†º� ™{ÚR¹ÆDJEŸP+CÃ*¾ås Y$¼Wø¬S~mL©E^[Òƒ€,ì½µèÛe­._,¼y4Û9ñÓmÊ£;þþã¦,s+ ª /éiDyŒi(+Ì«íÑÉћҟΠKÓìä!uŽóGµô*ž%Î L™¾¾àó¶­gˆsò7=³?‹< .R1÷AÙ*¿’›Qøì(è†Dï´Û„«�å‰GÑaéývò�Ü€œéPZP�aûö„ί÷˜à�9äÔvÜù }EÆ×™“ŠýB&³›»¼nr˜� {[c�b »ÿa‡•.äÔBý5Åç°0Äi~'ÝXýpÞè"˜ËuëAL5±¤,'õy”Õ/DtvÇ·««èù†Æj©$Ô©ºp¡nû“q×êÌ=i´fèË1mßÏóà ¢U1‡Ê®b)ÚëÛ¦ìò,Œ™iÃr…±gªÍŸ$jT|EÞŸ뉇öØKH�L©#�˜š ³)B¼¤Mí®ZÃK2Š˜W¿}ý”Þä·øXDÖk°à¡%©"�UÇ#P�Ò¶ÙØYNdÕVÌV˜…/ ~}ͯÑÍ…°3¤ßä1@úMG_êDmÁH+èV´ú“¸… M¯*Øñ’ã-ÞÎ<õƒ£R¡ÆÃ÷®$ûĈ+ lÀ~�Z8äD4T§S½"F‘Ý-‡óŒ+>ïYÀ§-�ƒxwäã{ìÝÎ÷I` k3yd;Ž—-k›Yßu°'4ÝÖðâçÅJ ëY½COê?Âòún`}ßy†Bô«wuMl�²÷-¡ õ’X¸Ÿ;`��¹¥…hºøä™êˆ3PÙ>XG‰Â’Lô·Î'Æ' †§Åˆg®­‘h〿ZÔà*ú�¡ÙÒ®¹ò²UT§ŒréIoI«Œ¯îÝ1ŒvjPѶÍc‹z–޹âø)&a’‘0/CôÇvS¡óà‹YaVXª›uÓýè©{¹í½j�Ï܈«Ñ 1Ç~–‘µméâöu9Ê­°äÚ@ 6lÓør:}Üû7Qüê{ƒ£*3A¯ƒ  ´ß6·ô«ÝÊZÆ�Šö Õ&:fŠ.ð1ÁáöÞœ-µ¡7"SÕóíÊÅ$ÝEúHâ,�˜-®ã<á"ߎÏß_ƒEïRç ZTœ¼Ùá"?à´š$yX[¾« ë_]:¥W=ýH²ØÁ¼x¯?Y}rný²éœýý cQúÒ#;$€V›©*¸!<i?yE¦Ð´ AËš‹_ᡇR“Ø C>«ÏÞò€És²{®X³Ü©{˜rˆ×Z�Lˆ�ùrýÃ1ñwHNçšÀ}Ú–’a|ˆ Â=䤪‡õÝ@DU•ŽÁ;$yÌSR«×dçßâ=·|†Ž:ölò�V¡eZ.h�‰¢FKÙ1ÒŽ Où4\<ß·3{»,¨Y¢´Eyó¡ÏÛg±–„VN l u.öæ™ú¹™ çŽqºöæ4ðn¸(ÌÖøÞ%8�VØô‘‚¾(Õ²Dt^OC(; –¾c‰õmÈ-}<Îvóú*ÇÚÙ†×ú‹Ñ¯Ç¦°i^œJ‰ºoÁÝÃ�îrB¾!)E·=U> ì±2p A/Ü– ˜ë* Ñ¦¾áïÌfùã^žRß7"^­ü¶«2{Ì8qìñóÎy’HرÿUÊE‘àî§s>éo5ÜK�¢IÚWâ4 "ó””aç±8ª8� 5”Ðê|¦•6TYJcäžâüá4+ÂÆQt–YjH5л'p’†{—Ô©,pñ"¢®ž,¦Eêï0Ýr`¼d�©Û:„Lí&ȃÞP°,$½Ü_´>¦æ….•{“*NÎû¤0íßANO_UˆÒ}Ù}å®Ç‚U(Òª5°VžBe'ª>§:HUž‰?˜ž.»:À‘û¿B<22{L\¹R¶óœm­µô[Š"·oç§Ú·‚DFçní@bÕ O÷è¶—Šp©&5ºKà'ª^ô‡1•ÌXÁØL±O®žºËÞì;5^R4ïΟ@�m�GBê Û— Sû•Sþ¿¨hÈX~Ç?èŒ�*0thådß® qÃà†Šîôð&×Ì@pÕú¤~XÚþaȵ�UP¤ä¢àqë{ð*µèjv ÚðlŽXð¶»@>$h… 6YÔ²'ÎQ¿P ë}_õIB2(fYHcRO­™ÓB‚Ô˜ŸsÆR#Ï|#ïÖ.OË|z8vø¦õäý K'{Gë“ȋخ�]Ɔ֥[ ð“eå18„lW²)O¹ª>î(˜HÅ™“²'dò'§ª Ô�ò:¹tÇÁ‚ìhó´FxŽìV:•DÏÕ¤dk-é.\Д!çªâ=WÖ¢ª>¢‰ÚÊÚ…8RáažÏ�ez»y™¢bm‘u¹ÇtÕ¥ù4ð=ÌÉ�«·#ÔIN¼ê¥z¿Å˜ï™<8*ƒÃÀ5ómmb ìV=”4×úVMÛ& ¾òúífx�"§Ñ’J‹öæe*¦Pã# Ž£kH}òÙ#xÈá—�I·Šz!bôÆ“íÆlÕ &Ç‘·û¶Y{ ŠI®Îa q1–[ï>÷gÚÏ J,â}^‚Ù{C¨Ö~½n†N'EÅmötS-n)aì†ïJŠx›Ô¬Ä³óM‰‚MX?[œQ7jðå=> Ÿ¤W�Y><À½ábÞ( ÕØï·ñö šps Ì4˜?òðÃñõék¸ c£sGLMù³r�…Èœ³»©È~ð›£^ÿò\i„aÀ~3%Úq¯û(¥ ÁQ˜²ÿɬ#j¥¢ÑøG‰Ÿ…/~jÿÑyF ùrœùÅû“ ÃÔ¢E¬Ì /ðUÓÊú€}»PChFž&ÙŽ §`þ÷+ž¯Ð‹fpP Y£¾´Ì“„$¬"ƒÜ4n§^$ç­"gÌðÙjJ_ù7þ3ÙÜU’åðµI Õ7¯‰@UêðéíÕO¦sãǰ�å¡ú¿ö¨·“kjYÍî#Ìиÿ”Šh¢|!ƒ¢b÷+}ûJà1ŠV½4ŠÕêbÆ]ÉÎÊm¸Û(:ªþœ<ˆï/ÓéC—ß¼J½ÁjëdÇ^0ˆ Q’yú¢_ ÷[`?c_±pt²Ü9o¿_Áˆ¥—¿LÖ·zš+r6%û®âèDœ‡µÉ€ d™æí³FJ@`‘Ñ]P aॡ=Õ”S6i†;þ¶oNíTžèòþHù!F»&ö¥J�•E;B‰¼(Ae&â¤PóIÚƒßyÄËGŠ1�,2 ëÈt«¸úËthŽiaÙ«m™3ó8Ñ7=ÃD2¹àY© ÂÞ7#À´5¬B þÌXÊnòw#mqÑö]Ž c©¾ÚwÒ ™Gᶺ¡ I42ñ% в%å˜J#p@.SºŒP8–ý�$)'z¤WF­ÿÖ2šqw"f¨! a'?³'T&¿9p¸yÌ© õ5- �bŠQ`U ‡ð¢r†˜#ì¾\ó6%-ªÙØR±Š›ýE¬ç±/Oº—œ|Ž ª£æêH€ b`^Œ[U?ñ«€‰í€ ï"êO a6}u»'ÝxöÏâŠm©SDŽ�¸��Œ�dØ7|%|¸[0xèú¦ÊæaÍI$\sK.çöUQ!9ù€º¦´õ[ üÚćÆÈjb:­½N‡±Þ@rÓ³`¤ü•’…–’šñIÚóá¯èܸH\Ó®¾aÒé¢÷öi•I×f—@˜Â¼sTr PÿLo©¡ü Æþ¼û¦Ý>m{¶ÛÒ7.Hs­">as¥Â�m¬}õ�æ B©…]´†ù0)¬{¦ íP¶¾7‘rÓH �t]8¬öìýQeSXÇÎ\m b^ýÊ%LÄ�nôBògNòÝ+ˆ‘ÛsÛ‡D¹}HÄýýGô„Ç£5úe<ªéµ©ÓÓÃì.0=P†Ð¦ÆAòamQ¯øè䟉 ÙݧÅÕ„H;, f/1 ‰íÊ¥~aó:H¿Q_*vT¡š'Áùòü«ºÔÔêµOW0°LÁÆ«ÖK"äHh„#ãÖ…~6` («§ì, U·8”�˜ø¨¿. ¾Œmßôp¿9y¾<Ž)´­&Cv|¢v…t"ã,ŽÐs|ö&úŽÄˆðêåÁž1÷{Þn˜M˜‡a§¸mn¿¢à“MgŒ1Ðä˹GZM VËc‡zÉܱ?¢ú{°D) ‘î  {œÆ:%ôûØ‹·<[pÝ ˆŸjÝ ]ã|JÄ ­yY·6wVôƒ§@¹ê,ÚÚÆèöÃ!s jƒa¾Xn¸¹µj�”ï¶PàZ¶Þ˜É÷rãvÎs¾õóSå'«¥ ¬Oå>Û£: ì&ι“Ä¢Ê)—ÓÔsö«ë|cˆ+=O&–0UÎqˆHÞ\cDؽïs"ß*¹ BŠœ‘[¦:²�´.l E^Éü.­*šÙ-èçƒÐs›ºáh–W}F*Â9p7@²Á-ÿ¹»rI¹›`(åúKßkИ™¥OŒYÊ/;܇‡Î>*Cè÷±/�ªu‘S £Ø•#§[´ÛãÅôã×ÏÉ”Id¸päBì½éé+ÃÏ,¾/dŒ“Ø2÷}YÏ"•OŰ�†ÞB³%Èh ¾*27³ʼn´–_�b™{áè ÒÚØ�yOÑÜ&UçÇgaOéäÝÚÕƒ?U–´—C·¯F¼hÝóâñÕæçN½LªÜqHÛ‡|dù+˜Îqë¦Ûéu-À•rLˆ]ÜøÈÌ2Ééñc—8H"¹ýN6\$- Á$¢àX¥òäÒ|Eõ3¹N–a˜Nž�Õ<âÅÑJƒñ«ËH«~h[™SÛo�;QÎÆµ@t†utݬ³ðœˆ¼îV„,*—ÈãOZÞˆEv5ba£PV¸Ù €Zúõ­Vü>YjÖB^ݺ¾˜þ¡S ¹OÀÉ›3‹yRÄìu’ú´sîÝÖ“~,åG7uúÜÛ�°ë@›â¾x>œŽD�Äþšo½Ô—/k©÷%�@^>ºî1CHb|¦9 Ï-ËŸ_Í®ìëø=÷É“fùÏW야þ”•ýÜ.²ª³ÂpÍ÷EïB”õtá<"ƒ<_.4SÙ¼wa ~ÅTW㺾HðÒÅÎR9ÕJóÀ‚¾=r]U‰žŒ¹ƃw¨´N¿�X…: JšY†Æ€Ü,"%Έ®nfÞ7Öû h–ñ�›–~saa™Pê¯Ä©$d�x33­ta‡æfLGŸ?r$ÅLΰ6—ùN?èUŒu“¿V“bâíÈšû’þ¸àEÃø"(�šn–ÓÒXz�>êij¦¹¯vg½(ö¡Ö«E,5?¶R—K*" [Z±±ˆº†R€±eû;:�z'©ãÔ0Á…Ü—„h�¼Ø•!}BWý`ò4õÜȯè¥jz&"ïvQÙ¦ß'ŽOôï¹ö|ÂCzº—9²áè¬ýÐ=®á7F{—²¶’hè½jÓ©•Pr*·¦°Rm-Œ–‘œ/t¡Œ.¬‚·<àt‰ºýDÿEíÚÁ££'š4dWüöíå›6¤]O�ó'ˆï–Ý\vµ“®‡û!%±YÍ�Ú”úMq‘¥6 XA峋ãTàñ`è&ƒQB[Ó©$œðùÜ”�S‘ÙÍæ9ÌI •áÚ¢¦‡m�¦˜À0íMÉ� eãžY=×&0‰Õ4?ØÛõº]«]Å,Ë«~#õZ)Ñ6=Ù~Цﮫâ÷¯°š²d(iÔü¾Ü¢ Éfù-sÏÌÜþ§Bš|ì@5–ï:ä|ŸM|Ó7z&/¹lU.ë`Îõ°V–Õn÷·çÍðúÛ&¬�Æ�CMA‹RLOV Á€[6Q 1»ij«ìªŸÝ—°’„=‘9ÍhI!•è�ñÕ�Ë 8Mlþs  ³«±WAѵƒ@⟠‰M €_™ââŽoÌ¡ˆ5\u¨z›}´H$7;qÏ�”[¶j÷ß õÈÅœàâ�íf©}.Þ¼“[ZH`’@ª^ß’EÙåø¹D½…%ÿÌ›Öóµ�gž%CMà]ŸØ™H·K#ÁöcvÌû‚Ù ÝÄ:Õ½÷ÉŒÑ×_=Û·9W 󺄆�ü\ßR“H90$ÏOÕÚ`ï’°M&²½DŽs× OF?fY‹(ÏÁ£—�ƒŽo3ÙJ�Pbñb¿�9Êp¦Iu‰e’Œ‹ù‚,Ãtlß~€C4u€{œÊüâMiv˜Š” òdT¾OŸú¢Áb§0²Tr\YþL1µ·; ëg €âÿÒÂiëPW(ÁÔÞˆn±ý°!€QR6³-›ˆXPùcßÌbM*Ó&b4ñGéáðîS˜à Yéð,±™ ·�7¼(T«]Ø/UN•jQlˆ­…‹˜œ;‘ëŸ�üë?>š°É byº­ƒ "„�¹%öÒg<*-Çé Þ{�ãØ”î‚áx ²wGO{¿¨£¥@n•j¹XËPÍX1'Eàî7©o`º8Š®AŸde7ÛXEXGâ¾Y†[Û¤6¡h�+§Á¾­^Cc�Owr}/R¨«½ujð8Ú ¥l½ÔõW‚üÃÛD™7ë¼áU|ìÇ:»‚þk�þ ë�5DœS+o «|ô�G†¦5Uášù«Û4w­«7Ñ™·¦˜1ʳ‹3\M£öUÂñuÏ–á¼�pé/VÓ"´L$§œCÕN´9«#T Ñ€½Ê±M:Òá/£‡ ¥ß×â(ˆ©^8ª5�…°4Îϳõ«ñãîÖ úØEú÷FïòÏï‹ó{1K‡ü€t2jÄd¡†²ªÐ�ªÞ†Ë=OªšÑ ,²ná—ÈÌÁ¬\ …œëð7ϼ ­K^ö"oŽªKÓùW"ë°“]²—ÏÚtáÖÁ³RGENɵ޽õFŒ–\n[vWšj_Ý‘}x¾ÀîaŽÜÔz•…›sÙ*‚@›�µ�z äe4HþÑ«µ YûábÁš ¾!Áqû0óš? EäžÍœÃµD‚áÞ.›’§J›y‰?G„�ÍfWM/åáSÚ«÷þ½ãfléÁsºCæ‹™øÏÀLø`G— MÝRg:¬ª÷â&™³†¢»áH¯n¬O2É‹C±Chô‹cÞ¬½�üå¥Ä|bhFÇCá�º³×ƒCÓůÑv±,‘3y\³÷ e{A»µw\·?u‘78­.›‚�np¡(˜059ëÛã߇_‰�Ä^5bÂ;Yo;² ¯L¢G 8ì¹Ê…�Ð3º£…¾“¡Øuˆû¿n y®¤ <#‰aĨÍjÜp¡Ëf'Å,�˜ƒ{°kç©ùl´“ÀÏy±Jw¬ˆ€ûÅŠ@˜+“¸ãp˜vÁU½„˜ ¿Z2@¸»Œ 6{ö¢cF”Çñ膩Ðx†VΖ$¸Ò'ô_ pOG !xšž.nŽÛXo�Ù'Ô%Á¼Gs ^*aýUÏPä�ð<Õ«‡QŸ­¯ZüÒžXW•eÕ´µ€u)êCºÃ”Å�ô„PA¤Ü§áTF^‰x´q•)¼$KȃÃ��ÖÉŸ­áCÓô2Kë3�îÎk-˜z& b~oÃÆA 4Œ'ËB˨LIF CîÐ�LJ; ˜r]&\¬2W TºuGy¿V�\·qǹåÿÎAQŪ†_Ïà<6êP9ÿø4» ~M È ØNÌo£T)"cšø�¥L:¤Ï>¨°Z:;¢¹N=—ÿä¥ÃœŒ˜("î\¤ðN¦)Ò"�Éšyããÿ�ùQã`çµKÕ¨3Èß~XL²³º|åù­ˆºÃM.,5#•ÊÊkv±ø¶ÂÓ‹ù ×Ñ�­MÇ«£/P¥32SÖ|Éb<ë®Bl >±jÐNñ@ <›ÃW#Æ*ä«Qk*D°^ ût>�Òâšn6‚²‡¥Šß}ºpWÉfBMJò+8— 9•lPŸÕZ¥Ï£²76qƒ*¡–º½ï¦ow>ö;ßC8zI“ÜfqfpˆûY6þÄž4ºé%‰þQ³â@òÖ :O=fl>�éÏâ«||®ïW÷óKÇ€ÄÖ‘‚¶@CÄÑTpë8‰’¦£±îJÿO$K—™«É®X84š¯ÔB�ÅEq¾­ÆmÇý[‹UÀÐ’5×ЉåµøV—Ùž#hÓÍbïiËœÚ뇋˜`Z_ kŨȪ²—DØvMŒQ3Ù øCˆüC·rµÍ¬¯¼íWæ!ª‚‡ÓA–L<šØzz÷ßÿ�¸ˆi@ -îü=�Õ"â´ÇîN~WÅ�á\œ®7¾¾@Ï8‹S$XgXÎkðúkñwD¡¢Óš'ÐÙá|ådG…ƒV‰`‡‡œB&ySõ”¨@�R5·1Ò�x9ˆ["%“kûŠvù'Óœ(OFü�‰XöŽé4ñR‘ å©y�a8þ•`¤… 9M$�Üþ›?¦…,Å�µ©sÐ4ɦo1�Ö;4ÜyÒ* «ÂY-q°ûÌ¥³9—V}÷*0 ¡±CG¹†îñð”¸GÐeáeÝaÞ0I'Xð]P.\lpà{Ÿ¨N{‹Uè ðºqâO ÜçmÍpê‡ùš¾ïG÷ù.ßãSíwìæiÔð‹ƒ¬Šk+³[5þ°m ——‰^Úmªf$+>–6åá\ îÌ=”öq¢Œu¶ý0´×- ;Je9Xo|AºŽ¨X^7ÉžUî�ü~˜L2’ÙçYE™)u:«F‚SAD¾p8�ÝœsŸ–êåÞ›c?N¬%°L÷Û`ˆ�IÕ}zš°;ÉÉoEâø�¿nßzú!ús®or’.¨ÐÉ=¼æ2޶íL!6ú|ha­ÞhÔЗlõÜî ˜z£±Ê™§]O²Vß¼(ä¸×ic¦!1­µ\W„~ò‚'m*€ÏCÔhp�©)ßZù¦½¿†öL¹žl§‚R£�£;àŽÔ«5³èà¡¥ü~ »¼f‚S‡CªcþÍ46”ÿG›iw�"'B1¦Á{W,ü�@†KøÞ7AÌ.ž°ÂÅÁ�ÚåÍ# ñbV•îŠ{…ÏV�ªg �ÿžv‘y‹ïÈ¿ë 'MÿòÞ Æ*V§,xëé�ª:�O—Œ�Œºˆþ’ ˜ÌUC³÷æo®Gê&yÈhçNéSÓ»#]XqlãÎùP)½ÿMÃÜÕÉÊÄãm2ò\$[ÃË0ÒÍJ™½©ÂI� öËú:wí‘Y`>þÜn™#G2¡Q…e««Ã0'fE¶�[%4î»_ÓJ Ìà2ËHRaß왪aߨd’¡ÈmlØ@”εbr…¹ÒÓÆJiÊQR9t¬»1&;Ÿî‹ñNŒ­qûú,øjCBÛd3–“…L‰e·ì|ñ^MÚ#VS¥ƒ®ö¹| ‚4ÿ„­$"p¶V¢_jK2¹êÉÍÛ<›Ë÷×îXÝ¢1�éµ^C"êš™&Ÿ‘ÄÈï+2$Úw7êS�ÊÄO¦ŒâÕM€ªöÕ1P§øÏDæN=g ¾w¸(…÷o2{Â}êæ@Ëë¡•ÑÆlñ ö\øgøø'î÷jÈó)Bd*%�ÞúѨ›IÚð—¾®Oð¢î4¸ží۪ػIODÒïkû,”,§“�¦ã¡§xYao* ¢I7úÔ]WìÄf¢ìL€I‚üqÛ{P›ÒÂÀ©+�×µ½QÞðÖAÈ$‘"çá\­b–Íl¦üLµÑ0¶?r׳+u“˜jTÓ?“}hCt@€ÈÁdN’†Åò�'+FÖ &Û¥õ õfG ù¼å:Û9z„›Ú¤ËwsËý€, €ˆ—‘A;´µN‡õO„´-¨ÜIšÓ’el³¿œG99\ÓÕA#Æ´H.ΰÑí$ûŸßÈ=• ~Æa7,0Tª!b¾¥{umñnÂÜHÕŽÜ_Ýsõ¯ 2 Ú=Ì´Z!Ú9¿hö御1rŠu4ƒêŸnü�™ç’9OÑ,” žçÜPtv˜×ÿQóö ‘»uK7ÅÆýñMn½Ö2‘U¨„-Vð1Rœç^£(õFš…ÂÖW„jÍq¸¸µñŒq]Oâ2Zr¹~âv“<—°“ú‹Ž4=|„ÅCRêç“Ü{ieŸâèÚWd&ŽÂàe?´þê#˜ ,}¡ÕÕܯG*7\ʯº‹ßëI+\݉VA9bTõÊ1 E·Ö¼s”äê¥!*FcÙ¢>É@©Ý/ë:ìJŸ©Ã�Ä�©aÙÌñ8uÒQRh§/{(¥u`†&6ä1Pn©Ñ$X±…÷VÞƒ¯Üpuf>h1šÒ2|ùÀEËæ.8‚h4²¹ÇÖ¼;÷ŒÚ; *¦ U%1~½þåík¿ÐX©ÕÏÄÞ<s\bf?Œª4±Ç¡k )/—È´ fKõzÊÔkÙ9J-Ì©ŽÞ…^’ÀZð³Žùþªms!�C§ Ô|È.Ì=Ë÷ô�ó÷�]EMsríæQ+*=ÚÊíèžË¿¦Æ�˜UÝ“Q•o-A®°¶L¦S3#ÕäÖAºÁÅVÿ»_}¬p¶˜ï÷÷»÷œ{2¨Û\3ž0ùÙNÝ%C( Ë“dgŒ”¡¤Êus’¼çb./Ôj�×ñ½Z+QŒŸÜ÷b•èÕƒm¬®À'¶�²ø)ã^7Z§ö;¦Á$À¬4§gäªß7Ý8ß8Hé}á8LU¦Uý¼°7;Rß&†˜#\4Ù¥«œE�3è² :`èšó!®úSËq¹Çb+ ªw¯µœåÁrV S…Þvó¸ØåtœÌb)QÜ�¸ù‰µyÙýv�èJ‰@Uq»CZPt0çªÕï9EŽ�+›÷™Ã#cïúe*ì¼î+µŽèºlóÈW¦@N=ïb—qÄ> ýÕ:Jí"‘ü¹«?R¶>×twc�«Æâ ç‰]I¢ÜšíOÅKú·Üò6Ž{Áò´|kŒE££"¿«3�£ùø,Êé¯Ù ñ† BÌŒ""|*CóÌJ]QËôxvû<G—hä{ˆS,²‹‘b{Zv—Ù©M9iîIÜö!»âZM ‡Ê]LÚ÷on¬8ôö·q×2´®5K¦3CýÈ–wèdcMÉ O¯R2Ü¥<!~šÉmÝEÂÈM n:Î 5#kUùäô3ÉòHÇ{Œ…HñTâ6ìà¶@!{xá„zLFGf!‹~�N�÷ æÆ*Ô FlÊ·Ûƒå@i�ôŒõ ¿(²J¬Z¶„—YÙê\UWcªes°Úüv äÛ 8§©y~ó°Ù±5Õ´i5÷¾A _¼¨!>?38ÍXa·‡ˆŒ‡HØ�÷TŸD!•KñM*üŒ`¦µN;‹|£É¸y¹À£ë�sóÄnn.8©¶þç„ñU·9}+^LßÏpù4ig Ý`f–H´ÏÍ•_"Is5íë[ì&ö̶G�Í“Eð•ì™f]Ê:uXÂŽt®ùí¡s?%„È^´¹cæ~bnbàKI颮‹­Ü¦X ¦Ú¢EOø„×PíiéÝMð…~ÜFö'ÞrvÏ£|G%2]ÉÒàfh–êÈãV¥†œPyÒ]„ÑÁ�Ü7È‘‡%%"` Ó¢"©ÀÖˆkë@ Toáeî·²I»MßË'­G{"ëjÑ¢Y¶M¶¬°˜éQÁZ;ß›{¯‡ÃÛ‘Œè9ª Ò=Fmñ—öóݸ¤ªÓ¨O‘URDn3šcãšF”oT4;x÷ŸbÌŠJ×ÎÒ¦Þ³´?f~]pÜ9ÙgMÕ�Ö�Nå‚' Ú{zðŽ¨«<FXýn¥Yî;’øR Rb!aD˜]´-(ù1Õ(IYª’!Ð}<Ñ©,Wõ"9¯>‘މº¡0pÆ@�Æ‚K=ZŽ þX%W�™£Ñ8Ïfá¨)I‘b/¢pB÷z% ý+M­–aE�ð¸T2u·¥Rn2Eo«^½·ùì­4\¸È‹Hqÿ¾.Ù€� ~\º[“Í=4ôI6ÏõÔ'šh§ÈšT<½*ÙþÎþ¢²¬N?Á⩞•Õ•Á-.Ñ"yE¡¼ŠO›«–ųÉ(˜9ª–/Ÿ¨ôªÀ†ÎÂY‰a�o­+q�1Ÿ·kGIQ.ÝlMˆ=&ÚRs±4ì«kø¡ö͘þ¹ÝTH¼O˜s¼œŽ¦âÏþ2ÕQÊò€˜f’°›ØŸ&•®hJºV4~ çDòÕ£wc8m¡ µ´ËôZ ºƒ© a{›î-éýæ„xð†f²º»äž‡Ü�‡Ùt2ƒ¸ŠzP¦Û3JHfõ ¿—i�츩kÓ‹oà,œ¹® „‹ B˜geu3A\®m˜ÙÞs-ihb´Ógè£&ŠHU™/K°Ù¬ø:$l�_‰AQð;IuÓ¦:õÄ�g·}W¢;$‡)7`Óø€æ4ÆÂ”#þ©‚¯&Ðí¿|¤¯Øe~dSÂb�4bÇÆô Õþ¹b˜"áë¢Ì²ë‹« Q·¤�%®/²-¸….oy�õmKX¢vØIâtº£õçq9X@¿iïÄŒžFc.ˆJ‰1…#Á7O*«÷[+\¯ÙèèPÁ¢xzlªFÄ ~ŸÃtÁðdI¹æ³ü¾"ó¾­@u…Nøðˆ2¯Oúvû™¨L�D%-ë¾Þ4úƒ<T­t‚u”ÀØH&àÀÊÖH&¯Ü=;²]q3;%Ö9)bußÜ©ÜÁÓ³ÜÔÎ*~7$Î\.õž{É=ü#Í…ÍÔ¬nçñ}½9X)ÃŽûZlmÄw6´=·â€Ik%aåñTöyÇoêâ?‡=3…ß�P=ÜGUpye‚…�ÈôÓæ'MÝAöÕ†úQˆ6F¿Ê‡8 4q�Kp#ÈErÈf?Ž©™Aâ Aä eʆlà yÀ�­Î„dq!Ó&,7�ãà›>¥èL¿qx¯$ÚýtÍQKQôÎW �`pJî‹¢©ØìXÛ«}é¼îbÊtÉŸ7±ƘžîÌõQÈÍ%Vv:r·�ìÜ*Ç×ñmŸpÙÂiK*nIqÂ3Kœ�ùs±º½9�ŸçÔ&¿g% !r²_ o^YcÅ8y¨%Ó4ĽŸލCÓâµØnrõD×T-¼o�1hÇ ï›ÿlÉS‡A°V,¼â#ös8_ë8~é™eJ?¬ê5�FåÛZora0 Èˆ;pßX_ç¢]�L d¼qŠ ?gƆhXª©9Þ\�ÛùÂÕ‡.ee¡ÊOEx¯ì„ƒÿâç}Ûg'1ÛU·{!ož® uŠ}nfÈúíTÉëÓó:Ñ ý˜o¡²€7ò�^Šß±æêa1‹¸“íl˜«7;-nêÌT’çÇÁÏšn¨4žÕ½eýS‘åhH¨Ôá€É „•Y´9gNÇA<Ú°_®µÉRæ´së¬ëY‚"�8ìdº;ÈÜLö̰¿®¨O96?"¿ŠkoAgÒÎ=§ºp«o:]F é1¡iÅ܉»¹1Íí<˜%ü‡VTб‡éžTÝ´õ8�oç¢sKU�#h>gÎé»ò-¯ïæóÈ�b¸�¾ Vûp{î�ˆ‚»ùø%kW²‡€ÑJ…‰ 'ýæ•XU*lE^"šÞ%úc\SÚdÁ[0y="[;ðy/bœærçÏ[‘šµ ãƒò‹JNýX;}äJTà);]ä")!󓎇EÀ—Fä'7¢ˆ¥ùž-*õ|½þÓRų銾i¾�&=òVÊe¶®¨ß¯’.†„=“Ü5BÙµ@Au®Æ¬›ÍéÄÏ—ü¨Jì¬ïÕôyÇõlÁ’ÁN° ÞÙÐðaO~ò¬1¢^Œ�˶5ÈW¾‘l‘éâ\·'ÝÒCãÃËÍ%ídí ßŽ ý¢™ïd¨BšÓµÑ\}(¶qaÉœ…<SŸkˆ¨¯#,¸–�ùê8ñòi â�Qswá .ž“À:U4Ø¢~Ø%HïÚ™ebQzðË ¤Bw,Ñþн­EŠÄ—)òKõšçÜ †·#m’üò¬B`f|ÕuMÂ�|†v¼4JO2Ô(mð#�:3‚®ô�Â#H 2_ßà�ûucÇ5�ý ;J|Î4Û_³vy1Y޼¨¶í)ܨ�ójЫ8³Áɤïìå5ýÞ=óÒ¸tU×Ù 7ØîRÏhè~™Lµ‡vàQ`Åo:¿x®� €f˜ByZ7÷ïk£-U/Æ+qÀÂË%ÇÁµ¼f€n2¹™¥h²”ÕÚtñ\ÂéýU:ºÃqP܇â´pW9):�ÿtvé߇â»o£švdL‰ WÉ(Øá4h] „Gê;º¦ ÷2Þ÷Z1îä‘»ö¦ŽÃ�Pœ–�JÜ®É' ׯÀŒ_wŸ�£ÇmH½e9äÌ9žLîîgQU6ƒm>?í­¿Ã:o³ Á£�í½Ë|‹–zûޏ>ˆ¡-|’@^m΋–PZËéO©æ„ÿi™F<Œss:±37LC‘ÈßE}ëæ07•`5¤{ÝæüvððÈ‘ eú¢ÑAÒ±®x¯žk:+C—µLvlM̦L8z´çÚqûÿó óHÔ2äŸÉkñÚ}ówªÎg³Dl'sÈSY&üëe!£³An¹ƒ¤¸�ó"²£–©×âkå¸Á,^E¦Mt•WO�­&µŒ{� rdÞ?û4ý �䯅haD |›qÁ—Y¼<Q’D¡‡$)Ó§BÊppªáXÿ§‚¤!ÍßhzOL3!S|{”è�8ür‡‚á!7y{¨&«˜W #z“zó†PÝÂh¿wé�F�°MÇIîñ0´‘¶ðÅ MÇ?¬ñ"®bKrCþMev¨Ö$Gâ__«H>ó0h^‘¦¹¶Ý› !bøW¡$ÄOƬSqZ"ˆ^˜²WGOÌ6¿³@&ÅÏ]�ˆ/ð–~Aõ”7»¼BÐ*ó늧‰Ù²Ü«ÓV¶-�eÐÁiKFD™Ž£ÙŒRG$D+”!ÑÓ¿ 'Û¯_ÀØß-Nª©ºY� 7ùÒ@„�:´Pi»àŸÉàèÚgÉÑ¥×e"Ê]±�þZ“…#˜yî ýüˆ”¦‚ð â¯*Kr¦è‡¨{#çõ�çÄ~�`¤U�Ëfwà‚Ö&yª´;s1®¾÷UÛ#íR)rùéP2ßw62Íù­Roªú˸чfÈK…®bCN𡦠zsÂ�™õàôcøM:yM†ù¸Gl̺¤f/^p¦0wžìUN+9—“4w‹úÆÇ®à ®Â0˜²¡p¶µèÿDð«\jF›îʨõJÏÖÆí=°¿…èNh¥ó¼Âô¶1/r‹ƒÑ *Ÿ4¼¹}¡2øhÕ(êá©ç…QJ� r©â)Ö�ð“g®³\ºäË:ÌX“O-‡qVJ÷YÕÕžæ¥T½IaÇÕgôvžI\ú]�¬ùPsƒ7~šHùG±rÿ2Y†ÎÛ´0Ùµøß} ÿÖªüßFÉ鹆\.î�ŽšÍ!ÞY!Ì�™ý5ÐîeÅÕM—Ó¥=³`Š|§œK!ÇâG¸DK—Í-ŒÉðÑ\Ü/¶±GµÿHR1Hº‘ÄòT#ú÷}¸£LÄ|¹i\uÚCw¥ìy»–V¹ÑÂ~î[ -Þ‚‰Irþd]{z-ÊìyB"¼v¡žŠæ‘M¦,Bõ©4Å¡íu;Gæ€"´ŒK`6ÖP…AÖ„¯JÅ%|Éã3ÿ@ÖóŸç�êb¸Ý2"Do8†Šcší}äT!ê¿]#ÊIïkãlÑ…Ýwš†§O~ï´Ä¸ ¨´çwR_Š:ÓAÑôcDéØÙ%íä�ÛÅ0³„SñRM—Ý­Mû¶aŸ¸T[½á;ßïä}ÚЩ¼ûì°¥��¬áÌcõ*ü‘eÄ”A½–£Ÿ ÕÏ4iXk™násWJŶ&Aƒºµ�n/ð�Íçlð4ðÝe¸F¯›ÞåY³*mY ׊'éüØ»¡éË­R‹`aY‡Ü¥. ÉYA®/ÜŒA¬F…£ãLy~Rá¤Í¬�í¦ÂZˆÄ‰{ndÇ=Í’À<Ã7"Ö�†€xì­(ÙE”-’*û8/Xýͺ–µ_¿l•ttô“¬"NT€J¹uø•±k°.^1Œ¾ºÛmå\µó˜ð#lèïærF„`|™¬©¿>�„2<Õ’¶jÓÊa�íê��,X`ùêRî�L !xZ|…‚7±)�»™÷œFµÎÂñœø4G¼[RÝ(¢“ð�ð|Ç–ö[�ÝÀ�C<þuh`\ð+†ºÆWk–—E~o)^9@fۯʵb9å;ßwä%õ.^ò:º`¡„<HaþëFÕ(š»˜·ÊHŸK±K…­b k+ýwÜÌ‚ò»u´Ù*¯N ÛVàÑUÏQÉ#�¨ x¿á=a«Ýîè²M×,œ—ë†}Žs�¼Š›ï.÷R’ ”½Èq?¶ ÊÍ:"§ˆì/L?§„ÓÍi¡œ]¦$4#\ãžò�[£ñ¬ð³· ÷á?ÇüöíÿÂĪÂ*S‘ò&V;Ÿà+oB `ÿýؘîmK'*¡… ®+�8Üåe‡¦pÍiŽè™½Â›uØÐ|Jº€s)]?ôàZ ŽEu‚OÓoŸH{!Lx<²2n±ªt<U×�âÅ&õ�«©pË-GéX&�DZMTì9z°ØŠ1ûŒ& ÃâúnÈA~ Ø€9ͳ_�@J9ý²s¶Îå7k× V‰ÈKï¾^ýf–ºþþÈî ²Š>å _mòúÓšqf�[Ëž¢�C@ˆápè2U-?Š�ìqvÉVy;!=!ŽûÀ£Æ�XéÖ�ÝtcBr[I…7ñ+¼J³‘Ÿçïs�\èù‡Æ«!KZŒ ½ð!Åþæœ8Ñiî/íÖJ~-ƒä ÓHØ”�àÑM'–‚ˆŒ½�žøßy¨äþI»î:ŽP�º|²=y˜³I�p,7V£�mÝ5oèÖMw“Ü6}Ö¤$P/“)à@aeÝñeMs¶WÓñtX¬b@¯prôøÿ…³f<UÞ.ZqT,iÇç¸WŠÌ流ø8aº™8p¬ß÷3®Ävûª¶² �XGÀØ/†cú¯ÈE`”/´íS±R­wš4SB< ´[[ì;${ƒ¨�3�sÚ¬y�=P6m6LЭʜ5xQÖfÆÓÉ2ÁÔ”Í@N,ñ‘T \�¨ÏS­ÂþC~®Òñ©›v¥ìK&âËÔÈÇ¿ ?“žÆÕ(r Â=qÞ3õdŽ4¸(÷,·—öÓ¦Ò´€/‚V±ûì^.L½ä~þÇIsH�ÓfâÙêØés�žJf`�BÛn2cŸ . CÃTÄ]€5xMóÿürLZ±“ÏT~z=0TÏù7pùCZt bá8˜x×­qÐøJ¥Á¶ÇsyØ'F8ÛIŒ+±p°¶síÕ<È”/Ó'€¦ê¾5Ù�˜mÏ^à;ËK‹õ*®ïÁµOx<ª2j÷Á¾Ý­ðD„ÒIø­ìîo‚¿ìƒ þǾƤðõÚ¶ad}ç]ߨV=cÚãP4@nWºU‹Öúó…¤#4˜eá@ Œ¤ÑÖõ)®Ló!4ÈÐ-ŸEþøNµV(ôêq²YÜÂížø¥Œër9YÍ2ð‹EüL3f’ôff`(ª�¦EÉLàN�³–ç3ˆbf.È,¥àâ‚"ŸS8`Ǿÿmq´Ñ"ä#,_u˜ZÐÎiÔ"ÇåFöÔÕ­ÄZ¹Èç°zhñæuü™ð¬—N]Íä¯!9°4F©)Û)�9ît$¢gOIH7·Eʩ˴6ÏнxîŸs�ò¶©¥t}a…(Œ‡Ù-K:^R-à¿) X‡éùŸ~šPV0¹¸ú[øž¿‘qÛ Þ~(]Å"p:—*²Øj¼ëJÎâã<W,óžáôfýSî &†1ŽæŽ˜Í_=ÜÌ<£¬ú4RâçyN$X{ò”ßžkìÜè¶Ðè?­”æ· >ÑäGHФÞ>¿XÓÓt3:ØIQ5þË(º5âÒ£NϜ߲ ÒCÍ©ý<Pt'Þ¼|ÖÆaªy¥—õö맨øÂòyõ雊Ti–~ö{^¾ìÈX©‰ýjÈDèK”L'ƒ AR[‚Á¹äæ&nœ§  îÅ5+Žåö—X>Wž•ŠÈ£�Cº:—È.(_Ù›lÉ€/˜;íDGhfB—o+«×¥Oä§bJU¯åã±×Až5²Zô03G/Ôa¾�ÏÕRQ+Ð¥yÄqè}ØhîÜ3 ß ¬Z˜¼q·¹^õ_`@›‡&v27G¥?¿þfî.ª¶+!y„% ñÿ¾ 8^¸H2á6hd)kô£-ñ5xjÝfª÷©9ƒ ¯&ù |0pŽ}ym®�TÌìךs¿p>²£¤1ˆ¿ ²bíþçÂòÙ„xìrùn8Ö\�†âÏf40\Ø¿ÛóÚû›¢A ÑjVÊë–�†-Õ5ˆXþ›nKô¦.Ü2 c‘ÇÆú�yaÚNðXŽ•ø™ã®õRôlXyù@_©ðy á“|ηÀ¸I-ï÷”Ë1Z##ôôE’qº¼Ø°ùXüxwH\oñ²M÷ü”ON:s ž0“à»x£ô'«õò&š¿Ó0?máË‚QaêŽ5Ö9 }aT;—i­JÓÌtp}méƒ=~–­>Ù�ædwsÚá¨FA6Úóý¦”†V“ËJÿŸ¶!5í±!q Ï8ûÜÂȨ3·�¿~“µñR5 Ž |†ÃVø‹Œ~ã¯C4/lH„Å|ìà«àZ™dj6ëB(ë€n2¥W®ãfúGdêF’^Ú€ÖŽ’£¤:Bi„:Â$[!Œ§úÕ£¯íD%Ë¥Ü}b^ v¨ÝzÑUVbŸ ÇÕÕ'" ~µú²¾Ÿ—¶ËÙM4Ë# ÖФ!¸„ëêlÆÅÊ#—V# endstream endobj 45 0 obj <</Type/FontDescriptor/FontName/NCLNVQ+NimbusRomNo9L-Regu/Flags 4/FontBBox[-168 -281 1000 924]/Ascent 678/CapHeight 651/Descent -216/ItalicAngle 0/StemV 85/XHeight 450/CharSet(/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/R/S/T/U/V/W/X/Y/Z/a/ampersand/asterisk/b/bracketleft/bracketright/c/colon/comma/d/e/eight/emdash/endash/exclam/f/fi/five/fl/four/g/h/hyphen/i/j/k/l/m/n/nine/numbersign/o/one/p/parenleft/parenright/percent/period/plus/q/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/v/w/x/y/z/zero)/FontFile 207 0 R>> endobj 208 0 obj <</Length1 1644/Length2 12541/Length3 0/Length 13397/Filter/FlateDecode>>stream xÚ­vcx$\·elÛ©Žm«cÛ¶*vÒI:vұ펭ŽmvlÛîxÒï7÷Þy¾™ù3sU�½Î^kŸ]EþEQ…^ÈÔÞØLÜÞÎ…ž™�‰ ´5vuV¶·•·ç–¥W6³p|ÚÙáÈÉEœÌŒ\€öv¢F.f<� 3S€¨™ €…ÀÌÍÍ G±wøæ´°tP©)kPÓÒÒý—åï€ñ·ÿ@>=��v�ŠÏ/nf6ö¶fv.ŸÿÏŽ*ff�K3€9ÐÆ ¢ ¨%%/ ’�WH˜Ù™9Ù�]�m€&�Y ‰™�³5ÀÜÞ `ó¯ÀÄÞÎø·4g†O.!g€ÀÙÁÌøéfæabæð¢8˜9Ù��?¿€Î� '#;—ϸ؀v&6®¦ø´›Ûÿ“�ƒ“ýç ÛOì“LÑÞÙÅÙÄ èàøŒª(*þ¯<],�\þÆv~Â�{óÏ›¦ö&®Kúû¤ùD]Œ€vÎ�3—¿±ŒÍ�¦@g£oŸ±?Éœ€ÿ¤áê ´³ø¯ è�NfFN¦6fÎΟ4ŸÜ»ó_uþ—ê�l¾ýãmÿÏ­ÿÌèâlfcÎ�ÇÌòÓÄå3¶ÐŽñï¬HÙ™Û˜™þe7uuøÌÍÌéŸQý�êÏ$ŒLííl¾LÍÌáåí]>C¨þßTføïù¿Aâÿ�ÿ[äýÿ÷ß5ú_ñÿï{þwjqWy#ÛÏø×Ž|.#;ÀçžÈþ.#§ÿÍÇÈhóíÿæõï·5Ìþ•îÿ…LÊÅè³-BvŸÒÐs3°q1qÿ �:‹=ÌL�.&–�s#›Ï¾ýcW³35s²Ú™}êûOkôÌLLÿ†©ZM¬íþ Áþ/ÈÌÎôß«ø”ìŸå´EÄÅhÿ÷%K¯bó9lÌœÿrQü Õof€ÿOCÎÞô? ……í=�^ôÌ\�z.æÏ×ø™7 Û÷ÿCðˆ˜ÿë,gäâô�è01011’þýdúû? �½£³3±7ý;H*.Fv¦Ÿ³÷Ÿ†¿°‰«“Ó§äÿ¬ƒÏúÿãüÏ+03ó03�[^°7á ²JÍHs©ÁÎÕéíf vøY¯Z˜ïWeßå›¶Å]nøZÌÐ0ÉóþëÛü‰ÃÛž4Íþp7– eW²ÙEÁwRêž|ÔuŠ6NÚý�FýŸˆi§Q^—s²›ÚLêûÛãJÊúůP„“m¬N0—�Ô~¤nù~dH>&)u1˜í( h5'§ G�”ý#Cƒ]×�={ø´Ù1°ä¼FØ>I'_]¾:ÝÕ›¼C>»q:WÌg6kT¡&¨¹{â¿,¸“ÝGo¡3§�³Y|�î2 .Çȸ_„†ÀG³Æ Ð�ŠL©Jë×¶/H�.q¬œÕ ð¤Zg,qGá"$RI Ù7ÞQÕ©%ûç2´CâL%Õ™¸PÒ”´Ô#ù§8Ùjñ¾’‹ E Öø�”%n ýÐosùNÃß R©šÚW›uªH?ȧÿÁ|àqçÈÇ$(¨eBsõ�ý¬\Êýu‡,y½K¸lªâ÷à2$ô×ÔÆèÔjw™‹]rÖgÜPTÉuÛbž(©ò[ïÛ$ýæ.�ŽÎT1ö�ÄÙ¯†S‡½ 2ÅÛ0ßêµ$;ÏAJd`¢ås}Ø’´Oß�挫èt"�t·Êñ3[…“3º"8vy 3�—lX;n_Õò’GC<"¬‘f£jФG@ï -˜lŽ¥«4aë�¼mÚ‘8:æuò"ÄlÁbŒ—¶}e_'Ö E^ÀÔ}ÁËÝ×r9DR�;ìÂz»¹eÌÇææTb’îvÍ¿¹v7z%�bkÍé:Ô§9¬M¹Ae®&ÇZ[›Tj$C€¢«Nt(5Jã—zä¸y¨Zo<Èf*�ٛɒkDñÊxÓvUJ˜’–køJÖÉf‰V²Û¢Øú‡”{Ô:«£<¸y:`0ßç+² �(š¸ï4QD‘o…Î 5þT’ CF°AM•q ‚²w”¡ÀLsåW| ZªÏâès+ŸD÷.ØìX� ì<€XlÛQBßnbV-z¬haΔ �P˜>¶çzòÄì*!ñAGäõ²�eƒuoñ[öEBovJs–B´çäQ‹ ͦw§êKër1`•ÑÛõñrÛ›2“­iúnÀÎ.Y_nHõ®‹¾±ÖÈžLœû×Î>vg©k›¢U0½Fûw†})ÇQÔÈ�›|7Ò�ö&1úéã|ÏÅ Y…"R´ñúS©˜6v‹¹ì¾ÔÓIµ&ŽÇs’ºÂj³0ó»=ûDyB%‹3'oþÕZë›às̳»ÄiF#á(5~·3+&óêÚÉ÷:Ùtp°‘p+ºi\¼¥HÖévZv›„TŸe#NÀín­é`aüAZÎ/¾ñÔ"¨e3º¨éÛ~ôFh~¤?9]¢¾m˜d7¶l˜�[Ýä~yžz·yÀæû¥¿C¶)ƒu=ÜB©¹G´!¥Xçäð³xOIw÷aud{ý«¿€ŽÀ¢ƒš¥ˆLö]ÎsùC2uÙÁÞ1Gîâ6ófó.›Ï\6)1ø|!T&”.ô—q<Þà$¥1“D!ℇ­5Ê6¦H†K¾ÄÇî7í*é�rjUÐ;Z”àoÄ„ú¬£ßÙÉð®(®‹¤ ò¤<>`‘ ‘è^@Ö,(ªŸgÛÎøHaNsDÀ]Ýð‚»q'ö�Inò_¼�)TÉ›^ð¬>JJF<Xô¢ÃS·ÅdûWSÈ•ºÒ÷‰ý°+ò®ÃQ¾^þjUŽ…1žf?¨pØ®m¼bHNß´ÙàXpÑ@ž4MÞÈþíûãAQÉ^uXôñ`íS�šÃðÜ'.ÄUe†®Hkw��H¦ìú¥#ú±É÷&ˬ·ÇdÂÆ¶Þt&„8ä¤bŽ×ÕoÐÊ\<®r€56+:ùÝQædǹ@¤()•9©ÜAz~àƒï×l?|ÿCÁÄìê‚Â+7ue H=@[„ +ïFò”܉¦õÞÖÀ¿K<èBnâxüò6PcøB(6¸¹¡ „À¢P�Î"eNøHë�”f½èWùÏûS† ÕU‹®Ì9Y)ѯÁÊãj©“¥1èº'P}ä„ÓôÓ.Ç®(RL„¶†`dçÇ�.JNT»‡¯,;ê×ä?m3S¡TsܵóCˆ‡.ÓŒê–ò-³H}Ô4÷&K à—4±5:wn€f?:�C.S7ƒŸ¸œXøÝýä©ÓºØZÎ"PôËÒ×…\S7_�*Fˬ@ “f‹?:),Øw[ɺ—<ÂÝŠV¹’“ÍS1‡ëVÝ"ZnÊ'D`û½#t8´B$ô•½…3-ùëËV6cEú+òd_lrüàÑhs •s05}*'µRX£ZÀžk9\‘›Öæàƒ>I¾Y'ñÞÝ—©Ð•Fgš ›]âkÇŽ~ñÊKÝ]°#Þ0äü¶ËIBŽ€: 4¶Nðw½Ž„3Ò� :}/3­ðg¤¤"´J†Ž�/ÿ1 éâÎ*´.ªj¼>N¹ŽÀá­… ^’-8ëk¬Wûó»¥rw ÷G¶Þ%‡ãÂ�›¾vî¾Ç怱³g�#Ó<ÕŠL=÷~È4’Mx©Å›>ÐÀ`¢ ëÎ`å(v\=ªêkØO¬Qb=*ǵå(®„í·&RDfR.¸J!1¨5™QûŠ £Të¾j�oéß3{õ³–f‹V‰d[ËÕ¡ît¤ýï`ÊAx›sn�>¶}åH§gÂ4ºh?²h¢u–1´lZ ƒ°Õ6~yü°Ž"="(õù3‰†íuÒ„ž+O˜:Þ…/Òõ. »Ÿ(ø+ümf—+<¾ë¾ÅJ¬ƒä�Õ„->¢� ™!õÆ @Ø)Ó}J¥óeÙ¡YGi·±/7æ[nê;Õ-~)Vv‹°ÝÆG£šÜIDtËm{—£ÉR"yŠ7¶\>'s8º>\gÇvï«Í¨Ç*¬Ì0CÿU{| ÏiŸ2YÕHOîŠu‘?îk¾¬é¤à{6Î�Pj‹Ðb€<ø* FBŠþQ¨ëfâÁú½è—n_PâÚËx¼Ñ`À°H@¼+§-xêJÒfDže±Aaœ%Êâ=MöCƒŠÕÕ¾cŒ™»kdb„¶1æ�}¬¯'¼‡Jë\j!Ö8@G6 ~·á:i•5¶—ä4X—!Hmωj]\9AŒ*Ôèæþ±ª={´q,rå|û=ß=LˆÙ#¥\ßKUH©T½ �ÎlÝ~0‰œ(¯æî|žmNIŽ\’dêßmñi÷1èOóð 55ò…ñS �ÆÕ]Îu¼ä‘O$A¢VŒ8£sQÜ­È·�Ò[ÔphFÀ–õ³ô?41Jn·»à}Ø7®Ë…�PlPBt›«¼zÜ0S£Š^”t˜wÌ"·TñM=uĶ®9ø4û*¸:];Ðöú”*Áçϵ–*hi\s×5"æ¬{9áz¬›l"@ha¡•þÞ…LÖÎ¥�°¨ª‘‹Ó«ìi‘ÖÐý07,å»KlÇ.}âHxƒÂڴß7MwèÒˆ(§‡K‚ž¾–Á1É5-ÜCèK‚âJ˜‹›¢ŒÑŶg8õ-d Úc±$õY?#Žw¦ø:AFá­ljó*Ä{—ß ¤vj\“ÉZë s%;;…í üô÷D Á©½4,œns¡•…q•ËéyËû(0®d=öŒõB?—ù®Y¨xš¢GŠßƽ¾x�îñ®'øz�¡{ïeÝÖ!¨Ê¢œ²¼ëô{7Z{8¸—AѦÖ�QdJQÁ m|è6µ!£ø‹ÝàG0]pš¥óÈT‘ õšˆÙ}�'½)Äéîë´É¯`%J>¼æ<¼/AÐÙþ‰Ø/ÜÄ8{ró³¥Er$d𚲪A¤Ûbƒuë\»?�ˆ™Â´ñÕ’˜»û†-u/áâ“ú‹£ëcµ¾¦�ÚàXVÀ7ë`„ÍÂç<ÊÁTÁE³áî{w|xÄ1…Öi›Ëó)(Ø?ñì\ðÏWåíðºù8aI“sÆœ|�¬Æßn <©Û³ýÞå”pÖߺC¤ X;’LdÏ›Áš4s§¼(ª:�ëE²×€Û‹Û�‚‘礽4m³)ºÚ�”FOÎŒ’?P•¿À7H¶# vÿž<PìJØ;þ�¤0CGÎßýz_)CX~Ÿ U@g°}lR¶h�lŽx£ÂSuvÜ;Jrb)¼/|V_Næªý)ÄöŸ`^A‚ߢL“é¾§¥êþÐ*&µO]Aø÷ã�!ÆgÿÚ˜5“Ÿ:ÅÇ“}RBBÐUÚ÷ª¸A¥/Í=oJ.÷g3uœi8Ãà20š1ëg«T!†f~x3VÏ©)’Œ„ù¦ ¿Õ«|Ìü]érzß:(Á¶éPtÞ/AÆÍ ýö ½/‡uQ;½Z2}0�b(4ZúãïˆRÇ'º-&«E\d/æ�üIÇ�ÈÕa‡rl…æè^yz¢Åt?£[Ê‘vÑÆx]¸!ü%$¸%N™G©lâ|8»Íéñv)Rä5Æ*ó‚¹ ume—ˆ\<^ÌTs¯œ­Fªá <g1[¯›zßS„„:×}u§Á$B®âÍàS×;Dò€vV×yùýÌ�’y;T¼‚1E4O*©ð‡EÐ7i£G�[²$,>]Ð2„ƒÚé�ÿÉx­"㢾=“ {H×&<ÙÌ$[[ðð ;;š„Ä5µ«<-êh”P+Ѐe–@.ìôžZ<»|p×hIz¹PZ�DRzÕÛ‡¼çÂMÓz ûvÌžŒõs0 ¿,ئÅÒB¥÷:¼.hWEëq74C¯Ã÷öMúx’²H�çåPDLî|^üîÛáBFa‰kˆ:£OµÏ©k­¸\þîî³V»6;½0ç—ŒAþu·ý†ü¥Ì€%¼3Œ‡`Ô³é>îÆk5jT=®† À÷NVK¥ÐÌzΓ #+ÿºí@©ƒo2IÆtO? l$ ƒkŒqÍ5kFƒHÖP'Ë–Øró~ÑþŠa©¬âçG4LËùƒ7ýtaB¥Ó´R$Š"T+b´g wÈøæá—]éY=’¾;‡S)Gi®s7eŽmgFÍKµ¨ác†¿‘Ýa¡ðSžÍ|^y Hà±#`¿Òaã¯ø"Ú…¢`RòFMí¬ÛJ�^Ú¹^ÜuúAÊÞêÅm‰99žç/>b;õÇøH�Æ�Á¯£7ÅÅjw³aQó-° eÏšTU~øªâÒž¡¾U†!Ûj²ò.%ÿÕfsu –¤ì¦ŸÅÝ_«ÊN*j-@{,ÁÙÔÇë-ƒœ¯Â|)LÑ©ÑÀܵK Æÿýƒm¬êŒwuò�ú%JƒôÖ9Ù/XáC'1QÕ§8ÄR}su”©½¿ÿ'l±Sd»wvÈ*Åž3˜”j½‹Ý‡Ý ΋OuqaàaÂñâpû‹sAè²DÅù“�3–À \½Û\‘Ÿ…Ìô+úËL� Øý»CÀf·»­Ÿ&(Ç8ùZÿº ¯`’+‚èD×øèâ»ø2s†{Éݨ±«Œ¸>Z]€tÃ|E%Lԙܽk<õ‚äºxÓlÁIÕèQë¾z,´•È0]Ü/ŸEôNÄ<Ç1 òÒÜæÚéJ·–ê\½r]4\>}å¹V~yé�PP¤PðéùJ 8áÍ"F½†VRµ¹VÕïé]•à nÉ—–(ϲPR±!êgb¢ßa^E¦&8Ûl®\¼lÊ ÂdåÍÐTÇYîsV‡Ç¨¥¤"˜"2š [v,ÈÞX�”±”x—+ðîsK™£`‡­øš�cî%«9îˆ>gw?®ÀQ þüxoóM-ä8�šI k‘4Ÿ§Ezüà -3kŒ�ÆÔú�ÿÑ|G\F�sءܯÉ�¶ä'�oš é•-6É7ìND‚¶½þ/à~Cw”ýReÞXã„QFGè…®½b��K¤%ÛÂÝ®A‘rÉã\.(ù�¡·¨ O5'±7žÂ2(¹œ—èhò¥BÚ+rI]¨6ÂÓ�˜‹T‹K야©K_qØjŸùòH[?*Ä'y-È©ìªM8*‚ç'±Ël¤ÓÑר�ß›ØYºÐdéb¤Ñ¯‰1»-µ ð’Oëa—dDåË +®m·Û  mÂüPÕgÿ�»+ÄÅQý§Ù…ÐSZÒƒ·7˜"¯Ý�sY=súÀâ{ê›=Nb·—5“N|y³Žÿ;À—ï�™…¬ÍJ+‰÷R¶<X.Ô×Í*Ë EË6¬ áÖïD–;dæ\<Yºõ´^Úõ­b’ôß*‰GâPßÕ.Ú¬�ÅåÐ]‘Ì`>O À¿kÆqkIm ߸‰’¹‚ÜÌ´ˆH«Åù„Úê{-c ‚‡ˆƒçAå|:%T§.§ØŠ^—GÌìR$¦RƒÀe÷åÑäª>xg‡ÏXÂ÷G1h-â`¨cºu'Ù/®ˆÎf)Å a("èùéõú3%“ÊBZ ±ô•^ÑVm±ÆÌð‡îT“ÆSÔW|E•Üœ¯h mG;ì‚h­—¬kÎúNñŽI‹`Üßy3ƒ ^óæÛȈ¹ Æ×»V˜¼Qqþd¯Wiìi—“ À(§z!¤¢]©*ãÓ- /¬—  ññ àby¥ú/ã`ô{ÂñzÂ_e’çWa‡9ÜþtÄ¥îéÉ”Ê|ݰSáÖ/°—M)Í Lmtýe Y€ßЋ¬KL¥ ÏìAR�‡FÙ À Ø×]$¶‰ÂJËjWÜ à¸¨¸¿¼g× æõ�{“Ž6Éõ­~Rc½¼<u�3­cT^êO^LÞµ” üNX­½¥Æíeì.üü �±›&Ãé¶×tvO=þó¬HÀ¹»O‚FœCÈ9ߟU(´Ÿê"*¼3Ä#Ÿ�j™–¶x¿¬ĨØM^-JlÐmïKÕEY´ç ¯xíU˜Xž=QÖ=.q—º¨½ ;†ÀW;Ý€TÙhÐù§·P¼bÿ ETÁ4}#V:~)$üÕ¯f~Hî‹INÎÓL]fîÔÌÈþS:!UU™¯¿+µÎ®éÝGlåZV#æË¢›""fûè"íáŸ,â’ïnEñ‡Šéƒ/ê·Þ? …ùÇã²üÛr WÞÑ4‘;{¾“ûˆ5Q×lL;uª—‚ëîÀV«wøâÌEm'ðuN—|Âã#YÍ„xÀè�°Ô• �QºÒRÛÙ,ÙÕc—ž˜�Ž w0щò–Ô�W×í¥#š‡"²:™¦ >DwqLû¸æ#[ZÆ!u3ž3”hŒÒPɶ»]…èÀU6ÚÈA™þÛÄ?s;T0ü÷Ÿ£8©Èëm…dž¡'oʤq"ÏcèE¡σïÐ]sôaù·t"E� #{ïkjâбãâ(� ÈÈ+ê4ÉF´.Vx%ö=XÛST—†5Þè Ipc3ëG€ßyk³0V™R«³ñ.Ÿ9¯ìüPN伃ØQž¦/‘÷ù©èÀ€f¸dûbi—y+»mçL®‰k�‰Ñï“ü°bñ‹qœ@ÿˆrÂb:P‘ˆ ÛKDkIÞékû/±,73neŸË²FU')ý±�.‚¯§=Õ´—{pre ¤E„áDK³tv#ÿ(È9ÉW ›³�%Ö&nø‚ô·í¿å- CÐ4Öªú…þv‘ÅÚH–"X|ÓR.Ñcpµ¾|²ÔÛà�|»àgä‚Lë8…Jâܾ�{Dºœ¡åJóŒút\)jÒç4i®ìÑH�ÆŒ«Å7’6?¸ä:'jcí&­Æ´Žª§êÜÛœgáv””o_ íËqNèÁPD—‹¶R(޽"”6ê¶á�§QÂ%ZXU Œ¶1Ê›ÝSâkê=�ƒwÂî�9žWéD¾†,ØŠÝáÄû‰G‹¸_cÛê!6å,Ó“d¥°’((t�§Ï~õa}7 )¯'ØeQ5W|ÜtÕö„˜/"¨Ë·*Ñ0‚;Sb âMBö7‰‹örˆ×YMÅ\"Lãqn,4“+5€Î\&�_pùMê—ßËÓžv!çÿHáµË1n�¡úäÿ-÷ºm1úä¼f¥ÉýÞ¤,žaÞn8c"R1ºß¯2Ðçb SÚ¦5Šè¡�­*þ˜¨ÆÍm²ºeBq„å×ìHäP½ï"ÂÞ>I_*¥,¹Q±?‚¸~ÎQoÿtl&(ï¦Í½…ˆLªáœÄ:39¹l–âÍLâB/Ni×{­|B–J¾öä9p I›/?h]^z±N©Ë>mÈ¿« âÕ©¡ó'&ZZn<` ëÛAó¡PÂüÆ/$À3åV´<ÜѨ$2êç_ˆx91!8éÙŸ‚I%UYK¤œKMdh‡*j[2ôjð´~> VZVURã<Æ\SùµÍ[¤_ɲø¾Æ‚+h0‰A”2ðO(�­¶ œ|w*@,>û�IyIåÊx˜ÖùøÏ„’ͶbwÞ=°¶ò&c„ØY QÏ«'¿Ìð`³ì U…Ì‹ Ú�‰N—[c§;—C qôñ ÁîGÛVºô_ÔI:…�—öÚ¾úÒB{X"È‘¢ ôÊ{D%òGwËËŽëdÛôÂc©ô2æÜ§Oðí”UʹCkÓ‹""U—¿™ÌŽï@ž'¥¶­–�QX˜ úÙž@ìÃð5¢£Žn §Ñ €Å§c˜8ŒïL ~©|'ÒÃ/ù÷}Iä«gïÚiR¶3ÂIhú&²Ž¤3ŽMp8.E—m7d„¡ú2~6+·7ÝÉ3>yE„Ø×I;ò{¹½èõR öŠ#Ã�Ù|÷ð?9uþ5YžZ´Ïu®I3³‚¸ÙåÖÀEêÀðûv¬¦Ø[;­I2?£³é–*Ö#�JØ«¡I?vCè½U0³;®»s‘©<êÛ. V(­»ƒÇº:Ó\*“Ò(oQ¼ýl×ßËúQ‡Q(Ày^Ôt�‰?/÷w³â�Ú 9‡`t°ÕݺrfOLN«#¡mŠ3½ªÑ˜£©}‡½–�ø&n^÷°.�ÇÙô˜)‹¤†¤ UÅG4„×z(P´÷ž×C•ùbç:­mÉe]”fVÁxþ;W(@¬Ò¯©Ínˆâ1×·÷yÆTdäØól!S`®9��“ï+Ty£ÊI)¯¦.¿ò-ÊÙF÷ÒF¤—fða+xhj®ÚdÄŠ˜¤EX¹þY»ÉKL,qLè�ýªrñª—9» d»JʧfÝ·x°îBLIy=’šÅÕ“˜K‡#úp(µ´™ætI<÷$õ;ƒ-eTpÖw‚C–U„Ñ‚¹6ªšœî¹NŽÊ{ƒâþÁËl�PØ\ãMFËÖ*C¼ä�uäôÀŸŸveÁïBéàuOp2IÑð °ŠûSØaŽ6™&ÀÕÀbœ�rn8`¤ 휟5nS�D]Þ 0˜éËC[Þ_è‘Üj†)_û…Á›·†”T³ø¨&E(§+úÁ¯Å>šQ6b&[ÈXoÓª—\t±†û‚¦}§�þ#º§ÐðMÊ”+¹òÃÂ…øÏ�œç÷²ef\B”‹ý cFmpF6n£,ȵ<wAU‚Å!C¨5/'±ëŸ½vÁV_¨D›rÅÜC„ùJ`ÉV‰J7ÔÚíÚ¨É ª9emx8/+SíïÔf†ðR"Í!<ÁŪY#ä-) L¾$ÜJ+ü&þü†þ� ÆÉZjÕŒ‘ò2BúLÜkÃ*àµh p%lEE¯ÛàZÿ�XùôÄXÏ%Yª1 ÛD‰Vó¤�âÃs3œù ô+Ъ­ø ÓeW©'ËÈ=¹‰da•€^XqöYó  ÕÍl.VfÅl�8«¤ C&†hœðh‡ä1«"¾�â¿ïÎ󈄋ºø#ÖÆ·íÑÅΠy(WÉ ‰y0ý™1MÇ™�J±Ó¢èó {S�K×Mml,©›xnnz2!}o5qhðn–hàä§u¹°" yQ×¼oaòKñÁ¾v†P.y–ßmd†cÞÎàÜq¢Qˆ0�YUOSÑ<£Ø¢m p.°/8$y#‚Wfù`üC¿bE‰®T¼çå.”w¡på`=¶uC}åÿÜ}¾æøì#Á’’M!c»5yó€Söbâ‰õ5)qO‡$px¹ö×7 |H=…›ô3ž§‹‰ûÎïxƒaf?oè‹vK ¨ý2°T:©ä#Z]~$X=âêÓMÊ�E«÷äz=\2>u†>ƒZùþV[T6žÙÆß%¦R!J:„W@ZjnDv‚#ììÅšåH(‡¸98ÌÔ0‰öÆ|ˆû¾\|Þß"±Ó/<å?â)¼$Ondùÿ̸¢¤¶dk1‰'  î$ëYa‹mVy¨9NôŒ;µp네¢›æDLÌÝÙv ßxO/¯¸�-õ–}Á­å9‘n{e%ŃF¸eJ™§l)ÔzÉ Û¤ÈÒèÅ3`¹t– Qts 6¢€ç¾$v]ðdU^¥ü&Qö¾Iîqsêûëã!À@²¨Ž?Èr�žÅð(q³½¬¢™®@ëAüè—[]¿�õÖë¢KúŸ¬qÆdÑá®ñ7e{ê!1;Ùõuå,GÁí·âO©ûøå0ÆqÍÿz›ã…‰K äé‘<è¹sf3fƒ]í#‘7ÒÇ3&Ô2'Xç»Ș��ÈñJèÁߪ¢ª{”Ì©O@Ù\Ø…?²+Þ+p¯z¢PÈå@éu“ ¹«°Í¨I¤p�âw…u µZéZ¶3`Uü^ýƒ6:õÕÞ(ø±‡�ë$½HÿéBBº _Ûq@ ”~ÏXY4…–¯tºÓ}�ƒ¯/Åä“M×¥8i™®j4AI¶5ô÷Ù žNÆö5€G²“SM-M]Cà­­šÐá¢ÕòL.¨ò¢Ì1|v{äå A³ºTP¨8[òlRÑ$f�oYíL#¡Çízam‹v¨!x%ÊäËéõ€¦ UŽãá3ÅþÊ@÷üÏ1w�´ëκ 9ojXŠUeòˆ?’Âi•ï©�>Û:lH_¥_ã•Ãø$]Ågí�ìX ^ÖÉC섽Óh±_ÇOÈh]޶…vö]&±Ž3!ÞÑ=}w@zQ5«p�äÔídz•4õxdéV6šÇ,/ÙŠ‡5y‰kÚ�†æ– gg¹îë�Ö-Sq|ÞÎ…Í2bñÇl© |²#Í éïÕµ$�Z!ƒÂ†¡+qL»iqOÓïJã¹*ƒˆû<D°ð8‘Eþ‘(—O™Ç¹ù³¦ágû¤*@Œß³w­€¤ß_Ÿ„7œž+ ÛeË]+)©µVFs¢,½£»^EÖ øº73 9 ¯ÃáV1üßÓG2áIyVv³´à8¤#¯œ‚ŸÀV~—øØ¬™"„ÆQ›hDÊ8¾–jÇ̽Áöa¯Dùí—ÛÛqœi)Nüo0,Ûr¶×sqÎ.°ãGßs@] DCÂt£™EhY§À³D¤ÐŒ¬àTÒY’W ª@}ÛÆfÑÌ=n†ÜC"¦ÑV˜Z0dû&-šûB»$êÑ[íêLLpÚuÕXµI…Ü¢ën™Nú óMH¢“lšæC½öÇ<딿F¹"ul�îS¥ü?'€1ÏÓűú§A�ñ´ÝÒºïÕf²&†Ü=RÜè´S8eˆžd–°dSt,ª¼”ï9Ã5äø^=Äg^Ž_üÜÚ}²Ín"¶¯–&áYq¨ˆ“Ã&T¾¡åmà[Ž Å,Þ _y°ËÓ>6ç}¬âjÙ õ¦F� $1ÐH4Bå¸RФžŠ“m)�ë(£7lÈisE°üHðh=б�ãÿaµ'Œ›¤ñëé¶š.›Îc6ÉÊÈÃ�çho«±nÌÁ ÆÞ;â„‹Æ¥›:ÑÊ”›Zië‹×ç;/I9õ¯wýâo­¼@ã·éqùm,·¯‡80�—]Æ—GlΣ%¢">�)‘ùë&…«<Ò’'d½[í¤òèä�zã•`gdÙD*cöx\�n0£¸,eóÑáû¯/ž¦%ÝsÎìû¿ßTkr´O’ ¿~¤‚GÑgO¡´ÍL•"‘¬ˆ·b‹ÂtGî%Ú©z—;L15°$ƒEØÉ4R„QS>o¼w\¡Ãð†e‡]tÀá Ûé60…3¢É§¸U°,§£\Ò&Ï·A+±�ÏÈQ d[2—ÇÚÙ,½A2ˆÓ~‘&,èìÒ÷3(ãØPdpµ~ƒ¯+Ý›¾_FÓ.àævÛlûÙñÖbB’þ-KØ¡àvÏTý§í|B¨ÂTI[»71‰•Ú†ö 4Ù2f� Qê�xDã  ¾oÒØíaBV^WŒFZ0ZBQ°O;yZn� ¹›>" Ø›þ'pƒxþNÍnÓ´—+²ä¸n£ÕFæ>|‚¢³0ÆÇm)¶·¢úTBàxAw<P[*}²_^A¶@4Z]6 vÞ,öt@ñ…¼õqPz³Ôümx˜‚¥½�T’rÁÀ©2H¥ô ü‹û®Û*P»ïò1[­çë\¹Ï)-ܘžý¡23¿” 3ÓÿÈýcSJè[0­^y&>iUÔ´LjöÛ ¥˜êV‘¸S[*p©ÿ¢lPÖ]1ëàë¶5ƒusC]UDP}�Ëèº$«¶OãÕ¯†éÃfEÖ‰D$Ê+×k8Ö¹w€ìŸ‹Û¬¹M3Ò¢žÓ<Jˆ ÃœâTÆÄ3ˆò 8¦Ò¬È†-g ÿl6îŸÝWüaû}=Öš…Ùµ–2þ çª_eLgÊ™Óì«&*Ô@°·ƒ‰H Tß?¤%ÊÊ â ù;ÓüáQ´£&Í0�…ñ ‡ÚÌ!9R§ú>{²x¦ÁÌ=ºû#x\¨Þ§=Ê÷FóC‹ý4çÜ g7Û„ž_Ú–~p^JôeA›åhP§mÞ¦b|¿ £|`Mþ«ˆ+'ÞM5³ßÊÝWŠuôè¡ÈIøÚH~g UóƒÂÈE*:Ã%zûnÑ`Dbõîö¯eNãZéÝ”ìéœúnFú ïÛ [mv™?r5�LZZ;t¿E‘]x˹²³–¶ìÊÐãYͲ»â�_Š~>d3×¼eÒ“®ä\oUvØá^  v>¦KÑ�FŠ‘¿ÕÛ¨c‘Íék²GýIg¢žNÞGƒ=�s+p$?=Ý^±�vãÖ:îÓåj"/…³’“£Vg†¤X€€D𧋦á;À¢fíÏâd®IX:Æ‘_Üjɪ�ä®áOȨ‰â! u9¿qc’$`Ùò Gˆ¦!¢Ik×!‡±Ð¢Âß †TÄÛD¶ç©I µŸTƒF6”ÜA¹TkaQï�¼0²ŸQcj£î9�"¬óVþ4îîèÛ1ÊÝ-,”44ÀÏQø,R?jl»�Y×'­ü|¥é0�1�ªz¾%�_¥œÓ-aé@”°™ø™ªVl{Íõ ì¸`©ûNÝq¼“#¡È‰™hzd½KšBk`ÜWV•×…O¼t•Õè …VüÕÆŒõ·„DmõƒFoç :kÝÝù†">ð^Ì_œÁzRš”*5Œd YØø/LÔ=7™+ê‹<æò'ô€D»ÒNŽèI¯×,NÔ’coSÓ¨©]o ¥‡(DmвNš÷×1y¥fL]“åöhÕfžÄ…kœN�Â<Dleò–E#ÊD ª;[Þ%/‰º”–.•lt;-ef1`@ÓÇêoc²{šÄ²îW¤³¬bOêÆ74)ó~Zï_«E[¤éä=B;€ Ù÷Ÿn8]Õ!öU݆«à5?蔚üá<I@² ê£7ß²äJ„ç:æQ9Ï‚4 �W`4ó›hÙC}4!% ` GJY¥ú_zÝ¡º˜Yrô%·°Å¢ÙprÚÊgXRË @!&¿V²�4Kk�­êü^ë/O7Ò›áNñç­1N@`Z%&‡tÎ-]¬�Ör…²LJè�g,‚IÖ2B3�YŠ>öärGmšõ�¾¤Ø'ôËíYSÕ‚J³&<t¬ÿ˜ŽoÛ¿èå„;/1<C¨¨âÀ¼VoÉf4UN?ÅåAö/XüâÁM†ü‘Å�ý`KG?¬: &‚b#Æ=Ž+|˜™lßH¦Á ˜É´“µW.ÏÅ7šnÂå!ÞÉ·¬ÆJ(œ²Ã²ÇVLD –5Rb#9~›_8aHÓÅzÚ^Ty1mÃÇbŽÇØ3H/�¦žÁ!�~nÊœA„Ÿ[³”tüPÅÜ5öwçÐ.%" å) ÎÄ>ƒw‹:sZåàújô¥DdÞÛ3×áZ›~!Nòx™u‚È·PɆ�-¨Oe?�æfoxÖ+‹]vôÌ´’r ¥ä¢,�H¯™É§BÓ7,RRd|t±Â¸°ÛeÊ=û„úQÆ�§‚Ÿú.£äÐ ¨´€}ù*vÿ¼Î—Ú ¢üj Ç©Ç[·!brÐÙUö…/«PB2´WÃfè©"`;VšY3MѦ#¦ž²muP€ F-øQ®.KS“ù½¥�”SñÔR¢¬—4¬gÔ¢½/j$$’Ø’ŠÏ &ö˜ðXxãW¢VËÖº5|‘<¤rh½ö˜Æ-V²VÏÞá¨øUOx¯õ„p#±€ º' ÷}çOÿÃë”fék@"(ÈŠ¬â½f2 Nœ&®;·õŸ\‹=:m’§ŽÈí`«'«‘ç"æ�‡~¦ö ùcÏ)S’ +ª¾†²k­´dÒÁm³8(,£MÄjlÉeVCqÉ_©¤-Ÿûõ¢3f c~B·i‡s[ô³_%ö0>øÎbõî~L˜r•Y(t=cÜ –j…ÉŒ¯ÒÁ<¤¨Sľ*ø£îèhr×�FEN»ìoS ›§-‹ÿpv�+Ûùª´öùKž0ú~ÍRkõ²"°e¼ÄÇg€QKTc,jÊÓcÓŽC·™øX«÷ Õ\zÙÁšsSJks>¿›<úõf £ˆ õjg�DîòÞ@¦Øèâ ÑLAKè+Ρ™_|hæ5MY-e`ǃz½Ót¦A‚ (Eþ¸ŸCvé÷ñÐ8NuÏwl±d�ðÆÕakÿòé W4µ!k ÅT„+3ú1_ëÙ°ñ"t€›_þ—K”“µøzÁ„±�A4ãìH¾ÎxT;KÒéݱ#¤æMG qІ[M¬&ðìX§E~›®/8d5ßç>ŠÆ)û¤`õŸ]oú7w˜#ï-³ 3¨ýaìT%�’€¡ƒ](V‡©±YVÐ~Ÿ^zö»9þÉèWTŽfi/7΄W»ìØ«‚ÇVùt7øínJDúL�¼Q˸ �¹qI¶_÷P�¯”æƒa�R†Ô\»¯NC^‘ir©écTqlµØªÛ¤݈³wK\·A%‘« ¼§h—Í>uV?V{hW\äÈiµÔÐÜ‚t82\a\Ý…�n`âŹ=q׉”ö{…ÈÞ?Þø�(š¨\^‡ØÈlêóqt3Z”&Z‡L›B¦^"6b„Ë{—ÜàݧEÃ[Ýuð”L d]¶ zUÒꚌmEk¬‡öcµ}ÔX„Ú;cåu‡*#³À¦ìÉDiF·àŸÿJÒ¼D=‡k¶Îsä\…^F{5cã‰C*±Q‡Máªèê]G3}C½Î½»°G #­“ëPDSÎeÉ.ò”è|²š?DÓ÷J†¾iÇ*&èÕà P§ÁU³²V³Õrn1T—Èå³ÎtÂÊ$‘›J�ì™›†ðÂd Ðĺ)xj¡jzG](lItÄ~”z±.ð¨îkzŽY6øÜ À,"¿€,gæç_Eâ§©Ìì¥Ì®,œ|© 0MÕÊd ,銹(ÐvmfeÏóß0ú°ÄŠ=µ­Ä*m«æËbjhÃÝÔ…¸¼B�•�I�Ç*#°gˤnEÄP+÷¦/nØ iº fV#‘ ³* �Y«p �¬^…ä�Q ]�piü-ÌìYH¤nïGºƒ�ý®â¢`?¡¿ð¹“HäBe;/�¿æ¸\ÚëAçMÒΜ^²ff!+³‘p�NoÖ”F·¼bÇt|ßz±*2 ¥˜0n¸©rì¤lL…Õ�ÀJdQ °\ú–Eà \‰_YÅc= —µ‰ß=ÖÌ`™d�í’Y{5T¬94NÂcŒ›p¥�ücñŠ/<R .($7ƒàª8VV!Û¿VHÑD³¢<oë&^M ½I½f†côã¾V‘ægXþ¹‹/’�6G*‚[¹±ih>ë#"ÎTˆÃ`¢,Êç©ÄÅç}Åÿ¾ œOÞgØ×¹·øâœoÌUC¿ŒìQWbia¸ ˆ1 [ܶ+%J)öHY!ö7§­µ˜Av.ñV§)¢ .Yg-6`Ç ê‹¹YWñChê²<h$QR}MBõ”îHœMI�Û�FEžgf[Bψ#dj¼ú««Ù¯"›,P61^[ÜüBsÛD2¦ÛÁÁ„H¸�pfªÉ‘3Àד? ´êžªÑ”Þöa7€Èã?­}ãáfDQL!÷çØw(1‹Ó91êPE‰ ‡6$œ……ã�œ[']?-+¸{§¨Î¸ ‘ôžn¸¡kLò=”S.ªd›£QŠHƅįaÿi)Ts endstream endobj 184 0 obj <</Type/FontDescriptor/FontName/MZCEPE+NimbusRomNo9L-Regu-Slant_167/Flags 4/FontBBox[-168 -281 1000 924]/Ascent 678/CapHeight 651/Descent -216/ItalicAngle -9/StemV 85/XHeight 450/CharSet(/A/D/E/F/U/a/b/c/colon/d/e/eight/f/fi/five/four/g/h/hyphen/i/k/l/m/n/nine/numbersign/o/one/p/period/r/s/six/slash/t/three/two/u/v/w/x/y/z/zero)/FontFile 208 0 R>> endobj 209 0 obj <</Length1 1647/Length2 17228/Length3 0/Length 18093/Filter/FlateDecode>>stream xÚ¬·ctem·&œTl[;VŶmÛÙ±m«’J*¶mÛFÅvŶ�t=ïÛ§O�ó}ý§ûüØ{¬{⚸æ=×XäÄŠ*tB¦öÆ@q{;:&zFn€¼¥­±«³²½­¼=—,�2ÐÜUÊÅÈðWÇKN.â4r±´·5rr4€¦�Q  €™ÀÄÅÅK±wðt²4·pP©)kPÓÒ~ÿOÉ?&�cÏÿÐüõt¶4·Pü}pÚØ;Øí\þBü_;ª��� ÀÌÒQPÔ’’—�PIÈ«$€v@§¿E(ºÛXš�d-M€vÎ@j€™½Àæß€‰½�©å?¥9ÓÿÅrœ€&–Ý€&@‡Tß@'[Kgç¿Ï�Kg€¹“‘�Ë߸Ø,íLl\MÿIà¯ÜÌþ_ 98Ùÿµ°ý«û ¦hïìâlâdéàøUQTüßyºX¹üÛÙò¯`oö×ÒÔÞÄõŸ’þ¥û óWëbdiç pz¸üË0µtv°1òüû/˜ƒ“å¿Òpu¶´3ÿÏ ¾œ€æFN¦6@gç¿0±ÿéÎÖ øßª7rp°ñü—·ý¿¬þW–.Î@3zX&æ¿1M\þÆ6·´ƒeøg^¤ìÌìLŒÿ–›º:ü‡Î èô¯Qý33Ô“02µ·³ñ˜Í`äí]þ†Pýß±LÿßGòÅÿ-ÿ·ÐûÿFîåè»Äÿ¯÷ù¿B‹»ÚØÈÙþ€ïÀßEcdø»k�²€–��‘àŸ…ciòÿq5²µ´ñü?9ÿWk ࿳þŸ˜ÿUýïBvæ¢cb£gû·ØÒYÜÒhªhébb03²ùÛ¼ÉÕìL�N6–vÀ¿$ÿ«¿�ÿ‹NÕÂÒÄÚî6Øþ­Ú™þ×þòö¯ TÔ”d´¥iÿÛö_ÆŠ§ÂEÕÓøŸ‘4äìMÿ×á(aa{€7;€Ž™ƒñïeü{¹˜Y}ÿÂþ ˆé?ÏrF.N–�FzFF&ÀßÿÿøýçIï¿ÀˆÙ™Ø›þ3G*.Fv¦Gï þQ›¸:9ýeü_Ûàoåÿqþ×%�=€&°«Kö&<!V©i.µX9â:ý½L`á% ª…ùÕö=þ©Û\†ï5¡ô�SÜŸmž‹§ûÒ4£½˜6”=ÉÀË<|_Rê¾|”MŠÚƒ ý„´3�ŸÞW ²[àÚìŒê;JÊúÅï�S,NÐWOÔ¤nùèd�ˆ~&)õ¿0:‘APk NÏ(ŽŸ)ÇF†‡zn úöñh³Á�óaù%�'ºx:Ý7˜|B¼ºq¸Â¹#x£¥}¸’Ú‘¤Ú‹Ôyͽ0Pu”ÜOé §87¬Z42z] ß[ˆð‘ÂñCßÓ9|ÅkIcLÂn¯‘÷ûy�ñ“þÐJ«¥w¹i<4¬$#øˆ3P±¤ŸKyÜåji²Z´ðˆ¯Q)¯dÀ©< »*5ûã¢Ççe-»L çÍôDÕÔËô5Ù‰QÆ¿ÅCæ�maºKûÈ�¨NB³ Ø„�£zÅ弞�<ž; +W«˜1ðŸÖ­ç3WX­þ¼õz¯·à�ô›RFïFËC›óÕ”ªõ¹axjaj®Î5¾ë9ùÓ…]–½Æ>ZÅþí2!›—Fð-Iéþà\#&úººxy ç-V;s/[žÆ_üN�u*ÒÊo\Ñ€…Õ0½<§-[ŽoJ#—‚kñC ÁÏp´N²máɼ(ná(zT‘?¦N 6묖÷$Á˯%Ñ~n˜|¼Zì?cD)ù³^ � GPcô�,>0¸ÈìêÒ’Ë”•ö¯.e:îþ;)ÊdBì xL^vý!�ˆm�9�CÚŦcñ®û>JÐHÕ’¨)ÛÑÁ¾ê^hß{‡ezqü�Ï›ã"TO9w.Üo Tï¿Ë§ø¯¦Q›TVÞµ4£âÉ�ù}žõYSSEärËœQmÒ~…76ˆ¹”ѧyD´¶U�µ"=DM¸rdq=ù \Ðô?Ÿru;C¸¸Ë`j-o,À­ú„‘å52Ëî*tÏ*<×åYL:Žo¾k©&úD×�í™ëB'ýñ' ¢¶‚y0�¿áLs<-¿æ†U€pṏj¯8 1²®·a¹ÚÈ(Ó÷û#w*=›SL¡!ž™«le8ûÆÆjÖ’=*Sq‰ˆ áPB×oÝ]´ÃùvZË1^M3Ú÷ÌLýÆ^*0•/¦½o}èB™©[d”ɨkÚÛ´t gPÔ?pOk×\Ȱ¹ã‹qâèìTø_$³Þ@‘ÅUž ™(ßÿx{fÃÃq¡¡Ó¡£»¢c ¤8†¯Í=q,¿‘´ËlRm)ñžNLdÐ"‚=R;Ži4ðr(`OÜù%ܶ—U—Ÿ’í÷€Ÿú¬~éa3®Q£ŸÃs¯©HòN‘½†V~òÝA0$ïÁ#ËÄ…­îy4‰åuç»g'r˜“ÆC/£cZÌ�‰rú¤Ë�õJåÔ¡¤p%ÿÌ�9¾ZIÎ@òxfn]$½²Ÿ �ù�´Á˜KÐ Â=NïâÀÃêOÉËgM†u:Û×ê`¤d©6$LfäŒö­çË<jÆèl•;º5@6{\Ðá¹9Øêz£2ë``ðs1;�VDf&@1~üŠCâü Ÿ{³|_y7 ÍU¯§Xwsއý.lw]ìDl©[ŸO`Hfp[Ó_�IÈ 4²‚àÆá&Ì©›™ðÍ=‰‚þ3ì}áp¶Tu�Ô®Ïì+?*PžÏž�m÷ô–&HLv“G’²qéTŽ“­j¡±ÞÒÌ€¨·ÕÞž…î¨È î?ž»�-cX­À»Î­Ïx]ŸF_ømðCœÿqfrÞã ƒRãfzÎY—o\¤i½õ;›—Ôí©çÞÃ�ö�ìkP»Ýw{D»S�Áâ¾I'úŠëžÞol¦C!b}º ¬Šk¸¥b&fo£½Þ õ&µüžØN^µ$êIˆrE�›ÍæÔ•ꢕ‹h‡�ý{Ç,ÞwݾÆJÔ”Úþð!gš Unòfg½m9|„ÀŒ,eÓúE‹û#k1§ MfZç†Ú¸«•±eèÖ¢Ùµ],�†ãìõ¬ý�¦‚(ã~Ãmô†Æ0¯4x¢Co Q5÷ &)ű‡ë·¨(óñÎF”f(í›=t ¼ÄJ‰t!òiò_/ÍÄWjÜœf˹ií»lŠ?Î ¸Vî{’f˜¿ ëûL~šˆ®»@u 5TÈm·[ª4ð×J'9Vži­7¯Ñ}ã,ÓSöšr›b ²šrË”Œ�ÈwtQÎÔ¢Ä5º}uÏ?\� íþEú€&Fiã¤ãü¸KÛµ�¦Ø"Þc2:=zò4ˆ…¾ƒRwÍ:ƒäA oe™ÎM”ù¾M­3@_ù(w±éä5†ßCâðF)_¸òΰèòf°õ«4ì!{5ðâl³—}�¥œ¹Î¦«ŽAÄ 4¤2¹âú§ôKü–Ú!ËØqÕ踆ˆ®îÅƪúÀãiøý±j•ìI‡îöËt€è–ý;òkcì°!v§GÞ"’ôe&¬6/&~–Î>ÇFUYÊÒå�ögK¶ª×åþñ]ÂÄ„ëövÊklŠÔ@þUJyD^ D°ÁÒßË3uº`ÑñÃñ«ç0]pÛjBg­²Õþû÷ ¢ÒÅO¸¡Ä߈×okI–cÑt�D8‹·ª¹sA¶'õ0<õŸb¨%ã>Ø'´:¸'xñ ´èNéŒ!ÍÙZmoCç’$J'ò›Be,R»w�UËIáÐÖ¨N‚ïÚ[ÀŒ…ظ¨�XI³>v°z[Ëþ”œäv¨Æ)ûœ=ÎIQÍ-Ï`‰�à­­?ŸŸq?]$tVr'„�MîT9•GÈ20þ¢ºZ–½ö—”ĸÜÁÌL*Biÿ3Cmiè¨:/�>G¿�Â/g–¶B¢zã3; …©‚ Œ£¾Ö-”d¿WÎ>WFMõ)Þì…Ñ7÷äØ ¤ôû`¨ oLŒ�E)Û›>Ô‹�½.”Q(]àƒ’}¸ kº½�ê‚}Ë¡‹8–Uã¿ê˜&õ™Î8m�R)•„:Ø“‰LÐÓæGgåo™úËtùK®ñÝŽ@„%&®wr"ò«ÆbÍy XZ±b@æÀÇÜ…�sÁ1Yé®Ô:zýeYДèɨ³ µ¿Ù„iQšÞ¶�©Ÿýœ›¸Þöš¸ÅÌ'ºÃ_»¹]ÃÇ#Õµ,ÝšÿØ¿˜è­ (þ"ÆaBçÉ%ð…>ÃòîL¶Ìizë®ÜŠòMØÍq�VºÙ¬y«ïñ¢Ë³X$êJ“0ol±ÛV¹ú¼_í—Ø„¨rÙRU›ò[©cÙ‹„Ã[é<tÅW$Ýä0æ†Øò@“]È7âý­üKâéJ5›¡’�v”vööÏ-!~Œ!˜›S_DXdÔb¶¯*ÞDåÝŠÇ ýÑØõ~%_JÇ*á“è0Š<lµM54¥øÀ¾ý“kÏ­”gJ÷¨¨d¯:*ú�âô�븶‚ßÒoL£]:¡2ör@°PI•tf©©° ÑÆÞûí•<_öy¢‘ ͨXpaþÆ�[jªséw;{��Á[ɳgœj*-=ê­KÞßõ°[ ’ŠÏÑ%T`x\K¡à°ó9ò÷ØNy&iÄõΩÚÛy-\\ôU›­V{`[ã>¢Î„}V«½Ì”¢È x€ZjÆ'E@Ln�iL&–tYWf'3 W‡µ%œNw‰í-}¡´b�TŠåáƒú�ž·àG~í²eŽùk› ¢)ĈШÝ�fr—°—:ëëÎÚÙùÓYqÇzäšðiH%÷G#x#AÏ çœäD¶$׺nÈ_fŠà6Ò ¤'èÊQ[i=ƒ¢ÜM`Ù 5‹±ß£ÉŠ�rµÄ• Ì4ìqu~ÜHÓÀª8åäK öè{ ½Rë(�°Ö/–FÎâ�º0�c·0š”]¨ø¾ØyËVó ¥A†ÓF Uqs¨fc`ÿÖ=Zm¢Že+õCI[bHÒïé-"·©�^€*Œüs¥W0séìÒò÷�ÒFRúPˆ+%‹¡'L¯ˆ­Úy\"„Ž‹2_d¨•‚€ú¾\åøæ pt Ì´Ãuª´£Êûí7+v©*2«’hŒã=îö’¿…G`ð�Š��;�æ¶kQ Á¯+±‡éS<ý[|ì7ü~·¬æ®•õ€Ãƒn�°„o(:àXóÐMÝø 5 ”óW†BžS6}MÑ[H_Š hÓQ`Yo±ñ .´íîÏ/±í ³�°±âTÑ™,û �ê„íf™ˆ"²ÑD„µ'÷Ô'ëea9¥è¨„´zïîÌ»ïÅpé�~ë&ÚßJµÆÑå^õ¤[ÚÐyË×aß:“™Çác¸2m><‡Ûë7ÁëJ`|ãp*Ó»ÁJ¶´Q\1DŽªz¿ßŽp�‰_ X4)ø7K¶žBÊ?Šìޝcï)•û½~•!ôE;*[½\„R›³„Ÿ� �çÉåÍÜ)z,Õ#W±°`iÍ+8@ Áîj‘�¹×'œS¸öÞBz2ÚæGó)¶Ëôîœù¶°·9ì=óßí Xospa4& ?°Ë/ÁPÓÊð•¶Ýý~½Èüé®O¿ø°yÛ&ãj£í¦;il#·„2Ùé²¢w«"·�cá}¥Á-½bv¡b»õ<’>Õqi�à¿>4KC‚lvÌŽZ)ô5g“ºë ÇÛ¡3:Ò³–Μè3%aq€j– Â]t¹Â’L[öÚr¤˜öbNÂÝOw:3©´aè´Nåš®"ù•K' k™,C±éKÿR� j€þm× ÝEÖKÝ’ ¤6:Ý€Ï' ›÷åoë� *ÂsüÓ×¼…K"¼_ÒhÔE�I�§ã^mŽH4é#ØBÃçb†–i!}KµóÎ òc]Ñ xUëA^ œ¨nXŸ†(´�cŒÕûøÈ)}EÌÊ ìå­n»Øˆ�õ&Ç_Í>@•„Ou$øfä6j²&m�¡¦Öº�¤†¶â÷�Ç—7–-¡�5`',ÎÎöÏ&T$F¥†æU~n} 7—€~5òdžb6€ü�gø n5Æñ\—ý&í°Ìä÷’@,VïÌWI¤ûBêZ_N´gÇ^?'½6ÊÁ"˜ y¿ÅjÙÕO! b�t×µ"ÈÃU—ÄtÏž/£ð¥×›LO•$—þÁl•ø#]"+ÚSY^Ñ�E©¯Œ1K²}]¼c’º'Íá³­ �!T£QI47ÜÖ&j»‹²¼Vɸpó���ÝI.Ù´¿ß 4úúUÏ2\Æ¿×>:£ý†í�9ÐWqSu uÙ‘b¹Í¥Ú^‘{À4¦*2LOò-±’r wT{¸øù$öK3<7ˆ\üÅj¯Ý«u./÷ŠJî F�-!33mûñ5t–:Ûgy²Ô<r>6Tƒó½™n «(ÕXˆ�FÊ<·¤±IÒefÙ¹/²³öqTo×d<:ÇHfÔ3¢(ðÑQ 3ùÁe`ƒ»™\g3Fœ Šyèm[Œ,Ø.XéNø‹ä�¯gáUØ…Q�ÜÇÂkaa‘έÏÎ�£È™¼ÌçùjrVê¯Ò2¨ªæ]ÈLFäu¸%­¤›Æ�ï8TM¯ôkáý€ìI�Æ®÷Äý�)à¿€ÿT�æ�kî»ÛÕß$Ÿ€-Ù[¨‚'Ò}%í£#›.ý “\¢ -ÂK#âhvqä™JXvttOdÎ;D“­´bl±<?ûË:—”È.au¢S�QÝ)ð.Ð;€P#¿®l/k$ù‹e~`t xëÆ>Ïï*eg‘^˜#Ðå_Iv¢ŸO]»Nªð‚©�,UXïOÜô—yŒ•®åwj\”L2[ÌØmd&±£j,¼bÒÈmíÖâŒ�¼!4ǯڦÉ�W½Ch¨‰UxY0G.Ö¸K¥§ì*Qg‡!öÀ×E5Ÿ§þ®iIã)™øá�YDæä½ü8D2�/7Ñ Òá$t!Cd`är…¢ë±ÇÔu=ûkW{� �ö”í-þ¥ÔWÉ?lnö3ƒ©ó:ÌW�·MoÛûÇúScs·%æÚî’Ì…é׿ppfAùÔ8Í›Ow¹RúÞïƒQŠå²÷:ÌÄæDÅÈB3öïƒÓ~Ñ…‘;H8âÂÎç•V6µ, Vùè¶®R¾ž³†ãMºw]bÆò“òÇo"U>gå„‘c`o„ Ùq>ò‰Ê´—~‹Y2 Æ)7ú~vÞÙÂî• ËšÌ[Øf΋y�‡Uî¹9¬šmlH/Éz¥>Ÿ X]B­†MeC¸×ÝÕøWŒ+Ó¿f·}<˜S"x¼áÌm†¯¥E[WŒ@J�pö½óôŠ<s;ÔÙ7ÊÝY,ñ³R¯JU½[ –[Çë©ð„¦áGÎØ#kdkÂÉ%´W¾ì£Œ z6¶†€ÓšUF0×êZ�Í„%"+ù[G¬§t‡Ï“Âäg‰ "–äK-k*´¯G‚WŽYø•ë ³º} ? l¡Á¡G4ÛBÛ½ÚìÒ=±�{Z .¢þ!Ñjî¨ï“íÆÏmäG®Éá;>€ôÙÑcØÀ|T vJVo±©�jmëjöèUÚê”Ì®?cf:=£"éÙ1œ5Û „0‰Tsü®„ $²ÅOv3�U.†Ü�w‹“ù ²~íÊs)#ß(¶’‰ë0›ú´Õ¹3�,½ô: “¯†í±#6{mÿÏú£êŽ'>##�ÿöí �7�a>Á˜Þ¥ÞW¼�NO*ÓÇ 2Æ Ê 3¼§2âÅ~ìÛô””ߨ‚ÌúiP¡šxªY/²Þb‡"¯�üRŒ6—KÔ©qöž«3õx^ Ò¼v“9a"ÉrWÌ ¶ô½ Sº>¢¾Ž–o•¥+—­”QØäêöõâùú`4¥^`¤~íë¤?S.Ú¹¢@+Yz{ylßx‰;¼®ü0í÷ò'Š’éÃÙuv7K¿¸¼áƒ„ó›nL©žažõoƒ"k˜ÚDä] & kjõž!|1-‚¬éã)1,»õE¼ZLnpgœ™þÉ+×.�XG¸…U6Þbq\tv-W³9b”h+N7 ÿÆ' z†­�xø·âà…ât´kŸ‰äCtÓ:Êšb P‚ETÎb$Ÿhü›xΚAFïlq+yƒ Êæ~°ª(�¥�a–Î2ø5+I]?5‰h‹Õöä³Óø–,½Þ÷4mŸ«yG˜ñ¥ô§—^¶A=îÁ�Ù1¹©„»j\ä™(ðÜ·÷�ÇQEmEäxcŸÜÉEÀnŽ{Ýì<ð÷/�Sƒuœ©_äøøC'f¿ˆRRÞZZRùŒ•ÝMKq¯Í›[¥³#¥–4·Ðµg®hý`ÿÈ ÌÃî´‹ã,ÏÐ`Ç•£ÖîÓ]=PŽÕYïÐ^ Ð,ƒu  �@($¥3'ûIXW‡WÝÎ`ݺN Ñ�é)ØE'y�oÚ1—«úv¼oYùbÄHHxZ´åbDÑáxí^{(Î+£I… +õ/2u×ô;@m± âרca£�‘­<…±é6zê›Ñf¿ qÃ"&iž8|ñfk%ÌÁh½˜u˜€)àï”Ô<DŒ‰5 ˜2z¬1"|,¼·Þ­Iä®±óEý�üÊôèÛcŠâè6ïC6"š÷¼¿Vøõô~'ñ4bå Y[ LÆû±oði(´> � éèf³î­uç\eå…l±€–@š³j08H�…è,ž¯-u…H Žgm·¯A�Ÿ[Πֆ7§Æâÿ–?ûÕÓg`õñ …3J;*{ò½ù¥Ù#MîzÕ,Xθßu ÊŸ1ƒ0åa/}e¶vÈò!3¨;fƒÎ9ËT[G¸!·‘v�í¸ÊÃ'Éåû UÊ�ÅúL©¡¬äÔ‰V¹âÑj¦¡RÀò«»Ä�sÉ -8ü sËnù>èñ§Ÿ¦­ºë©\“Éæ…¡ËÁ¢¼fÕŸƒt‹ò'1ë×¼Í25}X¿eÎÑ/Ó€�ÑfjŠ#”Œ�æ6=O0R¾Á±½�Úh$9˜*Dš¬’ê�{zK"tañè÷e%=pÃ'–*¨Â=r8ÍÌmÛJIÔh·QA ao¨�ÇòW™•We�rýªp¦ÁÏœ�Ü�žåmÜK@^/]¥ÿïò¦Œ=,Ýùï"û+Ùi“± ¨MÊ)ï¼e'£Š[æ}‘ó?}&AŠH.Ç\ÈÓŸ¡Qlì{BÔ¿N/ô†eI~ñ^й¼ö± ä·fèþ*f®¹Þ°}ûl/Š4aÀ»ðg~¹¢’ /–rhÀXßeŽâvÈÂ÷.��vuƒ㔃z—é;'ÃcißQ¾Ì*ßíÌZ7ýÑ¿§� ñ¨p‡’K%>ÿ¡´¦†}Šr'E²¨M†øúvžäª\¿€ Û°%ŸI‹£©HŠy CüÜ<Œ:9ùäÔåæþt*›q'šR�™ ÃèS› 3-Š#,ó�f†öæi0h1ŸÙz·où2+ôž�»Ÿ†Ðú¥ªÄIR–@‡‡ŠÓ­¬môuA2gŒ Yp•1U—‡ ßà¨ÕöÄŒg °t±¤A–ILP¸7ÀJÜ bÃk+<A71ÇîtÝ1‡ÈdŽ­Ð#¨&¨‘L#´¬Ò­9:ÁuŒ”°3ãx„f áyºöœŒAvTäõ`à92iP×µr¹�ý†@/¶É vƒåkç'6¦ c‘S½JP~Swü~at;D¤ûtUb�ýîj i–Í:œ{ǨïqlœÑ1¿õ£ Öˆo ^˜ðR¶~æÁxÖâÀž Ã{kùút],`î)¢‰]fŸ†8m¤”÷ª|UM�B—~A>ĸ ¬€>×´¢Ô}.îz›åÓ•Tåµ6ÿ"eþVeÂæ;GUÇ™tþu¸²)ÈO™ÊI7Œ^žw9)³‘ŸT\_ô«ºµ8ÇŽß�ø âH …RB¾#ôdS¯æiF™Ž‚}Üu¼î¯ëœŒqÄϹ“RW�T§¬`Ïþ q#HòQ�„ž±–RùÍ®ëƒéÄl$¤Ñ¾&©+ƒøé,‚M¼±ü8`È?õ’ÄÐó7uÄ·,Íh.LF¯x2®l¯ÆE؃ƒ›aÊ×Ñ»:ÛåQÊX…ûWWÚCךt{)С~ ‡EùˆV!7œ¬9ÄÿQê[•hF¨__˜zˆhHÜÛæí)Â,sY{ËùT‚àµÅÝËÌWST¹)¾™ªtÓ ­ªYæ2%±¥‰'\Š-ÖeK¶cejq."9²ò¢û\Á|ý)ÇÓq@­²ªýÉc¾Î³äÎi1´ó³u�Ï�M??'èw¤Æ§sï´07¾…2±.Ž�F’»»y7øs �˜îÍ¡9Êf�™Ëë¼·æ¦n<œì¾jªÍ…ž/<f±`h ø9,¥Ån+?¤rÐÒÌB÷Lš’þÛ©ÀŠë\!�I{Guºƒ# J£�2®ꢈOs8eÑÌqåKuñ•‘Ðó'2äü|��‡Îwî=ËÉAA«ó±v/Œ[¡"¡•’@X”öÀ�0ŽÙñߦ“¡"^±s¶ñŒãtÓúh3ŸcŒà:¶�öŒjç›kÐL†ž€èrÞ4��|bœÚ ¸XRÈw½kò÷W*žã“†^A8f)ê'kî°&õf9ÎsÎhÌÏoH×x¨VFîçéVÍ,Ò�Ä/‚égÆŠ¶vÅ(å¼1õã°7‚ò%��Ï…©âû‚o'[õ?}XͲ@+Ôún�zN¢†<Ïg� Ò†·=©6an 4Ž·ž^ aÛ]7¥;¿û²Jt¼0r^‹óèQi”[tup�èëR€=êHâ�ýKÞ�Ñ›‚ìë®ý¿îôA°5"½X>œFƒùduæ]”pdN^-™BVvïé`­óÚ\Ыly¦^Ûðlèçg ’¾º†ð�kš!ê95à†~¿Ö ËÝ'á‘Ó/™y’¬5Ï.7¾)]ʇttXÌYHº�Œë�Ž÷F.#$âSZ¬@±ì›ãÇxåäå®,DÊhj±ªHcÈÓ‚s÷—Õ?|&Ù(·�N|ŽBý„^ʇ‰Í[ ‡Zª&·ÏsˆÑfþ¥a|a¬² ¥äfØTtcYq´*.%ñãêc;Ԍʯu ÿ)sm·y.N¨:�ã‹�ZÍ9^ w˜ÑÜ^Ô\RªY ]†”'‰^à—»±#/Œña4¤]·´þôÀÞšÇlàë¾=%,A¥x × g5ey¯\óÓyêÑä}¹±ƒ^¨‚Þ|÷îEãã„ ÿe‚‚žsÏPGFW.áá»N�Ù…C:<¹çùÛtË‘!Ô˜"�‚¾ùòwkÐUÌ‚uæµü¨Øv`Å—�’½¶fmV M“ûÇ û‹ýû#e7[Å0»—Ò«¨³É‚^l±�‚HÉ´VÚA‹˜çbÆg™ŽÓÞ/ybzì…ª²¦•;�8ž„å�’¤�t¤Ÿc&ÚÁ¤e–ɫޕL?a…rÉ™J/áž?Yõ–Ëñ€®Ï^ªrx÷š½÷Ïì¾çœÁlvI�›XŠ·…±‡ød|Of^o3ŒºC1L´ñªçÇéÞd`Tª _x$ÁÆþìC ÷´V'"9ÎûždùRØ¥çÛ›à›–A™ü@’ø„8PJ~{g>Ä×U‘ìŸlã9:é`˜²µÂ˜ë,..3‡4âòýp _l�¯_‰ì%×ÛË04#ß·ÓóX´"aÍοAëbݺC]Çßâ(ÌHÝFÝ÷/ó M8÷�=Z$àR!«P%yÚÜé|Û‹zknÕ'u™M@q£d€-SæOd)$úM:ÆVASÅH¨}>ÞÉ«®]æÉ�2Ÿ`WG°Q­u~ûî4#ËÅ$�YjÈM�p½VÛ®ÝëDGÎ�1u5˜ÄöJÕ¤ƒ§MÜUÿªJÜüG˜›ð––6x0Èä9üƒ¥%±6!S¸±(‘Uj[œô 7¸Ö^ûÑZ’�ºž3þî+ëÓÆ Â‚-AúÓx½#aek0&ÈÕ?jòv “hœ~oÎQŒü™ãþÚ°)ò–ùÈXY5÷ìë¥rV\vÎ=n›f–M[,=žC:ãn$Z÷ûu%E4Hƒöh²h§êºÖË$(‘’ÁT�£#Ó½|pnHØ‘g^{Ê0³±ƒ%N“ïÂzÀW�– ³ÒY½^–¬šÔ}ƒǫ́pÎ^<o xUUV§z‹]hKs‘ƒÚ·}Ùi—ëcœ–ë@ôjDõ‚y䥤È|ÖF…ûŒ»Ý>¬]ܽÂï~–k6g3Xžõ/>7�©W“—e™®•[NÆ(ÙŒgjÔ�'ˆ?4TA…ÚWÒjG‹ÕKÎ+}mÊÙ ” i”쎃{¥振n’vS7íê™�’ä9Y­Ëšœ]‹D^¯×‡é‚Ñ3ÀšÚ0ñuô‰ÔבÔ¼ikâ‚7ÌNꥲ?hü)PÂááNxÃÆUÌWß•JüüPôÔ„¨‡\ÅW¼p˜<*¹["ß]ìA¼Ë¼Ÿ) p kÅx $Ö(m1¥8¢`1%iy½“�[uÅyyÙ_;SS{áHU"LIR㊌G¨U0¯ Z(�$l ùN|Üú€èŸ#Ï5f–hc:hÉô6Y{ý(¥Ù˜tà9èK7AM½“XçŒ%•«:iÇW7i4ã R´F€fˆè)Žéx)²¸ðe#‘³Ø:„åëÞ›„-¥,$Ǫ¦yYÐý1þuîßC�¢y­ôJbžÚm$'óå[š�»¨¥œ¥LrqÓ¼µ+(¤PjÃÉ�Ÿ>À p?cþÛw§Äçªl´Ñ!<áQìö ÞŒGI.µÐÐfv­2Â" eZ¸§ÖÝD¦hÌ®�ÙÛBÂi,´�bÓM±>’Ù>*þ~Ä%ƒs§TªËÝÉÕKŸŒ>“àÓº/�*=¹”ì¸tb€ë…¿u‘P€“ËÆ‚zôO ©Ã…ïewü· †dßüôSÑÜ~¯0óW€¹Pƒ“ì’ì·È¤ye%¨7¥ËfáZ’0”w9—Cú!çaó„ÓKFuiü7âE[xùŸnÁ¬�»Ë2Ô‘ªž\‡;u7P§bîö­ÜáÝ‘×Ýf gÀÚ5Ñ�õÝZK÷SÈ¢€@Ùç;<N¢—ØùpÛ}Æ:|J¡É¥¶æHCS¡UR~ ˜�Zh•|äÈÜ$ì%¯ì”V‚f"i›ðz-¸DIŠ ÊZ[‚ŸÁº9"µY¸Í”p–«YÇdnÑ34œŠ�J9š\†?G�ŹªôZA]ý“ü”^iÔGØ÷?õ“d3a­‡¨BÕKVª·Ði9 ¥HÒ²âhì[g’bÄŽê·diöêoŸyâÆ»Ê…^*� Ôîè)'5»ªàÐ%X­i—a–ýÇÉB/ÜÈ1LymhÄ^f%³°½W¾YÙö”9WÅM~]»éj»+,yûƒ•íî u¯dl[Xû·ª<.�8õ‘µ ¨pRß!&q{l«ˆ[<±Ç±_ndtb“­ÌŸ¥/™J„DŽúð‚pŒ¾üÛ&G�ݨ¢mÂîY’u¨üÙ@åF6Îä6¿�¾C33˜£ÿHϼIVA¨Çæ¾˜ÉØüÞ�?A(¨®zNÃtˆh¦<Y‰õ&Çûò‚ù‚Á¥D鎸‹¨%Áê¥OUb9¦¥àºÄ¤´^œ)=´ÍH¥’ÀÉ,àlõR:C-¥^¯ÁO¥�û…žkªÄL"s8Ø·�E&`"Ç®ë�è9%òÅèÃbÅ9ºÃ®“š+´Þ0¯8×:ôÖF¥Žå÷º^­N7“dtO9‰[I†ã]÷õQ4¢üí6ÒpçÇ•¾Äv;ó²ÕƒµXu§5Ù±Èw­î¡ÛÈ?òe‡ß{‡áw%wˆÕY+ñÚ~ÐÐ-KÇ«ù½í0åË3A‰ §ŒKï"¬è8U§zý"TÐ�ºœçé{σê†"ׇò˜àªÜ×ešO\ðT®A¡ú>J TO´D˜ûlËm7p*› ÙÖ£›ñ1ÂðQt¥>èí'ÃPúò¤y«ªhKð20l† L]b|°Ñ/ØE†Õö¥’rjN€võ¤r¨ð%Ûõ׃S˜oÆI'õ!Ô6+úú¼ âbÏ;$–b"´6·m�r‚Cl<é ‡•½›’!â…&Rhäm@0Ö1aHÊo¥x› ³¥Tl| 7b–:_œò–Ým_l<!7ä@ÝŒöø‡¦ÓqÊ#»m:A�a¡pý›Ø¬2W~R`®'Ž5€ƒ5z?NÕ±x™>~Ñ+O±;ÁTöÅðJñ/ù’{4òü›„�×U x| Û¦­ÆŒ ¯ãßtí“.‚Ò¶õ731UŸd’ÄêQmÍÑûÏ> >§~~Ïû6OÜ0N?Çú´oŸŸ«Iß´µœ®F×ýHQTèþ�ý\¢ix| *¯}l5²ËVÀß`×nÅQ¾òÛO�ðÌ\/ŠgOÍÍ:pЛ[�3+!E«n—U°>9晆¹µÁ¿ë’`núÅÀžä:ífßc2cc~ªXÏûq„ø£kO:üÇu•ÆŸé�Z(gØs¨Òß|Ôìñµ+Iˆ^ãI"£ %2‡r'šÎ;�" Wì"ã #:Õ-¥¡]÷ކv�³póоµ!êtªÍn�T?Ô¥9-WÂ,GIø_èßÑä|#·½Òº¡¼‘ƒ«¼&æÙû-4_4êM{˜ÉÇ)¬AF]Fœr¸oǤð´Ã»æ©üAƒ�,ÿÂ�!^Š’™$çÉfÓ6B¨;…õ'”ÈÌ-+ž"ÞnýjÞ’–pÌãåÜ�x¿0•íTãQ÷q(ØÛx�i(™øNZñжÄ|'fJøZö�vÆ«éýÌ„¨?]{ϸ"¶|³£LQØf1ðä¬I i–ˆ–&<ºò`¡á×j*³88}×zcEdŠæ 0²IëŸ&ÐúaͪôÙ(¸ž·Ê_úv ˜1$êKЇïX¼zP:Qíh‹£q”}ðý<ÉÂÌèvØrªÛÖ Zþ)¨Ý«Ü:W`Ñ:A åiø1¨|É3VÚ�ã­š*Y:�v0âðfã6ÕÏðý§™2Q‰+±ŒG ÝTT›ö^_ܧ©¥O¡›pá{ò‚¢¶yŽõàKèœ�4¹Ú¹íúÛóË Kã°Ýâ­g¤ù¸ŽÆZÎÖBغ“XN‰dçÛ›Kj—ž;’x+à ·žâ~£7³SÍ"6ƒñ#ãÓ/—Ò/ËÞÆvó=&˜½ë•~be?&2”ȺLŸ¯Þþ2\“<.tx ­hâá…ãƒþ°–— ðÐQ0U1mÅœyÝ„øDè.ÿêƒ5f–:õ¿° +P nüá'°ÔPañ±ãwKM‹�6á�@õZ®£Ù B醪y¦«s¹…ÈYVæêŽ&"OpmeW.±š£}†è¥zp ,ý.‹k&(+ŸNó¸�p6’(â·ca•ãtI ÓczÌ¡ê¢Ê-ï5:bf§Ó›w¼JLº„æh³òžò˹+·�ÍÍ̶Á~4Ko[³vëïË|�Õ ÝF.JØÞM‘²‹M® ¡<þÊ*ø‚ŸÞâŽp�£æTò�ë2Á²ë÷<ÂxrŠ‹žÃ¦M…3ßÇ1ò*•ßÜSËaró3‹öf”tï^DD²ð†þ˜OM™c¦²€Ön05²f’Ÿ|p`¡6ùÆÂï%g”í™–I©vä`»µtèYû æ­J )VRfjز0—›@9ªáq 0±gÑ>~¥ÍgžòQ5“DžýàBÈj ‘ÑϽu)hv Œo6Zœ�¸ãÙ°síº^SnnÚã®H¿XÞ�×U<ư˜eí–_ù{¹«¸§ôD<ÍŽ}·þH%¢’‰‰�bhAXK+f};öÛ�Ýí™âSËí%Ö»ßk «c·jöšp¦�(ôkòÕiÓß·Ð}{Å~†8äé1~úò3I;w3µB™(­X©…ÊDĽ¡›ÍV8û£›ÛM±‰ñø4ñ>Õ$&°h’RœJÁ2B$¥&f‡&ãÛkbg<h('‹át. >Ò–òpF]ïÃ&6Û½wëN»xؼ^+\ûý3V$ÌÝ¥ä]G&Ò-[ZØ“C.R*¦mÌ‚Œ,­êDqrn`*ãÃ�ˆÄ¼Å1æUY:cý+S„n7ož™a©|äãúBäþÛMЏw¥#®ëno\¡RWð]Ä©Ùc7Ú´‰ä¦Š…?&êPÈÔ;“Qh\Z�Ï#3{”„S˜GÂâÁ)ÒÌÔùí;źIùÖ§&3ûOAŠù"ßÛZN½€óZßàEr! éÅQª8wG;k�øÜD@®ºA†ï("#˜îJš0Û¿?Rì;k�•IdV–?y9¬XLhÙ9{ÝEnȨn3¢ÿöÛ¥‹4m‡õU1–°™N‰èwö*³î%9�Ǧ@OæU˜/±>i°óõ…;Ë‚°¦1ˆž'V÷ò{U�¾Ã”óERÓVó´IÊÅ<CÙ˜2ãÇäµõçÛΙÒmÒ!$�áFŒ xݬY¿N¸Ïø3ò[’x×áJìº�²€s<£0ñ—ÿ8bb²û6D¬*~…`ªÒI@Ö�>Ü?°Å—ó´tû‰»~�ýâ©’è84x×�tÇ¡4;«¤eÚ8Ë=©¨Ä”|¸¾¾Ù;Rô"Ú,cˆŸ­©\,»ŽQg8°[�ŒDæìÇ+r*¦Á—Oô›U§ ¢/Göú¦âöâB«ùc¯¼²‹ðÏ/TÎo W°¡?¶�SKz›õrBxsjÅD�úàÓMªãÒžïГ"ÜØrgR>ÇTV¥7üÈN2‚5-Ô°¿Oµ´¤ Ç¥½ß‘K´ÐÉ0fëÙg0æ� óiÖÄùêh´jìÒªoÍÏ¡ÊVUžÿL´Öd‡-bÂ1Ô €ö9Þ|"|'“ª)$nÞd3®]šfç„Mñ´ ’0µÛ˜$¹ >uÎÍ�­%!î`)4àåôƒµŸ°¥뱎ßÔ3>le.ìY zî§ŽŸw”“{e†º —Ê%4g]3$ /W ÙÂpAúRÛáy T9Ôl\mÊ=cçed`5ÁQ~Ûþ臾/ë º×d”t¥ïTM 'eFÊÃSá½BxÝ11L¶I]Çâ<³Š#/4ÕlNs’öåì#ÔlNŒïRbh�£Á o„•úQ—Gè!HžU¼äÍe˜”¨yEt��`E°îO$p�O¬“•Q òÕÍv�`æe °Ï¬ÿ�߯ç3cwrg ©lÉnÂ]æñh?&lBk¤�ø[~o È•Ößo‘îïõð8šW„�K‰¬ãeýšþ«¤c˜¡ñú»Få¾}ëk‘ø˜~”+šLe¶TgFR¶!ºFZóÜÀ„Õ÷j¶oN ®aÌwy?;£h'üõÞðrCc’½‘-F‚_hn²õãÑy—8æ%÷º•2â�©²=7LgïnÍR{DT_ÊìF;Ýs9¯MîIÄÏ õN: bsbü¢ºáÆ¢” Îl¿Ñ‹:€Á8V0[žù¨‰0÷V¥°cì+&ºË›–b¿ä!¡í°Ú Ø‘•®7q•LÇp“Zþ\Ù«>c 4ùƒÉ¿�:Ö@MÆÕ3‚×åðïçÊènùY±žs¾Ã™µ=ú•®ÔJà⊼Òç�GÄD.C–òsè¢ï§ÃØ”ãRB¬•R®" „…Í;Y”F‡ ˆ¨½ K_ÁÂæJ�ß~ÛI~ã,ìV Íôb£–¼øËY5kŸøç÷Í}};¬‘_¦—¿_0Íi7t›û˜²ä õu�'A1whC;±¯Ö¥aÉ`… ÚEF>²ÝŸh»Eùˆ"}ª•{gžÜLpG[ýx˜±:K%üà›Óq.šT¤´ýÓâ�”�˽~œH%õ’úIÜhíLvxŸ.ßü Pïo>wß�´ŽB<�ïF Pªù#FEòþô é9 ;Óâäš6b4ÍŸÈ!3dšpLcât¢ É(‰ãSÛ#èl'9oÄ,¨Ë–�8H9!NC!>$û@¤{h³Á½OpéHòàÆ;nf-±ôÝPícŽ“ò¨6 �@ØQÈ‚vÉ@,¯ºØ~ÅZî¾b— ÝþŸ¡ÉbxþȸÞ!í,Ö$úºÈ,gF‰”j‡2slFðšúJ”²¬~?økNª¥6rá³²{ÓúõT!8C®"4—Ñþ@?)âùÖ|ÅOœ‚ÕƒkxK¶*¡²t†Öæz÷git…:6áG€êb�&X¤0ñ'>KO÷yMÎ|·õƒ¼^#æârŒú’¥ˆÕûÚâÔz˰=°GËs¤©çÞ3uU%Fó�%ÛkóïÛQ$^X,„°BYºgN›N�˧t~Q¼UÁšzÃ\TÙa"jæßAèEù½ý>TäЉ,ÊU¢0ýíËz¢ó ª; éL»…%nضk 3 Á—d�IIhžÇ·=u×0.ç�ñ~¯÷FáuP� ÐOØ1Îã^ËÞFœhQÁÊ:¦Ž•^)ºƒ¯ž§U ÌR×T±è(†é;~¤Ñód^ ¬bò2A‰…ž9㎅xʤ¾ªn\Zðô4·…t$Ûà4ËÁM׳FU÷h.üôˆ‡~¬^¬XqMîiã�ðǥù²Ó<èÆø‡sa�uyfå…ü'²¤’Þw˜�"ucX0ýfn«Ñ»½ûnãßnðÀϱPü„¦æ–®´Ó`MÙ?«"Œˆí:ªcÛ©�%d…ÅsÕ÷Qèj颶02 Ä ß.ôÑ=Ðm3†O¦éÄèÿÜЀÄÐŽG`ÜMH}/8æJIèeŽ�Õ,ÇL-Ò¬©Õô€a}£ÊCaöˆ±ÙMg¬³<~3ýŽ ª�$ÃiË!yëlã¨vÉûÐB{÷V°a0�!œÍ˜~%ÆaóÜâÊo¥Ñù™9õ,é–&§óQ¾ÿÄ}¤_G˜)e%P{T€“@T3�3ÞÝÂOErH5†›:gÀ›ŠrcÕ룊‚ÙMÉàüs’�rC˜rÔ…ÍÛ6ü÷exƒÇ|%0Çä*ðÌž¢æ�*üaª�) ´‰œÓ~®ËïDJTrAxãO\Tƒ"=Ÿ˜ßÝÖPÛ¨5½¢Ôˆæžq¯Âº,Ö1ˆ&¹nOp›™6ëyCÝòÕþ {¨æl嬠<îË7¬~IÚÁ­]]ª›Ïàd 5ˆL<—c§fÑ;ëá­œjBÜM»œ8‰Õé’÷-š<¡ ìÀl)ìdšÒð‘*õÈ•;mk"Mûµˆd ç/TLA$IwGWûŸhRç�‚�·“hxØä(‘KÎ.F²1{Íf·ôsªGy–Æí˜Œ>nšÊ­©É¥_€� –©™”çɇÌ;=\{ãrlÉMÏ5®Gù�|$¢ÒkišüÖ«©<D�…Jù1#Ò)ØW}GûÆFГ-þÞ› ä�Ô�Ú˜SGXvSÖ§œ"5&J‘ ð¤£WuéCFÿÀ¶H½XTW\ @;4‡tÄÃë˜Õ= °2 9´ßïž(þŽj€ÝŠû%¯¯�s­vØR± R¼È8¸qmXîjø, Â÷‰M¬rÇà$ªÝÔC˜rt?BDM£§MtBŒxåºrþÇ€Ð`2|LÅDšvq�-(ÜŠ[‘®“ kH{4&Úƒó&î›=½;½éSIüb·÷‡ƃŸ%Ã2Þ˜qPhÏ6ø¯íêqãp{�)¬Î¡éÄêÖÝ ¶ákYãA/J‡ðä]ÉÓ{tzŸ„ŒQÞk!í «NÊr$âWí蚦¼5tìɘ¾J\ i„pø«ÙÔD™VéæöÓg'd#¢’[|•=\Ø�“ô 1½ù˜ö˺äbTZ_["3¾ÏÕÅõ'TÒ<­ÚÎk¢„w6º9¸ ÓÌéYãƒm‘ÉO,s žv8L}ýÌŠ@EÙ�DV¼Õƒ�Q•ú8ìƒ ]ázÎŽT,·Ná‚$ÄõþèLú¥Óêsu4œ\ ÖñEJ¨Uï·—Nðë©ÝÅü½nôñ`›A¸?é‚bò°®—ÛÅ)¯Ænu!�}pR/÷ædÑܘjmÓ©N21Ç�¦àuÓ�_S!Pí{±äÚÕ¶"ö/Ò�>º�L�AÉFŽ<&Ñ1ž)jþ¦ºø%#õ:Wa>Á†·YÔnßS�\·t�Na½fJþ�×ûA‹ �,½]ñ‹:°¹?‡6 h¤ìKÆÒpÄêÆdÝJô¤)^‚(ó·T�UFÀ.s†¹7äI‡ú‘ð œ&oéÂŒgm™µòË4LhX‚F:Éaͦ.¡8®«²/nÐGRH�|.²‚P%Ï}âÇ@ûåÙ½§Öö ¿-žÞ¥dÆ&óš\Õ U1£¦|áÙ�~•8+e‰Æ—K ±ä?yË¿SÐ�ëFÆÿã™p åÊ— V¡Äª’íyR5iË8J%ÊF[|ͺklêúÚÓýå$‡è¼Í*+g$l j'ÈÈ×l¾¤çwÀÀι ¸‹óK?pA ¥‘°Dì9cº­Êç7QR�ùÇR?žõ¬4u6ÅAVÖ±õ|Žü]´I©<¤«]�`äø-®PA”dAv®ŸÉü¯mj4� è9 7§åvŸ“’‚•Íip�z‘ÑCû/DïœkžEÏ`}�\2øT®Ù1ãås¿\»bBç�ëd|˜kîÏ]’·ŽÂªo2œ½›îea×ØÏ»X,¯|$£Ï‘5H!©ï«#šî¾�%l$XTC¸pQÌ.¤û>'͈§NZeΚ€TT~k8Lâ–—†Þ õ愺’V’¢¬¨_cš<ÝRk„eg†-!eé)%^K};tô²DáìÁÇÖÔ$µ”âk~rÍåÃi¸0›cB*‚à åûéëe=yêÞ‰c+ƒAsÈ™þö9‹ZìqÑi¥l»#ÈlÜM®¨H�Þ¸°Ý_ÐöÔ ëæ(Gñ·97ÚxP®K½•Œ}™q±ü *‰WQz¾1 ­ŸBK„L$G”W±[¦Jm¯ /²ÉÕ§ßez™F`K™2œ±#$+X%¢­I³ŠÝÜN—ŸûÜöH›¼²L‹Þ³…è9&àÒùh‘ùÝ(jx7uÚ*aÊ(Ô\vˆ¸�s¸jY{ó]ïÀZ• .=ôe£ `.Z›Uýê/À{ב‹©µ§6(¿-<ÈFx·!ËçØ®NŽîèéáö¡,ò¿fb$âKOxy±ºBü¼÷(Éú3ÈB2ÙŽr×£r—‘! :V;ŠÑž¨ n4â‰1ÊÅW¹åÝ‹&ùÁm¹�æñ�ðü[«7µåI©{,‰ O ˉ[ö%±zˆÎ¥Ã\â� KðQ½2çÁ‰ö¢bÖ0ö~çC¾1 çbò–ÁÂvÀI"w^�&IŠñýîꃊåXà ?”F(gµ„½++|>G¶E2r“ìñpÅäšó`§ˆAR欞�°KxAÆrºÚAHŸôå×øÔ®½Š9Ù® |#ŸJëÉt‡Yœ z&C¦û(?-Œ¥R~Ñ@cßS±ãkŽ©3>ëÄwUù¥Èenõ¢($$šC7Éòdß³¬øø0‰ˆ>/b]I —ìezS±³¸ƒ[käø‰Ãæ0v«oU8òÔ� ½ž@í¨1a™‘Ú™ª\yüa#ªÇ\ÉLKWRñƒoÚÓ—…Óš(ÛÀ³{`%Ù÷»‹ã‹Å�d��Á �³&YÔ©²\�GHy*xGïœ~ +ØâR3Qï›úêšh½í_ióöƒNº5<˜Ê2ótˆþG�¡^ú-9äD˜g=ò¨d�³³l­íjØô õà„ÿ¸þ—�²zÝX“GNÔº'#¡—´Y�/xH¿ïDBô;ûA± µLà�èßéµÝ« yµÃtþíŠÆ‡¬ôЊ46^ñ m/r½�´*G\ n·Ñå×G‚½U|)òjú@Mì3†² vbg}|«0è–föÔŠnÎi¯"Ðfëd›èý¹ŽûÁ¢e†&�°çýM—”%Cýé $ÉUfFõEÏôé'jÕÎЊ7'ÿÏŠÓà˜âŸÛˆ;c>©_pDØ$±k 0ôå+Œ‚(¬×¹ÖŒE 6ÆJ}AW×°;ý’5Ukr…‚cç³¥0Wíb{W]¬z$.�ÌTs¿ܸ)ÕóèÖH¹ÔÓ�µ=�¨E�E¯ýc/ iM[»}àœ‘á¾’otÞzG�L]ûkU¯ækWÌžÚSW),@L!_DìÈ“3²½“äIJl’Ç|¼nýpà!Ì~W”¬á­ao…î6�=&üÂÞöoX’M`Û8å]éùn-È?Xyñ O‘Ê70(¥—$ 1�6ÚäÀW@XݦýÎm·`m¨µc˜Aƒ1"�øÎð5Íiu“Ô/éªD²Œá ËúÛi-ö�©�ƒÇ«ŸÜl6v­±ûPæP;~ά�ÏEÇ Œ¢óÅ“Kv¸É½­ß?1"±¥Žþ�\]‡ËÕa.dt~ª e]ÇV Ge*D=œ�Ô—¿Û‡,‘Ù�Üj]=‡ÉëH˜ŸÌ£­ag�IÆ­ÆØN„ªÈ‹Ëø0‡#.èNóP˜ŸÉ´ÉŒK¯ Ö½1nò–åÍ;,ê8*¥O½¯Þ¯ÙµüDïRwpc¤Ž¹#þ†[¶£ãÀ’pÕÝ]…Ìê¡XŽºíOÕr¾qtq^‰a­ù#èB‡ÍSÙÔ‹‰ƒ�ÿu¢¾‡Ñ’¹%ÔÁ›�hàøË¡9ÛjlUB©¢†(Û\RqtŒõªtíY»'E´Êáaøf‹Ž±•cš‰Äº¾N5åÈœD8N‰¦£G;›0£ëÆ€KyÈWÉoG¼Fv¶öñ”i7¥,|2³@ÏK”‚·('ùQ:k2¯oJ,%1, çøþOÐ ¡úlÕ‹:…„ânSí#ülW9•Ñ›·ÿ�Tž‰»µ —ާÉoÑÓëN .Û%•m“÷¥ ¦¸+¾R)~ôl^@'5ŽX"Ù¾Â•Š§¥#þ‡C oÈHlôÏÖ.'^Öd <.‹4…|È(`jí©~§I›ñ!cõöA¡/ SôèÊTË ¼P1'Óà ÄüË,Iè±,Ø}ªTºß«“œÚs¤!qr¾ µCcCH•u [¾ ™ðêÊ¥..6W9Ð5­.ŒœLÈC¸7·e¹ÉØ’¾�Ž�s[u Ï ~ÕT‡ðU¥�-÷ D-ÚWõ çá»à¸»Ù„:Û‘Ý€ê‘y¶£-!)_® $ê$N¡‘á«Ù‹Ž¼ÑkV`²âg”Ø(µî÷‰^ïª�Ò¼Ž°­�Ñ7¾ µþÎ-|]-üN^ð¢æºQÚóÖ™,uÅ^��ß‘ßä›7M9þœTÓû8‹ÅzÚ²/Ç`�ŒßQbj÷ø—w‡@¢ x¦V¯˜ìH"|‰‰�c‚:ì^ˆGwF­�ïz?ÜÔïØ–a¢šŽO¥nr”cçÌhâHöÄÕí§UaÚ°ùà¨{ÿ�`· ‡›qoi®ÃúZŒ�œ‚-Žˆî?Y óÄBvq€G{ ²6ã"Û³wÎ�î<pŠŸ(üNÚuF…^Æ…RäAs] ´9B‰®>ÂÉ”{¼6• P¯¹+uzT:á)¤oˆbI'TLj)¤¶úû ÿ—d&æ1ÀÓë]�Žn8BaÖ²¤› endstream endobj 49 0 obj <</Type/FontDescriptor/FontName/SUQKZJ+NimbusRomNo9L-ReguItal/Flags 4/FontBBox[-169 -270 1010 924]/Ascent 668/CapHeight 668/Descent -193/ItalicAngle -15/StemV 78/XHeight 441/CharSet(/A/B/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/Y/a/asterisk/b/c/colon/comma/d/e/eight/emdash/endash/exclam/f/fi/five/four/g/h/hyphen/i/k/l/m/n/nine/numbersign/o/one/p/parenleft/parenright/percent/period/plus/q/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/v/w/x/y/z/zero)/FontFile 209 0 R>> endobj 53 0 obj <</Type/Pages/Count 14/Kids[41 0 R 121 0 R 191 0 R]>> endobj 210 0 obj <</Type/Catalog/Pages 53 0 R>> 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 <</Size 211/Root 210 0 R/Info 4 0 R/ID [<38f81177f239849d69c477e8e6c3bb41><f5913c882f2b13eaa98bc56043cbd120>]>> %iText-5.5.9 startxref 453291 %%EOF 4 0 obj <</CreationDate(D:20170131183532-05'00')/Creator(TeX)/ModDate(D:20170217150125-08'00')/PTEX.Fullbanner(This is pdfTeX, Version 3.14159265-2.6-1.40.17 \(TeX Live 2016\) kpathsea version 6.2.2)/Producer(pdfTeX-1.40.17; modified using iText® 5.5.9 ©2000-2015 iText Group NV \(AGPL-version\))/Trapped/False>> endobj 41 0 obj <</Count 7/Kids[220 0 R 39 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R]/Parent 53 0 R/Type/Pages>> endobj 53 0 obj <</Count 15/Kids[41 0 R 121 0 R 191 0 R]/Type/Pages>> endobj 127 0 obj <</Ascent 688/CapHeight 676/CharSet(/A/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/q/r/s/seven/six/space/t/three/two/u/y/zero)/Descent -218/Flags 32/FontBBox[0 -218 775 688]/FontFile3 219 0 R/FontName/XTUCJG+Times-Roman/ItalicAngle 0/MissingWidth 500/StemV 116/Type/FontDescriptor/XHeight 461>> endobj 134 0 obj <</BaseFont/XTUCJG+Times-Roman/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 127 0 R/LastChar 121/Subtype/Type1/Type/Font/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 0 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 667 0 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]>> endobj 164 0 obj <</BaseFont/YAVGBP+Times-Roman/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 169 0 R/LastChar 121/Subtype/Type1/Type/Font/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 667 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 722 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]>> endobj 169 0 obj <</Ascent 688/CapHeight 676/CharSet(/A/C/D/E/F/G/H/I/K/L/M/N/O/P/R/S/T/U/W/X/Y/a/b/c/comma/d/e/eight/f/five/four/g/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/plus/q/r/s/seven/six/space/t/three/two/u/y/zero)/Descent -218/Flags 34/FontBBox[0 -218 863 688]/FontFile3 218 0 R/FontName/YAVGBP+Times-Roman/ItalicAngle 0/MissingWidth 500/StemV 111/Type/FontDescriptor/XHeight 461>> endobj 178 0 obj <</BaseFont/YAVGBP+Times-Roman/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 169 0 R/LastChar 121/Subtype/Type1/Type/Font/Widths[250 0 0 0 0 0 0 0 333 333 0 0 250 0 250 0 500 500 500 500 500 500 500 500 500 500 0 0 0 0 0 0 0 722 0 0 722 611 556 722 722 333 0 722 611 889 722 722 556 0 667 556 611 722 0 944 722 0 0 0 0 0 0 0 0 444 500 444 500 444 333 500 0 278 0 500 278 778 500 500 500 500 333 389 278 500 0 0 0 500]>> endobj 210 0 obj <</Metadata 217 0 R/Pages 53 0 R/Type/Catalog>> endobj 211 0 obj <</BaseFont/KGORFR+MyriadPro-Semibold/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 240 0 R/LastChar 150/Subtype/Type1/ToUnicode 241 0 R/Type/Font/Widths[207 0 0 0 0 0 0 0 301 301 0 0 236 0 236 0 536 536 536 0 0 536 0 536 0 0 0 0 0 0 0 0 0 636 0 588 0 515 509 0 0 264 0 0 0 827 676 704 559 0 0 519 525 666 0 0 594 0 0 0 0 0 0 0 0 508 585 449 581 516 319 573 572 256 0 0 257 0 572 564 585 0 356 417 351 569 0 0 0 500 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 236 0 0 313 500]>> endobj 212 0 obj <</BaseFont/KGORFR+MyriadPro-Regular/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 237 0 R/LastChar 83/Subtype/Type1/ToUnicode 238 0 R/Type/Font/Widths[212 0 0 0 0 0 0 0 0 0 0 0 0 307 0 0 0 513 513 513 0 0 513 513 513 513 0 0 0 0 0 0 0 0 542 0 0 0 0 0 0 239 0 0 0 0 658 0 0 0 0 493]>> endobj 213 0 obj <</BaseFont/KGORFR+MyriadPro-Bold/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 255 0 R/LastChar 121/Subtype/Type1/ToUnicode 256 0 R/Type/Font/Widths[202 0 0 0 0 0 0 0 0 0 0 0 0 322 0 0 0 0 0 0 0 0 0 0 0 0 260 0 0 0 0 0 0 0 0 0 0 534 527 0 0 0 0 0 0 0 690 0 581 0 0 540 548 682 0 0 0 0 0 0 0 0 0 0 0 528 0 451 0 528 341 0 0 274 0 0 275 860 586 577 598 0 380 434 367 0 0 0 0 523]>> endobj 214 0 obj <</BaseFont/KGORFR+MyriadPro-Semibold/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 240 0 R/LastChar 150/Subtype/Type1/ToUnicode 254 0 R/Type/Font/Widths[207 0 0 0 0 0 0 0 301 301 0 0 236 0 236 0 536 536 536 0 0 536 0 536 0 0 0 0 0 0 0 0 0 636 576 588 0 515 509 0 0 264 0 582 0 827 676 704 559 0 569 519 525 666 601 0 594 0 566 0 0 0 0 0 0 508 585 449 581 516 319 573 572 256 0 509 257 848 572 564 585 0 356 417 351 569 508 0 0 500 450 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 236 0 0 313 500]>> endobj 215 0 obj <</BaseFont/KGORFR+MyriadPro-SemiboldIt/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 251 0 R/LastChar 121/Subtype/Type1/ToUnicode 252 0 R/Type/Font/Widths[183 0 0 0 0 0 0 0 0 0 0 0 238 315 0 0 0 0 0 0 0 0 0 0 0 0 0 238 0 0 0 0 0 596 553 0 0 0 0 0 0 256 0 0 0 802 0 0 0 0 556 490 0 639 0 0 0 0 0 0 0 0 0 0 0 540 0 430 544 479 0 0 550 249 0 496 249 821 550 543 0 0 347 397 333 0 486 0 0 472]>> endobj 216 0 obj <</BaseFont/KGORFR+MyriadPro-Regular/Encoding/WinAnsiEncoding/FirstChar 32/FontDescriptor 237 0 R/LastChar 120/Subtype/Type1/ToUnicode 250 0 R/Type/Font/Widths[212 0 0 0 0 0 0 0 0 0 0 0 0 307 207 343 0 513 513 513 0 0 513 513 513 513 207 0 0 0 0 0 0 0 542 0 0 0 0 0 0 239 0 0 0 0 658 0 0 0 0 493 0 0 0 0 0 0 0 0 0 0 0 0 0 482 0 448 0 501 292 559 555 234 0 0 236 0 555 549 569 0 327 396 331 551 481 736 463]>> endobj 217 0 obj <</Length 3451/Subtype/XML/Type/Metadata>>stream <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c015 84.159810, 2016/09/10-02:41:30 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/" xmlns:pdf="http://ns.adobe.com/pdf/1.3/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"> <xmp:CreateDate>2017-01-31T18:35:32-05:00</xmp:CreateDate> <xmp:CreatorTool>TeX</xmp:CreatorTool> <xmp:ModifyDate>2017-02-17T15:01:25-08:00</xmp:ModifyDate> <xmp:MetadataDate>2017-02-17T15:01:25-08:00</xmp:MetadataDate> <pdfx:PTEX.Fullbanner>This is pdfTeX, Version 3.14159265-2.6-1.40.17 (TeX Live 2016) kpathsea version 6.2.2</pdfx:PTEX.Fullbanner> <pdf:Producer>pdfTeX-1.40.17; modified using iText® 5.5.9 ©2000-2015 iText Group NV (AGPL-version)</pdf:Producer> <pdf:Trapped>False</pdf:Trapped> <dc:format>application/pdf</dc:format> <xmpMM:DocumentID>uuid:c1b0e4b5-d14d-9342-9145-22c99ffba43d</xmpMM:DocumentID> <xmpMM:InstanceID>uuid:ecdfa650-f2c5-7b42-bb3d-654b62e4dfd4</xmpMM:InstanceID> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="w"?> endstream endobj 218 0 obj <</Filter/FlateDecode/Length 5836/Subtype/Type1C>>stream H‰d“iTYÇ«µà…XŽ]¥U±]Ðv_hAÛpAt$â‚Ø h {€PÑ€¨ " qA�ìÒ¶‚Š{‹Ú.�£¶Ž¶Ž­ã­ÌãÄsz¦?Ìyç¼óî{÷þî½ÿ÷ŽÙÛa8Žð Ó(£')´š ˆ>{„Èá&aýdõ F`Þ‡%aÉ ˆr¬>ÌË©ÏAï®Õ%D……ªbäãÖ(Ö�Ÿ0aâŸ;ÓÜÜÜäÁ ÿ=‘{(£ÃB#äcm‹8¥Z«Ó(#bæÈÝmÞjuØfy¨:A§Š–mÙ¢ÜÒ¶6H­ —/S‡étÚ8ù8÷ñòéS§N›d›\0 · ÌÇàØ stÀ¾Æ°Ñ$6‘ÀfH0W;l‰ya˜w?l†Í¶5‡Ùaæ�åauØ¿ðÁx^kç`g²k•¸IÊ%wìWØ× ‘Aô’)äKJG=¡‡Ð‡éß|Zú}ÛïxÿIýÛ8Hh70_JJ�Hÿ=hÕ öÁ΃·9*O;ÍsÒËÙ.Ù½!+†´0_1•CÕý,í�&EO­£Kð¦ 4Y]™…þšÈ�ïi�™*gäÀ"Yõø¿�á-þå±?„ç6çºöŒî}{k×ösÁ“ŠvÞÜ~¢ª£�þþ=’äÉt6�(¯n ï=?óXònÆG>¸)òȺS)IÃ~ö®P™ÐG—˜ïÌŽJvÕ­äµÞšPwZ:ÎToá�uKYp–AÚe Eº[ í-¤Ý2ÒVôö’¤ON0õ¬lÓS4’¹]Yí*{Au6@ÆËJÃËôU9¹™™9¼lSV®É”ÉåålO ׆¬ lÑ[mu:~`4Q‘êˆcQÇO–;~2²\#H�åV§rüè[(x+�\›¾A‰ªÁgµQ}jà•È¡q5XÝÝÆµÔ�©Ú.Õ� Yš #Ñ_øŒHæY="�)å..�_` ¨êAÒ#HM…âŃ÷l¹ÃlZ×ÙèhéTÂHåï=���Eç.ÊÞÏ•î3„ ½~ÔßÒb’RyCª1#h7m€ã…Ôw™Iû›Xñ%5u‰e�8¼ê‘ˆZÁ$ï%!É©J#á;ð ^¼>Ûõ�ý0»{”ïºØÍ!|x˜!<Ñ£tǰßÎU�ºË=kUÌšûýäYÓ´ù)"KI�Uâ««NÐñHÙ!» “à)s¥lWêQ¡=ö¬b1;KáµPŸ{4„?¬IÌMäb Æ8UmìOÝ�Ê-�B£¥¼í6Û’Ôq’�?¢Ï,¦e¿Üm<Vý#ûxùå)~�‰á¡¼FgˆŒýkáÎa÷-õ•×¹›õ�Þ¡†Ð¨(A£Ñ–DÓRÛµ;ßç–8AýÃyݲע’˜1¢O ‰n÷úËá4šCÉþÙ s>’hé ¥“�o ©±Zl}„ƒõ' ,f`=y(;+w�Pó"5—ˆ3lÛÇ!%‰p´�ؽ˴{»#;#ïÔ¹ôd TÈÅãØ +Ì�OÌ=¢áËÂcöÇqÆ”(ecôƒg-„†úÒÖ.¶Cßàw�¬S”¡~¥´ÔhíðÓ¯!û¥DTX0ˆÜæ£_´žFؼUˆD,;³bF­Xóct;ƒ{þ< YôQ�qéJo¡&€=`0­œFÁè,ÓsÁ9"»-+=g¬ySZòÌ%…¡ғûÎpÒ´ñ~'.®±~Ãô’ä*ä\”FÜ©=\p‰ ‰6ô¾&n’ ²~m“Âl•š�.wyv‚ö®o—¬jEŠyñÌù;ì÷«ÎŸ½tªWqÄç)¼ìÂÜbÕKØo-tßú�—uw‡5£�/ù„ÑÌýuGCW³^^ó×·=¿qä|[#ßÜÍLo m¸Ì¶Õ[®ß© \¬Ð(”üŽ “ig-…mµ¢½?ñ«äJ,ö—Šï4ÓŸº®Á`àXp›ˆAý§�E’vÌìÒùC–‹|0š…$r41’†+`eâw¦nM壵!É¡Ü|ÿпõÐÕÒr¡¤èØ�ãÜózô� ½b{+ë-âÈܺ¶˜ سm¿ªe‰7‡Å“hKoÊr46%É×WzØPLùǘó÷Ü[ 4€…¤e‘¯Ë�4²Q‰ikwózÈ£z“a?˜�FfBšm¬?‡Û,‰×2©GÄ‘qÛ“Râ¹TÞƒphƒ_ÞFÎÍUí»Bð\¡œŒìØÉ'\Z¼×Õ_•ï9 Þ7<¾&$&<.Ó¸rÞ«Kj6 ¾Íê— aaÙkp€1­?Äm>ÇŸ /Ô{Ñ¶ŽŠõÕâ/Õúb§OEpYæ'À÷”äù;x™ZÕП+/· 7¯T¿xǾÔ<ô½Äß]‚ð*4‚Ce¤l¸žz”¾/u!+S¬dNȳôÜL kâ®±¸ ŒEý‚gÍÞÈG¬÷I™ÉmNÙwJ�®ëË µØWcKûþ£,F|s-‰0¿MÑh§#7íÍMvìÙu ˆL¦ž&»e`ˆ!Óƒw¶éÄdmÚFM†(Òœ“SÁGqÄ0­H8FfÀ(¢×LÊ2õTçö£'Û»Šò4ÙZòЋՔTn*†k £mÞ§æ¤$æphLuouøÿS»ÿGõ¤\·ö ¥‡Êbj^¶ñ` 0†z\d˜�o{.Æsâ—sø) Eù;‰Õ¾0(/�¬ÍÈÏÈO£ Ssb6±è[*|¥ÎÍrV¾1¿ªkæ›ëÚ+îp—›ÿCv•Eq¦áŒ0óM­²qv6Ømuc-n\âbÄòf5I-HP‘嚆™a8d8†k.Žîs@„¢D��¨e¶¶’5qk÷mö#[û5úc«üÛÕo?ïó}Ïû¼O+âO±�Éu)-R»Dñât‰¢@©Ê µÙåUJ¶ö@T5ñÞHüöÀÑhÛ>È~ðõßã` ý^ïëdá š2[&+ážá¬ú9Ñ¿ç`bÎâ�Ë!]7™nW1îR Ûù&ÍŸN´ê-§.m¯Ìµ\£ &pÈËÏùÀ—ëq0" ¹„›wåD€"rÚž«Þp’TžãÐÆòlë ¡ò†ÕòÀ@*Ï)ÐÃB³f%ô¸Xõ›9þ½ù7äz³±Ä@w›u™TzÚ± PïÂëŃn˜L÷*Im¿Í˜sw¾¸‰ÍBw}ÚR¡6ß àcÔÚø¯Uâ[ÛÇw¦R*U~²ž)Ô”èÕ¬&9Rª2z=Á*(w‡½xe¦®úJÅr×¢E�žâŸ.J#…ÿ|åYqª´œ,é§ AJú#‰oneËC׬Ö;¤�¾ÿÓ™¬â…Ò|ú |Ån�ñ‚™ÈÉ7̹̿Ï#'›ÖGý¼c¢ß •uñ<¯Y,ß Ì">¾P†³ù21WHîZÔ¾ÔÂÛhµJáS@jÔ‚Þ²ìO)Þ�aaTl•¸MilyÎ2çONÙž×Èy;ºdìç,ŒÕh5 ¤V+ÐÀIkQmžÔ¦ª‰ßMá¿¢9¯ãm ɰU9È.ìF²Ð—‘V ™… XDØþ¿Q/öV�¸À/B¤Ø‡WàÕ8ʳÛk|ë?ùý§�iƒ°¢þ‘ô0è{Õƒã:ÞudDyÔÁއwyâ¥T`î™!LÞ‰¬iiÒ„„Ê`:ê@CW2rä)q­¹ö'C£Ìð©³Mèűm„s‚]ý<ÙÄ®á�8åÅ­õúVzvÜØ<Ì^êvLE ©R:ç'Þíž4®—ÈêÉéŒÚç×i·å??øÍå9D޲D>õ­ªª èË‘«ß Ã(SUZ–ƸJ8þ™�77¹îö¼'�+Ï4&õâX¨tÿÚÒiîi“v·rC£ÔpnÿñætœO+Áì�ÈÎ(ÐM�Qó\žZõvá8;ÉqVäZˆQ„¡‰2ÈÃÓbX/‘….Dð�äí¦êAx}2Ú3,#&^ÁDO(x§Xê¶RåH·ñøôaÛ²k�@õT¶‚ßGN<C’V¤ÑdÑÚ,Cu+ë±:T}”Ž>˜•t„MHTÆ„P›œûÀ5�¹7Û'­É­ÈH¥> ‹ò]çܘ4I'N7Idþ\©ÙZK›ê‹ò9ò¡œ�AÝ èû;ÏîÍ`÷kìªÉç8uahàò™!E|ÓuÔz¼.PÚ"f…ÿiHUsBn}E¾p½¯Ñøº>C¦Ý ²�i¯G iRâ%v¶YR�[Å Ó’¼UÜLN³�WšHÊÉÏs¢ÎÁ/Nx³|Î\wßHF!Gòºt ÛчùqÙǘˆ¿ÄíôÎðæÑVÙ�ßÿ7'º+8‘ƒì£“Æ—Â3︷¶‚èfß•SLóPÍÈmÊ z5¶ùWm¢ÿø�X#ÌÖùÂM •Qp\›Ì�(ô7ì?Wä5éË—ç5p&ªÙn/%_¶)ÐE½1¯wSÏF÷•¸¯æ-Îo(ª7QMÖªóåä�b:_X«ì÷„ý ½îµXËoï…MâZÉC°ÛA£Ü˜©æs£°ymóKH�ðÚÈSHÆ‹ëòÓ¨�2)ž!)ž‰™<Ln¢lµÕ=¥L{©˜ÃhædCÎO˜övÇïáýëÞ,, -"‘CÅ¡=eµ�ª­méa`)¬ù¯÷„7Ρ”ÙÚÃz¦H£_t?bÃÁ•9ÆèImîð{øË̬Íü¥aù¢»�ÿ„+Ä¥ö �%+$cúz]*¥-Tçå0dÕdà5pB¬©+ ¼¬5ÝeŒÁXRjb9Ü£@Ÿ[U?ã7á äŽ}‘·VëUD”0Å¡ue*ó-ŠlXÓ�[›Î8œ¬½¸w’wo^6ñ¬¹G+à+¹*K]˜C§å[�,„ ±ÂŽœfÆ‘ÍÒž;ÂýÓl™öæF[“A_¡¯b‹kôÕUT[wÓàÙ¶¤ýL�Âkwgé¢ã¤é™ªÃG(Y¨¿óà´ótãØ4#³„T4dœ¦{Í}¬,ÿñ;yba^†šQ¥&çeРɽìM�vÀ«NÆMÛÍ/ýBtõd>vÏù-ò²˜œ]dîò$�8•VJªèÁš¼v¡%><rÜç` ¼¯mûÁ#`O|x&ìzjÔ16{n vÃ.~CØ[�óu^Ü!j¹í¯/ù®ˆøÔ½´—ß]@Ï.\»ç°hÙÊtqruƒ²‘nmâì»F7„‡fÆÇ²a“?ÜLáßÝY .gëºL[3×Ö9%uÓŽ•Ôñ¿jµ=‚Ì.ðD+�1qÒ+‹KNÒñ:Óˉ Ë"²´~YË �êÊ’jº¿FËb/Ô—bú„Æh-QÞ*üÛ›Þ°dbÀ6ÚËú‘õ횟¯Öj˜Lå mít^ñÙoo}~62˜è\…¤n@ÿ.øÈ·ED'ùÑ{£;.&±Ê�üžâi)LKt3ÚŽÝRDZ¨Æ:,Ry8Ž�ŒMÙ¹‘ÂÌõõ€~¼9¯ 1xÞ•Ïšzû§ééædo +$‰ZÞ£bÚEÏ­Ë$ã×@*™äº­Ú¤æx�Y[OÛ¹»ã`ëÇ»ƒSþGbµ7q�ÑzœÕõ¢i¥lƒwËn§ÓòÒ„’™Äió€˜@3QüÄAbc[X–_’liWZ½eU’m½µ–Ñø%É–�ƒ©MÛ8Câ&ÐÀ4’Iefš&Àt¦™içnæúGWéÌþ¼÷|ßwî~眦nº[ikõü®ìų_¡›’×8s¥‹b`Œ³¹CÀ›P*f”Îuø\>5UóÃé’ô-h¼›J— *a>ÿ Ð3þ€žÖ±pW×p7ùÌ�ʽŠTË Ý?0`p8ËT�&½žÐEÍÒS�u©Îõ÷”ïÜ›^X£.Ì&²ˆ�“ üÂG°z_Oh”Hæò© å <~rð\Ì3B¾{‘OÍÒ¹4Ÿ_%2Î 6K!û�Ûs_:VÈæL­U¯6#칪̥‰@la•†ßâ×Óù¥Ùiƒz”k‹655�mMGNúˆ’ná"U�óù$|â;Ù½ïž/Èÿ+…S8z¶c@Ћù¢1oˆœ •4b@¥…;T¤Åƒ7†maÑ� � P‡wõõi4ã}éÌÄx&Ý7ÑIKEà ¾ä«BiàûRÜ yÃd.l:AoéÀ1·»Ò,˜x ÷bïø˜xž€ �ŽŽø]>·Ïíw—-~‡“°ZfªŸ��¼Déï8wú2ú5¬ß‘Iݾ±±” –ñq_‚ òè+™÷D\,a³²¬™B;‘*€Ë×bî´UËÕ6ì‡YKþU(Å ‘x#Qo�̆ٓôV7¨cM §ØÇÅ�9|…ˆ—�Z,‡ åRÄav®•Ü/@Eñ+='ü÷Ç‚Þ92ž ÑˆÀÔxD€Ôû˜È<óÀ ÔÄÔb"O^o{�FjPÃqÕEûxPíe‹3¹±%r}¬«‚F­ Úf«²‹'4<èöajŸiL{ÀmͽRÕÐ]UG­´§êH¥†UTÐw€Ý×ÐßÎÕ2åEƉ+%_àÁBéh±Ã‘°Øa:Ä4ÒÈ ª9¶¡X¹� CLtŽ€çÁ{Ëãѹ2Ùñ�Z€Âd8^<Ñ̃F1 ¯p�<P^=ÐÔaxó0õ…X©q@¬d,—ZÒ¾tIækÿºú‹ÿËO÷îA"¿ÝePöè¿�‚O=û=I›4xáúñ=°·ïo>3yQGkÖŒ·nß߸-êš:a€jQ8¥Éî ö¾ÜvâÞPà�!ò|À">O8ÆqG”|—:�ü­1°ßkŠˆþý ÊOZH¸íøüüñëÿØ]£ì©SÒw�ÃW§k3ÕÊáîýøÌÕ¹¥ÏW^Ee¨´qåÉê¹™bé8›€Õ ²´lò>4ä Ü^ÆSMêP3‰~²=&&SÙ�}®]™^¾D££ f€9(fôäâ 6j .ÂC¼†þŽ÷ºLÕ¯U™;ÈŽ®pROŸÍè>½AÀm|¾¹1«ú=õYz9Yò7q%÷ÇCÞ(9õÃfùÁq»ýÍâJØypØoà× ¨ÙÅÕÔHÈi‰PìhÄ#'ùD:§K¶Ÿîì;ØH# s½¶Õt´_´Ä”eÜœžIšÆe—7à‹·äOÿÀ›¸ þ ã$ƒƒ˜Ýêñ¸H‡Å7ÌÑòDP«ê&_ªn¨¬É¾³y‚¾¦ÂòúDo¡<«ihïˆ�÷Sº)ë„i½ÌˆöÆ$áÀ�/JÊ¡ø cB¼îH§\cäÝO®ÝZíÍ™£Ñ�>Á4£ÌTЏ8›^ZŸiß7QTËš°=+‹A'úCA¾ ƒ¢ Ë?Û%êpØãwPv«Ãj·´Ôž:at•É79»Ãî$ÜÞAÿ %ÿìô¡ä…™S×W.L®å(SëÑ,Zò “ú3 ç�|óß©åZuRøm‚�Ënà¡‚<!ô®âNI'º|„öyÎ�6ÜQËq™�ÆÉ²¥íê0«Éæ³çÄ1àh –Ýq¦‰@Ãà¥å†¿¾;?šJQ‹‹X�+†W“s‘Ëq‘Þ΂ðq²DÐ�„d$ÙQ«Ñåq¸íôn”A�Ž`ޏ+&&>°è£xô6 ¦] .h€äÙá·ñj,}|´•!˜>…AMu³Ú~–tX}Ã:Ðo2�}z}¯*Û³psù*ü凴˜�ŸŽe#áI¹TŸê“°6)™Ù¶ùøLpûöͱíOî'¿ßƒÿO€� ú°® endstream endobj 219 0 obj <</Filter/FlateDecode/Length 5670/Subtype/Type1C>>stream H‰d”yPI‡«hêÀ£ÚÚq«´ªt¼@eñ<]A<¥mŽmšnîºAE9U…�áD.GDE]/Dð\utuu _õ&±»MÄîΑ‘/óå÷ÞïÅËÄ1K Çñ>ajeôLo�:0bÈ/rxŠ0•˜Üˆñ˜çQÉHX1 4ÖÕã¾)°rйj´ Qa!¡1ò©¼7M›>}Æo;öÎÎÎò „ÿžÈÝ”Ña!ò)æEœ2\£U+#b\ä®fïðð°íò�ðmh´<pÇ厡kÕ*ùò°ð0­V'Ÿê:M>ÇÎÎ~¦yrÀ0Ü<0+‰aÖVØ·6‰ÄfØ\ æ„cËHÌÃ<‡a[0ÌѬ ³ÀÌ+Àîâ³ñxüº…§Å.‹H‚%¹–RËxËÄ*⹄¬¦ì©2ª—ö§k¬«+6ìÃð}Ãï�pÑ9róÈÏROiå(nT¨žÑ'FÿË:×úºM¤ÍcÙ$Yù˜ÑcTcþÉ(˜ë¿[.´—¢g¦IåxÛ€ÚLNÌR?udð6Úm^¨-²b‘¬nÚ_&ó�~U±?ª Kƺ\×ÔhÐÑ·vö}d¿=­îæ�Ý'k{ºèÿ`Ào@R�ܙ޶“Uu-ô½5ÁŠ…1Áïç~âƒÚ"�m:�’4ö±gu¨q }|åáŶìÄd'íZ^ã©qõ¢Í í*OúlvgeÏÐæÖ™ækWÙ ¡gýC£cÂxY…ªRW›—¿/ 8�Ÿ•µŸ+ÈÛ•®Òo¤†*“M~ü½“@¾YŽO`bh°àµ^‰¨!9ødÕºžWÔuDwqM¥5µB×¥z a$ �v0}ÃgF2Ï›�”H©�;8(¾ÂmÉ€ Í*/¹gf.Öy3­´# Taî᜜tþÑÒœC\ÅA½Jô¥þ”“”ÆëÓ ™�ûh=|_L-ØŸt¨�ßSÒ¬>±²‡×Qã™ä\Â;89ÍŸCé$,�7â図}Ù�óû'úlŠÝÌ«ÂôªD·ŠÝcÿÖP{ú÷ü²·ãÂm³çh9ò"RD–’jÅ×Wm ç‘²GvfÂ3æJåÞ´ãBwìYï嬣·ÇRm|þñ`þ¨:1?‘‹ÑâB›bïö?ªjlZ«ºn±I­§øøcºBE-ûùN뉺ŸØ'«;gû*U!¼Z«�Œýcñž±÷›Ï\çn6+<Cô!QQ‚Z­Ñ¯ˆ¦¥Yå`{C\XnÍõËÞˆá�ÄL½$º5èE¬†� %û{?¸|"ÑÊ Ê !ÞRC�xù¦»X%>f`3Y’s ?[¨™–OÄéSwÇqHI"¥ûöfíÛËîÎÉ,8Ý�‘ÜÈ|qÍTvúÚ% ãó�©ùJUÌ¡8.Â�¥l�~𼧺ã‚ÐÒ\q¹�íѵø^àç½+Ѱ Zj0Š–-øo ç•Dô6-a™ê¥[¶™FØ¢uˆD,;¯zn“/¯¨ÿ)º›ƒÑÆ,{‚(E\†ÒS¨†é` ØWÑ(�e.¸"kd±c­ûÜ oavG�±¼X(©8u°†“¦—‹÷{qqƒé;f�$×!ÛÒtâvÓÑ¢K¨I´eð q“„PÓ·æRMR£MgŸ{/hîøôÉú¡I¤˜kÎÝfŸº^µEøü•ve_fó²—sŽ _Á~÷h0¢ÿÏ¿ò²þþ°v4òŸ0‰¹¿éxÈzÖÃßßcñæ®7Ž�ëjåÛû™9]!-�lWsãõÛMŠåÞo%¿;3+kO&-…Ô&ÑÒˆŸüEr%–Ë¢Ke·ÛéÏ}×`4p,8Ï+Ä ás¦ I{ævé\IãE>9"‰͈¤á ˜˜ø=i;ÓøhMpr·Øï ¿\rµ¢J(/=qø{îE³Z H¯˜{es£8¡7m,cü³S…ö¢âͱñ$Ú1˜²MIIòÛû{l)£ü⋌…ÙGr‹„°" ˜lœNjó# lTbúÆ}¼ ¨Ád8Ä�F ‘‘�æ΋¿6àfKbÂÄ�LÄqdÜ®¤”x.MŸ�§J¶ølåœ�Â}Öîk”³�;ë¤C‡7ïqõåˆ-O® G ·¥«ÔNœçúòú�Á§=üHXXõ¬`òåã¶7ð§UÅš2Ú¬¨LW'þ\§+³ùüI$—íÿ 8ãš’¼x7/ ×Aô—3�ÝÂÍ+u/ß³¯Ô}.ñwV ¼�çP%)§£eL[ÊÊÂ?�aN.h¸™ÖÆ?ÜÐè€0 rœ¿•�Øì•2�Ûžrð´ Ý4šá`½9ì‡O²ñ-,d4$Â|¢ÑDNKn ÌÍÏvgï=\ÊBÌ¢ž'; • �!3‚öèwèÄdMúVÍ‚(Ò˜—WÍGqLo_*œ 3a"1h$eûuTï®"ƒ;;¸Žr7è—™%¹éÄ:J*Ï*ƒk¿%*F›ß¼N¹¤$è]84yˆš;D÷ÿÔþÿQÝ)§�C…ÒÁ™2jQŽáH 0™zRªŸ_hnCƒøµ? ¤(/1ùÂW$�M™…™…étqZ^L�‹þ@©Öj]‘£-�°ö­ñõùv¾ý|wõm®³]rV8©)ÑžXKW’éBÄ’º] †8.5);?A(ößV`þ{·¢‰ÈL«^Ò¹NX~ë�,¸°®©i@Aý›Ìj jêLÃ��|™uKwÍf‹ç8縮³tÚâÒV+ŒwÔmgA‹ŠÜ‘K‹ b�r!! � á’@È�Ë $�[¸GX•"‚Øâ -/U§ÝÙ©cw�;»ßa?º³ç ?vÆ¿™¼çyŸ÷{Þç}¦-Ö)Á¾3¼à�}çß^8éõ�i a¸c6/Ôꔀ…³j/Ëi«Z¹ƒåÔI�Ý5EÖ9 ¦ÂIýúïtÄëõ( 0µ‚Zò¥80@€‘Óî"åÖ³LåE „TÚwmÖGz¦ò¢<ÖZT{0¶Ç•ª_y}è–Þê,¦ =~®Ü¢cùy§"c´máÂp×l~PÃÔöIÀb©¥hß«—ØÎv×K�¥å.?mÍÿÚÀýv÷ľ3˜BQ’­#´ª �’”À) DW*LAÏ�VûÃÃ0âælƒñ¦a-…êÁŠ@èç+ÒÈ¡oÃP¡,M‘'—ñ¿Èˆ”ãŸòB‹jzIú˜³Ùî˜>zÿOgÃ+¥EHè^ðÊõƒ¯˜q<t“×gécú¶�¹´ÁÊ—3Ú 5(l+óœ³Z¿a™Å”»\… é*.Š“ðj­ÊPlù]°Q! .ej”¬ÞdŽç� ~yŒkãùM«ìÅ,Îç#�à<M«„´\5õQVÂf²éûõ| )% ÿ¬­¬¾˜oWÔ¥ÀÐ_Á²�–pÑ. oĦI$—�AÌëHë€ÀJd°a»éÿº9=Œ°wBžü™�GÐ:´%vM"ç~øâ{ÆÂup=Lü»èqäUòVøV÷{xºïè¨ô¤›œˆë D«±ˆ¢?‰£‰âÓ²ÓyyüŒŒcÒ(<ñXSg=šùœq-oû³á1bdàBËe|em[áEÖ®þá……Œ]eÁcÐ#,okÔµá‹&çyµË=sVôçtžÏ7·⨑'hdžHcR¿¸F½«äåà·WË9 ²è_Wm­ â×6¾‹€XQY•Gøé+(ú çõÂ"na)€¦U‹M¢” küoXÏYº]ü®6jx )êËí †Ò‚ÛÌžà¼ÌkLª—òT+w³ã<ÇŒÓPdeŒ"LVÁb4Ã…[x‚˜åxú‰°Ýl„¿žJŒ-HI—‰¹¥ï•óýÖ+Üùv �°¯™{Ïëè#ÌÄ xye*• WËôF)è¶?n<‰''ÉD™dF–4%Ûæ9}#ˆ;iã©­iüº"CÁìÓØÄÐÃ/C¿X"�wep[x‚pªÒb«ÇÍ�e%ó!yÿ f‡à‡{/FÎ"ÿ9rÃTŠg»<Üíü°$½—è<iËmˆà·òØ]¡æÀZ/›[ß.Ÿ«TÁ¬®Ï3Û®WX™m7N�Èk‘¢UÒÉ+…;¹Ë3¼R´“ëdŽÓAA_œ‘”‡^¢8ÿôŸ=>4¤-B¯¥á¡‰Y9»ä ùr€OJÒ Oñ9aY»ñ}qαRÚUÒ÷ï²NtŸu"7s�JͪP Í´çAÜ 9ó½7çpÝèæ{Tö¥7íœÿ3±†Ý­KÚ&UVPš«Î&˜(ô7ä,7·èª×7—RfÌé0MT2_¶KÀ�©¸g[wˆÿzÔ‹6Ò¿ä–4•5š±[í¥jæåpI[/í „G—{üëyp½ n^ÞÆ­ç=†6S;äÀ1jÜ\÷¥‰½¼ö¥UL�gÛ(–ð&ÊJò0¹J*J'˜O¤Ls>>3Ò‚Ùë�Ý•D{%—B—%`öl“ü'DBÚì�>@G?ü�¶,¦Œ‰ ÒK�¬¾¾µo”€«á;OÑznw\Ó 9&-TŸÐe*ÝŠû16U#7%O¡Hèò‡€ž]´[¾Ö¯õCÙê+‡§hçšÉïà; 9x]¨�)µr<¯Äæ!a4×vÈ�„;?™ŠÀ÷Ä…çÙÅg³½E¯3èjÉò:�±suµ ^p‰ŽÚt@¦INãç‹'21AL¸'iÆ3Ô<>C¬Ñ†¦‚!¼§ÙÒßK bпfi‹ ”„âLvqž‘Ý3BêÁô�¾é!üÔ]ôê¯8·Añ÷>0pi‡P[•"ÏÑ$­i¸… ²F_Q‹Ö§�Ë ëqæ}èï…«àïá[»~ 8x(=NLDùŒ¹Ç/î@~È'>,$ú˜£•`9ß¡¹œÖz î�O?s »Á‹ËsÜVÕqY“ÏÍ66I›ñ¶Ê1¹lk\Œ8=•ŒMÊþd;†~{oô9?ØÐé&\NÊunšï§¯h ÑÎq=�âG>ð™Zƹ @'-¯8‹§kÌ£$ý5ÐVÅË2Ôa²µ cM…ï«S§’(t¥å˜?ÇØÄHaúÍüf¸j²ß>ÖC†1÷Ô·¤D©Vbéiµ޼ß‚Ü ß|ûå…„(’¥s Šº psè÷a°pW|²( ?œÜqEDJûKºËgøp†§™Uwœîâ»O%6Gã± ÒidBjξ w¶@ðt~¾1L Eø¾pÑÜÓ7ƒÏ8³7[Iö´×Ó]0¥�ó‚¡u�I©è-ÈçMQ�ýÍ6µ¨‰Èm°¨qÕäp'µ}v *'1—ÌMÒ¤ë¶ñCN>D7x¡*åÞ2B­õLP™ç1xú1¡At~d‡o·ÂÌC;§ý6,\pµûЙ´¿p`'Ë«kÅd¾‘kÊÉ1äâ›öì w¥]Ï$%R©¬TËωÅX�E9$&öEçdÇ¢“žÎ/¶ �ý��]ýص„á=ÕÖp£ªN×5`öî^—‘ÐÕý�Äj�mª ã.£=Æ¢½Tݽr¯1Ê€¢˜è4*èxH¨�=ƒ9›{°®Œ­{´÷¶½}¯¶ÝÖwïZš=h;V6„l8·1„�NE�ˆÏhG"òЉ$šsÉÙžbrþ<ç÷}ßï;ßï÷ynªëXÈÑK�:#ÄO0©„0:C&­Ü�Ì‹¤ÜœúÕ2Mý™ÒÕn¬F’W “g<¡ñ¦Þ‘_NŒNž8®QöÑѺ`e5YÜTW¹óÀ7÷éÜE9¦j¹0ƒ+È~~ðZšøˆûåh}‰„^§Ä 9}Ô O[Å ð†­Zxlï1ù±A@@ˆå°M~¤µU¥êoM$ú“‰Ö�&&ç Y¿¥³=³åÎ�Ïé§R~Ý^f± ì¶Û ôF'€v§ä�‹ �’Pà³h§Ûæ²»ìn{ž—w[¬¤ÑhÑÓ,l¤UîÆcΡaÙÓÉøõ+ó“Io^·vE(¯€ösÒÓŽ€�#MFŽÓÓhÊ•ˆùÀæªÑ7™ µyJ“äQ­Y¥³�á|z¥Î@Ðé¥FüÜ>f±”r:…gd€¢[ï¿@ŠwñãÝš~«&/\̪٬›i¨ÈœìcâsrwÈë PÇ}Ú½ êÅ�l±@™‹ œ&á(pyý=04¥Îö×ma� E[Päd#ó$ìéè$5=’Ï ZPd2šñ •�š]¥KÅ`\VýÅ;…åÍ…¥ô\g}¼”ªRqŠ|æ`v•wÔJؼ ãä…¬_Óps:»/“a¯g˜ð± r‚"Wž‰\'€òn68F“àÓ©þ`ŠšlÜΠ ÐiödnT  o§Ó$ìw«.¾[٨ٱ�þGªèÄ‘´y¹|BÜ�ÈJÞ‚á[ÙÐ�ù/O¾¼шº³Ê ìþ¿�†O­¿‡V2:•<}y-î‡äÃm›ª?<ÓÆ¨fµ×®“÷>›¿ŽuMÑD;¡ gî²ÒP}“°úÄUr§Ïó±�:éáq{êÀnƒa—…&Vk FÁ&§.€ õÐ0:È�SpÙm¸¾�ßòǚ⪣¥UÌOÀâ*m«Ó•hòàšMòá‹c“7¦7¢¥(»bSÁ¾¢±áLè0�E_в„lð&Ô¦ .ŠoËã•J_5…žX‹–àUQveÃÝKŽO�eÐ.PÜÉnÆKó´ $hòŽ“â=xý.o±éxÝ¡nÐ7R�Gü±væp²í›+$\vþÆÂü‰†÷éÿeéíXÖ�x$DRîûœAjèÑd¹Á³yGf$ÌØæÖs$Tƒ‘‰™x¯ÏÊh®/` QƒB$‘j‹ÕhjÝ\ÁÜÆÂ\¦®ÕíêÀ–çûõ1ñ¥˜®_vn¾q�X¿ƒßÊmð‰AÚÕ%1eá]=†ˆxÕêîfê­¢ò‚â‘C {™K ’ÑöHK#YuXU^ßêï Û†Œº¹¥ZôrHê÷t»‚¡ð…»,ø¹%·E©Ÿ¾¾tm¦%µsŒA�}-Qõ±Cqò̉ÄäÜpý†�Œ²ð³bΈ,­èƒ4±�½X†‰««±ûn m6ZŒf¾¦dÿ^­m)±`0[ÌVÒîìrwÑÄÕóèséëÃû/O28›¢uÉÑ6 ¯¦>bã_1ð4 þ–æò—Šbâ›.,»ž†[ÓDDl™‘[¥•ìZð>Ú�ˆ”ÌÛƒüé�ÊÊqZ}¤Q¯¤ªŸÇeÀ_ÐjLÙÃl%‰zÀ[Såߟ:Ý�Ó’|@(º»fbc�saLoSZü2–%ª2NB±Ò‘>£Öæ°ØÍÌ”D�öJ,a[(@FÏ„‹ÐA·E ^ ”"ÇÓn“ ”$öôÕ²$ÛªÐ(éfNÝÁQ£«‡g<šn ÕÚÞÞÒ0rtüÛ©‹ðùϼ’­ �üƒî¼Üö˜Xƒ%1éð²…åÃÞœœ…hΠѾòáZù �ü;Uë endstream endobj 220 0 obj <</ArtBox[0.0 0.0 612.0 792.0]/BleedBox[0.0 0.0 612.0 792.0]/Contents 221 0 R/CropBox[0.0 0.0 612.0 792.0]/MediaBox[0.0 0.0 612.0 792.0]/Parent 41 0 R/Resources<</ColorSpace<</CS0 245 0 R>>/ExtGState<</GS0 244 0 R/GS1 243 0 R>>/Font<</T1_0 213 0 R/T1_1 214 0 R/T1_2 215 0 R/T1_3 216 0 R>>/ProcSet[/PDF/Text]/XObject<</Fm0 222 0 R/Fm1 223 0 R>>>>/Rotate 0/TrimBox[0.0 0.0 612.0 792.0]/Type/Page>> endobj 221 0 obj <</Filter/FlateDecode/Length 827>>stream H‰¬TÛNA}Ÿ¯èǪ„™�îžéž�'Q0j4ê>HŒ!ËrvWv¿Þsz. ½S]}êÔ©ËE6z=.Íñ*íÎJój‘}Ê.îÛloÛî²ÑK'+S¦?³šÌég“_g¿—Æšî(sUºÆÑ6…+­7µ ¦›eûÒi¬‹ ³«ÎVöÔVøk#;f¡µ,͵ôкð²6k}Ò_«ÂɦùÈ'Ó¥æÖÃåöF–6E+3õr ¶yœh„uŠh¶#cô[÷6ËË¢,Arbn~\_Temr¤tæ{xfe5Õ¼Æó¥º¢’\mDè1�¼üT`D„âÍI ˆæA@=y�žƒ`o$‚«kŠZ®A­–ÕúÆ<ƒ“¬%*j{E»v`×’�íEÆÑ¶…¥7Uhz‘· åå„„Z9XÄÈr +‚¿£Ž­\’Rà$MOÜ}¦1’g‹ã`ü�Âuºÿ¢.wÎW­ó à9ŠÍá@K­(×Fzp›�ë³)S"LbÚ¡hQÖjŽ…òñœ‚E¹6Û¬ ­åíÝ™ÙKÁZ6ršzà—:Kºa-‹¤¶¤àP–È9Ðp·9n™gh»/CŽˆdÅÒU·ùw<>îtM>ô I„ö`ôdÊ®-\ãøû0“ t_÷£§à žn9âÇ6 ýàú|ÃÂx”—aßkîY+&5å9°ü�©¤¿Ùï‘ÍÀ*嬒ç³Dúà�]G½9 [ ñQyâÀ-öòì-ÊrÚ3ú£yó• Ó�´×%u‚•3e*ž­ÿO+„g·‚{¬Z”q`áïåøpø­ëÇ <KdÓÖÎTîf¾N�J0g1¹k­0úu?È&B8XG8ó#Ì\-Wpmœ>·HëéR©ÎŠBÖ`^¬G Æ9q~Ãná™z CæÍãÝÆ5SË‚pï±z„%,·hÎzRÅË舻£®‘1딀oÅjã%j$—QBÒaûp£ôÄ|Z¢¹O¥®5jœsÐ'œ#|Ã.Ïþ(IÈÅaelÿ‘¡—™I`á¯5Ü!¥Õ¦¨xjw:Í�‰—VQ Z¬òN—ý`�y�_ endstream endobj 222 0 obj <</BBox[0.0 792.0 612.0 0.0]/Filter/FlateDecode/Length 127/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 245 0 R>>/ExtGState<</GS0 244 0 R>>/ProcSet[/PDF/ImageC]/XObject<</Im0 247 0 R/Im1 248 0 R>>>>/Subtype/Form>>stream H‰„ŒÍ Â@ „ïyŠy�nóÓÝnî‚^Š‚ ⩊öýÁì¢g3¹$3ó1ÎGz…G6A1†ÎŒ÷�.xÄÜŸ÷�Šzòs0ZF“ªŠ×ŒV ·ÖÂÓ<áºÒxX»'-¡ŽŽíäRÿ“‹'61‘Ö„û¥Ù¾`ù�ú0�²O'j endstream endobj 223 0 obj <</BBox[0.0 792.0 612.0 0.0]/Filter/FlateDecode/Length 12291/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 245 0 R/CS1 231 0 R/CS2 231 0 R>>/ExtGState<</GS0 243 0 R/GS1 244 0 R>>/Font<</T1_0 211 0 R/T1_1 212 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 235 0 R>>/Shading<</Sh0 224 0 R/Sh1 225 0 R>>>>/Subtype/Form>>stream H‰ìW]o%Å}¿¿bg$îlW÷cXØÈFk”H€"síe›Ø‹üúœsjæ®xÊcdY¾Ó5]Ý]§Nõ„éâo‡ÿ>¾8<{þ*L§‡)èoz8Ýžý¯¾8<»°‡É¦‹×‡0]œ0}ñ & xüÆñýd]+ñ°4ÖjžRÊk™.~<|=_,iíó›ÅÂÚæ·‹Ùç‡é'¼ó%ßÚüÓbP¹^òZçûé¬óv˜¼]~OK_Ó|Cý:ÿ¼ü^é÷új×›ÞáÙpRÃêëéåbGÜ/{ßé„ÓbuÍ8(ð¸+lióãC¾ÇoÇÁwXSæ×ÓòíÅç‡cXChòÞ¿Lq-棭)¥éâ N¾["�¾^Žmžl©´²,1ÀæmJ3_Áþùl©ó§Ë1Ö/—cÂã³…¶þKJÏclîn—<¿ÆŽó÷n² ·'ØL7¨ 5Zù>=Xœ2‡W‡yZ.~ø3ŽMìõ^ðØ‚xD~ã›_"KΕØ�áMÃÑw÷ Aúêïl³›s±ÔÎð/ÇŠÇió=a|{Gëã|ƒgÑ2Sø ×ø-óƒvøfF–`MnÞ_\÷—6@I 1Æ%6XiKc ™ço–ÅvY�ìèÌ“„m`ë�/¸(Á�úþÝ’7¼ü,].ÄÏ1"Jó¯S\AÔ–B$Ê Ç#Þ|¡ä¸r“× ~ƒÇÍ�0°8zT`sçQ�nÄ4bïË ƒF'ß]:ˆö¢á¾]j úG˜>ÒFÄÆˆÓ�«‚HP×{€¥k^º@³ � (у§˜ÇêÄ=(Ÿ!ê<a/éÇ8°ÂB€µÙ< `¶Ã²cÍÜá' :bÅš<BŸ•Åls‚4iI ŠÂY3œ��Rgt ¾3ÖD<ûñ zŸÓóšZ+`Ÿº&7ÿïË‘ ùi«†ûvòo pbÀ˜u‚ù�qO(ûwö; ”À¥:�dÑHAnî´å¾úšç4ðy­# ®ƒPãõôˆBê^�U$ºÖ( až)¤ŠBêF!æ÷)Í|?”jxõ˜CŠ8¤“CêÆ!ý1‡qHû€CÒì§ý)‡Ôø» ÃI$­¡ÔœxA‚NóÛš$`‘['9Ðs@"aß�ïm/í{�å%¹d�RP¡ÛrPJvËë w›7Ùιc¥‰‰"R±Óiöá÷žá°ò�ch6%µ¼xëméazHl ‰EÊŒ<l¶óCæ ÓwÎ(¿zU¤ª)ULØ—JäglpÊ”ÙFWŸ¢ ¿¼¹<]_½üäÅôì‹çaúø“ç´e¤•©X€§½L(›ØÚt}øç¤†mlØÐ÷ʘ¬!¿©öÑûT3JéÉÒtúñÀùŽ Œn¶‚ÛиoaÍØþ‘ˆ¦>!¼#SD˜ =Ó5扄NŒu�.HE2Û¥ÓrÏïg± szë”ZÈ:ƨZV-,9Mç eìM�j”=¡'×ìÙhPOØ´®Á*¥‚A²Ü(!JÔEÂQmmܹ‚G�R«”4»bNZ_i¤")¶q–ŠtÝR98ÑÕkÏCh�<Ém­ P^È2“!�lN iÏå<ÖÑ$1²Á­§�o¯ÿðËÚóWûeíÕó/‘¡{�í0}�w?àÿóéëoÃt5=ááÿAç¼9¼*¥yp³Œ47¤9ÃÿR|8ç™ùÓ}}�U»‡�¢_Í¡P¸5¢·‰��*™k3!)öêŠ( -¾cMá•ÏTè$D¥Š©}CDW«è‹Æ�b†u�_0ÃBÕÉ–“«¹X8W‡+6žÜMgÅàŠ#j.bY‹ábs¡A)ÊfŠ5aÎ|ŒF)@H±H/ukÁ\®ò#õAA§¤áz l@+ÊzÔe&8šªðȳtb›­¥�gý##¸Ô£cD«rÕ¾=i®”ÎÇð�“JÏ€-£kh"4þô,ú¸¹Ck£ëf¡1"í¼2æÐIzYº¤\ÌU«©ÞKÕF5:ŽQ½ï¥Öú¦K·bÇA×î:„PÀå`t÷j¸f#òáP§Ðå•9g‹'Õ0îɦÏYA †%+Tˆ(-Ç·e%RŒ½ÅX2!ÅX$¿8Rš*–…·£È¦$ 5Hè)îü]üA´À+BLÑmð-©ÏbŽ„ ©— \±Þð “Í7T…ÛÀ· º<Ǿ#ºQ-UG_a2HZç˜hFr›¸3—èET5WådpFî¤w'T°²èe|Ä�†\Š(šwŸ¬ðó e•ÇH Ûçõ�ɽ‚Q²Ú@‚ NœFäß�ú3¿’`Ø™Z\®LxÉQœÝ¬m(r»G¡»4ç÷&È[i»DˆÇM„ÁpBªiÀîÙc²‰f$kâó<„–wJ£Tš¨/;ý“2Q,JtJ;#t‚èÌ£=,ˆDÜ ~äSXíÞÆÔè62ÀçDó¢�Â`m[]÷æ¸kÞNÍ`V•�Ú·ríMk͋Ț:ËÈj½¬‹ÌË®oÛ’Ä’N^ý¬/©¦c$Ï�Ÿ�ÓtîÑHu*g àÍÅU7¹\lÊm®ÒµQ܃<sÛdìðX4“Ôš2�SssÅ*¬ù¬Ãƒ˜rø ƒQeý[ÝÈ¥×sÌ£Û€\ù•ž7£s+ ¢“7›*¯%n©“.WOmô©�>µÑ§6úÔFŸÚèSýŸÚèï¿Gc�Bµ�Çkޤ›’¸ÍÞHy$)võ¤›ŠGT)wÛ°ì}ª 7Ï!mC¼›-:Sïœä¡9OV_R�†%¥Í,Ý…`E%²ëÙ#i‚AÈ2û~�›€0h§kÌjÉÎl!P2#%1ƨ$ÀR9n}ã?^*ŒÃ�XF]ˆ¢¾4cäÈ’”P€%ªi©K­E%Šç‚éÕá"µúÖµ¤4‚�ð$Îdì7ÅÛ�oF[‰�†ÚÅrjÙ›�Ÿáõ ߈‹?Ê­gÏ€Êټ桢ËcKšJÅ�=wAŒaUnuÏäêX(N­8’“аiïûME,Î0�ˆôÅC"ß6q]ðûLÛ1ïAia ±‚E‰ÑTãoHH•Ï™æ÷3fRÝÈRrÎÌ`²² ²„‘Þdf*‹pkqöZÈ›ÐvÙǪæ^ƒtCtÒ�C[Ý21’sP“×Ý¥ùîä…†¾I—ÜĨz'WÏ�g�(RL)×#(…)û]Àu%a»ž7]—cù/ûÕ’#Ù�÷>E^  ýE�§0€ãÍÜ1Œê¥òSír70€1 .±SO¢È`0H®+CB‡Ì™$Ù–4 0È*«¢¯1HB6È••%ÒÈkBšQÅ< D’ª,6áµ¹~á7›]Z’7ãš j³de�ÍIÏ”]Èg…?ÿ|þúãƒýb°_ öÄ`/,O‹ Än4”Šº…išKЋÒ�Ù‰HQåÔ¦¡ÐcZk¬?~ó #,ëüÁ�w…_Xëœ>~¿KQ—ÅS“Êá9IBÀ½fŽƒÁ�@‰Oy•ÓJ0¦äì lžîK>Uü¶& ��ãŒÄ IÄ-àÕ“¡Ÿ¥{sU}«Um„¹üšæ¯÷bmíÅô0ÔÃtœû{�)Ü7 ­Ymãú©¨JPþä[VC*Cå sß–îË?ž;Ò¯lþƒ³™˜Uh©LIäyïüÏ¿<íGÒ±µ¯…‰ñ}Òñ­’~œò¤'Zhèüf)�Oδ¹xfSâ<ZHòƒ®|µü½•+‡ HÓ±dn™ÇužÑÆû.³‰À†çÐè±µãWàí0!DãηoªáŸøˆ÷§ä(•êY¾�âÀ+iz‹¿Þ’¤œ:”‰C°¶WÛàÀ£=­¾Ú×~/ Ò;½‰p^N– ó½[¿÷¦ku]š–^\9Ë••íÕ¾\-l€Ïvºo=–à�ÚuÁ^¾>À|ïjz�ÕrcqÝw�qÚ‹Õz¹÷hy·Á�ùÉp<»ö=Zô±¸jøÉz‡ñdî‰ãÂ9×Eº+®±ÌÅú9ƒd”¿s4‰Ø‹²¼1ÁÔ�«·�pÞ‘òp=瘓H™ Xû g®Ÿ–ÙþÈ»Kš÷3EWÜ…JlÛ‹L)¸�ž¥lü+�¦I3ãöEãF%Ju¼¿dÊ7CÔJ¦ìµúƒ»æ«^åÇÈkÛBÇûFb¨7{°9•ä�f¥«gõ±›�—BœA—£ñQǪ-£1™¾¹÷�„ئ¬×X5çÕΙ,FÁR¡ÕЀNLXÔ³±ì&¸+Y£…ùo˜ˆëµ5¯µqßfÛçÓQ]ì›f�ôœíl‣w$*n~æX÷—cP¬;,ð­EÀ�«+�o ¢]JòcQo£­éq›U¢4w/+Ϥì¨!~4ýœIz2SµkݳvÉò¸é 3q”ÏUÂ%>t$$Ǩ5byþe¢z¦ –2çFÙi�&SÐ9x¦BUÕ+FÍ”chƒé1ÍS©ÃV˜¢lVIÊû|_§ø wÃäÝð*ñ¿�J­ñò?/+{y¸æ@úÌ B€z' ´>æØÿ}’2aÒ ]K‹{ªFÜ0E€'jʨƒQ42 ¼„aYÓÍeé ©¿rºT›A°˜ŽêA�{–BÞ¤¸’ñF@”UÛÙ7G1`3ȘL(Úfe_!EÈp¿·ßÄàZÉobšmñ­~Âl„Ê>€`!>nårSન*° ±.$ fÀ�Ø[¤Æ‹95f3¡Ðsd•Jëãv&ù㥪–á] Bç]¦²W‹ÌŠ0E-‹e{ €²š{ñ r‘5}@%›ûÔÎèÖˆë_j\ôšE¤¶¨Í(±ªNç�N�•§÷ziƒ0pêý¡Ëg îöBNë:É/¯ù¸ÇùEÿL/<Àóî¡G^œþ{å×¼‡òõndï ŠßVÚ2hý+šîËÇ…lÄõK¥ïXƒOqØ�ÿ‹!�øæ)tšÉMkÑñilJüSù£ØM1^jséKEÜŠÎ êZÆ>–¯>¹ò?èšï¤¼JJ˜ëþ¾ž c‚âÒå_Ô‡@�žè§ž¨§žø9Ñå„�rbýŒœ˜Orbœr¢}YNä’ö¹œ¨§œ˜ß•vÊ ûTNäCOŒCOÔÿ‘ž(Ë;D©(þ·úÝcØ3»WYS$8Ba«¬Jt5õoø¼�¢I»/1ÂYg˜ATTS† !>—‚¯¾9g�_­.h° d¶OÔtGbª: ¿5c,Q­´@ÞÂ>Kd�´(gQnîÔ.#èfðаu.N-½œfb“›• Öl°ãUy„ÎXF`½j¦èYhS³G[&ˆ,šñk¤�5é"MôÀÎT#ð ¡iMII€TÈù47̹æ55:"ìÉz; Uß3ûJ) $;N³_u"„ÊJŽId†G¥�¤„ è” TÒI'EWŽQ½îø,#ø çPà¹3K˜EC4>µ•è¯=´Xh‚±�V�¼y.ch¾¥±JÀÜ^‰ñ± N”¦£��\¦Ô�•ˆÏ««‘HäÊe3ø­¹$p¯5|D¯Ö¨Ý|ÿ±ðuT×CüÚÏb»ð»|I=e”M˶'&;ƒf™ùeí5¬í’Z´é¡Ñû–CÛûº îJ O©³kV†ƒj h�8oM:v®q‰»É=ê7ø²—к k'6Ú„·]X ÎDŸg34‡&Ãç#SX[�µF‹²"Ü]¬é´À�‚¶F‡âK¢{QgÎ�Áy �íAð¦Q£ÜÛG©¨Z _õZ/Óu_oàéTñ’ZÉH꠬ؼÑ4X²Ñå˜/AfU&2‡Þ6öï)a? xSu‡}}… P=‰òÀ6 Ñ64Kì£@T‰ïI|H“º Ç)/x¸195Ò;µ§*4A´¹ŽYŽD ÛHP�)éþ*‹(e+|sÌ8UÌ*‰\2930ù ÿ×”¤¡�è÷¤2öD÷LaÓ£ëz½¾mréâAiËg«uq$'ÙÃ(l�Ø—×£áY/¶·=j˜ØÖë‹õŽšT·äÉ�ó£-Ÿ÷òá¼gŸ›½øK6[”2Z²1E�ñL^§æH]µÖH´­µæM_€3ã¨Â.†ÁSCÞIƒ �¿*KÆ)©ÀÊl4Šô­q˜Û¢©µ˜í¨* ÉþÊJÌÑ;`&–'ÕU't“$I#DSÞçû:Åg…Ìâ¹¾…W%¢„—ÿyYy¢â+¬Ä\ ùRP<tXô™Ä.† U—.n�ÇmÒßß$�5îª8ɃSÎãôÏoªEtévYzEjǯU2»é“.ØÆ¥­d7}ˆ K¨ Íì”ÄÝ9$+6ÝÑ»AŒP*q‰+XT‘Ÿœ«šä¹ Ûâkwc@* K­NÔŒh#tUÕÓ‹2°iRî™Øtb=z‹ô¸^J�)M~˜7wB­�Û™êgbÈ ƒœ¹„·‘»{™[Îù§µMýª¶©l¦’6å�´©Ÿ)›¶¾#mÖ_K›SÙ|GØ �ŸìíŸ;„ÍúLØð #‡�ùa3„Mý’°)CØ´a3a“ïÊfþmeS^”ͤ²)¡l2¥�ý¸´é�Ò†e[ç'ÒÆÞJ›ñ*mê–6ù»Òf#ï­¶)wm“öW:ÅÍ”¸©!H8„n[Ü0¸sJÜÌOÅM_Ÿ©›ü%y³NyÃ4òçWySþJÞäŸÓ7ó+úfüµ¾q�ŠrG£sÄø{ÖZ�UªÊÐ7ÖQZYãz‘µ¤*5Jÿ0`~SE}pT $P�Ùë4Z׉KèèLúâ�}@R”»Ayrþ6æý#’÷y�&eßU¨šÃ ‡h=<tBlk{ïý¡öý®¢«ö›çjwˆ‡j�” I®xƒöïí�”1šqW£š3w@×ãöíS� ©?×M¯ÑcôP¼SB !@ØEÛ°›Ö¤±ËR¤õ…’°ÏR~vz�8Ý®œn¿”ny,è%‚È~#Á؉€�ßþË~•#I’ã@}^1H3 >hÍFhiÿ/,ÝddvU�¸R)Ý�JF�ÄáGv°SÍœ2h´™Š:dRY%rõ¦H/)|.-D4‹8•˜Ó1L/¯º4ÇLuÉQL˜ÚŸcýYÈÔý“¨õû_³¾´ËÅ´ý�‰x Jê7ÁX5cè´`ؼäêº÷ÛÐËWïÄØrô žµBâ-ÿ\h}Q Oµ”ØD[cÆÊSiVØ‚ÆÀ¥‹¼ÎMŠàJ¡�ë¿pÞÉù|öz2¶ÏH)Îw˜üû9•åuêRL‰n1Ï—Eγgý_·Ð¯·îгu†hát»í‹Í+˜�²…`Ð72—à}Ws°=øJ|H°s(Žs wµH £JJ>s:æ:FNWX‹´ ÖÒÀ–vβHš®*/øûŒ”ÖÁpÉ(,c“NB`¡¶]GºOº³J„Th$\²9Qn6/*ÿK0Ô%âïÒRø5æ"irùÑ÷;)cX~2<Nü‹±Øœ.MàÆ<LPÙ%Ü«&ÿ…äÄœNaÆ §|hI•<ÛäJÕêêNù뼸ÍT5n�â) �ïÑQ0æ¢Æ;ògE†ò:”sM׌8^Å™ü`Vm ³Ã•�Ž{o*u]´Š‰dE¸Äu5h`BŽˆHßûÅÏš�JÉNf¡Žp¹vvž~Ùfä¾0Z}û’÷ÜcŸØznNÍš§‚ž™y^|Âò"�bõ\±ruw¸�Ȥ`bŸô¡nòv%Ø–µAæ(õF‘zûõmO› Â·¥vpä˜Ðõ´!ÊÙ¡•âZ­+eyºˆeÙð°u–“�ÊkwH@y+Ç×ì9WûþãN ×ÊY„*îšQœ§ÝéÅ æXZ Ž;  ] (´gˆBsª¶/”ýWPÄ•ˆ¿.ÁRôíÿ|�4ß›me·¿¾U ç¬{R? jOƒj•ýW„gC ‚„ O¥�Æ–R¿d0Æš± õI”�]„3d_†t¡Q£g)Ϩ—�ãÚ™þ�©YôUƒARòCž-w.©Ûqž7˜ž bÌ«œ ’Ìrât?å’Œ[g�ˆçvލ×]a¡R¿EOü[zª£ÐÂÊÉ…L”O1¾ :{7õ‰p‰•îo߼ѤrÃ,óÕF½+Z±û<gSAýæÉ•ÂQ{O–6—zæ<¨r.×+ƒ73}&€F"B ~k”ÿ•zÑp6ð¼ �1h¢H°¹¢§¥ÿºñö¢!b(�ÓŸ!ºÉ‚©UAŸ¸1=�™˜…bɼ&¸rNàz“e”ß�Ô‘8P&üæŸÍuciýœ´:{HƒÈrªéZ“�‚ÝPWˆ‚qb82T‚bŠKôÉ!}cDÓ¤ z2 x•3³‹›-+›ßChÔ㙬/!@ñ#lU6g°÷˜V§C›G~©9ÇÔDð7ÌOÉÿ©¶íüq ŽEa¯—`˜E%Èg�¶[w; [»6"ž‹UŽ)°­i9ÌqÖ˜e>úa2»—ÿÌÌ{Úž¨“2žTïçRoÞ˃ºµ¬Ö®[R¡”ª}rZ)_œÌ\ÓxÜÞ9ýT¾¦5ökZ >fÌL;͘]èš“&»úwB"ã‰&û=¾ë¯�ùˆË~·´~:Áádž‘üÞÿ³×¼�»m=g`T1E>v…wg}jB]åðT¶T[Ä­Æq7?fo±CLRŠMš}ï¨uÉiŸÔÍuÍ£Ì*!ãu8yH›U‚xª ©W@˜F©Q0öT¶ƒ"®Ë)yP‡ �þÏ�°]XEðgp‘‹èW73ì4 �"ŸûÑc½?Þ¢4öÕ[X6zõ-{8÷Ÿ£vÈ º¼�¹—ý]ô æ‰ðIÑÃ9ejpö&"q�å [ºJ‰§¡5Y�m‘ˆñhÓr°®Ìç»p#~‹žzë�kMtÔ܃äuk–·Öf{~„�¥j ‹²aÄ!©É^p!ó”ì+�° ;�%ƹÀÕb1ËÞ)²ž™‡*ã´w ÛëØKKî*i/Ål’°E×®�~çWÌ£¾+Ú4ù’8†ËCœ+&€ŸÃG6•^!¿£It¦^øùÞù 6Ùu–3é¹’¾¬ÈT4v4Ž�èH•vç…s=Šo’Ò—nÕ¸- 7‡2©Ô*¸Ú¢ 5 _£Po<¼74M䤱�–ÍÉIÅÞ¥[ÝkôC« ”üUŸßzç[² uÑÁØéÉ1Ó@¡þÍ @,Ñ0·’ÿ •fåõ€6X3AÚqÌ0¢o�LHoULÔéAûèìÎFe”meÑ]A®Ä ?ÊžK •p/~ÂÕSnù¬y=уd’m5øñ• ¡nÛ$²q Ê®ó‚jd›‘C‹± r‹l8Z+�8�ÆáZ9 @ç9îs9²$[ÃÔ®—@ÿ²ï¼$–bv_2=8‰j9_ôÎsŠ×éBÓ"­º$Œ¸y“õ�NsiÑ Ù⤆Æ}tuŽ^A¤ÖÑ|å¯]?¤OQ3 áÐZÝÁdŠöœ4K˜ÛïìVŸ;cÁ’xu$Øšõ8Û¨Rè+èèõ<BjEÑÅÁ›íQpHy/9Ap�…óé¨mÔS“üWg*­¿åQÑÒ´¤�Rƒ>vj? ¨ÞŒ€Èv™—)9•b½q�ùÍ-3Š—Fd£:m„› ÝðÛ¬bãŠcÆ!–Å…!kˆºJ(wL{-©e ‰µ©§+(­Ë7òy´CèˆÐ¿/º¾UEM;Ô‰i:@¥]^ªïÀ›j±ò™™ë~q’±”jÉ÷ˆ<µÛ:³µŸ¥¥'žûŒ4ž¸Ïê�"„¹£ –RP7NÑËTyÑ �ês¥8/3ï!«©¼ÈŒ"Ô«àbUê�³ƒš—®” %XØæ Æ8èÙ¯z ï³ÉóÚ�–.Qî¸ÓÛãÉâ–.Z�þce;(4Uyt]p�¹ÚAóÜz`ë&jêü­.Ö¯×ùè1M)À_$=DU#ª&R �n"w,ÃspÚ'$†ÊÌEScDhŸ´0¨ºXybì�Þ)ÔCkrÌä:ËÜ*Vu¶u#äW®ê<Vqç*“• h]'Ï£ç±d15�cþTÊÜÔ&K̤$È]Ù˜G·_C â�k^W^[Ö¸)²qÊ¥¸ÉÍNS5$k„×}f³ÄäÚ.MN=StZ�0E|ΦîФàÔžÈÚs¡—8 7·´¦´|­ÈšrPdS]Äš½CÖ½þÕG„Ѿ�oG ‹Üµ3¹=Åß ÐïÊÆìÎÖO!½œc—\L �Lëœ9(MBE*zTîÊ Ê½EüRÎ8uó(jxyFœa¿!�¯ò�vñ1Îò .Ò‡è�´Òßrk©ƒsHÐýsFh„™·©t\¼%° ›Sƒ‚t˜rUaÆÈRôV#g ¼ô�ö·¹ [í�dÙÈò‡,Èò‡,ÈòÿM–8à£ì=½.`åıߨ2óôë/ú´ñ5¾|‡®é_ã»C5¿Äß²Æ{ ¦¯Ý ñ³ †Ç¾D6‘•>‚=Ná\GÈy vÿïÒä²���±¸ltÿ=úîð¾/¾M,F”·é¯Tpï9<Z—Ý\4Í%æSÑj¤&;£M¢³`'aNw�»‹pHŠ+áÇŒK-, Fd¶•}áŽ<ÎŽYôÎF éŒìú …-õì2 5ØïE��„&š„¬TF �µ4 mÈu�¯ImSÉÄYz; N}!íõªéó�Í4,? µÖÕl! l…Ç”N¨�g‰ê™E¾9I5˜“¸ô?öË%G’Ü¢{�BÈ¿Nò<‚�-JÝ!73g$£jª'»Q3À`z“H2"øñ�ùsㆃúâé/Šd婇nnÌQã½ÛˆlFqwñ_¼‘±„& ‘»î=Tø4T2/h‘ ðW]–% †×¨é]¤¡BSU®ã8EÔ”y^¾—ç >#º jà :d†L” \,*îVùVeìéIËÏ/:f¯e5Ç6¨5ö´ÅÉüž¼N%n§Õâ2�º¼¯ âšqÿ¼a™øÚÛeA„P¾ X˜-þ›±bi$ÇÄ�ò3TàâòŒ8¹ì¨B¦F¸ÁÁíŠDxxD�n÷&Fƒ¥r¶?·!ïÿyŒªó÷r¥‰ßlEþà’5+G5SÎ J•Žþ?¥)ÎS®F*FfÃÀ]¨—1%ˆœ‘ŸH [Z)QªA^!G(|……⣬9É×4²÷»$€ü�ãŒoÆ×O1¾?>Ãøü ÆÛ<8þUŒoÆ—Æ3~ãû‰ñë;ŸOŽÏw�Ï/’ü8I¾$?o$ß’Ï/‘|ùa’ÿ”ãÇÁñýàøyãørr¼�?î?NŽ'Ç·Ç—Ÿâø~r|¿s|ÿrŽ/'Ç·“ãÛ�ãíàx;8~|Ç——8¾œÏÌÞ ?�7�Èç¯ùù]�Ÿ?�òóòýòëòõs�OòóFò–?#ù|Cùö Ê{H¹GYn_KŽò.ýèlNìÌLyÔÙ‡ºFß«énì*Vo{O )íh¬EÑ øxkRžã $NŸ |Ùs5Ÿ,}ï”iÓ8T7j�»'óqs�¢– iˆƒ=$ž¦†ý�×ìƒçE®b)(™F2ŠK÷àEÓCŒÉ‹kØÞÐÇžØmÜÆuñ9dð�ô ×F�/òV¬½X:“b`Ò¯uò>ƒ:6Qs 2‰­fe�âå*AÝr˜¬6¦µ‚*¡Nd‘Ü2n³Íý  „]¯W3û€¹Žªgª�Ié§Ú@�Æ‘t¡}Z¤ÊŠ‹({tC7Âz^‘[·e¢ç•Ñà¯Ë¥yÂÙÈÏ”*nG0ïÒ¸ãD{'úK8Ñ^Á‰òN¬'ò«<QžÈwžø)œh'NÌ?'ì5œ°' q¾'Rþ(æöPôW�Âþ| °/Šü@1 ˜,PÌïE>xb<1o<1ž(_ËãOá‰yç‰ò:OŒ;O'ÚGœøšXî8ÈÚ¯–çöKžÉóy®ŸÊ³ý’ç_òü·‘çúŠ<—„üLiy,[†Æy‹„°ºä™ßW U¥�…Qq¸£!w'=Yªú�„�j£„å&Æo�×EÀÁµjä(ä£ãkÅ%䧬&5PÝF„Q ç3Ï�fmÏõÐX•½º®±OáùU�zöÉ!8½'©¤c2¿¸Õ¾³çs·mH¶a( ’Þ™ôõ»³¯Ñë�>´6ùVSUk�õÚvFéd8Xã[84ÎŒç‹Å«²HLvx­KXaX ÿS¶�ižÙ×mËïÉÒúBNØkÉ?Û=pœv—O÷¹än�Xq ›(Dö<;aEãC‘¶ÿºþJ VËNJˆNDw¥-r3å �Áÿ©Ä]• n-Å™µ,`ÂzAS§ÄK@˜=Péü‡½(ûz0Ö~ßK½VrwÑ,Ø¢P=´µW�ËÀxkÐi•u¤Ä%*+ྊԊ«Wâˆlÿõ†�$¦3z?i ¥¸ÇC›hkä@_q*å C°q4XìŠrV7Á¸¤"×VVšåqìñ´˜?�‘LßÐø×rrËcû%k€CÈ•û|áä8{øÿq@(ö]ãÕãUcü– ºôu¯ˆÉé�”šJwHíODnû8)0‘¼I{�ΓïJ¼˜ %ŽGD®º1öG¹/ÒôFÚ‰êe„Ýp°€æ°73™>˜¬ÀCEƒmîkX7$3*™q°JÕ‹Hj™ÁC1öª6öRáÇ’ìX�ªiîUYsОÆ6wYÐLó]š»[ÕÌ«[#Ü©öè?sÑÕ`?©®’þŸÚˆ¢ëÿ­…âð{–‘Á2¥1qË©—Vâ-Ö¡5qÌU$ϼ�ÏÌV�Ú^©âþŸ¨7‹Ð#qå:PZá=2*ÅyØ©‘v'>iQëï¯ög b§ÎÕ`hÞÃp”ÎØhƒ¨¬X x‹�xˤœß[f¡�=þ+ôË~„0Nt“(§ ¼ØwÍ·&Üæ‹ƒ ‚eá@¸|y¤Lò5)…l.¬AFŠP)€ž*Å( ëùÿŠ= 3Û~e0eofµjéjHð �©†µ]t»Ô¾åU:1P—�bC¹×.&dÛ…të™d•YÎÐ}©qÓªŒªŸtÂl§ÑM"ŸÍF?f„;Zœ/Q’T ï€ÙжhCÖ€Ì8)éùIŽvr©­ÅwDµÂÞU²QÆíˆKª€¾Æ4H%”2Qu„îó†s%{¦ú¦–Áýؼb*óöÿöwN¥›�‡™ÜÕ––_¾7ðï©tºL-âÕ¦2.”¥½‘z™D yI¥WÄ=H`Û™VŸOÐÒêÅÞµšO–¾wÊDè8e wýÏ?¨Òº8e‹„O'>­‹ƒœ%2Šü®®¦ˆÌ%ÏQ/©º9ð¾GЛbü†ñ¶7ô±§C·q€B|…�NgeDæ>~\{‰’s­<Ux‰€ 3"‘3_lö«’ýJx±¼3´³‰SAÚȳ«÷ ¿ÚÜ*Ýbø&~šÏW! ±¢°íõ•EÚñlq¤�O:-Ê¨YJQöQ’ÈÊF ^Ö¶Ñà¯Ë¥ðñ»Ê\^8—⻸|Îw ¹7¤}+8F[ûa|½z²ãäu¬RÌ­<_K´²`õ–¼žÿngUÖÙZÝ;«¿VceÅÆÊþ�ÕÑW�msj>ûªùj_5¿®¯G_•´±jƒÆªý\c•ÏÎj|yg5 ³š·ÎjþVgU‡'hn€wtV9§A4:x#Mž‘Ê�ª d=Ù †¢sÕ mlÇ<ØU…©š²Þ ļâ샹&é,Œã±y”Y9†ú’Éê*ïðPtu™ ï "ÇÚ¤fÉå“ájmx„%Z6z‚ä¤ è™ÈÍj˜„6×ù÷*M@‰rYTu‚ìz®:H¿Øî,ÙU¤`„Ãq{jt›ÑW̉³—’ÕÕQþB!jä˜ÌÎôCû—à§PaC _ÃpŸ7Qêî£ge|ôÉvÀ{ ÿ}f1Ь�?\f èïŶ�}+sù_¬ú{�ÉðnÆ™Ü@ˆ˜™ß L†®€#°:öœž7Vm¯ðnæ�3^ó¸­¾’£Ç7/R¢ïÌÝ<Û—¬ôúû,ÑÝ™‹¢zöæÙ9,€¹» glßL‡¸M¼q"O,ÐÝg8·{-ŽÍïãáãÝÖäŠð3–¸Ï`�æùBÓ°Âø™–Ç Œ9ArïÌÿ¯yãÍÐ'yt;çT®�,n8.¯…htÄñï¸ÀmB×(~¬8Gá5¦§:ÆÞtðÖåð*|7ƒ5<ò#(r\Ã;Ýòè{8Yqìkž3oZ5eÚ"q 0m¥ÇÐãu5pqÎÆ%î3¾D[.UQŸú¸Ä×ÎmòŠ  õ»¬a®.tbE ¬Ñ´•þm ÐÜlˆÄŒx‘ûÄ[Lô˜ÉñE¼Ñ5î)ž·Kœ3Zƒ ™±gZãL�VbìþåØéc³³Ðð>¡‹•†]šûÛhŒ…!J=¢µpÜò¸¢õ9#Í3E¡±FÖÆBô=Ö÷­1&îYRŸëò‰Y#õϳ)ï5Ž™7z~xob%1�0¬aŒn•WÃÅ…¯öðó9£X�±½½dô0v�ŠÞÉ ®aÍ‚»ºãWmoÿg¼Ú•ã†a`_¡¸1I‘ Ù&ãI•ÊEÜ{’¸Ð¥ˆÿ&» J¦..<.,àHð…ÝfϦ¨c GWr€Ï¥„KÆb®ª ,5¨Š¶qrlrXÈr4ÀšÂJ\© +‘ '™=~ã;afföw]Q¨p¶¨þ®³Çß$�—°ïšk¦SU‘é'n¢°lv˜$œG`¶&;4¬E— øŸ΄‘@ª*òa7Ý ˜]ïVÕ ÐÃê„|öìlêžÆÚ6ÁA»¯iÐ’®®×<Rkr8²Î±•ÊšµoÜPJ‰ò|—dl¿:�.+15Íç6£!¬®TT ®°šç÷Ù³Ic…’� M-"©Ä$1P»l¦›Hèγɓ²ë]g»`,y«+�}R¥qvb—¦ Íÿ$ùÄ“Y¦»„"˜2ëÎ3b€Ì%NÍ×í.N½ñ$QÝÅȳûìØF¹a>ƒµìÂsQÞ>ÔG–ž&*(Xá¦7NÉDµ9I•e« eÒˆySãI'‡§•Q$“Í mÁ>(Ÿ|â’ØSsöxbéþó¾8 b—]¢«�‘Jˆœò®²“ÇASU0Kàæ8üåòcùƒ îáÛS\~¿]"f€�@ãÜÉŒEöû×uú�J�T ‰@ =6£Ø3š�/ÏËÃÓkXÞ^—ÇçeÔˆÆGp6Xqa7åÁŠ_kuÙUcQψ·#¹¡H‚îé¾î<®w±ºL4—rFQ6ú*»›IÍŠ6wÆÀ\ °@: ´óŠbòž‚tMøGoMœ\gÏ� ÀÖ(D´„J›`…sÔ3�ðØ4•¼Ëæì…" 7¸šËÆdï4Åê)˜hËSpö ZáÎàÉz~SÅO;�@"I6ê”5 Z™=#n†ð ¸[�U¬¼—¦ÓR5+žÉº2(W=Ë�!*àÇZ:Ú‘´ƒxlDz„3ˆ�Ä>*í1&Ïæžµ¹Qcÿ™k�±'¬Q½ ™ßŠÇ8{6y¢;éŠz »~‘,h«$6#œ=¼ ¡ð3æ ‹;u•Zž—û¤þ?GoòT•Pðð ´YnÂ6æmƈÒ6bÌžÍ=¬¥9gm>GÕ#c~�•ÿP]�$ nCÑ ;>®Ço̦�p·Àu(õˆõ�çxÆ3ø]b€=&ê„FšxùûS{Øw€ñè¶°…M5Œf¤¦œ“i¸±ûL(„ÙaŽOüË�é¦OÈeÜM ”ÙÝ"O#é23`W>+è�?_W5%_8FÅ,R¶÷Õ϶�—�óÞ*P¸Ùã ë´aq Òñ9mt˜Ù•«–ÖhèÈ08Ys¬úÊuYŒÀ=NQJv ß}Õ|¨Ë0¸€XìÝîaœšé ¾a„–ïm·�¢÷i‡á1Ýôõ4g߯±A­Û¸. ‰hذ·‰Š`(ö ¸,L`qˆ8ÞÈ¡ÀS,ön¸4HÅ51K—sÄ—Ë/$èã÷¯Ë…™úO€�Õñôš endstream endobj 224 0 obj <</ColorSpace 231 0 R/Coords[0.0 0.0 1.0 0.0]/Extend[true true]/Function 232 0 R/ShadingType 2>> endobj 225 0 obj <</ColorSpace 226 0 R/Coords[0.0 0.0 1.0 0.0]/Extend[true true]/Function 227 0 R/ShadingType 2>> endobj 226 0 obj [/ICCBased 230 0 R] endobj 227 0 obj <</Bounds[]/Domain[0.0 1.0]/Encode[0.0 1.0]/FunctionType 3/Functions 228 0 R>> endobj 228 0 obj [229 0 R] endobj 229 0 obj <</BitsPerSample 8/Decode[0.0 1.0 0.0 1.0 0.0 1.0]/Domain[0.0 1.0]/Encode[0.0 63.0]/Filter[/FlateDecode]/FunctionType 0/Length 206/Range[0.0 1.0 0.0 1.0 0.0 1.0]/Size[64]>>stream H‰�À�?ÿý¾\ý¼\üº[û·ZûµYú²Yú°Xù®Wø«Vø©V÷§U÷¥Tö¢Tö SõžRõœRô™Qô—Pó•Pó“Oó‘Oò�Nò�Mñ‹Mñ‰Lð‡Kð„Kð‚Jï€Iï~Iî|HîzHîxGívGísFíqFìoEìmDëjDëhCëeBêcBê`Aê^Aé[@éY@éV?èT?èQ>èN>çK=çH<çD<æA;æ?;æ<;å8:å5:å19ä,9ä(8ä#8ã7ã7 �é>jò endstream endobj 230 0 obj <</Filter[/FlateDecode]/Length 2574/N 3>>stream H‰œ–yTSwÇoÉž�•°Ãc [€°�5la‘QIBHØADED„ª•2ÖmtFOE�.®c­Ö}êÒõ0êè8´׎�8G�Ng¦Óïï÷9÷wïïÝß½÷�ó� '¥ªµÕ0 ��Ö ÏJŒÅb¤ � �2y­.-;!à’ÆK°ZÜ ü‹ž^�i½"LÊÀ0ðÿ‰-×é �@8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ �V�³)g�B£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚ó�ÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= €x¯Íú·¶Ò-�Œ¯Àòæ[›Ëû�0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±Z�L®Ä„?â_øóyxg)Ë”z¥�ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.ò�ò· �åÒ�R´ ß�Þô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ�;ÂA4ˆÉ 䀰ÈA9Ð�=¨- t�°lÃ`;»Á~pŒƒ�Á ðGp| ®�[`Lƒ‡`<¯ "A ˆ YA�+äùCb(ЇR¡,¨�*�T�2B-Ð ¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°Ž�Sàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4z�BgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p�0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"E�ÒI2’�ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷�?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@� æP+¨íÔ!ê~êêmê�æD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒ�Ó¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™�˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 N'çÎ)Î].ÂuæJ¸rî î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…�EŒ…Òb�Å~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X�[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„�Æfm“�Ž;'_9 œr�:œ8Ýq¦:‹�ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=G</zÁ^Á^j¯­^—¼ Þ¡ÞZïQïBº0FX'Ü+œòáû¤útøŒû<öuñ-ôÝà{Ö÷µ_�_•ߘß-G”,ê}çïé/÷ñ¿ÀHh 8ðm W 2p[àŸƒ¸AiA«‚Ný#8$X¼?øAˆKHIÈ{!7Ä<q†¸Wüy(!46´-ôãÐaÁa†°ƒa†W†ï ¿¿@°@¹`lÁݧYÄŽˆÉH,²$òýÈÉ(Ç(YÔhÔ7ÑÎÑŠè�Ñ÷b<b*böÅ<Žõ‹ÕÇ~ûL&Y&9‡Ä%ÆuÇMÄsâsã‡ã¿NpJP%ìM˜I JlN<žDHJIÚ�tCj'•KwKg’C’—%ŸN¡§d§ §|“ꙪO=–§%§mL»½Ðu¡váx:H—¦oL¿“!È¨ÉøC&13#s$ó/Y¢¬–¬³ÙÜìâì=ÙOsbsúrnåºçsOæ1óŠòvç=Ë�ËïÏŸ\ä»hÙ¢óÖê‚#…¤Â¼Â�…³‹ãoZ<]TÔUt}‰`IÃ’sK­—V-ý¤˜Y,+>TB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%�—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† �ž�kï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»Îå�wW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO�¤[þ˜¸™$™�™üšhšÕ›B›¯œœ‰œ÷�d�Òž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª�««u«é¬\¬Ð­D­¸®-®¡¯¯‹°�°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½�¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ �÷„óû endstream endobj 231 0 obj [/ICCBased 230 0 R] endobj 232 0 obj <</Bounds[]/Domain[0.0 1.0]/Encode[0.0 1.0]/FunctionType 3/Functions 233 0 R>> endobj 233 0 obj [234 0 R] endobj 234 0 obj <</BitsPerSample 8/Decode[0.0 1.0 0.0 1.0 0.0 1.0]/Domain[0.0 1.0]/Encode[0.0 63.0]/Filter[/FlateDecode]/FunctionType 0/Length 206/Range[0.0 1.0 0.0 1.0 0.0 1.0]/Size[64]>>stream H‰�À�?ÿh j k m oprtuwyz|~€�ƒ…‡‰ŠŒŽ�’”• — ™!›"�"Ÿ#¡#£$¥%§%©&«&­'¯(±(³)µ*·*¹+»+½,¿-Á-Ã.Å/Ç/É0Ë1Í1Ð2Ò3Ô3Ö4Ù4Û5Þ6à6ã7 �ÏÔ6@ endstream endobj 235 0 obj <</Metadata 236 0 R>> endobj 236 0 obj <</Length 36847/Subtype/XML/Type/Metadata>>stream <?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c137 79.159768, 2016/08/11-13:24:42 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/" xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#" xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/" xmlns:pdf="http://ns.adobe.com/pdf/1.3/"> <dc:format>application/pdf</dc:format> <dc:title> <rdf:Alt> <rdf:li xml:lang="x-default">usenix_logo_full_color_tm</rdf:li> </rdf:Alt> </dc:title> <xmp:MetadataDate>2016-07-28T13:48:14-07:00</xmp:MetadataDate> <xmp:ModifyDate>2016-07-28T13:48:14-07:00</xmp:ModifyDate> <xmp:CreateDate>2016-07-28T13:48:14-07:00</xmp:CreateDate> <xmp:CreatorTool>Adobe Illustrator CC 2015.3 (Macintosh)</xmp:CreatorTool> <xmpMM:InstanceID>uuid:6be068a3-6f66-e14c-a412-1d9510750738</xmpMM:InstanceID> <xmpMM:DocumentID>xmp.did:047e04d2-fa69-4b26-9428-764c0547b43d</xmpMM:DocumentID> <xmpMM:OriginalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</xmpMM:OriginalDocumentID> <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass> <xmpMM:DerivedFrom rdf:parseType="Resource"> <stRef:instanceID>uuid:2e734826-cf82-ce45-903b-dfd35b207876</stRef:instanceID> <stRef:documentID>xmp.did:5f37efaf-fdf2-4ef4-b6c7-a42aed802ebd</stRef:documentID> <stRef:originalDocumentID>uuid:5D20892493BFDB11914A8590D31508C8</stRef:originalDocumentID> <stRef:renditionClass>proof:pdf</stRef:renditionClass> </xmpMM:DerivedFrom> <xmpMM:History> <rdf:Seq> <rdf:li rdf:parseType="Resource"> <stEvt:action>saved</stEvt:action> <stEvt:instanceID>xmp.iid:01801174072068118083C67C01A9FAB7</stEvt:instanceID> <stEvt:when>2011-10-17T00:16:06-04:00</stEvt:when> <stEvt:softwareAgent>Adobe Illustrator CS5.1</stEvt:softwareAgent> <stEvt:changed>/</stEvt:changed> </rdf:li> <rdf:li rdf:parseType="Resource"> <stEvt:action>saved</stEvt:action> <stEvt:instanceID>xmp.iid:047e04d2-fa69-4b26-9428-764c0547b43d</stEvt:instanceID> <stEvt:when>2016-07-28T13:48:12-07:00</stEvt:when> <stEvt:softwareAgent>Adobe Illustrator CC 2015.3 (Macintosh)</stEvt:softwareAgent> <stEvt:changed>/</stEvt:changed> </rdf:li> </rdf:Seq> </xmpMM:History> <illustrator:Type>Document</illustrator:Type> <illustrator:StartupProfile>Print</illustrator:StartupProfile> <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint> <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency> <xmpTPg:NPages>1</xmpTPg:NPages> <xmpTPg:MaxPageSize rdf:parseType="Resource"> <stDim:w>170.000000</stDim:w> <stDim:h>60.000000</stDim:h> <stDim:unit>Pixels</stDim:unit> </xmpTPg:MaxPageSize> <xmpTPg:PlateNames> <rdf:Seq> <rdf:li>Cyan</rdf:li> <rdf:li>Magenta</rdf:li> <rdf:li>Yellow</rdf:li> <rdf:li>Black</rdf:li> </rdf:Seq> </xmpTPg:PlateNames> <xmpTPg:SwatchGroups> <rdf:Seq> <rdf:li rdf:parseType="Resource"> <xmpG:groupName>Default Swatch Group</xmpG:groupName> <xmpG:groupType>0</xmpG:groupType> <xmpG:Colorants> <rdf:Seq> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>White</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>Black</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>100.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Red</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Yellow</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Green</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Cyan</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Blue</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>CMYK Magenta</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=15 M=100 Y=90 K=10</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>15.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>90.000000</xmpG:yellow> <xmpG:black>10.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=90 Y=85 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>90.000000</xmpG:magenta> <xmpG:yellow>85.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=80 Y=95 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>80.000000</xmpG:magenta> <xmpG:yellow>95.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=50 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>50.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=35 Y=85 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>35.000000</xmpG:magenta> <xmpG:yellow>85.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=5 M=0 Y=90 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>5.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>90.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=20 M=0 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>20.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=50 M=0 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>50.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=75 M=0 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>75.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=85 M=10 Y=100 K=10</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>85.000000</xmpG:cyan> <xmpG:magenta>10.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>10.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=90 M=30 Y=95 K=30</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>90.000000</xmpG:cyan> <xmpG:magenta>30.000000</xmpG:magenta> <xmpG:yellow>95.000000</xmpG:yellow> <xmpG:black>30.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=75 M=0 Y=75 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>75.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>75.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=80 M=10 Y=45 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>80.000000</xmpG:cyan> <xmpG:magenta>10.000000</xmpG:magenta> <xmpG:yellow>45.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=70 M=15 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>70.000000</xmpG:cyan> <xmpG:magenta>15.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=85 M=50 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>85.000000</xmpG:cyan> <xmpG:magenta>50.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=100 M=95 Y=5 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>95.000000</xmpG:magenta> <xmpG:yellow>5.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=100 M=100 Y=25 K=25</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>25.000000</xmpG:yellow> <xmpG:black>25.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=75 M=100 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>75.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=50 M=100 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>50.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=35 M=100 Y=35 K=10</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>35.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>35.000000</xmpG:yellow> <xmpG:black>10.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=10 M=100 Y=50 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>10.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>50.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=95 Y=20 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>95.000000</xmpG:magenta> <xmpG:yellow>20.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=25 M=25 Y=40 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>25.000000</xmpG:cyan> <xmpG:magenta>25.000000</xmpG:magenta> <xmpG:yellow>40.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=40 M=45 Y=50 K=5</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>40.000000</xmpG:cyan> <xmpG:magenta>45.000000</xmpG:magenta> <xmpG:yellow>50.000000</xmpG:yellow> <xmpG:black>5.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=50 M=50 Y=60 K=25</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>50.000000</xmpG:cyan> <xmpG:magenta>50.000000</xmpG:magenta> <xmpG:yellow>60.000000</xmpG:yellow> <xmpG:black>25.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=55 M=60 Y=65 K=40</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>55.000000</xmpG:cyan> <xmpG:magenta>60.000000</xmpG:magenta> <xmpG:yellow>65.000000</xmpG:yellow> <xmpG:black>40.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=25 M=40 Y=65 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>25.000000</xmpG:cyan> <xmpG:magenta>40.000000</xmpG:magenta> <xmpG:yellow>65.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=30 M=50 Y=75 K=10</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>30.000000</xmpG:cyan> <xmpG:magenta>50.000000</xmpG:magenta> <xmpG:yellow>75.000000</xmpG:yellow> <xmpG:black>10.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=35 M=60 Y=80 K=25</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>35.000000</xmpG:cyan> <xmpG:magenta>60.000000</xmpG:magenta> <xmpG:yellow>80.000000</xmpG:yellow> <xmpG:black>25.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=40 M=65 Y=90 K=35</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>40.000000</xmpG:cyan> <xmpG:magenta>65.000000</xmpG:magenta> <xmpG:yellow>90.000000</xmpG:yellow> <xmpG:black>35.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=40 M=70 Y=100 K=50</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>40.000000</xmpG:cyan> <xmpG:magenta>70.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>50.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=50 M=70 Y=80 K=70</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>50.000000</xmpG:cyan> <xmpG:magenta>70.000000</xmpG:magenta> <xmpG:yellow>80.000000</xmpG:yellow> <xmpG:black>70.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>PANTONE 186 C 1</xmpG:swatchName> <xmpG:type>PROCESS</xmpG:type> <xmpG:tint>100.000000</xmpG:tint> <xmpG:mode>CMYK</xmpG:mode> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>81.000000</xmpG:yellow> <xmpG:black>4.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>PANTONE 186 C</xmpG:swatchName> <xmpG:type>SPOT</xmpG:type> <xmpG:tint>100.000000</xmpG:tint> <xmpG:mode>CMYK</xmpG:mode> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>81.000000</xmpG:yellow> <xmpG:black>4.000000</xmpG:black> </rdf:li> </rdf:Seq> </xmpG:Colorants> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:groupName>Grays</xmpG:groupName> <xmpG:groupType>1</xmpG:groupType> <xmpG:Colorants> <rdf:Seq> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=100</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>100.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=90</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>89.999400</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=80</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>79.998800</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=70</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>69.999700</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=60</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>59.999100</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=50</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>50.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=40</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>39.999400</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=30</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>29.998800</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=20</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>19.999700</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=10</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>9.999100</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=0 Y=0 K=5</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>0.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>4.998800</xmpG:black> </rdf:li> </rdf:Seq> </xmpG:Colorants> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:groupName>Brights</xmpG:groupName> <xmpG:groupType>1</xmpG:groupType> <xmpG:Colorants> <rdf:Seq> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=100 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>100.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=75 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>75.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=0 M=10 Y=95 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>0.000000</xmpG:cyan> <xmpG:magenta>10.000000</xmpG:magenta> <xmpG:yellow>95.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=85 M=10 Y=100 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>85.000000</xmpG:cyan> <xmpG:magenta>10.000000</xmpG:magenta> <xmpG:yellow>100.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=100 M=90 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>100.000000</xmpG:cyan> <xmpG:magenta>90.000000</xmpG:magenta> <xmpG:yellow>0.000000</xmpG:yellow> <xmpG:black>0.000000</xmpG:black> </rdf:li> <rdf:li rdf:parseType="Resource"> <xmpG:swatchName>C=60 M=90 Y=0 K=0</xmpG:swatchName> <xmpG:mode>CMYK</xmpG:mode> <xmpG:type>PROCESS</xmpG:type> <xmpG:cyan>60.000000</xmpG:cyan> <xmpG:magenta>90.000000</xmpG:magenta> <xmpG:yellow>0.003100</xmpG:yellow> <xmpG:black>0.003100</xmpG:black> </rdf:li> </rdf:Seq> </xmpG:Colorants> </rdf:li> </rdf:Seq> </xmpTPg:SwatchGroups> <pdf:Producer>Adobe PDF library 15.00</pdf:Producer> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="r"?> endstream endobj 237 0 obj <</Ascent 881/CapHeight 674/CharSet(/B/I/N/S/a/c/colon/e/eight/f/g/h/hyphen/i/l/n/nine/o/one/p/period/r/s/seven/six/slash/space/t/three/two/u/v/w/x)/Descent -250/Flags 32/FontBBox[-46 -250 1126 881]/FontFamily(Myriad Pro)/FontFile3 239 0 R/FontName/KGORFR+MyriadPro-Regular/FontStretch/Normal/FontWeight 400/ItalicAngle 0/StemV 88/Type/FontDescriptor/XHeight 484>> endobj 238 0 obj <</Filter/FlateDecode/Length 288>>stream H‰\‘ËjÃ0E÷úŠY6‹ ¿šCIRð¢êöiœ jYÈÊÂß‘&¤P�4GÝat%í±µ&€|÷“ê0À`¬ö8OW¯Îx1Väh£Âm—V5öNHwËplí0‰ºùAÉ9øžôtÆ•�o^£7ö_‡n²»:÷ƒ#Ú�4 h¨ÐKï^ûA&ÙºÕ”7aY“æïÆç⊴Ϲ5iœ]¯Ð÷ö‚¢Îh4P?ÓhZý/Ÿ—,;ê»÷¢.âå,£@|d>—yb Äs¹d.#o˜7‘·ÌÛÈ;æ]ä=óž¸â:U¬Sñy•ÎOÌ'âG®O!6ë2>ƒÜ†»Gêê=Ù“¾$ù1ï¿æ&¤ŠSü 0�‹Q endstream endobj 239 0 obj <</Filter/FlateDecode/Length 2829/Subtype/Type1C>>stream H‰|TiTÙ®¢»ªAMOìšbÆ.§ª#ê@@7dqAZF%n@·¬v³)A3*Kƒ� ˆ²ŒÈ*ƒ((¢ Ê.  ‚qcÆIb¼…sR­?sNÎ;ç�wï{ï»ßûÞ½ÇÄ&ŽãÓ<×lðvõž³nŸ&ØO奉˜ë­ŒóÓ7gò Î)æ§O¡·£ô÷ïßÄWVvÿw�þÔL½9}²� 3ÁñsE+#"€À (…e€•ÂÎÖÖV±\á¯V(÷i£Ô{´ ÷ð€Md„Æ/J­²V, Sx�kÞj­ZctúX+­^Â�ð(Å*µÖZ©W‡Zâ¦Ö*üu`°€¨Q«Q?•z�Ÿ&T±ûÿE³qUnÚ©V,V¨Ô»1 &5Ád&ØbÌÃþˆa6f�a+0l†¹Š±u¶ÁS’˜… ‘`ya*ì;ìì&Nà!øcÌ$Éä?¢Å¢Q£˜G‰G‰¯‰x¢Žt#ÓȲGÂH¶IšM'›î2=o:f6Ûì¯f£I©õüX=.Ì3ëE©b>iÜk"‰„tÔD£¥p‚€$R ŒÆÄqɹãã–"Á&ù´q…Œ–]•¢-p¨¿©¢‹ÐH{Bj«DŠêt ÃoÀdˆttyÞ�å—´AAšÈÀÀ¼ÈRNŠìÇ—Çâ)ðFÔ@CÉx0áJ¢¢Á„4'†oJ�•�n˜º:óáqÖ…¤ºÐŒeYn@Ü!ÒHij/ºÞ âw™÷¢«i’ëµ|_>ƒ)ò^¯çâ¾{'{a‘±îâÏÌXÑzw«e‹�#²ã\݉T× kU· žŽ¸�R/ªJè˜âÖ¨^l†Fÿ5êÑì”É¥I¨ß /ßî”lìCŸ¯v×h‚Ø<O"ûB}î f°dû楎!žœ¯{I½RÙê¹MúÀUH̬óÎÏÔpR]'4u€u?^úrGD¼ý¸%�rt/ç�¸2Äç[SϳÑçrä<Š0`aú ˜À�9>A’•›‚ýÂØd2°ž7À�Ï?–›v.Å}3q�¶Ùúè] wöØéïO²µyõÅ Ì`ƒÒÚzËZΨßý^œŸü\t{œ¥W@w²•NôÏH(çGˆ&áé­|U‹ìÒ3÷' v¡z©~È·¢i¿z¦²HÙÌ%I¨‘%Á¾^òo†œ`:ü~ì�·69³éªÿÑ¥ Í�ò!χHÆR#ßM¼¥¶6µ¥sw/_ï;Ï4�*g¹Ûß%,ÕŸÆWÑ‹|6{í PÆq.Ù[Ëôm¦·*k{Yib8t@]^i€ŒÑëD:;¥0­øØ½]Eõµ¦­wk߀…œÞ¡ihÚ<„!)?˜fí7 ®–³éäÁ¥aÊ]»ƒþ³åðž£Ñ)qzS°ç éçU‹�8…KHJ<úV¥ÝîÅ,ó½=ø¼¡ý>÷13§BLÅ`’ÄðŠ.Ïý±ìRTA`°fïî czêÑ¿ÿ×)ýép'd´AT‡¬ï)D�¸=§Þö¥ÑG kŽ63`Ò—}¥†++ɽÚ$ãÒà™iŠ¿—õv»¼!º2¨€-õWfÚ3Ö>¤æžn¤Ó3rÓ+ÃÏ¡Î>¾¶ÜÒCÜCRo_ ¨l­‡Ì ÓêÓ÷ l³rbÆÆâ ¢ã é ã %R°IÒ:†o}'Jß¼¢¶��9\–Pa N<2̦ëKVT/½æ2 BÐ+B¸å€ÊI*Ë"ÍáÄ<6)%¬+ Ûw` …—Äœ Iibb/_Ó+»e€=ª¿ª”Ö–wǶ10¿oôŸ¿zßDd5g]î_tW^SÖøüNuÜ�–ªÎë!¨þ³á[ήaÐöÎ3ævn57\¾{­|Íæív”?ä©XiŒ®-$RMVf€�ªŽ·ƒzz,ð7dµÞk¿&€Íö"rK¯�©a~ÕŸZ O”  z Od&_]ïúKWCiE�ðåÔŸO¬'È#%É—«ä ®ÑTÝ¡”ĤC¬‚€'³S]Ðôð¬×ÉœtSb7�ÝÃ+„²ûú ­Ó„ÜÊÌYÙâ7Í�AT[rP—Ãewg´ÛÏlf�Ý,„#+dùÊf·]Ï:•ËI“»À©,ZðŠa89,âý!†N;©?sN>â²C°G4Ízf –ý7³2ŠØø"!T¥[ËÌw©ƒIÉœ¾…¾s¼bèóKž½2EøÎ@¡<t€c7>h�³9¿�L;�Y�ä~vûý‚¬#‡3ØS�Äñý{�‡2;„†pþªøukäQnn $Ò[HÝ3:à}§.VV1ùjŒ�‡·45ؤ¯L/e�Ij,i‘L^ŽÞqeƒÄ ´1ŸS4”Wpiß’è3÷mó6l=—ÊF¯!öþÔšÐÄÜé̼RËÕ\Éí�±|>L§ã“÷I`½÷ùobæú>z Ds÷“¶*¿Íg¹cõäÒÂ[{!4ï5€Î ê57@5™¥?óýi¶6ëjåmæq¡‡3‡Š Bb‚“E¥GHØ¡ø½ldBtT‚Æ4ç“Rt^@‰‹ý಻€[¨°Àœ�›?'4ß+| ]š“_X�­ ÏÑ "f 5ákŒj 9î+ ©8õ’|dBõ¢’‘vöØ)¶îlõe#÷OTª$àhQ鿤ܱC+´WªúÈ�áL¦è¶È¥5ºv~R;^ñ jž‰ OGƒ¦þ—¤j i* ìq¾™Ùùái17Øñ‡$¤¦d˜Â,‹щ¶²ËÄiÛŸ¢ònêŽ[SCçÜV+ÝfÛ̘©E^jŠ£¼†e:´¬à ”’n’ß‘O¨3ûûÂsƒ÷}Þ9˜ C#~"‡£ñ+ î%�Sܘôù?+îo¿×ûBâбè0‰O¡Äk0}šfÏü7Óý…X›ER®Ú «óe>sPØÆ2<C£¿#ÿø“—Ò/’Œ‹Ïµ ˜³õçÓø^×l´ÌBbÍcë¬ÅîGìÌ£Ò2û_W’Z³Îjáãè:ja[‡˜ö%¶€f}³Á*œ´ <{#°4êt�äG_sC_-ÈÈ”§”’Z@ôÖ}ÅŽ�£L/•ðñà*&ï$kt -±]NnY× j”qè_~ŸÓûˆ·å;\üžŽ‡#în¥¦EØ:�Ù s­RAHjj¼¤/Ë{™|[ÜVz�/¿zEœ“í°q”P5 7<¬Õeö*=Ã=˜�üÙ8’¦\g�°¤õ±ªOÐÕn2ÙÉ:V§VÕ ¤Ê®qZa B?þ\3+÷-EàŒVz 7]D—s£Ñ Pj©ÚëB%—gDy+$¼�z8ÌûÌý´<2üô¾Ð�ˆò["lhŸè†ùxiƒ7y›ÊJˈ+ÃÅ[åØ"€º‹ȉ½”L¥Ð(ü´ Ê¥vQîpèäáPÕ°ÇW™‚ulž"z>è>:æ #¦í#w‡-¯ü À"iβŸþ€(Þ<€Q ë!�„ê(‰ú\�4H 4ƒª‘бXË;DHG�¡Îj|óê!õ°úE ¬çáŠV¦Ë`Së�ζù”bQJ@ ؘ�,G§ý�­3È�ìy¶‚–üwˆÅûP<4Â8¨ÆÂ@rˆ²�*¢òVª£ÒYÑž´ÎÃ5æÍ ’™a¤yмUrÐ)&$6må›Ý¦NGØš›XÝü7`§Çß»Ë{3`7Ý´‡nàþ`�Lb‡æ endstream endobj 240 0 obj <</Ascent 889/CapHeight 674/CharSet(/A/B/C/E/F/I/K/M/N/O/P/R/S/T/U/V/X/Z/a/b/bullet/c/comma/d/e/endash/f/five/g/h/i/k/l/m/n/o/one/p/parenleft/parenright/period/quoteright/r/s/seven/space/t/two/u/v/y/z/zero)/Descent -250/Flags 32/FontBBox[-71 -250 1198 889]/FontFamily(Myriad Pro Light)/FontFile3 242 0 R/FontName/KGORFR+MyriadPro-Semibold/FontStretch/Normal/FontWeight 700/ItalicAngle 0/StemV 124/Type/FontDescriptor/XHeight 487>> endobj 241 0 obj <</Filter/FlateDecode/Length 430>>stream H‰\“ÍjÃ0„ï~ ›CñŸ´jÀJÒBý¡iÀ±•ÔÐÈFqyûj4¥…l¶vG3f�¯·›­f•¿†±Û¹Yßw/¡sjÏÊJõC7ÿ<¥kwj§,�Í»ëyv§­?ŒYÓ¨ü-.žçpU7÷ý¸w‹, ½ ƒ?ª›�õn¡òÝeš¾ÜÉùYjµR½;D¡§vznONå©ívÛÇõa¾ÞÆž¿Š÷ëäT•žKšéÆÞ�§¶s¡õG—5E<VªyŒÇ*s¾ÿ·®5Ûö‡î³ YS¡¸(â-òù¼$/Ákòü@~ˆ\³·Fo]’KpE®À†lÀ–l#kÖkÔëš\ƒY¯Q¯…,`úÑð£7ä ˜~4üèGr Þz3ðf¨o o4Yƒ¹—Á^†Ù ² ½ ¼ ³²u:B�ŽPG #ô,ð,Ì+È+Ô—¤Ï,‚,Âo+ø¶Â,‚,Â,‚,–Y,²Xú±ðcéÇÂ�¥ ?–~,üXîe±×½UQ&6‰+è,…ïë40?“�щ®~ç²»„G2ýi1…ƒw¿Ê4N*vá̾�&SÓÿ endstream endobj 242 0 obj <</Filter/FlateDecode/Length 3890/Subtype/Type1C>>stream H‰|”yPYÇ» ý®FÉv &­ƒâpÄ *Ã"$ ˆÐaftäŠ×ººƒаÈ!ˆº ЏZxÀÖŠ8ãÍ.º*0*×õ×Ù‡UÛkþ�ꪮwýŽú~?ï‘„µA’¤låÒ5K"ÜWåéSâ5ázÝ—jíÖ”]šÆ²;�““œÌšs±gB±ÑÅúÌÿ¨Éqæ¡ìw„¾‰/]&Ìu"¬H²¢~‘.ƒO‘¼9›�™èÆúxyy±Á]‚–Uçeek·f±ËÓuú �>>[«ñ`ƒÓÒØËñ,6B›¥Õ,‹ë<Ôl8 =› Õfy°ÚtMJz²ÇçîØ”,6žÕk“SøŒz­†ÍÖÇk´[ãõ[X]ÒoUó\¢ŽÌËвþ¬F›D$ÿ"+Â�  b¢!!)ALµ"¦“Ä,‚˜MÂך ˆy""Â(BmMD“„Ž ² BÅKG¬"‰ âq�#Ér'yÝÊÅj¡•Q€ëù‚*A»à½u”uEPë©NÄ¢ d@­B;¡�°V$%ŠîÛ̲Iµùh»Ð6Ïö¢í»5våvö«ì+ìÁ!Àa¯C7ÍÒ‘t2]–tro:IþïÚ)(±æöšÃÇ÷"0ânχC #Ìâ« X&ã…ã(ö—1ÌÇüq]Œe„-3zÜ•æb PœCÖA˜`ļ€Ù˜133øÁ!iËí¶±Ú!�oÌ2�·Gf^ά Ã’b%Âëzñ¤îyŠ(ìu4L‚Å2Xv ¤½?+>�ËGØ`[¦{ ˜RØ ‚¨• YûXáƒzÜ/ãIx‰ /‰ÆÎa³ô y¢C˜bZ{Û€¨ÁL¡4ß?cjÆ]�>ä˜-�qsñtS{GZClÜ–Ô�±õ)mJ:´`„Ë!›Àôà(€Š¼žò%�:Xì�gÏÁr§ÄÑ¥O° ¸É�#ÌÒ¸gàS¦�¶gw~jöÁîØ+É7XA‡VÌŠ ÀN�°3+¦!ìTåv7©2D‡–˜¸MïHåKq9>^&¼~™ôa`„²ÿ.~…]BÓµ1Šf?êT㥺nù`}T¸²x΢ ü%ž2‘4XÈ÷üö ƒxŒ„ÿ€“€ÛhV0ø%ŠÇO)ã©Zc‹˜kÑ ç/IX®>þƒN©÷ r›zrÈÁ÷½ &<N¾]¯¬Û´öh„<7¿¸h§ò8H(0"KÿÜEy•[.¸Êçœ7‹„¸v¼� ‚Z®�z$¤ëª  †ö·%9NUÜ ñCÎÔÌ-¬¦@Š°Î¬¢°7ÂiŸTˆQ7¨©Êa¦ )ñð‘s‡;·ŠÊÐaÍŸ6M¸Š¥tÚwÃ�õ"^9õ Q0a*0âýeÌ÷ WöÜ‘óÍV]¸¤<ÛPÓqS6´âzh…Â(s?Ö¶^¿-ëֵşRÔÇFñ–/ýî[�è@Æx´ª¬YþèRúʈ˜Ä9Ê0äc} ‰? öm ššþ•ÎPbÜ¡¤s ßsù¦ô§3 ÷qõ`ÃìLÝP-ÇnsF`&¨FŸÁäkí»v6(Å-5o)qßQ}Dy '`OìŒõ8$X©½å®SÒž%&ˆ~!&²ßâl$÷ƒBœ0�»|Rqî&ÜÑpÑn¼zçÞÁêÏû%<vç ô.…ÕPi—!¿æ!Rå|Þ7«˜O*p4«„´þ×eÚFC!ºu"ðm \.á&Áà…Ý^Œ wdoÏÚ‘é¼z0�hÈàm½"òoæD�yŠì‘Æb“òÀ'3¿ÊöÏ qÞ‹¶ß7<Ézì ÕR¬B±û„è¨Þ?´ï£ñßÎe¨bnµgÍœ—ø¼t�BûéÁ¿¼:1àlDÅžû¿Øç'¢ûø"50�§â. ¸ HÜaØ-?AÑ‹=ÏûJ´ü5ØBq'¿3«0»�k™ß}EÅi?&>Š»ïŒCà…§|R!úMÁ(·g”l g˜ø»“�Db¸á(Á?3xW¾{<ÔÊý£ ¶] È@Ö 6¼¾Ž=Ø‹ñ”eØ Û)éßó_Ã7?[¤ͯrBß«,>)þ úr§²¥¹²«WÖ“y5±QѼiÅqoyÀêÝ߯ò€ùñ€U›äƒ]‰ÁAê�žúÜÒý<OZ>ëé— þ%kâgoi8}Ý-ª×UúVÌ=y8GN(¿&ïѶíø{zGt…È(ì=qãÆsY·¡#©^qvãŠòYòÐ¥»¿‰á+ÍeŒGN[åO®lYç¯ A´o¡‰+0¥æ8uÁDX ÅÏ70ÛZ~ʹ'‡à�a _«o`›v¥w“¦ºKv®ñü£žŽÜüS q{Ý;JüðØæõå!r<ÃÓ Üû×€µF9˜Ö´5J—¶ºò¤FAð>ÞyOBŒå5ŒáåîÀú÷ã\!Ñ7xGþ™CÞåemä÷ïò|ŽK„x³É¼@õq4 ŽÁŽã“…Xº~µ�ä-�*¸ÉBzw ÐÓ-�;äߌ ÎJ;- NBnø%nÉ ÐäÍ¡íO³gzÂM)–!Hç9¤óymÏ8ï²’»"àú%üå{ _Ã�� Z„•†„�[óâ-ŸÝѸíB(¥x*‚uøŽÁ#LAÿ�YmWEsy+Ïq¥æxr݆{X&¥JƸÔ1²†; ¨‘pÆð[#ú?ÑUÕu†;�Ü; 8<åf,™kïµ´F„qM¢«‘%1jªì"UÙf 3̈£0 ‚"²(«ì2ƒâŠU—Ú6’(‹ˆ€¦iü®Ï™>íHžþ¸νç;ßû~ß÷¾çÂ$—G<´Ä/ƒ{4cQBgÅØn)¨žLŽ:\À5õ;ÊÄ}]¢7¡³ÈÝÓ_šv€9»‘8]o>ÙC�%±ì—´]‹xþH(Þ|uëÌ�Þê–Zæ(IeÀ'óêÔ�bÊ„ìúDªBU�Š9(?»‡Þw¦çoß•�jXašbÚWʽÿ¢Ó0Û \kÓ�,QÙ{Õêæß$eÒ?ž²£ñZÊ_iø%ðG᜵ëgÑBz‹$.ø«†NdO‚½åQ©Î +fúŒÝMfúÛ6¯uÎÁŸyJ›Ì9¬ºXSR"¢ÕÊi¸÷²Ð*‰X])SâTô‡¾×_±ãškC/èÎZ•² â™I,ˆ¥ !%¡4Ú´è}ä:»>èï5–žc…IŠÙíRnù”5ùFܨÙ`�[ò6H„jÕ‚¦´ êí4²]æ‚>Ô²ÈeÂlïßlè«et˜!½'<R]¯î3‹¹ÜK"Ê”£‘(‰<,zív÷ùóÎûß\»¸?ØÀê”Ú¥X讜‡Xø”× lø\ D‰0èòJñ›@,Ö«‘ûÇX°ÀOºÀêû7ŒåíÌá§DNT¤jí±­e¬€yÇ|ìÂÐßéo+6‡â 6< ì,™á=±CØbŽýqbi•àVEoå©#ùẻ)BŸ‘¤�¡#öæD`#"3ýýÅRŸ•V ŒFQS`;·_(æyHÅ<LsEðJD êZuõÌR’šÎ÷%ÔdkjxÓŸ0)¿sAk3²Ý5ÕvÔ°ºÒiGÄÆÏ¿.�c݈äöÙmzðAY—™íí>ýè{1²'‘L“yD΄Ê"…ОƒßÍöÞºÜjd�*µ ¹XxCqz… ³vS †3`õž.Ò¨5˜æ²† =ô½s^,ª¶z’�Ü×^ý(.þKY2“œ#ÍÈNµQCn&!ú‡ÊJï9Üýcš„�‹¹,\ª,õú6×'j¯®kb[4Iµô¾„ø¨Õ‡ÚX«õá}P0—vZÛÁþ?Aø´ d› _µb ÀöµÚÀ‚äL¢…h•<S&•g¼§Æÿ ;`Ðünkòoƒ¬é@Þ2…uLìÀ{þyw 5Œ?±ƒ6²LWVddêKÏ7uÓ׫ƒ¼YԈ׻eºSw£ñ|];}³&h‹Îàu+î�¯nܧÌH`Òdé陉X“ú¤{šüè�ÂB£RÙ<wy 'R¡ Þý3±Šù)żRÿ˜#¶|²¨„i664šèÁsLl ^o€Ûš«ë7HB¢Ò«+ï±ôçXáŠqx:Ž;˜‚\ øP�ýΞ`HÎ.ߣeh¹Ó Ü«Þü~Ãm ~ðb¸ñÙèÓ†5›œ÷z{aÙ@^RØ1÷§ÿ×�é´×蘎Ü_Õ›ÔOøÏ`+|àö½³yWÜX5I ç=&Ð/H]ˆ.ÐO ö!"jºÏO �Kͽô7í^ë\C|=~ ƒÆPŠE£ç@ H¯™;�2ΡדT?n,��¹fhk¾AŸ4hÔ–2‚@@õ딹Z9-ÙuÐ;ÅÊfmþñ[òh¸6ÈÇÛ¥ƒ‘Qž ¼Äw観¢ô¦+²›øB;tgœÕ<ŒìZ}ÞæÓÊÔ²ó⺳g:;Z³äLÕq*>Ø@#b«Ïº�§bÙ[iY1âØ”Ô€0É×_%⿊båk¸>Á�Eüî±È}ÛÊ!”!ð+ ­N`’+›³»é–zýñrV=I‘É5itpVÝ-K‰í²…_ „QŠWÞÖv¸ƒ~�±vq. ÷0ºDÊÔ²|%+�Åúä›ty˜…r¼~Q€Ö KÆÆzÌ §­òŸ¡ßB¼!Õ­êžb¡s!,p™‹g಩D>–,‘ð—E é� ±5æ„)¢T‘6¤ªUyQÖñG(t.u•r¯Óy'¸,þ ëFoËnâ˜\››/Î+È=¢b2câS³“'+¤ù5¿w¬+2Ÿ2µ_7w ‚/¶°gŽØx7!£2Nõ—ÜD윹ՊfeÝZ(s¢U…3Ð9ƒ½Ö�_±˜s›AÅ:²ê\eÍÙZ؇[¯�…Z�œ MI>„üPNbÿÉ«ãüùuÐ-òàüñoºN âµ€Š«°B \¹<8(¹ìã ñѲÞWþ|—* o×—¢ Rp5˜K,)z’óÑ#?½%ÁÐ¥¯Ò æ_‡`¥Ád°¤·á|õÈþu­Þ–9î¥*û¯�íİ_öÇíií„ x—ûAô?��Âð� endstream endobj 243 0 obj <</AIS false/BM/Normal/CA 1.0/OP true/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op true>> endobj 244 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 245 0 obj [/ICCBased 246 0 R] endobj 246 0 obj <</Alternate/DeviceRGB/Filter/FlateDecode/Length 2574/N 3>>stream H‰œ–yTSwÇoÉž�•°Ãc [€°�5la‘QIBHØADED„ª•2ÖmtFOE�.®c­Ö}êÒõ0êè8´׎�8G�Ng¦Óïï÷9÷wïïÝß½÷�ó� '¥ªµÕ0 ��Ö ÏJŒÅb¤ � �2y­.-;!à’ÆK°ZÜ ü‹ž^�i½"LÊÀ0ðÿ‰-×é �@8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ �V�³)g�B£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚ó�ÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= €x¯Íú·¶Ò-�Œ¯Àòæ[›Ëû�0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±Z�L®Ä„?â_øóyxg)Ë”z¥�ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.ò�ò· �åÒ�R´ ß�Þô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ�;ÂA4ˆÉ 䀰ÈA9Ð�=¨- t�°lÃ`;»Á~pŒƒ�Á ðGp| ®�[`Lƒ‡`<¯ "A ˆ YA�+äùCb(ЇR¡,¨�*�T�2B-Ð ¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°Ž�Sàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4z�BgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p�0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"E�ÒI2’�ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷�?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@� æP+¨íÔ!ê~êêmê�æD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒ�Ó¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™�˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 N'çÎ)Î].ÂuæJ¸rî î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…�EŒ…Òb�Å~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X�[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„�Æfm“�Ž;'_9 œr�:œ8Ýq¦:‹�ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=G</zÁ^Á^j¯­^—¼ Þ¡ÞZïQïBº0FX'Ü+œòáû¤útøŒû<öuñ-ôÝà{Ö÷µ_�_•ߘß-G”,ê}çïé/÷ñ¿ÀHh 8ðm W 2p[àŸƒ¸AiA«‚Ný#8$X¼?øAˆKHIÈ{!7Ä<q†¸Wüy(!46´-ôãÐaÁa†°ƒa†W†ï ¿¿@°@¹`lÁݧYÄŽˆÉH,²$òýÈÉ(Ç(YÔhÔ7ÑÎÑŠè�Ñ÷b<b*böÅ<Žõ‹ÕÇ~ûL&Y&9‡Ä%ÆuÇMÄsâsã‡ã¿NpJP%ìM˜I JlN<žDHJIÚ�tCj'•KwKg’C’—%ŸN¡§d§ §|“ꙪO=–§%§mL»½Ðu¡váx:H—¦oL¿“!È¨ÉøC&13#s$ó/Y¢¬–¬³ÙÜìâì=ÙOsbsúrnåºçsOæ1óŠòvç=Ë�ËïÏŸ\ä»hÙ¢óÖê‚#…¤Â¼Â�…³‹ãoZ<]TÔUt}‰`IÃ’sK­—V-ý¤˜Y,+>TB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%�—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† �ž�kï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»Îå�wW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO�¤[þ˜¸™$™�™üšhšÕ›B›¯œœ‰œ÷�d�Òž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª�««u«é¬\¬Ð­D­¸®-®¡¯¯‹°�°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½�¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ �÷„óû endstream endobj 247 0 obj <</BitsPerComponent 8/ColorSpace 249 0 R/Filter/DCTDecode/Height 363/Intent/RelativeColorimetric/Length 23095/Name/X/Subtype/Image/Type/XObject/Width 841>>stream ÿØÿà�JFIF��Ik��ÿî�Adobe�d����ÿÛ�Å�!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDDÿÝ��5ÿÀ�kI�"�ÿÄ¢������������ ����������� � )Q�����!1AQa"2Rq�‘¡±3rÁÑ#4BSb’Ccs²áð $%&'()*56789:DEFGHIJTUVWXYZde‚¢fghijtuvwxyzƒ„…†‡ˆ‰Š“”•–—˜™š£¤¥¦§¨©ª³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêñòóôõö÷øùú�‹�������!1AQ"aq¡Bb�‘ð±Á #$%&'()*23456789:CDEFGHIJRSTUVWXYZcdefghijrstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÑÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÚ� ���?�¨¨H¨øá»¬¦Úw¬Z�±ýÛºÊjTô*áÖ�ë�”9Þ° ‰ÈÖ�¬Pãë�š”.húÀ%´}`S— húÀ%´}`S�Ú>° mXÔ¨8:Ñõ€K'Ö5*áÁÒ}`Éõ€MJƒ‡`NÂ{±Ô¹Éõ‚éLZ¦ö npäÅsAÅŒY>°K%"T�²}`–JD à²}`–O¬D¨8,ŸX¶�¬D¨mX¶�¬D àëGÖ-£ë�š•t´ïX¶�ë�‘8u¯Û>ªHbR×ßýT'°CBî23�GF_C(ÏRLËx‚êÁg&q8×x�æ[y+›îo2W½2Mq9>L|Éê +ð…6°÷ “÷=à¡>÷Bí_ål^â+7�4‰w*ë8‚kò¸Jobºà‘ƒ:só­Nbüa< "]Êžì6‰*ocüqõGw”VŒê_cüsõGw—i½Í8–­"$^xÏZiWR ž2˜네€‘¡8„rF�€.N‹ÐBFEéHN! &8�ðZ`Œ]a Ù™²o&ô�R£CÉ2@’o]+Ðe*Œ $ƒ‰‘§RuQCfhdlwZÆ1½&P(6ˆ¾'¾»‘›UêÌ�–S ³/™ÄÌ.T†â§r˜BëLn*w+—°º˜8 C`LÌçE‰k� Flåu)4È�鈿�sy/qtc£ÂIœÀHB|$‹ÐHl\˜ë¡HŒr@.Np½@\™¼ §z{ ïpÍd†™�` ìœa!SróDå60ë[#­àZx :‡K”�Â$ΜR¤ä¥ ‡F%)ÁNÉ’ŠUƒÚû[ µhvÛ€#¥‹Gc6n2cYºÕˆâª[QqÌŽOäÓy\$�\™‰O8$Dv ¹�ÇbšœR �Ô‰ÉtjD䈨J‘tèÔ‰Å"�HœR èÔ‰Å5tèÔ%)N‚„!�)©Å5��ÿЧ©ÛÝ»¬¦§Tí�îÝÖSR§¡W ¡*áÁBT�* ¡ ‡ P„*D«€*T%AÀJ„ àæ’Ò.!u²Ê·´†;;N…qO°í"Çízº'”%Úõx=!s²áˆJ$àƒ–åGM¯[ƒÒíjÜ‘áL²í‚1] r£¦Ö­Áéí«_ƒÒ<+ŠsX÷˜h.:�rÜ«du-~Hð¥Ú•ø=#›°Wà9.ׯÀr6 Œè­­ˆí©”pzG….ÔÊ8=#›µòŽ’í|£€äFƒ Ñ[[ÛO(àô� ]§”p:G…7ke%ÚÙG•¹v4Éѧkb;iå<‘áK´²žHð®n¥V�ïkš4�a4L¢Í·*Ù}r]\’»Ÿ!·@Î<)ÁŒ¥~PæŸI°Ë�̹ԧiÓ9‚ABp= »«^ÉJΨûd��†´`„ÒK±]Näl$bz-;+.ŒeY0¢i`p¸í<¨:v2oÒ<)�¢ìZMÙÅ˸9XôcùÔ¯¾JíMÃVår\¨ˆØÏG… É2¡è³ÑáK²å#Ñ®çOÊÏ£ΈZ!5kº£G•;èð§m\«ÊÏG…=®Ê„—=ðâ�”eàóÓá]…¢rj×uNc#ʇ¢ÏG…8ä™QôYè𮢦W¤óŸ l©·—ÏáD-˜Uk§!’eBíŒôxTšT¶“^´lŽÆâ¹ õܶà@$NeÅÖžeĸé7®Ø­Rê¬qàa$¤'ÙE•r7'YE”‘°…ÔQ¨á!¦hTD¢a,§$�Ÿ„‘‰Ž…Ö/ €˜æ×:ð%tÊ*Sªæšb Aº:“KˆhĘ ΤúNhx‚L�Ê»ˆå’ž3‰c›¾qˆ])o*w+¾Vꎳ²2ÄL_+•!¸©Ü¢!„Í2rËZÃ6-c M–6£ˆ˜€F>àe�cI¶ fA¦H¨ê�Åí‹î�ƃ³µ±#”ÕÒB‰#™HŸ !F$)ð’ÊÉÏÓzèZ�µp쌔Õе6Ê�)%:ÊHAѨ”°ˆAѸ$)Ð’Êà ”‰ÖQeF(˜N²’ÊŒ8Ê ”ë), $],¤²ƒ²sHºYIedæ‘t±­%�h 9¤],kE�h;'4ÕÖÆ´–5®�“šjëcZM�ZÉȤ]v=i6=h“²ŽI«¶Ç­&Å­vNÊ9!tØõ£cÖ‰;(æ„ûÒXÖ»!(iM] nL„Lÿѧ©ÛÝ»¬¤ jvÇ÷në)Tô8…J”.(H•pà©BDä© à©RåÀ• Pp¡*¦7K°\©ï—Tb¦Ó4äÚxÓ˜˜ô8nJT�Þ”9�$œÂ²{Ù’S¢IÃ^’U}=û{¡Ö¦eØ3Œ÷�®g*¶ªV!»}üÎS¶ûøœ¨iQ,0)ÈLöP�s”£²à7œ¨IWeœÀ§!7ÙEüó”áÙœó•'�Œ&sœ…®M• ¤šOhŒ1(9E!F³˜ÜãˆÞºd8Ë“²Ñî$ñ5uÛLè�YÚÚWAÊ©!×ÁH <LžSÆ“$.ÔÀ �™ ð©Ø<.uÁ°Òº€›PØ:Tˆ'jÑ� IÉx<Ò,àñâÌÐqäR!rtl�:`±ƒw Ñqâï®4›âÏÕ‡*�Ç‹¾¸Ó�•ÇJ#‰Þu„ëí n̘ÛN ÒWJµ\É 6ZÛ„)Aí„W²�y2ÇoNc¡&Á_€îb»·(®I—�éÏ©7leXåZ%“V�Ë`¯Àw1K°Wà;˜®»b¿–mŠþXQfˆMZ-‚·ÜÅ+hU.ÇD‰¸®›b¿–7)¯hKÌMè³DäÕ I".7"`vFëÈ å pT™»b«£�s…Ú±¡#‰sU»ËÓ± „× Âèšáx\$˜ê`ì�³�¡ºåB¨{MB ‹ FuÍ‚j4LK…ë¶SLµìåóœæ½w"Þyi*Ö©Z-ÅØ@„RŠ�Êë”Pm6]6§I”·•;”[6„¬.9¶Á°ÐÓnØ“1#BJÒÚ�màx™@l�0“ºlvYT.-�ÔßȸJa‘¡6HI „Ži |$„9¤+¤&�¸vNe!•ÒvNFR] $- ‡dåzEд$€ƒ²sB|ØAÑ·¤O€’Œ½$”ø .Œ’’J|@AÙ%$”ø 쌒’J}�‹!'9)$®–BK!dç'JI:WK!%�ƒ²s“¥$�+­�’È@IÊN”’t®¶[¡%–èAÙ9IÒ’N•ÖËt$²Ý §e¤éI.ÒºØn„–¡e­;JKNÒW[ Ð’Ãt.ÉÙGNÒQiÚWk Ð’Ãt"NÊ9Z:Q'JéaºYn„HJ9’cÕÔ´A\à êgÿÒ¨©ÛÝ»¬¤KS¶?»wYH•g Ä(NH®'4`&®´±+‡ GJ ŠêŒÅp„³“Z\Ÿ±)iïyWDg"ÒÔ­a7àœýêxÀq äØ3c:RA‚º¤vù¨9" e.Æt§¥AÉ9�f3®�®á$óĺ ZèÆR4‚ê›OƺrE w #šáy2º;zPrD¤Â\ÓšÐëRò¶[ ¾ •Æ—‘ã NQäyWUÌ…O<ˆii‚žÚ."I„ê£{Æ»…È:ê±v˜…ÎíY‹Ô°™.;•Ø8ªb �ÙÈJrw ‚»„à»p˜Ì€±ÄÒ»eTKë—L\dB+;•w­Û]K;±!SÏì¤^• œ.N74�H¦e€éAɰPÓ¥!czè*goÌNH�kˆÐ�eÚSÃNƒÌ�dè]‚-œ ƒ^º†?H uVˆÅu w |Á»¾6—� Rɬ-Ù# k°roE¯[$b›X<9Æâ-µÞ”l�»:Gŧ]œ©E„'=°#Ò´ò`� ß“ö7yžd´"ÅÂ$ñ®�¸•‡[µ‘ßm—–´�0œÀ÷‰†�ÄŸXx™äO`Ü7ˆ"- °e‡yžeÉï{ ’Öê¹J…ʳeôøü ­NÓ­ ’h¸¸òæ²y îÁ¾âL…ر›Y×sI�‘©&ÙwœÈ®ß<�K”(6ËRM\uÛ.à3™q«PÔ{\Zf)l¦‘zãl’I•àÆ�MæJ¹KXæ†8L¨–Pât®á28 ò]|¥Œ�Œ1ó3p=K‰¬k1òÖ¶Ë|ˆŒQ”šN³±¶ÌLîl¦SŠ�Ês�’I8´àÍûpÄc‚}F5ΨûMÜ‘�‰ –�áˆ2Pç>�W8Þè�qåÌ¢‰·l‘!bbá�8…!¯¢(9¥—ÚmÖÍð ë‰n4Hp�„òap�êTvI$À ¦Ö§¯�?'ƒÝ.…I+:œ�êÐ šdg””è6ÓŽ8�¤VíNâ異ZÒæÚ3ÂäZw àœLÁq�Tz´ö3¤g”9ލâÁäŽêfT,§ñ”T í7B�§šJ�hÒ�¥%$ è€0 �'PH¦dÕ²vRª×Ó—PM²-n…Ñ™D{š\K[e¤ÜÙ˜å(jàM¶Ô\5”’‚@‘’W�%´’Ò‚DZIi� i%¤"KA% ƒ¢¤E ’Ø@[[vH’ØÐ’ØÐƒ°*D–Æ„–Æ„�P›lhI² ¡ rDÝ�hI² ƒ°Ç$MÙ„lƒBì†ŧ—ˆ7.r‚IÿÓ©©ÛÝ»¬¤]�L[tðÝÖQ±µ)&þ9©Å°ë:WAM«‡9§Ó ó§lmÌšÖË£BJgiR�lmA¦"Bá™t�¹1–¯+¥† ã€y9®Ç2/ Í`‰( |„×8HŒÉl54¶ iAÄuédiL ÒØjX pµ9—PB亄ðÆ $�‘„ Š dŒm¬PrÈ:‚÷ 1œ¤Ú‡0!tå‡J.‘œÖ¥å,ε�0K\t޵/)`plæ•Õq]Q„ˆ• �_®í{\$ì²D_*C2RD�z‚¸„:Z1#�r¶6[Y°]ÆKK9<—§Ðc¬†‚uË�6 °FV‹»­íüW®‚›±7q˜@q76x…ÝK¦ÕÊ$Íf×zêDËL–‘eBâàfnÖ»UØíî�ð3Âm ’¥'ì•*"È“Ž²ºT£’¹öë\s@©%aÖËvb8º¥ŒÇV>S¯N CcPÖÎJÁ,£1¤êNNeQÖqXï5¢rT\ö,APœ/õµ&½õn c�®òí³;Içw„.o¬æß.3¬÷É]ØœWÜ=†«€6{œ�/‚9Ò5ï€o]Zƒ ]"ô‘å$>"Bî*±Ù�åH즥 Ç1®HõIKh?}L m¹x¬�&-ªYÍžTÖÑpyx!Ív„»R“»[¹ Mm Ôßdi·&È%[fv¦"£fëÓ*½­.¾ù7.ìq´†|W:™;K›Œœ¢Ë¦¦Ó…4 $Åë¼·Hç\™“É6³fÀ§ìôuÅ'\HÚÎim�d’ŸIí,`� �J!‚ÓpN§A¥¡ÎÏ™ÈYYn‘θUx/m›ì®»^ž¾uÎ¥CŒ (s)‰$Ós\ Ȧ—4bG:)Qk³’Ø)§'§šB•°FÉdZ„9åà É�º9–\Zs$…Yrv „–KœÑ$àá�–<8b5Ìs 8AMtÙÎug‰‰0Wdïl‚EÍ.æDd ,·�¯[f‹¢'<â™LnÄ’é�Ëø‘{ ”#�–�Ù5 ¢3Bi5)‡S2ÙßÐY-kXËk}7jC€m¶ÕÕ‘p\;'SuBCq�ž@¹�§dï§h�ŒH¦éu£}×ó¨ÕÇE†XŒ`“<èjÉ:ªrÔHM!t!4…c©T �ì èkRÓÐRQ¦×Kœ&.u4ÙÁ˪`‹jHµªµÍ²Üø””ë5­ uÑ�t¯I¡–š � )Re€â$›ï\¶IJÁÖ¥§ ¨õ³=¬fr�›¯&³Mœ̆lªSˆ{�PC­ŒÁ šV¤Û+ª1ÔÞênß4�xÅÉ„)ÙuJ.«U�¢ñQÒûD“ÍÆëÔ"¢Ô2Ê\¤Ýƒ iO)¥p˜Ô‰ÉtjDä…F§º‹ÙE•ÌX¨\}òÜRÒsP:£V‰–[<¡YUÊ2Q�äî9+KKêÙfÈðI�k©&�¤j©§JI¹z‰N‘=ÄH 01�Iª$ƤNHƒ£P•"ˆ‘*D‘9"�)Šj�DŠCX؉(²Ý„FHWW°�3§Øh̺vHÉ¥J-iÌw‹.! �NF$)RÒb!]:58¦ ÿÔ�žüR¦º ¶éá»­#RpnÃÛè¸K­h]F :&·~ä›#s$k Î•ÑyÙÐö¤/`u=êzäÇEÅ>ÛP ýêxÀ.NtÜšñPr,:$vù©-µ!t™Ð€:¥ �á-°‚0~x—EÄ;u+ {WA�IOÆ›lfKL™€&t æ#¨C·¥>ÀhšŽ Õ‰J* (²O È#"Ñcˆi‹®Rª†˜µ'q¤*Ô8„[s)€¤–µ÷p7Ù ò)"º�¤wÔâ!—è´åÙ¬«WxÒF“‡x.�¬iÜ1¢0s·né¸t§Ú¨ýû jݘ °EÕ“TA“šµ�ý74dm« cª¾5‘Ñu  /-5¥æWVÔ^†€Ð¥ Cq+u=Àh}p!Œm!®æ�‡)~/Ž-Ï�t@Þ65›ÊvÈÓ¾´zB–ÄŒ¼ˆäÌ•” }»O+³i1×–’tÌ…À‹-»°Yh ©"5Tïwœ¶­7-ë'¾›’Qhˆ»�u”«°²«+°Ò�:zÓ_@¸Cj9œ@z¥Ñ,®Â9,ã°¾.y= ¥µ�¾yR¢ �\ó²4[pÕëÒIÎRÆ:÷�HÏ�0ÑDó®C%„™Î5s%§TÛsmcxMy4ñ�7:äÚ„:Ó„Î:W&Ä¢sl’¸êÁ#�i&#X\©Ôcž��e9Õ¬8ƒ8ã™JT‡#©¸Tl’±rRØÆñ¥ 7·rM÷`Q²�ë¸�8 æ‘ΰñ3ÈžÁ¹A%kL�· 缆=¥³F #ÜCÂmG�X v|É6jzù—*�¶àEÀ`†Á'$¡Ÿ‰$&²«\b”†³5žEÙG!‘ë<�Kœ.Ž%Î.Ò‹Ðy”bp‘ÎÖ[{[„çN-# ¤_ráÙVžÂð“+«+–­†ÜÃË…Ë›i¸¸Z$JZôØÇ�Íß+·[ˆåŽ¿(e4ƒ H�3p¹0n_Ĉs´ž”ö5Á¯�D…ËÙÛ”I4—�.$Âs¢�ºoÎ1œ¶0Z  %ÑÆ´)‡Óé�×�p”œHO!! $Žd$!t°ã˜ó&–‘ˆ!S:ÐÞ5Шì{˜n9“öWp êviÈ•»[�ÎÖÞ%Ê­G8Y"ÈHÊŽh² ¹6�Ápv*6SƒxÊèj¿€Tz�sÍ÷FeÆÉRœœJiO)¥D´aM)å4®C D⑆¤NH€ƒ8fJR.‘8¤AÑ©’ èÒ‘9"�Hœ‘�5"rBƒ£R© �Ɖ �¨@ŒQ²êAÈaS|Þ4õÅÎ.2S…GÒƒ±põ¦ü®†£‡‘\I“%u¥ HR”‹¤Æ¡*,»Aæ]:!MN ŒSPuÿÕ€æ¶Ûˆ¾\Lò¥�¡A â !$nËE°3Ô�3&ø]@9“ZÑhƒ™=5»ç æQà -%Fd�%>k7©è5ÀD§5 ŽÞ§ s°\ÛÄgN ¾88�3'@Б=¬s°i+§Ì4ZŒË«ZMÍ€)5×›NÐ0]ZÚµ.h²5\ƒ��ØØ7æN�áN¦^ë©¶ÀÕ�:xm[ómÚþ©v¤2šÃÄÛ±7N~r»V|1ƒ'kwUˆo<Ø®€6<J�­~÷‘£&–DÆ›O6�®õ$lt„Ü'œ©ªvUfšlŒÌžµP6Sv‡\ÞFúîÚi Õç07s4'º$�Œk½Ç‘ ‘½gÉ:÷EØEm·¡¤DÙ ]�2V±‘¹m¯4ë‚peòo:]yæOŽU("ØÖÒlÉ¿P¸'ìlÐ¥]‚-±6hKaš¥AË@5£�œ˜^Öâ@L5Ú0ôu®Ê9 �Ò¨¦»ü‹G)MÙ²ƒ™ƒ�s ÀdĪ «”yŽ”ñZ§’hä>»„Ž`²B%sÆäëMÒ»' |¡6BT—#B™2j̺!�›Cl�`\žX%±~ ¡"…:VoÓšd.° ΂¸ÑØÐWQzê8ï$A¼&¶“Y†:s§‹ðJºpK Ð9—'Ñ—K`Šì¹Ôß0ë\hr=¬kD�‚Æœ@æJ…Ó‡l ¨íXr®Ð˜ÞØî ž¸Ž±�l´ƒ¡D�éÓáS\a§ˆ¨‡Èêð®TJ‚Q �f‹ œÄ.ë•{ÙH]w¦ô8†�, …<u$‹×��Z›I`“}Ù´¦–X¦ø;—E“øwSsï½"ó¥¥TÒk@�C—"òj«”•ä'Ñd¸º.oYO¬ÂË-16oŽ2º±í²Ã"ìn½E+Iº¬°B˜à ç]ˆñO«wÓDZ3 õØ"™ƒDža<£&‚ÇñORx‡r(«‰7k#×�°� )¶Û±]+F×:Ý ÔÝ©â/�r-ØœîÄäæ–’Óqõ)h¹ÙðVp~Q"ދψè.�߸¨~²PÑÚ= M+½0 *Îf]ç‚h`yÏm—ò9B ¤àS �à6»L_²:ÿ�ª„Ú  TˆµÓçŠäOq8†9áÅ¢CiÚ„Ç}s‰ÁXŒ¡´XXYLÚÉÛ²I$ƒèQêÆÜ¸�6FÜ ÈhM·f‘ ÷aŽ¬ÉªOÌŸ[Ñ�s�mw¿dmüŽ\‚IœR.Îk°Ååï¿‘©*€J3°Ïž(:žâqH»W�=°#ÄÙê!9àmË0#e3bgp#$]é�rˆ"é}Ü…2�T›â‘ë;'(19†)#ø.Ìí5~©Ö’¶ö—¦‡©96ÁÅ"íXP�#rÏQ Ð6嘳Dfß.�ÀŒ‘v¤¨A¿rÿ�Q)´À-©9©÷ÂÉÉ!]ZÂóœ9�ô„ €û!¿ê¡gq8¢É� ÉÁux3¤:yÓÇn£Ü3¾ºvw=B0@Ö»¦Ð‹fs1ÝEuhÜ¿¹apåNÓšŽñ )`x›�šo}p«ÏmÂyºŽÒí8ÕÚ )ëiŸ<Sk� bïoRé4Â�¸•×´ ™Í[s'7¶òžúã"Þàp¨%‡RŒ¤ÔÞ%uQqÿÖ®s�mÂ'vNà§’ ‰O9BLÝ“”’g:èí Ý�k¢64¹Ú!4 …Õ5£tu.Žw!s¢"ÐD‚‚21¤Œ/]-;BJx'�8 ÂIÆä­s¢"WCL‘y ÖS…†ŽHÀ^pjvÆwÕÒSÞëš#‰›£¯Ð/+¤dÚ.¦Ò㤮�•^%æËu¥aqÜÑg.*U<‰ïÝWw ]JHURZ¬ŠE†)ƒUý M<Ÿ)­Û"›46• T„1 kκ©*JªÍ2-‹8ÑÉ(Ò¼ GIR$4I¸ÈÕBøÄ›š9W;EÄñÌH»‘ªV+ŠÚnÖv5 7-áOCfw" òF÷žLÉLͧô›Ïª]€p„k"üúqw:è�& ½­ß]#xôª3²‘äë+™ª÷byÈÂGp0Ôcq!0å ò ž…% ˜GpÜ×yÂm·I)�(D„!Á8&„¡tààœBpAÁS“BUÓƒ’„‰WN À”ÄåÒ#å,¦àºpTJ��Â[nÌÙHZs&ÞÞ ˜ˆE'é¼iNcí\qO�rî‰�&:¢ðWDŽ! øÂR—¿‚ž„èŢ鮑WHNh‡ä$ œ^*Fêð¹’à*YÀñ(ø�¸Ñ$ÇÅm!r¨/¿B”™XKyBëG´çj«À"�©H˜¹u³��¹$3i¤ÚĈç]^ךLkLnwA-A»b|_ ‘y&îdWR|f0 .[¢ï5àSH¸5È4lî»Ë�U^sñy™Šc¶a|ókR"âR†°¹�ž‚!²Ü›HƒÄŸâðD‹ým ¥6�^4Д�Ìë…È&ê´‰Weˆy‘3ªR4Õ-hmÁ¤òÉ•%ìoÌò”Ö´ CŽ"Ó¸VœkÚ/2£8Ôc¤›È"u”âÑi£Lt®X'ƒáq¢TÔˆí§R \ ñb�ÒªZ‚A#‹µ-Â’z`[±>´JäÃ+�¨Øó1¬ÜœiUp�‘ Àq™]ìQÏà†ôÏ�9Í€ÓÂø\‚xWêSªDºø�r̾ ~ùÒ2°s@·EÀr£±�·�%Þqä4uUaÊÅOÃÅq¿ Õ¥ÉͨÆÙ;ÒA<cýjq`¶æÎö×BãQ³EÎ×¹UDPö†�ëI#ŒãÔ•Ôê †ˆóß]ØÀ6Îü4Ÿ«%³6üÈž�°ˆu-È·Œ�8…Á/Š9Û$î¦g^•Ö³|M®Òâ9€ð¥¨Ð×@ÂP\;7�¨×[u}üx®ræHHƒÄ»•ʦ<ˆ$˜Àòæf|O!”=ÅÁ ùÙé'¾‘"á sœã$ɸs\[u½’wS3­ €qi‘q¿¦âš Ò ñ%H€Ñ�·1‰I$Ù³šf5¥MAÑÐ÷4 Âc•;vÇÀ–��âN$ äœ7L'1 ŽBœÝ”Ò¼nšœƒ²s;,7Ê\@f²cYRW <Pñ.�LacÈ�›€»­5í~.¾��HMD�U¨çÛuŒ§´Ök­H(¥�ãND�oÁáñº¼.JMMáâQ—Q:\£ÿׂD8�Žb•1ÁöÝ7në(‡éI›�îÂê¸A˜‰+³iÕÎc�p©­;¢Ÿ` óçPCHô]>Rƒƒ€'��b耒+;ĂƋÞâPDVì`@Ý'‚ó½0ö‹©¶P^ó¾pn¡ê�´Ç¹¢7nŽ’œÒØÜ‰ãKK%«Vû$îØ©ô²*l½æÙуy‚êM�ª´±É”êÕ0ÙäÁK¥�4A¨dè(� †€œ¤©)«4në�k4Bzâê¬f³ ./®]vmáω]˜!‚Ù)ÕZ.¢4`8Êâê¥þkV ð”ÆR©R-n[˜‡2’Êmf�%°±h±�¤÷Á~ º‚�Ö†áÏ�"cë±—L�vâ.YÙ5ÕXÌMú*#«½÷ ÈЄuQ”�ì¡î¹»‘Ò¹É7›ÊhJ$”$8'МpPœSÚ×<ÃA'@½tã% E<†£¯y åJfIE™­&õ5Ceo4¥h�Ç¿z â »rJ§oð)àp¹ J„VóGˆŒÜŒy'sñ“RO*ê^щ•&ÈÜÒx�R„G ¦ £Hy—b§ÁÈ´s4ôú%Ü”Xrܺ¡±Óà„›= ÒîJ- èð¢À´fÂÌÒl: ékH#“À‹mÓw"K9lnÓ`ŒT„"á“Ëu&–…è€� n8¦¥@�l:BPHqiĨ8:A¼!4Lƒ˜®œ) é@è§&Â[!AÆ\€’O,Λ®3¨ê™Tˆ ÒRìcI\ÜË7âÎ(“¬]r  @`•tᣅ±æWAº2+2ûC?ZFÓ²A›ÂŽ2vB:nˆ¹qs]N¥·D:å,šö �-9×Z8ª‚6hNÞð‹—F n]2tMÎÓ¥A_i7t fOTZ&̸œç:æð[,9Šž£etÆÈ$ã]0¬9MRí#�j<5¤Zº10º ’­€ÓffqõJ#ši�ö›Á•mF «MµqxÖ¹JNd•mÒ“WjÑ©Jè�íJZ‘pÏ�8=åyR›j±Ô݃„*�’VÏ`²ñsŒfŒë•ÓÌëNfôt¥AùE0êe¥ œ÷õ.›K(µj[<gDhKH ›({‹Ú[Qäx¾ã•‚í4¦´HÕ[NË™�¬“×u'Ý1'¨ô¥.�Œ9åYvO%Ù©Š¬ßÓÇ[só*}„i*º“¥Áu*éO3«êy7Z3×áQ©Ô“dÝs“ßNu®7ë\[L¼ÆŠ‹lµ% ’^mgtÏ*ãUñL·I�z#I\êR²-0¸u%#éÔ�Ü%€É‚[DZóB<® §hI0�!¤ ì)YòÐÍžuÕ€e@Í 5à=RŽöYÖŒ‰‘”0�}KŠó®ÊgA�vOH Qw…rvODžÜÞ� evU÷ù3Ö£¸A„=#´§”�rj^:<)6µ." CÊÉ'£åãÂ�äô|¸txTr‘aå$ž�—� iÉèùpèð® ÃÊw4)yhèð¤Ø)yhèð® vRP§N.¨ 6pÂŽ"I„cIAÈÑ::�2AÙÉl0ù0£9¤Ò�±é(;'sMœ0¹ìt­l‚ü×.f˜ÒW;$ºÊéÔ´I[8a4²˜Åà.;ÒS]JéRÑ:¶�&Ü*<^í�œ0¢5–µ�Ÿ± %ZÑÔ:¾�2Ò @%qÚô|´txSNÈ�er]D©N,gÿЇ�’âo&`_Šp�`Ùã) €s€‹œG1Ik_y$m�Ýȼ4h¾�Îs<¾ļZÏŠè„��8ÉÀrÉMÇZéK%¬òIAÎëºq¼IÒIJÖ¹÷1²yÔÚy6ÞýÙæ K@h†€�rì¼Ñ+ˆ4ò®¾«¬�óàS)dÔio~“y]ÈMÁI"º«©ŽJ¸ã `¼ê¸s®eÕ*Ý$ù–aÊâ‰#‚ô‰¯M—L�õÅõª:ã¹ȋܕ™9Îl Çœ© c½¯?:-a�Z'P¨ìw]îæÀ)4é2�àIÒo)d Êäü¥�¹»£Ð»b"Û¨�¹¿(cn£«uÕ^ýñ»@¸&®aTe;:³ßq04К„ˆ‚hJppN ¡=�sÌ4N� §ö5Ï6Z$©T2?tû‚²¥F�! ¯:�47 S^j•ŠÖB£Øòo¬cÌŒTæSe1e€4$}f0Ùß;‚ÛÝ̹º£æE)Á£wPóHëV$©)nª¯;9Íh—»“vIÞ4»^ôs•Ææ™€Ó¨m?�èsñwtl7˜^»' qy˜sƒN†‹GÖäDO‘sµ¸ÀæõI®{)n_Q¬ó,{å6Õ­å'?]Cd}jOBä�ƒ¥ 0s¨^{Éf|“�c¼š”$ÊcC[hó˜êK°¿¨÷rÙYœ³(·hyåŽøM/¦1Ÿ<?ŽNÚôs¶xÉ=iv\óØa+Deºzü÷€¥µO„áÏßNØipÌlx’î¤[ ´Ew¯žcÕ wyÀwGZærjGHâ'¾“`{{]W GthY—f‡Ëøkä'�bZéïé �¬¡›æŠƒKLbš*Ñ& Ò~½ÁðÉÚ¼íh�ðå� p!׃)“Q¾lj¸ø ÇPÝs‡#‚éÈ@8®N–c†”ýÛ|Øæ>¡Íx# ãÌ€¸` àœ±Ôͦà†Õ:ík’v1£²&é J` Rºpp2`š ÌpNÅ�*fɃ‚réÀLŒÊj¡É¯Ôé �ž$ Á*m°S��@" äD\º’�“™p/i¾WÔ=ŽƒWEʘ3˜.¨@ï8Öo’«�]ëÔ &óŠŠç´ ¯QªòtÌòz»%9;áq]H›Šã“SØéÉÅ×®ÊJå$*‰pVå,Øí76!?#©`†:W<ª¸ªâx¹6W_ƒ/=å^µasYËK% /¤MŠíÓpµÅ*j�•ÔÞÐTÞt4^T깕Q*¥H®{­¸¸ù"O:²Èël´ì�ó.<YŠ­Ùò~;Œôc‘Ó`fÊd¼i&ìØ¨Qyniͦ²U&WC`ª@ÞºöøÚ©ËkÓ¯lµ×Pp�«§œ)f‘$sÂÐÆA+�<]Æžê¬ã+‹LàU‰XÎ¥s©½<E8Ôf•Ê¥F–�ÛÉ\:“ {À”®l¨l›¡H¥Aõš^Ȳ Z&¢ó®ËY®÷•wÉ{{yz’ÔÈ«:àæyåÓ'ÉßN«\âÓ0é8!''KÛ‰‘kv×÷G­F©Š±©’—=Îmî&3¨5Àò×8‚."Éð®4JŠ“8$]lÓáýdøRY§ÃúÉð®IÉ"éfŸë'Â’Í>ÖO…dæ‘t³O‡õ“áIeœ?¬”“šBºYgë%!k8_Y(;#Ɖ"©ÄZè(.§ÂèA›÷ÍãOLqa ‡a©:Õ>B dÌvÃÄž]O…йË-ZµŽ¤‘©ðºÓK¡Ntð<iɬ,l‚ìuëTø] §]ãjoˆ¥=ÔËHè+…–p¾²WQ:lGÿѬ©ÛÝ»¬¡­s®h$ê¬E”8¸‹D’LÉλ6¥6ˆh�¨BLÚy¦DÈ,È«¿5žò“O ¦/¨âíBà»lÃ0'›Â�×vfsŸT‚ºÞ�Ù”éÓ¹� âÅtPöjÇ�O},å/ÓÕà]’—�’ä L$ÙY›uÅzŽÚ î tž•Õ´ä¥Üf䄱�¬MÍ�Å»=%Üó.¯3õ‘rêÐpÄœ‚3�h¤ß%ºãØ\º‹°\Üö³|c­p~Tp`�evã�Ù,¸4KŒ k‹ò .`�g¹Î2ã%rI*3£ª=ûã:³ &„¡‡'Д ààœš„š $àåu£’¾£vGŽŸçÔui“ä�£r 6œIíŽð:ilª¼ÑRC£‘9Æ{¸7ÍÖ¬è䬦€HÀ ‹§‰P§&ÆâMÁF«”¸‹‰¤Ã�"j¸y–œ³Ì­TªEÝUW¤H©Y”Èi½Ç4K�"àú�q-y-ÓN™—ýYØ7Ö½r¤Ú•Ø›a®ÅÒeÚËñ<—kR[“Ò¦Ù¨A ¾øk¸Ã”ÉÖ»-œ…N™É–œ,ÒÝ ¸rÔ8òs®¢˜¦Òç¸1¹ìîG+�å5J·díÜùcÁ äž�­+rfH}Rj¼gv‰¸AÆòÙ¡ŒcjvKNÔù3¸o9¼§l5Ûª8,Ü7Ÿλ¡vadúãJ�>ÖÐÞ!:zºFðB€!�B€!�HæµÂ éP€8œ²ú,ó8·™5Õ`†å,²s<aΤ €D æ+‘�–[w�s€�vFiáÉ�>P:¸®ÉßLÛÉÌiaÁ#*µîƒâU³ÎŒ.N&v&Ôw—2çî›ÂþP¸T¦�¶ËÚt.í©&ÃÅ—èÌxŠ ÚeÄâ<‰ä]jN' àë1n#RêLJ¶yÂâáaÖ€Ž5jÒï0ñës(̉$ ä)Zìǣ셆ÅKÆ•Öd è=åÙ8ÑÐÞš iŒÈž4¦]"8Q •í)áÈ��ð\ HNŽÁtkF9Ó’J%U3 ñL°0„®ß ÁœTIb:5¡¢R@s.{.¥ÍõK͘€e†Æ:ââ/(§I¯uâáyHSÙT1±gŒÊ�“ie±a%qÊe–F.êLTù•Æ£ËÜ\W]VXFš\ÚG{nEú–OHQ¦Ÿq¨m¨)›dZŒ °ËdMŽŸT£L+IׄÒJâ[ˆh.7�$ª’ãS+mC䤢㠵l¤Õe€,‰¾ù\)öú|g¨¢ª¥£´S‚›wÃ&É›V iî*ã ‚¬¡•6ƒ,†I&I˜ï.žÊ>“úתE.šQÌÒšêwX޹u}†•†˜}IPÎU[ÑB¨ŽZ2ŠÎ¯”Û7n` a9€ì5nàu¨UVÙ–SN)cmNÌŠêl#\Àâg2’A\Y‹¸Ô “±�c4Ê¥6Ù$!w+›÷§‰p’gl¶�ò¥ÖhÚt[ZuÊ==àRjøÒ�—UÏH*½iîD Œð»äl»4ßÔ¹UÞò®ù'ŽËÔ¸¯%Sν&q¬Ñ³<ÅöÏZL°NQÆÖõ'Ví¯îÏZL¯Ç¹K™A^´Ž6[¡4µºÒ ™È6I2u–è@ß9*áÑŽh‹®MkA¼®‡ÆoPwYn„Ç´!tL©½@!ÁoAkt' D8½°@Óì4fC÷ÍãNAÙ¸act.V7vsÝs°ñ êw…†èMsFº$@IÁŒ’s'Øn€’ž�9t“vœª1¡¤‹¡pRªoˆº‰ÑqÿÒx¦ÜuœÁ8Sn´䙫,¯œ¥ f€„«¤G ISRŒn'¾ƒ‡Dª3²Žå+›ª=ûãÉ™w’ÝY�Ï'@\]”=×7r:W«’IR�²Mæô!:(NMJppN ©B Á4)tòXùI4Úw¬j;ˆfã+©IÒ¼åJ•JϱI¥Î:ŽO’1®€QTfôSxÎu"†H÷¶Én×£åc~î詎u –˜˜cp9:�Ä•m4cbÙ¦jÞul�”òpÓ²T6êf9† 3&ÕÊšÒYH½»ëá�ÖçfâÅDÊrÇHcí0¿yB�õßÇÑÓ­-‚­`Wé‹Û“S¹£º9ÊœâEx:ÕoKkkLcjUÊjMx=µÂ)³¹ižs%K£‘1†ÝS²¼ÞIÂyqåä…ÜšT0cEÀÐ�\â­}ôÒ§ÁxÈÃ’ýk©F‹8ênìêêû£NˆÙ1ÌÖñžö)BÑ®vG Àˆ`âo|Þºµ�cCXZ0䫱”„Åß\„.œ!�B€!�B€!�B€!�B€έVáxÀŒBè„qi¹Ô|O(铹~�]…SN-›TÎö¦Žë»9­p-p�qBsjdd¹¾)@ïšo-Qvi(ªÌ{‰5ÍkÄôôÝNC¯¦pwëJÇìm)tayg­Y”�ZöÈ‚Ò8ÁEúg-§H…{…ƒ¿nƄƽÌ7r…Þµ7·†­Kƒ·r|�ßú‹°ši¢K*5âëˆÌºJ¯-2.*M:Á׊ê¨åTÅÇ|S/,èKq] tê)Ö´®d"ÔcΉ;[HãÄ™:ƒÅò»' æL¢Ö¤§ã µ.rfWR¹Åê,’Ö¤Ç?RèSMáQÈ:Ê õæŒè*$Ž/tÝ‚h|‰]$q$h€¸KÂýE%Wg( §•Æ ¼q”VØ7d8xHjêRvz¼.�àHrŠÜ.�à\Øê�³!›EÙà®Ì¨NOUÐbX9d§mŠû%›WAºàIR¥Z�I: ;q,XÈæ©‡8gã ƒ\ZgRȸȺ;ê;�’t.2j-Õó%r}BDD)s¨iÔ¸uAŵ DD…*³ã#¢`Þç.À œåImJ/¤)V%¶ -"üP±…W§2Ü]©wÈœNPÀußÈŸQ™%ïó¾©tÉÛ“¶«v'8ºø@Á Zvª– ±Üñëº+>ï&zÑ•ŸŸ2Þ¥"¨ÉöG9ÓhÈ�j-gŠ•­` ]ĸÎÓliíêH_©tH‚gH2�oQ@£©9péÉϺ"C¬®®.”ÄõÍΛ°]“* ¥�†Àˆ”¥úŠsD�‚ƒ§8“)¦¤¯¡­9Nf¤f\ímg]×0ÑlŒÁT ²j)®¨bá ²i  âÝr�²y’ŠcžºIÄœP¸DBä¤ÕÂt(˨�7ÿÓ]•­0ø˜8Œz¶V ê-¦¹Îƒ0â:K$oyŽ 3c¶væ¤5Üp�t¨áÀ˜790Pò÷»R$J¸tT$Jƒ‚¥H…Ð*D¨8*TÔ¡�9u¥Iõw·4bãsG*ë“duk:æÆs+ºŒcaÙA¶F 0rgS¦‡QNišÓF;H&JçÉ›'=w�Èî[ë%mC#¥@Û3R©Æ£¯>©+òŠtÎÅL•�º›‘ǘ5µWÕy¤ñ³Tù�HÅ6úr§{ «RTè±gUUè-XÚÒDŠ™`!Û’¿ªã›ó�C”…žÏ•:ÞJLŽYU·ÆqI™†¾µ&žAlµùiKw”š,Ðfˆn~3Ð¥¾£)6ÓÍ‘€×¨Øn×a%M”©{[=ÃLã“dtrPKsÝ¿¨ãiî:ÉOub\iÐÞ.$ïÆtê ±V¾þiSàÎíÜdaÄ/Ö»5­cCX@À ‚’ȬD¶]¬çNˆk¶G�’§æÔaëÕ]"Ü‚„�!@„�!@„�!@„�!@„�!@„� €D„¥:™Íj"Õ"wlÑĺ1À Ÿ'ÝRuî`Ää :B”DÜpUõi¿"©³Q¾“Žíž·BƒX6âÜ ±߸“ÚæÔhsHs\JôK ¶] ÷�…=Žlù6é®ßÓÏ9È�Zî×2£$nšà»z9m/@­;© C†ù©“œ)ELÚÜÎÎ5K‰�÷; ñ*Ú-NQÒ�b.>¨© xp¹W�=µ O}uT‰¸Ÿ:R¹2¨uÙýl@yB”É\@˜aÌ–AA½4úÅ�:Q)³¥€�JfuÑ­.7ÌA\È! êšRSI*$’à�¦É$.+‡`½)5ÄœSE¬Ë„¢ÁÅs¨pãN6õ&¶›Þö‚ ÀµÃªË@¦”ê´êS{š²× ¦ë×#²!’V�ŸUÔ\ÆR†Ëœ`I'YHrªü3Ì< –RM¦iؘ¸Ž\m�T¦“„J9U~æɹ^PI—œtà縮rA�¹„ò’T,‹dNeGÖ&�]Ð-q‚ÈQ€is÷­l˜ÄæŽT¹5G·ðê%qs©T� õ$IÕL6´‡¶±²,†´h ®J Wêó­ð(ÁŸ Ôrä“Á:Tªð3cÁo�wÉ^çWh1s›R‚I8© ;eƒ5ýHNÔS�zL+=«Å×8æx—QÖ†ÃÀ�]Çf¨<ۺ׊ã%J±i‹Ý«˜$´sÁäLݤ6ÐvëDŒ TËá±�èÝê\:)Á5›Ô޵àš-fAذè˜ýê]Þ¥ÍÖ³ êCƉ1¶âìvMHçtÔåÉÓ7â‹n;EÌ<I Ü™'Ó©ŠEÏdrBçºá ì OÆœšÚ5¦ZÒ8îë]FOXâZ:P ¬¨ãSxx”e`rK[÷“Ä!7iSá;¡ ÁÚk¥ÿÔ�–0³*­väU|9·-£8LmCwMá7¾¬¯ÇU½:ÿ�R*9eòÝ˸®åI»Ù³KšTäC…— Ä"7¦Fƒá\ ‹Ü,žpæ]œï†�¸vZKsLJ:pMiÎÙ®â¹%L‡ àñ�YvŽcþ¤•6u ê<È89 ¶M’e9Qñ npÎã o9WybE}Jm©SKݹM�ô©ÓC«á•ךÓEîÜ…FM�å9Q ž¹¼å]äý‰¡@Z¬AŒ`Àåq¿©M-ª5*ŠmÙhÊéQ6ÆFçE¿-¨83TÝ8ØêÕB§EèŠÕš×š]bÐÜÙ%µé´XɘjF€« •jŽ7(©d»{BŒ—»—}ÍZp§–×íŽ38÷U9^DAÊ»S£“ä­.h Îç¸É:Ë�yåSµ•X´^…º¿ŽÌž­FØ#jÑòºgÅÝ<aÉ~µ*�*Tb“C/�pã\vÑ©vJÃWÍ�Í?<qä(É�Ck*vËæ�³L}W?,¡hZqËâkM­Ì]�Õw90´3Ô=¬qp¹.Ö�N€k¶G“R§ Ùµ€ ®.ÁĬ! §B�„ B�„ B�„ B�„ B�„ B�„ B�@p ‰„ º¬«�ÕÙ)_MLJï.�APlù>'¶SÂuñõ©cj4±âZEáU¿"¬L0ï�!Æ‘Êm`½ À¹<5¯-TZ5̪˯i¸ƒÔT ôM¦MÚ”†¸¹Å̆Õ�2w/ˆ=G�®Á̬ÂÔæœF¢¤ÖÑ ›¥èc*ä8_xü�ã ®qeÓ(ÉÝAÒÙ³ä]œj\ÛPŒ4Ÿ8| §‘—«T«P�Ä`»Ó¯™ÜùùW3EÇ‚{Ç:æd7KA –!ÀÞ�,ƒŠ€Ê¥‡Vu)•„Že%T�tÁÐÜ‘�¢âºD{*o& ¦‰”‰%v�€S JzI\:†oÌÓÌšiÔàžeÔ9ÍÀÂCR®gtB;/@âiTàžd¢�HÞžd®­\bzA^©î¥Ë4Nç´4êpO2r†9¶m†Ú�1zS^¯  .oÊk Ð,Ñ; ä:V5ê9ÃvX\Hc®\ *œÌŸ¶*ðºiÊ+pº<§RjËyE*®sKXLSh¸.…+w1R+e5šE—@,‰\NY”pú�EÄã'N+Žg'¯ånæ)§'¯ånæ+©Ë2ž@ð&œ·)áôåš$óú¡B�fÔ—1ÀXx¼í+“rzâ›Á¦é!±qÒ¦ ©û)¤K��ëÉÀœ!sfWR¬€\Ó ƒõTB95_  keVï:Rml£ÊÝçJë·²¯,<ÃÀ›·²¯,<ÃÀ¹f‰f]Õ9íl£ÊÝçJï‘Ь̥Ž{Ð&ò `¹íÜ«Ë0ð#oe@ïç�xfˆ5[MgmÓ8×íõ;·u®c®qs‹�‹ŒžTƒjáé¤+ 7Õõ¡�ôʈpLn ÄÀMaºwäÇïS“n„`•€¸ "SÅg1Ò€˜#T̹Á7 Ôý†žq<iÀà�â];‡!“Õvhã¹t' ÜÊXk�½ñPêu{š[ÆëAš=#ƒrzMò3Çzx�`#‰tm*¯Þ1ÎâtÚyW•»£Âˆd]KÕ#¡w9T=ÿ�;=I§'¬7ì{xØï!†ÊŽ)«¾ÂÜõXÞè<~Ò“`g—Òçñˆƒ²¶‘ÿÕL¯ÇU½<ÿ�R+Š¿Ê}ëTªú´ê´Û{�D™‰¢;°=�nŽâ|u€•tU.ÆjS›fm,ò»…ba¤Ù´ÙaÒÛº‘ì7d‡¢§‰Íð v²GÑ_Zo…s¬�dKohæªvh¬ñVâA¤n\€ö ¤°èpŽ•pÞÁvAص�ãxïJ�ÏAÚǶÕ`KºáuQSÄÎ=´fjú–À£ÆðC‚P_1fN¥¤§è5ØößRÓΣ±�¬ÂíO°ÔòrNI^µu²§©µÇ¥Knª+{jÌñNÅBÚØT{—Ö‚(–´ù'nz êÏ&ìNÅ«Gfv·³›:°ÚÝ�e³ÝPaõÔ»d³åLü7þÍMfibz…æî«0©KC ánÜËJ˜ &96 ­ý³(²4S`&SFM–�þV~«J›zí'm»¶Ö­WQ¨Z9©Ø q§³)”±Ó°S¸œß’d·yS…B3שk¡Æ:Û–Ñ 7&cëpØÙ óβޕҞG’R3N“¸VAw9’»®¥¤Ž:“¾jÓp¶D_qÕs3'oáW÷š:S›‘R�úÅÕÞ05  8›sG2�„FÄæÅf�!]"B�„!�B�„!�B�„!�B�„!�B�„!�B�„!�B�„!�B�„!� •¨²½3Mâã�Δô ‹J–9Ù5A“e$€ Òª1lç´…6]lÊѹxÞ<hõXŒÉùNN̦�‡Ü|‹³‚ Ñ¬h»hå£säpÕQÌ«âW±N•z½nhžÚÀÓ¨Øtn˜zÆ‘­We91¢t°à{ÊcÁd Ä–�åa¾ouáÃJ}°ïÊ�—\ä]Å êæ]jo¼å-Òå]�¨s.;¦ë]m5÷c©ÆþGxS²œ™Ô ‹Øp:5 0Ъr¬eÊ*RŽÎ¦fyà›�ê×0ç0ȸ„6©ˆß Ö¹t¶ÇÜy�Þpï íªûNŒÊ럹:s.òsó¨N¥ ÄæuÜdžթDÙp1 ÷—g)Jwl‰Ó¢ô—.l¨Ê‚ZoÑ�:O”��Q)'B'J�8’J&5.0±§W'2H�=È:Ž.¦sÉÌpÄ)D™6W ’¨†Ja%L-k±�®n¢Ã„…&ªGX¨Kƒ\Ðbì÷&lòÆôøS“œÄ5ÌѨ3ĸu5”a¦Ï,oÖ¼ ¦›<µ¿Zð!Ìxŧ™r2 ­3½BÊuj>Ðs� '=×®Y>øòu¤5œq 'Ih%«¬¼€Ð`^tIØq‰R."T‹‡DAOB#�\MÀžDÝ�M%uتsORsrJÏ05ýK¡)c8*l•9½�¨IkÈe˜›D3è©ûLÞIxó-s‡9²‚ÙšÒ±•§ UƒHã¹]ŒŸ#£¾-[­jc¾œÒÓÚ)=úÃE&óî�Jî ›d[2¡¹R%Ä�ÑÎaunFögY¼s৸�wu)R:5_ϺëHin�:•|ÕW Lõ¹WpNmãd"ÐÛ‰Bþ¤»H›$ .ÜŽ˜R‹Ã=JˆÑI¥îóÞ­psòi’*V:\àÁÑhô®@&òˆkq ñIð%i¨ã›'̶OQ]6ÍžÕJ›5Ù¶yÞJcòšïêŽ��ÙÂ,;kų[•�ü·»}‘ÌHL%ã­ÌÉ<à. �'Uë Éò‡aIþtŽ´%|çNú£�Ïß+žç4ô.§&¬7Á­îžÁÖRl oªÓD»ÔA\†I5”å1…É­Vï^áÄâ;éÅ”F5'‰‡¾Boˆ¼ë|( ê¶²‘èב¬Úë”›r¿ ó7Àš]L ™<n'ª-·ÊÛÎïã‘/)ÜÍ;�ÿÖÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�.VKO*§e×8o]œÝjl:›NUå^O•TÉ_µ2Ì0cÎàSD±¤0l”Ž4Žmm=îhNÊrjyU;þEÃU}¦·cê ›+¾Ÿ�©ŒR¯‰lwbe¼Om<M�eÑD°øaµ5¨‰‰{58bc�BÊrmŒl´�ºNÁÂøVn¦×ÅjN²ò.p¼ ŒáG²Zò*ŽÆ›¯¥SLǧH(©HQT9[UŸ’sT¤W¢&˜-"÷RvùºÆ‘¬(ʦ a9CÛQÍÀݣ̞+6!«ÛçJáxÂð’e)’CXã,0t´þÒo]X÷o]Ö.< ¨)â³ÅÄÚzêg2OI‚ŠÜ¤ e¼FÐæ+³kSw’ÍÖ»(ƒ¥£¤£‰"K×N z-ié½6J- ë‡`Y\E,ÎpxÂn䤳  DùîJiksÚa!k‘⃠ä@ dfpé°ìÐxˆJ_S8ž1)¥úXÞhê\;hlu8%4±ùÚyŠ[làBG}#8'‘å´äiN,úÊi¢Ü,cæWm•ºçÏ�4Ô.v|^W,$›9mfŸE:Qµ=%кÛ'O+�}+; _Y'­ƒ å8íVŒZÁÆæŽú6 CLqî »lÎ!­ã-j{rz§ �̸ýdF€aèœFž`÷w,Ž’S¶:MÅ€wu�èhw9 Õ{Ï [pêL#"§˜8ë{ŸÐÐÑÒ»‘›¥ém#�º,À°wËÏ;×Fº­AâtêÔÜXÞf€:SVÚZ­¬kzM£Ò£Õ¯R®ýÄñ’zÊä¤uRÞ-™Ù¶ÙUòúY9ÜÌ nÃ4Z=(q¤ëÞêµÎ—M�2W Y=z®u†$î@‘¤Âèrz,íõÚ€Ôw�äÙ�i'}ºZѵ&ov:}à WùçܹÔÊXìZê§Ò¯$yÖ LŠžò“ë5ds7Â�åõ›uÓ¢<Ãó™(�‘ÕNƒØ¸úã™·ª¦X<Ã,=Ҙ쒱3^¥67Ts Eq©”W«Û*9ün$.*2´Y%KÐZH”hä�ßåµS¦çtºÊlä Áµjq¹¬Ê:PÇœO% ‰`åopÜÇ( 7™;>®ç¿¾M·PoM�Í6õ�S[’å57”žî&”ý£\vÒÊ#Ò�kO4“ЋNg1µ±r0åyK±ªà4dtBâç¹Ûçq’zÔÁ’ä�¾®VÓª›\î“ ûK�ú§Í8�ÌÐÞ´CÆÖÌê©b¥ì®O§Bµ[©Ssû–’¤ÈÒgh¦Ökm6Ï;ËÊãW²ªÜ÷TpÐj9š )ÜûÅlèr;±§@zR£Zy�'¡0·!glÊ C¢•2~´û=J)ª1 `ÖAqúÑ)6z¹�g¹½@.JÈK¬oegÃ%ì´�ñ ‘Õ<ÕW8ŽfŽ”Ý�ÿ�0èó;øõ îs·Ä»ŒÊår$êÌÖÓ ÿ×Ü!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@çZ…<¢™§TKO8ÖD ‹QN”ö)ö]5rgŽqà=Y±ô2ºV›ï[�®Žk^Ò×�摪«‘å ÎQ�’æbêFû»ýjéѧ&BÙY¥ùÚòâdº´\<ÔÅàŽÚÍ`çëãUõòW�³Q;5,å£t8Ú=mJÇ#Ëèåbæ Å‡M+«èí’™Øêp†ŒgëC¥T¥UÕC‡až�o ³Ê²fÔ2ð(V8<v§ñè<}*²£jQy§Y¶9•5RÐÅ*®Ù $b‰D¦®"'JI\ìªú{Ó³) ÊÁ¹â5æPл-t¦YµÂA‘ªô\«C‹L´ÁÔº·)xßnº î™ä&\’å4݉³ÆºH7Ž…Ù# — -¿Ló&ÊI(²¼hõ¸’ìÎÑÒ|+””’‰;‚vÙϧÕ$ÙüÏHþ5q”ÙD† $m�ÁéƦ»(7Ø-3�$] „¤’¹,î $mâ8Üÿ� aÊΆr´ž²W)•G`-È–4¡Ûr ÁÍoZ:‚c²ªŽßUqå+«rGÜà:BÜ’žùÆ¡Ð0E¡�ħI�@N2yÓ˜Û~I¬Öë—S•¹·Qki�BO:ä좻÷Ïw<u.XJÜ‘±v­;ž÷T:,7�ÈÛ6Ñ©ñnßÎeG$œL¤D�ÁËiГR_Z´¹ÐH‡;ˆf ±@y'ž&�ÖJæRA8.I(:Z <‹Ï€êjM’�Â�ås�T&ÃFùÜ‚óàIm�Á£�Æz.ÓÙ�.1N“ ÔÒî²SüU»÷S¥õVÚæh%F~Pâ ºíáÌ#Pf“¸-íI;gcq©R¡ÐؤÞùèM9k‡kc[­ÄÔ?[$t(&£Ž¤ÒIÅs �ÛµŒ•S-¯PCê¸��ÀæsS@LH‰’j”®¹Ç:jU;&ìF]”Á ØØ|•M龁 7u¡UTÒ¥´‘˜� O“úd̃”=ÕN�¸oEêÅ”rŒCN—0w>*Å™<pŠ*Û] ÊS«PÈRìn_^út9GÖ¡Kg ÷d¾°Î7OP+O¶ZîÖ×ÔÖ@çtNRìÚcY/<ÂJ’Ì©Ñe/mY¦JiÓ¼Îû6r¢/­Lr8÷’{5ò¯.§Ì壨 »mG?P6õ˜=(Ú´t>ÿ� îÝS“TŽõY§5l©GÿÐÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@2ÎÆ²¹Ù¨а¼8\ ×k�ÉUÉßµû"Ò×f©f:µ\ëÐ¥”3c¬ÐáÒ5‚¢é¶i±ê2ÅšJÁ­JÅ••"×0B‡”d ¨Ë4̃{GÄujPÝ“e½Œ&¦HMjšfò9;ã™MÉ;#“å{�lTÎÇcÉ¥rS²¥ î Tç¨sN†-4R×ÉêäΊ�,qŇ”\¸Ú#Ë™jÜÖ¸¸qðªr¾Ä‘52CÍ3‡$ªêÌÚµZ]Fnª²«\E\Î \×ö–¸c§™ : õªËÇ!$é¹$ è©).@ˆ¼âG*H(«rš�Çuƺ ©‡|â¿À¢Ùv‚’Ë´dK ɵ'`áË#­8í鈂«ì<àÒº7'q½Ä•Ù"éK0‡ Bl ˆm xºN³=+²šC9w@Dœ‡ŠÓ°aÎc¥<S'ŽååŽò ŽõÍÙCß¾'�ÇR%À©èv©³ÈИ줋˜ØÖoU–Æ—_V‹C„äaÝå&¾£ß¾$ê̹¨·pŠHóK’MPI$&—´gë€a7‚ gE–ŒH'@09×$0QÛdf�Ï馣F<Ù×#8�Ðlë%‚ކ°Ì9ÓMg”Ë#HD (; Üs¦¥†éFçZáѨK-Ð’F„ ­*U«¿c Â÷hh•u’z½Ðü±öG•°ßÊï•4º®D+ÍiÌø™ì1”-cÞl±¥ÄæJ±É{^®ê¸{ÁkeÇ”À QC&¡“6Å ñ‰ã8•ÕZ³¬R½¶7e*4q•¹.BÌš ™­w«í; äRìe.ßTk51“Òâz—t+U) ºÝN]ú6î'¬ÓÛúœn s6{(Ò§¼c[¬<éèD"8Mã! §B�ÿÑÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�(9_c(e[¶ø•^të rNÆvš�.S‚˜eywcˆfXÓZŽ ¼óøUžO•PÊ›j‹Ã´Œ8Âì@p!ÂAĬÊ;Âí›"y¡P^�&ÏEáF*¦ëVLe“Ewç^UvÈ™”ät2¡â‚™ÂçI•v2½ p+’ñƶöC,ÈÈgd)7 •¾´u+ Ÿ,Éò‘4^x88rÆ©¯Aê’O4Ì­¾�š2Ñ ÷Ò_¨­6SØì›)—aü&ÝÎ3ª|§±™U p+4·QŠª¬Í­Š3jjÐyu$”!@´YÜçMH€�òÁ¥$`4ˆ;CUúa0¹ÇJDˆ!"‚„�$KnD�€å(:¤ß€Òn–Œ7G]Ù!$ÞoH€¸»É™5\�H„ è$B�‘LÉ»–epiÓ!‡É»rßWÈ®²^Àdô¡ÙI5�£zÎlJ�4UV"ºóz(½ËÈŒõ —(Ê�fƒ Îr0dÜ®òOAæˆ~XûG€Ë‡+±W¬c)´2›CZ0�@èJ­§2JûE3MµWU”çV¨Ê4(ÐfÇE��€„ô!Z,ÜÚÁB�„ B�„ B�ÿÒÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„� ‰o ¾¿b2Z¦Ý) üÅ—e`…Æ“¼•5ÕM©ÁSg³ô·+¦3÷‡­tgfhƒc)¦ü�þh<= É5ôÙPY¨Ðñ €GJæ W=�¤°é«‰©ZjÆD}ÇeâAcœ|“õ¸ÕvQØJÍ““¼Tn]Ï‚°©ØŒ†¡�ÃLéa-è¼&ÇeT¼o•¼ Íx¶]3};Ë)Í0x–¶´*_ «Fµ˜æbîuÉi ;,—Û¡À‰èQ*ö>­KÎHÖ�4ª†ô ·™ä�Š/§6Xã`þ¨SÏb2ÙÜÓ»[›=k�NÆå”¯u7¥¢×Q*5de‹4¡ëKfCBsšaÁÀè":ÒKsr¸LjÚ9®âH€JD è$B�!+Zç˜`.:�'©�"E2—bòúÛÚ.hÒè`éSèúU7×ªÖ �9…%EO ³\Λê[‰HŸJ…jî³Eލ|È•©¡Ø\‚�冫´¼Èæ¸)ícX,°�˜ Ř¼l¦­µ¥Ä©½; ÞOè?”Ôƒ”8RéÞo“v'"É µ–Þ<“÷GÀä+)Ìé§µy¾i]îE`!S*!�B€!�B€!�B€!ÿÓÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@æ1âÐá¬Ö£?±Ù Mõr =P¥!q¤ï:ªjæÖ‘\îÂäÁ®o�~W3Ø �àúƒ”òµBæ95›f‹Ze?³'ò×ýgÀ�föOå¯úÏ�\!snéÈwoóNjeHìH7Ϩy@ï.­ì'cÛ‹î7žô+.àS‘y¶hõ¦Egc²{Ú åºåIkÁ hhÐ�IPº’Wu7{oL„.œ!�B€!�B€!�B€!�B€!�B€?ÿÔÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@ÿÕÜ!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@„�!@ÿÙ endstream endobj 248 0 obj <</BitsPerComponent 8/ColorSpace 249 0 R/Filter/DCTDecode/Height 359/Intent/RelativeColorimetric/Length 22354/Name/X/Subtype/Image/Type/XObject/Width 841>>stream ÿØÿà�JFIF��Ig��ÿî�Adobe�d����ÿÛ�Å�!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDDÿÝ��5ÿÀ�gI�"�ÿÄ¢������������ ����������� � w�����!1AQ"2Raq�‘±Á3r¡#bÑBC’¢ðDS‚²áñ $%&'()*456789:EFGHIJTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š“”•–—˜™š£¤¥¦§¨©ª³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùú��8W�������!1AQ"aq�‘B± #$%&'()*23456789:CDEFGHIJRSTUVWXYZbcdefgh¡Ñijrstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÁÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêðñòóôõö÷øùúÿÚ� ���?�Ü��������������������������������������������������������������������������������������������������������������������������������������������������������������ÿÐÜ��������������������������������������������������������������������������������������������������������������������������������������������������������������ÿÑÜ����������������������������������������åm Éò� &«ÏD•5ȳ¥çÃÌÆ<Ž”üs•_.M¯mV^c“gd®¼ŠE©–d”|ehEìrWê8KÃÑ7/&}ĘdÙ=>(Gš)wRK@`°² N Ñ<yzæV¿ äKNéøm‚ðr�<%ëC%FŒøtã.x§ÚrQ_Ygcá1w—Ô#ÓðžASׇKÍø5‰Qœf¯¤¶§uæ!ÕðOƒêð¨Æ/loËçàÁçduçFZ®îºÕ™ÉÆ®'ˆvÖÄêŠ(qTóEÈN^ÈxIeTÖ¾óZ]§lŸÃù5G™”FT'®ûèõé]Anªtbƒ°E)Ã(—-sé p �«:rS‹ÐâÓ^aÄÊ€��������������������������������������������������������������������������������������������������ÿÒÜ����������������������������������çZ0y‘NsâGÓ³¤)�n²o6’ÝÒÖ\ìnå:¸×x{÷KÒûÉ(«%d´%‚8v…†1BOŽü‹ü(ý�N������������)Èr\­Z½5'ÆXIt¬I� N³©´æœžASÁfE'[Áµ[\Fìýftɼ;›=ÃÂÝ)¬’itÇJ.ÎVG“å‘ͯ-’Ñ%ÌÈZ5L.XW ••GE‘O—*Ö!V*tä§¡§t8ÎÔȼ!à™:ÙÝZ:e_X÷¢Ç ðµ ¶ÔåéU¸�àù˜(é“¡‘ŠÅ%o ¶†ú­b¢Ä� •���������������������������������������������������������������������������������������������ÿÓÜ�������������������������ëe2u�Z¤`¹]ŸPMÐŽ€TW÷�d°ÂŒeUíàGÏ�˜®­áܶ¦ói/R³Ÿ[õˆ;,*ìñ ¡Ê{$W%Šj3ÊòZxN¬Z³“}HÈÔ­”TÇ)«9zœç~­äåud³c±{¸�vkȺ¤¿B4U|5’É´§(Áqcy¾—‚í9¯ä”–m3·+Jü­Ý³>) »n‰¬uS’^ËÞDý–‡\þgÅÃ[UûsõŠQNeȯ�Ñ=‹„ô¬¹ø¸k{ón~°åï!—³P]øB�PË‘_ ±cá=+/ãï ¤øtd¹š~±ÞÈeÂs‡<}k™¥ = �Tž²JË”ö<5ŽjéøC"«À­ ìo5ùìHÎ�³®³vß㥅ðÍO šŽ«3ºˆ<¥W"xèÔÕð–EK UM­Qß?5ÈÒðîM{S§Ro™.ó? F2¼£®+º^f‹ G‚Þò\ÎXÊS]©†\nê@òžnE$‹øS(Ÿ‹Èæþ—põá ¯Ù²*½ 1”rOå>&1ob””º¯s¯°ºñS«KÉ©.û“V÷ç‰.˜©»¢Õ¬Túq=ŠB>:…j\®›k­\íKÂghU�ø­æ¾§cŸ¡rÚ~+*rä«/:³9Ô�f­–d�¯5+Iûl¬üçgý]1ËX]#õÍzòÄ ªPÉ\³r:óÉj{õ;ÛÛ*wwl²‡ËÅ%VþQÓÓ�SgT_¢¤ƒ‚óÆt2aUáSÊ/[&µ*ÚpÂ2})cG(£”,êSR¶•¡®tñGC­(•ð†(¬qMPÊ“ÂÕ²Zž„ðšiÇQé\ûW){FqR‹R‹WMb™Ã,Ȩe´ó+,Wk„¹™I徫™SÓri<6tl|„&க~ñm¬6jaÀÇv�Ñ�Ë'ÊhåTÕZ2΋ëOcGRÊÊiÉÐÀ��à��������������������������������������������������������������������������������������ÿÔÜ������������������εz9<sëÍSŽÖìSe^ò«Ç#†w«ž ¡i#JÙ8,QDZV=ÂòRŒS”šŠZ[vEnSáÌŽ…ãJõåêx>ÜûŒÞQ•å9SίQÏbÑа8ت+3¹@ÜH•19á*‹,£Ãym{¨IQŽÈiöç‰])Jo:Mɽ-»¿8åNoU¹ÇªRZ-}¯Ö*mºÆ!†(I!Š8]ïV×Ü…ÏQà+z§ÂøAû‹nò�åB:Û�š8%P‡/XåFžÀ�["(*|TtŽLž9©.T8ãH€>ªO‚°ÚðE‚¡J>Ê›æðÓ�ÛR.Éx†²hÅ^¤»‡¨F*ñV[^kF÷K£eJá]ô°‘ËiÖp•X­çæ99Ê\œÄ¯CRå]"<’:¤×S 3ª(QRCÉ'ì­?1ÍЫ1o›’%l�Ó˜¡ki�Ýdº>Ë(pj9.,÷ËωS©µQÆ”T4ž)wCÃ�vYD;åÕ§´³¥^�xçQššä}ÆD|%:rϧ' -qve�ÙZ®‘xòž±hÍÊ´iVŽmXFk•\�èZÔqÉ*´½û©yá𗜮ɼ1VŽSÒ<xá.•¡—rŠ9DsèÉIk¶•΋†*«éJ"†;¬”C¨èTšô\K[DjÅÙtT]�¨ëºe9?�[½/ ·ëž+O:ê%J1’q’M=)«¢7¡êPÇ$•£®ŒÛpèzcÙÈvMQ'CÈuc;„ŠuiÕ‚�9)EëAR�:°têEJViè!¥ µ¦ÞK•i”ZÂ\ëD—*ÄíO(jjŽQÊ£àãxKÉ}ÚBwÎ8eJú¥6Q‘å^ªò¬‰¹Qöh¼l¶Ik\º‹|‡/£—SΆök‡¥zè”ÒjÏÊ<»ÁµrZž�ðuâ㌠µm²Ö¶¢2pR©WWLX¢VUk\Šþ/�ƒàï SË¡ší Ñ[èmå\„âi¦¦Šb…ÂÜ.†€�œ������������������������������������������������������������������������������������?ÿÕÜ����������ibð��"Wð–E“ÝN¢”—²Ç|üÅ>Uá¼¢­ã“­Æ<m3õ‘£†¥°XcŽ¥%}—™NY“d‘ί5 ‹LŸ2X”yW‡ëT¼28f.<±—V…ç*従œÛ”ž™IÝõ³¬(U¨³£GŒ÷±ëvEQY"Š…@ÔOÅ‚xu&ëWž}i¹Éë“»IkÄ�áNgžõ¨ÞÞÜý`U$•¡½\šzô•—[QGL5PQáÚ<�Ô;z¸+¥� (%}�cB´±PvÚÕ—œéÆäsê¨;ÚSŒ^Ëç>¨Ü‘Žœc�Vm.U›Û‰Ô™D3½<ž¤±{Õ˧¨|§“à QÎ{[Àäç9k·6AÉ·U¤… T´µ}¯HÙVŽ¤ß˜à(Lå­úG9Éò.A�P:€à8 ¢Štà‚Ø[ ¸FXI'ÎŽRÉi¾ âúÑ [‚Ù¢²Z‘Ѿ\šNViÙ«2ÒÁ(FjÒIœµ$¬—ÊÁISÉšnÜ�×#Êœàí%c’‘5cGÓœéMNœœ$µ¬Š�\džRµ<ªÑzª. çZ» TÓWX¦dÉY&][%y«K\®g«°¶%Ç’/d°'L4aõhÓ­ÚŠöÅ= =©¬S#TÎ¥O+[¾Ný©kÊ>R]«§iÞ†QK)†}'u­hk‘£©l“¥ ÍÃC¹rñ3žL“ru²w¢§ Q\¶Ò¹tíÚKMI)EÝ5tÖ(‰*2vêdŠñnó ð‹Úã±ù˜ÚRI:Ùå úe„¢õÙ=“CÔq9PI¥šý1H~ðdã?Fä;Ú±yÒŒp¿*åäÖIðo„¡–Gs©h׊Æ:Ÿ*õ‰ÔêB¬黧֞Ƶ2§Â^ ’—£r+Ƭ^t£~©rö‘jÕÛCUÔN”k-ÇC[+ØL¸ƒ|#¶³´kAo£·•ɦšš*Š pºÐ�Ò ��������������������������������������������������������������������������������ÿÖÜËt¯.<Õ¶r·š7r­/U®H%;Îg&vWÚ;6¢®Ý–×�ÅåT/hË=ì‚sø-Î5¥‘døÕYò[oR^å‚ VðÔ’Í¡t–ÙÍIûl.EÆ•rÍ–CbqT›é ]Ú«àQ•¶Í¨.öC¯á(Ѻ©Zœ_šueÚ‘U/Geü*•jÅê…7yÜž�É©|¼UŒ=Nz”½¶š}¤mÕ’Ë¡°Â¶3¦òS}/L>¿†+Nꓚå“KÍ»Jú•«V~™9O‘»“]oRV§BUå¶mÂ=Wläü!V8dð§“­°‚Îöé]•·:ÞA|)-‹°Ý8ÚYWUgF›ŒxÓÞG­Øì²C’�GÅ¥oo�‘YVUS‡Vrç“9·)p›|îç&¯”n¶–!7}OÄѧKÕTœg?rv]G)ÆUujð“å”§Øš# �µ—éOK3¶çAiªß“Þп ËUI{l’8�©dõë;R„§Ì°ë cŽŠß®>ŠÑJþTÛì°»µ¸0„~ƒ\ïèOª´)z”óçÔ…Ýr:>&“«.5G‡¶£²wdˆ['RqfºQ”ÞY[ YÍz•šºÕ�÷Fœ1ÊjÞ\H<ùuè9ÔÊ«ÕV”­,w±ón––�Mb℞Ä$ú%C ž Ÿª{éu³Œ¥)»Í¹=¯¹ÑÚºÅÎŽÕÖ;) 8ntv®±T£µuœˆœv®±o«¬éÁEÖÔ8� )Ó€-€P8€§N� (�XPÇN*JÍ]rŽ Â5L‘<i»r=iBPv’³,ì$¡«I]p“VF«¤¬‘S%”q§¾[5œ,FR&šu§R¥ª”¤ã%­v5¬ºÈü! ¢Ôêo*ìÕ.oX¤ †' ìj5MwÍA¾Lå-ÞƒÜë¥lïe’âÉk^tBÈü$ãjYKºÐª%ë–©¦®±L¹5Ьoô“ ÂRœå*kqÊ¢½2“{Ù­·×Èú*•hÖN׌¢í(¼%±‰_'…t�Ü' a5‹÷u“œª(Tµ,® {5À©Ú¶­+PRŽÑý(ú™¢'„² Ñ©èü‹{8¼éÅyä—j'dt2ÚYË{R8N;9W#;R¬ªÞ2Y•#ÃÕËÊž¦Så¹-OWYvI…6÷ñÔ¯¥s?1�vʧZ&µ1e¸¶2د× qÉršy]Zž‡¥kOZgbÄçIKM6�h��������������������������������������������������������������������������������ÿײö3á*’tè¤ÝÚVŽ|¼É/0Tö+U_+ÊOW5Mûl1"Tð†TïIQ…Þö’T×›+m»·wµâÅ\Xmô†’±«�Ã4Ù5ÇÁÔñ©R®U/R·8õÊì_GÆŸË®OJŽÉ5ºO®D¬hWŸœåÍc“w:BN™6ñ]«•åUümYIl½—R²8£¿¡+.e?.¤cæ½ÅT(¯”CšœßbA&ëéN§ ¡t‹¦8%,‚:]ZœÊ4×�ÉŠ²Œ–>/&‹å©9O̳PK µäóY²1ÚžK”Õñt§.\×n¶uö!^>)S£äSŠ}m6ržS”Õñ•g.G'n £ äâ¼–<ÎëÁÕc�z”¨ùsMõFã•/SáÖ�g²œ3W\ˆB„Õì“–­×EÕ•äôþ]òh'ƨÝGÕ eL·*¬­:�G‹êêV#¡P[3–�ªe7‡NlQF·ã&—>�ª'ÀRŸ2vëC�íe¥» ¢–„ru&ÚYª.ø&îú‘">S%�(Ê1ÚÔiG®m¤ã¢¶�‰-‚Ù#N„1©R¦u_¸¨¯8õ•dðv§Ÿ7ê#v*’ó�•òwcaF¤øræ‹cý QpÔaåJ1ía,¦´´dòkmG6½ÎIyŽ2ʲˆht©s8'îí ù̼HTöx¿%J‹èx­._†Úø6i ÑM]5¯ÍŸ.æ.çQé�GäÒk¶Á5x-]×,bnãG[kŸ1~ÜÂ0¢¤â炳Në«Yqã*ÏŸ6=¬7*z&ùH'Ö ^\N¶OÇóÿ�jÉøëÛ¾†¨Ò÷æ_‡`9Q¥ïÅN‰Å„ð‘ËU}ô�91F“Ñ/?Âd8Ý„EJ’ö�hô_±ŽNœ}ž¤|¨¿…;3–·›%nkT½Þ°ÜÞÓ„jCßȾ{®äuNú1æiö0"ÓC³Y Mò®{®Ñɳ§ØQ× �°¶ÀtàX° XçV„*c¢[N¶Á#‰È­�)Óv’æz†–’Œd³d®™®Lᾆ1ó¢.Ãèd{òL¶y3Ì�åGf—nNB0M§4v$¢RfŽ…H©Á©E¬ZŒ+C6z�ÓXI5¡§´¤É²š™,¯ô ë”»¥V�h*”ÝÓ.†%�¬p8ÕW©¹ªU^exßr¬–ZÓ]«¥á8׌¨ÕŠSJÓƒÅ4õ­©�«Ja™5†”Ö 5¡§´Žã'%J«Í¯ ºURÂKZkµt£µš‰^—HUµSÀÙ^to,š«Ñɳ�yÑ} Ƥàó£%tÖÆFœiå´g“×Y³\%±ê’äøb¿ ¯S!ÊA”ð[ÞKRoGCí"°.Y‹« –D²ä3Ìᯠ_.€�° ����������������������������������������������������������������U²œŸ'W­R0çxõi Ž¤Ý “¨¼?’à 0•W·‚¼øùˆ5=ä\¼\!Ëy>âÉ º[SÙ"¹,SJB~ðŒý­›äÆ+¸äü#—¿}=ºÄrò¼ËQÇ}@1^Ärõ·6t�…ü# ›ò”_peåy†ˆã¾ºSb^Ÿ¼ƒ-‹Jq…EÌâüÌïñp×÷æÜÎåØH<¥²+‰ãŸÿÐY: O{)bôÉ%§b]âîÉpiÁs§/ƒ6s— ó¾ÑækÈíèšëƒ,ß%(|!’©R|9J\í¾Ñ 9$® �¢ @QcN¤øræM�–KUpói¯W8ÇÍ{„ˆ¶•Ó€¨ìéäÐñ•ïÉN^yfŠ�hÐ�_URy‘ó%ÚvG-°žk6q:Æ�Y+Ækm¬ºÞ»¸¼kR¡êhCuŸ·cÚ.7Ê•JÏ�”TÍ�RõÂ@Ûý?D&bXJ¤#É}ÑõBëÎuY:¶tÕIGlœrhuÊïÎ,UT±«ÙF ?o—®1ÏÁôÞtÞí>4å*¯ª8{‘Ù"3n©¼Eú…O&ƒÞ8'õj¯?o©eÔuPœÖr¡)®5yµ¨æGÎq~§j4ßFm%î*Ró‘çáówJåÍÏ—\Ü‚h»’Ão¦'5W{RYë{B8¬;ÅûpÙÓ£z®R–Ú•!OÍyÈ®•zõSÝ*JJÚvêÐr9lIXÝùbn¶M�ù!:Ï®£HkË#k)U’Ø¥ Kª)�†([3¹mbâ’%]7…5ð)NoÎíæe6L"»ŽOH™ÛTuuëËMI?�1·oKo�ÜjH[·¥¯)ö!‡}Í*QÎ’�ÛzÒ–À8ÝG4‡$9B ÙTXú–Ím=)ØLTÚÐÚ:ªµ‰K­œ�õc¤YÙV¨Ö-K�'Ú…S‹áB/šñìg%aÈìÈÉã8­pæ•מÇXÔ–©©yJϬŒ‡#³"Ò%)½pÃl]ÐøÊ2ÐñØðdXᣢœµï¹ÕÉLƒ„‘`±Î3Kjó£¬Z|§H°°b:ÀtŒÄM -‚Íh�� íÕre-ô0–ÍLˆââìÕšÔZ �(Tá,vë8á' r¡•§J5ªdóϧŠ|(êcçAÅÚ.ûÁü)ÎÍ`ðdiE“M_EÝð¯8>u­©N5c›.tÖ 5¡§´¤¥Rt'ºSøÔËšá^ðéZÑl1[P뎚¨âÔç% <Ü¢š¼'l$¹¶mZ´‘òÜ�eÔ[ŠÍÊ(鎾ng©“êSU#kÚIÞ2ZSÚqjsyÑ´rŠJÍ{,—¬õl`ÕËá Riªý2> ËQOrªý6š³¾–´_×'”¹\*‘ð†L³wÖ©,µ¦¹Kj¡”R�Xh’ѱëAÌ]k¥Gl�­Žªw/3 �*��������������������������������������������������jôrxgÖš„v·§‘-l)ÐŽ€BôFY”|ºÒÜ ý«^몚ǮÁì:qË*O)|Y<Ê~Ù.»œ�âv©lg,%KSÂY%™îµ8”“«.¨'n‘žŠËjøŒ‘Åj•yÆŸ¸Ç=’²\Ž�že- .¢o ä´•à¥Sc¶j|×ÇÌq¹VäJg±`o ýItü1=5¨Rä�9Ô}r”{9^S•d·Œ¼ ¥Q{$2x7Òܰ!e~Ër•™M*Þ”�äùÞmªm÷zŠ¢²^ž,Ƭv\V« BŸK&K©á_ N9¾ˆŠOZ¦¢úÑRÊ[rš�Fô¼æŸœvløÞïPZ¦ÛõzÅM·]#à 5(V"‘ÏwKÆFPåjë­Œã5x´ùƒ:kJóz×9¸R›½³_8v9#¨½:¦ªÇª_ :a<³Öž áÉQ�i\èêrZW::�8ÏÿÑz¡)ãÓ“xáR+O•aÞƒÊ^ˆgy2Œ»9¼¢¤¢”³^HzÇ78½6èIv ÐkJ,,ÙßЙRÓF~ÚØ«&Ê=ù©í’õˆÛ­´7×aU%ìöøõ€”XD½Æ²ÓK7ÊVø3C¡ï€â¼”Ÿ�'ÚVË*\ï›×òš�F�w-ÄﳎQìòoÊšK©Èá(æé”WKîEvé7¦O¬M:@’±µuc"vz�µòb¯Öî6S¦ñ’�Wê�ל�OOAØÖCýR yÌ5åäøO A)è|çJð�NNò»|®áf´�Z�&1&ôÍ–ÁÑЇ�61kæ›Ô=®ÁÈLbRZ…¿"2Z@àiÄQ.ÄçàÚÚ¥¶»Ž¤Ùdž·"¤ÏaµøÐë~°¾Ãkñ¡Öýc¶®ñ¹ ôC$Õñpèø*:{ ¯Æ‡[õ‰‚”¡Î׎ÉYhKZ{¨Y3T‘b÷%ME+Í)6Òokb:uª*’JØIû*ÛÌJyó=BK‡müS›È+ÊNMÃÞ—¯ ì™h]g^§'¶ÇÖ«TäöÕëWƒëq£ÖýaË ­Æ�[õ‚Q¶ƒe9:²ÌšM4ìÒI¬/¨j‹ØJ£‘Ô„Ô›�•ô>Aë$©¶=gmYxS¡‘3^ÁÈ”²Z›cÖÉ*'{Ǭ-YËu|à¢ÇY¢BɧµuŽô4ö®³¶¬�º¾GC‘Õdµ6ǬrÉgµu�“8âWÆFR\§E$ôà*ɧµuŽY<ö®³²d[B 9PšÖ…t¦–¦vLŒÐËnÁ}Û FÝë-®&kZ�à’Œd­%tp©K7ÕGUô¯�zä„ö޲jÏÂS:›Es§ÅÇÔ¼$%:“¡<øt¢MJN8ÅgEjÖ¹™ÎÊJï_f\ëY H±9«è³£Z¡�:ÖÁjSr´ í8ð_säeM9O'šœõëÕÌ[R«ÐÎ�JÖ‹!ŠÚ‡YLpÚ¹ªŽŠ«TŒnÚÍ­Ië[9Ö¦@Éjú(Ü›½ ¸Æ^dû™iR2Œ·jjòJÒ�zëQ -ÉãV“­K½óäzßN¾³‘'Z­‚$ð.§Ò@AðnUºÓÜj=ý5‡*øBq4æ¦W.Ó��:D������������������������������������������µå&’Jí¼9Ö¯ )^òœ°„#Œ¤ù~„qY<ëµ<²Í'xÑXÁsñŸ›bÖrd’ºèB<¢¶S½ÈÒP×^iæü89sà¹ÇÑÈéRžë+Õ­ïíMôº5%ÍbF lH†òš¹KpÈ­™{K(’¼’½™ù¹ÎbÒΦÜÒ¡]};ý1ÙFUC%Šu¥g,#œ§'±EbÈ®^ʱ�²<i%:íspcÓv2urÉΤ�l¦K}'¿ªû¢¹0EF[á,§,¼/¹QâGùÙ£J¼„[c±7R£…D³KôÆ;åFC’Éî Ñ5õ×­-ÒÜ×ë²¥yÖ“�I9Éë÷p£�±Úñb”8›† öï±—–¨õµð¡¾Øºþp‡ �¼¶yþLí©¯?`ñ�ÔÓÐÁÅ=(V“Ò®75® èx¯\Œpk±“Š—ŒVkD– ëŸl$³{:Åi<(ÎG ùÒñ›øqÖ•ÎŽ©©+§tõˆâãŒqÚ›¿iÉY6é+=px\é*ÎëJçGCŒ$§g¡ß°ìÿÒ¬¥'›§C:]í#Â2x§nS¦døÂlÞiLZ�{ÎÎhYFK�(èÁµ}�v¤5¹½¢8´ìÀäÁ 9SzØ»›Ú&‚›Ç ìpIÞÚΊ2ã"Çèž�®2¶›„Sz�åèK@ÜÙm¦±x�ät!Ç8żV³e´1ϸqÍ&¯~(åm°�ñ’Ò.l¶‰g{Ác¥s¢o„oè…ä.ò$`î±Ö‰ž‹uÓ\EÞITÈ=�#!Ýíïh‘‹“²:*OiÂM�»ÚuÇp�ÙÉv!Ž*úQÖ0r¡^™.È�êÅZù´¾Í.ÖsMí;Ö¦Üic¢’íg''Yè696¦Ú¾�ê“ÚG\—ÇG§±�CrTÖQöKà¬HÂVÒITAÖñ&•)ÔÆ6²xÞIv�+P”*Ôš²…ðJJýDUi½ì:¤�jÒ¨•³�í°”ÔˆIκ$tCµ Q–Ñ\^Û€„Šlz‡(b¡Èmš¶t‹Œ\�—m„QÇH³«¦í1Å Ç�x¤¶+Dˆˆ¹1\ÛèÁ‰ŠÓƒÛ¨�[\mœ}Ü>8¶�˜Õ�9Æ­ ¼úxKaÙÇ`'m=~¸50NT¢wº{ס§Á|ã©ÊT§�OJÓ³¼‘VŒjb°–Ò3M<Ê—VÐõ¢-H±4×®,©T�XçG¥l/I“Ÿ´æ÷ëc~ÍÌõõ‘)NPŸª÷¯\ŸF¤n´<}ŒšsÅ*‰Z¼&UeY<²JË)¡Á½í©=œÌ´£V5éª�ÐõlzÑÍ%èz˜Óš´ø+î!Órð~PéËÄÔÐûú5‘Ø®wxL›Á©fJ§}`�XR���������������������������������������µ¥�¸ÐJuu߃õÉ÷i~q'RudéPv³´êiQä[eæZö)Ò…(æAY^íém½-½låd¥*^@Ú4#I¹É¹Õ— £ÒùÅÈ-zô²zn¥ifÇBÖÛÔ’ÒÙË*Ë!“µN)Õ¯>(ðŸ+عH2–ãQÖÊeùZZ/j4ï÷'Ìq´¨D¡�ÅK»U÷õÕ«Gu˯Fƒ{Ì�c9½YÖÅù+¦äL³ÂS¶åOÒ’VP‹YÉz©-ËU ‰_+�I77&¬ê<%m‘^ʹ/[dB˜£¸²F ±*¹R¸¿L‘»¾Ñ£˜Ò²ñ@: �� ¢: *§9h]:�1™®< W££a)Pã>¡Êœ…׉Ù²"Eç`“ºÒµ„¨9êiêz.pŒ¹ÐÖ Rqyµ5è–§ë0 kÄSœf·G™+ïj{+ägOL÷ú¹ÅJ2WM;¦Eô="êJ)ך?ÿÓ¬¥Áér¥$•ž[­¢lÞu‰SƒÒ=h\Ç*’V²Ä|$šXâCÆË…×[FJK9[QÈê(Õ$ô1×[@àÕÃ|ÇC’’Ͼ¦tMm�c†ÓÐùÅrHlX09pê$¸,.„“V°pÈ5kºŒ³Lée©Ûœã&°±Ñ4ΜcóWyý`ÌYü8èåõ†Ý I*•£MØ_:Æ ë<¾±+,Š•dÜ”w«~äÎ;­(Ï5S‹³µÞ’FUVª%8Fo5;½$®2·;eˆÈ�§½ütòúÇUñãçõ„†UJøÐ‚;ÅÒ¯J£PP•8ç'qMªçÒ�8f»Ô�­©6û)EÆ1‚´c{_KÚÙÊrJ-_-),Û7f€%A1(Ö„-8ÆPŽkRv¾7M>‘'“ÝxÚksøCŠkhÚ’M$±;2)9ÐɱɛXT§íß=dÒãÓöï„#FQqŽ;N´é¹§+Æ1X9IÙ]ê:¥xƒš»ÒcN4**“œ[Qy±‹»m¦ºŽh$åªÓ²õOo1ÕR‹ÑVŸ·|!Ó“‚)78¯jSöï„9ÙÓ¨ã<ç3¢¨jkh®I#¤E†ƒ¢9ÓjÖgUc¨ã zÐs“V°øµc¤]CÐk@¬ âtˆô9 MV:pU¤{IÁ&1<NžÊŽ¢,æàÖŒVÁÙŠó�DpOƒÚ � Švx?3±�f´hØ$áŠÏ¡ë:XKl ™ tÜ7³Æ:š:R©*rWסêh�Ò’³WG RÍÃL\yHÊT¢VÓ¡’¤¡Z›OCëMw£„áèˆ<ž¶!Š–Ý’]ãiNP–kÓækÝÐwœUX©Óvœq‹íL•dv+Í26GZP“Éka(áÜN!W§èˆn°Yµ©éZðÕë²\¡W…ž� w„.Td�O±ÖÜ� €�������������������������������6¢œ¤ì’»o�w9e-Æ“q¤°•E¦\‘õú¶‰iezo4J|û#ÛͦNZ’K™$ŽWˆKbâæ„„#N*J1JÉ"Q–Ô•W’d)T¯ìó~.šÚùy5òÊ™d¥G#–çF;*x$µ¨òò•õrˆF—¡r$éäþÍ=¨õ¶ôÙùùˆEê¿J‹`±9Í×yÜÅ鎲Ê)d¹ðɤêÖŸŽÊž2oduw.VBœÜ°Ð“m.W¥ã¥ò‰d°X!Km�C X·Æ±æ5œ&5ˆÇ1§�bbÑ¢äívvŽM®o¡ÆÒ#¤Û²Å�#BOaÚJQŒU¢¬dEÇxåPŽ…Ž×ˆáÂÉ�Q�èÑMY«§¨p‡œ%�M=2…¹ÚõÑÇv§·Ìýb\´>cˆLÿÔ©§,^ƒ¦ç)pzG‰¶o6æsœUÐèÓV»Ö-N�õ¡sÆèsˆ×;-gQ²áDáÄÅTã¯w8Ž�96sQßfì:*qxÇÌ=�65Á[!í'A)è|àrt ™%•Ðð—�ɉ&®ÇfD#Á\Àãg9FÃÔ±%«œè�Ø™‘“«e\½ÂÉþ^aÎt‹©â ·Wå¾ÒN_*Ënbï8KÆ?)ö’rß¼…Þvã Þ FB„sž:‰Ù,"©×å¤C§¦\äì—Å×û6ÖGFATÒ�Ö¡iÓRWcåÁ|ÂÒà Ð*¥' ÜVƒªSƒÒgHøÒN*ø¼I’ô2Vö«z}J9#¿¾eöuüD"nŒR4¡g{¸³ª§Ô(ºùL ´Zò{iì>ŽÙu¯X”07IìŠ&UîqÔt«Î ê¥ õ2Œš� yÉÉÉáuëªxÅöj€Ô¨"¢¶¥ Tâ+‚µÑ+'É•X¹Îéj±ßÐt¶Ë¯á (D]‘'"¾ÎÅ�"t© tå™M·m7Ú-8¹ÉEk9+€âºsq¶(t`­vKy56­v$éS§ãÈJÔ…ºg³çް¦§‹Ð‚@܆(¡Ù¨ë¹G”I$�‘)œÎicc­·© \3µ°±ÔqŒÍ*ã¬$@à8©+3›N/™Ô4àÎiÜ[ (¸â´ ~p: i<ÌS³Ó©÷�êÒRŽ÷JÑë §Q­òÅ®ÛËÎwNüëJ:{ìøéÖ¶œjê:�Æ,•í^Ž2¶+Œ¶s‘êÁ¦²¼ŸO³G·Ó¢“¥,èã j:5g»RÅ>vòóœ¬êrý:F:�hÖ†tzVÆt!NŒ½“ãÂ�»î¢U*°«èô­h’wdb†ê«4<�‘��������������������������Zñ¥hÙΤ¸0\'ë.P§@ê•!J.svKݱÅS�v§]fÁ;Æ“ó9ròjçNŒœ•jíJ¢à¥Á‡7//`µòŠtûZê+O;¾…ÊÎaº‰+Ê—|}J�¥:�F+Ke6W–z%<ù:Y*zŒ©È¹=Ü^ŽVUS(•åŒW+Ñ}\¯Ȱ8f¶ó猵l\ˆª(çB¨fÇaµ¥×šR¬ëEC5R£è\¯k9±ÌFVË•XÖ9ˆÎ#ˆÀèÖ5�QrvŠ»;C&×Qô �6‘FRvŠ»;Ã&×Qô"JŒb­ddEÆî QQVвÂÁ¢çpš]§WâÅó½êóœ:“gAÁμø8s.ö7q­.ë%k}£»”V–†:‘å} bÉ¥®}_/¡á­·ÔpíÅuÎÅÞ5Õ[<ã·-O­Œ›ÉéðÜW>,©a�•egÍËë7eîÜZ™fOÔ#�†Ä‘ÑÑ÷ïν`,†xÿÕ©„Ôpz›¬§f®ã£¥×=BlÞr�G)ÍIYhŠÖz…›I]F=Cãk-ìom€qÊBn‘)]Ýj:ÝqcÔ6M)$£y�âT޼Ý"9YhŒz…ºâǨáÊJ[ì㢩YífÆË�èšâǨŒu°ÍÒuº~Ë£ž©�PŸ%4Õ�™þ¦=B=@¤¬ÇgÄféêcÔ.éêcÔ$•ôSZÄÝ=Lz…Ý=D=´ψüž_!o ñÏtõöÑÑ©wlÈ{iÓ�PÎóŒÕW½— czÎùnvê³bå¼ZkXÈåU••×Qß*«Va'š´¢L©ÎÙUS Âbñ„±õ,�“ÞkÎqqŽçkÉ[’=<«)mÞ¤°æ:Õj+T“’ØôRAn‡#„ª&¬µ‹N¢Š³pN-Û-,Üæ®Ø¢CÕX{¨IÔS²Z‰-ˆeX¤”–�EJcáUZÒÒIÝ#èTþ®¿‚£Œ!–üŠ­-ÊqN1yë�aç% �Êãi)Þ&d7:[¤•§RÍíKR%�+«tóe}þ�»Æ(…b ÓX¥~S•Æ­VãŒc„}pQ•Jôཚ”/È­¤3rgì³÷X�‘Á4ëY&÷±Zmà—9RN&_PÃB©c¨­ Y ¯UQ¦ç¯B\§B¿,–é7PÑÎY’(�[EN9,Þv7w¹c“BÐÏze£˜…’ÒU$³½Û„`WIÙ]À!Õ¬¥6µGwÊj:t›Z^"Â)E‰Ü#¢lt$¤ÔV–MIEYj8Ђ¶v½c°£‘:D””cvpÝ‘õݶ¢ž*…¤®ÜßAÔIYjHãs)%†±"í§Xë'¤]G�3�\QºÎœ2Q¶1€�jw«XÝ ±8tbÇO ¤%ƒå^qpIÉk�ÒÇ #!½ßSÑ®,ê2QÇ:8?3©‹koé⟠;~�*n›Ýòmãð‡xË¡ëB½9ÐÂZÖ§ð§™ÔäkƲà -(èF�7ºQy••£Ô²Œw:Ë6~f Üg7VAÜ� �������������������9UÊ)Òy®ò›Ñã'Ðsܪåå2ýEéò¥¯™aÎrgT7]YW�Véä¶vÂU_<ÜgæÚt¥FS•ܧ.匟ÂrhW(¡“EGZXB:zµYFW[)¼x0â®KרEÄ•t²È`qP¨Wï“2¯ BžòŽúZ3´®…¯°«�IÔ“Ïwmß6÷é“ÖüÛÔ¯Áé›î¢¢¬Š¢‰Ä1 ÁUcm¯X1XŒ‰1¬kÄ`tk:×Ðu†M'Œ÷«f³’ ¤G³nËv†LÞ3Ñi%F‚´U»E%".;Ç8Â0Vа9N­8`ÝÞÅ‹ŠlQ²qмšK”á<¢O"ßKÖBF•Y»Û7ÕK}#“%k~�ò¬­x¬6Ëz½sžtêh¼—&ò=o¬hB.ï}-²ÄxšU#FÚm%cÖñ©Â8¥Ž×‹ó�N¤)«ÎIv€M°�S-ŽŠq¿+ÃÌB­^­K)IÙêX/1É“†ÆÞaS(£O…+½‹æ"TËß´áÓ/Y,%ŽL±A Ã<¦½N�¶,˜ãfõs7úVó}߆É¥QI¤ï°äNqVwzŽY�÷WÂÉ(�ÿÖ¬¥Áép„¤°Jü‡LùñDÚ7š¤uN�øè\Ç JO­È:�¬•Â@Õq’áDLéñF6Û»Ò$�ÍN|[‹�>-Ž�«Æ>c¢#¦ï}gU)ñ@:G9JÚ,4!EPEP8*D(|8C+§p8ÉÒ¹ÉYgŽ^Jï!FSºÞë%eò’¬­ÄXõ’¸ÊšÁ,Fp§¦\çdE„œ^e9ñNhé. æ—'9µf¬…§9Ç«ò9* hm^ çªTâ œå'¾ÂÚ€ŠT“ƒ­*’¥R5#¦/ÝD:u*ZÉgXéºTâLƒ†á¦„ãR qÅI] ­IV¦àú)Yଭ缞£ác}h·…¨�œp¸"–AKšÔ³^ ;2VK=Ç)©“·x·ƒå–º´-V–“Jx'ŽÒ%|®¤ªÉS•éçol—­r½Šñ ”ãW$ÑrEÊéậJÒõΙ5mÚ’“V–‰.S´¢¤œ^)«2ׂE pňUP“ŠRZS-!%8©-eLã:eMbµr­L•’V–vç(ÙKCå!“‘e’«dK©RZ"YÇzô¬ ¤|¦2VœUõ2Q+¥p»�JY²³ÐÉ ùñItjn�Ç„°a ¸v(n‹R7Ç`Äv#ÍÎi,53¬â¦ƒ¼d¤¹V‘H´æã;½zI@œÎ5 MàùǼÎ*MIæëÔ Ó°ËâÃ:\Q­ãˆL:­�22z#®ö #ZÐ�±wÀ�Ò’³ÞbǬè„jç�DÓI­�"ŽlyRyÙ²è`(ß�hcnÖèzŽƒZ¾ �iÞéÙ­a-Ϊͪ¬õ?Y…šÑŠØI[ÌpèÔ«Qàúd6kGHV§Sìö<Äå ºØ$·:œ8ÝíX0¨%:òQ ÉN.w\Yúâú&Q¤åX£³9jîRH’Ê(¿f·>E8=O¤ìÑÉ4(�À²©ð¤—;HæòªZ!y½‘Mœš:“wÀpÝ2‰ð)¨-³}Èç8ÃßMg/SêêX„ÿ�JލEIÚyM(<ÔóçĂΗ˜e²šÜ'¸Cb´ª>�ãèªT–nONËozç •ëTÂR²âÇEÅú"jzXo¦%î™.HšŽ2zm¾›ç~¹¶[ZxCÒ×&2ëÔpvKb‹Ñ‡)ª¢Å­Òï±’·³c}Z[šß ÅõΖK×�,˜Ö5Žb0:5�Ç„ç‹Þ­¬ÎG¤2yËoWœ“ P†…wµ�;jEÇxåp‡c·XáÇÕ„9_›¬*#Kp©^ÁožÅëœç:•9#Ô½v,2vôà¹tõzç'xš…*ÎS«R¦—dõG×<Þ�âØ´’£N0бÚñb„ŽÛÜG(R…> Çn±Ì'(Á^m%ÊD­—F8SWå– «HP�'%‘ªå”)àž|¶G9¥z•�¤Ü¹81êC7:œ‘\„\EªÄ•lëW,¯<#jQóõœo|[r{~iC7!TÛñqÀ‰jI*™¯gX’‹ÖíÍ€­VzZŠ%N/~ÜßR¨sÍ\¾pÇÙWpÜù[yË‹'Uë��÷u-óŠó°n<²ó"3½ùGÚ¦Ó¤­NŽv[Ô‘Ïu–Ñ“SÍ|Ç =Œá% ?ÿ׃ ¢RWiÝ¥±©=ïIÐM›®3¤ò‰Æ7IU¥e‚#Ô{Þv>.ñO�Z©÷ilBJ¼”’²Äæ6oC‡D�Ú[nÒØŽB�É!ê¼³œl°:*ÒØˆÑ~˜Îˆ4ŽÛ¼¶#Ÿ¢êqcÔ!ÀB¯–WS‹¡VYS‹¢* Ux’²ÊœXõYeN,zˆ¢„ÂÖÄ¥–ÔâǨ_FÔâÇ©‘E;3–�Þ%¬º§=LtrÚ�Û6=D1ðáÙÇ7‰Ë+©Å�PŽo(«ûbÔ]¶\à‡Ó’Œã'¡4úŽÌ…ªU FÝ×±ÚÖŠ–ÛùŽ4glõÇõîuμTv_Îæ>tîÝ;ê½ú.6„})Ï•yïë *–n¥µhè°”%éY»Zó_× §)–AÛ6Ù¾©wØJÔŒ3±æ:ù¾¥wÜmj–»¶3ÎVç:ENghE*iú¤¼ÃóV|¢½—;Ì2N r§æŸ¾”—³_Ît‹˜Ìב«gžºÒ½ÉË)Ê3£Ñï­©k J¥§jR½ú,HSßF\[yާ"1)ÊhìëÖœeNêØ«,q±ÂI¹r´—5½qÊV¿ª]÷N¥äá±¶Ÿ=½c­ÌâRœ‰tå:sÍ„­}=W»ÖÌ“ÎwV¶ƒŠ–û;ÝÑ`ÎJ\�‡fA©Ü¼tR�IZnïSvØž¡c¢û,r¥Q7œµjèHêžÛo1Ô J�õ+UŒRÓȶØè§QÞ.W²wÁªËx—»¦çXÏ9gm]§gI¨¨zX_”Få ‘Ívβ}`žå¸ÉÎÓ‡©·hU’TåŽ:»v¸Äôò޾ŽBDd2)n¯‘\î›±2ô×ʬwLD91´ñroMޱFYÙÛos·ˆÜgS”�äù§ a7}}à´8(Q°wŠtãZW8£fì×8ëÜ€�‘–uùÀà£e iC�´•ØÆwRºÖ {G´¦»n-i"IR>éèÒcG]�Ù �8�&8F€Y®^q/Ð:ÂbpèܸÇ\bú=kv‡FæÇŠºä»Ä´x‹Û¥ë‹Ò#ç8tU% 8.‹öƒ¯[B•¹•†» a3²A)J\)7Ò2Ûçq­$†±ù‡ÎmzÄc˜ŒáѬk:(J\s¤rwìï¡‚i‡Æ„å§z¹Iq§pWN±NÚœqÞ8ÆŒ!ªïk8kiiêÖtäæ ÉN1Ó§`ÙMÉæÇO'{ÐŽj.Z7Þh/\ãd’¾6sœôanö�^±±¤åŽŸU%‡DI šNòß5¢ú2rGm¯ãN1wÒö¼X§*ÙU <)]ìX²$òºÕ|RÍŽß…8ÚGT:zVL©V�5y»rk ÕËÛy´•¹t³„”V5%œö#šªÛµ8ÙmZH¸‹¡±¬\Ðé:“yÓvåožñz¡Î/LÝ»F¹B+~s…ˆle&·±²äÇŒÆ*’–—nl�áÙ '¬w8™òkg0ɼ-´"î€ì¨ç=\ãÎuŽ@$« ^ø¡�?Ð8c’Ͼ­€è�@Ë“I6öwHí¨ÿЧ‚“ààv”*FÖ–˜§Ö%.IÚz¼„&Ù¼Ý' Ó¨¦£'vÚWÕˆAO?s‹³»\˜ªÉgç_(»õ¡(ªùíïs›¿YÐMµŒ,\å{= ¾¡\”¥Åµú]‚””\¯…á%ÒÐêM%$ôË6ÝLà:&>0©›�{$Ò°ç ™ªWÁ¶º‡¦·6µç'æb¶·8­i¿=Ž›88¸¨·ìÊ뭮㪋Ý3�œS¿Às†Öiæ%ª6}m�"Öï³kôÙÐnŒfrŽ|ï�.O Uã)j�¯Ò줢§|/M¥Ï€°’Tç¦Y¶ègôÀ¢ó3õgfù®+‹QRÕ+Û –㛯t½¹3l,¤�8EiNWéhtá(¸¨·ìÑÎ^ï@²ƒŒ³^œ<êýáRJJ cji>{±õ%URNêÐó%p9NlEN[®å†vvo%ïaiÃ>N-ÚÑ“êM÷S�¢·Kïw[ß’áAúcò'ðVtãnOLÕ¹*šÜómÑpqqŒdôJöèvï�}�A)'NœSÆ*Wéw�éÅ–|-wŠ’æbÉMOs“Æérco\J²R̳½©Å>t>¤ã,£=;ÆñÇ™+�Ι‰ruw$í,çêºRm¤ôEˉ\XN+*ÝÞî�ß‘¶6Œ”e''kÓšéjÈ?\*Sœe+á›évï*j¤]’’O¦ï¸JrJxÊ)/nLXÉn…÷Îqir$ýp9{”Õ(ÔÎwr”m†¤Ÿxµ ÷wJ÷yÊ)¾Q²ùw‡ÙÉöDéRIenMàª&ßQߨGê…5StÜ¢ìî×& :«;Ú\¹>dJqÉau•UŒë;æIgrt\‰FJ9ùÎ×§$¹ÙÙHŒç7.�XÅÊ2ŸÍô»#*ŠêX)(ù¯Ü2œ’§R-ã%tJã”–àã|wDíÉšÐõãܪf)9a&×U½qÊN6Ó%œ­Î×pÇ$éB)â¥;®{X‘JJY¶ÅÆ�Ÿ>sgHºHýδ]œ–„öé:SNjRº‚mt;–dê+ÊÊÑÔÝðX¨¢¥VÎ÷Œ®­kbNEVÎk¦!҄䜠í›kô�Ô+fçg-6“4¨ÉkmyŽé¬Ëkο˜âTMÍâ‘ç ‘JSwNöè:BM;)+ެӢ–´ûΉ¬Ø[T;*H·F8ÜÊÉÛ9 pžé™.v¹!´åuÈ,÷5i¹ZÓÓgË�)¶8BUÍ‹Ôðæ$ÑUm)JöÍim¹”ó%�{Y;>‚] Ô”e9Jë5Ùk¾Ð„#Æ9ns²i;¾M�­S5+Ùëc)Ôœ³o+Þ.ýgkãÐuH‹lj§9a9aÈ21’›Pz0¹ÚøŒÉígÎvU� r�^28ɼçœîÑ(ŠüdúA„7N�SxÇtͩƟs:‘é8II;=,è©ma><¡á n¡Ž—(ÚwSk¬ês�÷Yl°J �gD­ŽÑ•!�ŠÒ<œ™Æ�ÚqzÜ’ÖΖØNHìÎMX,ÌjÁ¨«ì8Jà…�86Â8±àfriìÎâXäŽÌŽ#$8Eé]XÝôJK©œ‘ÔÑÈkòyê©î(OCT×Uûj9'x”Õó›�ÖN’´¥'æ¨ÓZ¯ÏˆI…²"éÁb;q›ÕnrU’Á`jäu“ñŸPåJÕ׉ÔC²G-› á­€#ia¯`ŽWÂ;îlXDzNï‰öp’BJm»G±bú^„1«»<_=ìê¡&¬÷±âÇ×çJšµÒ¶¤pê©ÝZz8«ð£�¢¶%ÐE©–¶óhÅÉòbE«•òŠ™«Š±~±epš�ºè%UË©SÂ;÷É ‰R¦S]o¥¹Cf‡ëŒÝiÓÂŒqÚñg9gË’ÍD[™l0%s$kt)<é-¬$êÔÒócÔ6S„Ì�ÞÖ$¥)iw"Y/щ™J:[›ó u&ÞlmÈ(Ïg|Ç qÚØ× 0:1�ìÎJ9Âæ-¬Xh|â�Ùœ¥b"…ÕÙÒ|"й€ì蘶³œ£švSW8Lj§µƒ¦¶±â�Mœ\^vh»šÚÇ?Ð)ÒS9JžÏQÇs‘)è€LêlÿѪ¥%kk:‘@RG pÌïVJÖÖr8R‹³Oc‡,pŒ”šz·KIÉRZØ»”v²%t “¼›UåštÜãÊtìÒ9ŠŽŽš¶4p'1Â��hà8*A@à¢�h pp£G� …8éÁECE‡LæÒM»- R¸¨b€àô9 C‘Ò#ÑÞ„ÔeŽDtu¥ ÒVе�Db¨œžÆšQm¼_YÅP†Ö ”[‹Ñ©’¤ªJu�2y¬ÜÖìîHMéRÏÅ»$vT!µõ�S‘È’˜êÓY¹©âÙÖ”Ô¢±Å,HÕ)f,äî†&“ TÑatq­;µî–�—#¦*a9œPÈè™Þ3ͤšjùú=›áˆÉ�cš¢¥¿ÎàØê8ÑÚ�mûm$¥É �š!ºµ/%,í�……oÒ£ÎÉ&AÂMS„q“9Òœs¤– »¢,c)»E]�)ÍÑ�䞆¬Õµ”ï“.E”­R\·):µŠÅêÔ£+IYƒsa‘2ŒÓ‚WÅ.WÜ[�QpjÔYѶ9®ãÕjo]ˆ‘Å¥µ’Õ:kUùÎ¦ÙÆ’’êB)I¼ƒŠ®ó®ø;²„Rk �^£‹Ð�ÌRd�ÚžÑ'UE]c}̇Œs\m‡!ÚNQ†>3SŽtAN2y©ÚKQÆŠÍnIÝ3£„g¾¶;A0i&%J’Ž‹½»W(ØUºÅç-xcÔ:SQ^˜°ZÐÝÆo¬å3:¥*D©(ÂM7až‰ŠvjëiÒ¬båyFú1"Ô„SY®×ÔÎ9¢P¤ë&FQš¼]Å"ªj¥ŠÖtU¤´â¾EÃxì9ƽ7,ÛÙìg]:1:rM ° @h `8Da²Â-òѲœcƒºÃ”lT^2}Çf'¢=-Ø�$¤„uaÊ7v‡/PfA<^sÙ“Ü£„œiùR¼º‘ÊI$°ÂU•ð]/0×Rž™^ocÁu Ý(ÛyTåà®¶5¤±v§w\ŽL’KéºÅð›K‹eÖ6yM:qÞG]ê]¬ŒêÑ‹ÍsÏqÒ »dû�*™ÒvŽe´+Ý‘¶'iŠ-Jµçø1Û/K‡òL��F1ßÉÔZ°Üéô-,*ÂS“–™/g›¿iÃ2— rueÉ ‹e�Â¥ÓR弤¬¶EYªE{ZVäX±]GkE(­ˆ�8­',…c7h¥h,ÞW‹9¹§‹wlAÅl8JHç)]ÝjŸ²�šKXìØì8J�£´ç�¾¹ÑÆ;y»ë�)ÎŽÑÖ¬EÍŽÁSä´ Œ’Á‹�¢F)âÅÍŽÀ:6rMY «Y‹8«] «]ãp;D…sŽÓ”å}Ž®1ØrœRjÚÀ‡gÇ^�ç¡™ªàã€vƒ“–ÿ�8~|vŒqßæê›‡N¹ •H¤õàrÝyÒ„Zxj8îKhPIHÿÒ¥�SÑ�¨AP>%Îs�šg2X§5V/�]ÒH•I„|kæ:í<í§]Ò@p::‘¶³�C… EA@࢈*‚¡D (‚€ >0œÔ¥Ú‚¼šÔ´\am’{ÜrœÇZÛ†þê3–Ž[�…L„qZ©ÊeX£ëz9z?2Øî–½ú`v±Âˆ�pr†@pz†!É�Æ=¨FPœá5›%k§¤å“úÚΦvr¶fmºnMʪdÔòš¯Ó7G+>f®’iQ2¨�6²u …z1ÅW¥·ÌÄ�xfµ[;2®ñ×'ñ},ìˆt+(,ÙhÓsº¯Ko™‚tP¹±õ¼[çDdÇÕ­¬Øô³’`Ý'aRGDÇ&sLéMÓ¿¦gZÞËkùÀë4“j×W\§Hææ¬Ûî¹Ølä:Uô>e;çø½î�zN1qqQŠ{®v¾‡j!9¡ÓsÏ{§ ]Î�úTyØÉZ.q¬›©…�ôsŠß¤Ç��¾rðúw96Ý“V½®Hp�eKNsXrã¬�s¤jÎ6Ívͽºt�Nã94ÍVtNTjjn=BN£©<çƒä Ö©i<e¯™ R�LËß õ…Ì)…Ã�·ã.8;S~™reÊäìîµ#”6±‹|Ä¡d"…²SÐŽpÍÝ&ÓÆÊêÃjVͧ fð“Ó¨�²Œœ–½'[8¡m2k{là«ßÙXÙ×v²V¾Ð¶AjΔõó�/³:®©ê:nþ¥œNƒ®2KjJÏö�W…µr­DIדÁ+-�ôò›od›ó�¶AhäK”•ìúÖ“•JYöp´¬ô_5ލ£)µ{;"-U”Eç- E±ÎB°äu’ÍxÝ ~UÒsŽY;ZQÎÚ.ïB\%*}G&‰Z»« Kzmí‡Ï´zRZ\Ò·yÏsÉå<øÖWåôé¹'Á’—3G¿Ò�ê­UÅ镯Ã)ž9ûžTŸÂŒ•j^trŽO˜ðצízèìÙÉBïýMiócëç–Á+¤ÝŽnZZ]1þIœç* ZURænþhœq3ªo6wYZ’½¤“äKµˆëÂO6ÎïEÝüÈŒ«äpVßTè·K¸Xet¥5Nœs�³�°êG-°ÑÛKɿޕ+Õ¤­Jíù„¶WSM’åÇÌ®rÊkeä£FÉ5v웿;8©å¦ÉË¥¾Ì7r’J'G¯%J *Õ«ÛÔ§o2¹U²:uŒç©»%ç»ãã;%Êû•Î2­B.êò~¥[Îñ8Ù8aÅx”"L²šÏ€•5·_[8ÉNnóno•áç8ú-û,-Ë¥œç”IéO¤‹dÔ T’;,ÈÊ[å}�Xô±ô¥Úжu•ñ›Œ¯·I/%žt¥…°ï8™(¡’lmfó¤›ÁéðGå{¤â–½'ÍÇ 'd¡TYΧW>Fs”œ°Ð’´�Å;akƒŸ#²\$9œ¥&ÝÇgò;!Ã=�óŸ!Ï9Þà DŸÈÄsä°�CCç楚;?‘�Ùø,HðW0ÉM¼4fÒµ®eAÐçSW8®|Œç)90ެA›¦Ô#ª¶Ù0~3 qÇ9çgkº­‡dvC˜Û¡²«ƒ²ÔpÝ&$¡gÿÓ¥ê)¡s")3ÐÌæ)Ó2"îq œ¶G1QÓ2"æD&rcCó".dN˜ÁPüÈ‹›91‚�͈fÄáÉ�vj5�Lh£³P¹¨Lh£³P¹¨Lh¨[!l€à‚‹d-��ƒãRpRPm)¬Ù%­i°–Ad�P²È�¡d*Qº½í|m¦ÇN�¤Ú¾„ô-,ÕSM\Û¸Þ÷Zp!ÙjDTS¹ C“$9$pè©’)Þ½W:­Éémë#¤‰97 \ÇQªl’¡*êt âì¬ÒÔu¤áœ³ï¥ZÖÛÊ:»†tóo¦W½­Ñbr ¦nr¤�“ÓŒ£�%|l‰ ⮣ŽLý/¥�Ð*‚*Ùʵ8¨çEZÏŠdŠïÒŸ:"¦qÖJ‡¦93�Éqy?¡Þñ‘¾1½ó_&€Tƒ æç)$›¾j²äCó$©ª·V½´âp¹ÝYЊ¼SsÓìß utKXÎ*2RŽt¥¢Mè'é1çg ¬É8¦¥mkAÒOÒ!ÎûΜj¬S®Os“U’Xca“´g%RnÁ“Ê’“Ý­kau|n2rŽ|³87væ ‡%‚uúáéµ LæåŽ#. âdu¸\çqn$u†úimdí"¾œ­R/•®N¸ëGIpbE„Ví%ª8¢L¸é"Â^Ÿ>nî´r™"ãd”“L.#v@på“¥g-w±Úç zùη8ª%letœÖ‚’J Ú^,*Ûsw×° ã™_B9t3s­où‘¥YÓ”s^—fž(‘ZÛ£½ô"-W Æ÷ÁßQØ®„îq|%Ô'¥½m {V†1³“;!®�-ÒêKnmÑÑ×°á†í}v°æp“NŠG:i«=¹Ê�ŶñêõÇ3Œ,³­­Üã‘Õ9:Nî1ÛçG:‘¤âóšÃo²Â1“Æ-=€u,1ÐÜTo§]½{�„ÓšIigÙE%¨}/s‰�j°ËjJžk…®õÚìäç&±m‹álÑ—Àã­’…`PŒ�8­Ù-Owg ¿N�7iÆN£ñÒ9�g�á¬ùz�ª'ÌEƒôÉ’r~æv*™Æº¼¦ŽÖöçzï>“„÷¤ã¬’Ø£™Î¦‹�c'ÁH²�Z0�æ·Ë”pÙ½òp•àg$–{[‡4÷ìÕÕ˜¢0�ZXá°ÐùÇ'XÊŠñæ«Er„ø,#Á@�åQhgS�]ªÎCX¢,ˆ+tè’ÐÎGYh|Ç $�ÿÔ©Ž„8椒= ò: sÝ»¢å9 “:Ït�(»¤yBG$΂œ÷D.z’: sÏB磇$tçž…Ï@(Ìô.z’(Ìô.z’s�g fr9Áà79 œ€àáFg!s��ðœ…Î@pp£n‚ç@p¨mŸ…C..p‘Ñ1𛃺8©!ÊH4KYO©ó„²‡%š•®FRB©™Tw¥UÓÁbž£²Ê½Oœ‡qÉ�™Ç gz•�L-e°eÆ\[„ÎJGK‹q—àîv…IfÆ"¦�í|H÷;Ƨ¥F“ÎSº�°ç:ˆÄ…¬ïVN÷ÇM­æ;S�9ÒŠ©=Í+ÙÚ÷ä#MÍͺœ-wÀé'éç}çS¥‘j„‰™<(BM®èÚÑšöôŽ„hªòš©�'{Ã5àA£YÑ“’IÝ[¥•%]Î 9I7fì±$¢TPAÀés¹„v«N„ª9J®kz³^xÆ›ªâçh+ÚV«'4”µ¥ŠÐrO|qºj% 4Wp—¹dþÿ�{ˆ»�½Ä‹qn W}ô„�·¿¾c¼c4°©uË<jEr¢uÉBB:ÔRtà”­ƒ»Hˆ£M;ª˜®BdZœ/i-#TÉ+9¶³lßìJídaiM7 ÝW¿‰üIMIYÔÑXOA×õ>܃¯ê}¸�7‰`o®�ls`ï–èºúµÔ' ëúŸnÐuýO·�㳆ú µ%éêÙÊš’àJêûy%v—Æ[YÞ�­Ñ¤–œnu'3Ž$•s)ÏÝ]žZ¹“Xï¥�1&¤óæå·A³W�+±È®„埘¬ï§P�tÛæ:7‚éØ8ëÓˆëÏÝCn·kr\{g ;ƒ%ŸlF-;׉ÔãM§�mNǪ˜ëÌd³µ�7h·±Ô2öÐÄ£Vo(Œp¶qÎ5¤’¾"PwÊãåúägJ'*!×Â/Ó!äw�ÕYÅY< ^ñ°ò;È-„U²V5€GG^§'QɶÝÞ‘„I¤tݦµß k«7¬`Ù M§u¤•‘ÎRœ“â÷‘ 9^Ox*ÎF°,å”Éî³Z®rŽw²�Ê<tü ‡¤.�TB„{§!ÎYÞÌvS‚PÈçÛ úg å¡s�Î2½ñÒòCªiG3„•"¹ÈeõŠ >B9Éà €v@›Zt�Œh�²“zDRk@t认†¶Þ,@©ÄÓ¢1Àè�C9�†s:IÿÕ¦Íl3XøèRg ˜ÌÉdŽ‚„Î[3–d…Ì‘ÔS“ fsÌ�ª(LäÆfH\ÙLfl…Í�ñN˜ÌÙ šÇ€˜ÜÖ.k(Ææ±sXà“šÅ³(˜Û1lÅbY‹f( rbY…˜ä�Y‹f( pK1lÀS§°¶`8�K1É0B 8 1É0¸á:pQ@P8(¢ tà§XF[ÙÛ{œ–‘&&gQÔF'!*8gÔÎRÎÃ6îýbÉúD9ßxÊþ:\ýÃ¥â!ÎûÂù�þ—¡IÖ“Šy¶WÚt£ Ƽ¡ %(Ý^×Ð.Aã%ä÷�£òù?�v’J¬R178•äp­œªÉMçK[µµSßòŸ>uØp\".²pÔ±Ü[��|%›8½�îW-+œ±' ]’à\ƒVYÕ$ÖÒq\'ÎÂ#�VÄÄLE‚b&#„�W´y»Ù&“½8ò+å¢<ÝìïGÅô²J²1UŽ>ä|¡ãjw$«ð—0:ŽCY!»Å>q·Ù"4/ò}V·˜êqö¯IÙœDÝÌA#Ѻr¾·s¼´>c�=/˜gULèÎux -jÃÙΧãY’šlb›§W=iŒ¯ç$-$Zœ9s‘-T¶ZN�¶œgv¶5§•ƒ©ñåÔŽùË´z{NÌœ“¤¦ÙÂÜ)ЙØu><º�×àøqåÔ‰ìk Tw.E|ƒì>wÔ†¼‚wÔ‰Ìk9$vÞ+ä'�CŽú�èžK Kµëæ$²6Wâ%ÎŽJD”N&“etäç''¥»ŽƒÞÛc9�§¡�/uQà<çSB: ±ÉÝ <+8*�Žcêp†4 ‚ˆDQ�è‚ F(Œè#FDÇ gNˆ#C¤†½ `÷¡Œ¨ÿÙ endstream endobj 249 0 obj [/ICCBased 246 0 R] endobj 250 0 obj <</Filter/FlateDecode/Length 343>>stream H‰\’ÍŠƒ0€ïyŠ9¶‡¢µmÒ‚ŶàaXwÀƱ+¬1D{ðíwÆ)]XAç ™?2‰òâT¸v„è=ô¶ÄšÖÕ‡þ,Âo­SëêÖŽ�Õüµ]åUDÅå4ŒØ®éUšBôA›Ã&XëþŠK½…Cën°øÊË%DåÝûìÐ�C–A� 5z©ükÕ!DsÙª¨i¿§Õüe|N!™×k‘±}�ƒ¯,†ÊÝP¥1=¤z2…®þ·Ÿì¤ìÚØï*¨49QrS > Ÿ™/ÂÔ$ݬg¦@l„ óQøH¬%GsŽÞo˜wÂ;f-¬™¥�æ>z/¼g>˜sáœYÜ4»iqÓìfâ™)' ³8v0[á-³øö1âcØÇˆ�a#>†}èäø8çÆKó‡çÔì=Ø|IæIñŒZ‡Ï{ä{Tůú`�—•¨\ endstream endobj 251 0 obj <</Ascent 882/CapHeight 674/CharSet(/space/comma/hyphen/semicolon/A/B/I/M/R/S/U/a/c/d/e/h/i/k/l/m/n/o/r/s/t/v/y)/Descent -250/Flags 96/FontBBox[-103 -250 1165 882]/FontFamily(Myriad Pro Light)/FontFile3 253 0 R/FontName/KGORFR+MyriadPro-SemiboldIt/FontStretch/Normal/FontWeight 700/ItalicAngle -11/StemV 116/Type/FontDescriptor/XHeight 487>> endobj 252 0 obj <</Filter/FlateDecode/Length 356>>stream H‰\’Ïnƒ0 ÆïyŠÛC¥�´BÚh+qØ�íhb:¤¢@¼ýl\uÒ"�Q>'_ìDeu¬\7Éè= ¦†I¶�³Æá È \;'¶‰´�™î³åoúÆ‹“ëyœ ¯\;ˆ<—Ñ.ŽS˜åêÉX‹è-X�»ÊÕWY¯eTß¼ÿ�Ü$cYÒB‹½4þµéAFKÚ¦²¸ÞMósþŸ³™,ó-›1ƒ…Ñ7Bã® òG!ó3ŽB€³ÿÖÍi—Ö|7Aä ‰ãrÉ\™�È»ç…1ˆ<Ý.Œ9aNˆÌbÎM)7cMFšlǼ#Θ3dÅ{*ÚS±F‘F¥Ì)1ëÕ¢ß3ï‰ù\Eç*ö©È§â»(º‹b?Šü¨ó‰øÌŒ…Ê5ûÔäS³M4{ÐäA+fEÌçb "ß«IåÆW!½4·°�ËÓYúG�ë<^—¼Ä,úį��¤¬Ä endstream endobj 253 0 obj <</Filter/FlateDecode/Length 2365/Subtype/Type1C>>stream H‰|T{TéŸI˜!l!*ã f0“u­îú*V¥ˆ»ŠnApy.,*˜H”— $ XAˆE±,O‘‡ "Êè ¨XP|¬V{”5"uW¤Ûz‡~xì÷ôœþÓ3çÌùîܹ¿û»¿{¿‹c Çq‡uîßø¹ùÍóNVEÉÃ}Tq ü•1QЏèp�³ÿsŽÁ9‰…ÎZÀ9XÓ³�ÑÁ"çß$1Æl eÔNyæ`Un‹ p<-ïë¸xgkd‚ìó-_È~ïèè([§PÊü“Õ ÊµÌ#vKœ*>N%OP†/”­ŠŽ–ù™WËü”j¥JÃüHD¥–Ée*åÖ(>N¥ —%¨äáʹj»,.âÿaþÎÍ? 9^)s–…+#0 çÌÇ0l&ŽÍŰ…¶Çœ0l5†ýQ€yà˜—æ/À‚0,ÃxM0oÌ‹Å2°K8‰ïÄ ¶‚$A¿p®ð°ð±…«E…Å?‰yD,±ŸœN¦��–Ö–[-;,ß‹¾9¿ÿ"÷ÓEœϺ(ÜoÁÆ|Æ $Ñ5­€|^‘H†:h0ã-ÇÉЉ3¬@¼Mr—ió ™-1:&ž£ÁƒA/l@ÝÖs°æad§·W;‡ÎT®‰ ÏðZ(ž‡›tŠF²èÁGqþ°ÿæ Oò‘í=Ý‘ô#AÉùÓNµµÄÖ)6D…oRÔD7³b˜Y®��´¿Æã¹^!7 è2@€ é4æD Ù$2½ç³L&‡ €h4ÑOà˲¦â %ÍÓsHã–ܠ܈R´Ü^ü&cŸƒßK[n*LZ ÖÔÛªôÞW3ú˜Ñ'Eg®°í'OwÜ—< ½ìU*5ZR¯”ݺö\riGSø1éqEpÁf½ÿÞ=¡ìˆ m<R‘SÍô´ªýݼKØ@2y)}…¤ÞÞëŽÿÚqyä’DMvN2+F!åš1'-~ B˜;æD£©fª"¦òÔÅð6¡Y®¶ùcTü˜¯Ý sQŽ$úºCP�±>Ûר׉2ɬžô;Ý[¡Ï- ©xäjÂÈÇp·¨¯|´ø_lîòKòWЍÆt‹xIÂ2¸×x¿i°áoÓ�äNç]óun"*> Ý%Ä£¼¤u?ÂŽ!œ[6ÂJ;žRÔ]dw]ôÒì—ƒërSD`Mêk2¥ ìíÑ^Ø\,2Z>¯º{{DreGsDµ´NîuÄ“ññÚ«ß̾YFç–æÔ2·Úã¼V{û-b=Hñ)ý·g$Jkk1à0‰z”×H×&ÜNxš%‚¹ èæiHç²VÖ«AYs^r®¥õ�ôJö¹¤£»EÔ¹Ó¯ êQQü†W9 ‹åˆv¹þíc9Ûy<&LâéééXR.ƒ·îgn@‹÷�è£Æ«Ç§Ñ™Q±ôé³µ`›-—a„�ar²"]Ç¥’îð pfÜ­wjŒ5yU¼o!~®öÖpóM«4×ÚÖ€ l|CUSë¹�»}×ò‡ ï_„ƒöTõ‘¿Ãß2H‹Dh rù¢Ë}ðfOÝ‹6ÖHR CxV¬è(ÔÐT5šœàáÈ'µ\a?‡±TAYÑ>C+Vë‡aX3¬Åë@,„ïh�:jw(ã)oþaôÞ/`Q_‘žVÂÖšˆCIÊÛ´Ñè3þ Z=ü Ä7Û �³b“nع› Rk{œ‡÷¥Ú¹ ±z3Ò‡41yj¹£)hrE‚î5ƒ¹Qwë,›CR©ú¥Ä;2§ãPOA×(Wo�äãQ4Õ>[ëíÄ$œ¿øŽÔT¦é Yq¥~>„Ƀ<W” r �trdØ®�fSdQ}«/Ë<‘],ŸL˜ÖS$O×_™‡–# -AsÐ'=ÎÀ\ï-¬l“†À�í»"YgK¯¶÷Þg+“¢Yñër ÷%¯9¤jqn X ÁÁî,¤ÿ(íí»Êœ-Ž�P4†$6U£Ú@äU垬”˜š×ºn VH÷‘]ÐN ‰˜÷!üš’ó�)ZØã0 ì…0ÃnˆK1ûާ°’ë¤Ïœ¨nÍfU•Êí±Šˆcª©¸e" 2µx—mfq¾êêA*h~Gˆ€MšE¢ß¢Å»RS’R“§ï#û9·ÿÍ<Â@ž�ÆBÌC÷ÑÉ '*ÐÖimß}ÀÂtجJ‡ «ÁŠê‰] ¤oJnþÐÉ\(Ø‘lH2hù²�`A¶Â.^‘ë·;™–â8y’!1SË~‡* xEN¹U¹§Ê%ƒA­R÷¬õÛÃÖŠ.gFµ­d¼ÖG{†²ûHêMÁ3b6¹Wž¬óõF/ì•}‚ ðDf6 <ê ¯W $@–÷õ\fΫHâ;�ÌS©!ÀŠÏ×HäË=yT2زÆÝ{›g(ßê§‚Aⳉ »}½Ì^èLðÔ„Ÿ�kH7·5UGókÉf‚Ë;÷a4 ¹ K~¬—!Ñ_�`û½‰ö‰¼pûe'L~u·Âû»¹¾Èz +–ñ<§©ÓÚ–Á¿¨F^ÕF&¨;¿”v ô3ùùû³°@i{²Ó�À žÛXI5æ5OëE³ÉŒÍé®róCöb?ý â=`ÕÊ/¾œ*º*©#¥‹ßGVY¦€Iº76ÖHGK«%õµg›êwëK¤µÄŸåG‚d¹ÌcA@“üj,Û¦*ÒÆH¶ÅÅo ÛPR¨’Š‘�þçµîS“í ø s¸‡t²#áIî\Dô’rïóô­†ÿ¨ @*x]üíå«ú&Í‘›öŒµ³¾¶«V:§~βùýK',”ßø=’õ;#Ûܧ¬¿Ù}då[Ýý�K ”.…vÿÈ.Øý£Zô(s²}_ JÓÀ”Éû»hzA`mF}G[Çê¶ ­Gs¾·IðÍêcÌþ±’yPÛ›?¡½MÝ­í-’¥É9™Y%¹%™õ¥ÍËÔ%VN<½øðÁ3§>:ö�ë»Û÷߿ؔ·”„ÕgÕç“xûšÖõMR¿×Ið5Lûi6ýwô´ï:ÓöLû“?‰í‡ò¤ß“ÿäOÛ9yÑDvˆtÜ´ïúiŽ*@éI@é]“–Oà”[�àÚ4ó?çS®ïüÜ=<|ß›D~D‰�!í¥n endstream endobj 254 0 obj <</Filter/FlateDecode/Length 353>>stream H‰\’ÍŠƒ0ÇïyŠÛCÑÚš´ Bk[𰬻`“±+¬1D{ðíwÆ)]Ø€Î/dføÏGT”§Òµ£ŒÞCo*eÓ:`èïÁ€¼Â­ub�HÛšñq›ÿ¦«½ˆ0¸š†ºÒ5½È2}àã0†I.¶¿ÂRDoÁBhÝM.¾Šj)£êîýtàFË<—LôRû׺Ía«Òâ{;N+Œùóøœ<Èd¾¯YŒé- ¾6jw‘Åxr™]ðäœý÷žh»6æ»"KÈ9ŽÑ Ìò6™ rÊœ™�È)û¤ä“n™·ÄŠY˜Èj=3döWä¯8¿¢üJ3kâóŽxϼ'f Š4(Ö¬H³:1ŸˆÏÌgâ 36$Ó¬Y“f½aÞ³Mz4ëѤGs-šjѬA“Íu¡¡&?ºIíÆ­�ÏYš{8ÆyuæùÑäZÏíò½—EŸø`�ê¬Ø endstream endobj 255 0 obj <</Ascent 897/CapHeight 674/CharSet(/space/hyphen/colon/E/F/N/P/S/T/U/a/c/e/f/i/l/m/n/o/p/r/s/t/y)/Descent -250/Flags 32/FontBBox[-92 -250 1256 897]/FontFamily(Myriad Pro)/FontFile3 257 0 R/FontName/KGORFR+MyriadPro-Bold/FontStretch/Normal/FontWeight 700/ItalicAngle 0/StemV 152/Type/FontDescriptor/XHeight 489>> endobj 256 0 obj <</Filter/FlateDecode/Length 341>>stream H‰\’ÍŠƒ0ÇïyŠ9¶‡bk5R¡Ø<ìëîØ8v…5†h¾ýÎdJ6 ó óõg&QY�*ÛϽûÑÔ8C×ÛÖã4Þ½A¸â­·jCÛ›ùq 34NE”\/ÓŒCe»Qå9Däœf¿ÀêØŽW\«èÍ·è{{ƒÕWY¯!ªïÎýà€v†-´ØQ¡—ƽ6BÒ6UKþ~^6”óñ¹8„8Üw"ÆŒ-N®1è{C•oé�_è mûÏ'’víÌwãUsðvK†ø$|"Þ“Qy’&C¬…5óYøLœJ�”ë¤{á=s"œ0K�”ëè]`2į9^KŒ1ÒKs/}>0—Â%³hÖ¬Y‹ÍzôE˜†�g¢-cmY,3Kߌûf¢3c�™ô"Ã|LŠGI‡çžÌÝ{ZQxa7¼•Þâóå¸Ñeñ§~�×n¥� endstream endobj 257 0 obj <</Filter/FlateDecode/Length 2018/Subtype/Type1C>>stream H‰|TkPWîffz B+4MpZ»{} Èð q³‹QA„�F@�ò¨\Áð†ÅÈðPEä©"*Añ-É 1îÙ¨›Ýf)cY®f=MîX»Mj÷×Ö­ºuß=çÔwÎ=$!·!H’t YáºSŸž¨ ×ë<Wé25Óž…GJÎriŽ=ë�jçÈ'fs âÔC0Ï„/˜cû©aC’‡»WërðóÔ´<qq²»èëãã#htIZ1rgnž6+W\Ÿ�¬Óçèô‰yZ�—�™)FLÃsÅm®Vo˜6nòŠôÃ1 ;O Ôæz‰9ÚlMzvª×»ÊÄô\1QÔkSÓqD½V#æé5Ú¬D}†¨KùÙ¼ƒ"£væhÅ¢F›B$>MA¸‘„7A,%ˆå6Ä*‚$ˆ ’&ˆP9iCÄÄlÌJl$’ˆÓÄcRFF�Ý6³l|l2lþ&ó’•Ⱦ‘¿'åírPø+ú)j+ÕF½i¯–ž “ø^0,«–K•SáÖJ jÑM­„Ï0I!]aaZ±îWZ©ø·2¬DX§¤vZBÓM#5¤½ » YÖc¬4¿PÒh{„ ?<€�j£Óeb¢™4á{õTÿˆpÍ”Ö÷)·9E»iói͈`FÞÙ™Æÿz&mÚÉÓ·«Á–Ã,üÜ‘µLJ•<YdÆúAp´.{ã'€#êÂ3E_i5@{ýw56TÀ,T�� ø…7ECf«Aª0B´‘ÃqºA”A’ $(Á¦êiÅ~/ÕóûÁή‚¨Ñ–Oùa>¢©…µ>|ù**ó�æûä{H„jWôÆ�¢_ã¤%`°Åñ< <dc.X¨ *››ŽpO&Ž]Îõµ^W�é®'ôò}ñë{r^ëËKãðÙZKkM71�º6&飼sín�+G阕ntºÞ°�¼™‰³=¬áÌáÿO£¾D3¾–õ¦´ ¨Nöt�ÝÊßÝÎ3ƒ'�V0-ÉQÍ+9ä»d9Rºßy²ðHד›¨JHÉ^ÒÚšÌÓ÷1àLB æ b0aXÝ�ÎÖfä Á˜,MÐÒíiªÔ`˜±)?Öj¯DÛŸ«ñXþô4¼„Áú¾Ù'Dþneü-°ã¥÷•ôÕ¢×`×Ó»?9u˜‹˜) γ Œþ}è»NŸŸÎw,Q´ô\94Ì}Û”²C(W¢�D…!F`†üo­~~s¸µ¿‡¯¥˜‚± ˜K•Ÿ¨¼ b†Ð¢Ûl‰©¤ª”Ï,ÎЧpé;Zúo~ÙòP óŠa´ƒž¼^ðaîJxØâ<]y*vñ‰ð�iäÆCî쉲ÒÃÓ× s·!#a2‡‚Ý‘š‡<_,ß›—ëOôÕbPL¾zþ‚ì……°~#“Š!š­±ÔkW�CÌD¾ÈßÍE³�çSøhl´¾u˜7¾T&%–mæC»¾ªL¯Ø³{ÛoÝáî Mh4Sî�r|ì‹�Nß�š™€].’Ã3�»+™ÉãÊK­ýÃGVîi䙉:°S0“û ;ömçâ7ïNÕÛ’w‡«òƒ‘üŽÕ·8®ÐøÔN7à´‡›„t©·¤Pɼx ]`‡»OžLY½±\lÆöm‰Ýé—p[Z S[Œä(nê(îûÔ¤¦hÉåmu3‹ŒN£°ø×ã<‡˜Åóú”�æ¦} |Û�c]ýÜÐÑÄ�:�AýʆšæZ ßiik;Í K Ðal?§·À1ÏÔ¬’‚>·Ð`Ìßa[E]6Äö†p+¶f„JŠ*W –ªI¨‰Þ¨¢Aþ?E¨ñßV3ƒÓ%R˜©SÊ&sÓÞz¾Ãr¼ó<wíè¶ jàóJXðñø¢ßÆÆeyq°ìkrý5âË" á�¸‘Kñ¨/•ÁÙ"\€y A°xÑKäŽ|ç»ánú‚�'Ìj�dCÒ¾úëŸ;îÿénGÀêe)áa�÷È„áÏÞ3~).¼˜G£(–Åòž*ãè…Ü[N¦ø‚æøxLŠ�‘ºèT¼;˜G¿µµfSˆ Ô[XæÙs}Íçü`ý™žîëSáþ+4QëÒºÏ Uõ¦úí‰÷ËÏ0¯ÈØñ6!Ó8ÍTSÌh£ÙRSÏ_ª?Óy�;ÔPUÕ€w(ÌW2£5EeæBnKxÖj½°‡b:ËP ª6Ñ·ZE'¿†á‘ƒàvÜd½ÇYcß�‚?r Þÿ‡`º§½èÕcv$¿ñ˜ª­µ¹ïÜÀ®¢£|û+EsVLS‡üƒ¼SDÔ?Óm¯ïlÞ­Wéó ¶ÆÒrHÇÓb1^¾AN>wÙcé/¬÷ô”¢8ePS\G6¯?~îCÜù¾ºý-‚ ”ŠÊÂb“�‹/8qK€5˜29"a¶’ÂãLÖIY�TÈÂ:k”bßgæ²rUyeiE)_˜»CŸ÷YÞîÜ’ü==ÈÙµïõC#® ]œø6ߺ¢ñ)+Ë.M-Ë™]I•·÷•v¬‚rWºÈ2å×€b,°Ä2\oÍ­£¤à}(¤Îª³ ÖÙ¯|玷€·eÈbÍÛo+ס ïÜ�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 <</Size 258/Root 210 0 R/Info 4 0 R/ID[<38F81177F239849D69C477E8E6C3BB41><1E176FDB5E6C4E6F93264F099BE4DA4D>]/Prev 453291>> startxref 597803 %%EOF �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/fusermount3.1�����������������������������������������������������������������������0000644�0001750�0001750�00000002513�15250106036�014636� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH FUSERMOUNT3 1 2011\-10\-23 2.8.6 "Filesystem in Userspace (FUSE)" .SH NAME \fBfusermount3\fR \- mount and unmount FUSE filesystems .SH SYNOPSIS \fBfusermount3\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 provides a secure method for non privileged users to create and mount their own filesystem implementations. .PP \fBfusermount3\fR is a program to mount and unmount FUSE filesystems. It should be called directly only for unmounting FUSE file systems. To allow mounting and unmounting by unprivileged users, \fBfusermount3\fR needs to be installed set-uid root. .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.fuse3\fR(8), \fIfuse\fR(4), .SH HOMEPAGE More information about fusermount3 and the FUSE project can be found at <\fIhttps://github.com/libfuse/\fR>. .SH AUTHORS .LP FUSE is currently maintained by Nikolaus Rath <Nikolaus@rath.org> .LP The original author of FUSE is Miklos Szeredi <\fImiklos@szeredi.hu\fR>. .LP This manual page was originally written by Daniel Baumann <\fIdaniel.baumann@progress\-technologies.net\fR>. �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/kernel.txt��������������������������������������������������������������������������0000644�0001750�0001750�00000034724�15250106036�014314� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������Definitions ~~~~~~~~~~~ Userspace filesystem: A filesystem in which data and metadata are provided by an ordinary userspace process. The filesystem can be accessed normally through the kernel interface. Filesystem daemon: The process(es) providing the data and metadata of the filesystem. Non-privileged mount (or user mount): A userspace filesystem mounted by a non-privileged (non-root) user. The filesystem daemon is running with the privileges of the mounting user. NOTE: this is not the same as mounts allowed with the "user" option in /etc/fstab, which is not discussed here. Filesystem connection: A connection between the filesystem daemon and the kernel. The connection exists until either the daemon dies, or the filesystem is umounted. Note that detaching (or lazy umounting) the filesystem does _not_ break the connection, in this case it will exist until the last reference to the filesystem is released. Mount owner: The user who does the mounting. User: The user who is performing filesystem operations. What is FUSE? ~~~~~~~~~~~~~ FUSE is a userspace filesystem framework. It consists of a kernel module (fuse.ko), a userspace library (libfuse.*) and a mount utility (fusermount3). One of the most important features of FUSE is allowing secure, non-privileged mounts. This opens up new possibilities for the use of filesystems. A good example is sshfs: a secure network filesystem using the sftp protocol. The userspace library and utilities are available from the FUSE homepage: https://github.com/libfuse/libfuse/ Filesystem type ~~~~~~~~~~~~~~~ The filesystem type given to mount(2) can be one of the following: 'fuse' This is the usual way to mount a FUSE filesystem. The first argument of the mount system call may contain an arbitrary string, which is not interpreted by the kernel. 'fuseblk' The filesystem is block device based. The first argument of the mount system call is interpreted as the name of the device. Mount options ~~~~~~~~~~~~~ See mount.fuse3(8). Control filesystem ~~~~~~~~~~~~~~~~~~ There's a control filesystem for FUSE, which can be mounted by: mount -t fusectl none /sys/fs/fuse/connections Mounting it under the '/sys/fs/fuse/connections' directory makes it backwards compatible with versions before 2.6.0. Under the fuse control filesystem each connection has a directory named by a unique number. For each connection the following files exist within this directory: 'waiting' The number of requests which are waiting to be transferred to userspace or being processed by the filesystem daemon. If there is no filesystem activity and 'waiting' is non-zero, then the filesystem is hung or deadlocked. 'abort' Writing anything into this file will abort the filesystem connection. This means that all waiting requests will be aborted an error returned for all aborted and new requests. Only the owner of the mount may read or write these files. Interrupting filesystem operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If a process issuing a FUSE filesystem request is interrupted, the following will happen: 1) If the request is not yet sent to userspace AND the signal is fatal (SIGKILL or unhandled fatal signal), then the request is dequeued and returns immediately. 2) If the request is not yet sent to userspace AND the signal is not fatal, then an 'interrupted' flag is set for the request. When the request has been successfully transferred to userspace and this flag is set, an INTERRUPT request is queued. 3) If the request is already sent to userspace, then an INTERRUPT request is queued. INTERRUPT requests take precedence over other requests, so the userspace filesystem will receive queued INTERRUPTs before any others. The userspace filesystem may ignore the INTERRUPT requests entirely, or may honor them by sending a reply to the _original_ request, with the error set to EINTR. It is also possible that there's a race between processing the original request and it's INTERRUPT request. There are two possibilities: 1) The INTERRUPT request is processed before the original request is processed 2) The INTERRUPT request is processed after the original request has been answered If the filesystem cannot find the original request, it should wait for some timeout and/or a number of new requests to arrive, after which it should reply to the INTERRUPT request with an EAGAIN error. In case 1) the INTERRUPT request will be requeued. In case 2) the INTERRUPT reply will be ignored. Aborting a filesystem connection ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is possible to get into certain situations where the filesystem is not responding. Reasons for this may be: a) Broken userspace filesystem implementation b) Network connection down c) Accidental deadlock d) Malicious deadlock (For more on c) and d) see later sections) In either of these cases it may be useful to abort the connection to the filesystem. There are several ways to do this: - Kill the filesystem daemon. Works in case of a) and b) - Kill the filesystem daemon and all users of the filesystem. Works in all cases except some malicious deadlocks - Use forced umount (umount -f). Works in all cases but only if filesystem is still attached (it hasn't been lazy unmounted) - Abort filesystem through the FUSE control filesystem. Most powerful method, always works. How do non-privileged mounts work? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since the mount() system call is a privileged operation, a helper program (fusermount3) is needed, which is installed setuid root. The implication of providing non-privileged mounts is that the mount owner must not be able to use this capability to compromise the system. Obvious requirements arising from this are: A) mount owner should not be able to get elevated privileges with the help of the mounted filesystem B) mount owner should not get illegitimate access to information from other users' and the super user's processes C) mount owner should not be able to induce undesired behavior in other users' or the super user's processes How are requirements fulfilled? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A) The mount owner could gain elevated privileges by either: 1) creating a filesystem containing a device file, then opening this device 2) creating a filesystem containing a suid or sgid application, then executing this application The solution is not to allow opening device files and ignore setuid and setgid bits when executing programs. To ensure this fusermount3 always adds "nosuid" and "nodev" to the mount options for non-privileged mounts. B) If another user is accessing files or directories in the filesystem, the filesystem daemon serving requests can record the exact sequence and timing of operations performed. This information is otherwise inaccessible to the mount owner, so this counts as an information leak. The solution to this problem will be presented in point 2) of C). C) There are several ways in which the mount owner can induce undesired behavior in other users' processes, such as: 1) mounting a filesystem over a file or directory which the mount owner could otherwise not be able to modify (or could only make limited modifications). This is solved in fusermount3, by checking the access permissions on the mountpoint and only allowing the mount if the mount owner can do unlimited modification (has write access to the mountpoint, and mountpoint is not a "sticky" directory) 2) Even if 1) is solved the mount owner can change the behavior of other users' processes. i) It can slow down or indefinitely delay the execution of a filesystem operation creating a DoS against the user or the whole system. For example a suid application locking a system file, and then accessing a file on the mount owner's filesystem could be stopped, and thus causing the system file to be locked forever. ii) It can present files or directories of unlimited length, or directory structures of unlimited depth, possibly causing a system process to eat up diskspace, memory or other resources, again causing DoS. The solution to this as well as B) is not to allow processes to access the filesystem, which could otherwise not be monitored or manipulated by the mount owner. Since if the mount owner can ptrace a process, it can do all of the above without using a FUSE mount, the same criteria as used in ptrace can be used to check if a process is allowed to access the filesystem or not. Note that the ptrace check is not strictly necessary to prevent B/2/i, it is enough to check if mount owner has enough privilege to send signal to the process accessing the filesystem, since SIGSTOP can be used to get a similar effect. I think these limitations are unacceptable? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If a sysadmin trusts the users enough, or can ensure through other measures, that system processes will never enter non-privileged mounts, it can relax the last limitation with a "user_allow_other" config option. If this config option is set, the mounting user can add the "allow_other" mount option which disables the check for other users' processes. Kernel - userspace interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following diagram shows how a filesystem operation (in this example unlink) is performed in FUSE. NOTE: everything in this description is greatly simplified | "rm /mnt/fuse/file" | FUSE filesystem daemon | | | | >sys_read() | | >fuse_dev_read() | | >request_wait() | | [sleep on fc->waitq] | | | >sys_unlink() | | >fuse_unlink() | | [get request from | | fc->unused_list] | | >request_send() | | [queue req on fc->pending] | | [wake up fc->waitq] | [woken up] | >request_wait_answer() | | [sleep on req->waitq] | | | <request_wait() | | [remove req from fc->pending] | | [copy req to read buffer] | | [add req to fc->processing] | | <fuse_dev_read() | | <sys_read() | | | | [perform unlink] | | | | >sys_write() | | >fuse_dev_write() | | [look up req in fc->processing] | | [remove from fc->processing] | | [copy write buffer to req] | [woken up] | [wake up req->waitq] | | <fuse_dev_write() | | <sys_write() | <request_wait_answer() | | <request_send() | | [add request to | | fc->unused_list] | | <fuse_unlink() | | <sys_unlink() | There are a couple of ways in which to deadlock a FUSE filesystem. Since we are talking about unprivileged userspace programs, something must be done about these. Scenario 1 - Simple deadlock ----------------------------- | "rm /mnt/fuse/file" | FUSE filesystem daemon | | | >sys_unlink("/mnt/fuse/file") | | [acquire inode semaphore | | for "file"] | | >fuse_unlink() | | [sleep on req->waitq] | | | <sys_read() | | >sys_unlink("/mnt/fuse/file") | | [acquire inode semaphore | | for "file"] | | *DEADLOCK* The solution for this is to allow the filesystem to be aborted. Scenario 2 - Tricky deadlock ---------------------------- This one needs a carefully crafted filesystem. It's a variation on the above, only the call back to the filesystem is not explicit, but is caused by a pagefault. | Kamikaze filesystem thread 1 | Kamikaze filesystem thread 2 | | | [fd = open("/mnt/fuse/file")] | [request served normally] | [mmap fd to 'addr'] | | [close fd] | [FLUSH triggers 'magic' flag] | [read a byte from addr] | | >do_page_fault() | | [find or create page] | | [lock page] | | >fuse_readpage() | | [queue READ request] | | [sleep on req->waitq] | | | [read request to buffer] | | [create reply header before addr] | | >sys_write(addr - headerlength) | | >fuse_dev_write() | | [look up req in fc->processing] | | [remove from fc->processing] | | [copy write buffer to req] | | >do_page_fault() | | [find or create page] | | [lock page] | | * DEADLOCK * Solution is basically the same as above. An additional problem is that while the write buffer is being copied to the request, the request must not be interrupted/aborted. This is because the destination address of the copy may not be valid after the request has returned. This is solved with doing the copy atomically, and allowing abort while the page(s) belonging to the write buffer are faulted with get_user_pages(). The 'req->locked' flag indicates when the copy is taking place, and abort is delayed until this flag is unset. ��������������������������������������������fuse-3.18.3/doc/libfuse-operations.txt��������������������������������������������������������������0000644�0001750�0001750�00000031735�15250106036�016645� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������List of libfuse operations with their in/out arguments, created with help of chatgpt. As of kernel 6.18 (protocol 7.45). The list was only partly human verified - use with care. 1. FUSE_LOOKUP (1) - in_args[0]: Variable (up to PATH_MAX for the file name) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Not used - out_args[2]: Not used 2. FUSE_FORGET (2) - in_args[0]: Size of fuse_forget_in (typically 8 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 3. FUSE_GETATTR (3) - in_args[0]: Size of fuse_getattr_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_attr_out (typically 96 bytes) - out_args[1]: Not used - out_args[2]: Not used 4. FUSE_SETATTR (4) - in_args[0]: Size of fuse_setattr_in (typically 32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_attr_out (typically 96 bytes) - out_args[1]: Not used - out_args[2]: Not used 5. FUSE_READLINK (5) - in_args[0]: Not used - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Variable (size of the link target path) - out_args[1]: Not used - out_args[2]: Not used 6. FUSE_SYMLINK (6) - in_args[0]: Variable (new link file name, up to PATH_MAX) - in_args[1]: Variable (target path for the symlink, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Not used - out_args[2]: Not used 7. Unused (7) 8. FUSE_MKNOD (8) - in_args[0]: Size of fuse_mknod_in (24 bytes) - in_args[1]: Variable (file name, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Not used - out_args[2]: Not used 9. FUSE_MKDIR (9) - in_args[0]: Size of fuse_mkdir_in (16 bytes) - in_args[1]: Variable (directory name, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Not used - out_args[2]: Not used 10. FUSE_UNLINK (10) - in_args[0]: Variable (file name, up to PATH_MAX) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 11. FUSE_RMDIR (11) - in_args[0]: Variable (directory name, up to PATH_MAX) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 12. FUSE_RENAME (12) - in_args[0]: Size of fuse_rename_in (24 bytes) - in_args[1]: Variable (old path, up to PATH_MAX) - in_args[2]: Variable (new path, up to PATH_MAX) - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 13. FUSE_LINK (13) - in_args[0]: Size of fuse_link_in (16 bytes) - in_args[1]: Variable (new link path, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Not used - out_args[2]: Not used 14. FUSE_OPEN (14) - in_args[0]: Size of fuse_open_in (8 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_open_out (24 bytes) - out_args[1]: Not used - out_args[2]: Not used 15. FUSE_READ (15) - in_args[0]: Size of fuse_read_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Variable (data read from the file) - out_args[1]: Not used - out_args[2]: Not used 16. FUSE_WRITE (16) - in_args[0]: Size of fuse_write_in (32 bytes) - in_args[1]: Variable (data to write) - in_args[2]: Not used - out_args[0]: Size of fuse_write_out (24 bytes) - out_args[1]: Not used - out_args[2]: Not used 17. FUSE_STATFS (17) - in_args[0]: Not used - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_statfs_out (typically 96 bytes) - out_args[1]: Not used - out_args[2]: Not used 18. FUSE_RELEASE (18) - in_args[0]: Size of fuse_release_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 19. Unused (19) 20. FUSE_FSYNC (20) - in_args[0]: Size of fuse_fsync_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 21. FUSE_SETXATTR (21) - in_args[0]: Size of fuse_setxattr_in (24 bytes) - in_args[1]: Variable (name of attribute, up to 255 bytes) - in_args[2]: Variable (value of attribute) - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used - When FUSE_SETXATTR_EXT is not set: Size of fuse_setxattr_in is 16 bytes (FUSE_COMPAT_SETXATTR_IN_SIZE). 22. FUSE_GETXATTR (22) - in_args[0]: Size of fuse_getxattr_in (24 bytes) - in_args[1]: Variable (name of attribute, up to 255 bytes) - in_args[2]: Not used - out_args[0]: Variable (value of the attribute) - out_args[1]: Not used - out_args[2]: Not used 23. FUSE_LISTXATTR (23) - in_args[0]: Size of fuse_getxattr_in (24 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Variable (list of attribute names, each up to 255 bytes) - out_args[1]: Not used - out_args[2]: Not used 24. FUSE_REMOVEXATTR (24) - in_args[0]: Variable (name of attribute, up to 255 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 25. FUSE_FLUSH (25) - in_args[0]: Size of fuse_flush_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 26. FUSE_INIT (26) - in_args[0]: Size of fuse_init_in (64 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_init_out (typically 80 bytes) - out_args[1]: Not used - out_args[2]: Not used - Flags: - FUSE_SECURITY_CTX - FUSE_CREATE_SUPP_GROUP - FUSE_SETXATTR_EXT - FUSE_COMPAT_SETXATTR_IN_SIZE - Additional flags may include FUSE_ASYNC_READ, FUSE_POSIX_LOCKS, FUSE_FILE_OPS, etc. 27. FUSE_OPENDIR (27) - in_args[0]: Size of fuse_open_in (8 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_open_out (24 bytes) - out_args[1]: Not used - out_args[2]: Not used 28. FUSE_READDIR (28) - in_args[0]: Size of fuse_read_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Variable (directory entries) - out_args[1]: Not used - out_args[2]: Not used 29. FUSE_RELEASEDIR (29) - in_args[0]: Size of fuse_release_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 30. FUSE_FSYNCDIR (30) - in_args[0]: Size of fuse_fsync_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 31. FUSE_GETLK (31) - in_args[0]: Size of fuse_lk_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_lk_out (typically 32 bytes) - out_args[1]: Not used - out_args[2]: Not used 32. FUSE_SETLK (32) - in_args[0]: Size of fuse_lk_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 33. FUSE_SETLKW (33) - in_args[0]: Size of fuse_lk_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 34. FUSE_ACCESS (34) - in_args[0]: Size of fuse_access_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 35. FUSE_CREATE (35) - in_args[0]: Size of fuse_create_in (16 bytes) - in_args[1]: Variable (file name, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Size of fuse_open_out (24 bytes) - out_args[2]: Not used - When FUSE_SECURITY_CTX is set (fc->init_security): Additional security context included in in_args and/or out_args. - When FUSE_CREATE_SUPP_GROUP is set (fc->create_supp_group): Additional supplementary group information included in in_args. 36. FUSE_INTERRUPT (36) - in_args[0]: Size of fuse_interrupt_in (8 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 37. FUSE_BMAP (37) - in_args[0]: Size of fuse_bmap_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_bmap_out (16 bytes) - out_args[1]: Not used - out_args[2]: Not used 38. FUSE_DESTROY (38) - in_args[0]: Not used - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 39. FUSE_IOCTL (39) - in_args[0]: Size of fuse_ioctl_in (64 bytes) - in_args[1]: Variable (ioctl command data) - in_args[2]: Not used - out_args[0]: Size of fuse_ioctl_out (32 bytes) - out_args[1]: Variable (data returned by the ioctl command) - out_args[2]: Not used 40. FUSE_POLL (40) - in_args[0]: Size of fuse_poll_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_poll_out (16 bytes) - out_args[1]: Not used - out_args[2]: Not used 41. FUSE_NOTIFY_REPLY (41) - in_args[0]: Variable (reply data) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 42. FUSE_BATCH_FORGET (42) - in_args[0]: Variable (size depends on the number of forget requests) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 43. FUSE_FALLOCATE (43) - in_args[0]: Size of fuse_fallocate_in (24 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 44. FUSE_READDIRPLUS (44) - in_args[0]: Size of fuse_read_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Variable (directory entries) - out_args[1]: Not used - out_args[2]: Not used 45. FUSE_RENAME2 (45) - in_args[0]: Size of fuse_rename2_in (32 bytes) - in_args[1]: Variable (old path, up to PATH_MAX) - in_args[2]: Variable (new path, up to PATH_MAX) - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 46. FUSE_LSEEK (46) - in_args[0]: Size of fuse_lseek_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_lseek_out (16 bytes) - out_args[1]: Not used - out_args[2]: Not used 47. FUSE_COPY_FILE_RANGE (47) - in_args[0]: Size of fuse_copy_file_range_in (56 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_write_out (24 bytes) - out_args[1]: Not used - out_args[2]: Not used 48. FUSE_SETUPMAPPING (48) - in_args[0]: Size of fuse_setupmapping_in (32 bytes) - in_args[1]: Variable (data to map) - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 49. FUSE_REMOVEMAPPING (49) - in_args[0]: Variable (size depends on the number of mappings to remove) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 50. FUSE_SYNCFS (50) - in_args[0]: Size of fuse_syncfs_in (16 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Not used - out_args[1]: Not used - out_args[2]: Not used 51. FUSE_TMPFILE (51) - in_args[0]: Size of fuse_create_in (16 bytes) - in_args[1]: Variable (file name, up to PATH_MAX) - in_args[2]: Not used - out_args[0]: Size of fuse_entry_out (typically 128 bytes) - out_args[1]: Size of fuse_open_out (24 bytes) - out_args[2]: Not used - When FUSE_SECURITY_CTX is set (fc->init_security): Additional security context included in in_args and/or out_args. - When FUSE_CREATE_SUPP_GROUP is set (fc->create_supp_group): Additional supplementary group information included in in_args. 52. FUSE_STATX (52) - in_args[0]: Size of fuse_statx_in (32 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_statx_out (typically 256 bytes) - out_args[1]: Not used - out_args[2]: Not used 53. FUSE_COPY_FILE_RANGE_64 (53) - in_args[0]: Size of fuse_copy_file_range_in (56 bytes) - in_args[1]: Not used - in_args[2]: Not used - out_args[0]: Size of fuse_copy_file_range_out (8 bytes) - out_args[1]: Not used - out_args[2]: Not used �����������������������������������fuse-3.18.3/doc/mainpage.dox������������������������������������������������������������������������0000644�0001750�0001750�00000004147�15250106036�014564� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/*! \mainpage libfuse API documentation FUSE (Filesystem in Userspace) is an interface for userspace programs to export a filesystem to the Linux kernel. The FUSE project consists of two components: the *fuse* kernel module (maintained in the regular kernel repositories) and the *libfuse* userspace library. libfuse provides the reference implementation for communicating with the FUSE kernel module. A FUSE file system is typically implemented as a standalone application that links with libfuse. libfuse provides functions to mount the file system, unmount it, read requests from the kernel, and send responses back. ## Getting started ## libfuse offers two APIs: a "high-level", synchronous API, and a "low-level" asynchronous API. In both cases, incoming requests from the kernel are passed to the main program using callbacks. When using the high-level API, the callbacks may work with file names and paths instead of inodes, and processing of a request finishes when the callback function returns. When using the low-level API, the callbacks must work with inodes and responses must be sent explicitly using a separate set of API functions. The high-level API that is primarily specified in fuse.h. The low-level API that is primarily documented in fuse_lowlevel.h. ## Examples ## FUSE comes with several examples in the <a href="files.html">examples</a> directory. A good starting point are hello.c (for the high-level API) and hello_ll.c (for the low-level API). ## FUSE internals ## The authoritative source of information about libfuse internals (including the protocol used for communication with the FUSE kernel module) is the source code. However, some people have kindly documented different aspects of FUSE in a more beginner friendly way. While this information is increasingly out of date, it still provides a good overview: - Bharat Vangoor et al have included an overview of the FUSE internals in a <a href="fast17-vangoor.pdf">paper evaluating FUSE performance</a>. - Some documentation of the kernel-userspace protocol is available on the <a href="https://github.com/libfuse/libfuse/wiki/">libfuse wiki</a>. */ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/meson.build�������������������������������������������������������������������������0000644�0001750�0001750�00000000163�15250106036�014423� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������if not platform.endswith('bsd') and platform != 'dragonfly' install_man('fusermount3.1', 'mount.fuse3.8') endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/mount.fuse3.8�����������������������������������������������������������������������0000644�0001750�0001750�00000031416�15250106036�014545� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH fuse "8" .SH NAME fuse \- configuration and mount options for FUSE file systems .SH DESCRIPTION FUSE (Filesystem in Userspace) is a simple interface for userspace programs to export a virtual filesystem to the Linux kernel. FUSE also provides a secure method for non privileged users to create and mount their own filesystem implementations. .SH DEFINITIONS .TP \fBFUSE\fP The in-kernel filesystem that forwards requests to a user-space process. .TP \fBfilesystem\fP The user-space process that responds to requests received from the kernel. .TP \fBlibfuse\fP The shared library that most (user-space) filesystems use to communicate with FUSE (the kernel filesystem). libfuse also provides the \fBfusermount3\fP (or \fBfusermount\fP if you have older version of libfuse) helper to allow non-privileged users to mount filesystems. .TP \fBfilesystem owner\fP The user that starts the filesystem and instructs the kernel to associate it with a particular mountpoint. The latter is typically done by the filesystem itself on start-up. When using libfuse, this is done by calling the \fBfusermount3\fP utility. .TP \fBclient\fP Any process that interacts with the mountpoint. .SH CONFIGURATION Some options regarding mount policy can be set in the file \fI/etc/fuse.conf\fP. Currently these options are: .TP \fBmount_max = NNN\fP Set the maximum number of FUSE mounts allowed to non-root users. The default is 1000. .TP \fBuser_allow_other\fP Allow non-root users to specify the \fBallow_other\fP or \fBallow_root\fP mount options (see below). .TP These limits are enforced by the \fBfusermount3\fP helper, so they can be avoided by filesystems that run as root. .SH OPTIONS Most of the generic mount options described in \fBmount\fP are supported (\fBro\fP, \fBrw\fP, \fBsuid\fP, \fBnosuid\fP, \fBdev\fP, \fBnodev\fP, \fBexec\fP, \fBnoexec\fP, \fBatime\fP, \fBnoatime\fP, \fBsync\fP, \fBasync\fP, \fBdirsync\fP). Filesystems are mounted with \fBnodev,nosuid\fP by default, which can only be overridden by a privileged user. .SS "General mount options:" These are FUSE specific mount options that can be specified for all filesystems: .TP \fBdefault_permissions\fP This option instructs the kernel to perform its own permission check instead of deferring all permission checking to the filesystem. The check by the kernel is done in addition to any permission checks by the filesystem, and both have to succeed for an operation to be allowed. The kernel performs a standard UNIX permission check (based on mode bits and ownership of the directory entry, and uid/gid of the client). This mount option is activated implicitly if the filesystem enables ACL support during the initial feature negotiation when opening the device fd. In this case, the kernel performs both ACL and standard unix permission checking. Filesystems that do not implement any permission checking should generally add this option internally. .TP \fBallow_other\fP This option overrides the security measure restricting file access to the filesystem owner, so that all users (including root) can access the files. .TP \fBrootmode=M\fP Specifies the file mode of the filesystem's root (in octal representation). .TP \fBblkdev\fP Mount a filesystem backed by a block device. This is a privileged option. The device must be specified with the \fBfsname=NAME\fP option. .TP \fBblksize=N\fP Set the block size for the filesystem. This option is only valid for 'fuseblk' type mounts. The default is 512. In most cases, this option should not be specified by the filesystem owner but set internally by the filesystem. .TP \fBmax_read=N\fP With this option the maximum size of read operations can be set. The default is infinite, but typically the kernel enforces its own limit in addition to this one. A value of zero corresponds to no limit. This option should not be specified by the filesystem owner. The correct (or optimum) value depends on the filesystem implementation and should thus be set by the filesystem internally. This mount option is deprecated in favor of direct negotiation over the device fd (as done for e.g. the maximum size of write operations). For the time being, libfuse-using filesystems that want to limit the read size must therefore use this mount option \fIand\fP set the same value again in the init() handler. .TP \fBfd=N\fP The file descriptor to use for communication between the userspace filesystem and the kernel. The file descriptor must have been obtained by opening the FUSE device (/dev/fuse). This option should not be specified by the filesystem owner. It is set by libfuse (or, if libfuse is not used, must be set by the filesystem itself). .TP \fBuser_id=N\fP \fBgroup_id=N\fP Specifies the numeric uid/gid of the mount owner. This option should not be specified by the filesystem owner. It is set by libfuse (or, if libfuse is not used, must be set by the filesystem itself). .TP \fBfsname=NAME\fP Sets the filesystem source (first field in \fI/etc/mtab\fP). The default is the name of the filesystem process. .TP \fBsubtype=TYPE\fP Sets the filesystem type (third field in \fI/etc/mtab\fP). The default is the name of the filesystem process. If the kernel supports it, \fI/etc/mtab\fP and \fI/proc/mounts\fP will show the filesystem type as \fBfuse.TYPE\fP If the kernel doesn't support subtypes, the source field will be \fBTYPE#NAME\fP, or if \fBfsname\fP option is not specified, just \fBTYPE\fP. .SS "libfuse-specific mount options:" These following options are not actually passed to the kernel but interpreted by libfuse. They can be specified for all filesystems that use libfuse: .TP \fBallow_root\fP This option is similar to \fBallow_other\fP but file access is limited to the filesystem owner and root. This option and \fBallow_other\fP are mutually exclusive. .TP \fBauto_unmount\fP This option enables automatic release of the mountpoint if filesystem terminates for any reason. Normally the filesystem is responsible for releasing the mountpoint, which means that the mountpoint becomes inaccessible if the filesystem terminates without first unmounting. This option is dangerous and should only be used after careful consideration of the risks. Automatically unmounting the filesystem means that if the filesystem crashes the mountpoint may suddenly appear empty, which may have unintended consequences. For example, a running backup and mirroring program may conclude that all the data in the filesystem has been deleted and proceed to propagate this deletion to the backup / remote system. If the mountpoint instead becomes inaccessible (the default), most programs will behave correctly (report an error). This feature may also accidentally unmount the wrong filesystem due to race conditions. For example, if another filesystem was mounted underneath the same mountpoint, or if a new filesystem is mounted after the FUSE process has crashed, it may accidentally get unmounted. At the moment, this option implies that the filesystem will also be mounted with \fBnodev\fP and \fBnosuid\fP (even when mounted by root). This restriction may be lifted in the future. .SS "High-level mount options:" These following options are not actually passed to the kernel but interpreted by libfuse. They can only be specified for filesystems that use the high-level libfuse API: .TP \fBkernel_cache\fP This option disables flushing the cache of the file contents on every \fBopen\fP(2). This should only be enabled on filesystems, where the file data is never changed externally (not through the mounted FUSE filesystem). Thus it is not suitable for network filesystems and other "intermediate" filesystems. \fBNOTE\fP: if this option is not specified (and neither \fBdirect_io\fP) data is still cached after the \fBopen\fP(2), so a \fBread\fP(2) system call will not always initiate a read operation. .TP \fBauto_cache\fP This option is an alternative to \fBkernel_cache\fP. Instead of unconditionally keeping cached data, the cached data is invalidated on \fBopen\fP(2) if the modification time or the size of the file has changed since it was last opened. .TP \fBumask=M fmask=M dmask=M\fP Override the permission bits set by the filesystem in \fIst_mode\fP. The resulting permission bits are the ones missing from the mask value, which is given in octal representation. \fBfmask\fP and \fBdmask\fP (respectively) may be used to control the permission bits of files and directories separately. umask is overridden by the individual fmask and dmask options. .TP \fBuid=N\fP Override the \fIst_uid\fP field set by the filesystem (N is numeric). .TP \fBgid=N\fP Override the \fIst_gid\fP field set by the filesystem (N is numeric). .TP \fBentry_timeout=T\fP The timeout in seconds for which name lookups will be cached. The default is 1.0 second. For all the timeout options, it is possible to give fractions of a second as well (e.g. \fBentry_timeout=2.8\fP) .TP \fBnegative_timeout=T\fP The timeout in seconds for which a negative lookup will be cached. This means, that if file did not exist (lookup returned \fBENOENT\fP), the lookup will only be redone after the timeout, and the file/directory will be assumed to not exist until then. The default is 0.0 second, meaning that caching negative lookups are disabled. .TP \fBattr_timeout=T\fP The timeout in seconds for which file/directory attributes are cached. The default is 1.0 second. .TP \fBac_attr_timeout=T\fP The timeout in seconds for which file attributes are cached for the purpose of checking if \fBauto_cache\fP should flush the file data on open. The default is the value of \fBattr_timeout\fP .TP \fBnoforget\fP .TP \fBremember=T\fP Normally, libfuse assigns inodes to paths only for as long as the kernel is aware of them. With this option inodes are instead assigned for at least \fBT\fP seconds (or, in the case of \fBnoforget\fP, the life-time of the filesystem). This will require more memory, but may be necessary when using applications that make use of inode numbers. .TP \fBmodules=M1[:M2...]\fP Add modules to the filesystem stack. Modules are pushed in the order they are specified, with the original filesystem being on the bottom of the stack. .SS "\fBmount.fuse3\fP options:" These options are interpreted by \fBmount.fuse3\fP and are thus only available when mounting a file system via \fBmount.fuse3\fP (such as when mounting via the generic \fBmount\fP(1) command or \fI/etc/fstab\fP). Supported options are: .TP \fBsetuid=USER\fP Switch to \fBUSER\fP and its primary group before launching the FUSE file system process. mount.fuse3 must be run as root or with \fBCAP_SETUID\fP and \fBCAP_SETGID\fP for this to work. .TP \fBdrop_privileges\fP Perform setup of the FUSE file descriptor and mounting the file system before launching the FUSE file system process. \fBmount.fuse3\fP requires privilege to do so, i.e. must be run as root or at least with \fBCAP_SYS_ADMIN\fP and \fBCAP_SETPCAP\fP. It will launch the file system process fully unprivileged, i.e. without \fBcapabilities\fP(7) and \fBprctl\fP(2) flags set up such that privileges can't be reacquired (e.g. via setuid or fscaps binaries). This reduces risk in the event of the FUSE file system process getting compromised by malicious file system data. .SH FUSE MODULES (STACKING) Modules are filesystem stacking support to high level API. Filesystem modules can be built into libfuse or loaded from shared object .SS "iconv" Perform file name character set conversion. Options are: .TP \fBfrom_code=CHARSET\fP Character set to convert from (see \fBiconv -l\fP for a list of possible values). Default is \fBUTF-8\fP. .TP \fBto_code=CHARSET\fP Character set to convert to. Default is determined by the current locale. .SS "subdir" Prepend a given directory to each path. Options are: .TP \fBsubdir=DIR\fP Directory to prepend to all paths. This option is \fImandatory\fP. .TP \fBrellinks\fP Transform absolute symlinks into relative .TP \fBnorellinks\fP Do not transform absolute symlinks into relative. This is the default. .SH SECURITY The fusermount3 program is installed set-user-gid to fuse. This is done to allow users from fuse group 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: .IP 1. The user can only mount on a mountpoint, for which it has write permission .IP 2. The mountpoint is not a sticky directory which isn't owned by the user (like \fI/tmp\fP usually is) .IP 3. No other user (including root) can access the contents of the mounted filesystem. .SH NOTE FUSE filesystems are unmounted using the \fBfusermount3\fP(1) command (\fBfusermount3 -u mountpoint\fP). .SH "AUTHORS" .LP FUSE is currently maintained by Nikolaus Rath <Nikolaus@rath.org> .LP The original author of FUSE is Miklos Szeredi <mszeredi@inf.bme.hu>. .LP This man page was originally written by Bastien Roucaries <roucaries.bastien+debian@gmail.com> for the Debian GNU/Linux distribution. .SH SEE ALSO .BR fusermount3 (1) .BR fusermount (1) .BR mount (8) .BR fuse (4) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/html/�������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�15250106404�013224� 5����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������fuse-3.18.3/doc/html/doxygen_crawl.html�������������������������������������������������������������0000644�0001750�0001750�00000073370�15250106404�016771� 0����������������������������������������������������������������������������������������������������ustar �bernd���������������������������bernd������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US"> <head> <title>Validator / crawler helper fuse-3.18.3/doc/html/tabs.css0000644000175000017500000001662315250106404014677 0ustar berndbernd.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:0px/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}.main-menu-btn{position:relative;display:inline-block;width:36px;height:36px;text-indent:36px;margin-left:8px;white-space:nowrap;overflow:hidden;cursor:pointer;-webkit-tap-highlight-color:rgba(0,0,0,0)}.main-menu-btn-icon,.main-menu-btn-icon:before,.main-menu-btn-icon:after{position:absolute;top:50%;left:2px;height:2px;width:24px;background:var(--nav-menu-button-color);-webkit-transition:all 0.25s;transition:all 0.25s}.main-menu-btn-icon:before{content:'';top:-7px;left:0}.main-menu-btn-icon:after{content:'';top:7px;left:0}#main-menu-state:checked~.main-menu-btn .main-menu-btn-icon{height:0}#main-menu-state:checked~.main-menu-btn .main-menu-btn-icon:before{top:0;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}#main-menu-state:checked~.main-menu-btn .main-menu-btn-icon:after{top:0;-webkit-transform:rotate(45deg);transform:rotate(45deg)}#main-menu-state{position:absolute;width:1px;height:1px;margin:-1px;border:0;padding:0;overflow:hidden;clip:rect(1px, 1px, 1px, 1px)}#main-menu-state:not(:checked)~#main-menu{display:none}#main-menu-state:checked~#main-menu{display:block}@media (min-width: 768px){.main-menu-btn{position:absolute;top:-99999px}#main-menu-state:not(:checked)~#main-menu{display:block}}.sm-dox{background-color:var(--nav-menu-background-color);sm-dox__round-corners-last-item:5px}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0px 12px;padding-right:43px;font-family:var(--font-family-nav);font-size:13px;line-height:36px;text-decoration:none;color:var(--nav-text-normal-color);outline:none}.sm-dox a:hover{background-color:var(--nav-menu-active-bg);border-radius:5px}.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;border-radius:5px}.sm-dox a span.sub-arrow:before{display:block;content:'+'}.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{border-radius:5px 5px 0 0}.sm-dox ul{background:var(--nav-menu-background-color);sm-dox__sub-items-indentation:8px}.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:var(--nav-menu-background-color);background-image:none}.sm-dox ul a:hover{background-color:var(--nav-menu-active-bg);border-radius:5px}@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-color:var(--nav-menu-background-color);line-height:36px}.sm-dox a span.sub-arrow{top:15px;right:10px;box-sizing:content-box;padding:0;margin:0;display:inline-block;width:5px;height:5px;background-color:var(--nav-menu-background-color);border-right:2px solid var(--nav-arrow-color);border-bottom:2px solid var(--nav-arrow-color);transform:rotate(45deg);border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0px 6px}.sm-dox a:hover{background-color:var(--nav-menu-active-bg);border-radius:5px !important}.sm-dox a:hover span.sub-arrow{background-color:var(--nav-menu-active-bg);border-right:2px solid var(--nav-arrow-selected-color);border-bottom:2px solid var(--nav-arrow-selected-color)}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0;padding:3px}.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 var(--nav-menu-background-color) transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:var(--nav-menu-background-color);border-radius:5px !important;box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{transform:rotate(-45deg)}.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:var(--nav-menu-foreground-color);background-image:none;border:0 !important}.sm-dox ul a:hover{background-color:var(--nav-menu-active-bg);border-radius:5px}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:var(--nav-menu-background-color);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 var(--nav-menu-foreground-color) transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:var(--nav-menu-foreground-color) transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:6px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:6px}.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;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 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:var(--nav-menu-background-color)}} fuse-3.18.3/doc/html/jquery.js0000644000175000017500000053121615250106404015111 0ustar berndbernd/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e} var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType }catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c )),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){ return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll( ":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id") )&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push( "\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test( a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null, null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne ).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for( var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n; return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0, r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r] ,C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each( function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r, "position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})} ),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each( "blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=y(e||this.defaultElement||this)[0],this.element=y(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=y(),this.hoverable=y(),this.focusable=y(),this.classesElementLookup={},e!==this&&(y.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t ){t.target===e&&this.destroy()}}),this.document=y(e.style?e.ownerDocument:e.document||e),this.window=y(this.document[0].defaultView||this.document[0].parentWindow)),this.options=y.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:y.noop,_create:y.noop,_init:y.noop,destroy:function(){var i=this;this._destroy(),y.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:y.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return y.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t ]=y.widget.extend({},this.options[t]),n=0;n
"),i=e.children()[0];return y("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i}, getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(D(s),D(n))?o.important="horizontal":o.important="vertical",p.using.call(this,t,o)}),h.offset(y.extend(l,{using:t}))})},y.ui.position={fit:{left:function(t,e){var i=e.within, s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,h=s-o,a=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),y.ui.plugin={add:function(t,e,i){var s,n=y.ui[t].prototype;for(s in i)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([e,i[s]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;n").css({overflow:"hidden",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("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,t={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(t),this.originalElement.css("margin",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(t),this._proportionallyResize()),this._setupHandles(),e.autoHide&&y(this.element).on("mouseenter",function(){e.disabled||(i._removeClass("ui-resizable-autohide"),i._handles.show())}).on("mouseleave",function(){e.disabled||i.resizing||(i._addClass("ui-resizable-autohide"),i._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy(),this._addedHandles.remove();function t(t){y(t ).removeData("resizable").removeData("ui-resizable").off(".resizable")}var e;return this.elementIsWrapper&&(t(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;case"aspectRatio":this._aspectRatio=!!e}},_setupHandles:function(){var t,e,i,s,n,o=this.options,h=this;if(this.handles=o.handles||(y(".ui-resizable-handle",this.element).length?{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"}:"e,s,se"),this._handles=y(),this._addedHandles=y(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),i=this.handles.split( ","),this.handles={},e=0;e"),this._addClass(n,"ui-resizable-handle "+s),n.css({zIndex:o.zIndex}),this.handles[t]=".ui-resizable-"+t,this.element.children(this.handles[t]).length||(this.element.append(n),this._addedHandles=this._addedHandles.add(n));this._renderAxis=function(t){var e,i,s;for(e in t=t||this.element,this.handles)this.handles[e].constructor===String?this.handles[e]=this.element.children(this.handles[e]).first().show():(this.handles[e].jquery||this.handles[e].nodeType)&&(this.handles[e]=y(this.handles[e]),this._on(this.handles[e],{mousedown:h._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(i=y(this.handles[e],this.element),s=/sw|ne|nw|se|n|s/.test(e)?i.outerHeight():i.outerWidth(),i=["padding",/ne|nw|n/.test(e)?"Top":/se|sw|s/.test(e)?"Bottom":/^e$/.test(e)?"Right":"Left"].join(""),t.css(i,s),this._proportionallyResize()),this._handles=this._handles.add( this.handles[e])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){h.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),h.axis=n&&n[1]?n[1]:"se")}),o.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._addedHandles.remove()},_mouseCapture:function(t){var e,i,s=!1;for(e in this.handles)(i=y(this.handles[e])[0])!==t.target&&!y.contains(i,t.target)||(s=!0);return!this.options.disabled&&s},_mouseStart:function(t){var e,i,s=this.options,n=this.element;return this.resizing=!0,this._renderProxy(),e=this._num(this.helper.css("left")),i=this._num(this.helper.css("top")),s.containment&&(e+=y(s.containment).scrollLeft()||0,i+=y(s.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:e,top:i},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{ width:n.width(),height:n.height()},this.originalSize=this._helper?{width:n.outerWidth(),height:n.outerHeight()}:{width:n.width(),height:n.height()},this.sizeDiff={width:n.outerWidth()-n.width(),height:n.outerHeight()-n.height()},this.originalPosition={left:e,top:i},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio="number"==typeof s.aspectRatio?s.aspectRatio:this.originalSize.width/this.originalSize.height||1,s=y(".ui-resizable-"+this.axis).css("cursor"),y("body").css("cursor","auto"===s?this.axis+"-resize":s),this._addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(t){var e=this.originalMousePosition,i=this.axis,s=t.pageX-e.left||0,e=t.pageY-e.top||0,i=this._change[i];return this._updatePrevProperties(),i&&(e=i.apply(this,[t,s,e]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(e=this._updateRatio(e,t)),e=this._respectSize(e,t),this._updateCache(e),this._propagate("resize",t),e=this._applyChanges(), !this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),y.isEmptyObject(e)||(this._updatePrevProperties(),this._trigger("resize",t,this.ui()),this._applyChanges())),!1},_mouseStop:function(t){this.resizing=!1;var e,i,s,n=this.options,o=this;return this._helper&&(s=(e=(i=this._proportionallyResizeElements).length&&/textarea/i.test(i[0].nodeName))&&this._hasScroll(i[0],"left")?0:o.sizeDiff.height,i=e?0:o.sizeDiff.width,e={width:o.helper.width()-i,height:o.helper.height()-s},i=parseFloat(o.element.css("left"))+(o.position.left-o.originalPosition.left)||null,s=parseFloat(o.element.css("top"))+(o.position.top-o.originalPosition.top)||null,n.animate||this.element.css(y.extend(e,{top:s,left:i})),o.helper.height(o.size.height),o.helper.width(o.size.width),this._helper&&!n.animate&&this._proportionallyResize()),y("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){ this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s=this.options,n={minWidth:this._isNumber(s.minWidth)?s.minWidth:0,maxWidth:this._isNumber(s.maxWidth)?s.maxWidth:1/0,minHeight:this._isNumber(s.minHeight)?s.minHeight:0,maxHeight:this._isNumber(s.maxHeight)?s.maxHeight:1/0};(this._aspectRatio||t)&&(e=n.minHeight*this.aspectRatio,i=n.minWidth/this.aspectRatio,s=n.maxHeight*this.aspectRatio,t=n.maxWidth/this.aspectRatio,e>n.minWidth&&(n.minWidth=e),i>n.minHeight&&(n.minHeight=i),st.width,h=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,a=this.originalPosition.left+this.originalSize.width,r=this.originalPosition.top+this.originalSize.height ,l=/sw|nw|w/.test(i),i=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),h&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=a-e.minWidth),s&&l&&(t.left=a-e.maxWidth),h&&i&&(t.top=r-e.minHeight),n&&i&&(t.top=r-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];e<4;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;e").css({overflow:"hidden"}),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++e.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize;return{left:this.originalPosition.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize;return{top:this.originalPosition.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(t,e,i){return y.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},sw:function(t,e, i){return y.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,e,i]))},ne:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,e,i]))},nw:function(t,e,i){return y.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,e,i]))}},_propagate:function(t,e){y.ui.plugin.call(this,t,[e,this.ui()]),"resize"!==t&&this._trigger(t,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}}}),y.ui.plugin.add("resizable","animate",{stop:function(e){var i=y(this).resizable("instance"),t=i.options,s=i._proportionallyResizeElements,n=s.length&&/textarea/i.test(s[0].nodeName),o=n&&i._hasScroll(s[0],"left")?0:i.sizeDiff.height,h=n?0:i.sizeDiff.width,n={width:i.size.width-h,height:i.size.height-o},h=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left )||null,o=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(y.extend(n,o&&h?{top:o,left:h}:{}),{duration:t.animateDuration,easing:t.animateEasing,step:function(){var t={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};s&&s.length&&y(s[0]).css({width:t.width,height:t.height}),i._updateCache(t),i._propagate("resize",e)}})}}),y.ui.plugin.add("resizable","containment",{start:function(){var i,s,n=y(this).resizable("instance"),t=n.options,e=n.element,o=t.containment,h=o instanceof y?o.get(0):/parent/.test(o)?e.parent().get(0):o;h&&(n.containerElement=y(h),/document/.test(o)||o===document?(n.containerOffset={left:0,top:0},n.containerPosition={left:0,top:0},n.parentData={element:y(document),left:0,top:0,width:y(document).width(),height:y(document).height()||document.body.parentNode.scrollHeight}):(i=y(h),s=[],y(["Top","Right","Left","Bottom"]).each(function(t,e ){s[t]=n._num(i.css("padding"+e))}),n.containerOffset=i.offset(),n.containerPosition=i.position(),n.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},t=n.containerOffset,e=n.containerSize.height,o=n.containerSize.width,o=n._hasScroll(h,"left")?h.scrollWidth:o,e=n._hasScroll(h)?h.scrollHeight:e,n.parentData={element:h,left:t.left,top:t.top,width:o,height:e}))},resize:function(t){var e=y(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.position,o=e._aspectRatio||t.shiftKey,h={top:0,left:0},a=e.containerElement,t=!0;a[0]!==document&&/static/.test(a.css("position"))&&(h=s),n.left<(e._helper?s.left:0)&&(e.size.width=e.size.width+(e._helper?e.position.left-s.left:e.position.left-h.left),o&&(e.size.height=e.size.width/e.aspectRatio,t=!1),e.position.left=i.helper?s.left:0),n.top<(e._helper?s.top:0)&&(e.size.height=e.size.height+(e._helper?e.position.top-s.top:e.position.top),o&&(e.size.width=e.size.height*e.aspectRatio,t=!1),e.position.top=e._helper?s.top:0), i=e.containerElement.get(0)===e.element.parent().get(0),n=/relative|absolute/.test(e.containerElement.css("position")),i&&n?(e.offset.left=e.parentData.left+e.position.left,e.offset.top=e.parentData.top+e.position.top):(e.offset.left=e.element.offset().left,e.offset.top=e.element.offset().top),n=Math.abs(e.sizeDiff.width+(e._helper?e.offset.left-h.left:e.offset.left-s.left)),s=Math.abs(e.sizeDiff.height+(e._helper?e.offset.top-h.top:e.offset.top-s.top)),n+e.size.width>=e.parentData.width&&(e.size.width=e.parentData.width-n,o&&(e.size.height=e.size.width/e.aspectRatio,t=!1)),s+e.size.height>=e.parentData.height&&(e.size.height=e.parentData.height-s,o&&(e.size.width=e.size.height*e.aspectRatio,t=!1)),t||(e.position.left=e.prevPosition.left,e.position.top=e.prevPosition.top,e.size.width=e.prevSize.width,e.size.height=e.prevSize.height)},stop:function(){var t=y(this).resizable("instance"),e=t.options,i=t.containerOffset,s=t.containerPosition,n=t.containerElement,o=y(t.helper),h=o.offset(),a=o.outerWidth( )-t.sizeDiff.width,o=o.outerHeight()-t.sizeDiff.height;t._helper&&!e.animate&&/relative/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o}),t._helper&&!e.animate&&/static/.test(n.css("position"))&&y(this).css({left:h.left-s.left-i.left,width:a,height:o})}}),y.ui.plugin.add("resizable","alsoResize",{start:function(){var t=y(this).resizable("instance").options;y(t.alsoResize).each(function(){var t=y(this);t.data("ui-resizable-alsoresize",{width:parseFloat(t.width()),height:parseFloat(t.height()),left:parseFloat(t.css("left")),top:parseFloat(t.css("top"))})})},resize:function(t,i){var e=y(this).resizable("instance"),s=e.options,n=e.originalSize,o=e.originalPosition,h={height:e.size.height-n.height||0,width:e.size.width-n.width||0,top:e.position.top-o.top||0,left:e.position.left-o.left||0};y(s.alsoResize).each(function(){var t=y(this),s=y(this).data("ui-resizable-alsoresize"),n={},e=t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];y.each(e, function(t,e){var i=(s[e]||0)+(h[e]||0);i&&0<=i&&(n[e]=i||null)}),t.css(n)})},stop:function(){y(this).removeData("ui-resizable-alsoresize")}}),y.ui.plugin.add("resizable","ghost",{start:function(){var t=y(this).resizable("instance"),e=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}),t._addClass(t.ghost,"ui-resizable-ghost"),!1!==y.uiBackCompat&&"string"==typeof t.options.ghost&&t.ghost.addClass(this.options.ghost),t.ghost.appendTo(t.helper)},resize:function(){var t=y(this).resizable("instance");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=y(this).resizable("instance");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),y.ui.plugin.add("resizable","grid",{resize:function(){var t,e=y(this).resizable("instance"),i=e.options,s=e.size,n=e.originalSize,o=e.originalPosition,h=e.axis,a="number"==typeof i.grid?[i.grid,i.grid]:i.grid,r=a[0 ]||1,l=a[1]||1,u=Math.round((s.width-n.width)/r)*r,p=Math.round((s.height-n.height)/l)*l,d=n.width+u,c=n.height+p,f=i.maxWidth&&i.maxWidthd,s=i.minHeight&&i.minHeight>c;i.grid=a,m&&(d+=r),s&&(c+=l),f&&(d-=r),g&&(c-=l),/^(se|s|e)$/.test(h)?(e.size.width=d,e.size.height=c):/^(ne)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.top=o.top-p):/^(sw)$/.test(h)?(e.size.width=d,e.size.height=c,e.position.left=o.left-u):((c-l<=0||d-r<=0)&&(t=e._getPaddingPlusBorderDimensions(this)),0=f[g]?0:Math.min(f[g],n));!a&&1-1){ targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se", "n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if( session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)} closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if( session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE, function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset); tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList, finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight())); return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")} function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(), elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight, viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b, "_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); /*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 * http://www.smartmenus.org/ * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)), mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend( $.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy( this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData( "smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id" ).indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?( this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for( var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){ return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if(( !this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&( this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0 ]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass( "highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){ t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]" )||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){ t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"), a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i, downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2) )&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t )&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0), canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}}, rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})} return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1, bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); fuse-3.18.3/doc/html/menu.js0000644000175000017500000001336715250106404014540 0ustar berndbernd/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ function initMenu(relPath,searchEnabled,serverSide,searchPage,search,treeview) { function makeTree(data,relPath) { let result=''; if ('children' in data) { result+='
    '; for (let i in data.children) { let url; const link = data.children[i].url; if (link.substring(0,1)=='^') { url = link.substring(1); } else { url = relPath+link; } result+='
  • '+ data.children[i].text+''+ makeTree(data.children[i],relPath)+'
  • '; } result+='
'; } return result; } let searchBoxHtml; if (searchEnabled) { if (serverSide) { searchBoxHtml='
'+ '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
'; } else { searchBoxHtml='
'+ ''+ ''+ ''+ ''+ ''+ '
'+ '
'+ '
'; } } $('#main-nav').before('
'+ ''+ ''+ '
'); $('#main-nav').append(makeTree(menudata,relPath)); $('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu'); $('#main-menu').append('
  • '); const $mainMenuState = $('#main-menu-state'); let prevWidth = 0; if ($mainMenuState.length) { const initResizableIfExists = function() { if (typeof initResizable==='function') initResizable(treeview); } // animate mobile menu $mainMenuState.change(function() { const $menu = $('#main-menu'); let options = { duration: 250, step: initResizableIfExists }; if (this.checked) { options['complete'] = () => $menu.css('display', 'block'); $menu.hide().slideDown(options); } else { options['complete'] = () => $menu.css('display', 'none'); $menu.show().slideUp(options); } }); // set default menu visibility const resetState = function() { const $menu = $('#main-menu'); const newWidth = $(window).outerWidth(); if (newWidth!=prevWidth) { if ($(window).outerWidth()<768) { $mainMenuState.prop('checked',false); $menu.hide(); $('#searchBoxPos1').html(searchBoxHtml); $('#searchBoxPos2').hide(); } else { $menu.show(); $('#searchBoxPos1').empty(); $('#searchBoxPos2').html(searchBoxHtml); $('#searchBoxPos2').show(); } if (typeof searchBox!=='undefined') { searchBox.CloseResultsWindow(); } prevWidth = newWidth; } } $(window).ready(function() { resetState(); initResizableIfExists(); }); $(window).resize(resetState); } $('#main-menu').smartmenus(); } /* @license-end */ fuse-3.18.3/doc/html/navtree.css0000644000175000017500000001303215250106404015401 0ustar berndbernd#nav-tree .children_ul { margin:0; padding:4px; } #nav-tree ul { list-style:none outside none; margin:0px; padding:0px; } #nav-tree li { white-space:nowrap; margin:0; padding:0; } #nav-tree .plus { margin:0px; } #nav-tree .selected { position: relative; background-color: var(--nav-menu-active-bg); border-radius: 0 6px 6px 0; /*margin-right: 5px;*/ } #nav-tree img { margin:0px; padding:0px; border:0px; vertical-align: middle; } #nav-tree a { text-decoration:none; padding:0px; margin:0px; } #nav-tree .label { margin:0px; padding:0px; font: 12px var(--font-family-nav); line-height: 22px; } #nav-tree .label a { padding:2px; } #nav-tree .selected a { text-decoration:none; color:var(--page-link-color); } #nav-tree .children_ul { margin:0px; padding:0px; } #nav-tree .item { margin: 0 6px 0 -5px; padding: 0 0 0 5px; height: 22px; } #nav-tree { padding: 0px 0px; font-size:14px; overflow:auto; } #doc-content { overflow:auto; display:block; padding:0px; margin:0px; -webkit-overflow-scrolling : touch; /* iOS 5+ */ } #side-nav { padding:0 6px 0 0; margin: 0px; display:block; position: absolute; left: 0px; overflow : hidden; } .ui-resizable .ui-resizable-handle { display:block; } .ui-resizable-e { transition: opacity 0.5s ease; background-color: var(--nav-splitbar-bg-color); opacity:0; cursor:col-resize; height:100%; right:0; top:0; width:6px; position: relative; } .ui-resizable-e:after { content: ''; display: block; top: 50%; left: 1px; width: 2px; height: 15px; border-left: 1px solid var(--nav-splitbar-handle-color); border-right: 1px solid var(--nav-splitbar-handle-color); position: absolute; } .ui-resizable-e:hover { opacity: 1; } .ui-resizable-handle { display:none; font-size:0.1px; position:absolute; z-index:1; } #nav-tree-contents { margin: 6px 0px 0px 0px; } #nav-tree { background-color: var(--nav-background-color); -webkit-overflow-scrolling : touch; /* iOS 5+ */ scrollbar-width: thin; border-right: 1px solid var(--nav-border-color); padding-left: 5px; } #nav-sync { position:absolute; top:0px; right:0px; z-index:1; } #nav-sync img { opacity:0.3; } div.nav-sync-icon { position: relative; width: 24px; height: 17px; left: -6px; top: -1px; opacity: 0.7; display: inline-block; background-color: var(--sync-icon-background-color); border: 1px solid var(--sync-icon-border-color); box-sizing: content-box; } div.nav-sync-icon:hover { background-color: var(--sync-icon-selected-background-color); opacity: 1.0; } div.nav-sync-icon.active:after { content: ''; background-color: var(--sync-icon-background-color); border-top: 2px solid var(--sync-icon-color); position: absolute; width: 16px; height: 0px; top: 7px; left: 4px; } div.nav-sync-icon.active:hover:after { border-top: 2px solid var(--sync-icon-selected-color); } span.sync-icon-left { position: absolute; padding: 0; margin: 0; top: 3px; left: 4px; display: inline-block; width: 8px; height: 8px; border-left: 2px solid var(--sync-icon-color); border-top: 2px solid var(--sync-icon-color); transform: rotate(-45deg); } span.sync-icon-right { position: absolute; padding: 0; margin: 0; top: 3px; left: 10px; display: inline-block; width: 8px; height: 8px; border-right: 2px solid var(--sync-icon-color); border-bottom: 2px solid var(--sync-icon-color); transform: rotate(-45deg); } div.nav-sync-icon:hover span.sync-icon-left { border-left: 2px solid var(--sync-icon-selected-color); border-top: 2px solid var(--sync-icon-selected-color); } div.nav-sync-icon:hover span.sync-icon-right { border-right: 2px solid var(--sync-icon-selected-color); border-bottom: 2px solid var(--sync-icon-selected-color); } #nav-path ul { border-top: 1px solid var(--nav-breadcrumb-separator-color); } @media print { #nav-tree { display: none; } div.ui-resizable-handle { display: none; position: relative; } } /*---------------------------*/ #container { display: grid; grid-template-columns: auto auto; overflow: hidden; } #page-nav { background: var(--nav-background-color); display: block; width: 250px; box-sizing: content-box; position: relative; border-left: 1px solid var(--nav-border-color); } #page-nav-tree { display: inline-block; } #page-nav-resize-handle { transition: opacity 0.5s ease; background-color: var(--nav-splitbar-bg-color); opacity:0; cursor:col-resize; height:100%; right:0; top:0; width:6px; position: relative; z-index: 1; user-select: none; } #page-nav-resize-handle:after { content: ''; display: block; top: 50%; left: 1px; width: 2px; height: 15px; border-left: 1px solid var(--nav-splitbar-handle-color); border-right: 1px solid var(--nav-splitbar-handle-color); position: absolute; } #page-nav-resize-handle.dragging, #page-nav-resize-handle:hover { opacity: 1; } #page-nav-contents { padding: 0; margin: 0; display: block; top: 0; left: 0; height: 100%; width: 100%; position: absolute; overflow: auto; scrollbar-width: thin; -webkit-overflow-scrolling : touch; /* iOS 5+ */ } ul.page-outline, ul.page-outline ul { text-indent: 0; list-style: none outside none; padding: 0 0 0 4px; } ul.page-outline { margin: 0 4px 4px 6px; } ul.page-outline div.item { font: 12px var(--font-family-nav); line-height: 22px; } ul.page-outline li { white-space: nowrap; } ul.page-outline li.vis { background-color: var(--nav-breadcrumb-active-bg); } #container.resizing { cursor: col-resize; user-select: none; } fuse-3.18.3/doc/html/clipboard.js0000644000175000017500000000557215250106404015532 0ustar berndbernd/** The code below is based on the Doxygen Awesome project, see https://github.com/jothepro/doxygen-awesome-css MIT License Copyright (c) 2021 - 2022 jothepro Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ let clipboard_title = "Copy to clipboard" let clipboard_icon = `` let clipboard_successIcon = `` let clipboard_successDuration = 1000 $(function() { if(navigator.clipboard) { const fragments = document.getElementsByClassName("fragment") for(const fragment of fragments) { const clipboard_div = document.createElement("div") clipboard_div.classList.add("clipboard") clipboard_div.innerHTML = clipboard_icon clipboard_div.title = clipboard_title $(clipboard_div).click(function() { const content = this.parentNode.cloneNode(true) // filter out line number and folded fragments from file listings content.querySelectorAll(".lineno, .ttc, .foldclosed").forEach((node) => { node.remove() }) let text = content.textContent // remove trailing newlines and trailing spaces from empty lines text = text.replace(/^\s*\n/gm,'\n').replace(/\n*$/,'') navigator.clipboard.writeText(text); this.classList.add("success") this.innerHTML = clipboard_successIcon window.setTimeout(() => { // switch back to normal icon after timeout this.classList.remove("success") this.innerHTML = clipboard_icon }, clipboard_successDuration); }) fragment.insertBefore(clipboard_div, fragment.firstChild) } } }) fuse-3.18.3/doc/html/dynsections.js0000644000175000017500000001755115250106404016135 0ustar berndbernd/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ function toggleVisibility(linkObj) { return dynsection.toggleVisibility(linkObj); } let dynsection = { // helper function updateStripes : function() { $('table.directory tr'). removeClass('even').filter(':visible:even').addClass('even'); $('table.directory tr'). removeClass('odd').filter(':visible:odd').addClass('odd'); }, toggleVisibility : function(linkObj) { const base = $(linkObj).attr('id'); const summary = $('#'+base+'-summary'); const content = $('#'+base+'-content'); const trigger = $('#'+base+'-trigger'); const src=$(trigger).attr('src'); if (content.is(':visible')===true) { content.slideUp('fast'); summary.show(); $(linkObj).find('.arrowhead').addClass('closed').removeClass('opened'); } else { content.slideDown('fast'); summary.hide(); $(linkObj).find('.arrowhead').removeClass('closed').addClass('opened'); } return false; }, toggleLevel : function(level) { $('table.directory tr').each(function() { const l = this.id.split('_').length-1; const i = $('#img'+this.id.substring(3)); const a = $('#arr'+this.id.substring(3)); if (l'); // add vertical lines to other rows $('span[class=lineno]').not(':eq(0)').append(''); // add toggle controls to lines with fold divs $('div[class=foldopen]').each(function() { // extract specific id to use const id = $(this).attr('id').replace('foldopen',''); // extract start and end foldable fragment attributes const start = $(this).attr('data-start'); const end = $(this).attr('data-end'); // replace normal fold span with controls for the first line of a foldable fragment $(this).find('span[class=fold]:first').replaceWith(''); // append div for folded (closed) representation $(this).after(''); // extract the first line from the "open" section to represent closed content const line = $(this).children().first().clone(); // remove any glow that might still be active on the original line $(line).removeClass('glow'); if (start) { // if line already ends with a start marker (e.g. trailing {), remove it $(line).html($(line).html().replace(new RegExp('\\s*'+start+'\\s*$','g'),'')); } // replace minus with plus symbol $(line).find('span[class=fold]').addClass('plus').removeClass('minus'); // append ellipsis $(line).append(' '+start+'…'+end); // insert constructed line into closed div $('#foldclosed'+id).html(line); }); }, }; /* @license-end */ $(function() { $('.code,.codeRef').each(function() { $(this).data('powertip',$('#a'+$(this).attr('href').replace(/.*\//,'').replace(/[^a-z_A-Z0-9]/g,'_')).html()); $.fn.powerTip.smartPlacementLists.s = [ 's', 'n', 'ne', 'se' ]; $(this).powerTip({ placement: 's', smartPlacement: true, mouseOnToPopup: true }); }); }); fuse-3.18.3/doc/html/doxygen.svg0000644000175000017500000003614515250106404015433 0ustar berndbernd fuse-3.18.3/doc/html/doxygen.css0000644000175000017500000015254015250106404015422 0ustar berndbernd/* The standard CSS for doxygen 1.15.0*/ html { /* page base colors */ --page-background-color: white; --page-foreground-color: black; --page-link-color: #3D578C; --page-visited-link-color: #3D578C; --page-external-link-color: #334975; /* index */ --index-odd-item-bg-color: #F8F9FC; --index-even-item-bg-color: white; --index-header-color: black; --index-separator-color: #A0A0A0; /* header */ --header-background-color: #F9FAFC; --header-separator-color: #C4CFE5; --group-header-separator-color: #D9E0EE; --group-header-color: #354C7B; --inherit-header-color: gray; --footer-foreground-color: #2A3D61; --footer-logo-width: 75px; --citation-label-color: #334975; --glow-color: cyan; --title-background-color: white; --title-separator-color: #C4CFE5; --directory-separator-color: #9CAFD4; --separator-color: #4A6AAA; --blockquote-background-color: #F7F8FB; --blockquote-border-color: #9CAFD4; --scrollbar-thumb-color: #C4CFE5; --scrollbar-background-color: #F9FAFC; --icon-background-color: #728DC1; --icon-foreground-color: white; /* --icon-doc-image: url('doc.svg'); --icon-folder-open-image: url('folderopen.svg'); --icon-folder-closed-image: url('folderclosed.svg');*/ --icon-folder-open-fill-color: #C4CFE5; --icon-folder-fill-color: #D8DFEE; --icon-folder-border-color: #4665A2; --icon-doc-fill-color: #D8DFEE; --icon-doc-border-color: #4665A2; /* brief member declaration list */ --memdecl-background-color: #F9FAFC; --memdecl-separator-color: #DEE4F0; --memdecl-foreground-color: #555; --memdecl-template-color: #4665A2; --memdecl-border-color: #D5DDEC; /* detailed member list */ --memdef-border-color: #A8B8D9; --memdef-title-background-color: #E2E8F2; --memdef-proto-background-color: #EEF1F7; --memdef-proto-text-color: #253555; --memdef-doc-background-color: white; --memdef-param-name-color: #602020; --memdef-template-color: #4665A2; /* tables */ --table-cell-border-color: #2D4068; --table-header-background-color: #374F7F; --table-header-foreground-color: #FFFFFF; /* labels */ --label-background-color: #728DC1; --label-left-top-border-color: #5373B4; --label-right-bottom-border-color: #C4CFE5; --label-foreground-color: white; /** navigation bar/tree/menu */ --nav-background-color: #F9FAFC; --nav-foreground-color: #364D7C; --nav-border-color: #C4CFE5; --nav-breadcrumb-separator-color: #C4CFE5; --nav-breadcrumb-active-bg: #EEF1F7; --nav-breadcrumb-color: #354C7B; --nav-breadcrumb-border-color: #E1E7F2; --nav-splitbar-bg-color: #DCE2EF; --nav-splitbar-handle-color: #9CAFD4; --nav-font-size-level1: 13px; --nav-font-size-level2: 10px; --nav-font-size-level3: 9px; --nav-text-normal-color: #283A5D; --nav-text-hover-color: white; --nav-text-active-color: white; --nav-menu-button-color: #364D7C; --nav-menu-background-color: white; --nav-menu-foreground-color: #555555; --nav-menu-active-bg: #DCE2EF; --nav-menu-active-color: #9CAFD4; --nav-menu-toggle-color: rgba(255, 255, 255, 0.5); --nav-arrow-color: #B6C4DF; --nav-arrow-selected-color: #90A5CE; /* sync icon */ --sync-icon-border-color: #C4CFE5; --sync-icon-background-color: #F9FAFC; --sync-icon-selected-background-color: #EEF1F7; --sync-icon-color: #C4CFE5; --sync-icon-selected-color: #6884BD; /* table of contents */ --toc-background-color: #F4F6FA; --toc-border-color: #D8DFEE; --toc-header-color: #4665A2; --toc-down-arrow-image: url("data:image/svg+xml;utf8,&%238595;"); /** search field */ --search-background-color: white; --search-foreground-color: #909090; --search-active-color: black; --search-filter-background-color: rgba(255,255,255,.7); --search-filter-backdrop-filter: blur(4px); --search-filter-foreground-color: black; --search-filter-border-color: rgba(150,150,150,.4); --search-filter-highlight-text-color: white; --search-filter-highlight-bg-color: #3D578C; --search-results-foreground-color: #425E97; --search-results-background-color: rgba(255,255,255,.8); --search-results-backdrop-filter: blur(4px); --search-results-border-color: rgba(150,150,150,.4); --search-box-border-color: #B6C4DF; --search-close-icon-bg-color: #A0A0A0; --search-close-icon-fg-color: white; /** code fragments */ --code-keyword-color: #008000; --code-type-keyword-color: #604020; --code-flow-keyword-color: #E08000; --code-comment-color: #800000; --code-preprocessor-color: #806020; --code-string-literal-color: #002080; --code-char-literal-color: #008080; --code-xml-cdata-color: black; --code-vhdl-digit-color: #FF00FF; --code-vhdl-char-color: #000000; --code-vhdl-keyword-color: #700070; --code-vhdl-logic-color: #FF0000; --code-link-color: #4665A2; --code-external-link-color: #4665A2; --fragment-foreground-color: black; --fragment-background-color: #FBFCFD; --fragment-border-color: #C4CFE5; --fragment-lineno-border-color: #00FF00; --fragment-lineno-background-color: #E8E8E8; --fragment-lineno-foreground-color: black; --fragment-lineno-link-fg-color: #4665A2; --fragment-lineno-link-bg-color: #D8D8D8; --fragment-lineno-link-hover-fg-color: #4665A2; --fragment-lineno-link-hover-bg-color: #C8C8C8; --fragment-copy-ok-color: #2EC82E; --fragment-highlight-filter: -3; --tooltip-foreground-color: black; --tooltip-background-color: rgba(255,255,255,0.8); --tooltip-arrow-background-color: white; --tooltip-border-color: rgba(150,150,150,0.7); --tooltip-backdrop-filter: blur(3px); --tooltip-doc-color: grey; --tooltip-declaration-color: #006318; --tooltip-link-color: #4665A2; --tooltip-shadow: 0 4px 8px 0 rgba(0,0,0,.25); --fold-line-color: #808080; /** font-family */ --font-family-normal: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; --font-family-monospace: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; --font-family-nav: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; --font-family-title: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; --font-family-toc: Verdana,'DejaVu Sans',Geneva,sans-serif; --font-family-search: Arial,Verdana,sans-serif; --font-family-icon: Arial,Helvetica; --font-family-tooltip: Roboto,sans-serif; /** special sections */ --warning-color-bg: #f8d1cc; --warning-color-hl: #b61825; --warning-color-text: #75070f; --note-color-bg: #faf3d8; --note-color-hl: #f3a600; --note-color-text: #5f4204; --todo-color-bg: #e4f3ff; --todo-color-hl: #1879C4; --todo-color-text: #274a5c; --test-color-bg: #e8e8ff; --test-color-hl: #3939C4; --test-color-text: #1a1a5c; --deprecated-color-bg: #ecf0f3; --deprecated-color-hl: #5b6269; --deprecated-color-text: #43454a; --bug-color-bg: #e4dafd; --bug-color-hl: #5b2bdd; --bug-color-text: #2a0d72; --invariant-color-bg: #d8f1e3; --invariant-color-hl: #44b86f; --invariant-color-text: #265532; } @media (prefers-color-scheme: dark) { html:not(.dark-mode) { color-scheme: dark; /* page base colors */ --page-background-color: black; --page-foreground-color: #C9D1D9; --page-link-color: #90A5CE; --page-visited-link-color: #90A5CE; --page-external-link-color: #A3B4D7; /* index */ --index-odd-item-bg-color: #0B101A; --index-even-item-bg-color: black; --index-header-color: #C4CFE5; --index-separator-color: #334975; /* header */ --header-background-color: #070B11; --header-separator-color: #141C2E; --group-header-separator-color: #1D2A43; --group-header-color: #90A5CE; --inherit-header-color: #A0A0A0; --footer-foreground-color: #5B7AB7; --footer-logo-width: 60px; --citation-label-color: #90A5CE; --glow-color: cyan; --title-background-color: #090D16; --title-separator-color: #212F4B; --directory-separator-color: #283A5D; --separator-color: #283A5D; --blockquote-background-color: #101826; --blockquote-border-color: #283A5D; --scrollbar-thumb-color: #2C3F65; --scrollbar-background-color: #070B11; --icon-background-color: #334975; --icon-foreground-color: #C4CFE5; --icon-folder-open-fill-color: #4665A2; --icon-folder-fill-color: #5373B4; --icon-folder-border-color: #C4CFE5; --icon-doc-fill-color: #6884BD; --icon-doc-border-color: #C4CFE5; /* brief member declaration list */ --memdecl-background-color: #0B101A; --memdecl-separator-color: #2C3F65; --memdecl-foreground-color: #BBB; --memdecl-template-color: #7C95C6; --memdecl-border-color: #233250; /* detailed member list */ --memdef-border-color: #233250; --memdef-title-background-color: #1B2840; --memdef-proto-background-color: #19243A; --memdef-proto-text-color: #9DB0D4; --memdef-doc-background-color: black; --memdef-param-name-color: #D28757; --memdef-template-color: #7C95C6; /* tables */ --table-cell-border-color: #283A5D; --table-header-background-color: #283A5D; --table-header-foreground-color: #C4CFE5; /* labels */ --label-background-color: #354C7B; --label-left-top-border-color: #4665A2; --label-right-bottom-border-color: #283A5D; --label-foreground-color: #CCCCCC; /** navigation bar/tree/menu */ --nav-background-color: #101826; --nav-foreground-color: #364D7C; --nav-border-color: #212F4B; --nav-breadcrumb-separator-color: #212F4B; --nav-breadcrumb-active-bg: #1D2A43; --nav-breadcrumb-color: #90A5CE; --nav-breadcrumb-border-color: #2A3D61; --nav-splitbar-bg-color: #283A5D; --nav-splitbar-handle-color: #4665A2; --nav-font-size-level1: 13px; --nav-font-size-level2: 10px; --nav-font-size-level3: 9px; --nav-text-normal-color: #B6C4DF; --nav-text-hover-color: #DCE2EF; --nav-text-active-color: #DCE2EF; --nav-menu-button-color: #B6C4DF; --nav-menu-background-color: #05070C; --nav-menu-foreground-color: #BBBBBB; --nav-menu-active-bg: #1D2A43; --nav-menu-active-color: #C9D3E7; --nav-menu-toggle-color: rgba(255, 255, 255, 0.2); --nav-arrow-color: #4665A2; --nav-arrow-selected-color: #6884BD; /* sync icon */ --sync-icon-border-color: #212F4B; --sync-icon-background-color: #101826; --sync-icon-selected-background-color: #1D2A43; --sync-icon-color: #4665A2; --sync-icon-selected-color: #5373B4; /* table of contents */ --toc-background-color: #151E30; --toc-border-color: #202E4A; --toc-header-color: #A3B4D7; --toc-down-arrow-image: url("data:image/svg+xml;utf8,&%238595;"); /** search field */ --search-background-color: black; --search-foreground-color: #C5C5C5; --search-active-color: #F5F5F5; --search-filter-background-color: #101826; --search-filter-foreground-color: #90A5CE; --search-filter-backdrop-filter: none; --search-filter-border-color: #7C95C6; --search-filter-highlight-text-color: #BCC9E2; --search-filter-highlight-bg-color: #283A5D; --search-results-background-color: black; --search-results-foreground-color: #90A5CE; --search-results-backdrop-filter: none; --search-results-border-color: #334975; --search-box-border-color: #334975; --search-close-icon-bg-color: #909090; --search-close-icon-fg-color: black; /** code fragments */ --code-keyword-color: #CC99CD; --code-type-keyword-color: #AB99CD; --code-flow-keyword-color: #E08000; --code-comment-color: #717790; --code-preprocessor-color: #65CABE; --code-string-literal-color: #7EC699; --code-char-literal-color: #00E0F0; --code-xml-cdata-color: #C9D1D9; --code-vhdl-digit-color: #FF00FF; --code-vhdl-char-color: #C0C0C0; --code-vhdl-keyword-color: #CF53C9; --code-vhdl-logic-color: #FF0000; --code-link-color: #79C0FF; --code-external-link-color: #79C0FF; --fragment-foreground-color: #C9D1D9; --fragment-background-color: #090D16; --fragment-border-color: #30363D; --fragment-lineno-border-color: #30363D; --fragment-lineno-background-color: black; --fragment-lineno-foreground-color: #6E7681; --fragment-lineno-link-fg-color: #6E7681; --fragment-lineno-link-bg-color: #303030; --fragment-lineno-link-hover-fg-color: #8E96A1; --fragment-lineno-link-hover-bg-color: #505050; --fragment-copy-ok-color: #0EA80E; --fragment-highlight-filter: 5; --tooltip-foreground-color: #C9D1D9; --tooltip-background-color: #202020; --tooltip-arrow-background-color: #202020; --tooltip-backdrop-filter: none; --tooltip-border-color: #C9D1D9; --tooltip-doc-color: #D9E1E9; --tooltip-declaration-color: #20C348; --tooltip-link-color: #79C0FF; --tooltip-shadow: none; --fold-line-color: #808080; /** font-family */ --font-family-normal: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; --font-family-monospace: 'JetBrains Mono',Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace,fixed; --font-family-nav: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; --font-family-title: system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; --font-family-toc: Verdana,'DejaVu Sans',Geneva,sans-serif; --font-family-search: Arial,Verdana,sans-serif; --font-family-icon: Arial,Helvetica; --font-family-tooltip: Roboto,sans-serif; /** special sections */ --warning-color-bg: #2e1917; --warning-color-hl: #ad2617; --warning-color-text: #f5b1aa; --note-color-bg: #3b2e04; --note-color-hl: #f1b602; --note-color-text: #ceb670; --todo-color-bg: #163750; --todo-color-hl: #1982D2; --todo-color-text: #dcf0fa; --test-color-bg: #121258; --test-color-hl: #4242cf; --test-color-text: #c0c0da; --deprecated-color-bg: #2e323b; --deprecated-color-hl: #738396; --deprecated-color-text: #abb0bd; --bug-color-bg: #2a2536; --bug-color-hl: #7661b3; --bug-color-text: #ae9ed6; --invariant-color-bg: #303a35; --invariant-color-hl: #76ce96; --invariant-color-text: #cceed5; }} body { background-color: var(--page-background-color); color: var(--page-foreground-color); } body, table, div, p, dl { font-weight: 400; font-size: 14px; font-family: var(--font-family-normal); line-height: 22px; } body.resizing { user-select: none; -webkit-user-select: none; } #doc-content { scrollbar-width: thin; } /* @group Heading Levels */ .title { font-family: var(--font-family-normal); line-height: 28px; font-size: 160%; font-weight: 400; margin: 10px 2px; } h1.groupheader { font-size: 150%; } h2.groupheader { box-shadow: 12px 0 var(--page-background-color), -12px 0 var(--page-background-color), 12px 1px var(--group-header-separator-color), -12px 1px var(--group-header-separator-color); color: var(--group-header-color); font-size: 150%; font-weight: normal; margin-top: 1.75em; padding-top: 8px; padding-bottom: 4px; width: 100%; } td h2.groupheader { box-shadow: 13px 0 var(--page-background-color), -13px 0 var(--page-background-color), 13px 1px var(--group-header-separator-color), -13px 1px var(--group-header-separator-color); } h3.groupheader { font-size: 100%; } h1, h2, h3, h4, h5, h6 { -webkit-transition: text-shadow 0.5s linear; -moz-transition: text-shadow 0.5s linear; -ms-transition: text-shadow 0.5s linear; -o-transition: text-shadow 0.5s linear; transition: text-shadow 0.5s linear; margin-right: 15px; } h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { text-shadow: 0 0 15px var(--glow-color); } dt { font-weight: bold; } p.startli, p.startdd { margin-top: 2px; } th p.starttd, th p.intertd, th p.endtd { font-size: 100%; font-weight: 700; } p.starttd { margin-top: 0px; } p.endli { margin-bottom: 0px; } p.enddd { margin-bottom: 4px; } p.endtd { margin-bottom: 2px; } p.interli { } p.interdd { } p.intertd { } /* @end */ caption { font-weight: bold; } span.legend { font-size: 70%; text-align: center; } h3.version { font-size: 90%; text-align: center; } div.navtab { margin-right: 6px; padding-right: 6px; text-align: right; line-height: 110%; background-color: var(--nav-background-color); } div.navtab table { border-spacing: 0; } td.navtab { padding-right: 6px; padding-left: 6px; } td.navtabHL { padding-right: 6px; padding-left: 6px; border-radius: 0 6px 6px 0; background-color: var(--nav-menu-active-bg); } div.qindex{ text-align: center; width: 100%; line-height: 140%; font-size: 130%; color: var(--index-separator-color); } #main-menu a:focus { outline: auto; z-index: 10; position: relative; } dt.alphachar{ font-size: 180%; font-weight: bold; } .alphachar a{ color: var(--index-header-color); } .alphachar a:hover, .alphachar a:visited{ text-decoration: none; } .classindex dl { padding: 25px; column-count:1 } .classindex dd { display:inline-block; margin-left: 50px; width: 90%; line-height: 1.15em; } .classindex dl.even { background-color: var(--index-even-item-bg-color); } .classindex dl.odd { background-color: var(--index-odd-item-bg-color); } @media(min-width: 1120px) { .classindex dl { column-count:2 } } @media(min-width: 1320px) { .classindex dl { column-count:3 } } /* @group Link Styling */ a { color: var(--page-link-color); font-weight: normal; text-decoration: none; } .contents a:visited { color: var(--page-visited-link-color); } span.label a:hover { text-decoration: none; background: linear-gradient(to bottom, transparent 0,transparent calc(100% - 1px), currentColor 100%); } a.el { font-weight: bold; } a.elRef { } a.el, a.el:visited, a.code, a.code:visited, a.line, a.line:visited { color: var(--page-link-color); } a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { color: var(--page-external-link-color); } a.code.hl_class { /* style for links to class names in code snippets */ } a.code.hl_struct { /* style for links to struct names in code snippets */ } a.code.hl_union { /* style for links to union names in code snippets */ } a.code.hl_interface { /* style for links to interface names in code snippets */ } a.code.hl_protocol { /* style for links to protocol names in code snippets */ } a.code.hl_category { /* style for links to category names in code snippets */ } a.code.hl_exception { /* style for links to exception names in code snippets */ } a.code.hl_service { /* style for links to service names in code snippets */ } a.code.hl_singleton { /* style for links to singleton names in code snippets */ } a.code.hl_concept { /* style for links to concept names in code snippets */ } a.code.hl_namespace { /* style for links to namespace names in code snippets */ } a.code.hl_package { /* style for links to package names in code snippets */ } a.code.hl_define { /* style for links to macro names in code snippets */ } a.code.hl_function { /* style for links to function names in code snippets */ } a.code.hl_variable { /* style for links to variable names in code snippets */ } a.code.hl_typedef { /* style for links to typedef names in code snippets */ } a.code.hl_enumvalue { /* style for links to enum value names in code snippets */ } a.code.hl_enumeration { /* style for links to enumeration names in code snippets */ } a.code.hl_signal { /* style for links to Qt signal names in code snippets */ } a.code.hl_slot { /* style for links to Qt slot names in code snippets */ } a.code.hl_friend { /* style for links to friend names in code snippets */ } a.code.hl_dcop { /* style for links to KDE3 DCOP names in code snippets */ } a.code.hl_property { /* style for links to property names in code snippets */ } a.code.hl_event { /* style for links to event names in code snippets */ } a.code.hl_sequence { /* style for links to sequence names in code snippets */ } a.code.hl_dictionary { /* style for links to dictionary names in code snippets */ } /* @end */ dl.el { margin-left: -1cm; } ul.check { list-style:none; text-indent: -16px; padding-left: 38px; } li.unchecked:before { content: "\2610\A0"; } li.checked:before { content: "\2611\A0"; } ol { text-indent: 0px; } ul { text-indent: 0px; overflow: visible; } ul.multicol { -moz-column-gap: 1em; -webkit-column-gap: 1em; column-gap: 1em; -moz-column-count: 3; -webkit-column-count: 3; column-count: 3; list-style-type: none; } #side-nav ul { overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ } #main-nav ul { overflow: visible; /* reset ul rule for the navigation bar drop down lists */ } .fragment { text-align: left; direction: ltr; overflow-x: auto; overflow-y: hidden; position: relative; min-height: 12px; margin: 10px 0px; padding: 10px 10px; border: 1px solid var(--fragment-border-color); border-radius: 4px; background-color: var(--fragment-background-color); color: var(--fragment-foreground-color); } pre.fragment { word-wrap: break-word; font-size: 10pt; line-height: 125%; font-family: var(--font-family-monospace); } span.tt { white-space: pre; font-family: var(--font-family-monospace); background-color: var(--fragment-background-color); } .clipboard { width: 24px; height: 24px; right: 5px; top: 5px; opacity: 0; position: absolute; display: inline; overflow: hidden; justify-content: center; align-items: center; cursor: pointer; } .clipboard.success { border: 1px solid var(--fragment-foreground-color); border-radius: 4px; } .fragment:hover .clipboard, .clipboard.success { opacity: .4; } .clipboard:hover, .clipboard.success { opacity: 1 !important; } .clipboard:active:not([class~=success]) svg { transform: scale(.91); } .clipboard.success svg { fill: var(--fragment-copy-ok-color); } .clipboard.success { border-color: var(--fragment-copy-ok-color); } div.line { font-family: var(--font-family-monospace); font-size: 13px; min-height: 13px; line-height: 1.2; text-wrap: wrap; word-break: break-all; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ white-space: pre-wrap; /* CSS3 */ word-wrap: break-word; /* IE 5.5+ */ text-indent: -62px; padding-left: 62px; padding-bottom: 0px; margin: 0px; -webkit-transition-property: background-color, box-shadow; -webkit-transition-duration: 0.5s; -moz-transition-property: background-color, box-shadow; -moz-transition-duration: 0.5s; -ms-transition-property: background-color, box-shadow; -ms-transition-duration: 0.5s; -o-transition-property: background-color, box-shadow; -o-transition-duration: 0.5s; transition-property: background-color, box-shadow; transition-duration: 0.5s; } div.line:after { content:"\000A"; white-space: pre; } div.line.glow { background-color: var(--glow-color); box-shadow: 0 0 10px var(--glow-color); } span.fold { display: inline-block; width: 12px; height: 12px; margin-left: 4px; margin-right: 1px; } span.foldnone { display: inline-block; position: relative; cursor: pointer; user-select: none; } span.fold.plus, span.fold.minus { width: 10px; height: 10px; background-color: var(--fragment-background-color); position: relative; border: 1px solid var(--fold-line-color); margin-right: 1px; } span.fold.plus::before, span.fold.minus::before { content: ''; position: absolute; background-color: var(--fold-line-color); } span.fold.plus::before { width: 2px; height: 6px; top: 2px; left: 4px; } span.fold.plus::after { content: ''; position: absolute; width: 6px; height: 2px; top: 4px; left: 2px; background-color: var(--fold-line-color); } span.fold.minus::before { width: 6px; height: 2px; top: 4px; left: 2px; } span.lineno { padding-right: 4px; margin-right: 9px; text-align: right; border-right: 2px solid var(--fragment-lineno-border-color); color: var(--fragment-lineno-foreground-color); background-color: var(--fragment-lineno-background-color); white-space: pre; } span.lineno a, span.lineno a:visited { color: var(--fragment-lineno-link-fg-color); background-color: var(--fragment-lineno-link-bg-color); } span.lineno a:hover { color: var(--fragment-lineno-link-hover-fg-color); background-color: var(--fragment-lineno-link-hover-bg-color); } .lineno { -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } div.classindex ul { list-style: none; padding-left: 0; } div.classindex span.ai { display: inline-block; } div.groupHeader { box-shadow: 13px 0 var(--page-background-color), -13px 0 var(--page-background-color), 13px 1px var(--group-header-separator-color), -13px 1px var(--group-header-separator-color); color: var(--group-header-color); font-size: 110%; font-weight: 500; margin-left: 0px; margin-top: 0em; margin-bottom: 6px; padding-top: 8px; padding-bottom: 4px; } div.groupText { margin-left: 16px; font-style: italic; } body { color: var(--page-foreground-color); margin: 0; } div.contents { margin-top: 10px; margin-left: 12px; margin-right: 12px; } p.formulaDsp { text-align: center; } img.dark-mode-visible { display: none; } img.light-mode-visible { display: none; } img.formulaInl, img.inline { vertical-align: middle; } div.center { text-align: center; margin-top: 0px; margin-bottom: 0px; padding: 0px; } div.center img { border: 0px; } address.footer { text-align: right; padding-right: 12px; } img.footer { border: 0px; vertical-align: middle; width: var(--footer-logo-width); } .compoundTemplParams { color: var(--memdecl-template-color); font-size: 80%; line-height: 120%; } /* @group Code Colorization */ span.keyword { color: var(--code-keyword-color); } span.keywordtype { color: var(--code-type-keyword-color); } span.keywordflow { color: var(--code-flow-keyword-color); } span.comment { color: var(--code-comment-color); } span.preprocessor { color: var(--code-preprocessor-color); } span.stringliteral { color: var(--code-string-literal-color); } span.charliteral { color: var(--code-char-literal-color); } span.xmlcdata { color: var(--code-xml-cdata-color); } span.vhdldigit { color: var(--code-vhdl-digit-color); } span.vhdlchar { color: var(--code-vhdl-char-color); } span.vhdlkeyword { color: var(--code-vhdl-keyword-color); } span.vhdllogic { color: var(--code-vhdl-logic-color); } blockquote { background-color: var(--blockquote-background-color); border-left: 2px solid var(--blockquote-border-color); margin: 0 24px 0 4px; padding: 0 12px 0 16px; } /* @end */ td.tiny { font-size: 75%; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid var(--table-cell-border-color); } th.dirtab { background-color: var(--table-header-background-color); color: var(--table-header-foreground-color); font-weight: bold; } hr { border: none; margin-top: 16px; margin-bottom: 16px; height: 1px; box-shadow: 13px 0 var(--page-background-color), -13px 0 var(--page-background-color), 13px 1px var(--group-header-separator-color), -13px 1px var(--group-header-separator-color); } hr.footer { height: 1px; } /* @group Member Descriptions */ table.memberdecls { border-spacing: 0px; padding: 0px; } .memberdecls td, .fieldtable tr { transition-property: background-color, box-shadow; transition-duration: 0.5s; } .memberdecls td.glow, .fieldtable tr.glow { background-color: var(--glow-color); box-shadow: 0 0 15px var(--glow-color); } .memberdecls tr[class^='memitem'] { font-family: var(--font-family-monospace); } .mdescLeft, .mdescRight, .memItemLeft, .memItemRight { padding-top: 2px; padding-bottom: 2px; } .memTemplParams { padding-left: 10px; padding-top: 5px; } .memItemLeft, .memItemRight, .memTemplParams { background-color: var(--memdecl-background-color); } .mdescLeft, .mdescRight { padding: 0px 8px 4px 8px; color: var(--memdecl-foreground-color); } tr[class^='memdesc'] { box-shadow: inset 0px 1px 3px 0px rgba(0,0,0,.075); } .mdescLeft { border-left: 1px solid var(--memdecl-border-color); border-bottom: 1px solid var(--memdecl-border-color); } .mdescRight { border-right: 1px solid var(--memdecl-border-color); border-bottom: 1px solid var(--memdecl-border-color); } .memTemplParams { color: var(--memdecl-template-color); white-space: nowrap; font-size: 80%; border-left: 1px solid var(--memdecl-border-color); border-right: 1px solid var(--memdecl-border-color); } td.ititle { border: 1px solid var(--memdecl-border-color); border-top-left-radius: 4px; border-top-right-radius: 4px; padding-left: 10px; } tr:not(:first-child) > td.ititle { border-top: 0; border-radius: 0; } .memItemLeft { white-space: nowrap; border-left: 1px solid var(--memdecl-border-color); border-bottom: 1px solid var(--memdecl-border-color); padding-left: 10px; transition: none; } .memItemRight { width: 100%; border-right: 1px solid var(--memdecl-border-color); border-bottom: 1px solid var(--memdecl-border-color); padding-right: 10px; transition: none; } tr.heading + tr[class^='memitem'] td.memItemLeft, tr.groupHeader + tr[class^='memitem'] td.memItemLeft, tr.inherit_header + tr[class^='memitem'] td.memItemLeft { border-top: 1px solid var(--memdecl-border-color); border-top-left-radius: 4px; } tr.heading + tr[class^='memitem'] td.memItemRight, tr.groupHeader + tr[class^='memitem'] td.memItemRight, tr.inherit_header + tr[class^='memitem'] td.memItemRight { border-top: 1px solid var(--memdecl-border-color); border-top-right-radius: 4px; } tr.heading + tr[class^='memitem'] td.memTemplParams, tr.heading + tr td.ititle, tr.groupHeader + tr[class^='memitem'] td.memTemplParams, tr.groupHeader + tr td.ititle, tr.inherit_header + tr[class^='memitem'] td.memTemplParams { border-top: 1px solid var(--memdecl-border-color); border-top-left-radius: 4px; border-top-right-radius: 4px; } table.memberdecls tr:last-child td.memItemLeft, table.memberdecls tr:last-child td.mdescLeft, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemLeft, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescLeft, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescLeft { border-bottom-left-radius: 4px; } table.memberdecls tr:last-child td.memItemRight, table.memberdecls tr:last-child td.mdescRight, table.memberdecls tr[class^='memitem']:has(+ tr.groupHeader) td.memItemRight, table.memberdecls tr[class^='memitem']:has(+ tr.inherit_header) td.memItemRight, table.memberdecls tr[class^='memdesc']:has(+ tr.groupHeader) td.mdescRight, table.memberdecls tr[class^='memdesc']:has(+ tr.inherit_header) td.mdescRight { border-bottom-right-radius: 4px; } tr.template .memItemLeft, tr.template .memItemRight { border-top: none; padding-top: 0; } /* @end */ /* @group Member Details */ /* Styles for detailed member documentation */ .memtitle { padding: 8px; border-top: 1px solid var(--memdef-border-color); border-left: 1px solid var(--memdef-border-color); border-right: 1px solid var(--memdef-border-color); border-top-right-radius: 4px; border-top-left-radius: 4px; margin-bottom: -1px; background-color: var(--memdef-proto-background-color); line-height: 1.25; font-family: var(--font-family-monospace); font-weight: 500; font-size: 16px; float:left; box-shadow: 0 10px 0 -1px var(--memdef-proto-background-color), 0 2px 8px 0 rgba(0,0,0,.075); position: relative; } .memtitle:after { content: ''; display: block; background: var(--memdef-proto-background-color); height: 10px; bottom: -10px; left: 0px; right: -14px; position: absolute; border-top-right-radius: 6px; } .permalink { font-family: var(--font-family-monospace); font-weight: 500; line-height: 1.25; font-size: 16px; display: inline-block; vertical-align: middle; } .memtemplate { font-size: 80%; color: var(--memdef-template-color); font-family: var(--font-family-monospace); font-weight: normal; margin-left: 9px; } .mempage { width: 100%; } .memitem { padding: 0; margin-bottom: 10px; margin-right: 5px; display: table !important; width: 100%; box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); border-radius: 4px; } .memitem.glow { box-shadow: 0 0 15px var(--glow-color); } .memname { font-family: var(--font-family-monospace); font-size: 13px; font-weight: 400; margin-left: 6px; } .memname td { vertical-align: bottom; } .memproto, dl.reflist dt { border-top: 1px solid var(--memdef-border-color); border-left: 1px solid var(--memdef-border-color); border-right: 1px solid var(--memdef-border-color); padding: 6px 0px 6px 0px; color: var(--memdef-proto-text-color); font-weight: bold; background-color: var(--memdef-proto-background-color); border-top-right-radius: 4px; border-bottom: 1px solid var(--memdef-border-color); } .overload { font-family: var(--font-family-monospace); font-size: 65%; } .memdoc, dl.reflist dd { border-bottom: 1px solid var(--memdef-border-color); border-left: 1px solid var(--memdef-border-color); border-right: 1px solid var(--memdef-border-color); padding: 6px 10px 2px 10px; border-top-width: 0; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; } dl.reflist dt { padding: 5px; } dl.reflist dd { margin: 0px 0px 10px 0px; padding: 5px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; padding: 0px; padding-bottom: 1px; } .paramname { white-space: nowrap; padding: 0px; padding-bottom: 1px; margin-left: 2px; } .paramname em { color: var(--memdef-param-name-color); font-style: normal; margin-right: 1px; } .paramname .paramdefval { font-family: var(--font-family-monospace); } .params, .retval, .exception, .tparams { margin-left: 0px; padding-left: 0px; } .params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { font-weight: bold; vertical-align: top; } .params .paramtype, .tparams .paramtype { font-style: italic; vertical-align: top; } .params .paramdir, .tparams .paramdir { font-family: var(--font-family-monospace); vertical-align: top; } table.mlabels { border-spacing: 0px; } td.mlabels-left { width: 100%; padding: 0px; } td.mlabels-right { vertical-align: bottom; padding: 0px; white-space: nowrap; } span.mlabels { margin-left: 8px; } span.mlabel { background-color: var(--label-background-color); border-top:1px solid var(--label-left-top-border-color); border-left:1px solid var(--label-left-top-border-color); border-right:1px solid var(--label-right-bottom-border-color); border-bottom:1px solid var(--label-right-bottom-border-color); text-shadow: none; color: var(--label-foreground-color); margin-right: 4px; padding: 2px 3px; border-radius: 3px; font-size: 7pt; white-space: nowrap; vertical-align: middle; } /* @end */ /* these are for tree view inside a (index) page */ div.directory { margin: 10px 0px; width: 100%; } .directory table { border-collapse:collapse; } .directory td { margin: 0px; padding: 0px; vertical-align: top; } .directory td.entry { white-space: nowrap; padding-right: 6px; padding-top: 3px; } .directory td.entry a { outline:none; } .directory td.entry a img { border: none; } .directory td.desc { width: 100%; padding-left: 6px; padding-right: 6px; padding-top: 3px; border-left: 1px solid rgba(0,0,0,0.05); } .directory tr.odd { padding-left: 6px; background-color: var(--index-odd-item-bg-color); } .directory tr.even { padding-left: 6px; background-color: var(--index-even-item-bg-color); } .directory img { vertical-align: -30%; } .directory .levels { white-space: nowrap; width: 100%; text-align: right; font-size: 9pt; } .directory .levels span { cursor: pointer; padding-left: 2px; padding-right: 2px; color: var(--page-link-color); } .arrow { color: var(--nav-background-color); -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; cursor: pointer; font-size: 80%; display: inline-block; width: 16px; height: 14px; transition: opacity 0.3s ease; } span.arrowhead { position: relative; padding: 0; margin: 0 0 0 2px; display: inline-block; width: 5px; height: 5px; border-right: 2px solid var(--nav-arrow-color); border-bottom: 2px solid var(--nav-arrow-color); transform: rotate(-45deg); transition: transform 0.3s ease; } span.arrowhead.opened { transform: rotate(45deg); } .selected span.arrowhead { border-right: 2px solid var(--nav-arrow-selected-color); border-bottom: 2px solid var(--nav-arrow-selected-color); } .icon { font-family: var(--font-family-icon); line-height: normal; font-weight: bold; font-size: 12px; height: 14px; width: 16px; display: inline-block; background-color: var(--icon-background-color); color: var(--icon-foreground-color); text-align: center; border-radius: 4px; margin-left: 2px; margin-right: 2px; } .icona { width: 24px; height: 22px; display: inline-block; } .iconfolder { width: 24px; height: 18px; margin-top: 6px; vertical-align:top; display: inline-block; position: relative; } .icondoc { width: 24px; height: 18px; margin-top: 3px; vertical-align:top; display: inline-block; position: relative; } .folder-icon { width: 16px; height: 11px; background-color: var(--icon-folder-fill-color); border: 1px solid var(--icon-folder-border-color); border-radius: 0 2px 2px 2px; position: relative; box-sizing: content-box; } .folder-icon::after { content: ''; position: absolute; top: 2px; left: -1px; width: 16px; height: 7px; background-color: var(--icon-folder-open-fill-color); border: 1px solid var(--icon-folder-border-color); border-radius: 7px 7px 2px 2px; transform-origin: top left; opacity: 0; transition: all 0.3s linear; } .folder-icon::before { content: ''; position: absolute; top: -3px; left: -1px; width: 6px; height: 2px; background-color: var(--icon-folder-fill-color); border-top: 1px solid var(--icon-folder-border-color); border-left: 1px solid var(--icon-folder-border-color); border-right: 1px solid var(--icon-folder-border-color); border-radius: 2px 2px 0 0; } .folder-icon.open::after { top: 3px; opacity: 1; } .doc-icon { left: 6px; width: 12px; height: 16px; background-color: var(--icon-doc-border-color); clip-path: polygon(0 0, 66% 0, 100% 25%, 100% 100%, 0 100%); position: relative; display: inline-block; } .doc-icon::before { content: ""; left: 1px; top: 1px; width: 10px; height: 14px; background-color: var(--icon-doc-fill-color); clip-path: polygon(0 0, 66% 0, 100% 25%, 100% 100%, 0 100%); position: absolute; box-sizing: border-box; } .doc-icon::after { content: ""; left: 7px; top: 0px; width: 3px; height: 3px; background-color: transparent; position: absolute; border: 1px solid var(--icon-doc-border-color); } /* @end */ div.dynheader { margin-top: 8px; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } span.dynarrow { position: relative; display: inline-block; width: 12px; bottom: 1px; } address { font-style: normal; color: var(--footer-foreground-color); } table.doxtable caption { caption-side: top; } table.doxtable { border-collapse:collapse; margin-top: 4px; margin-bottom: 4px; } table.doxtable td, table.doxtable th { border: 1px solid var(--table-cell-border-color); padding: 3px 7px 2px; } table.doxtable th { background-color: var(--table-header-background-color); color: var(--table-header-foreground-color); font-size: 110%; padding-bottom: 4px; padding-top: 5px; } table.fieldtable { margin-bottom: 10px; border: 1px solid var(--memdef-border-color); border-spacing: 0px; border-radius: 4px; box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } .fieldtable td, .fieldtable th { padding: 3px 7px 2px; } .fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fieldinit { white-space: nowrap; border-right: 1px solid var(--memdef-border-color); border-bottom: 1px solid var(--memdef-border-color); vertical-align: top; } .fieldtable td.fieldname { padding-top: 3px; } .fieldtable td.fieldinit { padding-top: 3px; text-align: right; } .fieldtable td.fielddoc { border-bottom: 1px solid var(--memdef-border-color); } .fieldtable td.fielddoc p:first-child { margin-top: 0px; } .fieldtable td.fielddoc p:last-child { margin-bottom: 2px; } .fieldtable tr:last-child td { border-bottom: none; } .fieldtable th { background-color: var(--memdef-title-background-color); font-size: 90%; color: var(--memdef-proto-text-color); padding-bottom: 4px; padding-top: 5px; text-align:left; font-weight: 400; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid var(--memdef-border-color); } /* ----------- navigation breadcrumb styling ----------- */ #nav-path ul { height: 30px; line-height: 30px; color: var(--nav-text-normal-color); overflow: hidden; margin: 0px; padding-left: 4px; background-image: none; background: var(--page-background-color); border-bottom: 1px solid var(--nav-breadcrumb-separator-color); font-size: var(--nav-font-size-level1); font-family: var(--font-family-nav); position: relative; z-index: 100; } #main-nav { border-bottom: 1px solid var(--nav-border-color); } .navpath li { list-style-type:none; float:left; color: var(--nav-foreground-color); } .navpath li.footer { list-style-type:none; float:right; padding-left:10px; padding-right:15px; background-image:none; background-repeat:no-repeat; background-position:right; font-size: 8pt; color: var(--footer-foreground-color); } #nav-path li.navelem { background-image: none; display: flex; align-items: center; padding-left: 15px; } .navpath li.navelem a { text-shadow: none; display: inline-block; color: var(--nav-breadcrumb-color); position: relative; top: 0px; height: 30px; margin-right: -20px; } #nav-path li.navelem:after { content: ''; display: inline-block; position: relative; top: 0; right: -15px; width: 30px; height: 30px; transform: scaleX(0.5) scale(0.707) rotate(45deg); z-index: 10; background: var(--page-background-color); box-shadow: 2px -2px 0 2px var(--nav-breadcrumb-separator-color); border-radius: 0 5px 0 50px; } #nav-path li.navelem:first-child { margin-left: -6px; } #nav-path li.navelem:hover, #nav-path li.navelem:hover:after { background-color: var(--nav-breadcrumb-active-bg); } /* ---------------------- */ div.summary { float: right; font-size: 8pt; padding-right: 5px; width: 50%; text-align: right; } div.summary a { white-space: nowrap; } table.classindex { margin: 10px; white-space: nowrap; margin-left: 3%; margin-right: 3%; width: 94%; border: 0; border-spacing: 0; padding: 0; } div.ingroups { font-size: 8pt; width: 50%; text-align: left; } div.ingroups a { white-space: nowrap; } div.header { margin: 0px; background-color: var(--header-background-color); border-bottom: 1px solid var(--header-separator-color); } div.headertitle { padding: 5px 5px 5px 10px; } dl { padding: 0 0 0 0; } dl.bug dt a, dl.deprecated dt a, dl.todo dt a, dl.test a { font-weight: bold !important; } dl.warning, dl.attention, dl.important, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.test, dl.remark { padding: 10px; margin: 10px 0px; overflow: hidden; margin-left: 0; border-radius: 4px; } dl.section dd { margin-bottom: 2px; } dl.warning, dl.attention, dl.important { background: var(--warning-color-bg); border-left: 8px solid var(--warning-color-hl); color: var(--warning-color-text); } dl.warning dt, dl.attention dt, dl.important dt { color: var(--warning-color-hl); } dl.warning .tt, dl.attention .tt, dl.important .tt { background-color: hsl(from var(--warning-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.note, dl.remark { background: var(--note-color-bg); border-left: 8px solid var(--note-color-hl); color: var(--note-color-text); } dl.note dt, dl.remark dt { color: var(--note-color-hl); } dl.note .tt, dl.remark .tt { background-color: hsl(from var(--note-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.todo { background: var(--todo-color-bg); border-left: 8px solid var(--todo-color-hl); color: var(--todo-color-text); } dl.todo dt { color: var(--todo-color-hl); } dl.todo .tt { background-color: hsl(from var(--todo-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.test { background: var(--test-color-bg); border-left: 8px solid var(--test-color-hl); color: var(--test-color-text); } dl.test dt { color: var(--test-color-hl); } dl.test .tt { background-color: hsl(from var(--test-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.bug dt a { color: var(--bug-color-hl) !important; } dl.bug { background: var(--bug-color-bg); border-left: 8px solid var(--bug-color-hl); color: var(--bug-color-text); } dl.bug dt a { color: var(--bug-color-hl) !important; } dl.bug .tt { background-color: hsl(from var(--bug-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.deprecated { background: var(--deprecated-color-bg); border-left: 8px solid var(--deprecated-color-hl); color: var(--deprecated-color-text); } dl.deprecated dt a { color: var(--deprecated-color-hl) !important; } dl.deprecated .tt { background-color: hsl(from var(--deprecated-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.invariant, dl.pre, dl.post { background: var(--invariant-color-bg); border-left: 8px solid var(--invariant-color-hl); color: var(--invariant-color-text); } dl.invariant dt, dl.pre dt, dl.post dt { color: var(--invariant-color-hl); } dl.invariant .tt, dl.pre .tt, dl.post .tt { background-color: hsl(from var(--invariant-color-bg) h s calc(l + var(--fragment-highlight-filter))); } dl.note dd, dl.warning dd, dl.pre dd, dl.post dd, dl.remark dd, dl.attention dd, dl.important dd, dl.invariant dd, dl.bug dd, dl.deprecated dd, dl.todo dd, dl.test dd { margin-inline-start: 0px; } #projectrow { height: 56px; } #projectlogo { text-align: center; vertical-align: bottom; border-collapse: separate; } #projectlogo img { border: 0px none; } #projectalign { vertical-align: middle; padding-left: 0.5em; } #projectname { font-size: 200%; font-family: var(--font-family-title); margin: 0; padding: 0; } #side-nav #projectname { font-size: 130%; } #projectbrief { font-size: 90%; font-family: var(--font-family-title); margin: 0px; padding: 0px; } #projectnumber { font-size: 50%; font-family: var(--font-family-title); margin: 0px; padding: 0px; } #titlearea { padding: 0 0 0 5px; margin: 0px; border-bottom: 1px solid var(--title-separator-color); background-color: var(--title-background-color); } .image { text-align: center; } .dotgraph { text-align: center; } .mscgraph { text-align: center; } .plantumlgraph { text-align: center; } .diagraph { text-align: center; } .caption { font-weight: bold; } dl.citelist { margin-bottom:50px; } dl.citelist dt { color:var(--citation-label-color); float:left; font-weight:bold; margin-right:10px; padding:5px; text-align:right; width:52px; } dl.citelist dd { margin:2px 0 2px 72px; padding:5px 0; } div.toc { padding: 14px 25px; background-color: var(--toc-background-color); border: 1px solid var(--toc-border-color); border-radius: 7px 7px 7px 7px; float: right; height: auto; margin: 0 8px 10px 10px; width: 200px; } div.toc li { background: var(--toc-down-arrow-image) no-repeat scroll 0 5px transparent; font: 10px/1.2 var(--font-family-toc); margin-top: 5px; padding-left: 10px; padding-top: 2px; } div.toc h3 { font: bold 12px/1.2 var(--font-family-toc); color: var(--toc-header-color); border-bottom: 0 none; margin: 0; } div.toc ul { list-style: none outside none; border: medium none; padding: 0px; } div.toc li[class^='level'] { margin-left: 15px; } div.toc li.level1 { margin-left: 0px; } div.toc li.empty { background-image: none; margin-top: 0px; } span.emoji { /* font family used at the site: https://unicode.org/emoji/charts/full-emoji-list.html * font-family: "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus, Code2000, Code2001, Code2002, Musica, serif, LastResort; */ } span.obfuscator { display: none; } .inherit_header { font-weight: 400; cursor: pointer; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } .inherit_header td { padding: 6px 0 2px 0; } .inherit { display: none; } tr.heading h2 { margin-top: 12px; margin-bottom: 12px; } /* tooltip related style info */ .ttc { position: absolute; display: none; } #powerTip { cursor: default; color: var(--tooltip-foreground-color); background-color: var(--tooltip-background-color); backdrop-filter: var(--tooltip-backdrop-filter); -webkit-backdrop-filter: var(--tooltip-backdrop-filter); border: 1px solid var(--tooltip-border-color); border-radius: 4px; box-shadow: var(--tooltip-shadow); display: none; font-size: smaller; max-width: 80%; padding: 1ex 1em 1em; position: absolute; z-index: 2147483647; } #powerTip div.ttdoc { color: var(--tooltip-doc-color); font-style: italic; } #powerTip div.ttname a { font-weight: bold; } #powerTip a { color: var(--tooltip-link-color); } #powerTip div.ttname { font-weight: bold; } #powerTip div.ttdeci { color: var(--tooltip-declaration-color); } #powerTip div { margin: 0px; padding: 0px; font-size: 12px; font-family: var(--font-family-tooltip); line-height: 16px; } #powerTip:before, #powerTip:after { content: ""; position: absolute; margin: 0px; } #powerTip.n:after, #powerTip.n:before, #powerTip.s:after, #powerTip.s:before, #powerTip.w:after, #powerTip.w:before, #powerTip.e:after, #powerTip.e:before, #powerTip.ne:after, #powerTip.ne:before, #powerTip.se:after, #powerTip.se:before, #powerTip.nw:after, #powerTip.nw:before, #powerTip.sw:after, #powerTip.sw:before { border: solid transparent; content: " "; height: 0; width: 0; position: absolute; } #powerTip.n:after, #powerTip.s:after, #powerTip.w:after, #powerTip.e:after, #powerTip.nw:after, #powerTip.ne:after, #powerTip.sw:after, #powerTip.se:after { border-color: rgba(255, 255, 255, 0); } #powerTip.n:before, #powerTip.s:before, #powerTip.w:before, #powerTip.e:before, #powerTip.nw:before, #powerTip.ne:before, #powerTip.sw:before, #powerTip.se:before { border-color: rgba(128, 128, 128, 0); } #powerTip.n:after, #powerTip.n:before, #powerTip.ne:after, #powerTip.ne:before, #powerTip.nw:after, #powerTip.nw:before { top: 100%; } #powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { border-top-color: var(--tooltip-arrow-background-color); border-width: 10px; margin: 0px -10px; } #powerTip.n:before, #powerTip.ne:before, #powerTip.nw:before { border-top-color: var(--tooltip-border-color); border-width: 11px; margin: 0px -11px; } #powerTip.n:after, #powerTip.n:before { left: 50%; } #powerTip.nw:after, #powerTip.nw:before { right: 14px; } #powerTip.ne:after, #powerTip.ne:before { left: 14px; } #powerTip.s:after, #powerTip.s:before, #powerTip.se:after, #powerTip.se:before, #powerTip.sw:after, #powerTip.sw:before { bottom: 100%; } #powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { border-bottom-color: var(--tooltip-arrow-background-color); border-width: 10px; margin: 0px -10px; } #powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { border-bottom-color: var(--tooltip-border-color); border-width: 11px; margin: 0px -11px; } #powerTip.s:after, #powerTip.s:before { left: 50%; } #powerTip.sw:after, #powerTip.sw:before { right: 14px; } #powerTip.se:after, #powerTip.se:before { left: 14px; } #powerTip.e:after, #powerTip.e:before { left: 100%; } #powerTip.e:after { border-left-color: var(--tooltip-border-color); border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.e:before { border-left-color: var(--tooltip-border-color); border-width: 11px; top: 50%; margin-top: -11px; } #powerTip.w:after, #powerTip.w:before { right: 100%; } #powerTip.w:after { border-right-color: var(--tooltip-border-color); border-width: 10px; top: 50%; margin-top: -10px; } #powerTip.w:before { border-right-color: var(--tooltip-border-color); border-width: 11px; top: 50%; margin-top: -11px; } @media print { #top { display: none; } #side-nav { display: none; } #nav-path { display: none; } body { overflow:visible; } h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } .summary { display: none; } .memitem { page-break-inside: avoid; } #doc-content { margin-left:0 !important; height:auto !important; width:auto !important; overflow:inherit; display:inline; } } /* @group Markdown */ table.markdownTable { border-collapse:collapse; margin-top: 4px; margin-bottom: 4px; } table.markdownTable td, table.markdownTable th { border: 1px solid var(--table-cell-border-color); padding: 3px 7px 2px; } table.markdownTable tr { } th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { background-color: var(--table-header-background-color); color: var(--table-header-foreground-color); font-size: 110%; padding-bottom: 4px; padding-top: 5px; } th.markdownTableHeadLeft, td.markdownTableBodyLeft { text-align: left } th.markdownTableHeadRight, td.markdownTableBodyRight { text-align: right } th.markdownTableHeadCenter, td.markdownTableBodyCenter { text-align: center } tt, code, kbd { display: inline-block; } tt, code, kbd { vertical-align: top; } /* @end */ u { text-decoration: underline; } details>summary { list-style-type: none; } details > summary::-webkit-details-marker { display: none; } details>summary::before { content: "\25ba"; padding-right:4px; font-size: 80%; } details[open]>summary::before { content: "\25bc"; padding-right:4px; font-size: 80%; } :root { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb-color) var(--scrollbar-background-color); } ::-webkit-scrollbar { background-color: var(--scrollbar-background-color); height: 12px; width: 12px; } ::-webkit-scrollbar-thumb { border-radius: 6px; box-shadow: inset 0 0 12px 12px var(--scrollbar-thumb-color); border: solid 2px transparent; } ::-webkit-scrollbar-corner { background-color: var(--scrollbar-background-color); } fuse-3.18.3/doc/html/fast17-vangoor.pdf0000644000175000017500000222216515250106404016507 0ustar berndbernd%PDF-1.5 %âãÏÓ 2 0 obj <>stream xœ¬·ctem·&ÛvvlÛv*¶mÛ¬˜Û¶m;ÛNÅvºž÷íÓ§ÇùúûÓ}~¬1Ö=qM\óž{/2"e:!{#Sq{;:&zFn€œ¥­‘«³²¡�,�’©¹+à¯� †ŒLÄÉÔÐÅÒÞNÔÐÅ” nj5503˜¸¸¸`È"öžN–æ.JU%u*Úÿ”üc0òüÍ_OgKs;ùß7S{[S;—¿ÿ׎ʦ¦ S€™¥�)@D^ASJN@)!§ �0µ3u2´(¸ÙXd-�MíœM©föN›Æöv&–ÿ”æLÿKÈ`pv05¶üëfêalêð�Šà`êdkéìü÷`é 0w2´sùÛ{€¥�±�«É? ü•›Ùÿ+!'û¿¶uÁì�]œ��,\£*ˆŠÿ;O C—b;[þUìÍþZšØ»þSÒ¿taþj] -íœ.¦.ÿÄ22˜X:;Øzþ�ýÌÁÉò_i¸:[Ú™ÿg´'SsC'Sgç¿0±ÿéÎÖ øßª7tp°ñü—·ý¿¬þW–.Φ6fô0LÌc»ü�mniÃðÏ HÙ™Ù˜ÿ-7quø�›©Ó¿DùÏÌPýMÂÐÄÞÎÆ`bjà gïò7$€òÿŽeúÿ>’ÿ(þo!ø¿…Þÿ7rÿ+GÿÛ%þ½ÏÿZÜÕÆFÎÐöïü{Áþng€,àŸccèôÿ17´µ´ñü?8üWCuÓ'ùÿƒ#åbø·Bvæ a¤gü·ÐÒYÜÒÃÔDÁÒÅØ`fhó·Sÿ’«Ú™˜:ÙXÚ™þeô_ÍÐ1±1ý�Š…¥±µÝ?­gû7œ©�ÉMþ/IÿJ�á¿.Ó©þ’î¢âéð7£ÿYÃ{“ÿuøÇYXØÞàMÇÄÁ  cædû{×™\l,¾ÿ‡@ÿbúÏóC'K€ößjÿ:ýSóÿ|þó¤û_`ÄìŒíMþeC;“¿“õ¿ÿ³tKGWS)Ñ¿33r12ÿKjìêäô—æ­€¿ø�ó¿&ßÔÔÃÔþ,zÅ p€öûuÓ2ƒxP[›íÒª€-qÔVe¢S/‰æyyëç­™L„e–K“Óvn¬í+ÙÓÐØÙíWÓFyø%õö7 Ͷ�vì¹Ü–™�<шô0q÷‡�*Èëàý‘&  q�7óír~1'¢¢£Œy_‚þW�³b6–E �hÓ®‹{2Ÿ'#U¶µö¼¦î¸tÄLàêÊ‹ÒwÖ¦.®f´%*þ�¶�x¾m$ ¿�1�‹m¬Ô"›l:·[ž,©MÑFUZ÷œ3ñÌí6À0ñ8Iyícô ­t(‹'QPÑXÊK¶ìsÿœÝZÂó¨´û®>¯ö´°Q+ÞÌ8Dó²£¹–Q�PÇ$suv—8xõ¼êãrJ$Pæ“$àf-¡‹{²ðÞòËÅ9Â\¨ Ûb÷·ƒôüØ#¸i÷a …¿·cò@»ÿ`=ÅÂ-p\Ê‹ÆëÅÙA‚4/s ²k|ê…¾ “ä:›DXPpµ}±cCµÐ�Õé™ìÇÖ.} ßë4“àŸð„ Wn›L¹.î¸ÕÑ­¨ÚR{u”ðN0ûaùŸTƒÃ^àQä‰Èîf:]JÎJ÷m_KrÑó‘úÚaˆÇð&4ÅWX¶T;f1¹þQ5¬y&Rƒ¶¬FQƒ¾'‘TwG#žÕwj%b(�ç1Ú0/AÀ"„Líð48¿‚ü/åÏ<«Ò‘x;1¸ ᎋX�·Ìf‹òmX‘Œ;f—Z´Z¨¶U�¶ Ÿ…Ûu¦=‡Äì$‰JÓ6¾ƒ¥ÄXÿx´‹!pbw¬wi“Ý|­JÂ5N!-gQÁVdžÙ˜üuÆìñbîÂñ¬¸iS€û,þä`ÁzxˆBb•ÿØÜà9F èdµÔ áû¬ª^È쫯|‘,Ö ý2õµpm‰ó™n[‹ñi¾×,x( ¿)C[ñåãõ6o“nìD.vˆ`©àÿ†�Úêw¥ŽÌÊ•½Ç¯�M­úí…{ûn3²:¥.`>aV¬÷Çùãã+A5²•›óú{oyaÒÈîÔ!bJ¸øs¦q‹Gvù}78'îÓdoh„Ð(‚søÂcø>ƒF[”ZÐdH|íç¼==ÆrÌ/g}¡[ë0%tܸ,�ü@$#e-óÜay÷ �e= ¼¼]yC¾i¼&Ä<®Á)İŸ>Â*›…¬ŽZ1m¦<©�ïxºÛÁ#¦®5~W�Êã¶â ’G‡6qUÄôkß­S%^@@¢MRØžúl経é€3výaþj’·l/æÙ¤lå8ä•Á]ûSÚ Þèû²ÑÉà´: ÷Šq˜f�\2ÒïVóÙ†çðS ßc]°»Cµ3@J`Ù&_¥Dþ� l"Ñ­ ëÕø�zM´•̳zNU,R¯M@Ö£ô‰;-rfx��F¨â»÷\�½¸E~X—„w¿@#‰¾"±‚�™ðæÐ� ˜�t A_Œò�³&,„Ó1¶:õ¥džâñ ·zXZ=±£ßÓÌoq6ò ‘÷t+™Gˆ+5¿U®ÎÇâ!§öûÛ3ã^TÙ¦82·Æ‡1ŽU(X5ý0ÐÏ­‹æôyh͆¥¼T´%®hygïr!„´M݈¦ì?o¤›,» m\ÈÖ¯{3>Zm=%®_Øòª[ÝL¯æ]Báx`\ G1+À“—®µŠ©§Æqì$!¡ê`Vkç�d"¶@Ù•³“>Ô¶î…<—O#2xqŠÕ)uB]¥µUqãû‡rù”nÊH)Þƒƒq"”uîGy4ºø¶syÀ€³v)>®”£¯,DJÂ^�ëC +‘–Eò=Ì©`š9p@�( rÞé¥vJ Fg…3Æå+wS¶®0)±Mg’2šK �Ιþ÷ªãt†=çBy¾ÞÁ`ßËŸ)M¦ô¤uyU¥×:…ª�¦Ütâ ½gÔ–D‰ÁÕÖy 6Ò3g�¤œŠ4µ—-Æ?m�Cb'1ßð‡h3Hv— !uÄt *Ç›N,9Uãt†Þ�á–l»qp¡]:” @z\\M'gö@¦LŠ$Š]îÍU�Gu<}O;!n¯i´7.yæYÒTUá§‚�láŒaü 'É2˜úX¶¹þÒD *1©äa\ïwU�hM¬0Mºt"àÒ°@æŽïìµ¼O’Om�LBÏÅ‚Æ<ÍZ¢h™ šôlq± ±ÛA4 X |Âæ£m¤ ¾Ÿcå—,ŸÚ5a‡¼ˆÓÁ­ãË*)ü^˜.«gNcŸ24»#º§�|ç ¦.¹™åɆO}¾ý–€®ŸS xkLÊŸ”¦üvŸÈ¹xÈ, Є·€ÓKŸ3£àJAÓó]•/,}A÷"�+¹*/Ðßb.b �xº0{ƒuò©qÛ¶¥•È÷$û1˜QŒáØKÈ?1a–ý X·�C=ñÁADñÄ‹¤íé¹Ç˜$Oᶤ­åJ�`ä‡VjågæqéM•!Án+fælŒ‹é÷LتUV%O\èø¸ÅEtN@Åœî¼.ªâ§~‘àcàEBâF«¨vb™-WHßË=ì•H1w'/78ejao >õ—a´=LVHÉ¢ šÃSÑo'ÜE…‚;à F´éˆØ ¥]½û€ä˜:©^ÄK¼„ ˜ÓSJx»|š"ä¼½šÝb¢� ãA$MeçJÕù ’yžŸ¹&îð>ɶQÀä9.¸†ß;“fsØj× ø@Pë�†Ã©#þ™ˆ·Ayêb¿UµÊçôZŠ4óhr\«atéI,}‡iá|«I%ã D—juhéa+¢ß²,w®:×h¨wåx •wEGBòHº‰Ït$,'|¶‹SÓÙ"ø\>EŽAn�Þ”F �n�D’ïá{å�ë"Æ.Û®}µýô#c´f—¦ã¤g<¸H¤Ù'TXÓ³¡_iË�§bç®»Wä±D5<îøWyßùLœûJÍö•L—SïåÎqG,A;—Tv�­§¥1ûFd@r#åŸ�cŽyûkÝcó¸Þ­«aB#Él ¾»Ó¨¡s(gÀ^ÆoðëL‡‹µtÀ#\¬ éAÉïdX‚|KÐyÄa¡Á š�öŠÇ‘U„/)«ì-ˆkÐÒ;âà0+{A]6Á…#Û“\ÊWÉ€„³ÄG*{›ø6¤‡”v$; ‚Ûs!u3Ô#¹.YÄ9�ä._VGžçveƒ›gSÁ°YYô¿ÎrÝ%g•޼µ`¼²!TUTt¿(»5nRè$_éGŠs\‹ÁnzÎ}jç•ð@.Éð…á1…(Êès‘OK¼LOcÍA¹»·îÃsÆs˜*{hm\‚)öáO%´…/‰~†•¶5åf߯9;²bw�Q´¯ÕVZ Ù+FÁ(ò ›³¿@sî—ú*VL$¶Ù–˜(¢C<¾ŠíB$YOæL1¿bö°�Í`5°|÷ƒvòè*�ÌzþnHã½"úÖ�È:ÑE­×,5&¯”¢2ϹE^R9ô¾øÙþ´;±F+4€7ûidP¯¿š‡'x·¦Nƶ¤Mè>®Á^W\Ií}éƒ ¹õ(ÍS~1äÖLdñ 2ŸŒR#К ¯ aL:uÚ´ Ì =y±ˆT3*¦ï‹ø{ݸÃjpëµ¶l~­Æ®ƒ?oz&ÕyâÒZ£ÙqœñÙvQ‡0¼gŒB5‹ v@p¯›JûDÿCP�òÕØqNu\¸ªØuƒW(�ü̬–%þà}ŠËàZo¯(Ë:TÛõœ¸â b6õ²÷h²œbØ(M).ÔÊþcÍ÷¢<ú.Oh‡�Œh裗ƒÑbpÐ) �A!ùó`ƒE]‡\-Km;z#O U#rg|9ƒÇÄ©*âgÑçc¶Ž¯�)BWøã»Ö³s¸|O7è2 Už[-P¢ÚvËŒ¾Š²VýÞ§smÓ[].{�&ß—îL•ÏEìeÅ]á»1¬p e) ¿3sÜQ;w˜Ï£PWÝB“CI¸IðpE+ñþ¥ Ç!éèÇtøò¯ÚIEÑ%!�Ä0s¥XŠDP[ã{ÃLª¶R™¹ÑŒGýóW¦æõÈл¼µ) %ñ˨£ÉM’}Ö픂yyËäÔÞ¤ç͵9)UOË�çöÒaT>Ôù§T ÙEýí?Ø\¼Ç–ö‡³ô.οIcDŸ1>$ùå\xÕ|2U.z:Ä7-Øp„p?ŠJ²»T‹K‘šŠ˜íàcäLbÛÌ�EºË �Xõ¯_T4é%ÙŽQ2[TgÐ� Vã’¾,ì‘êqÔ Ä £õƒúɳäi˜0 ¿¶á «Æ)<Ö‚Ö¿'"r¶LŠ€öŽ \ 7^ñm¸9?]&ìzT´/@úÅ.¼fp#ÁdV¶ 9úvü:(íä• ŒË”¨xûò`ç2UY:ôj]'Ô¿üÌÈûÉAÕô°À1eª&º¼uX¨>zW“æÖKËPÖUë ÿ€µnäZÀ‘])†ó¢5ךi£V[£#ÿÜÐÏkð‹ÕóMÆè>? [4gðæ"ß>¼Œ¯MÀ0‚êqF~Y¡Ètbùø:wU|øå¸-¬9»ZpA�·Q~©' i QÈØ †EȲz³·�÷Ò9ðÉo[³ÝB}á[R-OC+N¯Ø05ø×zsÑÖ�“E$‚õŠô0Öé 7—AgÜžI1ÎóÆxˆB`�ŸÏΚÑ�¹ Âö£i¹�òûŽ:­F_¿,\ta Þ±K@ �ÍëŽZì³ÑÅ$cÆóØ9÷]ûR�”h¶ á2˜„²w-¶˜·¾Çll•�0±6xr y9÷ °É‰Ë,E}e}þNëa½ýfoÝÆÃ°Ð…í�IÅ=£Eá³Òž›î¥ûùÖo®8©÷�À?:õ鞀çùèú~8O¤OÔKÒ\äG¾ }ú¬ÚŸÝðy8†#¨Þ¶˜ª ¨û~yzÞá{J猖â [¿FŒBøFuÅÉ�IŽòŠ «ÚÚloWÜ+¹ÕòÖ®ÃëMÜšu§'×�˜ÙJ 1Rí>`*…ÜFÇv¹ä™äÎòå۩䛨…žÚ?Øû˜$K€k[›Ó˵�L{ Üßñ…r.ºS8¯ç1‰éÒwÛ Ý™ï9ªT.zíÔ¯@¦þĬzÝÌ[}68�Íek-•ÛñÜúi8‡o”’Dˆ}w1-Ö‚ý�Í-¾ú1 B‹8­sY|qŽ‚°Ë_ùö‡ "=äÎH/¯¹…ž±3ÿfáyÈ™aK˜ÂNÚĺÄ[T¯K’áÁø6æ)Ú§,5ÈÙýâ«ê”Èp­‘¸DW{K=�ïÅnU€�«3!º¥¨™.|£8ÔKÔ?z,j-òa‹Ñh:­Ì¡Ÿ¯ë w¤îQ€ É„[I9GZaÿëd»á¾¸Ì³cXù~/�²Û@qŒ«.IÃW‰Fø#ÃÃaǤΧXa™âüº˜.#½ÈÉ!r�nÑ9— _ãµö 9,İîI6_�SC¬«HV8s×"Åů ÌÕƒ¹É Ä*…wÔ„[zI]p&Ø…é¿y|ÐxD$€C¢V_5Íœ „ÉCª%¯òù#ÜË”d‰\³ìƒ’ÙÄpÄŸnŽM³‰Û¹ß›K¨J¦àø(ÔSô¾ïêOuÔ.&zŃ|g)Ç`wa’FÄèÿìñt<ÁÚÎ?~ ¬Ê 6®�RÜM×­'äãÀëúTÚz»~X?Á iéäÍBµk¬±Û¹¤Lc,ØÜª>e!UhúZ€ KÊÔ°Ý[ˆ«À; ‡Ö?à®w%¨éæ{¨Ÿb�“�`¡aƒ�‰ú@ þ‹'7¶æÝDgvæ´´FPðâú'iD¹}´ÐíL×ßLSiøEîìä�RñAüÆŽˆ+�·pt•ZHõMJ(½°›ÏâGs*•ă!ôæ8𹤘(§‡Ä[»òqÈTܱÚÊ;9Xa¥››<¢¸tcn7ê;Ç%І=<�c¡™Öê™0jY¿M;­>Ë�ì ™u(w‹ ѲÄR|–£ü·L;Z/vé'g#q,°ÃÖV€Ý]èâ ôÔáá̃PýzK®%/ɹ¤¨µ±û÷^×°YòxÌ  U;õ_“Š—¶÷!ÀTÙ¥­&ùfÞÛ*œ˜Sv�ÄZz0ˆ_Þ¿úÛ}¬·ÿ -¿ãðzùb­žL_´æ‚£ Ë ‚w]¼Øâ‚Œ 0f—i‡�kˆ‰TŽ;lqàüÈU6þð5qK>äa>À�fu�‡Px·cßJîòÇѡĂ„bnN Äþ´Œ™Á9»ñ¤ŸV™ÞŽ«ˆ õyÈXpdî¥Avפª'52Q–Ÿbýy^æ­1KøÊŸ�°ŠNh3Bv»L3þûדWf°(E%9ñ›�Û�蜆®ýtâºÚ s¼.t}™‹GÆñèVÚpýÏ&úb4;Ìþ_ÐA�  dóÊA»^ Ü  ßØ”ÜAmööd?¨Ÿž]̈ûØ«ÁC ›váDãÈyH;TÔR¯íArLá%ቀù× ßZ»PUY[¹:UWå@–ÉÊ %MÒÑgˆHSqòq©Œ ´MúJ4kÜk£U¨™~IBY®4 kR'@hÐQô�k>e¬éK- Û…ù…Ïx˜3Œ3죕…–¯>Ð�a×é6´–?èm´ûß^ÖäªN†€½¶ºü ôfÍH;J˜ƒTE~?­Ï�Š£7™©e_Þ�·œiçK*ì«~ XÏò¤¡ÄÍã4gv]#~óQ69ª‘¯Ô¬1çtÎGñ©4�æI;ÕÙ�sh¨z×=Aæ—…Ë$'‰¯G´ò˜$`È23uNìßÊ�ïÌtÎ!ø¼ÑÃ3ιÕÇkM8Û€<&M¶Ö¤JzùRÎpá^O ºö÷ô‹~EE¥üÖµI�ä ÒjZ2O*œÈzœqøë„ö1̳ïsudyý;eÎø«1дõÖO À“O°[ï’�Gõ<[3‚œ4áÛ4 }O-¢”! |Íš"Zà¢k`ÝãB7ÍvJH={kž‹9ÿh gt­Óè;¬oK0wFÿIY ~½ˆ(p¤2 —‘ÆVàðñ™pô‡ä ÆÊâ®Ï â$ïjÌùSæ­?æbØAYŒGy_î#‹|ÌqM“ú ß$üÝŒ7]�*7?¸yÔÂ.Äï˜é¸È/3�21ym>Øõ87‰"�ži=æ÷Î[ Ïäñ=Èw‹Öh§ø£iÕ)?°i‘Œ×iæWñ¹·ÀjÅt+ºÜÀV•j¶Ü�–Y,…®AWÄ™^whcûM9¡½“Õ«ŽaÂ2ºtd¦Ô/áÛž!ÊVˆ|ÌPMV]ö-µ«gŸÓ{°­NPÚ›­rÿ–@I)Š.+шßâC‹¥š$ñÀ;þŒ!R¶„ÂÊòpˆTD6'û•ŽLÖKwá�´­Y6X@­§Zé¢äž-6d? pÄ ò~T`‹d .ˆ¥Ù¦´¿˜©Êóâ�”™ÕÂ~,uÊXMÓ¯j×Uîlnq™¹£è5v¿k>~¬[b¾å€Xé•Ö‹¸ Š<®%†ø8Ø! k¾&Ñóø³�Ó%æ1gÂ…ýysH5mQyñ¸£+­+ç,£ùl’S� À‚(<í0+dð—¨ãÍ×@IÊÓô�û8žU2 Ø’)ò¶0¯2¤•ö.ÌÕ›Î@éTÑ� aKÑaà$Ðy€çç ¦ºÞPò91ò gíÙšëÊ0!øgúëµ’bD®Ÿæ;Z�­Ál¼9+;OÝ.¥™9+®�,üi’øœÑ_:W§n‹áb¿0PFM^x`åtwL±µGXyº´iôS!ßh%øƒ ¤Þ‡JL7u)-”Ò¼åkhJF'°5¸¸dËLäÉ9¡,MËÿÄÉáæþlꬨ󑿨ÁÆÙy}Ü@t_4dŸï(^~Çܬò7d?žÑ…ô­8ô³Ž«;(µûÎHáÏÆÛ–6èf’gZ@GªÄ_ $IjDù!r‰žþIÕ¾¯ov€ÐÅ8Ò}kÄÚý`ó>ÇݾgªÕ‰]ü3«)<’�Ñá¸çø:7ùlu„gEöLAŒ©h -ÈC3Ýá èí¡)qàh±‘–tÇ‚¡;ønaã‰]Þ1½cï�}ïäo»#¯¥é1‘Åó˜é�:;Fžáºs!ý>Ü݉ô->›“¼4CBBÚÀ9<öª»tŒ{Ç«Znߊ,(—æK]¥¿Ïe© ׎?ýê|ˆ1A,1UšwBg2¢ƒ×ù;WDäx˨£xû.e†É�ÊïíÌêÃíóHf/Ùúµì²;¿0µ­×Õ_ºe;4û:w>C"÷lí§0�p�SK9ŒÇÊ{lðôPui®O¨¾Õ¿Y2³.ÝušâùüZÑøH“]{o6 �]í}õ.!²ÁÕ‡Õ\X?˜Ê>DRà@d©GרÓÎ�j0` ÿ(Bûû#Ñ•…éhÀMYj"¸$œ"<: ]‚§Å]€¬� y¯N81{L½ŠmyÞaIÌv ¢‡Ý¡Yy=®Ò  ƒêŠcà@>߈åxk/Φ×.ûØ gKê8+‰ÈþD"¥PÆQH~}º·ï„{óÈÇŽ&Ú½l®¡í ¡óÚéFÊT”�ô“š1 [‘T2.W™^ �/AžÝ÷4W$‡Ü É ª­¾Ú¨D·¡¯‰~‡ÉïËýÃùÓã§V\º7ì®V!·ÀÏ™«ÁÔ'ªyÍê£!Ä›¾7¤&›gKe-ç›BnÂÕ4FY»š‘âÈû ¦_;¿ûÁ'íÅœ†Ï{^T§C¡Fªüَ׊ª³BÇZú\·a¶f‡¶0ÙÈœÇ�ÝÇdÔÉ'J´ç5ǵdÊ2SÖ6÷[î@Ìn‘�á ªæ5ðË1ÏËëi}©¶* B•TúCè­\%�OR½ÏZ‚ÇL/Ð)`Û6S¼ÝIt™®¦;vª"U'²æM$Rè^/x8þJ¿#ºÃç* (àÑ5aqe¾T–/öQ 8o£¾æ�oï­i@˜]Ïêq æZ缿_K�öC1dùŸo±c¨TVfÛÕäͰ@OÛ ’OQ1vác`¹B£ÎMPȉ®ìL— hƒlR�1²­Ë)yɳéyÆáF~4zñã^á!ghŒäD¥Ë¶ÌÄà˜L¯á¤b#³˜]Š}Œ]g:Ó ÉÞ�5oÎ3ÿ9!ð’jAêE7ö‹)›Æë ;å}&âÔ XjÀYŒ9+|lÞ¬i˜h›tz‡È(ÉrF3Æ8IM‹ôêåó¥›Ê _ ±-µÈ}c¾;^>®XÁ.Ü‘¯›$?é×ÒT\•Z°öYÀyY¦ð‚y¬Ða{?jë„ÁžäêA‘ÖÖÙ_·špbÞÌxÆ ‹CþjËí*›=«œ´ÚÙPŒ¬"”Ê„žŽC1+¼“Wº›úãùs¾Jv6š[e}ôGj1˜z?Ä™jЉDùÚ«¹�‰7Mç'Gõ+;5Ê´I�ï3s&‰FJ_…éÖ€Rð*¹´ÞmG’:0½òA7²¨jÕgZP0T0ÁN„çÀ¨Ó¯*R,ód}Ō֗ÚB/áX„1vÚ"}ðò¡4w í9Eônå"l¦zðÐÊ?iþŽ÷££:5Øó ]x@Õ6–ý„=�åcPY2ã¹j¬KÃmtãÑŸ÷q†xË "U‹#¥i ,<%š»Ï’FÀ³ØÞ\„/‹|…_+#>7Qµy†ônÁÇ…ïöh¶®« ÕŸXf‡"Ñ”ÙOŠ à+ó4:ZgŪפr÷?Ñ!u�s¨ºaÌ, Ž 4Ò/‰ØOud%r} ˜çÅ„^ƒÜ�Iþ5M`¥Q+¦e–‹sOðúg4܈|Q°Õ'Öâ>$QÈw¬eÛñ8”ÿñ‹öð|–ºÏÀ‹,¿©ÝÊkãºæ…Œkæ>`ÎíÌB>x Òr0§ì‡{sãä&"£ŸŒó¼ª@:-ÝM%ÔøA~‡'§~“tš åcªé¢µØ9l¯�Fë�ä4[K' '#‡1¢�”æÐêoxlݧHa¯Þ,1|(Gi“ÊHHU´®‚~Z'­£ÌY/›ø ¹|ùC}‹ø0`Â ÛÆ«Z Õw©Å_uSoVß© ùBéUBƒ£~ù�arîmJ‰-îÑ9Æ´ü‹á-;VZlSŽ 0«�… U�…Ì:.aÇL « áÖª•ˆ™ª¥Z‘œDˆJ\Z<—A§7(L7¢ 4®uG¿h ×s³Yé­¡e¨T©èÌDî�{Üf½àI€EUë±Z„°´A/ų€ÕèÕ¼V=|5ò±%#—ÇwB˳NohïÉ׈ºÈ„ÇÛ5Ç £ávGª&šïõ쎳ÔAIH[­(9«2¶[4¤>ÓM¡|ù1HCD·–¤DƒMñJGÇÃo{ŒW|L•à�MHƒÜ¼4 ¼p±úl¾ä‚†úv¥¡�Ú[ûwüB�ë.(Iÿ¶ïe¸Ù�ÁA}¤Øò#d´“úóýá£4Qè„»ÿNÍ$`±…×j1NÇ€ Kp;×yLÅ`W+c^y¶V4î ääw ÿ¹mž"ðyÚćË/àìJÆxÃ׳ŒÍ%ÏC,ëdügé €’®d¡îm‘+ŽÐy§†¨†‰‡V…A˜ƒ^¹]iZ[…YSâcù¤.zb‹’ø?{)…yâ\¹¨ì—ÌLoãOúº[uxÓê;à òõ¡M�‘èäg[Ò¸/QJ hDJcÍ>4 ÜM…‹Ê­�¥íKc•f”;ÅìN/Íh°A` Tc¢ÐžJµX Lðw¿�O»~h ©båê›Ia †ÉñúÞÀ)àN3ûvõšiE˜»ùÈ Þ^õŽ\‘7¨%EÅ6}å…´=�ùã¦Ân�S­R³ˆ½¢ùRí—4§PÑדt„?tÙE�²4éã–J‘ ©FXæ*…»&ó)ßkŠ”*šqþŸú?H:qšì3¼Ãú•åþ·†xÛ}Ô/cTHçŸîÙCZR$úû™‰Ì|üccä(Uä€{­†æpèvJ„wá,û{¾’ÚÐÞv£Ù)ONT‹òqÊ¿±¸Œÿ�ûa?Cj~Fè}gYåR ÄØåE´«´ö+ØÍ/R7§‘É£tjä‘E]œ Bžn�ú‡÷edþo“Ú_ü„1?n8’ó"†ù¥.¡ûv Ï3Ø’Y�—Éþ4ì5ÐM3âŠái~ìwiüνf'ãPÝLî zâ'b¶ý ST¯WD/Möƒ_¬¿7÷0_ÔÓ@kJ”E0Pãé¯lµ(À0f$[A´¯pÆ¿Ú8 a¼nè4ÓÌwåceJÌýJT@øå�&û!¢i0²»·ZûÛR[�Sî @µ2)v›¦ÞËî¶ÌÓÂZ\Úb/ëâ5¬ã>ê=ï<äÿZwc/‘¯ªæ2¢Ë¨è„�?9^¤J}ë ‘è ´y4¯}úÜ–ÃjlK�‚1$>èšq6˜Þ†bqŸ×z«$� Á–²õ‚¡Kƶ÷u� ¼C…Õ­¡E�‰? ÉkæÕø#Oˆ=MÚäVU2̬£ÕQ_ -<—e0ûÌýTj|þz·«m<¿ÒC>ãÒÛÿ^'úÑì2˲£P–f*¿o�Vƒ’ ê˜!ôhYc¥§.Éñ‡çN4 ô�S#Á>ï‘D‘öþ��ì»×žÀ¢€+ Z¦¯râÍêA-?o@5´‚b¬ì‰T|þèXÞáW#jÄ/„’.ƒ¾K#H•d¾­&¾ïá£P{¸ÄÆ�úþ�g°«±ya¦3ÒW¶R®›×p»qÛþÅ¢9§ö"ûI¡/ý ²u¹̼üfªÙ$C4G�ÁÎ#C·ÒÖZY¡-&uÙ£ÊAÕ‘.Õ g‡M»%&•ëÎväíþjÒ‡_$r±î¥U-Qƒ&Äšœž›s²Ÿ%¼°ïÕŠ\!#u9ÒfûΑ&›‚Î9Õ�É`†ïšFÜé­`ÃJ*uÖô9Á–©¯áßš8­T&™íHõ‘œ°8h§.\»£ ‹)yé-|·²lŸ!ã4[ÂÔ °íKiŠw‹…ëî0ùÙ‰@)ÅkÒ·hñØôÈHEÜ\‰ÖšUSž¬å�á‘D¦žÿ0〠€9Áuvd$«ÈóÄE< ¨ÁÔú©§%´’1m8®Œ °e·­Ux¥‘ï1i¥Ý»„�d%³÷(]Lrê’4Çaû¦'l&ìÅWJ!#W™¼fóÓ"ÆxþÒ#{H‰KìDýiò®ZŽ(U²ˆ)ÜI ²:,4ÎAŸ“\¥ëKrù cÓ*Á°wðñ+TVK09´3„Ös`¾‹0سõÃg½*0PÿBã«ed«… t–æHþ.y|škÍ÷9RìwýÏÔÀ.íÊrü¼3Ñ&¸ŠA¸ŠŸT+ÞÏsÛ)ÕÇ%"Žn\»#FMÏìÈݸÞ�ÄÑçÞWªŽT”€Ü�P=¹@·´"£~„±×çZÞõÍý/Û0Õì¾?9²¡ó õ*0±\ÑèùÆÂ«/¼P‰QÏ=!I¤‘*Iæ úþAb„Žx�ÒYàù>�œ'Þð'¿j½³'èé…je4{<õˆmoU²3#"Gz¯wÇŒ¤•c¯;ÌÃË´�îKtñ{3I ·¶‡åSì<š`>(QÁ5�Y&ˆ Š(Þy2Å«h ’m»k´ /=–nâ±ÜZ(Æ+d7¡(Ê})L1� Ò€l#|e0ñbÀ¢(ÔÆuÏöºah׿>PÒNÖ^sú®ù~£[ø×>±×SÙæk�Q6Â;R!v!XÇÌbŽQF+á4ƒ&ÐÉ­2`=á {Ôm*ÒãÒ-Ä&PV7Z~ ;|‘µèZ áz®ÝÌÏä�ùÃëmÁ`zb¸–JÆHÎK©…s¯ždêÛR½¸ƒŠK57%'‹s£ìƒ?pÉ ôê7-é¨oï,h¤&Æ b8ž‘Ÿ¿ùŽq½í>ðIÿd4ÛŸ¨ y¨=:Ç3“dÁ±…!¡‘ô�ê0¯¥âã%–âþ ‰¢šç“¶‚E¿©ÿN7ûŠÑZþ¡Ö;,=úÒ\¦"cú$Gpxõ*{ÉEm"f97fZ±“ÿ÷ �PqÓ*�™„};�©ÅgÁ|õ,�† å�£ÔO+NH“ˆBP›mÌKÒñ)Ç&|i%?Ü.nxNQ 3B.Ü"±„^кêsäZÙò{è3‘mï3<°^ézlb² Y TµX ¦?g€�…™½]Z0ÊØoVéeô™ä›Op· £î‡«Ëºrná¤óݹ¼ôÛ«ïš©°æ£7æÂ–ƒˆt‚Í˱�p)%nèÒmë`ns¦oð%Ê–„.éýðýEa ¿#DY”oo˜¿£uæ»’cÂÆ�2žÚdËsZa3v~"?âýrÒ¥Z ;9iŸ¹Ì~­Üáë�4-uŠÛ EÌ�aaÔ-ñ�õ*nk¾súEÖE#•µÐ¿ÇLwO2Æ/èDã.V��sŸs'è…5ü–ˆ3qÐqлɖ„Y†±€µÉ&œåUIÇD1‘n§�â`åêäz…Ô(yºÞö曨%¿bëEþ„EЦš3[ViBõçÝþ,ÏÍŽ"ÍSh{\=CæD†u ðkëyøû�±iˆ†dŽ… Q?é®8R9Ft¦eïË­X]ÜýðL›ðg ç�Ÿ�*w©øG™64A \mU`a·dï>¸D\]ElS�#Éõ@ÔÊaÏQ|ª*©à¼n#(ÍŒÄhgóƘÁƒí†¾¼K/GØÈp ]bÏz—�„2�Œ5K¬°8”H¢t5ÒÏrƒ ¿¢œÕ‰|z¨"¢óÐ2zC¬%UyÓ±“×lâ€.Uúi°}Ê¡èú·c»NF@Râ )ΙjÑÆ§„ü1/8(4g¤Ì‘ÆïnÚ�Ée›ÁpsY®vîŠÑÏåf [ÒÒ;Cé›Znؾ)|ÞÙ Þâ3“±gŠJX§ôô�¦�c? �÷̃‡•ØNMÔ e¬ôU#ØTÓ0w bÜL˜¥–Û¬9ökS“Ÿ&DJç ÞvŽœÁÞnr:!«¾ý<±Â‡ &-Ъžœð"4ðH«íx‚ElùàJ™@? ~žÉŽ?”¬ý±žE|4�X|jfŒãsfÖ´xK›hróy®jÉæ Aõâf®m}m3ÕŒ»ß–bÛc7Œè è0ì6õÂß®.1aDö�,¹ºGE[—`T¢´¼ dÒ°‡ÅtímdÊ\çEöýzH„´w£ÜÞ=>É Ýé”ÏAë]ú Í;C%xÏ¿å�͹5_mæjD¦ ç6Ĉ 2­�ñKÿ^NØ.Tw¬ƒÀÄ_:* $n xê# Ûêσ?=µ/»s0O¦ÆÕÐìMŒi)œ¤ÜEÜ5¹�!%WÛ›*“.¦ëpXXd1„F?òïY5ÞC}w©&ŒRvóÃwìÍL¶v¥~®ýf!1pÈ\Ÿh8:´Áð»nö[–SÛ@3­Nvå"Mvxhky;ˆ¤ÖUÏ~�Ò?ʰ|Òýuê­¶u}†“)d_rR¹€�™iðáv°r„=eó"*½óAšŽÝ¬‹òµD®èF! øæsø·E;;<«&ür2x£ÇrÉl·¶ÍRòŒÍmEOȃçE†ªÂ)÷²bÈ“ü·Ö[ÒMAØ)bë�@¼…F‡«}‚Ò"a÷vCy²&/’0�Á±î9®¥¾»ò‘†Éu‚L7ÉH bÒ�oÍ .4€Š9¹–¼¦ u½dø ΨÆ2ê7M½/Å-]G7×+e–^6p·<+¶ûºÙ¬Ô³b00c…léTUÙ÷ñùuFZBN‘Áw=­Ã÷%DÝSô$†‰’¥ý¡�õñAíÆþ­‡¨¼g-cÜ:ál׊ö]¿éÞx¦›lå~þÍ‚ÕOèo&‹Ee0Ñäyk¤ò"8Oª}¯ò"LæGà+¼Ü «>pûcÊ¿ÿÌEI£W&BÕÔ¶œ�¨ä“ùU:3?å±W'L$âË D¯®«?ý;ðQ$ØÏ¢C�N}ýhÌÚU `º«‹Žpñ †»5ô2$}#• Š¿Þ›Qç6]·agÑo$ Ÿ?Ë"@/Yµ’(eŒá˜>.Ýw±Éìò½ÅPx�òëÐ+Þ!Ú`Ë 'ÐÐ Ò¦íö€mæYŠ  c›€Ìµ&bÅ| G(ª¿S׶̘#‚Ýòa¼uµôâ´‘³VaDÈ%�ŸÓ6  EjqaÉ•h#¢/döôëÖ‚LbÙÂ|fý¦ò †r�  kå7šÕn0GŽ‹.ÞR/+$EF?7[­Åïø £ �ŸWJT¸Óè<´‹³Å‹$—á>LSÉÔ›ÚÜ@ZC”þ€ P®½gàZ>ÛÊøA0žV2%,mfå #!#l¨`k‘»f‹³ Ä,ï6Ù¸ÇiD=þÉé ÷»jÖâoé:�{±ƒ<Fõ9"E[}4Lcr°ÂmdNû ¿“Û–¥”KWL>zz¸{!¼TÿêÑ�z¸=¼‡¯Ý !aÈHú|çâtçÝ7‡,™T¹®úë¾#ˆpíb— ±ÃLêVKžmHÙ‹DÄt²ùááu^¨Y?+1µÝà¤àq#óö§ëQ Ñ=?#'ƒ Ûuª]V”µà€}ªþYHµ´ÄåPy`@+–ÆŸn¤Ñ‰{p—ÛÎ×›0i]è L��ïq)_qV±¡šj·?üšç‚ÅþàQ¡©xäM¡©Qdm¼ì}øD1Wè¼²d‹JÆhl,§ùC[C”¹¦ù±bÞ,šyƒI‹`«iVRAÓùM$V[©•qâÄ #è¦iUÍ Ïíwí‚xJE Aå…qôÎêäÁÓh¹ê�˜9`«?P™~—þž¹˜²(£Ü�ž¹Õñýd7)ÞQY…Ë�’–Ø›Ä�2#©°2™ ïÏ.¾?Y!‘]ÁÓ‡ ÃXÌf)Ûã€`…“Nu�:½�ŠÞà{Ë& KÚílF„Rµð½TlÕm�JÒ&¢>Ž¿`É‹ŠÙŠÖ™ðAú6WF7·ÆÑŸŽõó_‹�Gô¥Ýøî쌦:ûI†¶l;!õy^ÔUi 4û1(-PýéPj~èr€Q®�ú?Ž^a|cxT!ìg[M¨ögPè� –ß0VWîrW¤åqË ¢JM,Ìq?‚mY½?°œ”/T�[ǽ J—U2�A]Éðò S讨ö,<‰Üç и¿Ò®2K@Ñ­ ôë›=€6ÚU°1pFLgU˜kaYø˜Fl ;nçÝž W+òkÀ+ÓdÏAfu Tú0üüfÈ*0j£Ø¤4ô’HusV1ýŽêÊ>ˆp’Å»£Â0±GZ¼Êî ŒeÓ|2¾ì\1¡sLG±å(ÛB†Ò1ÆWEúÉyl …* +çßJ „‘Ï„Y½Åv̹ÀˆÓ3™ž¨¹ÛEtÛM‹b�eU*O6Ö91N»\ÌÐPÄöìÙ+VØ1²ØÎï‚YìOƒ¬Ü1i¦ŒeKéHM?§4È`ǘYúö /¦’SX^#go ½wzz©ªH†Ð„yp7ÚÏÆWÚ¼žà$RŒ75æ?©¢¯„Á"3…ë¶ýn¥€X—QBÞˆ-E íy¾Yh`¤=ÇH D>BؼKL_�qÏhÃKñùƒvu-¹f-59ezÅÊîfô _©ùÕ² ½&vÑ‹ì£uëPC£à¼Öƒ#‹)'ŒNòzöl½Œ¬™ŸùSTE’™YgÇrqµbƒgwÎÝ…Rˆv�ú³ ‘mjg©Q +Ἆ) mŸm”iÆæû ª/¦¶2½õ¬% aÁ}Ü$‡PËýa1fÛa[™<¢zA]?GVlCnY£á$O�#g`>#7£5ƒ!øC×hs¬«�ׂæ5Sn…°?fß)PºmTƒMÄF‰4VåÊ[ÿ @ö¿)ù sc•!{¼†Xx˜ÒBêeÕCw=Tæ¡;I+p²ÚÐ I±´Ã šê ÚôYØX5“p`vÖ/L@ï0Wm"怒öªz€‘B.™;Wx•šµu)TTŒ{G}êc~ ï8ž”Ë%ûù)ô�É“¨þ,KY]™ïkçèô‰Ì´èq8Ó6}÷–¤i þÒÇ�°SªSË)Ä%\‰?wIÄF¯nÑü»À¬�¾§íuŒzöÅc£X®.ˆS×®•Á˜‹‡¨#9>IÒ1pŽï$wWeÅ6Ïö[_e̼Åô.§$23M}™ìLž�òÃ$SþÓ®©ð"ùÉô6Ëb >èɦóYw±7ÜH᥎|—QdNSã.´r¦�·`ØJ”w\×ÀÚEi‹xÉÕ !ÒÛ²‚ZfÑA).L3�Daˆ¬—Pc±:­ä)Q kÜm+®Á»ž«.Ê®˜é˜‰&gZ—b�.Ò~3=§˜…^Di ´ZÿÊ„‚¦Óß"0ð¬t¨r¯o++S}„ÿÄwc¬ c¡W÷lv¬¤Ü»¡Ï¤ÚÉëV/eÃÛ‰Ò �AÉÌ=KnÒò7�+@Ÿ!!R�B¿'€ûF‰m:Ç!CßBã¬=”ÈælZŠ®óZƒt0:f ‰@cƒ,ÕÙ÷9ë½0-ò«]ƒî;~Òô¢‘„<Ýñ“*&¶™£Ï îH�? UÏç¨I'¸OÌSÉÉÔávµ ¹ƒAÈf�êíŒfïß`2Uµ¨*jߨÀ]î¤Fx(FÃ#÷'ÕF³Õ8¢®�ŽÁ¬ ¶“A;·£š 0ùÙS3ȱÞ@×'Ÿ7?sË|&TN«\ÀR�fU mȯà<ˆþAÅÈØ¹�ÎQ«�r É@û[ øØÈææŠ�ò›þÊÿ1’ðñ#Ë— ‚ä}Á€×ÚVb˜¼}ϹƅBvÿt±uÖœQY úÏ ÊËŸ[š&ÜB²R âà·T;-¢¦+ê,,œì UÚT [¦]š¡a,ÜÔD¡vˆæ£ºþ¥²<ƈÂ3åM¶(ºU¾f¸‚‹C߸ÓÀJ–l„ IkѨ²Xë㇛]½óý�µùRapïêíÕ|¶ñÕŠ-íÛ 3ñyùœÀË;rC³\:ö@«ôµW´Í”ûlÿ´ÿpWN¬¹¯M#M#[_÷âK#ø¿+F‘%iÄ{¨/Ä&ÙƒEþ�æÀUAÀÛB>åÄT^yöv4ç Á‚ûñ„eyÛBÊO~¼&MÞr:E¼I„Ø[ôýQŒ-È¥3YÞ,ؾО––o§ Ž/óûÁpÝN¼Ý ünhÅ ÷?À˜ëŠºTž?oj9}‡!¾öjà,áQÉ2·Ú9ÀƒØñkæ^'â‡vs†„ŽQ²åç^ÃÊÞ[Ó‹Ï.dÎJÀz£–o–”Uıè>Z ÑÇlŽ�š:ŒÎ€eƒ¼‹TŒ=è˜ðŸâ~nû…y.xèœàL\6 Ð(ž �.ìy«®¬?ç?¼='Aìš¾²½áö…¢Ž…Š«. Äâ†ßõ4Œ”3òS]C¹ÝxÛ™.{ï¨{ž)�¨ow¼<öt¨8–æ)<ú�'ÄÝ ìVÓò·8º¸²+‚£SØ÷B‡W|û±BŠÝŠš\Û}èc£”€]8~ì­oÒ^fì‚=Ó1ÛY¸‹�")#FX:Š¿5Õ¡zÿä*`]rø�€3üŸ*Ó™»HjB‡vÀ’�iЂ‘ÞAýH{–O0snùü»ßjÄ ½gMwÙVP¸ŸýrËdÉÅvÈ* ?Y|ry•X#ò¸Sð»åf±óA;ði#c~è´ÑÐ>*}îeSºG›Ä=vkd›Ú/•Æ®ƒ¾{•Ȇ±Ó”‚D}zÔ¿(šÞòWÝ{æ×[é\q*Ê?Ň’4­aø†6œ¿ðÚ+B¡øªô>SLJizpÆQ²<à T9ä¯)v<Ф¾gÏÊ*X’6T Nnüµ°/CGûJ)<Ž5OÊuiíÌtHÈ]г MÖÅ{ÿÃ6bOºÒ˜a©±¾ÂÁÝ/!& l—³Q t¹]Úˬ ¼æÖ�ê|›­Ê4?AäxÖ“pŽ^ cßím«ôgal ¥ãÇš‹À­†`òÁÔâ´äûn îBÂÑ‚î ,}òÅŠ'BðßÁ<üYa3${ØBܶS³"ã©äXSEõ*A¤Sæ$ÆÊíøŽªÚ˜E÷ÔÈ}‹,´4ÄV/ꋃºÈ募O¸ê>Ár-#è’�©û ©$M‘ZÊåH´£ìøÈ%•;zÚa”að%yñ˜ðj?+]„4®÷(Ýôëî.ðß&<岯 (~D–Íq>Hd¼Âu�‰•i¬jù|%×ÓTôÞôËß+ÔàQG­ÞvLäæeòw¸í[°mö‘ÂQÚ:Âõuô©yÿñ][]§@aþŰ€ÅÝ n áÆi(þ%Áš� .€3( Ò-1ZGäm¢.’ÀþÌ+X²�…P3m¡KžÁg?«»zR-z"à…í�V‡|_f§\v‘·*ÔB½fÓ69 ;¥ˆ{´Ïk覊Ù1v+p',m4ߺœÚ`¥Óü¢M ö‹íf)Œ§o0×þƒ^<õŽM,î€^�$;Ó î2éorÎ$gãî š‡K¢3€ÖÒÚ@„‡®^Ï>Ã0‘®A'´ ²÷zÃU¹°-å²™àËÓ{‘IÓ®bþ”(Ô…\£Àú‡šÇm†‹¯R9¸ù²Tz(ïÐ{œ\eÞ¯>õÞéW¡§3†ÁýXsV~ޏgÕó*[ÍE‘¢ÿʈz„ÝP}™üÅ©NH>Ÿ*ñx4Ìš\2ºtuÓÎRXþ›:¹\à-¤šœb5¹  %øè×¼÷ŽÓ"ø°ÁОze}që—6gË3n˜E©Dq²’IM ¡{àyPB¥Ü=º–l‘¿ƒ¯F2Æ‘_œ~GŽICšV£ÏõnŽ8Yéê[·Á;è"“”zDÒÂÄïdo›aAqÚ¸ø¥Ë­Š³$ÈÚg‹ö¢—“Š<˜nч"ž-È.‘)Òòød‡Ð­¸ÎɺÁO3¿—‡±ûŒB‡,B$^#üg^h� —Ù@·«”Ì4¤èã$¾DÄqù]Í땹^>”~à”`ã=°f¸�脺¨ ¡üZ®"HøH;4ðœk…ºú¸4cL —ñ®Ét8Lúòäf„û³óY©cœÀ˜�@GÛã/”t;w&ÓÊå¼ib).ºgUãXðíJû¸¹1‡¡!~šž2œµšQ˜`^y EˆZdã=…àœˆ­ë­µÞcQm¨j(ž“òÛ,W™ 3w––}Qp·ùÒTÃmL¼YºÛŸ2eÂ-µù05tòó,”bmö¶+{…ó‘è€S•Ç(RA9¶—Àt^1Î&ØóNŒgð�°¶.ˆ`Gcη7M±Ó½ä,²j"•ég46}?�¶É¸x�~¶_§CP±¤tN’ýÕKÝŒ„H뱄¾KÏ]mXž¹n½»7{»À™2Nn�‘ñµÿüäiô–ÁÞåУý¤—HòUc%ӥРr�‹†¢yìœä0(?Ü=˜¬X¡ØRÙéß5ª©nN9Û« _$Lî¤xqSíš’ÁA€í�Ú-I×Í84¢K6NÚ[rÞýÌÜ^X»µ!Õ9öQ|赚¥ÊƒÑR�Žõ´3ó@ã ȇˆTßÃÑ2³V˜œa”'(+ã?ÞLþòuö.r�«7»/(îíÿCP�Ô�=o_[ºÊ]dÉOS3>o m“¤åAØ …ùKÐR#9T€Pf7]°-^‚óùTMš¤ß™¿Ãî_*âvÚ;ûu™°.Z�0ô3•E ­M¹Æ§4üßÞ}Ú§)’Á˜¬´~>ø»§�ùËv�<Ø—ÇüF3Ðä¤]AÅîòZ*m\ùò‘É6ÏL1ä]]⮾„éät¶˜T7aÕ"x�4劌‚7�‡ÜÉð3èÄb„ÅÛÕ.dú¤7Î�ªéU“/͵à…ÁÎtÕØ˜l ¥8ÈW'ÆOVDgdнÍÂVÍÝõ9@B^C´!Ðyót)×ÕÖ:ìVØc-®Õ&~°dÿ˺²Iz¹P\vî¼ß14Ù(ª¹»ýöƒ—ƒD8°`=¾u2’YÇi“ª0Ñ«2·ï¦�jX#á=ƒÌ„šq½¦ ¸A¦†q³%²“çyE•ë9@\­„6’餋Ù犅ÂÒÌ TÈ«{_›¬è¦d´™ÐŒõõðPm˜×û�§ž� çá bfÕtÙß2-Mà­÷aó!SKH7Å6 I¹Ì†ÒÿäÄœ-4,§T×K& 2Zèê_§Úîÿ΋ ðçCDL?°°?‚ù‘MÛÎèíº!7ï;oš\o0LdÇd N´yîî fˆ )M¼8È_™Ò2Š[‹È»¤ì§�«ï •34°´¬À­¿L1o†!¼ Pg{GD4ÐL2ô�>öèØOlêÓéŠ1ÃOÑ€³?dTiüGk2%£SL­Xèœ7P€�-ö£¶hc¼h§B=F:¨ÁbÆ“°ó¤CehÒ8|à‘ÐcPwôáíQç–D7 WCé±^Þ»x¡@`¢TQt¬Í}ЄœKúÄàYÜ!®ì;j‡Á« ˆÖÕ¾îrKo…Ðd0üRÂ.À`ì�4|ŽöJK5ˆOù©e¼ikm¿Ü{ý,à¶�;B�•UÃ, ”Yl€ ôj|i¶¼° òÀ¡Çhüò:�Žÿó…Ùxln8´O3Ó_ÛßÉîQ ÷Uýý²ŽäÉÊ‹ð®�‚þvéè "è^Ú>OØ Åï:îÆ7]â=]íSÆ\Ëí5ç¹�À× Ðþùp`�,;vÜy[TZbUí'‰½Ó�,+#„1ŸŠ&¨6òåÙ;Š-¶ VÆTv^¡4Hš½aQBå1jzF¯Ë©r×D { Êb”M+‘T¢©O|?A†•ÑÝ—p­ÓZL±¦JE*É ÜÓGÂ&á6‰t¬4âU¸n�šbf¼jµ–tYOïu»ãã‰ÝQ6Ù¹€p';\2ik¥m¼ªµ(C¹³?Ïí7dÑü`TäÊÞ&è – éNf÷9ºÑ÷e¨Û{>€ø±ÁºX4ö¢xÔpxÖt-V¨HH`§îÕŒ°Il�ö­8 ûä QÇJúf'vâŽc¸9¸Yd‡pUEÉ@ÓôYØÖGaá/®,úâm²Ë:€W�%¥ Ú(ÂÜ5O|rëkxÙb6Eõ1OdŠ¯Ð¬—‘ùa(ÛLÇ£Ì4øR¦¦–�Ê›Ö<Û͞Ю…s«¥Š1c;äàZ$3½iŽûò¦[Aï¶Þ¢ ò˜ —7*Î�¿ìMÆÚÏ‚?ÅÑkÑ'§0ÊÈ:Ò_Àm�"†0ë@ÀÚ§M]N(Ì£J”¡¯«ÑŸ„ÂÒÛÍ[ð\7îË–T|:µðC|çn ˆÀ+Ü—uFgC"6sw•›ÁW0.ϹµñùrRÜÝ  qó w¯�ÏBd½;ê¹b­*ö~‘ì+‘‚D ü›7*ÃÛèZßÏ/ÒC,�„ã'ñ^ù' +[Žx¯ñçña§QÊn;¬|*Ïõ©Ž¹SÈý(3 édW¤VZ½B+Ç TÖ2»ÄMÎ=g»"uت³�å€èœÝ1NXééÆ˜ÅVkÆ©¢N/ź\1Hî°„»ÅYÒ¦B0¬mƒAcTÁzšþˆM “ãD|’n KìÎò…âÆÉH¯!ЍEƒ_¥â‘à‰<_£"�!‚RßTe×3Ãìxb³»t•ݸ“�öÉ VÛ=éÍx¯.ê”)•A6˜OwÉïNjܨ(ÞÛâ?/<&™$ �dç/È®�ƒ[ãY;Õ÷ÄÃËoqy`KïØé 1²÷&=`NS {MC~ï€1´ùËKFÐ*°^!¯“¤\»P^î½AkæA á�´,7ª{© ´¨vLjRN*WéݾV ŒVUßùÅ“+ }Çn¹þpj1ts>­º3§‡|ïv_å6F�™¾t‹Œ‡-¸9ˆ¢V\{R#z7Rs5?@€sTì¡UI€á;7þ&¸WPäs*û€¿E$7syèvˆsÒéÀ…»°ƒ��0òo}<­äâöîªäÄg¬–HmÌúI¬ê3G³%ʼBì óã£tƒ5|¹;þáÐ#)*¡!á{Åï®››•ô Sø·¶ê±n¤¶±ÁSXz Ñ<� KÞ\~_úçhœÉ*2xd¬…d¦†š`†2Ù.Ù„Ä*W¥‰Šà—GÓwì ìÕ:"”Í Ê¾:§€™ÂÏ�JBb`?{°ÂšÈuùÌv™÷ZqSõ&\`Ó»Àùì€�ÝkfÃXÀ±ú°bKƒó,XÙr×�-R¢§Y~Z}-ÖÕhGëõýÜdŽŸúµ*–S4^ë‡;7ÝðapûÊË|ªCÛ“f.šd‚ô;êdškj÷Ôk‡E}`�aù½:á�®ãæã I3P„CÆê±meçÀûUÓ*ƒO°¦ªvÙjŠÛ_ ~ËÍŠº;îu0)cnø�KrÞë9w¥ŠxW¨úO�x°(ÊÃî<~}aÿ Ö€ÏRÔÞìEã“ÉÇÁ”è´†.{ñ•�T b1s%„½±OÖR¾ä¦#J7~0·Àçî{5m?îÈþÄ">˜¯O#à ÚU«×|0ûR¥#¦¤8kr”‡w+‘¾”‹z›öô žqfP¼RÞ÷ÿ!i6îËÔ-‚B!nÄÞ|Ó)×»z»�€¸¸yG)Öák­m3 {뼞ªqr¨a�^8©—h¾â¹¿@ÀnKWopþU•úEU'»©Påj2öÔ:°„–vûB ÕÝ{ÒêÙU{µ«£XfÿYqªÃs&UšÄ©ÍfÊ{v(ä/‡‡cŸ‚M‚Ý’t ðwŽë*MQ�õþ–Û»bܶ¹YØÄCÖ4œíûÏ”‹­º6@L‡윰ÍÞù·î)ôDئPÍÔUYýÿc“Í…mg~ȧÑxƒþsy¢gBü÷…È”.�î‹ ÒðQ„í̵<žnÉ0¿Ùæþjó{¿Y•ï0éÑÊÖa?:ðÆ•'ëÒJ9™‹ˆí�Î .½K³TxuºO “q[tØ�þYÕ£­'Gê2þ´aöŽHØKlÿâ¸"Ù$æ{ñyzF†²‚_þî·Û¸]~DdˆsÖWOÉJŽˆ³Ðn+øgª E�Žô‚A§ËÃ7{yßUæ#š,ç©ç‡ >ìÆÃìõÏ+œ©'ü&­ÁÎÅÕ…„Åœ«Â£‰î¢pß¹áï}oðU…lÁïâMhw´U¢}ªáC*Ñsv’R8°>ˆåÑðªÿæ¢MY6ª Î¶ßþpo8gŽ6qx 6ôfÄú€‡£ô�ÞãšeÒ»L§€m¬™™ƒ÷zË'\_ñz1$ŒÇXÄB�,<—`NÓ­?©â¸£1ö:òVO:ÌÕÍüM;ʼnæÇ¼~ü=É—úž÷[<6É™oõF%ÐSc>£å€¨Vßç „g/0¦"†l¬w�x>Ö {B•wCç£k÷Ô£å>SÙ$é¹V‚hü0)¥õ[Çr 6ò¢)Iío©üÜ;'£wŽûz6ä%ž` P­•šÁ}V`�mûÖ¹ZuMÕÛÈÆöÇÛÇjòšººÿ/U%ôFœÙWšF™=>ÊÕ?eÈ}PÕÏ3I•nƒ9æÛ€ ÙÁ÷ZG ®‡�s.¤ˆ]1)§M„\Ñ�«ìö%>þâìÁ£+TEíwû/˜�gFûë%»¾ÑcêDåÍ£ÇÑTLô ¿Dj>_S£¬qÖÀWé!%Ç-óthsN£`|FÄ¿ðrëÜ{‘ »«¨ðTÇgÒ|U!ÚØÒ`5º=ÓmQùÐΚæÿk™oó¾î;^ðD3¢êV'^¨70Ÿí<ðöûû×ùWø^G‹ÏâfF‰½VG¨Ú‘žpå5ÙÑÖG±Ïs$R:£Èô1Ý*´tÏ%¤Ê��VÙ÷íu�‘.qúC§Žè|%‘+E|ÄqL¥U :ùó¹dÔ,ÈþƒÄO­[KofÌ£•=CPí,!ù#FXüqàxÔìÇz\<—3ÆÔB/¡Í‰ö�‘3­vqßRÙ¶-Dñ¡àœ£@w0ïT¥Rí miÊB·žRúW0äx6ž/Èå™#Øý©öYX! þ×Ö%yrçRœ�Ä/Â�-Ö´‚îÇØŠƒ‘h`¤T-D³ªÐòB¨",ØG±ò‹6V»Â~„´{äÂ­ÎÆ0ݺä¢ÅµÔ^ýˆÌ%(,Á}W§;•ì§~›ÈW*GjY €[4Q&MÒÍSƒ¦’ÿHÁBú d)mœ±îªéßʸò»âÅÕ4€_‚Á‘>…¹V§g�…˜s` )Í:ºqâ|xè©®Dž“[‡»¸ÎL×~ ê}˜¬•AÄ==�â|k¸eòlХߎ‡É/fؼ½©;hmø¾Ë'D?Rü.hï«P¦„ˆ/ZúçJ-+ C1.¼jœ™ad/S•�Í¡V)ÅpëQ€³\V&Á¯Ã@¹Ÿí@c—íÿîÞ2÷«ì$—ÂØãáš ×Vc¯\7Èó^…غߦMjød]‘Ú±§ÉVµ(àÖÙ,‰¼U�îk³ug# à×X1f?´w}F˜¡—3¡ÓÈNÁÉÇþÐ<Àkï Š�ôEЦ~Ñ—È$�¡yÒÑA4œdíBÿ31»T£µœ“0c Ü)d£Q*ÀÑe˜šKt%ÃÂç±5¡ˆBâë´öLöcÈãv*¾™¸�ëÆíï´”ËdB6¿7;=K7]ÚV>)Ó7Jý2ð´ü€Q0$ ¶VöV¾²7ÞÍ�µªÇCñ1V'Pµ@ÌKz¦EEË…8rU BÊ�õ ú%мw‰�Æï „ _¯ÒQHw/Yµ!šß<_Ü¡‹Ú‘ö/¬/.)ïÒZxXÃ]Ÿ›‡}ئ7cÎ €9Ê´Ç?'¦hD/] lV�[R¡\EQˆ÷3½ÞðÒ Ç�>¯¹­ý‚õÏ…ø<¾öË—¡çݤ¼ú.’a£%Ÿ,ònf K1ä®�Bu=u*�ÝÍë:>ˆˆ$w8¦÷Š.Ô,¡›þgôˆØ“Ç2ò¬.íDå´ãÎ^a?ËŽx–^œÓÅ8&G½�Ã�[­¶ß~žž87Ü1hHv@"¸\6A«=r|UIˆƒp/^k)y8S- Èœo{$ÞCî> ]µ�l }i3N¢çYãJ§»«Þ�ú×|01µ¹b²:Æ�õ=×ÂÃ?„{¶íæ�´¯ÑÂ8áÈ_Wú§‰¾>$ê.¿ßle�Gq’…lEÄ-³À]§_ƒÔ(+#”Ä�£ ²FC mpíža�[×Y~œ†I2F;¿Ã8)§tKöÞŒù9cœ 4:_Êø ZfÙY¾9:�Âêï?ògëã›ë\"¨ ^ž¶8ýâ<7ØYJfë*l…|ZùûyGa“S/d­ZîU_4»÷^ÒG3?öðµÐÌ G’Ò¦Iæ-ù±ÂÖ�œÙ:E‡ Û~<—,æ]ZU�çnM¼˜}’ÌI*·‘ð«e2ÇñEù0fÂg¡[MíuoösS40bê (Ð�,÷iÈ0-C¿Š&þÔ�é(¿°@÷ò q‚` ØFæ–UÀ\ýj÷t‹ïƒNMüæøŽšÄ¦r½cÇQ]2 °z0àS‚:/߆ª0¸Á÷áUˆó¬ÁõX”äÏi‹Bè<7ø(Ô×ÄðZëô�¶÷=vŒÄŽÐÊY›Ñûäm¦‡P R(Þ–ì øÞV=²ó`¢ù GQ³’Dv.Kfþ×Ôq=þA 0ºí?×…¸Vþ¦±µ«…õV”¸‹O×1Τ5E9‹ž®uŒ5.‡õ2±tûu¡®\¥Õù3LÄpM1có+Ìÿ°õË©¢‘:'o4ƒ«�l«Éä=áö.ìú³Þ@˜ƒdŸ¡º5`Æ]Úð„ZZéc7­–½dmŒúäùÔ·¸7nbùJøiÊøÂ,¬+Ý{ÙµÉLÄqëÊ+©�ú×ò~°Ÿ¾†ûãÏ«ôkZÍYß´6�KN-ÊžùW¦~ɆCŠÍ~ ¡ æj½2Ɉi)�ºE!ßé ŠwÔ� ŽCiVÃȺ?s´r_uw·½$ç‹n3L¸;@VÁ™ÕE `r~§…žþjIn|w: `– i�K{™å%JƒÛøÂ›€Ï0½Eë}÷È1ý:Ò5^ïÜÝ{»bT£Uv:Cîúà}Æ�VÀå RY†ÕJé¾l³yÍ„sJQ O›Eºj¦z{Z—·¿x"lj58PE—9ó·3vÄZh°i:ªl=˜B¥2ceÍÇ»ðO2P0%¨MÏ^ænÁ‡ì¡ÌäR˜�c!&np�]h\Evg Âu¯w/ÝF±#ø#C®[e®EŸ¹Å$d�P³V„‰RJØ4ÔUD &K¿¹�ñƒTtÍÙ3³Ïÿ‡ØË²°I°RŸÀ˜«jÕÑí­ÿ!‡uÛÍ踯 = dù?ói’Œ@¸b­DïšB'óñ8?�*æêUͰ¢NP¯ðòÐËv¦üYX8€ÐjÇåç—ùÑý™Mþ„bû¥�ÁÉ•µÓ÷Ÿ.PºÜ†&wJÛL£è)å, LKϙ݅¸µíêÒP¹yº5y¾°QEržù׆ŸÄ³Ø±) ÕŸ¢ŠCT)n×±äÏó®”zYüÛµ754Ÿ…fЂç�ú�˜?l¿âD±©ÀƒÐÞÒBÌàìÃÅ7°z4§ñ¥)é¾»êBâö‚‹pˆžF<Åìµ»ê�[èr ”F�r ùjÖ# ÇC¡¿75&ÏU Úóê|=z4 õÔ)Üý³NŒäKCM/æc<~QÐ8øåeZS`¸[�8 ��BWjœ”¦`hÎfKÌ^žÄ�µ£zñ¡a› Ø D³ÄèLouä ÜJPŠA-ŸÑÄUJ`‰+¹«±a‰äŒñÓÉEȵÊKlnç@3Ö¸� â,òk©H¨Â`’ [Ô fáÌÐ"A’oâ®Íe‰ÛÃ¥§ytEšxxFzé_<ªF;¬3ö:W‹b¡(¡ÅzO²ÂÊN‰ö´{‡+úx¥`®«…󃤫rQ9X ÈÇ äÐú}M§ç¶e¬|Ô¾”›7Ý‹8s¨J*|a<´M,„i‹SÌ_éÖz37œ™ kS‰¹�Ú$LN ·vþa'—ŠºfR»ÛÆ´ÈÄ�ë�ß¹Ø2©pX†¼·éz>ž˜°GêÎÃ{ÈxQrù¨?ž/žb1âl˜loJÍwf¦ã« þâihkYÚiCOG̾˭«�p’Ån‹Ì#6ÀQ! Z/~jú,�Ķ…�B`Ww¤“õÞzåM>×k̰@ëµEdp¹VÊå´™®XkÏ*€Z¹Þw6õûD�¸»××ñ°H0¾C‚w A©ž^ z‰d$/‘¿®_ô9ïSL]9€ð!›iâfPÙ(/ƉŠ�\±ˆîŸ(ƺbfç@ÅqO�6‡ßTízÒVXï�¯ì©X:ÉÞÿ‰÷Ê´PµÏNªPñ¤Æm Ø�}×Õ(íÊ¢ŒÛ¾QÅ,aŸ­ïó÷�ŸIûX^µPÚ9 Îú�â„êäÉÙ¢6²À»3n$P½wzç­“’>°#½B$£¡nþd3*Ÿ]|¯Ý‚rB64ÑŠ(‹å²A¨¤=i>õ`D�ºz¥¸™ÜvW¢øc<,AÌ©õc™˜É°µÆ×²wù�Oi ¸÷¿gK²³p“7”›çþ0ÑP÷}6% ´ ,�k_‘Ûûçcà`ÝÚ½ö¥wÂÖˆ«ÿxØc4ÀìÀmm¶iÅHó(VP…ªLú ^8gÆý¼mú“»y]ÿJ5tîròÿØýÅ ³q‹±i$Ï}�2áuŒÄ‡÷zŒœ�Zó— csÏ­Z^XÔ¦’¤;ºÖT¼at�˜|ûº“Dd¼x§þæ/Œ5c‡A#zÛw5 #‡É®st”íyõÈtsvmLf5}|xáÌűݪfǹ.\$ˆ †Õ7×�•:œ ³)°"ñÎuuÄg³xpËfb(ä˜È:k”N Ð/IXhL5Gf1-zó9Ôø§Yí ü‘Vs m¬p«CUOlz®˜äÄÈg{â‡Qކ9ÄSN«8;u”|YöÆ­/*�·øú@ÏŒg�¸ÄJ!3‘ÍvÚø-¶#cÕ ãE²õÛÐÊ–i:ÑÖeò—ï–%åX­ê9 Âdm?%#(18¼xñÑÜtÅòêWm&ª)‰‚Ú¿Sqá{èUe{¡ZF冰Lz`߉mØÜw¶Í½¢"[«�Tµ>¤°{! ŠÀ/úMZ[•º.à$îr€ÂoS½5I\›µdžHíË>'îôï‹�/c{æNUt?ÂÄ%Ýë8&!ݼޓrŸMcÃÚÔܼY(®h@:ÇÒëýÞ|¿ß�'s韉ZáT-ùºåšêxëáªCüÞŸò)ež�¾¯«qoÿz’B£i´Ø.Çc©yn–u:¨¹Ôc1–º¢Wn_²ÿ¯ý¶  ä;² hö¯äûï‹mD,„TÀÖ[é:SÜþö$†;âŠöì³VKýç2J<�€ÉqͱÑíûŠ8[7‰çÏ·AP•¶Ú$iþíS¿ÅT¢ïoáÿðÞ¾f‚@þf¼.§8ç·/úÙc}A”ÌK]ï2Ž�eµ|3Ûh‡ü("" ÔiŽŒÜ&†œIï4q´ØQà§ç%V»ÿ̫Ė`¼âžËñ.Äã£QB»²œlmX²ÆDÚ°&*þÙ⼓,cœšÜ|¿³Ý*8—Fv¤dÔÊP5üE môWK�õH=rË·»ÎMF¢}8{@³ j¼rÇ�'ë6›®©™ò @QJ#³üþ†9’ﻈ(�fíÓ eÙ',lðÑ} »>Í«Èû0®1ˆ‚áóØA©­�e„wtŒþ6|¸MAàSH®¼²¡¡—ÏHèn[À¾€eLËhµÔðÅ~Á½;¦6LpýDO60%'„õþ@ <`G/eÅIŠÖg¹^%N½°¿dmF™Á=¼.´HŽÔà‹w,¿®yQ¨8+q/³;ü4�±Pþ)¯ABt¼Â„]Úª®hh€ÁA€ÃD˜h][ã`·b±-ˆüVó�ϳë^Ý�Ld Ô¹ÏHÜä¶P€÷Ö Ë)P‰°° õ›¶Œ§®ìâk^r{ÞÂ_·óÁ¶ÖFÇQ"†nœyS•tÂÄž_¤`¢™ ˆFhÁnWA†îDôü3ž¢ðˆóí1¤ÔS ½ÙÏXÇ�£ÔGQw½n#]R5hqT–m‹B‡�¡(‘Ú‘«‡v|§Q@à9Í‹ä³D9Ñ\�:y�ùúÅVÀ[§-,„Kª .÷2úÓ�ÒäaȱÓèU€ºÐÂP�OU$Üó8úê|aæñ®”‰*/P:!³ðn•ˆ˜I0C‘xÌÊY3ƒº¤J!•ë¨^m(Â7‚ñÆQ¨è´×€· ËNªÞ&Ö=ãÁ Á‹“#îL†æöX"%´qUi ž�”¯ø™Mct¸øiRé{'üªNuQ&ÃÂŽyV)§õ†ÚôxgÆe/nnÆwеÐMŽI``¸rú+Á"íöl 7nëKÍ…Ñi…JõSžÖÿ®#Qéþ:Ej,¡.}ѧò*5HL¾ ¤¨2¯{›jýM»€–gúsùirøÏH—»»v °aq€‡[y!ˆ·nþnkòslL�tV6„¥¨49Á”4œÍû¨Z—ÄZ¡Ù‰FK¢àR+‹rúÄ¥fÚ.“eòÅÁ:šRà|‰>”ÓíK½^³ñhã^ë�à>Ñ«=€9pv²Ùùòøº#Ñ5ÔŸq=Kå‹g}%HWbb)мû'þ*!ùr ò‘ÂÉèW�Ã×çœ1ç+JŒaõ]�•Séa"¬È¼ø!ùCçÞ ¿Žô~�нÜÙ 7+äa ãp´Ö;xݴȈ#ºþÿ/ê€#]ì³ò^ÆéAxÌ݇¾Œ“We‰Õ*¡J!O´èG;B› @s¥cħÙsÿ6><| uiÔg%‘/¨­˜d¸«ÜŠÉ{1óókÝ¡ ( a#ýØÁâ½K^ÒœF%jëºx(lßG•¸Á•ß+CÂH#ˆÄÃÉ‘À%7.νÑÜw&~wã+  ƒ)w"¨Ww:'Ð5cÐþc c'ñ_G&5$E‹ü „ßà# Æ$íq;5=ψ�¿Ð?gç;Ár»½{š�e˜Lɹvã_r vD�,Ûg ÃKx­Žyq®[¨Ç+Tâÿ½`~E°F˜Ž?8³=é¤jÉqÐã.o¥fh¦@í„w–ëKx¹¯•ˆßè ¢7¡�ŽUIŒ-÷þ12-�} “!CŠÄÈëçÍÿiSÑŠÑÂW3ÔQžâ"_Í"Z±ü×îÌ:æîÐDÆ#~�ˆzÜ”—Žª:¬ËFfOÑ(Õ�HÏIÓ>¿Êǽ0Ä­md42÷š­Tª¶)`…˜ˆ ÑUv�,hœSZF`�`]8¦M€»ôŒQ¦õõÝÒŸýÕ V,¦reoãp¹l`}Ä—Ysù,5ƒ‚¹L*‹c6¨! huW\â ?ó¥Á'N«ã'ÏÏèÎò?ŽLV±‘™X¢ßšR­W øðã…tQ4n8¬enÏ¡a˜“fÍÓ8A‚cPÿ•â îAYÊÁ†5<0ˆONШ6cÒ õ…>]šY8  ˜×⎠�4Ô Äê8°ƒªBÙ Uðm,çô0˜ÞÙÉf•þP1•Úß —ôa‰½Yüi;:Ãàˆ¥A_2 Ù®F›ˆÓ•ÂÐX€¿›mZ6i“RØ… pê²?A€O­_Ýì2Ö×ÅœLƒà�fl°ڀëúbI>AE˜,S•Ì��å0€¢©ñ)¼ÑŽ€²Âs'ßøZÅ×Dµ°az×肹ëÉygͽ®®Ÿ!ó dÙrˆ�*¹Z<¶Ý¥¹ û!Á™Õ‹<ïk•þZ$›YúPc÷Z2l@�ÄÞg¡Æ;µD‰6Ù9ˆ!@ÿpnu.ã©Þ\v¡xòÇï4B’œÅJ”ä±O3‹Eô:ìú¢ñß‘å‰5Þöjd›ÜŤ9͘•?gÁä8K�›Žø)Ét§vª(�RÅ�» L–¾H%‘IÈöwUë¢ñ —Ê× 3oÆ«`Š\ÓJŸïôßÛMß.n|{5†;;“a�òl‡:hH�íï4ÙºÜka%aƒ3! ‹íJ9@w¯ÌÍ‚ÏÂ3Æ—i9QbÐ99óQlâ¸ÑòvÏO™’j‡+sê¿öɳ÷•›èšCÓðÖÙ¬¤ûIÞfð§ÃI° Ýv„6÷Ž›ÁÒ"Ô?¹(ùnED¼ì{º´�Ð\iŠ¡Ûè¶¢}/‡‡aÆŠ«²j!sÇ.N‰4Û£bdckp9¾×HfJüft;A“ €»?>`ÂqWì nZ€ B5Ïí\óÜôì|l5ø†$Í9)Ü2Ëß\øî †ý 6èÝd™¯9J?õ÷ê$i^ÊÖé(êè:UnPÄ‘;l-L9�2’Âã  =¾Êíî£&â¤=¿Èaþ™OËeÐD”¬ §°a\6�R}‡Ó N¢’"›báöut¼4ž—¼ñV˜û¥îPúËI�Ð\w'"ñDV—­Æ6Ô½ÃõOaW©Y*sµb³"ùÃjVP¸Ç}$dŽ„Q³©3$Œ�§Î×QÅëa-ïEŸØøÃ†±f¡#Jß9‚ÿ<¸}T4†|e ?·g‰êÕÔxkN.¯ rqÊ©˜îK£ôûa±Â2K?JëЯv*1hÒóS.…·»:é³ý¾^wìAÜ‘‹Ñ"Ÿ[ØT”¦¼‘X¯™Æ˜Ë�Ç#„dUyÈ�ˆŽnõ9^sAµ#lk,Qáµä·û\¦iŠRb7^†ùž/†h‘à36€Æ´ãX‹î}“²áýû­6CÉcÇi{«�(±0"¾¬¬Çõ�^žÈÉ„�‹fÉŠ`µ¾í�×–fÉ"4Õõ/!öŸFÏÔ°D1#fÙO;-À^yö”üF5Þþk‹)Å«ëéfçÞëÛÃæÃWÍ;s– Ô—a™œ¼§¥%ãõó+P�†#·çÜ@$yáÕåÑÿðݤ=Qs:j„�UÝë— `BÀ8v³Ý­Ä U;(Uõ0%1¡ÅÉ€ÍA«½Àè2D7Òæ4Rx ZA"#¯­â'¯ðHA îkBÓîy¥e“ãñYV 41- ûÀ½ë¡TI®G‘ý -¦s·<qýå‡'狼yÅgWj“µA�ãÐ9+ðþñx©¬ZÇ ‰ƒf‰«ªW2kßêÜÂõŠHJç ™{\¾Bb�\qéŸý…HÂOδS¸ËÃÌ%¬aÝ—[!•ÏøfÆD˜”-"ò¬9€3=sø¸(ÙÜZy %“ ÿ"´�ðNÎn$›DI}FOi§Ý´'o˜p�GÃfÐã±;¢ú‹›«~M­UDÓùºte5ö&(p²ó_Ì+�œì®í®aY˜‚°]%v$³îZ0½Õy�Þˆð%Ü>çBRÊ2²TpÑÓeâS0j'gè2 oðû\³4-èþ•sX£^¸M·Rƒ¸[D̬yÓó�s\ß8­gËÅF¿ÜÒ”o_†uÐ=S�ÿòÁ}cù F²fIºÖ6w§¬êô¸¹¡‰ZéiÅøX­L£M×z)>øY9–KÁö&{ŸN ÜOª"sï¬Ý¹Û® žáуJÅ0áì+À×`Úp«/øÖPÎ<äß"Ï@Îu·Ö�7Ç›¶¯¹ùê¯b[ñ ™‹’dÛ¦-åF1×—Mh¤ó¼/°8ü¹–�í�5HWbÔPõÎðc#ÿc&MÂöÆuÁŠŸþM)ƒ¦£6 ®LÅ©C\iH)·Hqå+³©Ö§YcUçT1M5…è¾>À; ”vh/5i1 b¶{³KE×ÓÞ<\c{«‘Ã>šzWcQ<} ¨Íþ– ¶¡Ýdãpª½&¦à9PigØÒùŸ=ëÜ­-EŸ¸‚Nºðì=ì§JS:¬|Š!€X:p¾öàÇ¨Š¯Çñ—ë¿Àœ^s‘uôÚ�^èbu}Ѹ1–Ì«6ªBªÛv˜-í!2IÑ:F…z�Å?µâ¤){@)º§‰Æ‹<ãbb|ôš…E§bÏx>DZ[Cð7UeÅs`Ì£¬b[z© Ç`s6ô½únª£fºr/y9·RÙ,&%Á3â¹=£pÅhd¢ßyÙA÷Õ%¢è—þ<¯±w¼©_œ¨ý:�n¢nÌ6ñÇ‹Ðþ2²bxý¾\÷-Kð¯xîMYÐíȵ¸f¿GÅÿVøâX}Ô|ÞÄE—døÖ°ÓáXÈ/pã �©ôƒè’'»i&Ѩš-í6‘W)Î�íH9+{òá}!”6ËÚÖ®âÍ™AäU’ª±M~ÉVåC±âÃä½ÍôüZí¾ŒuuÐõ�°á—f®OG<Žû×"ŠŽ[¢ú\?¦Ã5éÆã/¼UÉ¡é æ�ë?$¶ =§–Æ]?¶ézĉQõHöh:#™+®•Unò¾®!Â+–VçcM¯ù¹O|¹ é—L)›[¸ôÙÑ*&iÖ)æ{Cä Cš°ØC�ÁŠÖðy$�oYqåë¦ìGQ0ÁL2\jÕ$#ðʘ°"©m1£ŽäèœÑ˜9ó�©A†• êbw"`p­eƒ!Ÿh=p�œà²Õar™;ò©95O»î3EÞ<ÊŸµOrQÝÃSo ‰–§ «ï¶s§ÄHŒãÉ}f�6ìOgŒ'±JýDøL¹>%}DkGÌ}½ÜÍfù´Mù?Sf„ÈDœ.á /¥"K§‰ø=ŽýbP,%.Vº;+.Äã8§Zoz!®Úñ‹'Ýí]ñœ=ÊÓK�îDÔ£R�ñé(Î'� }\|^~±å¹ûZ9u€t*pè\ƒÔÅ'=<ì™Þû,»à�Ùî…Þç*{x{¯ I(ÞÊ#!QŸÈfZ �-=•qÐóxàšs͡ѡG,‡?° gk<úBè^w/LÄ<(ÛI ¸ú.K‹zç?Cé`;µ Ë;eˆ:o¿ÑñR9˜Ý¢ë¦+£Þñg¡‹<³!Ï }(È‚ç7gFÉÏŸwšï‘�ôÿ4ES¨S�Ÿ]ˆoc–È‹< [–·„/{íêlK?¶ö8©€ç¬3ÅP½bqíDûRµÓ ØI£â�e¾_æEj£—ÇÐß�-çû-ôCÀPd“Äd²DV­§"œãaÏ12³bSâ¥W¼E‹8ŸÎB#EwoU=íœçÜ–]`gE.#åfb ›Ä†Å·KêôRGAXoæk¦.5ªÖ|Q­l›³ÃVó.èµý£øúþ1Ý¿Ad¼‡ú •ÇlÝΩÿ²#›;¼Ja¨� ÊE—&Ç:èÀÏ@Ø´u ˜¤G0Üä§–e©ÌÍÖkÙä¶÷]ì±²’;fŽ£ü&±t#Ëä6B š T·I÷ûñÒAi®ušš)žç`¼¯•Å–‰\œ¯]¸*ÃÍhúVYÑOB\W“³8•õ<š„àÃ<ÝÅFEš£§œDL7ÂF§¶‘Cs½$äbBu‹Q±ß¿nJ¹1·AÝ>¡Â· EÄ„ï8è&:î^b0øuüü8ÓÔÖ¸¾óÀJÆ€O8ü0ÀMŸtºâ£yuMg}&‰ 8#éôǾ+Xžù+ X¶¹IýѽõüHBÑÈ€Íküxˆ x!èY¸ðJ­u ¹Ð�Þ�Ëš!ÿ‚sFmp>L8¹8À%n±W ö¬D¿�»¬±×êÒ“Àã,@—˜XUÓLâQbͪ4·ö->)®OY©úŸƒ�³1°™gmá?éè4ÔŽôd‡¬Èÿ­]‚\[óÙAÀ{šâã §º©+b†d0Õ(àm_Â~®ŸEgib³„¼K†%¬ºÍý´9ÒAº¯Š‰ÓgÊ@iæÉðà[RS1h¨©¼ŸTJYH�©›¶§ånxž4ª¢­O]Åä’ßšîá,m´ûp†¡I_DŸ¡c=¸µˆõMËŸ¥8Qð/&#N5H’ß¿QsT6²ªUéŒWYV<ç;çSb]ÖUEâOL,gÀ(È‹‰8³¦ ¯~)Œ…ÆÆ(ƒÄÏHmÕ¶êpâ&)eøãÕ5 j²Hìû©‘Þ¹dV%â$â–sÁßëôciDËçm�î@R2Vlî˾>Ü Ë™"´£ïšGaùÆžeÞZÐBmI´iPÔc7aŸ†¯Î¥¡7b?Vi �A�ÛRbÄ$ñŽ£úcQrÓÿ6Ñšµi­äÑ䥑¼qÎ ‘Θ;�æ0u€‰%½x‚Ñö¤Û½À&`[0ô¯1¹> p ¦r[Yyë‰ãK?•¤ŸßXjšñ1‹7½–É8ߑ泦ÝB²ï£�õ¥ß–ÁíÕÌz˜‹ÌLwAL5ªjÈf±°ø5"æˆêmÌC:ì!Í)ô> æÿù6!­F§®îJ'ò©–¶q@ÁØËM�òù¦°Ï˜oÙ$�÷Y¤$) £v4ø#%Ïeqñ"Õu»08Î[HÍë\Áâ¤ã¤O¬g»eÉ�ÊRe_œýÃ}´Ox—�ãf5Mÿ¡©„«~ÚñL¶úlu“./)Œ]ÿŠE«îk‚—Êã\îÿhðè¯)Voô uOLOýÉ”ÀBTVv·÷ÐJÔí$'ëHOÕ:…Ä3Qám¾ "ìm=ó7ýî+ñÃð.±ÊÄQáûå=S¢‡0‚°çýŠ8È“�°ü{w†Ë’幨Õq‘º}·.ÌØž,o;F̾4eN&TéÏëÕ–í!iƒ¼fv;€ _‰pN‰6©î@"d‚Éreòœø­íè ³…7‘->_+‚�hnŠZz¹€22WJB 0Á†‹_=l­5»)6‘jµ&3]Ò+ €€À«Ãm÷É ³§soÕßEHŒbÐò-°Rœ9}¸Ø2‰lÑL±tÚð~ës²�s´R~RYy"<ˆP^­nïRp[ûƒd:Á3zåÿÅôbT¾ˆm¨ {=ì’eša]÷ÅÊ%ãÊì$þEDeØ>hÎ^ýio^®Q«Õ�’üžXLkÈ‚ˆv”|ùn×ué»N€v|ìs%ôˆÐt"ijU¤â®Ê=Ü`3®:<þ ¸‘Ñ™Jh¡÷Žn<1Z=8A¼dt!gbA#_Jp€áݰåôõ–¾ìÝÙ8ŽE«¿¦b[�¡AÃÚæø·DW Ø€Y7MϪ¡úYŠ:.û1°¬dRn §‚��àmª¦|YF IöLôK|׎ÄV_JenÛÙJØ­IÔ�/Y‘Pgð œ&+&GªÜ�âŸÁ�° ><ÜWãÃþîŒ0>¬»ØÅ›l?°2Dk¼ÂlŠÖáºÃ1­:÷� åíÕë? Àq1&÷Û4!¶c{fDÂ�Yó)G†\æ–…ãr\G†IÊÌš[Èí!9¹åRDX£æ¶6Däú¸„¢FÎùλóy~À÷í/Q¾Ì×ï�ºmm�"55Ú»¿®m­êèûUÔ&Ñä½7ºÈŠ&˜•Õéa$¿.‡ÂOwXv‚ÅU«A¢OüSž”!A\K�Rßö™èÏ@çLgG±(xi¹Ê½Ùm»’äÏ‹8“¦{!õm†Ý¶X•�ïØ_/¿%´NY ¹{³“БüS²B55ã¶M½К¸Üæ»g´M·øá±O2Û ¡ Uhà¦Ë€ùæNÞÅÝ ú…?Èi©Ç{Dw•^4ì7ŒM¶"à ±¯ßqòR�: ‘~+£"¦¸Z“6Š‘ ¸´ó|"ãð0€&²º¢óœÒ™Þ;ÖL úÉëà鳋‘îg ®À�ê§Á®ÒZ1 ñ?y7úʋƅpøªuÐO1Q~ÐŽc¥ïçZU_LÈnw}“wN BYVèqCgÂW6Gf£‡ÀÅ¢ÚHYмõÔ‰¾£9;¢2Côžgøq¡.`%›ž{±H…9,ÇÅÑï‚[‡Ï¹fÄTÞÕM@e¶§„ˆS–t@äÖÚ²hët9ø÷ZM’i«©?'VË/7�Õ¨÷;Ó²_¡LÇ^ÛR»|”ò¸P[åEá»�¨P*3(’'ˆ¨w²ãý';î8mq§®•�"aU|D­ÄÝ3U~Ñ뙂²JËÄlîåœ^W#�§„ˆØìöôL¨°½,ñ'|©¤ø¾Õ^n5±ï_,škœ_¥¸'A—ÎP@Ÿ³[û™�®Y½OÞÏVŽÁç>áÄÏc¯šš¼3£;sÎ ù¬ƒç°j‹ŒúCÖ«L½ ÕÌ‚‹�º'É|Ì3]h>wƒb[R™e/RßTý|T´]³A;†Ðî*Ø×>-æ¶·s�¿ª½-Q9±@Wý"OXáöûBfÄHÞ'‡3qÑíŒìäƒEvŠGü¨c¾f§ž!ýXtŽÛìÿcÉ,s¯ ¢yEÄ:QJ}˜Z 4É�;¡QÐxÖ—¨&¾ð¼åµYÅnºBÇ,ÔW¢Íê >c~¸jÉŠŠö¤3h‘hÂo™.ER»�k$r\¹ê¦™nÓá ¾°`Ž";bX‘ýžç7 2Ãf˜Snuu¦» Ô‚ÑUˆ¤Óµ+jQð_‰ ï)Z1뎨‰ïy®GÎöÎôJ «Çj³–G~z=ÔÉe”ÔdÖž–Ë¡šI‰‘ŠŽ›æÈd›]ŵm!çÑ54Ã7^Íq�ð¼y´+8v°]çþ8Kò]‚LJ'ËÏ^BÜ¢|Dăƒ³¯¾r.þÔÄ€Ç÷ æSîÂh�½f›5kýc¤”tÐøçîH2þ Ü+œ,2ž·wÍCž¾oÇduÁa³b…1¬*}éÈZ ·‹zT©MhF4ãã‚Q>kÚ«Q n £Òª´yÊËa†] ŽÙ¡{`ÞúQ¬ …³Æ…÷{­]ÖùÑ]Ñ­1Ö:ºa6ß�ÏÝ«kÚésHè{9]K…B ™£øiµ¤Nç[r;_«ûâ»^L%œºó�rò%óŒZg¢U>ß5Ño«¥m›ÃæìÿGPqQ·/ÈO†½LâC!!¸ºÄüˆ²MÙN�~äŸ:|'2´ˆ_ljVÿª JÞü¢ÀÞïsgg‰. ¹ÝÌa—ªÔg—oi¬+^Ô¯ùm­öãêäí#$x�ñ÷!?ÛõFž/åE,IË%ØÏ¶°ac·Î/Åî$P*ÇâF™@5sWZN é")N¢��Ï:>%ƳÕ�î†0ßþ2SÁ­SÑ9ûG¼¾öUIäVy¨WÁà£ûàHeâëñeáCÞ@7dä{h2̆Œ<ÈžüØ{þ‚“I•Ój€™$7ÕN4ÉYÃ~h·N(;qxY�é©0KK—ÀØö�†4ê¼×· @Ìê|�ò´zJ+QÍbðÃ#x�Þ `¼É†Ü¼`c_ <ÏÒ¿}Ã\ƧÉCyбßÍÅtÔŸ×ñ›kÞè÷ˆ;ùLÞÊ̘³Éþ“þ?ð¯ˆ7ý}"¢ÂB|"HBB¥JC¥ 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 xœeŽ» Â@DûûSj£yl–*l„�Ò†x“¬Ä½¸›ÿÇE,gÊaæ jz4ň‚c ’ úAÛÖ(ì Z]›êrn±÷^zÓ-FìZß©ÒTÿv“2Ú¤Å?Ζ Ÿ‘£Ø�Ûž!'33:{C³ˆëF†æ~²2ËhØ#(O¿PÑ›ãF '•‚ÊËuLCHkz�Ä4: endstream endobj 7 0 obj <>stream xœ+äî| endstream endobj 8 0 obj <>stream xœmޱ Â@DûýŠ)µÑ\¼SªD°BNHâ^roñ’ÿÇC,Üéf˜y‹ŠžQC I”Bž"Í`´nœÚ €±´ˆf<•Í®uy978Š·Øw ñ8¹‘ÑúêYBÛ3 wƒ—QzÇÓÒÜ©4Týrt–¯ŠüëØO“t®��ø¯�äÝ=Å�´†ÞîâT`²1­èi•4¦ endstream endobj 9 0 obj <>stream xœ+äî| endstream endobj 10 0 obj <>stream xœeŽA ‚@„ïïW̱.åÊšy´0èˆx{«¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC I´Bž"Í`´m]�ÆÒj·G”Ê–צºœ[Å[ì{†xœÜÄèü Í"¡†ûÑË$ƒãymîTªgt–oŠüêÓ_γô®[œø/>yÃa xRkèøK!0Ù˜ÖôÕ4U endstream endobj 11 0 obj <>stream xœ+äî| endstream endobj 12 0 obj <>stream xœeŽA ‚@„ïïW̱.µš¦- ºâ^ÅÞê†í£ÕÿOKt(š93ß ¦gðAS!‹§ÐÚ¶V¡€6´º6ÕåÜ¢œgém·Xqk}§JSýÛ�sµÙeÿý(]F|FŽâ {v=CNvbtî†fß Íýèd’ÁòŒ ´øB©7ÇN& ’} žÉ„´¦�%47 endstream endobj 13 0 obj <>stream xœ+äî| endstream endobj 14 0 obj <>stream xœe޽ Â@„û}Š)µÑÜ™ßR%‚�rBÚ7ÉI¼ÅKÞ±Pœ)‡™oPÑ3ø`H! VÈ4tó mc5 ˜žV׺¼œìçY:Û.VÜÚÜ©4TývumvÙ_%ˈÏÈQ\Ïž]LJ“�­»¡^Ä·Ãp7:™d°<#(U_¨èÍñ…“qŒ8ÍÔ3õ!­èŽ844 endstream endobj 15 0 obj <>stream xœ+äî| endstream endobj 16 0 obj <>stream xœeŽA ‚@„ïïW̱.¥²ºy¬0èˆx{®¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC)’è:C–Ã>stream xœ+äî| endstream endobj 18 0 obj <>stream xœe޽ Â@„û}Š)µÑ$æ·T‰`#„œ�6ÄÍå$ÞâåÞ±Pœ)‡™oÐÐ3ø (F£H�dPÚv¦D5ÒêÚÖ—s‡ý²È`zoÄ®Õ�jEÍo7)£Í®øïÇ™Ÿð9ŠÙ±bq23£·7´^\¯ЇÉÊ,Úð‚ ¼øBEoŽÓN¦)Ò¼ PÇ4†´¡•Ü4F endstream endobj 19 0 obj <>stream xœ+äî| endstream endobj 20 0 obj <>stream xœeŽA ‚@„ïïW̱.¥¶j- ºâ^ÅÞê†í£ÕÿOKt(š9ßÌ ¦gðASŒ(8Fž I¡´mí´¡U– (N—צºœ[Åöìz†8œìÄèÜ Í"¾šûÑÉ$ƒåy­ïTiªgTšoŠüêÓ_γô¶[¬¸/>zÃ~ pR)¨lš<“ iM/Q4C endstream endobj 21 0 obj <>stream xœ+äî| endstream endobj 22 0 obj <>stream xœeŽA ‚@„ïïW̱.åʪy¬0èˆx{«¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC I´B‘"Í`´m�B ci•'ˆRÙ2âÚT—s‹£xË�}Ï�“›�¿¡Y$tÃp?z™dp<¯Í�*CõïŒÎŠMYüO}ú÷ó,½ë'þ‹OÞp(žÔ:ßŦÀdcZÓ %4= endstream endobj 23 0 obj <>stream xœ+äî| endstream endobj 24 0 obj <>stream xœm޽ Â@„û}Š)µÑ»˜ßR%‚�rBÚ7ÉI¼ÅKÞ±Pp¦f¾AEÏàƒ! ¬‘Eˆ˜m« ˜žV׺¼œìçY:Û.VÜÚÜ©4Tý–£\mvÙŸ�,#>+Gq={vCNvb´î†zß ÃÝèd’ÁòŒ ´øb©7ÈnÆ1â4TÏÔ‡´¢àk4š endstream endobj 25 0 obj <>stream xœ+äî| endstream endobj 26 0 obj <>stream xœeŽO ‚@ÄïïS̱.¥æúçXaÐ%7ð*ö\7l­~Z¢CÑÌq˜ù jz4ň‚cä ý mk3”Э®Mu9·ØÏ³ô¶[¬¸µ¾S¥©þí&E´ÙåÿýX-#>#Gq{v=CNvbtî†f߆æ~t2‰±<#(S_¨èÍñ†ÂÉ4EšꙆ�Öô“P4@ endstream endobj 27 0 obj <>stream xœ+äî| endstream endobj 28 0 obj <>stream xœmŽ1 Â0„÷÷+nÔE›ØÚ:ªTpJ#t-õ¥�Ô>stream xœ+äî| endstream endobj 30 0 obj <>stream xœeŽA ‚@„ïïW̱.¥²«y¬0èˆx{®¶�Vÿ?-Ñ¡hæ8|3ƒšžÑC)’èE†LÃýûy–Þu‹ÿÅ'o8XŠ'•‚Êw±)0 1­é}4I endstream endobj 31 0 obj <>stream xœ+äî| endstream endobj 32 0 obj <>stream xœmŽA ‚@„ïïW̱.åÊÚæÑ K nàUì©¶�Vÿ?-Ñ¡ ™ã0ó *zF,)$Ñ &EšÁ>hÛ8¥�Ãö´2 ¢T¶Œ¸ÖååÜà(¾çÀ¾cˆÇÉMŒÖßP/Ú�a¹½L28ž×öN¥¥ê—£3³ÉÍÖP̳t®]œø¯�äÝÅ›ZCïöq*0õ1­èfe4  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Ú�:ÉvãF’w/݆Þ1È[שÊU^¦½=Kîy¯ÕuˆÄ°Ðjùë'¶1U5™‘‘{ì‘Ñf¿‰6ß}}áûîþ«ÿúÖdeCc½¹Üäyh“ME¡ŠÍæ¾Ú<÷7¹ú›­Ž£àÛßï>p©øûs?qaZ ü�‹¿Þè(¨‡Çþ±èÊZ:?ò÷÷±nLlïN…kû¶i¥t÷²Êßêªzæâ?n”RAÑí{Ø ­õ& ó4R8²ŠUÇvGSÒÀÊ»‚05f³] Ý®Æ›V&¼¿É¢–6ö¸¦? õŸ\úgQõŸÕü-@<ÿ‰- „PfF‡Qqaý…w›¼z“§,‘s¡*ûqbÐ\" ýÔ1—K¯——Šè³ø…vž™‡âXÏâ²>¡‚E{¿¼|Pþ%ÚaåT m Í4ra)a|ã÷Â…s n‚Øk5™¹/khû¢BåfUüšZÒ¸cÎNƒbO2^} Ô¨rå„ )yÀIaì— Þ¹�¶‹įImDyª<0üP·¤�x ×É{£BŸŽJÃ�¬…1´ìúijë®.?� `«QAÄ $$h\sÑn}äú<²\OE4�¤ âàê `‘|p�xz‚ÛtȽ©æÚt(&.Uõ©†&ÔÈXí½ú@ÄžY]B´ìš€j*Và £T¸eq·>�”4?š`_}–I¬ ÊB¤ ”wÏüe7ÆX­‚F¢ÑÉò™˜y ÌXe}šš�_ê!Í‚1ͦXR‡fX@à Ü‘dæ/ܼP97?\©‡YŽÀ5Õ”yVŒè4Ô-Pߥ§oßüú;[Áç©i›? r =b¡éÊ¡.Fq¯vb²õ—PŒÚ•‘= »ó¶*Š"�vô ¶œ ½¶‡±gÆV,göèTn/"+=ù…�((UN<�P8ÿ#.Ë ð.x�H¥Œ@"‚ÐO§ V ã{¨½(�;‘†Áþ¬Š©Ãçm;ú3Þ”ÖyplÊ¡ß.ŒeÆŸ1Wge¡IûéŽ`¤X“E¢C¡NÞðAa+°3Uòœ²NvCã,Œ±Ï¬S#±3±@>•à=«€ìÛôQ‰„¥‚ÕÎð�àü@bZSÁÆ~D!6à:똑÷¢Žø°} õÉø×7¨œN² ‡˜t„‹cp{*Æ‘—ÆÉ¡Q.àGîÍ7ã›s}[K/øÊjXUÔG¢¬<¤¸i°_nÇ^ºRñE«Ç ÷‡º$ Àò3¸—(ê òýUG*±új ñÂØÀòÒqò9rC�lj’œé(ë¼?�Ûb`w àÄ ØðH"AÈܰI¸Ç$A?-Žü)n¼[®´h¹/hµò“_'íˆõÂYÕÉ‚¡¡¨*�žêìJ”\ÜòxîJv{y¹z}ÏŒÄjÆ;9*Z$�8º˜&Xž§ç†8ªÃ}'§è×TçY$0QP¨ƒ²óÎ5²¦0˜2'fH@$~ăC† ¿/Ž´¤±Dˆ^”EU›‚¡,«üÛ_ß3d¬'�Ù*èö#¹ý1ˆÿ» È$BÝá%T\ù÷¹)|¥Ÿ� W²,8çÒ¸ÄzV1�Ù…s‰À¥s‰�†‚Li�ËWÅRЊ Y`#Y¦è¤ ŸŽõ’ä<âYb rßÖ.CÛvéÞcë%ø€˜?Ñæ9Að©ÈäÃ2švØJìè»|çÝÇKruüóÛ;†?Øø£À~¾Ÿ�:vbbK}-ïƒ?õƒ Š„WtMíwÔÈÈШ ;vÉ®$Wn_Šß¿¡‘žaÌëë;îôݯ´*@}0ÑG//]À~ÄP®l"ƒM�òAsêçæ¸c?(ÇhÞPÝîë¯o`o##óöîG×ͺnoOH)€Þ~ÿç²À ûXpc¿ëû=Ý @Ù2°À5w¡ \eòouõ}1ÉÔø]{½f-˜ ´1”ï:ÿ(¡Ñ÷ ò¥Ô£Çì†"Èû¹ƒM\‡z*?£Ø~"â² Z´KZ4WÑ3D ×¾È1o$¸�´¥œl`ógBio3Ë�]“ ¶Í Êæ°â×ܲX[1—a@ä¢M<÷¶àÈï¦áQ\ïF¾/Ä9@²˜c›ÿ±ÿff�ŒCüTræOŒáŪ^�ÇêV.Aé½ ùá­�.Až§¢}ì�×=Á/dKjiÖ`3Ÿý~äaÙFp9ãÁ-Þh«B½‰Ó$T.@þtè‰m¢9|€«P �z$lò„QÝMÿ5W�ËÉíDtrÏvD1â¡t¤ØW]QH×?-ªYÐ6».–‚ƒJ¼D„ƒXwéx”à) ‚O}{ÌoÑ b89Ó,î¦e£€]‰×m-×vç²9¹'paЇ×ì¥Ã8qöÙ&·ùõÈ6¿XÆØ~á¸\,c„RˆÉÎÎ<&¨ ^c.b&ðªf„åq,R/4Ðgc“ôÔ�ç7ª<4{ù.(ÒÙUýy7y)»®Púƒeôey>I˜ ëV<‹€®a‹ÖNÂ�ú×C‘;å‘¿dxÇ>ò‘‰ÁÊæ¤肪ÞAeäÊ®žž(ü‰ —Sß±ÿ�u¦£Ü€“º‚7þ�Æ,qø #´«T2°€ö¬úHl™÷Áš—‚4¹‰ó¡\ ý™xÄæÄ7Làý×ÛWÀèZ¢–-$(*O›%+Ë.ŽŠèÝîkvÉI>˜ClæE$/ßi¸„|t»ñ[ð@×®)ÝdWNwédŒ…Ejðy‚gŒG‘¹]Œ�3½±à›‰¿�Ù9 W‹Xˆ'Áëø+¾,”\ œüà…JI�~1@Ë>µËœÔb“—Ø>3l<ïþøvï¸e¥‰!"FaÆ�ºŠ–�bðûÃOCýHF™I“«Ë¶tçL⬯9•#ÃÎîS^¶­ô{S”ȉõxj†eR¿TÕ%?¨5ÈpŒõqÊV`�SX:�wm3ˆ‰�…z#�z˜a;[dß}²{ŽqÄÑ%kå+åu1þƒ³'` "qÊ;ˆa{¦@G~°.&Éë–ð¼¶<^©½VÓËåÞΩäK˜Ê¦a‡Å1*‰ ¿ˆdi|1#ÝJè‰C¿/#Ý¡ð-‡⊵‹MÓŠSj›¿pE&ê˜DþtàØKÁ€ª…ßr&8š3SE'¾bë~~áŒ\3§ûd4?{¬e Ò’ÄÙ¸p–’DP†ªl%C¡‘å#Š¡<4°ïyˆßç%Å…Ä‘äD-­æ7I—bW`¹éèx]&G± •hŽvE+©Ù“'ëxÕ¨¡Ô:òUÙ>¿áTì›ÅÖõÉ‚˜‚“)¥§´X¢€2v¨šÇ­ßÆŽt f„ÄQÕ™K‘ûc„¾8AŸ»ò0ôÎôãÎfîù|à ­{M×sçb©oØafuŸé¥k‹UF™YÀ?ïO8S†Ó$†c½jAÖ˜a¡­SnÛ�žñ+¥®¨a»ï7`��ãð#–œ€®×ï•æG s>×#Ó\bÉRöñêÑ��sÒçèåÐ:¹Œ�Îí—ÄF-¶b¼� û,r©>)æ°¥X89uaÁãÛΉ÷¤ñ¥fο¡ˆ}%ÿ–8o†3)XAÏœîG î8‘9`DÍÃ÷Ã&Ë%ŠsÌH/´['-æ>Þ´ùœ»³FòÁÚ’-ŒÉB‰wþ :Ö ‹L‰³ÉÈö¢�ËEà*Uxûj„‰¸U²d¢P"o•˜Räš�MNæ@éèWƘÓ8ŒîÞóÞËŒça™Â`¢çK¹èŽ…“gžÃJK‹*—;!�Œ·yïô’‡Ë3—MÌWÛ¥ÔÄüê°ØM,¡$é;ò÷©nÛ%$§ÛöøÅØÒ’*Ñ⺠@ÖL |”æÈ-,^Ñ}¯¹Í°ÖVv¡µ•FÝ:µ�§ïÑí*‚å(‡4¶ÏPª¡e«m𳤄o%S's:óv«LFôðkÁE¨où¥Œ‹È÷Œ¥i'�3t l1.Ùj§ÓŒ]<Û1’7ö YlËO¥ø“ÇEÆ®ðÔ|¬'XÄH6Šbg ñÖÙnû¹X=åËÝË+ÎP)åÒs¬Z¡�D"\Bж²Ýq@ ŹF£Ö°0˜®íù޳Ç"(RíÞú¤Ús”)ÏO�:í�Ï\[çÔÓ×^Žá:oùäBe@c.ÆE=ðt¸mB]wsµ@ý Mœí‡¦/æYèI†k¶ØäÞ—>º§¸/d‚^<’x%Ë›…Y’º'—œå½<ô}Ϥ?Ë›„Yj/‡DïA€ÚfÅ…{DÝ‚�dÌ#¹}Æe ¡ÀÙOÄ“—+žS�Ëή_�!lö²ãÜ—\ðƒ‰?Ò«‘(x[–ýP¹ ¬‡­L”;7Ÿó´Xãzb Ìõ1„ANð¸4µ`7K8Z.,(ÿÓ�3nËÇ�8ä P¸ÿŠcÅgÍjN*`³HU# µãÖ“PÂ\„·­Ÿ±]‚•, Noj¯3~ˆp¯¸¨æ«Ç”ŸÙ±¶éâ–M/ù!®> %ÁV�–‚¥Ì6>¹ê–Ã~TJ†3ŠM_ÍÃ�ÓÙ½˲8�/ffוQ¹°{?g?.ž¤vñ“(—7~vùÆÏ’.R�´¬Þ#€�_ úÃýWÿÈNÕð 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 xœ¥WKo9 ¾Ï¯ÐmÛ3Ñûql�v»@‘ÚíŠ=8ö$vkg;iÑ¿$¥ñHò¨]�ÅÉ�úDQÔã�`ÿÒïr×\}pìîІû»Fzí™T†…À™6œíûæöU£;Ã~4dË>ü9©5ƒéäDèà™Q8Μ5ÉÉÔçAs‚V8«kè©Ï‹gX0Š&³›ž˜5hk Œ­gÛ¨À³Mm›uc!HÍmg¹U””°0ã¸ÍFƒF-Yï™Rz�2_è›t­ï„¸#ɘ�ôÆÑ q"�o£y’r_èûŸWì>ª\#" LÍškXñ]^:+�J×À饦k¯ø,ø©¸+ØØKM6¦%�æ¼P˜âÞ À$:‹[¯¤ùpPš�bÎ룘yŒ ¬J”’(¸Ñƒn>Ô&D\™NŒ“)#’‡] Ê IqCé­‚*œÃæü†5îÏ Ç_›}„~¹ùúŒT�Üæ8$Æý—‚‹|8ú¯EîóØ ��ê#‘$¦í'Ý|Hèû1hÒæ»æÅ_ýþ¾ß¾œiÞÎaéŸ`ìá¤[éÁþCê‰è£åÇs¥ñØYêí†öh�g­”ð6Oiîkh”Æ‚‚Rª‚¨˜ ÇBRIÞ�(wVtJ©R(®n•FøÂY‰SºN�Ò–C£”ñYðSqW°•¥KL׿’uعóŽ/>“:tJC:uãÇäë1ï\]¬slþwóâéå <8<çγÖuÞrèžç«¤ÚÊÎ@Q•p’:¡!œ¹Æ™ˆ¨�3@l%Çœé !�Òëoß¶›åâqóß=ª ¸ùM¼û8{Ën7Û¾=ü<<ö;¶Zô»¨ôÜÙ� H‡çã¡ß�� åêsñqtâÙ‹N{¸&[èéIëéÈDù¶3ÁÄWò’=·êïÏ¿Ó*Ó‰ËòJX‡Å–¿Zõ߯nŸýqÙ+—+*‚ÕSsâó…Cqʪ¸õ”�ÛÍÍ~±ÿ9Œ3ñÒª‚™øü‹ÁTY¯õ÷&eøûÇu¿g_�—f~›ÒâðtÓðpŒóºù™‘J� 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Ú­<ÛrÛF²ïþ VíÃ�ªL3`€=OŽm%>‘¯%¯7•ä"! kà míן¾ÌrHQ²KUÂÜ0—¾w£‡ÑìvÍ~z™ç�WÏ~8�óYæ©LgW73-gZDaëÙÕröGpþáòõŸRêþ®¨?ugó8Ž‚uQÕ«{(Ë<ènëïJnèªõfUrã‹wo¸±ê¹aÓ6g" >W˲ÃYÏþºú?ØÈ\ˆ0O^qUõ=N D|9ƒMûÉ©W–Mm55?·õ²l»¾¨—U}ËMUoFWu_¶u±âZÑžÉ(˜ûV_ÜU}¹è·mù¶¬²€Ž³.ë¾è«¦¦FÀx°,Ø”íMÓ®‹zQrÃRÿžÍ•çxÔ¦õ­Òl[žgAy&ø¯Xmil7ƒþáÈØXvì£ÂS`�šÇss{ÝôÜÑ –<«#Nÿç,I˜W ÜU·wó•Ù ì¹\q; ©º­¹|�Ûö\)V]Ã¥®Y—vp_T+3csÃO‚?ÖSh§¼´µ\o*‚ªðØJàƒ•/%?ÿŒ" ‡æ ltÑVצË9žçð×EW-pW‰`4b¨·æÎ/“€øºY©sÇ¢lû¡DÑ@µî‡*ÄKQ½Ek¬-�ð¨:¢�r;žB™É¡Z×ÌG:ÃB  ‘Ô@ïo—e÷w 쌠ãÙAW®„%žUÇÁEUo¿bà¶-¹ I _Ðð8tÞmÚ²Xr϶+a×qÏ2µÀR÷ÿ…™}çF‰ Ó8X4K*²€†;4´EÍ-Üe[!=tf¸éfZ}‰8ÇN x‚¶€dêŽ t´™š)¡ÁBÚ>!¯�” òGì#‡=w›)Òàš6[Õ5É�Ýe|dß6ÿŒ ü¬BŠ`›‚\±°�SËdXØ/¹d(AQ]·E{ÏÍ‹f½‰á9ùßâ,½×ÿ‹”@ã¶Õl°ÀûÄ3/´|–a*s2²<Íf¼hjä„ÎOj;*ò ·`uSô‹»²ãÊ—»jqgŠ%?—Õ ’õ�´ï3­,VÛ¥—ÚoÚf Ü%)«"푲o­óÞ8„ø¶X¡^Ã/R¬«a�-ÐdzÕ4ݯö 0‘¸Á�œGFN £"±¡Z—ÜDðÏ@ãQÛª'2Âf#Ò‚œÞú«QÆ9€ ŸÙ°Gj\ÿF‚í7e�º­ãnÍAF1â, Âø/e[ò˜b¹ÜYÜ3ÉŽÄJ3,u©C,2“@¡Tt¦Bìáö:*‰,ù ׂ¨„%ÁFÉf|`‰F ì@ŠPéœw C”EQð3j²‹Ò%bM3¾hÏD6êv¬í †Ðë«g ÑL gY˜©t¶X?ûϳ0Ñ2æN§H]öÓðÛµ˜½jžýþìÄvȦ�;ó’奢Y–WªðP˜å°¸Vð4G;?C¢º…-Ç:0À ìcáÜ*p<¶=rA¯,°m86Í áäìö¹c Î%”eÈVa’ÊÑt@YB$ÙUÑzlž?\QŠõMÑöf‘ô8dËíûû–EÉâ|޻Ч4¿&&VðÎQQ–Ox–™U±¹ [cŽH ŠŽ\µÚ`:™‡è×ÍrKÚ”.rßs4,5H3´#°qÕÀ/Ôœñ³†èÀí¸¿`º !.’6šp*ؤa§¹µ@t´GÀ:²œh—(¤ÅH›?,ËÏ? âD‡*“väõªY|ây—–çE¦Â4ÙÁúçj�vh*æ<ó{É�¯È#mÒ2L?ùO(k®“3xC6…}åºì¿”¥éPêµp6ü:x, ÑaDs3‹8e,Dì�LNNb¯‚Û²F3é9Ã{�wÑž¨CsRhŽw\4Â_¢pù϶$AŒídýø0“†Jž†™8ÔyfG>Gí/‘è~v7Q(¥Ú1îˆðHùÔËAÃ×\BÆì26«ÊV® D= n|;W 3Ÿ°ñÐì4~ËÃwÂH+Ô¨(ÀšøÁp×GuÜ:q‘¡Ûë"ø¢! �4øˆG>ÄnÀ¾:2F¥b XLD¡ãû×:g:œaöYø fk„Ú`ÛK0âA­ƒœ�B; ZAìs¡m¶Œ­({Ç-0Ñ1q!‡õ‰€�úŽHÐß'g5ŽRkWMà[`|7‹‚¶DÕq-ßù K°{Üõí–ðÃ.´1@t°ÙöÆëæèTTµõÂéam�4€Ù¶¥qÚ_˜i{£w×Þ4 ^PïÕ°ÐÚ²VRc­cs·½w�0Åf¸ƒkl'9ÍÛnë•ìµ�ÅC4t�ë2mív *Ó ®s_’ñ4EöTgÐÇRŽË½¥òÝãW Je© :°ÂîÙ¤b·�Ü$psidš¢à¨Þ0ž¤ØÙÉQQ‘†i¤¬¨`i•¹RªÆaÃvsðÃ;ÅÛ1Èßͬ¶I`¼)BE†IE4 ím9G+ÄhùÄ€{&Üõâö Ã5¸‰ÈÉò'Æyóæ9{’DÚ)XíäƒÅ&CaîšX|2''Ð Gã"u�‹<Ú‹mXCÓ‰T†¾;±DÝq'ù�cEqsuo‚(jW0ȱowÖû3J¢2¼ MÈâõ×^A“ ˆ‡"c•‰|˜ó£03¡�‚d�̯ µ8!‘t„‹Í¹×yšI¶î,�³1vn`5ˆÐ\�ÐÉÕ Íó˜qh”d>0J®Æ·�™D 6OèƒÊGÖ»YlâäHÅlîcÛfBÁÒzl©ÕBîпQ!8ÛQ%sN�Ù}gxÒnx75£ð3u@áÇ ©ãÇ+|Ä8(Ä]›WdhùdG¬Þ$ÝW9IjL,­‹–>}$VDCÁáëÔ˜C–cyž°ªñÀŠ…1oÁØ@*šDš¶º­è{ÅàcPÉ`n×£ÐBÀ¹/É^ù¨ì±l¸Êj†Øœ¡(Ì ‹òž–Ü�¢Ÿh5ÓÓ±T™7 œ �àR^³í‡®õ¶¦™�þø]Ð&‚;® pàUtàƒ†±.ˆ¿È¢È†0$Çve¢°ü‡¯1¯ â0v¤^ N}ÓyEݦ¸-M|´ Q)€ÀâŽEHb„Žõ¢iƒq_Å×p_ÔlÃmü å�°Ÿ‰¼]¢mÀ´Õ.m(Ík ù ±ƒ±6)k“&ÖöfòaŒç|e>íó*n]‡±0q-xM"ŠY²/›Dèzw‹-ZJسMÆN4Çð�L‡ç+L:ý “¤©ý :4WæëB’ê‘Þ\4áx`º¾Y4覥`ž ¡w|é�Ó—OÔÐÚí`†$Cm4]C Ç€Y?vd‡<|BU¬·«¾òeº3&Ò®Fy>:YDiánðsŒeÆ"=–ˆ,ÄPçbýì�¿¢Ùº`É0qû…®gRâÀh¶š]>ûÇÎqžÏ’H‡‘Ž�MÃ#8Bnæà¯Ñ™�1ʤSؼh½·Ÿ(~ÛX™‰ÀßPåÓ™¦gÑi.Ù÷ÙJ&C¥åt+ïË6ru¦Up¿ayº‘$†�Dâ ÙCL”†™Vß‚•'¡飡‘{£ò<Œ¢Ø( ¼Y�…h‰�£å©Éffê4hIs=Ýðˆò_é?—¯‘äÜn Ã ¿qrroðŠ&z�Á§àÒLŠÿߣÔ~©(ƒß=Ëês­ZfàîýÊYòý°˜ >Pùµ_¦¶ÇÃw—Úp†äø R["(Òwt*³8}˜Ú2¦ÊHô· Å—E_Œä&ÔôöÄ­xéÍÝÊáã7çÿ/ôÿaè��(â0‘É1¢?bpîLýž&ýi ?qƒ­¥~h�!®ö#ÑÕ‹³8&¢ÁKšùç}`ª\†B @¦’£¤�(c”H\è¯ (¿×Isg¡¹P°R†A@&vùÒYƒgqFRœ—Û_Hæ>œ¹ %a–;ùà0ò­â²ö/þr)Z`ÀÙ…#ß~¥|“‚"Oµ>y×ï‘ó+zily{,1êÅôÑ xv9 ÇŸû©B!ô‘§mS5ªA˜K”^¶,3͸ßIûÚ@Ú37~ŒVǘ Lµ(Ê}@¾pÈ›ÏpiVóª’8ÉŽ�šÖFX5úi maXìÒw´-äãYéÜQŠ¿;ôøÒ·FŠ(9Yž3ë|p ó³V•¤'Ï €Ö$¬ {íÌyD£>ZƒìiT˜AŸáA�ª¢PHõ}ì7جæs䫉6•(Ó'ï£LÝ]¸ÌÁ ñÊÏrÑQ©6±Ý>²~4&;€êGŸoÕ1Êóä›P-³Pƒìü.¨A%Æ�Ñ÷mer:mê¤?y?¤»ûùÉAº‘WøIÈÔyy¨Â(;™.)>•‰–Þ!‡GŸ|�`†$;‰ÀeQ F¾ 9ȈÐ@ yýµ/k“ßuóO^Úƒywé)V°ü/£ O!€'ˆ91¥2,ÿkjø[K¡ß?U1HåÑ ò`ÜüãÆõ鈎òPƒ*<Ê÷yNOÝŽùîv\»øòi$ @ŠDéÉBÀÕ.o­¯žû?�öc«@ùcá³'`™|S¼-Fw*�¿ ÍÀKaœ™ ×åýzUÑå�µÄÓw²O.Ó�6~w,ý]ÈïXÅI˜$âd1á³@Žxq~’x<vi"Î1ô›B}q*ÂLdÇ7z8ñAš7=’&ÂöªjËEß`Ü…~€(ž¼Q¸[yë\^9äðÞï&äÑQ}î_<¥ƒ·§ÎœŒÞÇ2ŽÄ1Çò”u€”óD�¾ÎÔÝΦîv¦ò]w;{ÐݾØãŽK§åÁýƒMœåÇ0�†¹JbÅW+° uÓÉËŒ§1v1„÷üŽt‚ê@<‘Îr¤½´q@ò<šÓö$Ì�Šü›$O…êû|cˆñ;¿²C³øÄy §}cxò>´à0ÀÕÆ¿±|á�áä õÉS¿q> ¼œ0žgê8ǽ$ó�ž‹ƒ³‹Üï=Èu¤Ý2åܘ³ûßX@Ëg ÐG rø�¯ðûßX&ûˆ³PkA3©Øa{g©"ßFö4Ñïñ¿Ô p Û¿ e&œõE'¹:Ëe`¯fJº…)Ø69^|çÉ~¤‡†?Ð?çÌyJ.…¶ÛoYqB�”$8çªqÐUÿ5ÓÓ-"|ÖüÜð+7ãÄ!¥þ®ìª…IÈ÷µÞ�‰ú˜—ar†„¬TõNºN_¢¯þµwït•Ó±×Íj9Íç Kgšzž„õ¹?`š LcSP05…ÓP4fÀRn¥»„¾ËG0–>pš!¾èæc}’ßõ�l#NÍ3“í]¡äô0ŒO$"¥&zR¢†DsÛ8ñ‹Òd$%tc£I¤Ç¢ï¾•?‹LM©f)h²|ø‚1¤—c~x–8XÆë8wæ1žšçïÑ"lêmÒÈlnæžfÔ–›Òü¦]Ú¬ùiÒ§#›Ñw&”œnXõžk‹Æ¤ùÑF¨=¥Ì{Lj½Âd,ÃE0Vð´+¾ÝGw?WÞKp*æËâ†Ýtìdzã¥rËj:ö²7Љï4e^U-»r]Ô}µÀ«ñ±Îƒn—5M˜ëÆ.ãÜÑjàØ_ðcI+—×ÅfÃðÔ&wÓ| «ðæòÕ¼D=$Pþ�3N‰“c4tC‡žæ´8|åÆŒ¸æ_¿à«j±³÷£‰Í£zÉu$ŒÙåâ˜÷⹋Ó�Ò²³¦ lu|âçñq~ô("ç^"QôCæ:T «ëé÷°Rs>fϵ›f±í¸Ø ¿ÿ`³.çàí‹]¦X•£Ìì·€·QºØ;FNjsØ`âaB¯Muµ"t*T]–À+·,Æ$Ý^Ý•h¢¥™&¾´žÝ”¤É}I¥»aÌ1Î_�ç¦m–Û¥˜f|?"ÎL#6LRL1{¸‘Z˜K ‚â¥;¤ÆÙ®JÄC®°¬ð°ÍÜ'ÂKóyF7`°—/­c?Ýyá"§*c·ÎØx Irz÷Pš¸múªèÍMJë1´¤§jHGq͹0Î £ð÷¾T«•½Xã¿ÌÙÒ‚2×,]s^X‡2æ]¯ÏíÏF@_á§nL AKæ ?îšÒÿ3'fj†šw»²&ñ%Õoû­½ÛŠu»ÁÄW¾¹ŒÛâºZÁRœnŸОç� «Øx‡õvãŽJ”a>~ÔçK);;À‹fašìh{ú¼Mü‘_||‘ƒld—�„0^Ï## Ú8"@)ä“»ÁØ&[±.{¾}L@TuãËg€¹0J¦Ϙ&y|^ܱ<ƒ:Z‰xëKjççnÛ¢Þ®`ýþÞØ�:VÁKW·]¹"]üüÐo¨x�™†ñkôç%R ”{y‰#LºHz_Öàm¡ŽŸ›(P"9“GãoXLxêËm;ülÅx! ü$q@Öàe–5ÃmAü*U“¬á©¤sßaž@�ÍMl¿eÄq¥ðiÈóÛô.�<-¸X£Úšû)7A‚NÏq9ù2dA-¼ ß'éäJ­•q2Þ ŠYÊãÓþŽùQŒØ˜)ð4÷CùUúMl­Kf¥û.'�O÷ÿ7Bê 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׺?1pöV‘¶Ð(yØ„jÕÞ:ûl•Njq¸½ "ó  (£¦!s€’�‰�„È SÔ2ª¥8´ÞÚV±^kK]½í»½½·«¾Û·öamúÖ;±ë®»Þzk½$$gŸœýû¾ßïû~ßæP (‡”PPœS±>®¤8Käÿ½š ç0Ë0/p͵ÍíDA\p~y°(>‡ žÁûž¥¸ήô⨒Қò‚¼|qÄˉqÉ¿[»vÝ¿®lÙ´ykDvÍ?W"vçTä‰"V³_ªrŠJJ‹sDâÅÙ•O7�8P—“WY”UþW(ŠŠØ%*)ÝS¾·B\Y•�]sìxÎÁÜCùñ'‹’Š×oŒ ¨ÔA*–:D­¦â©5T•H%QÉÔ;Ô:*ŠJ£vS{¨½Ô&jµ…z—úµ•Š¡^£öSÛ¨T/õ,Å¡^d“BP9Ô}Î N÷‚°U f¹ùÜÑ€ð€ÚÀ—ÏÒÏÑ6ú¯ Ü€Q°sá–…‹8‹zoYܳx6h[Ð÷AÌ’g–„`sð\.òà”æEg.©ƒ—aÖ8ògˆ‰¹VM“ãóªh²Z%K×ó%8­¤W·ô·˜]ÖVá^ˆÝôÈÚ–R[RðQ¹´.É%¸Ì+±ƒ‡îÃ�ô3�ÈÃð®p¾œÅ»g¹íKq¾›N5ËZ‘â³`ò½®–3^ì.zWHr€þ*YZ#”ããn�fU·.B\~ȼºëH‘4zŸà!¨7¥Õ¨d|)h2;ŒNûìò4!1C¬Z™ÚÙ 5}Ì–>NÿwØõ›™£<²lóZ" Ëÿ²‡à�ÁB¶ñò¼PY›½¾–¼@èŒßï<žÛ}¡JX2%û }ÿ:q뮀})ÆÅ/|#äþ,®|¼,´ÕJŠyX×Nï4ª†�!Þ B%…¾.Íh8^ü=À«ð³{þüJ|fEB¦ðК«ò• R¾ Ø�6dGð¬MsX8ŸP’Z«…¡ïá Ì oàªobæâ²PšB¤íŒ:ç``–ž#Ø>Äùé —ù¿Å+¡Ó_Ì('+ °”^i6Ñ0Äo³úVUk$ìÂr1­z]¡Ú¦‡d.§�K‚8œÆPïQ´m�=t#^8ß'¡ïéZ”¦(8 ôQJET”0çA0~ÌR¶ÝÃùb–k]ŠëÝôïM2—þ:Ä•À;z©¯É®Ó8mr§®Án÷ɾ3Už‚,QeTšð?€Î”T™§Œ•°ñºÌvc ‚=vY¦�˜�>Y«�Q³ü|ø¿BªÀ2 ¨ß”*"YÈ«žB6›ûŒ/ÿ ï†×4ê:Vsg:À³Âe¸±¯_Ú-¯³ñ5�*ójWÈ·pägËØLßÁŸðð �jZ[§kÔ!-Ò˜ÔVq³ØZ�à›qÉQñÞcߤ § ÏUŸ¬@EüÌ%){󇞈2²©•¶9,&6¢Ð'jÑwù¹Óöžnð„ÿé£éÏ.‰Ïð õqI›¼õòG{'® nîãAÍäåÌÌrq “Ä[�!íЛu‚CÛŠ DRu½VË"i4êÍzø!¹Lo8zýâP÷Ô�ÒYY&«­Dü\yïGB<ü3ðË{š ñøëiï,—‘_âéè4S}³aâÉ)¸ÕØ¢A©�¨*Ñ)êÒÊ"U1‚ÇOœâ‡dµLê] c:$Vðæû)÷ηõö ÆÆ·‹þ’ÇçüÀÅgwQx˜7=¦ŒÅK„rÚÛèÖ Òè5 š—IKØ*l׺]ÈÎGíNÛ93t“9ÒÛ4/á r!̤5×›ëØw½Ygj°èͨ ÙZÝçñóx&¬ÿN“mÀÌR«¹7Í„u‡\ý¿üˆ¥ˆ9ðGžT¡ÒÉ׻ƅ8 )]¿¼»Òw´#Áõ»ÒbÄÕÝݧ<�ƒÕ`êí†fdƒ½ÞÎ {E‰‚€lØ/­;šSY­(@…,[1ã™7ÇGNMÝ„¶&YÛ«GÂÏ¢S-ç†Ø%²ñk*Ö©«TåŠÒº*óKÎŽ -Àxc|/�OûãÜ/dµúÊÜ2Þ�ÆæT�*ÅÅ )dy5 gã}‡ýQì ç%à�Ω2½ó›>Õê·üú<×Þ¶ªœ†ˆ‚Ó§þkÅ;.ïA|¤PÖ‹ :¤F*ëœîÉF…cÓ߈›Ãp޽s»­ùŽ•ßAÜOy÷2‹?â|:‹«¿åâõsoñt¦,yiÝa%_T(MF ²!8Ò\›%œoE³…�pؼ¯ÄÏîøËš‡òS«IÓ¾©¾�ä”À[Ô¹EAÂM�ŽLÎè<ý´Ý‰f™›,í%~ÚÃYÚÛje mc½ðÒOnÒº\ÈÁ’î¶�™XÒ³àtÃIu³ÓÄÖRj4X5}©m¹HŽdâÒ"yy•DÁª»–­³[�E†`…DR^8X>vgâ ^uEȶ¿u­^§£ÛÌ÷ëá.ØÏéyÀeVàM¼ô=yqnŒùƒ\ù쑯U�ë6U6‹Ú¥�ˆúTG×Õ=“ÛÒRªó²…©™%ûÐ�ðnÀÜ÷.´ ú½]}ןzÂóo}œÞǸš-Õ4OiТóêœBæc¶m¥Kó5Ñþ6ÝllBÍž·k²…dÈñ–:�!HÀHV�çg¶bîÕ!ÏäYa4°4â5S�dí ª¯WiÔÒê2�Áí _âgpàÅ™/.¿8Iè�êS,òbàã0[ðv^úŽ£¢h‡Žö‹®Õ Õ{õ· ¾I×ÝÖô—{‹}GN%£Tt¸&§àpvén ‰àî«ü8sS£ò'¼Žç|xÖwÝDÝ%­[ýUø˜ÿöqÎbšyÓ\üëÜv‰'ËÉJ’±Þ»ñrœp:æÏÇ¿e= /g½/ã'Ñã„ë˜O·ùÖ²)˜@5¾—Ó×#²Å*÷V'×–KËÅâüüŒš$te´ç ¦LþŒ0=éûÛè$»ØyÁ߬b…gõq0dÛÛ}¿nžaûÛõŽ�¡ÎV�¨]ÐVÖ¢9ÉE{{—/óôÁ˜äÒŒ2aYF]žá yâ+ò ­ß©Qïö»~«DšÕNtâOp0`#›{þ_qÍ"ÿÎ#´ù�ñ×¹Óê;9qaæ�Cß³˜ Î ËñJ6dÐ/‘Ìß D^� gy«?¯˜L»ó^’…·¢VäD#l¢ÉwsÓ¼14!9Wt9Ý»‘@ô²hÕ±#¹ÙÉ┎2Oæz“'Oü„ð"ôcÿßG&.Œ¿jÁ߆™¥—9÷fñVG27/Ñ®³>‡8ü’}926«âà¾tæUy]¼Œ_ê/M‹ÑŒ¬Ž5×Ο`½VWWÏÆ[䇬uN=û-�89Œà¥ž¼=B’ô»kÕq:ö¦|Ö�Ùm§Ÿ„|óäµÙe¡Ÿv-Å7ý®µÞî·< ÌdcB œUn‹©ÕhGüî§–+ú]µš}�0ô0·‰W*—ˆ:+û:;ûûÅ�"V˜*|•†ŒxB>Œ?/ ]ÇijꩢC—‹Ôji¸I-ÒfzÆ•›Û\ž…2¥…¢ü¢š,”ŒÞ�DZw�Oëɱ+­U¨¾›zä�Íû¯ààT�˜ ù��thL‡±Ååw¢“ õì“äC#uÃá~ûð?¿J¸MÂî W\ËGWà•Ñó·Þ•ä� žp•µÅ²®ÿ[Æ7x8_ÍrmK±ÒMW³Ìl/=ÏÇ1G�ƒ�Ygnä7kÌZ¤ƒµµZ•@"Ç"7�i.êÈú€¬ÇIaý½ø9ÐÛö±žï&G`Øàl@JT[«T(Ùá/8ŒÙL9*QÝ!¿ØÏ›F£ƒ�ÕìÊtá|0$56îV?-µq†ñpþñÿ:Î�Kœ{…Gäú�Î]mz ’.€öÕçÈŠKÓ£‹v¢Ý(­»t²Æ[}ñ=`¼çp|ic]Â'µ�q$·Ùõ(¿�9÷ÏÝt�Ú'Ј]Àô‹ÓõÈŸRÏùû,÷ÔR¬vÓ1fµÃp2?°p“¥9š½lÃjNc‹‘íX^‡‚,Ë€!Q¡Øßà«öÌ-açúý~˜YúJc»• Y}©ª˜¬™ç†‘µøû™ºNäæ#�Ëî5Y‘ÓØjd!vHÀEvJÛ‚ óan—3Óg:�ï³Mz®ƒ¥$lŠóxÇø?ܶ¥¸ÜM§eNÈÏdjvØl=]c'Ï!8Þ™Ïê¹èã4êx‘‹Ý )ÚôìèlcÞöI¯µ—n’< �ÕÖÒ²7•¸A™é„UíFÃ|œ ð¢ã7ÞŽM-;”(¨¹VЛˆ2P™r[4¼ÏžR$ìy@ΞZÍÍþóÀi»,]Hš€>^©Hð×ìM|æCÓƒóæUIŒŠfsªðÌ XOd¥žA“š_÷N°—ÍÁ “äÀ.zhÑ׋{,«Ùâ Y=‹Íj±8‚–PÔÿÈIí£ endstream endobj 73 0 obj <>stream xœeR]LSg>§e|ß´ž¹%M$²Òèf&H‚Ó7¯6 ]ÐQˆdþ¬U TN[è)?µÐ²®éwzÚZÊ¿´ä¥“ŸŽH¦7:݈¿ÓL‰3f[Ì–x³›ïtŸ;lYv±»÷}Ÿ'ï“çy_šÊRP4Mo¬4[L\áÇ6¶f½}GÚJK¹ ém%jË3ù¯!•©²þÜû>þ&>ü.ÞL)iú£OÙb[£Ón®«whß«:rlgAÁ®ÿ&ïíÞ«=íüÑ4qæ:«v‡\´˜X[£Ådu”™-§›9í›ÅhÕ–Ù>ÐÖêM5æfËÿŠ¢€ÕÎ2U±UN¥*©]T µ�ÒSPvAeQvê]B¯* 1Åu,0Ò5—˜Uú1ÎÅ[q®RšÕuA÷ ?1Ϫ¯}Xnhª¨Õ<$å°ä‹zy#$‹ `üÂkðAwŠ >äB3º‹õ&ÆÄþ1¿i¬Ê#^¨u»zdê9ÀH²Ú�8ý\VÂË¢ºBðô£[ëÁ7‹Ó½Q_{Ÿf´iÈ›Dp691wùìôÉêzî“ykDï_uõ»ù3ËŸùÜcôË;ä�9i©hšžz‰sSâ_ñ5ÞÖ º:ü]näGÞ +ÌÆšC‚{JË÷—.œziÌ»c�°#ÖXìŸéN^~Þ¢i$û’Ù±±H¤EÐ…žÞî)ÏJç$‚¿Üºùó=ÓbþBžn²1‰Ò0=!Î��w¶&4‰Ö>ç 2™Q§1ƒ÷(3AQÍñž°gˆ\•²·`=>zIü= E2Ã�Ǿpâ�«ÛDzÄLÌ[° ï ß Éø3¬žmç�ÁWV¨vytëÙþ$‚’¨k °q%±ŽØ/:Â^Ô™ƒ>/Font<>>>/Length 2744/Filter/FlateDecode>>stream xœíZKsÜÆ¾ãWàÉ•ÍûqŒÉrìJÅ$]9¨|PQkJ –²H9)ýû|=˜ž™]`Ée²GK|hôs¦|¥P£¤¿ò{½^\„ñæ~P#!w7ƒ 1çG§œÆ�»2qJH[´VãZ[\»–1 ­Çë�ë’)³`ÀKaâÈ,­3Rb9 åëëA'©…�™€˜$¤ªˆN> o*Ïv�…‹`½¦†Í™%[ÆBùúzøõ›AESÿ3Èñ»¯þzÄ_ï‡Ëa^lX\&$)¼•´Vè0p³’‰\ûñnKþgmµË¦¿‹ïNyðrÐÊzá±’�óB†1'L‚¯”1"êÂýªK¦ �£ÑèQÛ˜tD÷˜ßI*¢¡hR×ð*Tm×Ú�ËàÖ‚(¥¤°ŠÜʈ Ðî+<ÙÜ"”/±>("¦`�PDR9Ʃʱ^™`QÖkê�YóÂ’ c™|½¿¾:êG½/K*o<$Q6ˆZW"„Q±>h[!S»T^82³Ök'4©È€ƒ*i£ð³Î%¡ð[$òõõàbˆ”A¼’³T—,YÉ,ù²ˆ‡`¥¦ÌJ3?¶‰%òu^O_�sÌ9{‰Ô‡äòÊëóaÒGé ô—Cð*�3=�êrpÉT=Âéq¢ËE!Ñ�ú8ÕYYÕrd•¦(a•*Z¦"SOœ©'š�ž¦åM&j‰³£RèÌUA¦ÎÀŽ*APTëTM"Su?!_9­$nÓ’›†¨]÷O¾5aMš¤aŠ�1©äQà&i©›”"¥Ë¤<µŽ ¹båmÐ|¨ŒìË"ùÿøf¼mEÈHp½§ Uœ B¥ŠL1†ZÛ‹Y"ŠTÒÙ?Á 7«Æ.•\r¨6u!¨È¤ó™˜¾BÔl@òxØç&rW�½muαI ×�òÐ:BmÜ«áp—Sí¾¤eÈt²¨¡±[ŽŒ`Ñ£ÞÆžíÑ?”­˜µÔg©ó�†¹ �ƒE¤¥à’ítD�‚ ±¼”J¸T‘©åM�´/´é‰ Ò)›D°=QA:"ÌŠ*P#b¤'²V ÕÓÌ‘påhzÃL“LJNo. UŠŽbÕSU^-¸‹=¯‚ìñjTÌ«£ª¼`ÐŽWAöx5*æµBÕœÅT½³j mTEâ*û´5ŸVyµ|Ty]ù8y3{tŘΌs�z‹Ö2125$|î�ÊS!AÙœˆlʓ졬•œ(ÉûZ?w¡ÑÐå"d�N”Ø–H'‰w\Eò_±õ¨ŽK˪Ö{ø\LŸ’�]®…è=1ŒÏŪ"<ò£W4š <³Ž8EyÂ:‹77š’–!³�zLÓ…Œ‘ æ»DÐO B¸ 5»–-µ>Ô‘ÚÃ3±zRX‚ ”¼[1®Hm^\Äõz ©Åx Áb6íŠú¡¬e`Ø^^†»Æ¥.ÌŠìu+kv,ä¯èx¨…áL¬ž/Cv-ö¡,¡§c¬2F¦†xƒ½  >tp ­¯£±,h4õ=Ie{Ÿ<¿úç`°ñ½¡�(aéÎ;Ü¡/.À†ûà-±Ú(«†œq£-Ù¥2é«ßï·D½™…šqc–´œïþ°½»ÝNt_cz´&îßþË݇oïæÇåÌSÂI“æÛ{ÓñFjÜ wK… Ewÿüöú}¾­à.«òÉ 6Ü|óç{æ‹ÆVü•L3ã»�×Ûû{" çlÈK–μé5=;à¡7Ï~xyñ·—?>ß$8'%óìç˗Ϲúkõ+%#ÊË(/›�Üú§û/·×Y6›JÇŽ ³hºùÇñÃíçíÝÝï¿}¾Ÿ=éM8Ú»@Ž6ÁC˜#•QˬÍϽÎqÇzSÕq¼Ê>`àG"ýšGaü|L¹O¸Œª¡AÒˆmh�;YG¢uÂç7!Îz¼å›Ê9‘�3±&fŸ¿‚wö—Â,Çϱ~»Ý}¼]17ÂuR#ÔuXÝÙ¤ÜÞÌ�ÈœœonoßÕ;%�*w¾}{ý¯›»�¿ß¾Ë;«›tÛä=àfí¿?X)ÑÃx~ö¨¶óÍÙ0£g>Éê¶áööóÝ—ßß~|·]“´›¹� ûÛïåU_d�e¥}Žu×9‡�àÌ °Ø\Þ@wÛߦ/•ó£ùÛ¯ãÌÓQK�|ÉÝifÜù%³>µàFE6¡õȇ(>O×±è -%æD�-æô¤<µ†D˜-Q!!.C5-d- ný,ŒHužõ F:¾Ýëݹb®Ø²ÐaEÏ…V¨˜çbõþ”ª¶eC‡$ž†y´„!'íƒS×Pþ´‹ÏI´Ä%é͇ªMMˆáïfr´'�_6ƒöˆÂϨ.‹]é»Õ;�êôfRK¥é4\Ò¬ASõo®"S‡PZ5y"ã§@TN”@h$³{4̹¬m:Â@󎶸aÌd•Gwí ¾Êlÿ£ÌÒ»�ò ï„5Ë�k¼´“mØïZ7|&îO ´Fµ§/$½¶¯]CjVÒÆQ•YCÊSë½ç¦·±:Í/¾e-ó'Œ�ÞÎì*F:¾{yjÅŽ¥ü¥Ž �(2gbµÿ^¿~OS_}×ïiºWßõ³¢ÚÏ3UßôW*~y\‰ÚËãú-P“Çßuò~þ ‘S*& endstream endobj 80 0 obj <>/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ÚÅ[IsÜF–¾ëW0bSŒ`AÈ K÷I¶¥¶fݶEÇl@ÈB””Øœ_?oKlLÊR»#æRHd&r}Ë÷–Н®â«¿½ŠåùÕí«×ïL~•Gy¢“«Ûû«T_¥*Žb“^Ý®~Þ•MU´—ó]ï]œïþÞ]ï�Jw§®¯°”ìúê÷K5Œ¿=ÖMÃ=Êî$=îûîÄ¥ñXqão×*ÞU}[5׿Þþ,e¯T”;ÇsÞwýõ^kýë�KC5 u×òKѤör7àôíˆïÖRäšÆ~ýÎ¥‹í©$�l¬aFšéõ¡úøúþ2TÜuu{ßwµ6Þ v1L6^ú–Ëñ ?Ëâ2Ôí¿Ðn±p(ªS'=ÇŽŸÕµr»Ö#¿=ôEYÝ_šæé:q»ˆWb`ri¹‹Ûã¼Î4ÊÓXÑ–ò(I¿£÷×ûDïþN¿·ð«vo©ü#•ÄÃÙýD5ßSÍm`çNE‰v~D¹`¸¸Üíð>ðY�êq¬ür÷ÄO¾^(,®—¿º§í3éÄ®´hñ$`�éݨJ»ÝǺ» �Ô |½PšIMgjW buÛñ³éÚ‡ª—ºª:àò°üKìâ*zˆnB´öx¬ðfr½+øÄÐséÜw%�¾¨Ý]Ó•¼­·vÓg�+1Y”+€?Òq¿¥ã~Cåo‡®“ȨÜCt£�UªÛŽv¡˜0€0]¤u¾ÞÈÛ¢<âíêùÂ�ŽÅÀµ¿_ÚZy~/9#¶‘Ë2¿æ«²ú�ÀR­�T<õ|<Ö0óóC€ eÊþ;ér¯R9%ûNx`¸/:+Ǭ…ÔvŠ©¯Õîþ‰+>ÖåXŸ¸ìi䙵v÷A¶É�íåtWõ2ÒW€` D­§‚»'¹'âu(,IŸÈƒdUîÉkš¡›HM†¥ˆ îšË @÷¡œ›Š8�eÐÄð&´¼=BÍPÎEYù¯ÎM] /‰™·‘#«¹ZÙÿC-/«Ë®‹º¤>DQZE©›dmÛ*þô}ˆþ�‰â‰e~Ñ:Á@½/­¸Ð¾�RN«#IìþE©I’]ÝŽ$[I˜$r¸"¹Œ=XLQW^tºëÆ£¯äçJ†A¼ÈÀmxq!LtebÕtíçb<îÇn/saDZ/Ú¡)FÖgPÁÌïÎUªïT'"!kSZ}€Ùr�þô¾#úqÿþ7ýþDõ߇?‹l¶ø°“$Ö+j°Ù©â…Ðý@�h²aä†Þ+]W’Fi¾fØZ$jÓu+�z9s=ŠkÈ4ÜÔ’Vx亮•£õ2²µ/Ô°‰•çFõŒù½:¡õ•OtAE~R›�ãe[ ·‚SJ]ºûb=¬íA×ã‰|¤ãÀOŠÖ�äg/v'ÅžB¡ê@sà®t<×®HºŸA&Á-ì†ùë€NÙiãI«¿›¨C‰‚úÛBM…¤¯I¢Ô$3‘ðfö$‡²j½'/1Œ%ÑFOZ=ˆc`;{‘HXÇ 1&êHÿ%¡?,�»º7ÃÀ'Áãd¤wªŽ#3Ö¡*ëƒ�‹Z¬+šYܪ�Ʋëûj8wí�Ñ´бÍ7Œý¥$(òtsê *�3þоB@dð-�ö×ôû-~øêíí«ß_!ÇWêJYPñÊ]ÙLGÖåWåéÕÏ¿ÆWh„D&Ï®©ëéJGy†¸¡¹úðê‡ Ñ/.ÞsÃp(�Ì·ï%Ägß¾rÓíãÑK" ÚtÍg(¤:~"’WÈb¼�§K#d£€l’x#Æ”ë(â3¯×jÎX*D—Á­4ÕJ>SfIÎc¾iCÌ`¡8íæ ÜñVpJ ¹(N³g¨X»„%<ª¶êQ‘9��Ê£)*ý¹GHB+'�/]HgÓ‰8°ºTº>ܯ5^ÉXgPÝ¥×ÐÔ�«v�6®ù%ŽuƒrÉÄ^.a5*}Ö�øÆ¤½…EíAv¢]âZMB³{÷Ó‡·X²³ac<Є‚ô*�ã*#³\,.¼hÚcWÂRA”…"/õŠý9¶0€f�Å[æO`ÚC²ç€£25Ý9‰%�Š<®Äƒ$ƒ*§#tpD·,† Kx0kâÈmÍþMXR ËÑ^ä) «s­ýüf-Ô¯£9ÃMLÿXÉÖѬ�µ™1 U»².-&‰ç£Dv�U~×Xž Çå` v+®ñs¹÷å”B°%*;�¥ø2™*›NŒ+;®Æ®—æ³LÃ+Úû³ÆÞu‹°ˆˆ> íó-w= Ó�…q‹ò·âŽ/Ë..šž†±:q™VËýÙŸ¡½ u ~ʾ>�ˆEð½»4X5Ïaã™– ž„�玗öPõŠØ0¨æÅAù ÛÏE?rMxÈŽÿyí©ãæñ ÌgRL™‹Œ�¬³wc1À>ÌJi«â®ji£â$“Ôã×-�B•€F(­ÿ.JÌ5Ì,¸äµ|çù¯l:°˜þŠx<óx|+Øcœ. ™Þß=3Ã?ˆÄÈ Y“­6 ó³'Wô(\Mä-vâ^Ù@W«r¬gæ›`†dr‡Çu! �*ãTçô„êêzòÀ²üŽ ¬È¥Ÿrrù_5]²?H-6ª8Ï7™˜ÈЖqF)ÞŸÓl bí¼'øÒ¸­Q@LgÓîžø87Š/ù®©Y Y*‰L–}ÙnƒW—Ì>1„U*�ïTËS¼DXӖͱ°€¡[§ô© ²Oö*ópæ¬1¹Ž\êX¨ÈMbж.îf²�ç`Ÿ%ºÇžÄZØ …ôtH1þ7z| ÃX“K}M®*,ˆ;�"š¸\‹¦ÿPŸê¦è—ãýûðш’ yÀ”õú[M”$�ïÃÂåäpéù±–ZìPù‚†«ÏòéêÉ·|¸xUð³ýuáßÕ G²•ø÷‚ñxÑl𢙠¡FÝ´ñÀÕõ=w/ø•- ,MÞm|!ðŽÝÎËÛÝ{sjIj5bð•¨,x¥xÊ«/åÕ‘¸P5Tz¨à»m3�ûfÆöoÈ5ü5�î×ÓÍzù9ìÅl¬¬¯(Ò�3Zb)˽i”å~Ü‹waµØAPšì ,÷PË ŒÙ°‹‚#€íÊ OôLº;£«ßG¹ ­éêR̸o™—ÐêºÜˆ÷t›�­*˜ú°ƒ®‘ NŒœÌkGæf£ë&¿ÑÊÒÊÒÈÙɃq¨î‹K3Ð/óUe`׃øý2‡ÅÚoœÇQ'4”5rGóé !˜’™®œÍL¿©bä�“ë!É"“l4Ä,ñLºñ°¥ZÀçC_„"™ð>†fκ ùp^ÍóÚX¡Åu?:i¬3ZÎÜć¬N|•˜Ö †_rÆøa`פ£ê¦ Sv¾48gÝ 6=\z�SØ�7©0â ÇB¦z\€•óƒ×c}xaÚs7bxªhpá™î¬°â Î}¶-Ö]5>V•ôXÊ*ëI ¤ëQPÇ›¬ÿîÅ·Q&Ò`qåQL²û÷W€=bg©yQ¤&ÿ‘T¼~ÒWßt ˘šö<à~ÑËù ø*±ÄðSqË­cÒ†…¡\öÍW/:pÀè6°˜[ƒÐûŒ5 8uŸZƒa©Íj EÝP@Kü¸šs�wBXQ¸<ç“åæCGDÇììÆÖcñQ ~Œ0, B4^´‘sý]…Y3Õ'rf˜ˆ¿}p@Ô‚ö ¼zd©è)¡�ÀJ)Ψ™è~#ßñÞÁx÷z9EÞNª�}psÞιë½j £&”øZOÚ¬é÷¢h*I:…ª¢çZ'SØ5~_AÉÚ�‡é6¼07줳¾­ŽË `ÖSáäôù4C�º9 ü5IBƒ‘ž³TÜóSô`êu’W�ö§еÖSF+ÑËZyQªVÖ(†AË�P# Ü�=ú 3~#ࣕwå*†â€ºƒh|œ"ñ"DD]=?SÀFÆ\ÇõƒÎ+e'4t*ÎgàJHðÆú ôvcfs�nD9¨$¦ÝÔ ƒÍ´œS�‚æP‰ç@û�NSPž_‰a|+ŽB+˜ÀÇL“ª ÉkóY|>*Ù†‡ªÍ� �1Ðxß‚*-( †™{ä€^Áùa !Å-,8Uã±#ÒKü^+~a‚jjŒMÊ<á òd�Ø¿=Je`þÀ®™hIÚ ”Ø£>ðËÂ-e)ñ¤ï/çQ™€¡¸…þ»nºîÍ„6Юã%µ5û›€�ª 3¨B§ÀÖ—€Gš†¹¾àІSˆÁsÈœü$Q�MÒ¤{LM&`yì[Ä7o‚.ãl6oãåÒÓy¸Swø£á–.³$3³{u5®¥ª§�ÇþÒbxÿcƒ)òTÛgÞ4$¶ŸÌB,AÂûÉëÏ…x£×äAm³OAÿåy2çØ�hÆ}b� åÓ<›•ÀÞ!©}àQå9´oÜ^u–•ðÑît!É/R#âX2ù¨H”�=ÉÃS"Ù ;m(å jî¼A½áÕ¢-§XàC#¢èÑ·(ç�È�¤åŸË Q³`k†L¼˜l»XàÊ„ð¢pŠbÏɇ•3Ìö+YÖ㋎+~âìÐJEfÅs€¥E„�Q ¾:õmÊ+{ÔrKÖÿœwÈ/„ŸhYëÕ0ö,Ũ¤>§¢–»Œ•ùä8ìá.– yU%N Cj$ž‡K/_ ²¶.Y{�Ù#s2ðBÈ,ø|‰n|\Ô[tÏ×q”Î }Ô³ïQǘ¶²ñÒ<Ð)'7Ã¥v-Ïf` ¥³»â,†f`SÌ“<0°ý¼�×ð9@©:JõfxIpg3Ò½0�q÷g|V”xx¿=ð|—Eüi1Wå³hŽ}¼ñy\qdólÍË3Õ‚q{WaJùšX.`e×ÁB Gb J¬¬+Fo{™¤Rr¡`Ð�U|ÃŽþwJ±‹£Äæ§ÆQZ~J6aºÒð:Ox£7Áüo.³³�k ÝdüüPÄålÁ7©Ò�j,i ñ”T¨©ZÒCv‡–¼`tÈ<µå±ïÚî2ð÷S ÂyCi€„ÚÜ" Ÿ„�Y‰�dJ¼õ Pðlµ$ü åZ^#U,°o*´óW´v80OÌÊPÂc¶>ªèäy”| X’D$,ÞHA[©—ªÜ,j°��6?•ßFª8ݪªu"g¥é*{ö ó'Ó(1«ô •Œ¹6Äï&‰2“ÿ‰\ÝÕlK§l"¤…ab]—EY–lmóRÇ2ñŸÖ}óôÅü-háp²Nò]Æ/ló}ÜÔû—òO�y·;B}™š�JBI.fÈÿ— Ö¨U ÆdÕ0i¾¤~qèúã¤Ã ìáBŽ_|†ËÅÓc=Á%JˆÜ„ã)& —Ùc["SQì²?•¼þ•€-Aé{0ùäÀa³—Ãl‰Åµ¬LR›Û¤àŽs)`Mät"–> 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 xœuWyTS׺?1�sTL•Ü( Mx8ô:Ôáéµ­Š ˆ80 Æ’`&B˜²“�æ „Á0(" (‚u¨óXímõÞª·¯Kßíkë½}í>¬Í]ëí ½¯w½õVþIÎÙùö·¿ß÷}¿Í <¦ cúAaº@üa`¦(Ñýs=—AÏ›B¿ÏÌCÑãçÇ7x/&ðòèŸ÷^«7ìŸÓÞƒA3 &ƒ±õ¨h[f– n„ŒÇ�9$ïKé䧸RëvÖQœ7гgàì~oV]Fëx芘u·´QaŒ &2ȲH…z‡Ž‚%ð÷$‹óúÍÈaÿ¥ G?Ž9a;ǧµ§êjÏð8otÆ-_˜–‰¼JùlºTé¢ÿàb¸à¸.`Âr:�‹f-]€ü�ÿë â0ð}Èûð âð éÜ«M‡ÐÐRYdø~éEü§-�£×ù˜Ùyú]ŒËp+sœsÃ÷Š$G¥QQ&ØöödŒfŒ©‚({ó8mx@ž4À´¤öl¥œPžÍR¤h ¤@ ”幕œÇª� E Eh ŠFÑp> €±ÐãÞ)Hü€“¾¤ú”f^f<Å­† ™ðÚÅÝoÌoÔß§ �<Õªd~õ7¸¾ø 1„¹á"þý·”Uâ© ©O(ÔF¹)³“›é^.¨¨´ÕÔ69šÝ\�µ„¡ß!vÖþð´Ì–^…û„ ‡~ÕÍøÞÑ 71³á-L†ÿ†E cÐ<ÈFR>³n7) QÔ„”1ÙÒƒz êèûÜ–¦ê¾‡ÓvöðÚ"ë¶�u`¹ì£´˜Ô¨ã¹Á€ŠQ՞㻵ࢿëf`-¬f¶Œ{sÃl„RTD‰é‡dŒõÌb‰vK3S2£“ŸØ¨yÍ �¿€³‚Ä¢Zá‹–y$&((#{k+Gáê B4»•ç„G&n²ØtVùF;ã%V8vrÃLêp“‚¡ähû@W¥U§¨æ5e×k[ÕÛÚ~æ\jWTdŠx×qþ3*!Ïר “²O(PÇáÄ`-ɦ!Žù3ΟÀù7Oæ�‘ø5M�êŸ�äj“¼¦ì²;¯õ§uÈ à…˜%GBábL›Ô�ïÅo¯å ]ÍtrËeõúQŠÎ cÛ##åD߉É%v…1Ò͉þˆL¹ÝMÝw¤» Ø´ } a ”U뀨KEùÛÑŸMðXa“¾Tø‚ú*‹Ód«�jAe²¹ÄRf)0†ÛàT4èÓÆ‚«h߯Ak…«Üw20½©ÓÛçC/8ùA¿9œ´ð·  ´´L_ |•:«�+ɯ·Ž"/ÄÜz$0¾E|öl{KO–™�WXUjÊÞn;Åã¼¾Úš½�¿�DSSŽÉ’sbÓ¥© ŽÚ7sûÊ�}äS^Õ‘fÙ0\õ½ý¸Y¢W¸Y"™K"]ÚÞw¥¿ÿ©Z“'6ÆiÜèäŠ j³º�Ñ, œrþÕŠ¡:-&¿Ò™Ë0 'Jt""¡�ÆGõ¶‡åøýs1yçŸòÖGžPïtËûk'¹Ãz¢V?BÁƒd›îD9�³h|�ZU”ªŸ:z¼ðÏ“­ßõ¶ÖǧÃn&+u³L$%$Ìߨ0yퟎ'�¬«ùÚ„7ü«˜¼]‚7|Ë]¤R³£÷ƒ[nîPÔ†NeÒ™ÿJ ¦LS˜» …ùÁÝÒ‹«/¨«±¶ë�>¿%œ[Ö?I^~DþQ±H|µ…V« &¾Á Ê�™ê�Ø…ÉÙÙÉQ}iWz:ª›í—±vÂ5î‚¢Û¸Ñ&\0ý}%I0"V�1ŠB;ɸ¡ôúh<3ˆ�8�ß“¥?�uÙF†ùÁäPm«ù:.‘ÈVOÎ:ü-äkTÒ\©F¨ñ58 z·]»ÚÝ)N®uwz¹½ÌŽ'ò ½qp' Ïâ'kk¥¼Qÿ�¢ù$®Ûà‰NÏvú \©­½U…ÉI“�tö<°ƒB—Hô½ÞÅ‹YM Q1|€šH$õûª ÂI€ÁàÓp•‹A@67ñxº<@Fƒô”¬S×]r› VÑŸâ3i½ÑöƒøD3Ö-AóÑügBöÓ �¯nóQÜÈ5Ái }# oa•ËLÙXŠw=ø¿{?á1õü˜Ù<>s²6WV–=¦àúºMƒ O;?_RÐsÅm´ž‡î‹Y÷ŠkÆ j"ˆÔïUæÅ—‚‚²‚2 Ñ÷¸-¶êî?uÇ„h’²ryiš.PnÝEwÒׯ´.ïî—› œ }’¿œÃÙEçÐ~Ü1Ä!9'm±™æÄ¹hêúàå)5"gߑӤ–}’•(G@Bƒü–„âô…êÒ²ü§™pÝ‹Ñÿúã��#/İΠ0ƒv_ÐTck©®1pPœ«?ݽüMŸúdVŸóhóD(÷RÛ‰Ô¨C9KÖD· Ú+j:šùœe¡eÜᦤ+å)Ç�ËO½zÕxú<ÿ­µ›q›ªwÖ®ÕÉ” à,öLäóˆO7F$ËÂ#y°…IÈ!­¥{»‰ÒÿÏÛ™°·«r8~ãí ÜÞN‘VúÎÛ%½›‡Ó1»àFæx¤“+*‹¶�]>ךZkÚ[;ÚlgÁ9LÅÒh=³–Ô)�ÛÜT”j ¶à2‡Ï�ä–*mUÙ#ÜWÚHl7®{Â(ÖD ý‚ ,åu&‹¥ªÞŒgõ·½q B”‚´<~v~jÑ=žY�8 #\æ}.CóÝUôZð±MêzÐKÑSÝ',´¼çñºÂ-ÞPEr^ r|=7N(Œ‹íJ<×Ý58(ì‰s£(ëg»dvï‘_ N�ÃY‡'‡€ …dav‘NŽ]œÆ”‡+îK[´È‚é÷ݰÍ\; ©ü»¢ Î,á»ëXÌ–ýÇZ/$ó2O«ºóïS™¨¸ƒUÑVaµ+¨.uèÎç÷êÜ>ná÷_Ù�cž„tòÑ‚Ï?îËu‚ ¾7ú{ïõË’Oñº…õŽ`j’ÝÉÑL›Ým0IÂ:YÒPb.-/5¹Ý®y š…¼}è (XBv•Õå“ô&*ä"wSV9É(K± SЃlq¾F> b‹új”º,žÊ�d�¾Ø¤­AáÐæóýß[nZ)·÷½Àø;\  2Ç÷Œ/á¢41ë‹bGØN¡1-<¸M]{ úòà3ÒøE]íSÓÛr¯¨Z…‰FÏH°Ôqìzì°ð–üsðÜw ôõ¶>¯(x‡4|Vg»Qù–IÆ·õÀü‰ôùvÐGÑ_¢½²»Ì&7$M%Iž'“ü±ÇŸüËEÆýaŽŸwr“ ø2sö×ËLxRnH$/㦰%„€ØÁ>jòf3P\­vÛ ·ÅÓ¼µxj'™úV6nõ[l�µÕöz[E ÎÔKö»o6�J‘â¾Ù`¤R�*Û»¥f[Sm•Ãf«hÄnò×¥‰*e²{©’dCS‘]WzÃå÷æpb?CÛ¹ÐóÎÈ𜺟0v4-í(�ãˆ:)0[€ÁÌãİ1Ì­¶jÕ‚Ô„À>ÆFfŸ�‡úèø:îj:ñ�`ÏoX80[ÖDÇ¡ÐÀêœyÓ;Må&S¹¹Êdòò´YÛ,­Uåf“× ƒ› þŽ•[ endstream endobj 86 0 obj <>stream xœeTiP[×}BèñˆÛ¢Q,ÕŽžÒ´¶õ$&¶§ñ¸©±».bõ1†Hb‘„I€„Ð.}z-# $aØà}!àÔÆÛı“ÖcÜq»­�Ô?Ú$“ÞG_¦í£�Ntæþøæ»÷~sΜs>–ž†q8œçÊÔríÚíºUÃ;K�Uô ½2�~�»�‘/>³˜Ãƒ,.d¥Y‰Ë²‘ö¨ê{Hú}ŒËáä×ê¶iš ­ uõ:ÉšŠÒÝ/çæþô�¼W×­—Ôþ{#yS®m¨k’¬b‹6¹JÓ¬–7éŠÔµz­¤T£®i’i^—ì””ÊëôªšVÉýÿ Ã2›4Í­Z�~»¼äX1V‚•a«±r¬Û…å`X!–ŲÃÒ±0öWŽ›ó$M›Æpp¿N==Îk@=Ëh�í}Y‚Îü ÍÍS–óÏÓZ”)(+°Z�@Ø¡H :G^Cò`*�‚¨hªùˆlÇŽ"fã�ÄŸ Uamsç™D¦Œ‹ÞCNh;x¼N‚ß±šA¼y|­�¤.|rãËfO�X ]N¥­‘|›Ùl.óÚ [Ä?$0½0’üâ·bŽ5I¯OrF>GŸsÑgt™ dÖÝ‹ÅùÌ3 !^›ÛõäöGcW¯‹oß:óæ‰ÏJ®lwµ ÎŽÖ•ä7ü¤ª�TTÈZ«�x[9uéîøãÙ;ä©«gÇα4|ˆ&ÏqèsoÑkÃ~^>D%Ì`«‚yIÁ[óÚÞ0Y«,Öj/aB²hF¥ß–wôÖáG#–¸û0èe”‡~�6.TOoÛ^©ü™”ûÊð÷%ÊÓãñ1¯ê…(¡œõµ@¨×ïÿåé>Õ. 4íÑÔ±ãH8>OŽþæÚÌE K :7ÁA¢ç/£mñÓîM^�CzݽÝacØ•b,>81Ñ‘Ðè4fM YSSSd’™Â9Ôì¡¶Z¬Þ­]"cF*ð‡�Hê6Xìµv5¹‘™á-£;ÿÛ£œÅ5‹9‚ï(>íîõõ;®`t�Á­s¶2Ï}W.49�%v–u$–! Â8D¨þÐðuÔ.<é†$œ„�/âŠ:Â�¬ÎFŸÕ©Œ»„wQwGoõ:·—yÃ+úYƒ©�àŒO4‰#þ c‰l>é³òlI/‹EdI’tÞpG"ûëOÏß[Î÷�¢5=³�Ãñ`oôà;á"ø*Çá¨'¾âá�¹{'ÛÎU]%åÓ¦q%Ž¥’“—Æä›#âÎ_™B/ò̸½Óá6³Îë¦ ½ìÏpK'Õ±bë¾ý…�ÉgÊÉ“{ãuÐDT©”ûËTgžšÅËиuýs‚ƒnÒ‚Mø{ß,©~QÐp‹½¸wƒÇãrÊöìÜÝ`oµ9œ`%œw3¶0&©] n‘>izwúØèŸoŠ-¡}; FˆlÎP?@ÈÇè1ï!¾ä·K»ß§…‰ì™´åþrþº‰ÍVEa§…Í–Ãì $?% 9Þ¼˜Yç0Uæüó9E{÷4®°€í À>¥Ó=T™Eá�:D�§}}®^O¯ `wµv×Ë™ Ûó�` ƒ†©;¿¾Œv£L1�’áš õ?T ǧ‡‡þÂÆ =„ÄbZ‚|ùq_¬8Ô‚÷XûùÃ}“(‹®Ư…‚×ú|1!Óc¯Ûû ³ÇhWÿÛ!¬œŽÒnÖ±ÅÖ ´h˜sê¨ó6—Î@\ÁV©ÒĆ®T1u9FõEŽ“£´6‰°x$:£Ùˬf60›™µ›.•Ý¿³púãb¦å &ÿ4¿pˆä€Yר¡PªIy�Üøš~)«Œ<…¾H¢½§RÙÁ¹©û(÷†êwËùÿ õô+‚_ápQö f°±OÃ{åç¹»RMWšIi­¡´Ð¶™WíèhƒJâ­[Õß þÃëü°ò\Έ¸ú`K ¢DtøÝŠ_�8âí÷‚ÿÕ“§¿¿÷ ¹ä,Îÿ;3ËüM€8õS-PE”×nÞTuâæ‘à`lH<0xöhü@ù(Áÿ­¡_ÒV)ºªÛëIvaëë��ëG§¿¼úà6¹Ì0H¿Eµ)üè³ ™Ã==ö‘¬, ûCÇ endstream endobj 87 0 obj <>stream xœcd`ab`ddä ÉÌM-Ö ÊÏMÌñU~H3þ�aú!ËÜÝý3è§k7s7ˆrBß¿{ñw``fdtŒÎuÎ/¨,ÊLÏ(QÐ ×ÔÖÖAˆš($UÂd\R‹3ÓóÔ€Œ²Ôœü‚ÜÔ¼¿ÌܤÒb°Õ ~ù– > A©é¥9‰E˜2 Ì! š ¦ Œ ,ŒŒ,å‡�}ïãû™Ö=ÿûîíß×Ïgüöñûá�Ìóľ¯šÇæ0±~z×eŽïIßÿgï2kj°mã¨Ê°Ce~°÷\™:õÆ$Žy¿WU°ßh�ÚØãÈñ;ì÷áïaØdþ¸ÂLáûñ½{þ�7[¿OúÈü#bž¨eÝŒ®+?&dÿÎѹ jáoFŽÅl­ßíXÿœ`kýmǺ˜mÑwÆs¾³÷rüÓÁÖeÚÔhrÍv> 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—ÛÈ‘¾ëWðâgÔsB.@ã“Ú#y4›=Vyú îŠ‹x6–Vk~ýÄ–XXY²žu!™‰\cù""™ìžvÉîϯyþððêõ;S슸Èt¶{8íœÞ9•ĉq»‡ãîc4ž«»}š¨è±<|z껩=â{ý2USõÇ»=|}î뱸ÝSÇÏñNEž ôñóÿà öJÅEšòPÔãÝ^gE4v�w:‰¦‘_º¶ù”K¢ú$íÎòÍ»ç×Cyð5õÀϪ-›êßíM–GïÛÐ †ép†z­£C×þ”$úiê˱îÚáŠM1/›œúîÂÍÂhMCÕsѵïÕ0ø¶e_…ÆÃ!úW粨<¦ËÔ”cu䂺å'/ˆkù$”_ŸsQÙJsü²ÇQ^¿KÝêDU®b% �ùx<5Óp憛£ßû–›9Žç¾*�¸ ë¿SIT~ÂߊK¦+?ÇŽŸ°$ƒÝÓ˱îÇ/LâÜ¥“�ùÏp Yâ¢ÏuSm¾Ûo¶)ã)Ôí,1Ïe'ò¹7,{÷÷o™:uýE ËáK{8÷]ÛMA'Ç•}œ6ŒCèDx7s8Ài˜‚A/LÑ�äÚOc+XA k³IýÍ�B5Ä,�ñ˜u²dÓ¾‹0 ùÔ—Ç©l@ž�ý±dìëçFªiçñ黺Ví·ì%ƒ æÊÊÆY•GM}©q¢HS/H´Óå¹Ù*¼—m·KújÿÂ8´tÒ;ÔÀÕcÙVð-:ì«¡¦9R ÜW|ò  Ú¯€JýNhZê‹{hòµÐ‚¨D!Ëc§ / —ò7lóêíë_^)(Mvj§Ò"Ö¶Ø¥Egyº;\^}ü9Ù¡ŽM‘ï>SÓËNÇEŽ�5»¯þ‡UéVð2k“SW6^ÞªÀ ÌL¬ì,©×²//ÕH*V÷S*T³züB±W©‰ Ìr³ÇêDb »ß(:îd­jù4OÕ�N£Ït¸´ëeËöŽ nŽj‚"#+BÝÆš¶]+e·0"•Ò1Þc…]º£V¤øÁ¬Î¿ÑPX?¸�.Ý�J£_ñ‡ô'��<ÏÒf5;‹‚IMôà[ÔíXµ¨ðå5¨#¼ª#±Á<ç¢Æ«šR4Þ¡sp”zù¤¾\»daä×Í>c» Nš<~‘'YÆ~.G¥òµNJ—£‹©cä5³íœ_È ¿ç—¦jŸÆóÀ/¼Ë@´ÝÈD…ýÛµ©õHF¹�ý kÓ<ú·Ž¸Œ×³_�+|C\ÈÖßÙ$ºgÿL|j±{HxUd’”–‰e[Å’…©ð­^uØÑ…r㕾õV{®àá:°‚`s® `aþ°ˆ²!v„r:„ܾ4ê8µ/h&cck¼àƒóFlø\?eYœ'fgs'yþ}ú©ˆ]¡¡+çÐr6÷ùkBê)Íã¼(ê)UšÔ“KçõRg…Ú®6'€N@7fúë*9IâçéT¬Œù®%'Z(è º4öT2˜ç2??Ô_ÚF<”cQ„ç�•FL ¾n=4�ÏûBÅîlýgÝN¿¡nÐÑÿ¾ûÀèç‘©Ú?~ ŸTG€á&/¼Ú|KÂDTß�cS /ZPT `‘ZXM '�”R¢Õ¸²–fh~©¾ÀÔ.±ìi¾ÚSÝÆ`yô¤FPæ¬IY­™ñ ±ª;�ª~ˆG¤ŒŠS“ú3zßòW i £Çr¨\6Tãt…ó±¹Z¿Ù=3*:–Õ Òçr`‚‘È3îÒq⬟âf” ä‰À´­ŽUª—Æ^{a÷l‘*=WnF‚ý³±z£Qéh¾6b»e<Øu<]›»ðj`„DÏ:éõ±úõõ ø#$#ôȬ@ÿÃFèè­èö/8F.¾Žv(›FvÆHµÞî<îDÝÓÔàû’8ê èCwEq£78Ýjü\1´I=zM#vQú¶j¤â* ˆÃC®ßµ< H]½G9·–ä žÕp­5Ì-»vÀýå45\ ¢=o‰‹ —(b8]½@ÍÑOŽþF¿ïé÷~Uô6°›€gážóV®tÔ2Ø^9gÙ�.áÑÞÒ8oˆþ×Àh:‹ «žq…Iqg Âð î,lî@ŠVx$Å’Î6“_J~4ÝÈYkh,Ç’à¼öe‹@îòcªiÔåHÞ@&ê+a,0ŸrƵˆ(–Á>]^£M6†ÎOüQ‹¾ ì½…½Ÿyþ4µÁ/D[¹›y£….›]\›�ÏO´>"ìÃ’Gª¸€¢ß‘Üp(¼4ä»Ì- 1„¶›†�n‰·HHì!K™•¥¶“g_¶Ã‰X: ¦fáÁïFòî勺 "Ñõ¬É{¹ÔnVÓ8;TÕÜàs=ž; àÀ‹—\X.õ®‚ŸRdTÜ?T“ä]ÉðØ4òOø $óž_ªø)&’¥”ʆ¬=�0xµ‹ÁÂ*2XÒ¼p,±u2e¤@]o¬¢7ªí±êYôËF2ˆÍ½d¤à,Tåì7ûÐ)*Ô+:R),ƒ¢‘g^4RtЯ KÁ©¸a-NÜ>0Ú³4Ö2�¶mÛŠ H¦á¹° ¼Àùàä±£J&ˆªJþ¾'ýñ45eÏåžu�¾õ{„ٟȳ`L@¦À/Ã�#ÙÒŠe Ckü¸vè»õ\WËW,w@€� "®ÕbÐzi�>ŽAf?ö¬Ø\Î\‡ÀA©Y Ëp�ZÖ ¯¸NW¬$dï*çÅÍS=rsñäoÃP´š9¥&«†C__G&ŽN–Σ÷'®”ö$3p†~d¬šûÈ á6.WT)1Æ ˆ0plìô¬G >‡ëÊ�éÓ;­‹8×ß×uk°qØU¦=\ŸN_Á8FÇvF`àžœ»#ª€4,¬S/H‘Ø0ÆõqV H²IHr°ÅöÆ�ñ¡¼›¹jXŒÓß—À%óKŽøiÒ,dz3QÎ�W1Ž^Êˬg¨MçÛJ˜gk\¶�-o†3$~™‘Èàe–)r[ý°Hl5—�·1–u+”¹—™¿p‚Ì£AY^WJŽ@é|Ïa ¸{©J¿¡tB»`Tì„R…OG–q1ˆgÅÅcxŠŽg@0U„!‚F‚À•н-h‡,ÿ‡úR“ÆÃú¦{BGÉò*@‹âÉœ*Ar`ØÈÃòÍ®$žüg�^‰y¾)äÔ�•fŠ÷A\¾V(¯éÉ1”Ðû*ä4£»?x‚\œ�·÷_à%Ãhý�Ê#p���²Åó ;�3Ch1i°§å‘’éL:¢2oé¥�íb¦Ê `ÚlêáÂO[‘àMH š•+Y,æ\¥À‚¢I�pì=^ã”—îˆ6#Œ8{oq |ì�JıIúQÊù �b{k´$`Ð5IYác-Hj8¥Ä¡:³2Ï;ë¹PN×lB°P_¢¼s, ؕёaÛ¯�w™uÕXÑ Èº‡ETNcw)Çú ÞA•Oüs;pº޳f$Íõ’p‘ÉW^dÐJaÓ�ÂÎK*Û—Î åÒr\ù) êõ¡d¦MôæÄ�ö4õ=!‡)´òÐbޝ"6ÈL„AB߀ç†ôá\>I(S—ÒA/]”L(>žà:)D¯L¤öze“þˆˆ+å>¡vèp© W*š§qжÆX0ØŠ#¿424«nÒ’Ê™óÃþ¹ÓVÅz²d†×!`ž>žG`G²k}žAV9g–4«Ìe·Ù. Ç°H!ê3¹¸çÞ�`QS?ö%ðIF¢ Ú2zÓr Bž%·»xR6„Ýkx'/{õ˜ÌmèZº©Ú`]ÍÁy|®"‚÷œ½áܵ‘, &‹o"Ø/eYæTqš„âÆ±Qî«ÑScÒ8±ù.sÐ�ú8fäø±+åô·$´0&ù³ˆ1or.yîHÊc-úh¶3I!F/a}ï—nyÒ·ÙŠ•ú4¼ý·VjPMÔ¼D?3 ~?C]DÞ@Tý‚ð'Z�ðZàö*7™E¾ÕT=Ÿ™Ê@µçóX/yÄqîÒ%8€éàÿÀ£››Å&½þ#çy øÃ|¯ )¹wDPŠüV(C«C_Ž fhRðßçøá…ýaà®9G§m¾NŒÂiëoq±IŒÚ¨°ù¼?dOüÞƒ t!Zö“ÐÞtâ‹ÄvN]ƒ.W–ÛMøP ó³ò"i#)ë€Ú8tÇJ¥'– ¼åB×éì'…l0ÔŠÅu~�PEÖüÌEköÁwÙž È Ì5Ý®-Hjg`/ø¨ó§‹ù8DÔ¡:r)�bG ˆµt†ö§Ž«ø>˜$­®MG8’æI‘k|"N¾JÁ‰ :tTýUOº·H(Ҽߨ*cN5žSÓŠŽùT,˜îY¡ÁÀ¥hHAø,�R@| ›ïÇqÙê2qæóªåµ†vç^Ö]Øoèšr¾)çï<ïx�HYko|ßܶ@½â/õnb�ë»&N¼ÞøSG&˜ †ãt`ý¨Š%s‡uóݬ�sÁò¶Â}ÃÂ’ Î5B,8Vûo<õíd"gOºÏH¸õ±¦;30÷{¾õÌVÁà6Q(ÔÐED$n TÈí—}³V¼\õæ¯ïƒÌñFl¡ü»Ç.+§R¿r’Ù^J»©áíš^ØêYªÃDÿÊR�š¡zX!zÓ¬×I£Ï ÿo¸�4ðþÒ á…VH{‘†.]ð¢�è8¾�¤3³$xoùpàzI­!IÂõ'xò·“Â<)¤~o‚,} Ã{ON?ÊÛ°öÉ(…ëËòÅ|k [ƒ­?ŒÝÄ÷2ü7Šh¹Ùöë|rçuxé–ê*ò¾  n˜,Ε^<êÚf`äÇŽ/2Ò¿rcÍŽ ”]ª±ç%ãø>ËÖ¿ûw{dsÂ2ÔÌ;Nó'BJ]Ù7NáÀbä¾bK›,ˆãkø”;+AÔHXù3ÿƒKyÀ¨ÅŒcn„Ç- O ›PìZBž`p¯e/‘lù/4}ìºO_¹‚V]6øëÕ¥K[ç†óûA±S9‹U=þ£ŽòÞÖ 8Y}úÄY!–<“¥â¨à6×üg¯l¼‰ÿ±ÍÃ`�ü×€ã»9þkḔ‚: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“ä¶‘¾ëWôm«ÃS|{oÚ)¼–×O+|�t`Y]TW‘e>4jýúÍ/3ÁGZGlÄD˜ ‘�/31áÃËCøðíW¡þ~ýôÕÇo¢â¡ŠÔ¦OLJÌ>d& Â({xª~Ø=�êǽ-âݵOÒjù�†ºúð¸�ÂdW/�6ÇNz»kÝJktŸ˜ÚªîÏoMû"Ï?†¡=kß— ÿééhY{c‚"Idþ’©¼È,(²Ð`‘Æ&Ži(ùëã>µ»¿Ñ_³ûÄíÿ�ßY6f“ 4©{§¯ÿ9ÕÃHs'áîØõÒ(åçóX^�ƒ<Ì‹Dß7�6ÙýòhhÏC Óä«iöQÐ4{6Ée²ïºîuºžEÅI�f¹[ÔO=ó&N¢Ý™ß!ž&a´,=ÄöA>•d«O±)Ü·†± “ÐÒã›9 ¢ÄºÑthàýÞš$ˆãb{‡S}x¥Ã�’]sį)ë#E‡ãújpé×f‰Qû$�wŸ„oý›~¤¹èÈòþåfðIñ£ ‰)6OW§”»ò|îåX»GùikœÖyhÚ®ªµ»­¤Ñ×ãÔ·ú’È)S÷¾Éÿ95}]©´$4—rl:'äÝ�°¿>š�öÚÖgÚ}›Õz©·†æ¥Õ‡ft�v;q*˺‹Ô}<ÛµÓå¹î…H’\ž…,‹˜Ç¥»²ªúz¤·;Þô:ŽPß0öÓÁ»kbÆÄ` ü^êK‡3´q¾ƒˆ=¿ }|»Ö‡rI t„úåÔNú�A~_¦²/Û±ffâÅÎ7ñ3+]N"Ö�®"O'þH"'Χ;Ȱ•ÒæÂDGvx=¿ âÅ�̃ÄI…gzæˆl>²Vld�Hˆ!ÂÖÀÈõ,ƒåV%A$QjˆFKl›é™Y,g”Óç1gn�2bBÆb“™^²ÑH=J¥¾ý¬LÌÂX ��·Y;~ñž:më {±–Ò\V½�Lº«¦Z‡tò{*ûêÜ´¯Û&±¦ñ˜SÝ×ÄD}Å�–GÚ‡‘FñŒ¹l‹Û‹h¥üœÊá$­±|f«Ác*±:�&–ýòÉã˜ma¾6Zž­;­ S«j–$»@Îû'vj öÚb¯/^輦ÝÓwì˜ÄIÉß?óßï™þ7�mŽàªf¯=Jâµ|Çb’…{{“�5öFkEê2Ç&j96Y±øj%�÷Åi¯{× @€ÊA®½HNÓM)—Ïk«9Æ ¤!¤2“çâ@hÛÎ�3­=ôu9ð9Ó`¶†h�¼�Ì´‡Z^9Ð+#­Ñg*p±Ýu-ìD’'zP •žÊ 9?ãüÍê€þο忟˜þä; ,‹üKðt[ˆ D1äJ]söƒž_˜ßûÜÅãG᮪gÅVMÖ@*µÅ(<2£d(«Ÿ|Gâõ.Îm¾Q«.: 0ÛöêhV}wu/wòû[Ýw>dnAÑ7 ¤1Nè`ûG“ïjZž­.:aëÚúP“ ã ŠÓ{Ødf!ß­Ù63ˆ²“³wŸØJmUa/iÊø!MVø!]¼%5y«Ô/!‚hw‰–¡·<Žì£Ótxèz2n×®­ö~Û¯AïÎPˆ`Ó¢{Ô1L‡yôãt†[C7oS4-#éV†Þ @[>ìsxoÃX_`èXøxl–�¶w˜ñ[¦AZDÿ6'^ܨÏÀ°n “hî¡|´á¬KrrÖ\øÌ�ɾ™‚d~8ôÍudå£>àÐçÁÞܼ̌4¹ÿËdü½ÇW�alaÅE›b9H´× Â3  ~GV1´RéXj´é€•ʪ�Æ—¾k/V\!Yñ8  FùÅ^Ç:�~àpîhQ‹BË~­Óh:ÕB§ŽK‹ Ã�Àû¡=€Élš4²) h·«{zÌâ]_\h³‘ÌC�’‰6!i¾Qæ»o¾ÿüIZM w©Ûqéù¢I:bâbׇ¦f“Ftk¯jî«úŠ8"l!¡Eü>Î{¡lËóÛÐpÐCHç�9ñBºÖ ÈÜÃýòÄÂÝAé¦È¢9+¿v½Záæ‚v)FÙìz2Ï[¡o˜Yø&ûL˜½a”°(d!Ø+ngbé·WÜÀý’¦Š­±jkhºš¬Z¥Æ8Óc!Â¥?¤à‰ù³JR¡¡ b�S9 MYL´�ü@5µÑ7ÁÉ•= ˆË—ZÉg'�›CÿŸ}ÂsÇiö�ò»r72KʪyƒáJ’+ì…ÔF2]®žn‘€<ì»j:0é¹”Ÿ‘%³ÛWćv ö0úFß—o"-_ÐŒ%}±—hCLãjîEj ¦H+cþhmK^€c¸¾&@7�À 2HÌ5–$ Žˆ¢;! –�9yµótiýZ³ÌŸÄËü‘Ñù‰¸™?q!4ÁHE Ó*uÀø·>Ÿ¥%§ä\1„c^µÒ¸"S‹ef¤Ad©ÉÌì�¶ÔR.O=ÌŸ˜³(#ôŠãYÞpüÜÑŒ'ìm¬‰mß4™( L6çi¬Œ0áCJ.˜¬129$iæ!"û¨óªËÍVc¯&3^ýƒñbª É ­¾ƒsº_‘L÷ÿ°ž9Uõë[}&K6ëiË–\‘f)ö&Ï‚¬ˆn¼Û õn½òÓ˜õòóÀĉ›Ú‡Nè{A¸Í'ëj"Tº!¥Æ¨gÂèÙüÎ-«¦X-‹î°ËìR¾¨â®‘�šT5ÁbúÎÒÅâI¿Ô§‚Âñ›Ë Ä/á h’Šñi)»D2Rm7½œ¤ÍŠ•sV§9H‚ivEÔêqºÂÇ!Ì€Zkf†ºÆúpâœ�~tv²^cÌž—S4y¢®d�_é9¾´¢nbUÄ‚—{36È8¦ â"ÙÈê6Û�-}X :>jšáÁŠhWc÷Ò—YÓ&ÿ)Ó›t6íè]{ŸAœÜÇló³±/[ 0[­A¨|„D³ÿ¨$±W³±çX“©}]oÞ÷…âlzŒxÎØ!Ú˜PìâØÈ÷Žò:ºXjè¼3ZðÄ£4sÇMƒpëlÓ�³�9;34¡âP#"Ÿ î¿ôšˆcŠ7j¶­ü”j0f7aˆÇ¥OHÈ ÄùqN߸ÐËlâ~æWàõ]’Da#/¼+jl nCç÷o‡ó$)ªÈšÚ¶Žchr–‚~Wþ%RE¿‚&¢(rhbŸ$)[¼œâ;ÁfØ:E‡Pbù¦¿�Ÿ%¼ý:¨û$d±v»7ž¸*ýHê"ÈÚR¤\³Ú R‰¤ü–‡R~të0œÌ­Ý+£X»$—©=4¿ùcœ#‚ N£‘«F1Iõm ¯ ¶0/ ÄùŸ›¯u DRëÞ£‹öùåVÀI½§V0ðm�]–‚L–,Èt­8¡�¶ìÉ¥YšÛ¸KŽ0EšñCjN oZ˜•Ä¥ÂW xb¡§,d²À†™³˜G‰Ãxö„ròL³eu‘ œêu³$(Â[F{NL¶¤äåÒ7 ™Ï#Èþ=˃æŸÅÓ•J,±•Q_ÃAƒˆÝk‹V1W/Ýïƒ�M`Ò(_ê–ÏõIrMç¸&&À,n*5Ù²EØ5Ù"Ó¥?§åO1ñÂÉÇJzÖÝ3úF>>Ò'?éqá#m›Ä„eé£q$y 9!2›<Éì òPâ''<áð�¾´™•üç(ê“¥ZÖ̲ݚÏÚ7ïýêÕ³”¥‘l 1àuÓ¸ªéëwŠD�õR>á²ázH´:ot õ‡�ËgŽb¹9¿£ÌB$šäZôØ�?ŠÙ~Ps®Œih9 tOϵ¸jÎh\kUÙP£úyF?¨ÇœüÊóü97—fª|ÁË88éáÔ�•Î3 —þyÁVÂaÐà½|G)ˆÕ®4²ât>º> ÿäÁVkGéÃŒXà9“`P¤�9á™ÄóyyÏ fˆ0àcV…ƒä a+gµg³m²‚èÃ:DÏǾ»ÈHá‰TÙ¯¢n¯õ…™‡�´¤ÒØR'šõdxfHÛÞŸWJp–>[[#É�˜#+š£b0[ÑÏúöûÏ÷…Q{7rz6/Ñ£¸Ì…#>ðLy´”žs8Zò©8«"uÕ&ô÷ÍË … RûN–Rõ]&2�3‘Œ ã�DÖ«¡á0ƒ)d †Ëjxú; ÁU+€“éü{FôŠ €<Û  Zá°éõ% ,”¶“÷.u9L=çÜ}•ÔU(uâ$*Râ�æÈW^…éÛL^ªH =e¯Ùt Ä&› |¾/Ï@`Äå;Y¡Ù㯯 Àã?wÓ¸¤÷fþ %µ,ãý2JFá³$C5qŠã0 î/™,ŽÝ) B;ÎÃàWò¼YI^l}(S\Pxáp­JÏ|/³l­DÙpYõ‹~‡îRÏeèQª´¡~Ô ³@Ð"2!ÔRþdhÅÊä*ÖøEÎŒÙñjv·ÉsóÜ zËI Îȵ¿I�Äà>T~§f3'Ô#ì¢Ä¨: ±ŸØ+*þ‹8%ÿ öNúþEª­HB2y”op~@_ôcÖ h~È? 3 £H€´yböï4Zߤ7i­bâ2F-ÉktpmÂ3ýwM;ýºp*º|�6ÖT_»FRÓ„;Ꙭf¸Èã&üIvòKXkÝJzAÀ<à gx!øqÖó)Èa‚šQ„ØÝý #]ëd®p!ÏÇê«ð¸øØj¢�Cw¹ž]š3¦p’«3äĉׯB!³Ú8ÌŽ¹œ3h[°žÍðÏz,)’6ŠÃUu¾�ìÿÓ#ÅQîÜ1âTŸ¯¬R1Ô@T$âuÙ·Úí:ŽRߨÁ�¨ÃÁ‚«Ñ’Ö¥ät*µ¶B»\$,¤tªy’Íþ\¸º+ú*ÁÕ*2¨, h\V Èð¿N³8Ý%zŽF£"KTŽ^_·¸ ~6¦¹H¶è\î¶ÊDíA.å¦.’ÄÍ ¹Q›R$=0)83áå,ôýeZ.MDj¶è·kkuRËMóoîs2 çÈ]ÃzÃ…„A_qŠýn1ǃ‹‰3ÜŠcXWeF Æ –F‡øÜx{ R·•Ã+ÍpÄŽ%qâÊ‹w€Fï¤ØÖ~µüN-b܆G¤ÈÎÉvL¶Ð…în çDnpÅ*wËnš Þýë¹0´ñá|SW’oR¤çò°†T“ÝÁßçõÍ”û)_»€˜4ív+þÛe6È­½ ˜ðúZ~™ UŒhãR¦q.÷¹om£R½�°1WÛÀ,¦¸î‹âþksXnð"ß%Ü“ÎÛ=ya®ý�™  `hxõô$·*˜~įƒ´†Ë rC©Þ÷gNÅášSiäsÚRTÍ{ÛËDs=u^í\ÆÅ ¢ä&�Sƒ‡rUwS\^f³‚$¢tŽmqu Gðz¾&Ìä …³ *ì’äæ:M‚:¼´ÚN~/åψp¶N|,+²[w˜�€%[áž½7ô>rèñ=öeI—ÿü¡FÂms»lC±uvÇBÇ&Ìõ»lÊéœòüŽMn+E$·9ýãð×ëè;Mdi~ÃA\ÑËIÒ1ƒ�Ù@‚ªL¤Ö�·sŽ ƒ%Ë£ÞœçœÎ^§Ü&‰¸B€D§õAbR«ÿ_nKN$%šoà ½d)!UKSóžyÔ�àÿç›;Þƒ(÷FÑýI¢ÛÿÀ¤º°'dçuBI¨Wbâ$YÃ><2ì“f3È/þß ûejwí¢Z(×{ìò•Kùks™.òpWL[Y#Þ„\¾uHzf‰]n�,K°ó½íJ÷Ç®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ç${<~ (t73©�T·Û_Ÿº€WAv²³/"Xq)Ô½JÑænmÞ<‹Üóåûgß¾VÙ& ³D&›÷·#7FDa¤Ìæý~ó!2ýsùòj+•~ŽttõñýŸ¾}­ÍìeB)`:È?á�g×ïŸýóB£�ØiBÓÄ&.Ï>|Œ6{èûÓ& U–niäa#Ã,Í Umnžýoo±–PQhd¶Üãc[ö–7¶8‹’¡”Ù°³cÞæÛÛŽ!~'Š#:‘Âw>ੳ-·ö¹=45·ÛSÝáì›m…™N7[!à©yÚG¥qÐß[nNU_nûûÖæ{»w°foaI Z2vK¦:èŽUY”W"¨ïPvüI^ôå•ÔÁþäý0ÓmÓÒ^¢å.òª‚é34GÛæ}ÙÀ–á]]º³D†I$ÔÐ&¬çÞŒ£$Ù$i*øð×\œ‰ÃHÇ4�¯‹(òÜ›Ta&FŠzáÛ~h`®¯ì^Æ"©úÿؽŒã�±Üý%²“Y˜¦é´ým,Ó ¯÷žsle$-Ùò2/^G”†q\*ØÍ¯¹X/Ö’¦Àó̻̓÷<&ŒLrÆFqxµÕB»J£è_‰4¨ìmÏ-&Ja‚˜£e¾e~J’PË?áÌ@ê:¢ç'|\¶ÜÜÛÛ+=Àb `î¨NÖ}CÜÏ,É­¢©Ž"ywrlº¦³"3Å@RoáoWFMûKÕäûqü#:¥Á#ïñð \³J‚®om×adHy‹»»µ­­{¡èxdsË ×½¹v�£C‹›~�ÇÕ0R"&jÀáö§¢ ø”€¯¦mNw÷ y2ã�×@QüÍ=\A±õIÀ}ù™ÖAª�uðˆßDp,[Ù‚d¾åøÐÁ®ü ý=7èTð|ÄkPøÝÕ6‘28”ÞE‹p§ŒâSaã� wAÛöù>ïóíj Áʺ·uçĤÐ�¥�âiT^u�oM‹£?jÊÜ žK¥*x,‘h°•ãC`oÐæõ�kâñù÷oyTW~ÆK¥ïj7�ù•Œ‚å�“QVÛªì°W-€]¦íW@mÛ ø‰H*ßU–ÇH|H þ®hËQ@‰½°±@6ƒú{àÏÁéÀ«‡cÕàgOvk&Y6’1vw%ô—·OüFªM™,tÔ}‰ìT8jÄnFH4nÃ{ËnoÒHæQ¸Ö˜èù:z?:((c×Íãè¾ 6 Øz,I[Bß¡F=]@cçÒUF:”‰ø´­}Êf;ŒZŠà®q)2R¹Ô"Ø7Ÿ>J%HßQÙú¤¨ E4îeœŸ©yåÕs*„ƒ�ðí_ FJÏæEÕÚù¦Ü‚J Ól%u[ÿÔédÙñÔiÊzÏ;w ‚+?(þƒ9 Ø/MºÕñ%e ƈ•þÞV~$›,=›ƒÆbQç6 v±DÀ{¢q”— À- K²h›V1ÑüVL˜ÅãNþÛ·Õ0ÊÆ TvdH�jHØ„û<'‘ xRê/‹šd$×…6aG…ÖÉ�—¢äÎk†âÖ˜TÀ€ŠÓ•Ñ2œ;¬%ðÙ—Ë­²æçL¶Oh®Ÿ×&‹F\ãÄ5A0�[Áæ�Wõ”´m ¤‰Ú íÅ:¯ž>[.ì#WÀs¹‡Ž?u&‚$#óK÷éú&e Às@0êúl²�±ëX¿`/YZÆ�¥àîD–$)ÞÒó­æöiû‘ÆÐuSžjàÕÉgUK$ÐØ>ß•6h rßÙýZöRcô‰ý$ ¹R gš·%y®ð¾³ý£µ5¿¤ü { 2Â'Úˆõ©f@3°smÞ*4Æk9·¯†û¦ûBM³à¥-r²$�™on^uÜÊ[jÚ=9ÔF–¬ò»ºìO{7„]ŽŒc?s’Ý™à�¯^ud7§y"¸¹†¨z×Ft>º®¹uÍw�X�à/ÝùW% n´mxÎ$Jæ¬ê>¹œ~»Ë;^':£o�2Íèt H5Ÿècôª^—•Ý�štNÖ!áäBE�2�×ÖðóÎÖè»XçÓ¡Í*gâoácù|²”—¾wšW¸Mò9NGŸw&¢¬€1¸Á~± rìíÑ¢™ÇÌ}¶Àó½Í‘ÎJ�ú`)� GÆÑ#º>GKHqÎÏ¢ïTqUOÌ58¶oÚüÎ~‡<”ÎéŠ>Û[/9?”¹0Â]YCô ïx´ÿºÒ: ~�d×ÜÙà`'Vï-aŒ¡™Ê‚P¤[À‰�ÏïÝÅÜW’À,±ÕóUòKÑ8nfÆÓâ ޤ<ŸE:fÃçä%_t˜Hâ)¥×ßñ1H�× \Ç�¨Bol~wEá2î¼áÛ{(#ôŸC¤T¥ ¶ßýô£WáŠ8yóÒÅè2çNÊLÑšNb®ù ¥bøß¥Þþ8yÁcdñd!÷¼lØ \/ºÄ�ŒA<à½H‚Í„d�Îâ~€ð´ƒ,7Ù9+�=pÄ+K¬?1YØözg}+¿3Åo’¡ç}_Ö´�$îàñ¶ "Aèp^ÿÝÒ]ðZkåæ�a½ùãgßBøé¯¼9 ë„%ÃaƒHÃ-qìÝ÷?2€ï‘4JY±cŒý$dðyï�ðö†�Ì[>j¢XÊu2Œâ7/—€¼(@"³ÐBx»µÜÅó¶‡Ó‘»ÈXÀh Y3·¼l4¨&KçrH3Ã:¾µDÙ2 þcñ<4üÌüå'ÇC[³G´^ñt¼k] Ú™@>ˆC Å@¦oh°¨ÄVUîÚ­1ŒL�!êž_¿Qi²»«8 Ø£BÑ«Ð[¥CÍ %�ÖÀÖõ§>æÖ!>bKà%„�\>šøÎö8·»'—nï†(â°ü<¦ät>È4´QÔ•N†²„B %™9•u/¼�!÷¹“§9¿?+!`ß''½Ü•wdƒ3u_÷a9_€9Õç=GŠVa9Eò ŒÒ®Dâ0‘»…IJ7vµ4—�X©r„El\@É÷CÞ³}aœ%…#FùŒÐ¹ôñY’Dx1PßaLfôžA­%Ö¥fŒ�mL!,òÍáéRe¦�)’Ú ž|ÌÊsÁƒ5IfiÿÄSò  “¸g6;ŽztSìËo{Ïox§;}áªüó�ʺÙÛ¡Yb Æ…HôÇ�ƒc?¸°–-ÙQÂÞÌ-TÐM¥¼Ý󠋺~ÊÝd,\2Të[°—zÜ4ýHU`«¢ð3¶zàØ{ü2ÇìÃäó•qˆöØg¬bb‰×-ì±çw7…`ä ¿ ‘…"•³°Ø¶ÝoE¿¾PE*ÂDŒ£Q³&ÏQm¾ðçMÐX‹—»¾£´Ã5”ôÆ\Ò(Y6_Á¸Ø6õF�bš)wõ³ílû`}Á­$ 嚘ì[Þ®ä@\…R$‘<¹3è+4D£àú�¤FubZ;_ o,�ó¸ÜÍk¼¼‘iØe�¯¨xÁÆ%ˆv ƒkìOH⸜ºž[9?Ž-¦ɆÀq}ÓTÜ�zŸ;Ôç²Úó€ÖæÕðe³÷’ô©@"•™¡ÝI `Ú7ýÓ‘c,Qæ&íyTݸFÎ Çå-9ðí-`2dµ…Žâ¨…¼Çäöð¤D Ü$*�RÆN_cøýZrEp`KÀÖ¥žÈå$GÒa$&ëzþÜÅÉå ¢955DÊÍ 9ó ™Û0x¸Á5)Ñ£ã@‡jaÌ?”4ÿcÇcXøÁE_fDxŒgCž�8\ü JþÐ eHAÚûöTq»¬Y—°ôN`c¤8zc2Âaà[‡¾¥^Ù8ið&—ábEV†ü6ÅýWY¾Wø¢Céå3XYª,SÇ`ˆRb±Ÿ�ì`eœy±úÛ¶¨ð�ýx�ûÒ0¸vÌ�˜h�k$ °Š®šY{º>´Õ† vîEUÚv½ß¤Ì»SËQ–!üªÐ ¥$à‘øJ%$�o¨/�Ý·�-†Â°Á�Ùn®Ý¯ó9øÔ´3쀗�•áF(¼Í6èàÜè(ŽŒ-V%0ò¦Ï‹_n;†‚s>¦¨|çž³Þ«tTÆ* ¾ï´ŸÑYâèÆÌéÆ1?(íc†‡™9¶ÚŒid¿ŒK.d,Ùy‰Õpšïð8/Dà.ÇHKYðÛT�/¢áB…± N„´ “½ƒÂCޱ AÏ�à­°e 5Ǿ<`8ÏÅ:’(L…^¾½›Q¡Ƴ•·ÇÞ·Š)LïÂÇ 6P[t{4pBÛvÏV õ’S3½€Íw¥f$/ä Á³Lÿ8 ãduŒ[÷ºÑàr-B(RF^³¥ùt^°Ovò_¤(Y¢9W§*¿`þ�Lk«%ÇЦ—¯äšãoGGÄðEyU9Q9Ú{„PY… ]X�§Á†cO-«éˆ<ðe"m=ÊjDóô3~¤x`w?a_@r×5Õ‰Â|Ù\ø8ÝÏŠ"3n+¤ß9ªb<è"�>C—g=žãŒ—ÎŽï«ü”I».¡Ò`ò<7¯–®-ð£Ñ+K+Ñ)µ)~‡í¢ÿ]“ĉæœÝ¾kZb?¥`c´>h®§‹þ¬;× @’t‰ÌËMXY#`ë–ÌlÁ6»ÎrÂ|�U¤>á˜66¡ð„8œJÇÞ´WèwÙÚ_8”¥££uy^\æ�·cªaäas$af@‹³Í®Á¤Và¸=þÎ'uÂXÉÍv6j:DYïËÂ9Þc¦’[Cî ÄÈ:!¾òϣѭCWoâ\.‰HUb�s¿¨h"wõú9÷ë!cýéRaÈ“ËÌ.9�µƒ1g ¥;™®'ÓT æ°þ¿Wè»�ýôè¯TSQº¾ !fª`qRS~Ñì¶ü[_Ù% Sóe$‹Ë ”sQ�¨ ßòç[Ðp‹Fúâ¨Ñ�t]GNTä“£.·=}·fm"é. ›êy~‰†’Ð4»Ä2L“Ñ“|Ûâ`F¢gFTMu(Ï8ûe–SKhaÎH ßGóÈ%”ÇÄN»ïÆÚ`nØÁt#ïkÞƒ¨t�Ð.KÞ„Ñà¿%„E¶2 „')­³yÕ–7ù,ÃX�áÂ÷ O=6.B×&[,Í¢l‚ ǹ‚¤ƒ¡Ž²/„j_`)g:æÄÛ 0"§x°un#”nÚ§Aº§àÛ=çl…ûÂ:V ͩֈñE‹!_˜Ã*ööΕ³¿{söçMõàîûíȰâ7XY0ïm>œ¼SÇÐEõÑÖ˜0‰Ó3÷t(¹½½{â'“(¶ïËÊuº%)²Cµ\3ï¢ã!TáÆó|Q~²ÏAÁÐèùz¶¡Š�ÿåF_ Ù8U�òÓl2™q_—™“‘ƒ3ºÀÕ@g‚Ì)|‹'/(4ZWõ.©O§.N2ÔeakÍ*å &sŠÒX 5�] .X5‹Uµ«ü£'Ú5¨j‚8zO’hAvšH€�è-`Xþ£“2OüTèÝ`ƒ)[®:m¢lGfàµL_àªèBnMxSk&¦BZc9­\��•ÿˆ.UöïIT·þ¨œ¾ø‚FÏþ}âüÁMåòÒXÕØõÜr×Bu ±’ký:iðx¥‚¨.46Sð*ŽSò[òCC“M}D ±«�Ÿw൲s‚½M]=}!Ó4U®VvË•÷®ºu•ö•ìª5˜CÀ~6rÇÚ×¾¡b<ì‰5ƒÎ‹‡}±;.Màø”Ì†?ƒˆ3Ð ÛÝ—WÎ8ªâWXàûi�•�‹ú¬Œ¡ÌgR$I(T¶äÏqGCúë[Zf¦×<�úyà,ÑyýþÙ¿a�� endstream endobj 105 0 obj <> endobj 106 0 obj <> endobj 112 0 obj <>/Font<>>>/Length 8953/Filter/FlateDecode>>stream xœ­\M³dÅqÝ¿_ÑKˆÐ´ëûc)‡‘,KŒÂ É F`› L(üï}Îɺ·ò6ožÁÓýºîGeeež<™Y½…{¼þ¿þýäíÓ?|ÔoŸ}óTo{Ê÷qû×'ý~ûèçO­Õ[™ãöö©Ív·Ï_<}¼|ýÙÓ_Ÿ¢}^ÿ|òöö�¯qÃq›·×~²GÄ[­÷Š«îþúíÓ{·ðþëÿ|úàõÓoõ„^î}<þñ)ß÷æùžo=ÝGÕÍc»Ü<†8ÝÝ××pû2ðÖsܧÝ>Õ‡û§öÝùå‡Ü»àÕc²;—0n]Kð¯n_ÀíóÄ«ÇïÁžÐjÍ�!îð˸}j|ûÞ¡IüOB?©}?a´z?h}níÿœ—O ÷z ýöêüôÝcÜ{©ùÉþË÷øÅ¯ñú|…˜Z_o`äÀŠßTÿÀ¯>üð—¿ûÍ~…ÖÆñ úøc¿Bƒr>¼Â‡¿ùà×ç ¤Ðæ¹Ç—ù%R˜÷X®/ñÑ?ý§ý¥‡ýëË�ýeÞÓÃKüìW¿ûøŸ÷[Œ÷[¬/?ö[ŒyÏßů>øéÇœï‘SÏë-ìã�ü9Í{yЉŸðú§¯_tÝÿ3G31í°î¹ô|šú˘—^.¦õv° ¯h æ½·2 Ìù½Ïlvÿ×ß¾ýÓ›¯o_ýùö³ß}üÁ�o—Ð+®ˆwZÁO!©7ýöÍ7ÿýÍíï}ñÕg¢ÛÞŠ^n¯ò½ÛÐtþº^oçoxÿzéa³bm÷2Ú 3Òëñµ^ÿÏ_Þ|s¾Õñ¼þdæ–o°¡E÷�ü3Ìvijҽño¿/—÷_åÃ{9½ÿï¯ÿR»§ÛÄ”tI©ñ—¼ªêªWÇßÏѯRÛ—õF!¼:îkÏÒ"§À—‰sà+Ö£Ù½ÿôÇOþ볯¿úöËOoxëoßl£sûì)ç™dÖ+®™fn_¿yú3Öñ¿Ýþíöåøô¬ÖÐG<°€¿Z[g²Ï_¬Ïj÷Å9ʾ}ŽïðúsbèHR¢\0ÓL!u¨ˆ.�Ž¤Î»•{ŠºyÂÓ _ jlJ ”X¶‘*VDcè˜ù\‰Ec ,iì³ß›žUåœâ,é>£†4à:-ÁÜ8¤…zÏx¿Ë Í1p*WõÇ©¹¶œï�/8àñŠfÛèм>5¤ASš$BoûÅ»'{î°R~â3†u›câ�Þ2ù‰O8sÈÔMÛê>¢ŸølýžýÄGJ÷0ýÄá(î­ø‰�îy¸‰ceò+ê'Þǽµ=ñjZKuL|†FˆDöÛwjÞÇOX®´¬K BL9:ùŽß^ÐIw=[ÎËlé#M0¶Æ¬oŸ?ŘMÆ1]�vVã”pAÄ\lW´;C(àÚ)Ž0$ð—’5¦B¥¨�0½�ËS¬°1à±j.’¨"—‰# äKÂ}P7Ö ©iR–ZÕà¹{–VX'N¼R½µšudî%ê;=*Ç ¬ám¸I4©7†­Ä]P¦!¸ˆ{ r³i9ö1F·€'ݦâª�å,سڬ@‰�{ P×}ý¡C£bÇ»Óä(WzG¼N¡ ‘ŽöTø‰6 ¬1¸ªcVÜž6óŽ�Lt¡ ºM£‰ÂÆ·Í å�,øCiºGC¼•°–9W® Æ `?L®à0\ƒ«*¦”C7ÛG–M.°„ËÓqqêØ›QgÚš õîyT2@ féâ˜ÐðtË´YI Õál9m¨ê½jJ“Ÿà�aú²ÝAÇbäÅšÕ¬2¸Ø+Øú1œÖ:ò%š™ \Ì÷D¤1@‰Þ˜s13Ãùµ”î;o�rÊ\GÊD‹ù¼¹IÐÿn;ê07X9 v›ˆo0¼¹‰ÄÍÝ™›]Îò[‡¹�!c(|š› õor¢§¹IPn{›enàS°½‹37�9î–œ¹ÉPe<™Ä>yÈenJŒk¤)Ömm Ô¿�ê¬M„‹»_¬M�&›í3cu÷eHÌØèq6%_Æ*Ýè·±©‰½;cW:Áml*´ê⌠b˜|7ö¬M….'{�embÁŸº36PWÀ”ጠ6úa‘ãÊéÛç;Œ¥k‘9;#Ý>l��5ùdšo[Œ ýQÜ ÝkA¯H—î§jCœ4€Õ“µ¿#M|S´Ž÷Wl> ŸBOg4Œ­hVqSŒßÅIÔ–äÛé¦ÅâÐl1ÕBŸ#`¦³u?bêA¦Àf5ãŠßÇÝÔ§”J'w‘mâGLMOg?âîANBoL@ˆ‚hkâ‹o4`…"ñ#îîÐ:›øAJLò"ZéBt8ÆÈ@á+}üwP°þÝ¥" ©Ñ-UéCÀr/¡‚yØc©h´(¾½T<{©J™¶ çRU,Ì^*ZÎs©ªv•_ª’¢ çR ¿T… Ã/Uµíë–*Ø_—ŠX‹øä\ªLxýR0Oí¥‚Œ fÜRÕ¨�Ñ-C¢w·Tf”ÜRáF´*{© §_*Oš<îî�ÊssÞÙ1&ÏüðÂŽwÙÁ<§½¾ cLlØ8åM0™, kϘþÅâL%®·°8àf‚bj–,&n^Í¿@ö³hLeh ç]Ñ14$6¦Ö#†®ˆ¡ºƒfQE6/D;5f0Œ†ŸUXÄ!„Ù „d¯3T ®Ç‹æˆæ¨°5Å…@1b‡3cè$|˜±–R± a“Œ´#æÌ‘a[½ æÊiw ;2ñ£Õ†TE&�†¤[D†ùºvWŒ‰ø“Ü!£/ Lˆ0†Qå3¼  ý Lî[Nl€¢À@ô�™Ð*ªÅ*6$EÅ7ƒv¤,Â¥˜Ë„P^‘"s|ôþÓ0qá¶±hÆø•Ì1Ü€¤oaR6¯Š­<ìQUÎ á²b nbFFŠ[ïhêR÷z‡ÿ¸®Nïhꈱ¶ÞX ÌÚéY!ÌÚé]€¶F¯w9ɳ:½cJúæôŽÄQ÷z3÷‹ÞM¹y§wšÈHÛé]\pzÚŒ«Þ vl½Så «ÞŽ¢àMÇùí(êùŸ^2ÈÇL ϱͱ}9‚& Û³ÈtoÄôK äM›k˜ŸW@×€DJ K ÄM‹Û‰PâÕÃÕõé Í�àŠ ’CW•²‡Ü€7¡´#ô‡ë'ù @1ÈâZôÀÐV¨o�¶˜ T›ö6“kŠÆ @K;, ¨ˆò^pv(æV¡¹À]’åhà/�nÚÁ `Ö /Lj‘£9BŽ�²Â`T<ÐT¿6© iðšNB¶GH··éR¿#JᘤìK…œ�O�uH‹É¸E²""0oF)F„ÇähŽH†c°K¡úÄâMb‹t5£= ÁtbQ ³T¿emÍ#Øá˜ŒyƱÁÀh‡3��G>è ;ÝLT«2G@Dþ¨uQˆ¶57ÜqņÏhßĬÂEû˜ëŒNû„ ­óÚ—Å·9íŒ�º×¾†µÉkßÀZÁô8í# F =µo0|Nû*¡MqÚ7 7x¤Ó>²mÅk߀ö%¯}&êª}:.ÚWáÞcôÚ×1L×iÉ5¬óÖ¾Îy÷ÚG +æ´¯C°-{í«ðÝð…Nû:ö7VÃiÙJÌÛi_‡•ÈÅk_~*^û:Œ{òÚÇJ xA§}> Õi_š‹é¢}0À¾NûÈÁÒ2:íƒå†vÚG£½öÁóµì´OÆy›Ùy'’ý û¤â3Á Ÿ£Éi‡pPZü¸ˆq&W5�Ø|Q6Ý’Q„ ½|=Ùô vÓ¯"aåЃK˜� Ýß²Á®jÄž¥ø$Òó-a½ðC/�!U”$‡@o˜°`F Ø£ê™5àr툠>eEQ–øbT8[2›ûjÊGàM“‚Ø•Zà2ò72÷ÝÔ8ÿ°Ê8‘ù¥·ò‹ø³ü é ì+«kb7ðr\!#¶™½/–[ð¥t«ÿ±4™øñBɱ§ˆ�cUåt®�æN‰AvJ“- ÄÈé̤‰CW—yª^l'òs\ -UÇE˜:3iV¾8‰6³l›xöÀ©ÏFH¦×!íÏ©Sª6u¢'L]Ù6¥pâdÝ[?3r�aês–Ðd 9é_ÜÚÒX+#§%�-ˆ[[Y;Ž�ÀX™£Òo»O_Ü$nms§ÀX/£´�Ô @s_©=ŽÁUBù[ÁQi)TÍœ)–Ô(±§dFˆâL�äÆ,³Â'PüJ2 Aþ’Bµ™S^!¯äŸ†��3=È�k€"ÃVËö×iœ"WHjJi±2‡éA+  ½59WAÅwð .Š*9ð ³ÎÍá—4áÀYÒâð ÝutøïŸ 8üÂj?ÕÆø%�9Y=³ñ €¬ Ή_ Ϊª—¿àÅ¡ÒÆ/ªá Ñá,\aúwã—4XiÐ~��¿དྷj‚ ¿Àå6N{ã@ qãU²åÄ/PX-ÆÆ/ÐŒÁ”öÆ/Pü`5ÿ ¿DÊŠe/~I}H16~‰f½ñ ¶¡lã—HY5�_R¯ÒÓ�_¢ê�£Ã/° ŠC6~A<ÚUÌsà íš�_ éL|ã—Ô£v߯/°SuC'~�vDNüÄ/‘ÒšÅá—Ô†B´�_"¥5~I G9ñ¿DJkqµ†_Rc=Ípø%RZ,„:ñ ñK¤´†Ã/‰ MÂ�_"…ÅB²¿@¥¦,ˉ_¼3ä?ñKª¥jâ'~ @êàÄ/€‘?ñ‹¸„”~I5v™Ë¿ˆ“`y܉_€hä­7~‰×ôø%•!Ÿ¿ñK¤¸`š6~Idœ8ó¿DŠ &nã—Ä4§~â16¬ú;ñK*¬ôøE̦¾ñ `c¢{ÛøE+ Oü‚Í=4÷¿ˆˆŠ¿ÄÍüÀ/‘âb%ã�_…ƒæ}â—Hi±öòÄ/)÷¦¢Ó¿DJ‹E“'~IÌ«rÞ'~?±ñKÊ¥kÞ'~ÏÇÍ¿ NÈš÷‰_Ä&�_RŽTF‡_Ä:bôÆ/[¨Ó¿DJ SßøáOÔÜOü)/Ì}ãÙ®¹Ÿø%Rbø´ñ ¢1lU‡_"Æ×¿$èÁçÆ/0-âE7~ApHËá𠬘®�_cMýÄ/CÅpmü‚!MS?ñK¤À ð�_òÒ:ü)0‚¹¿$X4‚ü�_"¦*á¿ ü–uÞø%R`Õ'~A¨?5÷¿À¡dÕ#Ÿø%2ÂH¿D5Ð4�_àlüS®Vù|â—äº6~‰”CŽ�_69ü)-=nüÂ(�_"¥ÅÈÏáqÑácœ Ï*ßO" ßAÖ¿ëÇ—Ø¡}‰ì[<ø!~< žl�+x"…Ö=aš(ÃéÓDn8º>±ä5xºK#4¼ Slù£M˜Â, oÂiÈÄ�„)‚H¡á“0Å~LV½Søaá“0Å®–�Ý„i"ÕÙaš23YŽ0M$L»'L·Ìô„i"í:<]�½89íM˜ªZ)8º>±69yº^XXx¦0�1›0UASöt=L°ÀÐ&L!ÎÀyo†¼râ›0UÙSs„)¼›,7ašH�wO×'šÉééúÄìÌðt}bawðt=ПՄž„)„&À¹ SOEO×C×g¾ Óg´�ag½h_UP·µ�Ák‰í+V໵�Apòt}*I!¦Ó>ÓÑÓõ—BÕ­}­Èoí+AïÖ¾½ž®O, ž^û´¯{íË=>h9†zѾ\Å;í#WQ<]}°µ�”Gòt}b«]öt½¨“èéz˜$‘Nû*}zº›L‡Ó>ˆÕ—½‰\$Qâ´¯&¢A§}€ë´úNûH,UO×öˆ¶ñÚó\<]Ï)úÇkìsòt=¬˜h$¯}MXùJ×_ ­#ìYôóŽjÔgzÉ0ï }†tfR×—Ó8Û@gœVè(Ž”²uW<©�¾©¾…s00Ь2×mŽÉzø]?)ů¾ÆR!}±ú–¡×R|ç6£EWe©�˜w¦Búdå-l±H0ô‡ÝÁØÕÕa*„‹¾V“cX-ÂÒŠ¾jŸÛ¹Í1zïBM…“ÁsrÌœVßÂþ—ÕŒQ´�Îݥξ˜S¡ë📺U¸°Õful0ºÛ›#“bØõž £Ûuod2¬oQ…Ö ÙÜíÝ‘Év¸šÐ·V¬ìêF9f«paÿP3n@ÑÝÞ@sÃÕ�rH˾´C") +é·ûD@‡‰;Ó|Õ½9§æu�|sº‡s?zÝc0®—C÷r €‡×=ãµ;ÝËR¥xÝ á³Ó=”àmë¦a%.‡îå�Û5�´Ñ­Ä%že¸ä¬£×=2.[÷2ËÚÙ�°u�¡¸j\NÝ›Sö×écqÕ¸œºÇzfú·ef,®"—S÷fÊv–¹3‚/^÷&óÞ0÷�¬Èåн™û5‰>Tã²uo&98� ÀG¯{L¶³ŽËáFðý¢{Ì™ä .`Ÿ½î ¹mg˜‹«Èeë^Qñ`˜�™ý;«˜+�¸:óðï*cþú«OÞ|óÍË•ÌMáÇó•Ì¿]ÍÿílHp•ÌÍ*ëU½ÜT⿪š×�õ•úæZ“Ûh×]v.^[“É)][“¶Îµ5¹¥ùКÌÜþµ5¹…xmM澸¶&מZ“Ù¹xmM&‹smMfÂýÒš¬.­ÉÌ¥‡ÇÝÇø˜!i¾?[lúÌ/,оêËÎê&û²ŠMmØYlÈŠYu©²½ˆç¹[­ ,2O ûMr#Z’¶is²v¤„U!…­ÃjÌsÀÞZ ÕàK’ †„�eÊÉR¨7„,“€‚%#7dIy2"ê �´êª/Tùœ²˜ÝîÓå÷Y°a´«ËØÒ6�Î\=l a{‹±t¬d³# ŽJ¢lþší-ÆÊ²f®2ó|t抻¢ êìi(F[Èx(ßl•äÉÔ“¹VÞ/ãci[Ÿÿé¥å?.P&n·­/gi‡¹Ò¶‚+dS.P” ûƒÂÑÏ»êŽþ Ü2sO²?hµšÕjÁÓÑ ¤$éµ¼€lØN·Ûƒâ Âî h2oQʶ»ƒâ0‚CÝA&s¶Ý@æ»;HY5r“ôÇ«¯KÛvw�Rf¤éúW/{rŠkŠ“=9EíAÁŠ-9œ€álŠ“]9IíAÝê:{e%¦ëR‹­ÍŒéU�.Ø«éyT5Á3�ùÏþòÂÚŸãEU탣֗£’†£v[~R#àÙ'�etmùI]€¾-?ƒèÚò³º}[~4zеå“Þ›¾-?‘ùómùY=€¾-?©çÚòI ”K[>)¸viË/ÖèÚò³‘q»-¿X  kËÏÆ´¹¶üb-€®-ŸV¯^ÚòY.Ù|[~6ŠÌµå“É—¶|ráÒ–_é±.mù´zùÒ–ÏÆâÛòiôÚ¥-Ÿ¤_Úòiõæ¥-¿µU%z´å“EO—¶|ª|i˧ի—¶|¸zi˧Õ¾-ŸXq\ÚòYc.mù¥Ü¤®-Ÿ8+_Úò €Ë¥-Ÿù•æÛò‰´û¥-Ÿ‰œyiË×!—¶|ÕtiË×I#¾-ßNEs�ùŒ'ë¥1Ÿ™°~iÌg´8.�ùDùáÒ˜¯ãS.�ùŒ(²oÌ×),—Æ|&›oÌ·Ó\.�ùLZNߘŸBm¾-ŸÑnòmù‰¡Wº´å3–-¾-?1®ª—¶|æ{û¥-ŸUn÷å+ ¾-_øw›µ+m Cö÷Ó÷X w¡Êx�¬¡>A°†œA0s ÝŠyòêùk*Á^Ío%­\`6IÀ‡†‡¾¶RWš/ªo]…çƒéÔݳV†%ñ¸©¬ª¨*Úµ£1¡¨ 7•â’Dh¾Ý¬–•~£Nè>Š0«o&ã™J­D&‹ì#À®QŒ™¾n¹¹­¦´ ú‚ÝÖÖA)5êLUi³ÊØuxµjBŸ:ÒFÁ}Sé¡gÝa°[ÎkÜß•—xþ§ï£Ý;©þ“3¶/;î×ü@§çˆ#ÉLŸŸˆd!/¹‡H!_rBœ—¼‚ê[\^Axó’3PíÊ%gy(Â%%YìsI Ê=Ðý‘…<º_ˆÓsù*(¹pùBœž^¬Á…§OlCö¼ÎûpðI]ÆûìùÑŸïpDÃýy4ÅuJç3ñ3¿|E8¯SÀ>gs}9#ãž]�I êf?ŽŒZ›çˆ•u±ªÉ�ó¢Ô¡¤¤+ÀLU•âÇyQÚ9ʺî�Dû<0J;‡‰V×÷‡K;}œ%VL ]×ׇN;}œ%VÌ£ÛM¹«6Û΋zk´O¯¾£0Û°Ï‹R³€Œžëµ ¬çyQo�öÉÉ÷QÐ Ž}`Ô[#~|�a*CŠxœõÖ˜Ÿ1}D�*r>΋Rå½àîöÚÁ¶Ï‹zkÌOi¾u�vpî£ÞóÓ‹ëK¨s¸ëGoM?΢;{hë>/ê­?9ú†ÚÁqž¥f4ñY®W Á“†}^”jÔEžº>q™Ïó¢D‚;„ï,ñïøKÛF©ü|Ø!|G?�ga „�¥ÊrQ§®8Ÿ§v¦}^©«TíðÁ³ðž§î#£8D‡»’úÁLý>1J˜’!®\ž'r†}b늂¨SW Ï#9ó>1Šc²r<®Î�À¼í£TŸ¤l’«aŸM§_'F©J™+WŸNdžö‘QªºÊ®pKÀ¼ìó¢8 *·Ë²„Ìû>/Šcº²~»èJÈ<ìó¢hƒ‚2ŒUÛ¸=ÄÅ<ÀíÙ¸ø»?|cx\¦¼ûi ùqÇÇâ‚#†3ÕçëY}Ý|¾žAQ¿äâYY=/¹xŽ—<;ïèK 88_rè¼a¹äÐ9º]Rä¼aï×4¥Îq)HÞ2\S�]ÇÞîü"ïxiÓL].ykÞ±]ü!‡wŸ“&˜ÈÑÁûÃÄ;ÆG¸—ó!>îõþîøøù¿�ìK-§|DÍ�;NîõŒ2wÔC]Ó2®‡.àå¡d®/ãzêB枺”à ³­§.dî¨K­Û�eÝš�¹Ÿ®ulc”k[ŽÌ]ŠÔ¦YVW{}(@ã1—´L0p-/›Ë¶îÀ‘‡Ò±¹Œë®OH¬}&· u +ü¯ŒœtÁ¯ëÖ…ÿÇÙá¿}ú_gõrq endstream endobj 116 0 obj <>stream xÚ+ä2T0B™œË¥ï™k¬à’ÏÈJUˆ 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ÚÅ\[sÛF²~÷¯`U*µP­ˆÌ—“§øØòf³gm¥ö!›ˆ„$“ €V”_º§gÀ”‰Î–«„Á`.==__gh6»™±Ù»Wlðüí‡'›ñY*f)ÏãŒñÙbýê—_Ùl õŸ±XæÙìÞ´ZÏTÊb!”W³�¯þô�yžÏR–ʼn’��­YœëÜñúòÕ72›eqž$jvy=KóX0$‡Ç¹œ].g¿Dÿ>Ku´i>­6Åòl.4‹~,ÖåÙ¯—õöÒ£‚'IÌ4? <•0– èxS¶‹¦ºëªM½?¹J“X''™[e† yð¡l·«®ÝŸW+3)Ÿ1q¸ýÐ]=ÞýÉíOò4™žºv�Žl?c±NíÚÛò·y³œãÚ¿¹H™×Z¦q¢3Õ´û‘Zã%±Ì”kÐÝÎùõaÜ<“þ€¢7þ,a2÷Ân‰dGXSË–Àý¦?§²ðÆ© lØ–uW«ÕÕ`'*]7›5• Û¸ªoV%•ï ÝjµY]i›'ìÝk7«2>ˆçé<¡îÍ�çÃ;‹ð| á>—~i6gBG÷– _ñÿ‘d¿ÒœÊ…þtècw–%/ƒ~¦ã\d§€~’Á“ëúRt¥x »Ï# ؇݀)`;xæA^P„ E(¹Ôñ4tð‰@ׯgsÉXô¶XÜúsPco¶ª³ÂGíòr'sd r ‘›#r¹8º“‰ ¡ ÝS‘¿ º©< rÓ4Î@ž4õòÏQÚÏ"TgôŸFg7E½Ü¬ÿL}=•“@ï3hO]KD½`Ç ~*‘!è¡·L_æ©&‰ñ•'A=6§¯ï›9 ´Ï›~\[ûóô`ÔkS(/ Ø•v«“‡<Šû¦Ú5£G]šmž ÄÉKœ„DÑC$ ã9u 'SBº3®^EÍA¨’“@Që˜+@ñ×áyŒƒÑ§Àx=ÛG1çTçæD9ã6ðÞmÝ0ù PØù Çw2;&×gÐpµîQ>ïd*CàB÷D¿ÐçU,Vùi|^%ã\ðÞsà~yÏáyô�»þ¾„ëà I·ù2žÃdvL½Ϡ=܇Y&Çà~2•!î¡»È_è0‹D˜Ÿ÷RÄJX‡êºå6_Œ"_e±âS�ÿìŸGþ8ì}úO{òT¨¬è±®V+̹QÝ¡5pžëè3þ)Û©¨ñՊϲjÊE·i*4%`2g&I€Ï«¡ÈÔHÀQš2•¡ M‰—IOA˜Oã= ³”û05žRžGþ¸øôŸHñ�D‰|Dö•ý—”�É<›$>÷dÃXuT`9™ÊP6 »Î^èγÄü4î<Ë㢠O6–åjL84×üDÂñ<úÇ…Ã_Ài„P>f6×ÿ á˜Ì³IÂásq(Êĺê¨\ãd*Cá€îB¤/�ë˜%ù)„CçY,u²Žy[6Ÿa"û™“�ƹÁìnvF÷g£‡–åz»ÚÁñÊ ;_•õâÖ†µÅʵÙÞ…¿`ìœ16ˆ†¡rúz§ 2à€C¥¥<ŽÓÉ à¨sgÉËËtW2Åó 9yñ“ é³cM} 4'“Bá¥õhšÅ(ß·Ãqt3f#Ù˳\DÅ•É@I0QÿC‡ºþ]óÁ8f"�îíV·TMg“¸eÕPq±iš3™Fe{·©—U}CÕ¶n»êh¤æLéhsOÇÈ*ºá5!ú¸,ºb^Õ]Y·ÕgK[?5ú•R�8P}y&Xôû]ÙTë²&Üa못¥’úáŒG¯Ïq€1sË`›âþá5Ž–Ëˆ‹¬/Óªrñ¾¦šï¿yO…¶úä°•ÌA$€w%µ¼«HÆ'”C´ÅE´eçu´Å =»Û¢£ÞWC,Ô-ŠJ×­Ã’"£zSχq  îR51¤4U‹ª-—–ÞË[K¬¹�L¡ IC¦,6«íÚŠ\¿—«Ýùlu[:w¾‡‰ýhÙ®ýývù|;¦9 â@r ³ð ®.àiÓYÚÞ_¡þ),.Si–d^ a ìé¸\v-¸ˆ•îã©�]±øtÝþåL먥aM×›b‰R™&°Ò»²^Ú¯muSW×&’›Í6@&Z‡ªZu‡¹_Åx„¤*&�oT±­—e³z0’�ïKs\ò¹Z”°Qi¢¢·ñM|N{v��½w/ýžá„ö %”Ê}ÜZÎuÜìhšúÁö¤;Ã{08’’§ŽMÔ¸½õú¦€Nª¾!øæc4î*yŠ‹(ß4ÅÒî&VšÕJžD?¾¡ƒS ‡H(`úzo”Ñ9ihäŸe¤ŒþöæMLU—´!(›Ý¶Ø5­Zz6´/dí@Œ�ŠG¥Ýh¿-k¢èƒö»-C·r_(M²X¨¥O8C°§ã渲â·5Š€’¾„Íí4sž˜¤ûr&AQ'cr¥zRΤkñ]Gc­Ê¢5ÅÄè¬ÚÔ%z�á×ŦF›³m %¤Âç`ã’, y[¬V°JèâZ°HTi“–ðÉ4# :±1¹Šƒbƒíü^íyõú†G"v�ЦÜ)K§Q;‚¹Þ1=1¥ß‘N-ëV‹4fÖÑÄavdŒ`‹Ô𾩌l¢€¢<|rϳ�@³\x7’V¾£Ô#PÖN…™i”�GLë‰Æ k0� X‰µÿûÓÏTØvÕªúÛœÂî"]Ä¡Yr=›zƒádš÷ÎyM¯ÆÅH3’v¬¸Ä\F`ö`Û´ô¼­nnMjÊêYØ¡ Að|û{§¨„XÙÖÏHA�/xß[\Y" Ü­[4ƒÂ·¿²˜Ë¯©Îä‚àùWÉcñ56R[­«U±ÓY¢�9Â0od~)?,è¤Dê®´©… ”zç½¾²i“®‚j˜”v•+WUkÕëtNÇö|&Éûs±�‘� ˆÁãÄñªµ[ÓUiuÏ’8a ÜÝ£ë1—:±»%µ‹§ jçhà ¢Ç¸6Ђ45ÖÜïÑB™L%T£Â|UÞ~®œØUýÅÁ²ó'6 YÎz‡6�~Yu´M0Ò˜ey¡ '!œÆƒ¾¢×a¶!ã1Ë“�#N 2p¸Œ.‚eþû»ß…•´±&¯�)u_Æ"\”§T+0ÿ·�àçߤ)¬ ´4lÏÀì¿ÞvÔÊ̆ÍúQ\ûÑhºWõ—QâmDßa^\}2ÔÅ8Cd{±.0ž³$9tµÌ‹ùlUЀ*ðKñxj�)¡ë‰Þï'‰Ëdœ‰t„¶tÖW’û5š6I™ö:@�TY©µã†îÜví<©kºEëíd$0'çk6²‹ö0ÜÁ2†Vv„ˆs—ÀÖ à0¼cÑwu±zh«vD0pÿ³X[½3pMbzý�jß.~þøKIh¥µù%�Íj—ÎÁÂTC07†²uQy “A¶+A*Ï�Y_Y3O fAš¥cÉ.çh-ÞhÎq—{ Y&˜�8ð±È{®ÅÜòíCÑÇÿ…k;<p|)DqðÌaPiÎñ{ëŒiÓ`W2\/[ñÍÅšÏÞl^ý þ¹Os7âÜr?ã‘#,B¦™ù‘�xcê½½î’ÆJEÒdþ³èMu}ÆÁU‡—2ȸK&yÒ=ÜÈAc›3ÑQ½]_^C¥±âð¤^«·�M»P„¶ ¸(E ÁÖŽ¤ŸQ^L*Ý)?™høÉÄå¡b¹mÌÆc¹�cÃ[,€\XУqlÀ(Ç<í­À}¯ç‚ àÉĽvX¤£ {×kU^wáqV& ;éÎK \‘a=dݘӜXû`õEK’Ì£»¥x�[ŒÛ Œ“ôX–k0ä]c³ùIj¥>¹í…¢!žÍnMKãB=è$kñܬ~¬hB)Úd!Ý�€Ò )ˆT’Ÿm¨ƒÅìwÉ3oæ ‰;%ÕgN¸æ!�Ûv4픜@ýrĶǀXÊÄ$©%òí8D©né²Ú2!^cÁºUŽJ†¹25ô¤ÅÖÀßœ®U-E†an¿ÝÒä,¸žíö ë�}ÀÂÎmó#`ûÏæJ Û·¾—S‚üp¬ÝtÆ�ÁâЧÈ`�¯‹¦¥¯”ƒÁ¨†ËÑàÀÞŒäÚI çði¡¢qÆy²‹Š»»²hlØPûPC»nIdRD¿‡.�u’ݱaLÚ�5%¢ÿ‹(I76½!9·ê µÔÖ~0sÂs ê#hÜûé·mQ8œè*3†¹F¦æ"Ï‚WÄÜEoyîvë0ç4Ÿã·ã<¹iî0-‡¯¦ïe£L˜®À§¼À©)³è”J–í~Ý`*‘\³,—½5¥§ 5 ‡6µ‰ðA~Ìq��©·9ÒdŽ{IMA—c˜€®eó¼×ÿÀ&z�¾˜ù+¢ÌߟMÍO#¢.5ˆzoGÎG¦Ð1ßù‡4èOf¸·¦üãXþWÄZè§í³°H63DŠè£ùû·±Qpðòݨ†m½w VMÆI–…ìþ`†~kˆÿ‡Wþ®Ÿµ?±±”ýr¬.ᄨ ÏwÀF�h¡”?|p^öØ\�í¡NcÁzuûa�²7ãéÛçG'ÆÀ®¢}¨ûœ_ ñÍU‹ÛfSo¶(Z"gÞéŠ8�‚…%™a(¯+u WÅâÓM¸¶ Ì®Qå³i»xLÅ}G‡O¼÷¡è!Ã�¨*0b°G¦ýbTê® wbѨµ)þ“aIÄ"Iå‡cÌ4hsÄ#ûÿâDò�:'�Üø#†Çš�“t4é|™¥¾·‡õ& Õ«¢Á0ü¦¤j²�æâY†W¶†nªîmƒeÕŽªÎŶ\¿Z–]QYÕq`Õ) ÈÄE çL ¬Ñð ‚wul_Yí¥cÞ^¾úìÉ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 xœmWPgÚ^YH»n$FÞ¹Hœ“ØIÜp‹qÜ .‰‰M3ÅSŒè :B¨"Q?ª(ÅH4Ó»qÅØ&qlÇÛI0—r©—�äò-óñÿóï’ËÜÍü7£ÑHÚÕ·oyž÷y^fµc±XK<#bD‰ÝÅ1A±Ì÷ ÔJµjµš Pìlõ¬3g5æRË^ –°Á«ºU¶ö6Ôêepè¨}c³XÝy'q\ZBDXx’ý›§Ü½ßZ¿~ÿÙ²k×.ûà´?¯Ø;‹#Âbí×ÒRDÑâ¸QlÒn{'úîèèˆsöaÑiqá‰öA!!¢æo^AÑ¢(û#Ñqqâû7�Þ²ßêà°e#ý¶ãDDLpr¢ý|äö'Ä»ì]ìÝEaÉÑA ÿÿ †a[ÆŠãœã'I<št,ù½ ãÁ.içBNˆN†º†¹GxxF�ŠŽqزuÛöïØïtÜõæ[0l vsÅܰ70wl-æ�­Ã<±7±SØ[˜ö6vÛ€9a±Ó˜3vÛŒÁ°£Øì¶ {ÛŽíÀ\°w°°Ø2ÌãaË1û f‹±0;Œ�­Àb‹°¥Ø6º˜&ž²^c5-.гװÕ쟬²8$GÂù7€kÀ÷àë1·ÐsáÃE‡Õ/^½Xºø—%K=–v[»[›^yçó+_¼ZúêoËö/+·Ymãkó�wˆw˜Ïû}ù¹åÍË$7R9Ö³¡À}ú¨¿šX³^Fòl¡º<ü1* îØ¥rQÈœò8Z«L÷ËåKài#î—ZiÑVW ‡áB4pûÖëãtñ@Î R�W!�¥øœ–“‡H ÇšÊjÅuÖ‹)è<Å®¦Ö�%…åù€°”ÉN Q>ÜUrŸlBà ¸O‘L: x¿8T¯oÄhcô{B$Â�‹BêËÜbÀO+õ`”€iø·cý£¥Ç� žãÚ‚Ói*Ït>ýDµ…Úja5«¾bÃB*�DqX�hå7k¡ ´ùþŸPm7‡– brêæz´qÎ=ÚØ›"_Iÿ< ¾™x  ÏB15ÒÚ4£n£¬oÙ<™‚ÉÓ¶¼¬2j5Y–¯e€¸ SŸÎ…ãÀ[¥rÍ$xk¥0 ç�­Åä+*À‡Ü‚wD6ªûýZÁ7ે¿|Û# áT€pÏ,8•®ð”òáÛÈ–±ÎáÇ£û�ا8�qïl0 2Jº¨—]£Í¯3²lyù¿B œ”ŠýY/Z»pH€ßÚ'ÆîÜìúü¾Šyæyýè}ÄêD«�¸¼Uü¹¶,¤ïŸi'[+Jû¦ï¤G\<;Õ·  EÁ;ß=ãë¦Üˆsʲ6á|îUòè~›²±Ø4NÃô)[ž ÎQ{IsLY}ò²õÈ ½Žl>Þúíøõ¦‹ƒBäŠ�4™3רªªpO½¦ôÔw*üúœ‰Ù µ&Y©ŒÑ ®<ÕÕœr|L׿êã—­‘ÇèšC&c8Ð˺é¤ÿ1cËK¢¾…{I1×a�‰è5@ÄqOƒ b­.«0·ÔÀMøgÀ ¨t$ ,‰« Ζ©ä ©Xs†sLàZJJ̸’ 9 ^V³…8ÏÍ�¯qæ,\^¾œY)‡‰9:úÃrÙ!:zg Õ…[Ãi¼{M¬§Slµ‚¬*,Ë×â|Yz€âÀW«=®¤A©5àG ¥pƒ€ÉxÛÀ%sIY–ºBP-¯È¬D£¡ÆÒžbŠŠMr>-ü;žUà•¦p•ÐH½ ŒðöäN%Ât’NWîN“í¦Cƒ ½˜ }Õ }òß¡Æ�£Š„¶ñ}Eò*ð�€±ð üSP#Ó¿KXS|u½ÒDm2)êm.OÀ]ŸØò6À{ð.™ WqTÜÜÜ m^^6àgu�ª˜àÕ”&'ůÜãîãäÑvp<²#µ&Dó¢Ä>Ñ•õAÊùŒÅ "9TruåEtux.e *·�fBM¦Åœ]»rò£ñO.%¶Ÿì"ì#qµì<0ó{[-Ã7Z"¶60—÷R¿÷²Ú —²ÿ�=ë 'Qiw GŸ£×2J’@ �ÞÁ£NÄ9¡�ë žøÖòõà¨`ptÂ|Œ�QIOX‹¸:îü ¢�«�aœdn¦$MžÔ ½0MwÖà_z–®äôZ‡ß2sÞ=ò½.Ó.ëèí `nê+Ç‹ kت¾B-i³©„Yèð/a)åEò·<¯0S ÍÈÌЪEž�~éÙï¥J›©ÍZròs s Þý«èwgKàÍÑîÆ+íEEJ‚T� ø¡2ó‡B؃ó^þÌ�§4„]FÖï3pl† E‘Ð +*&u„µJðIm… 8Í÷u§Z¹—ék«?P¢¨¤‡ †cÈû¿]¡\ÿÛ)È gÆâ¸»‰z·F^eó` ¡s«¡/‘Y\UŰ~�¶â¼v)>‘£W_)q Î’ËUqÉÑÊ@„D]èòjàs´VŽ_Ì©’ã{.ú<êê©6›GœçR”{ÉÔYq¹ŠÏ�Ç8kedAœÎg&Ö…rgî%#¾«0½ <š÷QUåTî% þ2K¯¢g”5媾á>NÙ5ÚŒ}ßüÔ–7D�ø˜”Ê•Y2@$i«…�ÎþJV³¬1¹3Ðè ˆ�O»$™RëLõEyÅy:anY^)Ðæ¶úÞQsì)Á mú@ª %§Ê#@$Áóq ¸=ØWwå¶€Wé]\›Ò·ò¨ÓwtÓ—ÐfzVEge¤(åâŒ@„‹/ ‹h”ôuÂ¥ƒÄ|ç“{u†Mm™µ%õyå ´äê5 $'Åxú Ãh‡ ¢¬¨ø´„N°K‚?ËÔ+€óŸlÝÃô®ÃˆïeíOâMuÿ\óôÀ5g�Èr¹Vœ—T@Éë¸÷Η—;ü€ä°ÐºC×{wªKïó�È0ßÜ6jñ‡¬ûS0õ 6Ü8»—Ì*’ÅiÎ(ø±N:^’_t€è-ËÎUãÑ/#_@»¸¾_Ùÿíºna§S^V=#�Wž]Ú‹¬Ûïø.ï³ çÿ5�{¨ŸÿQqÔ'ð)É“dÒðÏ4G@ãR”t©<¨ªz^L§ÚñŸ3•WüçTu•PøExˆ±(vŠºmbQbš^h¥ŒÛV�‘ž�—™£¾�šK2«²+AÔt„Ëñ¦ìU©rQž]¡Æcñ­2>�%¹HcäñÉ9Èêb‰NZ$¥‘’ššÙ–Ð÷â|ýšn¢6T¶U”7ò„=¤8ͬó“lj t ý‡%ºÂáø ˆÿrýÁ§�•ªÐraIr©¸6­ð›ê� c‡GvžöI úˆ�‚=úËóM�=Ô[ÝÚ)07Í-7 ¦W@5µÈÂ2OÃÔ)6üAMÂuW8ÕxZ^.ÈD˜†&õ­~Òpõq)?/Í/¥€è*S ‘.j‹«8G,|â 5hù“ípÁX·iä‚ð8Í"+ Õ*Õª´Ôu, =_ÀW gôñÓ«£g¼„4,U¦ ˜6�5Hmd˜C©Hª·Ê»Œ•UåUEÝ Ù”¼;§*Û�a’—…�ô>GRÚ/á€*Mïbîœç^—K3iü)Q‘6€Ÿ jΫ¤NÌ�p˜*Þ‡±mïdQ #é·?0ö8p�ͱ7Òºµí¹· x›«¹£nNh‹éô¯ó¾àLš(âLpœ3ØE ÁÃÿîÉMˆõ Ð3¸�¬xv¡ë6¸ ŕےÉ;©ÿíd] ¥aä²áÿÌ:’È­¢=‡ÿÆ6‡knÂq—/C¾ ­•/\í¡ÿ?b_zÞºÜßÙ¹ž.µÕ0N댺vºu#@‹�«âHªwF‚4!))<ülšðgkÃ[½‡#� f,?ô�=£õ×ñ‡ô¯kƒAÖ/t'”¾BkÀ¸±µ»®J[+¨Ž×«kÑ`¬mè h:ù�Wœ¼0>@–·›ØõºË‡TJ'ƵVè�§ªOxZã}/¼Ä¸ºŸf`:ãê¢áY8H6åÖä5�gàZù@ã­¶ÎÛàcÐ/ïŽk>7¸Ý²‘FE —WC“KS®þS4êýÚ?TO¡Œª¼h*Åʬәáʉ3¯¿íê‹ðTy~AÒ¼��½·™ íyÙSlaY>�é“f ›Š¤ìÈž}x*�¦ê’KíâÊãŠã±é “ƒ‹Yôq¤P’–&ÍÌŠŒU¤Òó-E¯ìKuöŽ‹¡„׳€ïžs~Ô4i©(í…ËÆ7ú¦…Iþñá™ës÷@£f±¡Ã—ÎØ<›y‡Ùß ³�löäÈh¦ë *óË¿qÞBÊpà¤Va¢6àïkÊ™§AœGùÀ2.)I,®O²47Ô7[’biG~UÞ™l¢P_„ÉæÁ4”ÿlË[EyМHáf'©TRÚñÐs¯”àµW…†–F­ ÒÈØðè´ à vz@+ׇ¢+ÁçEeŠâ�Hóõ?´Õå:´ö$q[P8§žËs1æë« +iW�mÔÒ'ɺ{5½+!þåó_>ó¼ƒì׌ ‚kÄõþ~IX‡ 5ª*¾Ú•¶¥óRAýØÏ‚:Zòu³9—ƒƒwT*GFè†hÕ/’W2ª_z ‡\PŸÖ€�ÜL¸�3w››‰öq¹��Õ`„V€øcst4°>£Í÷,›¤ë–_ˆör…Ÿp.…^·rrœó­0à©ùç häwð¡ íÑÉÂ삜‚œÂ~©º0d™J�Dc Ü€ÂhcÐe´zÙ5›|<1Ü\Ê7UÐD.5 @9·'¯"È�&C.WÒ{¡µåˆgˆ”±·t~Œ†Ã ¥AjÖÈúuþÏ ›‚”ž3úêÏÊé©*c¾:¬£—.ÕŠÒcâüŽGÎàtcÜHZ›¶‹ÙÍ{´ŒG뤳LÚ£"ÐütÜYO:îõûˆÁä�bý8Å6Ò5(áVäëói­h+—ÓKg<NÉ.YtTÜ¥HY®Ô·t¼ÞR‘úˆ”o=k¤k¸ú kz º0/¶‘^À+ K™¼©,ÝOˆJ˜3dyô Ü«@VzØ�ƒ‚Òr�î|Ã@M ëà ­ï*•;×$îž/«,Æ[Úk‡q£6ÎQˆÂè…^£qÓÒ7‰ x|AL�¢ôða0…ÜÚçæïvJ�v#Â| ±ÜÑ…xBïî>zw—1»»¼iÖ¦‰Õø=¬üž��#é ‚¤¡án"„´ V;Z8âÑp9q\5�ã×»éý.%`�ü+²äÄ“SC´xŠ�(À~ÇŽ€ßa ‚ìiá ºZõÀÄ‚Ól8ÈÊ1Ž×WÔêjŠh�Õ•É¢„s¾8ˆÔ$¥gÈ2ä9AL�š øžüôrp‘ ~`<xJ5Û犸­ÛÍÛ|»®%NоáÕéï .?ô)ÂR´"¡®‡Vƒ[šŒzÈéKNhZrâð¶SßÂÍ—K-&ƒ°®ºµ¬ƒ1 …ô5&êÑcujömrŽËuEëj4÷j+¯>Œá¢ÓsßpîpaøìšùºXf­-6cO?†âûžOi¡‚NþãjG?¸G|ætkb½{Ìá}cìo›¼/¶+9ú芷Ÿ…¸dòã_¼I01Š–~E¤½N>òn ÄûgϾ¿ßgüoÕ÷��F'É­ãaÃ`ŒêûðÞ@ÀwñYw‘ +€ì¦DP=@YYX-gßL&¡Uåuã½Ñ_ŸÞ†¯¸’€»6Ã…ˆD‹·®E+‘õÃw!v½¿ºïª íDl{´!ž€7á, R³3TâÄPE öû=�‹oTߪkÖ˜ÎW4âoC;Ð!í¢f_7±.ÒL»H3í _L|¨¿óöðuóLæu½õÅ}~MÉW¢ôÕv»?wÄ=I¼«z ~¿U~fž°L´t>'þuô›fw£Ãäã‹-M]ÃþÖñ€ \úö™à‹ñõÞmÊt».æpË�ÆcûÁ:ðšÂ1î„Ø%&ÌÉ�iU¦)ýWèÐcË üý•¼Û>tÜ".…÷œ OLŠðê¢$�%ºüü/°@@þÊÒ’LM”8ôT¨Ð:ÕDy™ §‰Û²èåâ–Ò%K^Ö.YŠaÿ<.ÿ 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ü“}—7N6©rÅ3UIj½/déÊ£²F²ï•wjóéƒsÑlð‚h°M¾Ø�±Fçéìnü²yøËCóðûošÕ?ÿþ�ñÿlÌÃ`ã.ÃhÞýüÍ¿þ[óðÞÿù¿<4—v~¹ý­ŸçÿÕ<|zøá›ÿ}úö F°Í¥ñã哽t£‘ˆð#ŒÃT2Bß_L›¸éÒ˜Q¢â:Dgú’!ºîÒõ]b Û´—Q¤Â6ÝÅ–™áìÅM&5†ë½¡"n¸Ø¾LEé�KŒÑšö2ÙN"£5Ý¥µE¸ó_Ö ©1úÑ*RáGèûQ4%�5ÞP‰Šë½ESÒ ãÅO‹H†b0²)q­õ'aÝ2“Áç[oÇìÆ\&oÇ}ˆæ2^K¨ÿÿ¿O”Áe¸ëŸÏ%oþüÓãÇë/*°/_ýXMJ(†±”¹ðQR®5Ìš¡š¨‰±š¹þQj®µ¬©ç ”ÆXŒéýuæ“.­æ·?~ó›ÿê�›.SïðǾ¶�7õCãkœé~|ÿð¯¯þÛï~÷ú�uÍ«?>>ÿãÓ×ç×ÿöã¿|óÏ?®ª@×׻䠪Ȣélçs¨�£ùá*šk ŽŽ37ñÊü#>¾ÝôoËþÐóùCàKŠ‚ì¶¡Û¨ »-_tÛT·¨@yÁ�’Ðmù* Û ¦º­@Fè¶‚)�nË—1wÛ~˜|@S¾XX¯Ã”4[4j¶÷�“eïjíp�a?¸ÿ·ª÷ÝË2woÍ•tÏ�y¥{îÌ…º§Ñ—Ý!Öý¿_îÕ—§¿~úòöýËBK¯Dèè«(æŽ^…é�ÿâk±ñ¥Ïv ã¿ÿæ÷¦óÃÇÿ÷x�ÃøÍÜ:náO�kþÇoýÿ7/£œ— •‚ e}ä\/ ƒ´¦¹øÚþÐOÝeìÍ=†þ??vQlýÛ—¿=ÿæùñÝF€¾Æ7Õf1tŒu€÷RT _jØnà_ß¾ûë‡çß¾}~ÜŠóW¿ûøáC:Êk 1¶­fèHë0葉0ÌÖW–6äþö•㼬ãÜïD×j;t—¾«u­^›_çªEz©èbíìpé۪뵹:Síb ½Zt±v£ŸÈqªx¹†•þî(£…þõÓFò #=õ#_jÜFöó"_î»Fôã"_n‹FôÓ¢@ê\FöÃ"_î+Fô³¢@ªûFô£"_®ÌFö“¢@ª›Föƒ¢¨JÝÇW€©w»~Üé¦ÿW¦ëÿxº¶üü½ÿŠ¿ø/HÐòeÛ¿6’ÃǽdzÉHýÐ\œ³÷fa6é�ÈC%Ž#Oÿ¸Yy‚• JzMúÇQÁ<ÚŠ&²Ûf(…à ÌŠ ˜ëU=€Ä°­çg»ÍY*&P#ÑæVÖÜËhEkÃakÞÜ9Ü/›ÜÕ ÛG¼ŒáúƒÃ‡ëÏvíC{éÍ æßg@îd¡S¯|¼w‚z>Î�ˆ]üþ )ý_ìI)–‘°¨PÎHàÍ(#O-š<ùR‚ÅŽrJ©&RÒÿIâb2~)éY/1­žmcX®)g$�pÒÆiËFKØ8¼ÛƘ‡ýLJ¾l| FÀ b&ù*p÷'† qR 5ZJ ”|¸OQ2(¤¨@åŸ;%*ù*p¡åN `¥@*TÜ)°äËdé|93æ ²\¾L•,Ýèc›w±ì&Yy Ë8òúdyH0PàãhôÈOdk·ÑR!z-côÐ;Ð��Û&Kd¹rF�,±3°þ²Üõ€åÉ6BÃ^Ù¨– í¶‰¦,ËGXY(ç#€eT‘F“Û¥<ùJ‚åŽrBWbk¾ 9r¤®<ÛÆ°\SNHàʤ�-×FàÊÝ6Æ\é?Þ±w9o\É/;:á&%_ný�p›R µÙNºQÉ—�ÛT'ܪ¨@Õ¿nVòUàBÛI·+2P¡ê¤–|�+;¿ŽpãA\¹|™*Wvî2vó½ìí&WyàÊ8òú\yH0Pàãhô¸O¤±ã6X*„O€el�XFøŒÝK`¹rF ,±3–cŸß²ìi²<ÙGhÙ+•È2á¢ï y²ìi²<,!am¡œ�@–ذÉ5°<ùB‚õŽrBXbg€ˆº<õ4XžmcX¯)ç#€eÂFò&‚žËÝ6Æ`é?Þ¸I–ü𺃂K¾ Üú‰!H°¨@m–RA‚%_îR” ,*PñçNIK¾ \h¹S`)�� wJ,ù2XZ_Úšî °\¾L,ÛÖÆlÞA9ƒå!‘°Œ#‚åËÈ燽_t·þën‘??þýÍÓû7©Ã$æëOȯÌ)ÄC¼�~›£Ç©øº0�ÍÜ\«?ª±z y�ZNU±€Á©+cÔ8#¿ 0õda°²Q S&ÖØ=,a¥¢œŽ€©Q:š)ƒ©'_H°zRÎGÀTìÌ÷¹öížmcXý)ç#`j²¬µâûjwÛcªÿøÐ8âœèG·9•‚:(J�@Ÿå«À«b’–ù*ðúƒ‚¤e� Ôì)$-óeàfIÉ hY õ î”Zæ«Àõž;%@˨^r§h™/#в.îˆ>˜áûTyÙOµi‡{Ñw›¼|Tì¡ì¹×¬wt“ð[xÛ$ùÖ]\וòíÉ.†åšn6Ý&\Lß±ïîÞ½&Æpë?Ý:#Ùƒå�€WÄ$UòUà¦O AR¥@ꯔ ’*ù2p‡¢dPT)P�J?wJUòUà*Ë� J� T¦¸STÉ—¨²qþŸÃ�X¹|¡*W6Þå±½—Û~“+‹>€e}}²<, (öqDzl‰'4w€ô0 ÑÄèá%vÀ¸¶3t©â/WÞ¨ñ%ö¦”/ nô=ÙFhß+•3abWáFßÃ2ÖÊ Œe¤5�É1æÉ×,”S(›”9ˆïõ=ÛÆ°|SNIÀÌ„�–Ú‹.¸×w·�1gúÞ7M’·rFX–ä$gòU,ퟂäL� h´´ ’3ù2–FEË 8S ê?JgòU,…–?%À™P¨øSœÉ—1s¦»P×Ç™è 59ÓMý¥›«ó°…™Ç?cæ*øê˜y\@¡Ö¯"RÃL<Ÿ¹ã¤Ç9úÌÊ5ÌÄ´c×µ›�©ãÁ~È\;£™Ø`Ì^º‡y¶‹¡u¯]ÔaÌ„‡Ý6§—nb—�a‰¡��1£llÚvÜ̳/¤°îÑNǘØ8é¤7éžîâ¼lÓNÇÀ—I§�»ør¿�_^?Þw�€/#à51Å—¸ïCP|)Q�z,¥‚âK� ܤ(_JT âÏ�’™/*p�åNIàK‰ T¨¸SøR #ðåx½g:�/—/TåK_¦›aþ=oÜÌâ€G¯v¦ôZ9únûL© û�Ä¡Òã ‚æ;¤¬øÉ,=Îh]±zÈŠ=È>ZWDz®œQCVì 0«3ëÉ6Âr`e£³&LìäwÞ—�°nQÎG€VlX;úÉÊÝ|{öÅë)åœnM\N µÍ^®gÛÖƒÊ9 àš´±“ž.Ýoc ®þãv’.¥G ΖÒ�GKùðòÇŠÃÄ×€—Vô&�Ôè­ìL|¸MZјPï±¢Ç/ñ5à oe_ˆ@õÑʽÄhÙOŠiûEÎ<øOßkuø×ÜÓ–ÐlÒqzHšˆsìü¶®i“ˆÕ" U6Ž0IÀù”ª&Êr¬:I¥{çHOLC+I ghr©»7PÀM¨1¦3Û¼YmFý§z·ü‡ð¿Òt¹ >µ’Ý| J|8†Ø'Vôò™ºße�òP§ 3®œJ-V÷:5CcÂ'+ñ)P£jú@·VH CìLkGç2lX-Z*d0`âêhø·ZžaWX×(¤°^Ú.öƒ¼övûÃ^?\¦v�ìRòGXZ:9‰Z|K¿%‡ aK ­‚Ä-¾Œ¥«Ð2(à¨€Ο’€\|KåO @—@T'þ”vñeîrî2ŒV‘»–/¨Î]¾Þ´ý6š6ÁK-Ä^qˆuÀKM4TéXu]ðÂ3“9Y+J‚¼âHë’Wt vS¼ªÍè.ðZÅ^¼pìajㆷe ähð:Ô)h‘+§*‚W§vãµ{E>ðRÍhÚ Ùà…�élc3ÜU-Xw)$pWâ⨱÷v†]ae£�IÀ] »LòE ûöØvÛc—ÿ¸[ vñGÀ �‚Ä.¾ Ül‰!Hì¨@m�RAb_î)” »*PçNIÀ.¾ \D¹SØ%��ŠwJ»ø2vuí¥³£"v-_P»:¿ž 55õ’ê»ÔB ؇X»ÔDC•ŽU×Å®hfrg+…IpWj]î¡¶C»ªÍè.ìZ…^»pè vµbì:Ô)h‘+§*bWÂ';¥_¿ »T“š¶BòvEu¢q&ƒ]Õ‚e`—Bv%.ŽØu†]ae£�I€]I»¬»vÛc—ÿ¸µ’÷; FÀ Ý o,ä«À½Ö o-¨@mÏJo.äËÀ=Å o/¨@Ü o0ä«ÀEÔJo1È@ÅÉJo2äËØÕ¿&tŠØµ|Auìj})îÃ˱ì&v©…°+‘�]›‡ë\ß]\7•®kmît�š Pöcêr\4ÕÙt•â$@.޵.ÈáX»~›ãªÍè.Ž[E^•ãpä Ç5âûu zîÊ©Š—ðÉŽïÜ·¨š;° PÈศN´9Œ«+ãr0.qmøžÛroÃŽ;ï°TRÈ$à¸T.mc¯-½kq·]1ǵ>{†^tF�‚:¤F�@ŸRã«XÖä$NòU,Ÿ‚ÄI� è¾´ 'ù2–ÖFË pR  JNòU,Åœ?%€“P#ùS8É—pÒ\Õ”ü|52V)—/Y#å(EJë¿¢ ¿·›H©f(¿q˜+Gönžªp¨Ø±rL‚£˜ñ e0P5Ph q x);Š1js�ø¬júO=h4Z½ŽbÄAÏ«±ëß*Ú¡úu†òäÊ#´b…ì—vȱ ì§š0вØ/ª ƒÉÝ:Yïr(øAV ‰Ø—¸,Ú�WÝ•líöëTXÌ(¤_Ê)Á&8ßn§bâ3WÃE;wüpã&† Q‹¯wUbµ*P›£T�¨Å—�; %ƒB-� T·¹SP‹¯Pî”j d êÄ�@-¾Œ€ZMi{«ŒZË—TG­ÆÿQ7†sB›¨¥f@­8Ì:¨¥**v¬¼.jáÊ�YS�ºBi]Ö‘Úd¨3kU µ˜µVAWe-ô¼ ßÇ—C­ƒ,‚¹²¨"j% rE€È‘–jº@ÇVH ­(]š6GZ] °DPH`¬Äõàg~,ÚZûu†±êy´‡±ò+á”ué7â•lPcív*f,ÿqÓ‹¥ñGÀ›‚d,¾ ÜM‰!Hƨ@í�RA2_n!” б*PÅæNI`,¾ \@¹SŒ%��ªwJ€±ø2fÆê&¿Àmœ.c¡/©ÍXÝä×+Sx žÛb,Ý0gÆZ…Y…±t…‡Š½R^•±âÊPÓ 5´…U¨U!+5ó\�Z¡–BÖ:èš�] Yô~ÖQ…¹¶¨d¥ rdÑÛYºéZ¶FºÈŠŒ]†±ŽºÂA#_c¥. ÜíÍÀX‡y4¯_4&ÐUÒ#›,*EºÚïQDWÝäá¤ét%aéÕä] T,m”‚¢+‰ èk´ Š®2–ÞAË èJ¢J5Jfº¨XJ'J]Id@uâOI +�Œ@W£7¥›”éjù’êt5º‹mÃÍ‚ý&]©†è*“AWÛgÐŒ»­9oa>}~¿uÍïwÓõ@lD]X‹& T NK© ñ‘/w0J…�¨mp§$à#_.ãÜ)|È@Õ‘;%€�|{ÏÓÎÛ&twõèô9tL I£ãp/{÷•°‰Žj!†²‡¸…�™œ§&ªt¬z‹ñvM 0ž™ àU ’¼8ЭÅê®@ðp nؾç±Þ|¦þ4ÑwVAo¬U÷=¯Uû¦ð§óo3ˆWÏ£²ý¸•GëÓ]ÍX9t5!åMsœ-ÝŠSMhÐ ©\‡=±Ý4�²;([`I �-@v‰lmáë,¾Í�]E�ÊoxÔÈ`º8k¼}[YSzœl¿G1Ôù�7“äVGÁ¸OC�4ÅW�›(1IS¨«Q*HšâËÀ�ƒ’AÑ”@*ÖÜ) 4ÅW�K'wJ€¦2P]âN Ð_F )êTôšE.M-_P�¦üÎÁË~ÇMšR 1ÐTbšR U:V]—¦ðÌdŽ�ÕŠ’À©8Òº8…#uM·�SÕ&´§VAWÅ)t¸y¯/<ç‘éz•áÔÊ£Š89d §èãcº©Z!U§°'ž5Ú M”,°$PH ©T²8êÖÆž¦©jcŸL!q€©âÔI¾–}ß>Ùn£b¤òZÑý�üp³&† ‘Н7Rb©*Pg£T�HÅ—�›%ƒB*� T°¹S�Н×Oî”R d ²Ä�@*¾Œ€T>ݰó†Í´¶Ájùš,Xm LãU7^L߇ƒ;›x¥n€¬8ÜMÈ¢ÂM –rPÃã6�kÿ„vE3–;UV5d‚¾â°7—”ûÃÃaÛ!sÓbå™Þóýµ [KL† �ʰ á g]á&Wæ1úÕ]+c³•_[KÌý~Í„¹åÇíÄ^$´}µ¤Z‹j‰¿2´vBZÁÊC-­€ßie'ù#k_. ŠSK1`¹È;›ÜC,G¿'m¿i1Ëù�·£åØàU@~äØpKÎ�@b_ꇄâØ"p“!DPÇ×€J9s2À±5à*Êœ À7¾TŽ˜“ðÆØÍdm»£¾Ð…w›à–/Û$8zxšãZw›pK³Éq‡„h.=Is’Ðç3l�£~È3l·÷¨e±bôˆØ�$)JÜ^ÄWFþ`›Bü6Æ$W¸±]æé$*WÀ.‚\9’ZêŠ ‰ 9È_Ǧä`M®¼K-u%ÞÍL9ç¶�x×ï°¼ƒåˆrÞ_FµÇö¼<áº�…‘rÎd&rÎØÂõÜa:•ë‡�šÊùÀg`…ÍÃÝÆÀé?Þä?N²£‡ ÙÑ#Їìø*𪆂D_¾ ¼® † áW õrJ‰¿|¸-R2(¨@-‡;%�ù*p©çN @°@ª”Ü) æË¸Õ,oˆu²šEAÖ,r„‚šÅV±Ô,rºf±U,5‹‚®Y|P³htÍbËXj-ƒ¬Y|P³øS5‹­b©Yü)Yj_Ô,þ”,5‹-c®YÖöÒšE QP³ˆŠjS®YÄ%5‹©×,bˆ’šÅU�j¥¢¤f1eàšEÉ(¨Y\¨fq§Õ,¦ \³¸S‚kWªYÜ)Á5‹)#ì7Ÿö½þ½bË×(Ý+f¯Ž„[pÌæƒr¸¡ÇáÖ¼WL9¨áq÷ŠáËüð_5`â'ÿ8h�;ÅpÐm?¥îj ¿÷Wžé]¿ô¯ŒP¸W ñÆöÛçSŠï«|¡0žy·r­úc‘g÷ßh›ôóï^<²<÷ü»2 Vj?ëGf'7e~د�be?é«%ü˜Ÿ¸P2Ï“4¥Ï2?-Ã`ͤ–aðû=¶îû\Žù”t}[zÛØnëbº¼¾îk�Ü6Æ`YP#�LÇÖ°ôgj’èø 5’Hžc‹X: )‚¢9¾(åìÉ,ÇÖ°”RödÉñE@QbOp[DÀ¸¦÷ZÚ ÏuÝ¸å ª?Îüº6žÂíavÝÔB ЇXçEQj¢¡.Ǫë>wÏLî) •¢$è,Ž´îSÇq¤]ŸzeYÀ²j3ZøÜñUÔUŸ;Ž£7} Ô‹E ÞUíz`@ØÊ¯ŠO¸å—†}‘[9þRÍh× ÙÌe�19ä:áÒ€Õ‚B*r%.[ø:±ï3Èu†]a]£�I€YØ®³’?¹‹ëºRÎÚíWÌYþãΈž^Çwtbµø*p·%† aK u?J‰[|¸©P2(à¨@%œ;%¹ø*påN @—@ªNÜ)ìâ˘¹Ë¯’/­ëõ¸ }Amîj§Áû3¿_)u¼öÎ]z!Îܵ ± wé‰Uz¥º*wE3“{ŒB­0óൠµ*xÅ¡×n‚W½)-¯uÔ5Á+Š:€Wé¥àUïzØ^k¿ê�WÊ-¿XtRðÒ͞е5²'€Wœ=MÛlƒ×—FX2h¤R¯ÔÅaù›¢¼N±k^ÚhdR¯È®zû[û트ëúqã$\‚pG'† ¸K 7[bŠ»$*Pó£TPÜ%��{ %ƒà.‰ TÁ¹S2s—@.¢Ü) Ü%‘�ŠwJw dî}-™&EîZ¾ :w�îâÆp«b·É]j!îŠC¬ùêÞθK7t÷Ÿÿþæ—§×¶yÅz}¯žPøc#ꢞììjÅI°\k]–‹bí¶E^oJ QntU”ÃA/{hƒåª] ”[ùUå"·üŸ˜¢‡Þå N5m`  �6qQÚØÌæÙ×,?r.‘C6ù"ß} w†]a™¤�BÀp »®ëîï!q»ýŠ!Μûè«°ä‰t×EØ6r Ñ(:<ÇV€—"¢gó±à‚èÉ||¨[ËžËÇ–€ è©||¨áˆžÉÇV€ ¾ì‰|| ¨ˆÊžÇ'©I7Îì§[�¦K¢>þ(Áå ×Üé*>’¯|chçw\X·É ‡…Jp>fRFø ˜<, ¨èqD.]ÍGéE3š¡Ìà €†€—ήæsô"Ú®šmþT1¡|‘�ne ZS»šÔ‹¬¡oN³Ä£©QO¶ºõÊF´Övõž­™XºsÒÓüzXBÂÒB9!�k£„´SêT6�íÉ—,z”3ˆ7y15.ÿcO#ïÙ>†•›rJ '}´Ü¤ÞmcLÂþã]'ÚÎä�€Ä$LòUàîO A¥@j´” *ù2p£¢dP`)P�ê?wJ\òUàJË�L� T¨¸S�É—0óz�½t½f._¨Š™}³¼ž>õˆÝ3 ?`f~}Ì<, ¨öqDz˜‰g4s$ð8 ÓÄèq&v ³S¿�™*00såŒfbg3‡fFùhRGw�2O¾’`í£œ�@™Ék‰}³'@æÙ6†µ›rBdÖµ s·�1d^›Ì$9«(/;ˆ!HÈä«À­Ÿ‚„L� Ôf)$dòeà6EÉ  S Uî”Èä«À…–;%™¨Pq§ “/#@¦Ïĉx9Y]È\¾P2;ß–¬ oßÝ„ÌÃÂ�‡_2 ª}‘dâÍž<Ìh5±z”YÐ Û¤Ññ€A™+gÔ(;”Ù‹)ód¡}¯lT¢Ì„‰¾<[ñ‘ÊÃÊ ˜'dö6Ý“/%Xý(g$`fúbê¸pæÙ>†å›rJgbK73 8s·�1gú�í$áLþxåA Ar&_nþÄ$g T FK© 9“/7*JÅ™¨üs§$p&_®´Ü)ÎÈ@…Š;%À™|�3ýHntræò…ªœÙz‚ÌÌ™ã&g~àÌ8|!gnžélýÀ�›ŠÎtÞ^gÝÚÜ©ÎÃ\‚Û¤¯ø2ÉŸø<Ìh`±zôyÐfN‚ªXÀ€×•1jðŠ�xíÄwâžl#¬ V6*ÁkÂÄæbÆ¢wçàõ°|„Õ‹r>¼Fù˜eד¯$XQ)'$°kúZÊ=-¸÷lÊP9!]±�ïÃÝmcŒ®þãíØKΤÒ#�§Rù"Ð��>™ÊW�PÄ$ƒóUà% 1Éàh½@© œ/÷[JÅ਋q§$08_îÜ)È@—;%Àࢺucp_•lkªöŸíg%-_¦Êß~17úRvçïi“¿ =”æ8ôú{¼‡>ŽF‘ñLføX!x‚�côø`š!È*0yåŒ cg`=.¿‡ød¡a¯lT䄉†ÿ<àãÃòVÊù|åcßô}†�O¾”`½£œ‘@ÈØ@»I|±Jg+yÉ-¬Ô”sØ8‘�ÞÛ¦h{ü» ïv0†ãë:­µ’}]þxÅA A2%_nûÄ$S T K© ™’/·(JÅ”¨òs§$0%_®±Ü)¦È@•Š;%À”|�)›Á_énÇãá$L¹|Ùæówk0¥±ëçß-S�ÏŸ™ò�ÐSÆ¡'ŸË+bÊC‚� G“|¸n¦Œf2s0U!z*c’Ï­•Ø�¡·™RÅS®ŒI=R´ Sbcè=žâMדm„†½²1õ¨Ñ L™0‘dÊ‚=×ÃÒVÊéL‰ ëLc3Hyò•Ë儤L\K6¹[¸oÓU¥±å1K4å$˜L¥aKÁd¿ù¸q€ÉÝÞÅ0é?Þ'`’?^jC�0ÉW�Û=1 “¨·R*H˜äËÀ½‰’AÁ¤@*ùÜ) 0ÉW�«+wJ&2P¥âN À$_Æ “vrgÚ D_¦¹Ai§ébšù‡¾ÖlÁä1¡Ï0¹ ½úå1Á„ ¿ŠFmƒ2šÉÜT�ðó4¹²@m‹2¾˜Ý´I“:ì§Éµ1Z;”‘1¥4IïPžmcèØkuv(S&VØ¡<.ÃÒB;MÆ©é2O9:ûJ ëí„ 4™¾–éÛcN·q^¯i'd Ët]cßyÀr¿�X^?~-K|°Œ€—ÄX TàÎO A�¥Dj³” ,2p›¢d`)Q�ª?wJf°¨À…–;%,%2P¡âNIK�Œ–c{1ýpX._¦ –c\·½·5ƒå!¡°ŒCW;ujü•ÛÍxúü^ò&Ñcü�¦¤ÇªøâÈž7ÕˆŸ€ÕØ=XÅ VUq€Áª+_ÔXû²<™Å°ó`õda°òQ V“.ŽbX=,a¹¢œŽ«QIÊ7=ûB‚%”rB«¦ÒJ•tº�a ¨œ�«I[1¬î¶1†ÕÑz¥Ô;L¯PºM«ôÄiÑ‚ÈÓ¢Ëò‡‚df¾ŠeBA2³@´{ZÉÌ|K·¤ePÌ,PMˆ?%�™ù*–‚ÏŸ`f� ¨—ü)fæËÌ<øƒéŽ{búBUnöë‘@Íí&5|(Ðqðõ·d j}‘ê.ó™¡ÜÇ&‡¯G¹Kø¦ÚmÊUq€A¹+_Ô(wñåMî|Ú®»{Ï6šöÊD%Ä}a¡¡—¾·÷¸L„µ…r&à¢Lì­i3€{òeëå\ÀMäâ ½±WÃÄ}gEµ³¸ö…}¶O>Ûüåͽ™“¢ûý‹±Ö¼'>NìÁòGÀk b’'ù*p«'† yR 5VJÉ“|¸5Q2(ž¨@5Ÿ;%�'ù*p}åN ð¤@ªSÜ)žäË<éüÀ ê <¹|¡æiQ¿z¼4] Ên“( ?e~õ£ÇÕ>ŽHíÔh<£Û§F�s:Mì€Ú©ÑÈ�¡Ù~ÏŒŽ ª\£uj42FþÖ?àÊ“m„æ½²QçÔhdb)l�–ްÊPNG KlXgšZž|%ÁÒG9!-×yj´`ëTÁÆÒS£ÚIX™°Ž>5êÈS£û½‹ÁÒÜÿŸ,ù#à¥1 –|¸ÝC�`)P�z+¥‚K¾ Ü›(X T ’Ï�’–|¸ºr§ÀR U*î”Xòe°ì<Ú4í�•˪nTvÓ¥ŸÂY»M®<,úÀ•qôõw* Š}‘ÞN%šÐìùÑÀF; ·Y]ÒÛ#Òq€�•+_Ô6+‘/ßçn\ÛG•'»�{å¢Òn%ò¶+�*ËEXa(ç"@%®FMêÉÀ”'_G°êQÎF`Ê—WRÿ’)Ïv1,Ú”³ð2UÓšdQsç9´ðnÜÝ6ÆtÙ¹ËÔˆ¶-ù#, r’.ù*–¦OAÒ¥@´XZI—|K�¢ePt)PµŸ?%�.ù*–:ËŸ K� (Tü)ºäËtÙ¶—áÀ÷–.ß§Ê–ípiÛù&‘¶ß„Ë£‚l¯u|Ôö¾ôØ®èøèí¥¥Ùó£GYÍ#òHVñ’?Az”и"ô`;�;?ª?ƒUcWÔP»RºZpgí¹&Â2 6Q‰T±…ô9µâ;k�ÊCX­èæ!€jT‰R¿›¨ž{ÁúI7S“™8q38õdÃêO7�R÷å¢-|GéncHõŸvÎˆŽŒÒCPGFéè#£|x¹C A²2_^rC�¬,P�Z<¥‚de¾ Ü$)+ T îÃ�’ÀÊ|¸Ös§XY UKî”+óeÌ5Ë8+­YÄ5‹¡¨f1UàšE QR³˜*pÍ"†(©Y\¨fQ*JjS®Y”Œ‚šÅU�jwJPÍbªÀ5‹;%¸fqe šÅ�\³˜2n5ËÞ"ªYädÍ"G(¨YlKÍ"‡ k[ÅR³È!èšÅW5‹VA×,¶Œ¥fÑ2ÈšÅW5‹?%P³Ø*–šÅŸ’¥fñe@ÍâOÉR³Ø2žÄè§~Ƕ·»�—S­EË—lŸÚ–Ü}°ÝÅŒíü û°¹û f(¿q˜ÉcR{à û 8Ì?5�ýôøüæÝ}¯Á|ý)³§ 8Tü8òäqª½‘Ãî=³u (4•8Ðä1�½�Â&At)7Ö˜í}‚JÁ¦ÿ4ÑÅVa§Ž`ì;ìà°çŸÍ\ò�» Ct‹Ì·™M€ƒ‚»r(uÒb¯CóOü FSx¶âÛÌoüª -_!aà×ü(a\Ûçn<;èz€E†BÆÀ¯õ‰+¢OŸT*º"àçú£< + …œ�ãSYÓ¦o„-ñ~�ßíQŒ‰×”ž&ÒCP˜H�@c"_^4C�˜ÈW�;:1‰‰¨ÁR*HLäËÀ]Œ’Aa¢@êÜ) ˜ÈW�+8wJ2P‘äN `"_FÀÄÆOnW¡3l½èƯˆ~”цÛÓÆM@Ô 0ÔÜ(Àªhˆ\¡áõ–³ jÅ > º.â¨3TX'D £0ë2atõú\n¶™°Öl"atU"ÄA"l¨õmO3á1A3�ªH„)ºôí:Eþ"ÔLhîõ“x0ª þËr÷ws-Àb¢~¶ ¦®†¡ð¡~9<È¡°Î©Ÿ-À‚ ‡ ãÓûüNâq^„ΰ2Cí!�Ø�m”<.þЕVñ«=¢ÇßwÛOhÔq`ÿñ¤µ/ZOhľ,ÇÎ¥�ÒÐp‘z\hïkçtʈ} �Ïh¨åööÃàž—€a%¢�€\±acã2ï^?ãâ k"í´ @›¸|¬ã?K0ð¬’uEp«�w�tÖõ�|Ós¿ué^?Þ�"Ô-‚`Ý‚HبÀkb w*ðÊ‚‚^‰ ÔÇ)ò dà¦HÉ  W¢õî”ÌØ+P�kë]ûŸƒ±ö«Þ>hìV—´ Ý4L?öB7m Ó+¤ �$¶Äº¶ËÜ{TâÀÚB!q€‰ã-1ÒMК•¿ N#e#§Úvë­Á•¾ým¿G1^o˵¢[b † è��¦C¾ ¼t † é�¯÷ub’*PŸ¥T�tÈ—�Û%ƒ¢C� Ô3¸Sè�¯Wpî” d òÈ� C¾Œ@‡ƒ¹˜ßA·|Ÿê¾¨ïšƒ ›af“� >Ôç(xµmQ| Ê÷�Ÿˆ�Ñ£¼€.™¡·-ŠÝx³ÍšG…í) _oW‡oLæÍu*0¶Ec_ÔvEãËâ¶Ôî’«Hô˜³‚mÑú&ïŠÆÆ)mŠ&l3M᡽ܮèQéKÝô’Å~ í”Y•K§„׺H7ór—Pk 7Ö¿Ë@®ŽE£º©Лp®O¿'r߯è^çbò|ƒèÙŒCPäK�@“/_Ų¦!‡ É—¯bYZ�C�ä+P�œVA’/_ÆÒiù T@»áOI _¾Š¥Âó§ÈW Ê%J€|ù2ù:�K¦«Ü0¶öH—/SåÞÞÔ™zí&õx(ÌqàjÌ»މ—ØD=Äè ±zÀ»X‘Á]…Ð Þ�Ã×Þ%|�»Û/)Ðq€Á»+_Ô€_ó[¡GîS½wU2¨�wWÆ)ï ÛúäÕ—/&ÈÑîaÙëåìÞ]ì]Ÿy-»Ò•³w•x÷ÅÔÙÂSÎ9ÚUò¯w•3x÷…s®Ây×ýΟë?ÞÙmÀôîÒ#иËW�—4Ä$îòUà•1‰»¨�S*HÜåËÀ]‘’Aá®@j7Ü) ¸ËW�+L‡~MÞ±%A )„9åWL.ÿLG?d·G1#^ßÅÞȶ0é!(F¤G ‘¯/ ˆ!HFä«ÀÝ�‚dD� Ôg)$#òeàöEÉ Q õ î”Fä«Àœ;%Àˆ¨¹}dF}ØÒFj& ôùú h%ÌÔµC �IXWÔOÃDÊ –ÿþDÃjåßÇ–<õÓ€0rÈ éû^<$ò× ÜëM̃·ïâžY«&b„y)µM”|hUCŒ@%_^hC�DÉW�×Ä$Q T ÎL© ‰’/·\ÿÙ¾úåËÓ_?}yûþùþÇo?¿¿ÿù»×æÕ—§§×íðêñùo_>¿ÿøù/÷ÿò·Ç§_ž~~ûùÝ<øü—þñéëóÀ"ÍvÃeh¯Uâ¦ì÷O��Ÿï-ŠàÚKü•1ÿ­wŸÞ>Ï’þÔ¸æç·O}mšW�³º_>ÞŸ;qÃù^3Ü Õ\šöº*› ­ÊVßtmZíÃô·üW˜û—}ô�¾{ûõñùþ=_z;ûõõ§9Z¾Û�ãã­{xc®½kñÑ ô¨øÆã«÷�¯»æÕ_ž®øøöý-ÿ§þ�ë?‡WŸo�ú?ñ_öùþoîW÷~yºÿ�·ï¾þãí§OÿqÿÓ�?ÿíéuç^}¹:òï�ïÿ)aúõ?#¸ùýßôæ}úôåµu¯~I¹ïç¨Öîû/»ºŸpÚ¯x:ïòð׉Qý_ò"N_£øüîÓ?Þ?Î_ƒ®¡{È·žmy¼ÿK|á½0öí×�_>ß?üñóòÑÛYw½ºl>/Font<>>>/Length 9243/Filter/FlateDecode>>stream xœ­\M³$·q¼¿_1G)‚7¾�£ì dÙ’e‘«�#,$jEÚÞGJ¤ ÿ{gf¡…áÛgÒfðÀy;˜nU¨ÊªÊÂ_nÇ=Üþ7ÿÿéóÓß|ÜnŸ}ýTn}J÷~û哾¿}ü³§v´[ŽéöüÔR¿}~÷ôÉðÕgOy öyþïÓçÛß¾Á;ÿáÍŸžìáVÆ 5÷Û›ç§ÝŽ¿ù�§�Þ<ýZ¯¨zøùû‹¯ùÎO¯üÙq/a>?Ôíù½äëéüü½žø£x?ιDz?<u¸ÙÏ?¿Ï+rÆ?¤{ E/Èãá±»ð�ïóø4ð›rÕ_Ë%=<¿‡_‚ýù}Þ)��ë½ÍE„ŽÜ?(íáE-Ôõþñ½^BQ„Úïq.%ÔZkD'îÞ�©±ü”Fø_‚9¾å¸c†“üðúôíã¸×ºœî *Í9üüŸ~þæz{ˆØè2'0ÿøÁç a–m¿øÕ¯þñ7ÿ¼¦QZXÓ°?~øi”�áÛ4~öÑ›Ÿ¼yóñšÇmÍÃþøáç1²&àæñwô“7]Óˆ±¦9 }üÁ§#lÛñ¸ÿ²íE¤ÞÌIH…~ðIÔt/û$~ûñÏý6ŒrÊBøŒ~û ~ú‹ß|ò÷× R’a±9Ì?~ðY¤ïuׇ�?úÅG?ùä£Ý�ÌæM÷î)å–.'·�yÕFÅ»MêCš* øŠ|ÃÃêuã þé›ç?¼ýêöåŸn?ý�M¤Þ;õa÷ˆŸÿ“|û—oÞ~ý__ÿîGï¾üŒ#–¬å98i06^ßÏ—cÏï~÷ãýǧõ F·×V¤éqZoþûÏo¿>gu;gÀßXÛ=$�@>7ðŸS¤©ö¦”õOùeú°Ü³ ‹óëíü§dÿ„Þ>\¿Öób»Ó �{²+¿ä¿â�‰{sèÿøâ_ùŒc<~ø·7ÿðô!¼Ç}t¸¶€mÖ�ÿðûOÿ󳯾üæ‹?Þ°ŽoÞ.3tûì)æ=zÁ¾ zè ÿ“1£Ì‰�{Ö+hx� ;ÁÐq­Ý{ÄlJ8!‡6Nƒ&yÔ;§†ÍACú€ˆ1€%U �؈F€øxb€ÍÎøUËá~ØZ+Ž'Øë=e�Éå.×ïmh¼ä¨Ú‘ûÁ³ýÞ…‡–Ú=f¿ðŽù˜sá ê_¢_øHãŽ=u oÈ5ø…(pò ï nø…�Qî5û…÷rÜSw ‡dÒ}Ämá­ßk] �G‰STçÂÇ!-§Qûõ{5ï“§X.´P¢!»~éäËß½¦“Åa�XZŸ†L!íŽ�™A#k>¸ÿ­Úδۨ±Xcá�P·°ùÀ§ØNcúq?¸ÁØ+½ ÔQ¹ùá€èòtpýž¨�Xú xC˱û @�Î1©Þ©$�œ¶3´’¸ùÿëÕSó�G¼CRÓ˜8zp̓ߊš$ñ†~ î~‡æG; ÓÈ|¦Õ5«ÁÜ;4ÿ’nƒ²5*V'eÃK+?uìP‹Ú�†]9¨l¸VÞ�=ú­CósÖætH>ñ¼PmLõñ '§õ ЦSÖi1±ªJõÓª¶ëk¥À)Øs l8¶¿™BB$ƒSá�9Ž:TÓü£q³+t,Òü`2™!˜y:°é1Þ*ìÄ¡u� Ë“è UÉPf43Ñ’ÇhUË.4IEC†Žz…™ÈE¾œ§—O¡E²³�-Ç…ÃÁ$»†ððbI™ÉÎX–á)g¸Ûcxx‰ÁóøÎ8Îh�‹(ÞÃÓË`&É”'�v°ØEÅI§ÒÌ�L—éà Ç!¥‡?RО^,+A2Š uÂq€r†&Øc¨ Ñ¥-›Ç›Ç*Th“ž�³ ÃHeÈä'lùQì 5=$&h”œ¨5gÐ4�@»‹ÆÀRÒ5GÈESI0˜DªÀ‹Òá�1�˜¡ïZRFÌKŽ�ÅYËBT¡ðbï3m Ç`Óá²ñ´#é1 ?‡Š¨7Ý6‡`Ïq"#ƒ7¹³”èZéY1«¨Ue,§ÁÔ…~ÇrLx‹�&}÷�4 öü�·»ÃÎk `1Í5 Ã]�)Ørèôp9j6·3h†\²Y(Â&Š…qÓ˜^d®�¬ÿ¿{¯ÕÂñÁD7«…#‡·ZËo›Õ 8 ¥9«ÝÅB†³Z؉pW>­ö ÉÎjaCÊgY­ˆ9Ô8œÕ ð<÷�ÕŠ˜ƒœñi´0™:íì4Z‰Ñž™’iµBÄ ÆpV+a¹;£©¤ûf´¦ÐÌΚтÎ :£•·¨9£žß³3ZSÀvF+$¼ $g´2æ@Ñ-£2Þ0 ¤Y­Œ9P–Ù ohÎjÌ!ôî¬ÌB¼Ëœf‹’Ïu,³“æÂ§Ù*�ajvf ÂÔýËlQîÇ47f¶BÁó§I2³E¹§˜�ÙB\]ïr§Ù¢à«Ïi¶BÅ ²³ZSèÃ[-Øïx7 )«•n|048­ôù }YV‹‚§ º¬Œì ™šV«áý-GgµàóÛ]y°ÓjQìGôV ¿,´—ËjQìI‡î´ZXY¦Ý]V‹b/f¦Ù‚6Ç{òf«c´ñËlA›�¹îi¶(wíe¶ Guf‹bÏy8³ ‚\f‹X³2�f ˜²ÜËf¶(xS¿Ële!Hg¶(ùäÍÖh/›ÕbÎq8«e€ôV sèíÄ‚ÕÓ1#",ˆÓØÚ‹í8�àK_¼‚¯áÜ{e"glkÀîè ²�ŸC5s§ù,füé_ GÄ8Y®<Ð¥Ã\0³{ÃŒ”,R;©„)@™a肳½ÞšDŒ3¢c]Ø ì,Ç�§f{ ,'=°!ÀDç E"ÆIÚédþENØ`¢‡#¨�G7ÛòºL'¶Þ`"ÀjˆrZ×sÌßÝDh0P@“sʡ缸3Iy–ìw¾Ô2´çÎ0©1ß3w†XI^æÜ™�sºsg¹z‰kg2^®Úv†¸ ×íL†:wÏv†ø/Çèv³=…0w†(²Íï æ0e9w†htLG>w“0� .;ż™rI‘¿wi H¶ÄÌ803{üç·_üñß¿øì•8¾Õã½qüÃwþ´Üx<bŽ=Žç/Î8žŸÏ8¾Ï€qFpúëó½R-e{®—0ß@*Š(«Á¡xn�~¯—#a€Ë ¹¯èßbiŽ�¶U!8†"T<[ï#�ΆA0›LØÊd¹3Ž�F24m†38†b¦�-t1ï®8™§Z�ó ¥&%CÀPZ Û…D8Þ`È '[øJÓ€háW¸Í€ÌÃL{Œ­®sá¬Xôσsº5†Û Èlág.‚Áß0×Ö Â5!a¾NÆü ?{÷‚¨ðàz—º]¢ Á‰*FνyQ:pû–¨âcKT0Ã&†KTѶ҉Š(Eâ¼D)�ìEu °VÞãUàh/*¢ìE&Â\¢:b|U°¹/QÀ=!xQ… f/QAk‘‡w29Q åõ´‰jâæKTa „¯Ã‹ hsxQù\Éãéþä Øù¸¬MËfmxè_úâ• g}¦Äéõ±Ž¦}Ñ�ó�ÏYÆ�+¡6Já€m&<­‡……�Á N¢2Ê™€È“'!Øã3Wb~HÆà€õ&~í<ö„ p�î"D{Q#f:åAr� Òat”¢6è¢ÇTxCŹ�€R†9èÖ�AXÊÜ”f“˜` ‹%*a`8˜–P‚|s_‡}O×ÂC¤©$f2Ü4SÉÀ`›«®�*$ôϰ`+ãü�Ö4¦›Ý*qO´1PÊå¢B°1Paü¾JÔf“éŠTJ`å/j Îîn€#8E`ÂÁº _>l «L˜ðé] ë.0|À÷Ò€@ˆ×2�‘T93o3$Ü*ßGésé�±°ebô�?)›>à`/}à{a¸œ>àÈp¶K8ýؼ>0R¥¬—>pBòúÀ­¢Î,}H8¦xâÒîx^N;æåô�’ ›>$fû¼>@¼>#P"N3-Õëµ «vú€=fìâô�ÚŠ';}8h•»×*=–íô�"qú¡E›Ó0¬ÛéCd^qÓžÓ°ë´ºy}àa?®…K_úð‰ê¾§ éy-F>‰;òe¶^üê5õ~Àšî8Ó»ú8Ãmb|n…_B\ƒÞLW‡eÓ ‡ñè´JQq ¿g˜…݇Ùò¿‡ò& àán4¦4ÚônL„@lKHp�” ¹‘0�mÃî x†•[a�Ÿ‹½‹¨™§‚@Þ²:‘Ø”¨×R}â!à4F°Á¦S˜~a ª*ÌAÂê@_ºåm+´«&0¶¬b(x7‰ }ÃfÓ•¢a²à˜Ê|'™(I[ù!ÄÄÌ*–™ÁÄQª\yÅ9‰ÍÒÑAi&’±ö+¯„Ê1Z©1»B€ÍÐõÙö�9X*’‰ð[‚âƒqœNAaËkð‚âä '¨Ñq÷– *^ã´Å.E/(Dºh§bœ9}ˆtÏÁëCïCi”K0ýdi”KzSzcéC$ÿ�²^úÐ1ÏéL°›¦3—>ô¬LÊÒEª·ô‚‹4)—>¨jNI^ú€(¨{}€~¤] CÙ²P—>°®N­ºôªxР8}ðTÎK ÑUeéà \�Np2¢ Ê¥ƒÞ«;} «aiéëóÊ­�ú€sŠMßô�ˆÓx rN6}y×™.o†|Î&–žÞW†~á›×*çx•JNCùîüã*C+\œEhÒ¡ªÎú�Ü[S5öP} /Y2è%%ó�Aõу˜8Û ”Þ> <²V·œE Ž�9cô�§�`6�±[c‰JHšcªRàgHF0«¦; Es†}fh†�© G Øs ÝpŠ8¤+*­%›³"¦¬ó\yd�«<Ë1}Xu¡Ï•g`VèÞ¨ôzU��T^`EPC"æUÀ}¶âìXE^ŽA¤‰™qˆ?Ë1)›�ô­œжм“ë,/”¹òÌb1ÁA�Kà˜zÌòÂ0ZVb {\…`‘êò,/L¶ab†‚OÁó³Í†%g’ãšñ¿iÕŠE3‰ÆPT9™CˆçI0r”ƃ©“ù-Œ„_}'F*£XãÄH˜[“fa$’`DÌ<1ÜST}a¤R뤒NŒ„­¢[ó©Y„…‘R®ôŽ#•$˲0Är¨Ò¾0R‰4P #¥ ËBnÀÂH%;F‚–õ'FàåºF‚26­{a¤Œ€å¹0Šà‡ÃH¹Ên_ GC Æa$œišÿ…‘R"1Ûc¤œTÑ[ §0hÑ #åH^ô…‘pÜõJ‡‘2Iáua$` MÜa¤4äF‚ÑP’Ëa¤Ôå]FJZöÂH ÛÖ“ÃH0t‡Ö½0RÂÞcÝ #%–ТÇHØó{ñ)±„Ƴsa¤…<F‚…W"Ña¤„`F“V¾0’š ¢ÃH‰4®|a¤Ø5za¤Ä �ØÂH ðÖ…‘khiÃH‘å ‡‘Khô¾ #ŬŠãÂH‰54®üÂH1ªn¹0H×Ê/Œ—.‰,Œ„­È2bFŠ,ˆa} #%ÖÐÈ2º0Rda£F‚ɮޥj±ªº %As¢šN”PÄÚðBI€M] ¿PR YJ¡$xðlÔ©%Á<èè,”7ÄyºP‚^U¼J‚-ÆÒ:Q  *ç %.-üBI‘…°1J*à-œ`*›âpÒ€špÝ'N–er8i@KDÀ:qR„&ÐÂ9œ4 %\ø…“€È™ð8‰UN‘½Nœ¸"hƒÃI'„ ¿pп,·ÃI#Dê.œÑÁ^lLßre_eäD˜<ÞäÒ®2’¬ óÄNòmóJ»š­ –v5~3U™Ë¸Ò®²Ùb t=X‡Z|Í•w¥í·¤«Ñ?x®JsiWùѪ+ #FçJ»Ê ‘.ÀkTê4Mö•v•7›t�am9Ôiþ+í*¯(ºÀ˜\¹H›C;zå]Í»ZQ.6“Ä ]yWyiÑÚäÓEÚ@Úõ+ó g�/ôdyƒnõá3óú  ‰¬¯œ.M€cYàÔ„Dæ˜ÊmKb5¶À© ‰¬¦�7MF 1Ç>È¥ r T“KùLxí¥ r â œš�Hg¢€VA†N!xMH"]7_‘�Spš�Èe¢ª¬‚ =‚ˆ§&$±»·‚ =‰—&$²™‚×¹„I0MHÌ•±Â¸ 2ô " ,Mò ®"C¯Ǧ M^ÁUdè® UµUW“‘W»&cŽøü29b ¬|2òÒËà—¾zÅT¹(z¸\ùñ¤kÈEf3îV.‚ÕU.J)ä½|<¶ò!>öò!T9ïåCñ¸·ò!žÛ÷ò!"†¶—�¡âV>Õ{+¦À\¥/¦Áúòa"r+"¾\”HÉßÊE)³ïˇˆyÆ^>_|+"²I{ùámܡÄm/ŠUîˇˆ˜Â^>D(~ìåÃÄÖž­|˜rÏ[ù0±À—oõ½|é?”‹^Ї<ŠÓ‡Øë^>L ²½ÃÔâ^>L Ú¶ò¡Z¶òabð·•±Sy/&‘¾|¨n…­|˜ŠnåC®låÃÄ€v+BþaÓ‡4êƒ>‰íåÃÄ({+BÓ^>L Ó·òaâå [ù01ÚßʇjõðåÃÄœÁV>Lä»nåÃÄÔÃV>„;¬[ù01�‘7'@¼•¡2íÛåÃÍ ýÿ(ßD¾,Ö°¯ó¤|õå§o¿þúuÖwe^ç=¬ï‡ïvóx»ú$ë»VcòZ‡�1ŠÅŸüƒÉE={eOŽ7ÑôÖÄLÌ´wo(ïÝÛÄö{÷6aðÞ½ÝZyèÞ&Èݺ·‰É÷îmvžìÝÛÜ{÷6)+{÷6ñôÖ½]B}èÞÆŽX÷¶'æ> €ÄÜÒvç´‘s_þòḟ‰ð¤¾ðã¢èj�#él4M' S´Ád] ,#)VaªAy2á�QÉf%�7#ˆ •ñIÖš˜Ø‚}"ùxZ#š8›Ì�§ÉÝdêQ<Ç#ØC°Aô¹™¼r[{ ij½ˆCÚ”0 $ˆè)L ²+‡Í¥êp Ì>õ,’hÉF«+âx1Çl�RXe¶<`<©�4Ã4îl./Ýø‰NŽŸX_ÝwìľxMfçp±ÅVÕþ1Ù‰tq³õ…‘à6Éa4´$L“4´Eü2\,-zJÚ²IycôbuªÉx“ï(ڱɬ„µe6†ÔtSM6ŽQÈy6ïiˆ87ŒíQ­%,©Èg�iª©3 _ÇEM¤¸TO´ç Eöʱ_w·µ{läñ"ø{é‹×Dq¶ôÑEÀ°?&wŒƒ.æXSštv9ÉÊmý_jMÝú¿ð¬´÷©ûÞ÷ÁÊ…½ÿKMü[ÿ—¬œïÿÒ][ÿWd÷ÜÖÿ†%WÿW¤ƒÛú¿t5ÁÖÿ+—÷þ/]q°õEúí­ÿKâZÛ¿1fØ‚ü¾«^þî5‡´~ñ¬Þà‹53.žÌ³Ü�³k‚®µ>\ÝÐzz¸º�ÒØ¯nèäÑlW7�5¸_ÝÀö«H Ü®nè0�ûÕ bümW7tØÀýêñù¶«HâØ¯n [o»º�ïØ¯n o¿ºaôðpu§º]ÝûÕ \ðvuCäÆíW7 zsut¸>\Ý0ÄâuW7Äcäíê`ëº_ݰ_Ý€ 8?\ÝÀš˜¿ºÁw|¸º!´±]Ý€0?<\Ý�öpuC`@ã¯n`©j¿º!°3`»º�•¨ýê¶ïíW7`G®nˆ3Ñ·®nÀ?=\ÝgFq]ÝÀúÐ~uCœÙËuuã�íê†Hå[W70ÀدnH–�uW70zدnH–ûuW704دnH–g^W7÷ïW7dËg»«غ°_Ý�-uî®n bß®nÈ–¥wW7”V®níz»ºîæáê†b•wu+ûÕ t­ÛÕ ,JìW7«§¸«jïW7T«Ü¬«„%½}|HÓ Z¿ä_þê5›º~`…§3Â�gÂVC®”-Ù£ñj÷=B4y:B`­ªtÆj„&IõðŽ‹QÂ5B“›¼#ŒdÞ†­úà¹rŽ0’¬�¶FhvÔuïã(Š]#4‘AÈÓb� <]#tèÑ äÕMuÜ¡#¯`zt„›¶Ä/\sØr¥­^øâ�¹á³uùê]·?fâʆ]‰+’³Žv �¤—)³ÉŽªm:™¥®H‡2 VØUF]2#W…T¶]–Ù-Þi§œÌHDIEB+³ë¼©8ì„F’IÍZ´Í&Ï©x™e˜ö”Pf‡e^’zpœÌÈa§ e67¤ªºîdÆÞ Ê,_mI^éÆï³3š¡$¤Ÿ1û7_¿ýêöÇß¿}þò‹ÃõRó{Ãõ‡ïœbà�p»‡Ýj¿ÃO>l/óÎ.Õ£gC±Õh“ Ûí/׬M�íÍÚ궳؂tÊkoÄ®¿[A:¶7Y³MÎòÄ3H§¼öj5ÁmíÑ”×Þ­·ë"é¥ç‡Ög5¯]·z(Jgû¾e#æ5l–zØÃöGA|ÂØ÷½Aû‹_}]?|¶¾Î+ ´?®à=…-tO9˜Š'»;�ä•\KeªÆ«á¢uÉNÐõÁ7L’Ã{˜ì7Rv9kõBfr‘–Oº5ïíÌÝ÷9æ’íV…2ÙÔ‘Lˆæ»s�ç¥ ‡uKF6áß¡HÖ’.U€ñ9»!ý§ë>,Ö‘®ÖB£9s#à?Z —4|à^à "]ØþøÏßEjç�¬íì”?ž�;/§8÷Š] ÚšzÙø&Ö§ÆþK–7X9°l³S±ú´fü‰¬Ò€õ—F¡¹úËš! b­ntj•Œ“oë‡È]Y9ýÙ¦&b�k ëÆ?QÓ×ìSëì›w=_ä0°¨d|>óÌ-“¿xœ÷¶¬�µ ¯°=Ê¿±¼øÕw²sÇB.l<ºBør!r!š¢½ùKwE�ÙúHÖóÞÙ¥‹¢¶ "íÐÞµ¥‹¢\ÙEfhëÈâ=Q{G­ÐÞo¥{¢¶ò©Æ{/•î‰Úz©xGÑVé°{¢¶F)fý·:†]õ˜·Þ±ñ£ß=u!ü ß|Ñ­ß=[ßÅ•±?®`~tÌG¢cwžòl¶“p¦ £mNéeãê/Ú&¯ã¼ÌhNéUá%“‰ØJñ-g“Ç0’ýâ[2‡³�rÊ/‡~Ñ)Óà ‰+9åWŒ!¿È’ÔX5–#ÎÆ¦nì÷Å„d*þH<Ç)?2XË‘y _1­6{Jy#UPHìÄ™3¢·©Žž˜¨:)÷ðìu3¾ùÅ=DX ««Ä+L–3"Bô¼B`y]]%ΠÝõÆú?óÅTe=pÌ«9Ä?é€V7íFõ³»Õ¸kÃSýTÅ‚EãӺɕ$YÍÄ#G1ŽžÑC"kÒÅw2°ž™’ðf�`çzµ)°V [-r�•,È6 Ñ· °9Äœ3’hd’“˾: TcÆŠ3rw�~¬î�¤ÔoÆáá®ñr‘Õ�æÝC¤CXw S·±zÚ?/Ã![ÍrVÌëÆ”‹ÒŸYÍúR¸sê:»èú™zÍÌõÈl®.D¹¸øY�¾±È fÑ•éªØ‹hÏ[ÆB7†˜^Å�c›ÙâÐåŒüeõîÜyG®•‹’FíšW &+/]ä÷¢ÈdmÍRƒnÒYÄözXKŒ,cvõaŒî‹µNwZ�o%q²b!½–6»ëú½O>›šfÏûÍÎ@~YÉ`‰ÎuŸÙ1›–¿Efxá‹ï`Y¯Ÿ]”Ö3œËjк׬þ¾.qŽÊ™éÖ/»¿«K\¢ìïóÒa­þ².ñ„¢»ÏK¥Üâîê7äð×y©jœü]]"�uŸ—ÊÓÁßÕ¥Dó÷yé¬W—Åß祳Úý]]"ò$Ÿ× —ö`~/‹í…/¾‹ØÎŸ=â›ýq†ôãXbËg>âbÄœØ_obKdÎïbã՛؜÷]lŒö½Øš×±éº„�üÁþ¢]lºša'¾‹�÷=ìbãäw±qb»ØÈ|[lK ^lÿ‡ íýô?b�8 endstream endobj 135 0 obj <>stream xÚ+ä2T0B™œË¥ï™k¢à’ÏÈJ\‰ 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Žã$J¬uü`ûK‚$J$°À¬6_Ÿ¾wV¹JU‹žžá=}÷(YVÉê»›D¾¯oo^½3ùªˆ‹Lg«ÛýÊé•SIœ·ºÝ­~‰>TŸ.U3Ôåi½1ÆF?Vå!]úº90Rñg8vk•G2ÂFmÃ#¥û×$ѧ*^ÿvûGX´˜-ªò,Î숖¼=V2_;À²0|µ‘¥â"My\s9ßUÝzc�ŠÚý8­‹ —(œÖº8Í•ŸöÇõ&ÓÑ[ø«¢o~ØŠv±São:<}?ô¼Èp,„tôa(·÷ý벯¸ëP5UWÕŽ·ëÒXz¹ÝÝ¥c‚i3U <Û“€ÕZ¥Ñçûª«Ï@pÆíÛŽ�]½_ë4ÚWÝØ÷ý«÷ ôõ?«~�H–KÿáÍè/TT6x5àƒ`ºê\ÖM%èòþ¾k?×g8Éé‘Q¼UÙ—çJF5»Ð*@+æ’nŽ¿¶P?Īèý¥c\Ù”§Ç¾î¹ÕUx®àÙ«òDûÀߥ ÑÜ�<Âæª¦_¬œñÊwÕ¶¼àUè¤@V ï»Ÿ>¼ýj�¦Q�í<ÚUûµ‚å/§�(�ÿðzƒÔãvŒ[‰{±ùp¬·Çà9å*¶C=í�È•¸è4;Ï©gî„!á'nø{°AzÁ�ð²4â˜Õ}h|1Ê� ÒOT†×wª·åP“ä)Ï#ЃkÁE¤@€ÛcÙ|칟îI¹éè/YbûjZr¦ € :ôÂDÀ´Àyç²Ù ‡à`ÇBN<ëÌz‚«ôïïñ†Ò$z  ë¹á¿‡¶Ý-1o?–!’îÚáÈñ>�nägÀû^ Í5îÂÄVŸÖFŸÖÚ+>DͨIóõÜ�0Àº¯*¿T›±^å¼¹TüS¸V}Ò¿ Ñü´UÌ Ú¢3 ôúQ›<¬•6q–æÿ¥‚LcW$®x¥•-bk‹åÎ� ÂÖp¨|º]l”§¾h©ƒŪ!º`®"¢ˆÙi8 Vb­oP¢²! è#731n5€ÊÚ„o�PÇŽ¯—~�g0ÎŒ­"Öí€Ú•CéW êÉm lÕ\ÚKOJ#…�;”ŠÔÌȉh’Nøî‚‚‹qW"¿yfDz”€<¶xÌlY Ñ¡©‘)·e3à6pÈ©$.>ÓÀ …Xã€Ù¨CWnBZx'ŠG;6ýøeé`Ûžï�j;náÉðK¢P½Ã™Iz=�ù;Oˆ¿‡dÕ§Ó ¯Î´(ÀuÏ_”S´®óõÑúÐ]�‰ÜàïYo×ÛêjŽ“ Ö±Iô2¨¯ð0&]ÈÐJ°M;0pnñˆÌfŒùt©·‰ø†6Ø^GîqN§«7@þ÷Íóve�å‰ ´�¸/’«Ÿ™&9ÍÆXUKö׸Üü�úÅj…ŽUni&çÄù+·xÁ@Dн¶#Wæ>…X°C³ ª(Oä¢ä0[š,Ýj iÎÝkèV_?A£”ÎsÛ#Iu~zCª�FJÔ”Äâµ]DNØÕª’£€(K+‹EÆUxĹØÝß—È6ØÄxí È%Xé­›-ü²¯va£½?�êsM ûɈRIÂ6 €éÀáid)mÀ-#¹þköí›ÑþZ÷?¸¿ Tê†aý‚¿êˆ<†:О)¿/yºÙSO7wÞÓÍÁ‹§‹Htƒµðt±¥¿ŠûŸò¯ŽyK��µ"?m÷ñÔâºÖ!à±¾«ÓÃ] {B�¥nÄNà®çß²Ûüê]êž¶¾ú´év57jتs±K ÏôÀAÊ€;ô‡g­h–Ù)MsÐ˨‚Ó\ÙAlÌLÎs”:jç<ña@û®=£')fQ„Ä„F³¢XňC ]wà†c÷°˜æy/ª?²b6¹‹îËCÅжÜ1ft Â¾é‡ŽmžÃ{w\[£ã 棔ŸSà#Œf²*»ˆtT¬´'+î0©8KF…sn;Þ2øŸ:vú*$‘5Q�ÝŠ—,â#½H`C‰ÆAèr/i¹]òǸŒ÷‚ÑuÐ×ñá•q9Ûåã.ÐW/Ráqì8·;ŽûžMWëGÿ=L’{'];ƒÉ¯›†CQÇ!7vÉ}¥…Pé:7÷õºG?)sý¸«1%Aè6äñÈPJöU p¼ƒP_�…§°í÷Þ­U]î-÷G£6’ñÛªJ:4îÛº‘‘ÅQX€b:Ðñgôôµ÷7Gu¨Ž9þ¤“�à··“WAn‰f‡O{§W{§7°oÿ Èöñ&_77,÷ˆkÉ7!œ÷WÜ1ssGâѳu=wwªžcSXŸ’³^X…ÕBì¡4¹›˜3£y96…aÌÖûò4—W=Ðè.MÐ$ —å"V{¼¤ÜÔ÷Œûö¯?1 ï‹QO�CØ+„þEn.Ÿí;¯8Ïg݈�‰s·—ŸI‘Û/’Dé‘„tBòloõá80 ={L*úôdl_°û€­]5Ê¥y"ôÂÿË�øY·–‚ky7‚tsæ­.BþgÎ3½L¬glsÇnóÅÄ:º‰£Êý©9ÕÑÚVüCo6~Ü2O!´`?Ãè"êÏÌà€êu¶Z=]J2ƒ_tþ„~ˆ�ºú^+›D-,4Å‚4gl�y0à} ”º~À]({­êp4åGƒ˜(îÆð–Î�¸ÉK( ÅíŽ IÁ]¬8�Ìæ�}f"˜Sõ*ZTf#Ç 0E/“¿³øª“uêÄûsdÌðËÌçÀI%÷0÷A˜óA˜w[°0&@ú…U©$f¢j å]ßž@ò¸Å9W«ÆÄÅ=êyì!·ŽÆ·¥“€7 UÛTýw`ã‡-“ˆ לùQS¨I5 MJ� §ž„¡Jn€@1�'0Aâ7K6Hùùº¯šò4<Šÿ-þøB�¥Èé§r^xâ•/îƒà±,ç¿+ØK¬ JÍL>•ä¸>¦3’³µMÜq{ðRJ#.n ªî%Û3ò®ÕuR85q1¥£ÿäpgÀÊ×IaÉ_'qš^GÚ�8hSʘšœÐÈÕäñú«Fx!ýй°K¹ §‚�gb;J¨¢¯Žš¶ÞA”ÿö%Á` ®½¥v‘IÅö§°qÌüJŸ' A ³D*‡®Ü]@«<2þÐqLÑs/ë9ìøUë ˰/¤ÃOdxÍŽHy yR)blóHýù5ÄH‚Üw‹—Ê( °¸1\¼B„&Gô¹Ð¡qî1ó$ºã"“V²UøöXœ¢„.x…‹ô´c:ùÉ]Åu0ú9K³’¬LP}OùðÜß[>¥³¹ÉB‘ãé3p1Ç´3Ž B͆2¡Pnr/\€«ÏÁ-,²`RÁÍ2Ɉº({Ám6Ý¢’Á€²/¸‹‡d¢ƒó}Ô‰Ú„½Â°S–F/Ù}bqþº]á �ˆ‡Ðk%ç-v¡ aŒ‚? Xœ)F í‚#1Ôf|Í£&]oRx'Ñœõ~Ò¸¸R‰®͸¨DаRt%œî9ÇÊŹUKÇÊ‚ ÂŽBâX!ˆŽ0~é DP&¾Š?_p­ ç£Êû â#�ºž¨ª|0¹1ú�ŠC{é¹ëúŽB¯u nœ�kvô­pbÑ“ †K³Â6rÓ®¥²s–‹¿¨cuºgùnœ{÷åãl*UÃT~_¯7©M¯<¬gË3Ö*ñ©bŸ !Îÿ€—6ŒŒ J¹û‚&Óc¢ÜÊCž ?3Û. ¯Ë§:—¬¾fy#? %¢e@Õš›Œd�€(® (²ÒÆ›1ì€ItŽ“7ñ$€�´•v Ûtì ž7•Àw�_(÷ñTÁn~™ „iø ¤õƒ®2•Œô‘�mÇÈÐaãK¯L´7âK æ¾$XÐk̪K´”ìó$0—²<*ö÷Õ¶ê¼ÁD£ãùY+%±btáÄ@l=ZÿœDat_‰ùáœÖs%ÈbÄf /wœ=†Ž2àfå.N•ú¯KïÅ”‹ÕŠt�ñFñZd¨1©Š5ßë&ˆ?Ó$_ŠJSsY `­O=sú;ñí Xˆc­´™ÕU)ÄhŒzÓºª¾'Ca±`\±C3>‘Alé¿üŸZEç*æ„úÂ…€^ˆÂ/[Þ‰ýO XYz­ 9 ë3I ¡E^Ö¥AÞá ”á‚n.õÂø2ø`ç|¡Èã06d[��¦•àrö–ɉ-åâNz+4Œ!æîj>O¼çës+;ÉÚfùÊ+®y6casyN-FWÛXYY!�u fU%XnéêAVùyíRŸÞïaÎÛÛ±Òet��¹X¥–º>ÝÄiž¤4`‚¨ÃÿJ¯Þ�õêM{ó7øç»6~ÆÍlJ_ËA¤2‹G0 ËÆ@Gñd°V.ÝÚ8J”€ËoÑâ�×úüpöw’“aÀðx_Iü@©øò€é5Gêß´aQMsçQB¢ dC‰„0F™Ô|/&5OE»Ñã5f|gÉ�úŒh?ÄŒ¥G7?´JLl“1+„Õ�‡6áÏ~¬UN?ÈMœåãø¹Ì—>wäâ$·Ë}xw޳†3–ê81G®`3º‚õÄ‹@ŸÝÈšâ,^Q „u6_©K_àÍâÜ?êòU@,áŽõ¸TcBªß^z)î’ŽCì]å¨HPì­`ÏÂÜb‡·K¡²ò\Q¥–R‹ôå*,-Ίa=£NuO\‘BØçz‹áÄ*6�Ð9¿;ˆüøÝ͵øeŠ7‘�§Å�Ùo :JÍK)½CA¨x´å£û‡D2 €«YÔGrñÜà ›Ïß×ÚÜ¿¯èÐz`J`Ó¿¡µ¶ˆÄ�Ì=õêu>‘ëùÆ×Ĭ³Â›ÖÉkô«™7Dr[öÚ‘7l;âKü�P²É:ü&Ý©@IÒ€vr_Á%3ë8Oýp *u"À¥KÁ”üé*º†m…ŽVÌ—ñ}Ã}”ÖeVÍbuý¨Ú?\ìUiÊByÇ£ÙÁf{4EìÆQ F~z��Ç&•Ê·äõ,ý ¸ä[߆Ãá�wˆX}”ìò×ý©ÜŽïá7…º ÌXÏ^'Álì²qoïiW•­ ü—ðËñÄ=É�!¿�a¦ÇE©c6„‰oßÞ›cƒsˆ„‘ycUœ›ü*…v:µ[±ÖM/L7Øß)¯��(//· Š;+ì’Ã×k´zæ~7ÆA„FÏŠø½SŸ�¨t)ü’#·–[|ÚÝÈ»mÿ‚ §<‘ ûÎYœºq¿ßÍxævmŒs+\sàù÷w| ›ì%F†®–p0pŒ[±~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 xœmX TçÚž23nT‰S‰Ú„Z«­+nj]Á¥Š ˆ¬" „E–°“„$$$¬k $,BØd_q—jÝÜŠÞÛÍîôööúqïù'x{î=çï99œ„™|ó.Ïó¼Ïf5c±X3<£„ñ+ÜEQAÑ–ÏËéù,zÁú6@Ñ8Œ;sÞÁ\ªØ3Á 6˜aU½ÀvȆ^<ž~ jfalK¬=á$Бą‡†%Ø}pÈÝëÃeË–ÿ÷?«íŽJþ¼bç,Œ�¶[̼IFŠb¢„Ñ 휘»##Ã�Ù…FJbÂâí‚‚ƒ…Á–¯yE #ìv†G†ÇĈ’ì>púÐn�½ýêÌŸõûãŽ&ÆÛMFn·_ähçbç. MŒ ŠûÿW0 [¿-Ú[ä»#ngü®„݉Ÿí=ê"9¶/x¿ð@ˆk¨{øA�ˆC‘Q^ö«×¬]·þ#» Ž|¸Ãb0GÌ[„¹aîØbì ¶óÀ>ÀabžØRl;¶sÂV`¾˜3¶Û�­ÂvböØ.l5¶[‹íÁÖaë1ì#l¶sÀfc6›ƒQØÛØ\Œ…Ùbb‚YaBì1+†54eÍ”örv¿ÕÛVÎ|N3>Wã¿«ˆ»d 94uöÔ¢©¯§yN{8ÝyzÝ Á ÙŒßfÞ°>dÝý–Ç[5³f5Îúj¶ÎÆÎFes“»�ÛÌýzNàœÛsîÍù7¥¦~y{ýÛÒ·é,ëñ`‚Þ=ô»&Ö¸§‘:’¯Ò…=DyôMÛdO¤îE‹SSü²ybèk$ü’õæ²üòB½`Nå@Þ³¬,F ä<'U{æ�bXLL( Ž‚4C™9Öt0Ðó.²ž�BçQv½�*Ê×å–Ò\"ó \¸+åÞ™¤ †ïYh'áIâô©š²V@ÕE~*@B¸(¤>–›‚ „oaj"¡„xpi›¤tï.þSB“ç+ Wz¤ð&SŸÂäã2¾”BibüBv…$™RŠ8ˆoteÿËø>PÃ&Cqk®9×Öˆ.Љ›YU²‘²Ð:[´ZónF¦w&“ºÜH¸HŠA-0Nt ÀéðÛï�]«oU8�ñ€$Ež“ ”9©– œ1žE2]à0ò€ ¶p1Üsó‰©ìF�)…ÊL¯1³¿‚å_±a>H¡·í—!>šÿíbhm¾ÿ'äù«¾Cs 5zezqŽìÚR×�$�K¹ î‘ß ^¿Ç·_%ï§íf1Uf�c´'•“8IxzRJj2H²|Y‘o…Oñaà"÷yìØ'\ а²iýY÷«{¾þ ü4pí9)©Úæüi”เƒ¦ÀN�¡È¯d“ðÓoáTøþåsIǺù-‘qÉd€¢*¥U¥j¡­¯Ú<…‰¯ær3Jèw¨’\-(äI­ê°`"Œ^J¥k:É],…÷H±5WQ >#áj¢íx�ª�pÚ7Ð ¾gíøréÁ€¸C‚"=ïPR˜ÂCʃK·RM—ÚmA$bûnu:ìÞÞÄŸŒ \^ ݯÑ6f›ºW0et.W'èM”CTI0 ÑìeÈ -B6Ÿ¯y=|±þt¿¹à DæœAr‡¤PYNx”©‹A/I§$¶£/(Ÿ©P©ÅÇS#A$ˆÑ%›"“n‚Ï™Ï?|y½ùønæ¹Å°¯–tŠ�6?�Íå&Яá&J„û ,0½ÈÜj´ùÙ¥ ’„®$^ƒBï@ÖBY®9š)SÊR‘ú0æJ‡›‹Šøp>Îô¢FV¹š<�gÁ÷8fœ›+&¦ëå`9ÁD¿C.ÛÎDï,¦;køŠaÔ&ëñ([KÏ£ÊóKrËy¢$%@€ò à£ÑìMe˜¢1»ò¥p™„‰DKß™†¢’ U)¿B^š®d�¡ÒÜšd ŠNpö|Cdäy&†*\Å JÏ#¼ö?y†Ññ0…b R7Jd™Ðß·„^h }Á_„>òßÐwÀA©Ø’ÁТÕHl.�—ƒû$Œ†ïÏA¥¬ìcQÞ–\"y"ïðH}�˜Ÿt"­Vq™LAöz\«+ÈcªÃu)åÙµ +ÓÍ ™UóGn ß=ßz ]€°¢ Ù ÐÀën6\n _SËÐ+DÞMÿÞÍj�8m÷{ÜþN¡b Þ—U–U¦6¤%€@}DDì�qB–@îmþºˆß?t½á6¸†Ä]¡M¢Š˜ûÉZ\ C9‰xºX"O*�’/Ñ1øa*y½‡– À¶^rÜÚù½N¯œÝÖÝFÂ\)Ó’Ö°YuŽžÑb£‡hø—°˜¡<÷ÎbH⺜üt¾&-=M£zú¥d’Ü—JMº&cÈÊÍÎÏ&¹wΣ ø†¦À+C�uçZùŠÒ¤8©*ðBd Ÿ `Á}ù nQM#ê‡FÖïcðÒ !¢ 'î—–ŽhI#j#šR%pšìëUê&K_›�ÄÖ"…ž&x^B^u…vý«S�'a‘Äawýq¥¼ÜæÞ(ÜÉäVIÇŸ¡2peé€~�ÖÜV)q=«L|H”JQ†\®ŒIŒL�dpÄÉ^·>E‹åÄé¬rð'Q!ñÉiï] ü¾>ŽÁu)È>cj/=[γ�Ç8nedA‚É�€, lU¤nÈz£ÛŽù)åàÁd¸Êõ£L¸gÄÄËŒ2%ØÆ@ÕUuÙ}˜¶­³¹ôüàù\î)zÿç”Tžš!d‚¦¼_™ìÏe4ÊêÛ�®€\±Í×%Á”\[Wmª)È)ÌÑ ²KrŠ�–lh©éjˆ>ÄßO •û¤ê@ab²<'¹Þ.ý×ú{ªÏ]ãsõ^…UI=óO‚ê²¶NæZÅhUdFZRj¼\”–È0ÑÉ>Aƒ’žv8³Ÿœìádr³ÆØôêñ¹TYŽ€¦ì25H‰ QÞhZo ƒ˜KKŸ1 vˆ‰'ée àü'[?±ô®ÍHl²ŒÙ$<@ÔWÿsáã­œA<ÈåQNP‚ÉY7l$¼rå:û�æÛBwèzûfEñíBž&›ÛBOÿŒug&ÿ� WŒo¢2ò‚d1êà ^´š“Bå- »KÒ‚DäËãÏ íœ߃omy½d¿[¨o2ßÓªk°ýÜ“3›�5bûíuô:R{â?zÜEÿòF¢bè»p;%ÊdÒ°`‰ wãÛEm:Š÷ÊËŸ2©¶ý¯¦r ÿTUW1ÝFœ†Û-^E�Ò×L,ZÄÐ Í—á-i)™9éYÁRÔˆX”^ž©¥>?tØSÀp@iJ³dkcÉvm¿…¦´’¢k pU×aÔ—ëÊ :-ÌN�Y噆4“¼$ì#ÑWÄE‹9h‹ïåêîÃäÄ>‚ëýWÙ. ¸zz?“¯¥ew`t $ÚYôrè@ùm ŒÞ ÜA`côeI§¦5û ¯áꛪƸ–¨vÿj/àK„á‡�Æ8Gñ﯇Äw�®@¬—�žÀåTé““×À5P'Ò¯³0ZÞNÿ»�u’™C›!Άÿw ÐA´€18þ+Zì/¸ †]¾ þ;ã¦|àhýŠ~éqUàrgCû2¦ÔV`@ÒqÁ·y@Ó�«bg²WZœ4.!!,ìˆÄøƒ#UaÍ^Ça<3ÿÐ;Hvõ Õ\䟱¤™Y¿2m¼n¡Ä[ÌÀ66wV—«¢«ø±eªJ@Ö«jÛêìóŒñ�ĨCs6’Ž/Ð-lW¦:Y|»ÞÀ¨«²<"á-hM¼q5ÝðLã2~ƒ)�5— �À~ª>»2§<t}uW[Ú¯�ÏA¯¼3¦ñXÿ:ó •8·’a²Z§ús©U[4o`üI¾Ì¢àÜH:ɪA«m€ó¯^´ÔÕÉòܼ„Iÿ}®5Á¹'àñ®B3Ë|¦Œ4˜ÙôqÚ–êÚL$3Þ9Y›Xl£‹)ŒäÊmNö. ÂÏ� ĉ4=ãx´"™Ó¤²Ôždg¯˜ã „ô|ðÝ£'õ½çø�Í•- \?Ü»-QE¶žyq% ˜ZÛŠKr´9ùÀ˜­Ï) ÛÐÜÐj6´�3 1£VÞB"ÍÄ<ªUó,}�_·*Bݶ#ÎZ·ÆþZ­¾÷Œ ~K]1· 4×K£*øUaeþ ˜<æ èæ÷–ué_-µƒ K-GÆ—)a~².ú$: ‹loé›ÊZZê�½`ô):b…=õ–z6âÜSbâ‘Z§üs¨R·Zßľ�àŒeó!.åÁ4t�×ã\ï ?úe.-‡Wø$…Šùþ±aé˲-V…AÍtC› γy2ö3уN–Ug•GÆ0½,OŸ[xu“~UF'•r§!*ñi¡Zgy$¸´7L¢bD¢šscmM£9¡6ZÀÀFÞžh¢QO¸ÉæÞ+(ÿe.w}�áDž™ TJ{ňl1Ém- )Ž˜¤Ç£Ã"%AÀ lì?­\ï Ï=!,Q&�xr·�ÿö5.¡µ?oBaœœëbÌ-+7Ìg,|¦QÜ$ëìVwχėO}áqÙÞ,êÈ‹½�×OõŠCÛøÍå±®ŒžœKô�½,¨eü…v£&²ð‘Ré`ÑÙSŒÅ(�ë-£øqP#©ESÈ:<næL\ÃÓÑfN^YµFhÈ7»³ƒ�õ‚qúãlŠ©[®�­:…Ÿ`"‰Ù°²²œ,N_a ’s�å1ÈoãAÚ¡ù™yYyYùY¼bU~:È ÓÒÒSùbŒ6àù‘Æ ³hô´ml¸÷ùõ�Æbž¡ <�!r±Êñ®œÒL ê4¹<•Y@­mi"3O˜­vKáE©9Qê§Ç�¬ŒÁõ³iH—Q`¬¬â…ŽQU™ÅNT$‚%$bw—F˜ã·7r+p¾u1ƒ’M‡e |0iŸY a»˜xšÎÂí$ºI mÏáfÈzÔv»‹_×[2FÞ@Šõã(ÛÈÔ /Í-ËefE‹NÎì™±8$W¸d0UP—‚T¸HÒ¯™x½¤BÕN)ÏzÜÈÔð�s¬W£ÐÅòbé…”>¿ØòD}IŠŸYÎ�ÌaΈ3žy²RÐEÂ6äë´Úµ}•m€ì¯ Û!@Œ™8¨Tº[àš` Üse•à: ‰¦¾Öª@^®Šq P¸«Õnæ&‘�ˆÍ‹ÊST�.$BÎï�ËöoÝ”,ÕÖDñ#jtÌî-O�Æ?½ßpöŒ`àTõeðÜøœ èw¯EÓª'ñc¦­X'¿…_±i÷ñ­ÂUnâíÞÛìŠp€æ�u kû|:.Ä_g,̬WßA>œ³ý9"’4BA\­ Wדè(ê¢^�qb(0%xÿ޵‡^ÃUg‹Í&ƒ º¢¹¤ÍâWò™'ªMôƒ‡,úCž wEK*Õ}·«ôFáÈwâ[ÎM†�/œ¬‹yÜÚlséñއPtÇã133aMP?�oë·ÉNW— ÖÇ»í÷£[Åç~‰0ÇÄÈ]ó–>Ý9pÆÈç¿ò¹#`$|ÍüŠ”,¢xÕ…‚ƒäž#GölñþÛ�šÞáAþеf8t\"‡Oõ|v»/`§»èˆ»�Ÿ‘@f–¥DPÕG[™YMß°¯$RÐJÑx{è�¯ÁYÎ'¡ã*8QhúšÅh>²¾ÿ1Ä.öVôœçEÛ-�%á8N�äÌ4eš(>D È-~�àôËW«ë•¦¥�€üÛ©õècèÆ™X§¦�f˜¶Í/*6Äßy]Ø’I&s;>üûû=~õ‰ç"Ê*l7~&j‹yKùü ~Ó¿h¸n¾ÞÔ~˜üÏ!Ðï»í žnªï¸÷·¶Ÿœ àœ�ÖŽ=[ãÕ’šbûÌ¥!̼µnwé°¼§pˆÙ/r‰ ur³´*Ý”òhß5—øz—ºÕzê¸Jž ë:ŸÎçVGÔŠÛ‹´¹¹E|n`ž€ÜùÅEéêQÈ¡�u²‰ö4AÞ4íåô¦â3^V͘‰aÿA~ÿ` 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 yÊbåæfóÄÊdª’<@$$bL‚ FÖýõs–n,d“¶,Þy°Ø8ÝèõôY¾s`1»Ÿ‰Ù·/ÄÁï_/$üŠ™œY5³2�3!g‹Í‹ßÿ³%Ðÿ9±Î³ÙµÚ̔ұ‚ÒzööÅMÞŽežÏÒÜÆifÎõ fJƹÌ\_ݼøìZg³,ÎÓÔÌnîf6‹µMa2ÐLÏn–³ß£·]q_¶Ws•ˆh{wõçÍ??»¶vôŽNc�dÐ75hª®üC$þIn=Açq.¤o½(Ökîz×\É,Ú.ʶ­ê{|ñÅë›Ñ"•±�a.±JeÒ8ÕÉd™78|µ)qdèa.Eœ'9×árx)fÒMœg©_ÉB¥�å&q’(ߦõ{r°´ÔÆV_feVÃö¦OZÙ˳ʓXÀI=}Z¾Æ×Íù×?Ä×6‰ujŸ¼/ù1_§Y§ÒðÚß4=·Í�H£ÛGüµÑ_¿u„ònÛ”\Þ}K•W2‰ÞãŸr±Ÿ‡öµ«¶5óu·åßë_ß¾æÒ»+)¢²©KÇù‹í²<ÃïX½ç÷ÉòelN³â%u¬8TõœöäQ§œ¯Ë4{§¥&>/‚¡1Ÿò‡ öQÁ{´èáè›ò¯}Ùvü¢o»(N)ê%ªºêªb]ý‹+O³Æó§ÛsÆx¾úg\`LÏã1ÓXœaŒ§:å‹TÇ™|–fMTœ&ú"Œ‘$qî.ÃoWœ:œ5Ê™§pðø›DÀ${T¹H#®ÀÂb»CÁñèZ'$Y°bß– —Ú]±8'J.°ŒžaFë€Wìi†¹Ä žcƃBõŽyò¨S–�×Íù×?Ä2šëô"J˘8Éô±ÒJ¬ ¥•X‰VÚâÝ]ËÄeQn¶õ««yšH`ªÅz¿v ¨©×ï;Ã2g¢Ò> v.°´ž�ÆkS&NOóÑ%Fõ|4Õè³:éÉÃN ^—Ú>‡‘�Ñm~Ù£T »yÌH¬švëG.Þ>>Ód¹À”{ÏYêXŸf�KŒêd<*œOr†Až<ì”Aàuû,›E€y®.c´`3‘‡ùÃ3YÇd®Üu¨wžÅ(˜{Ï(ãÉŸå“K êùdyÓØB’ç±Lzß4WѶ+Ö§™äS‡1Édì$=c¶\dTÇ%“Q¥çLݧ�;9i|==ÿúô¤iÖFŒ� zÉdœÈ|tDÅía•¦‘ùüj®�޾¼J’èo�`2xëïéês£uÑ•õ¢"Ø(µ¹à*¾;‚‹¸Us¥ÁµöÔq�µ£+—!† •“t¥@ݵ_mÉÄå¾aKI‹¨-ÿš?4Ødn¾ÿj.»Õ\Þq³‡món½-–üT,š+“DÛvj29Ge³_wÕŽ¦Ï¨6ýCÕ“¶UÝy¼Ì¹vÿøæ›˜ÎÜCÄ)9ì¹JqÏqŒ466q.ÜÍ©3N§y„C\)Ør²Ñð Òh»+ò[|N¢{Ü,Ú(®®Q£cŶvo8ôs‡Tå3 Ê Øç+“Ã<À–IÜ<~ RF?Ã_åþ~O%ú›¾“a!¸XöXà«À0`ÁëþãNßPw¯©üS SPƉJ>ºÓ¯©£_èïkêúË+“ó(�I«8ö£û¿Æm´ *zKÿšu ¾Êh+æZ±�Ü=ÜH8bßt<ó&«ðžXFË´Ç#¿€µ‰V[dš©ÐIŒ3à²É)—[7 œª²*êVt/³¨ÞonIÓCÙÀ“égàÿõ»óÛh÷¿£¿g6Œciü›Ž7[‰î@áH³,›¶ŸýnŠ{¿*¸Ÿ¨7^UʽÕU^7]U÷+^�u( —宬—åÒ�P3Õ­Úm¶ûºiÁ¯ê 7;[ð7ÚL�{ñÕÜhX6 I"½ÑvœK0‰ê¶ZÒtrÁwôxK%\$«³ó›ªNmª62°©0öê¬Ýž¥i,ìÁ}p"lYµ‹}ëdXY,V\‹%�T¹Ê®¨Ö$âh&úÜ©¼_Û}±&Q¤[aᇪ޿Ǣd›i^€µÁ-ɡǞ¿¿Ý ÞŒÿ9¼ë7n׎÷ÈÀUIúïp^wC@ýMxi|C$Æ�d½e𽆃—VñÕ¾ãF¸=ø»Ý7ÜtAš IÎ_'U`#âR-­o÷ó®ãçeå*ê­£´ûÝnÛ¸vã;ÇØH)º®©nQííq_™V/ƒ¼KG“؉�Ï `êÊݪÂ^’,zW³lY—Ë{÷¢ó °È>–š²ÛC_NðÁ¶OõÞh¯úùí¯oÞüüËMàÌRvÉÜ™Á‰9|}å˜d¦Ã1ç°~¥¾ ã˜8KúË÷Ÿ¡Å\&\~‰…Ø8£á-ÞÂA]Ø’LE¿1÷èLG{v±�*™Ò­(Vâ%C2Š&¤K~d[#LNæ ÈT¯GnVnˆî X°×Üfzð4/X²õ:ÕaQŸä±µÙ'Éz‹áÊ b ‡íVEÇƒŽ¯U‘D £�矃¨× Œ-,éí=,3£b‰/ÜÒjS’H¦Ô 4€“²?rÑñU¹Àd}÷ÙÏ\h«•m<¹8©ßiºYùßÛrQìi H¤4‹ƒ ­Xb Kž5uÝîk»[WcÁ`rlÀÌ +XQ4®m‹;’[¶,YfãW$FA&Ðç—Î4-¸US¶`?3iºø"Ô}S,Ë |‚„ãÙõ©�¦¨ïI.Aù®Ùn¸ô‡RÀs/�ºÙÄü%N*I£¯·›¬pÙ7 6š(p“NE±Qflmãc[Ý×^ÎEQw¨í�xG§ñ[ÂÁ&¶7ËÛÏ™éoËî¡,k®K„øžKlº )ÕŽÄF ó¼E‹?Äž|F"aVÖÂ+£™b�“y¡hIÔÇÆÐ®“¸òÖÏ� �(¨øÉ]_(ë Q´fE�·Í2ZôŸè=’A—O1#¨‡£é¸D±Sh±£�‘rÄÝH\V0�¦{ô¯sº‚ÝÞïN±¯ rUöýWXÔ¬¬²ˆC ‰Ó#ß,lP0Áy¯!Å‚åõ©ÂÑ$É�p„²Àv_î¼èN3ðSôÁ�h¶ï« p¡7#í ü4QZƒ§Ÿ©™ŽsåчcäA"�[ðWÀ5g�LX«9€ÆÃ = pØÜˆZ…4(ƒæe´[ZØÁ ¤ïMÉ¥Ñ]eéøJÒ�� 3;Ý¡EÙ \}:ÌÄŽ¯7ìsn? q¬k÷÷÷< |£[Šß¶Ìév"Aðëć�ø0C(°u³C†¦æï@êµweCKR cŠÛíÞÕ9vF*ù,*ñ> ”ð6lYÍuÀJþ¤À#&ÂÖ|Ÿã"‚§)b¥{³cC9lšÎ?ýƒ7*vŒÌíÙE�eÂX(£LRG†ÚÕ 9¤v¶nAX½[r]Í$Z¯‘…™.üò޵=qé=&åÓ]À˜p®ÊhNÒàÝ£¾JòªB’×Ìé(Ž�mŠEƒXUü�S*šj»w„–²§Ð̬7ON˜ÞÇæ±4±2«ÀƒW¡£Ð±}ÂÑ�Ç&rösá—)*ñοóƒi§Óé1’¤”¯ûÉB‚b¿¡€ǧÓSv̹)È²å ™¿äó©�ª® ê.:Îqp¼ï’‚âÀœA1Š•'κ;Ь§¢«]â„�Ç 'oÒ)}�åħžPmÍ%«L÷@‹ÌÍW‹cEªÏQàš¾íÊ5ëo·­Éܲ³Ø€îlG qÃfÙpnÀ¾iš8û%Í s`Èj‘õë7¿raßU}F È@_2¸Ê·>c­0ñao§‚ÉÄιM¦Î9TTuè gYþ´[œŒ- gÕ¡$Áy Þà"ƒn2Šl6ct”ÆÙK¦Ð<‘íåK.²tÆZ–ÎH«ö k‘�^1TÑ”ó°÷Q.Æï­‘™rÍ[®l†Vb=.ÖlŽåh¿sE�˜ð#«ylÁÌ ¤¶Ø8Òݶù€y~�=5 ØüÖtšTì"ùZ­Ç&ÙÄu)°ô{¸iHÃM›âü#¼?;Ó©Å,‘,Ú@0Hìp€¬–@HŒ}|"Gë„—ìÝEúÑ'ÇÃ?²ï5o?ÖH÷HSpޜνH$ذ`ß ’Ùu£Sî‰O°ò)5yìòS¢1jûxÊ)âX:N|üò˜êA%¬¿ñ áMÖêð$¹~Œ â3s}õdЂc4¹ðý…f›ÏÕOváˆ9aðZËdŒØôà2��б‚Äg�º�ÆP…¤¼0ø¥.¥ƒåÐÄ#X ËaÒ#Âr\DvØïÝÜ4kÎn§Nz¦WÎ ðvãŽÃˆã§=aªüe{ ›lk¦°B†)d¨p+Cm4éz°ÌR›ã¯31� _ k¸x]­Ë[°¸WÜd»k?kËE—¦@PžA€¦ä€ 1(ˆ¤ÑUb 2\r�ÒK2Eãõ•‚ŸÝL¸9K/(€t|¾ƒ‰Üð•ʦûŠ„Ûm×­ÁÙ_¼CÛ9]T÷<n9þä£vPÀÍŒç0\áÍì±½0$/�Wº*}Œk4 ¼@xü]µÕ­»i³€ù] ª$:�$pîÒ±5\TÜT_xžîúK8?vYË×3M0ìÉ%úê#$ð}²„ s¶ÈÝ”á'Þ™·‰wæmrtsB™ÖJ×ÚòHa-­<‰9H]Ÿ'V;›^g“ ŒÆ �ÒÃü°lþ•ÞVƒÒb߀¥Â’'À£cP“Z3¢‰ÅÛ¢ƒrPN [#&&Uœ+52m¼)Œ!I›L¾—"Îc�X*øç$Ö¶‘LòOB–llŒ"X¤“G±j§F8àjH�‘ŽÍdOïxK@úbJ‘ǰ(‰‡„kÿ4”@{°%n°Æ R9RMx,2Çr¿`Ö§jç%åiœd*€€KP>À…åp€ËÆÂÈO„ì`VÇ.j°QðÉ'îO0Hš{Æ졬d½*qöeCÐ>�BûV°Žä'n²’– Ae4ÛÞcÎ=ähU\ÆdKBGKŽ+§”�ÙC/Ë=Ì v È󆦲ї¾b°/á�7úœ]§%b5¢®lK2vÊvµ]/¹šÉ3i:PžLži:'ŠÓb·[WýG7Âza%‚Ñ+gxÙáE£ ²"¶›²í-2RXË“ºàùž¥­Ó» $ë]$‘? ¿(_q¥Ïå—‘3œ4\µš›ùPˆÏÏ�:4>}! XÖªÔ ±TðÏIñ‚©šúSSzÄðQäÉÐpÐCØ 繘1æ2—"‹�<ðëú B.tüœ� X”îÁ9.ùÄ}°: Ô˜$°ýÄåå:Äæi';m,ÅÁ² 2ïi Do²pµ�æàÈä¥s@Ê®ÏÌÙ'’b¥dØ#ÁH©óH°è0,’«‡Á”1‘$ì�`…äŸÓ‰˜a‡TážûŠi^ÒÆÎûuµü„W…ÑRõ¹8…?d±ÔLS/Ïã"Nòt¼ùn†YœI0°á¸"³X?¶•;%<“Íømå=BV¥>�œ1L%"ú±ì 'z “ß®lÒç…f,è@#Gß—•ì-Ôƒ{eFù]¹„�z[® ô]ÿ®ØÙr1¤Ü a{â7tQØ3ÑÆÏ1àNmªE³�OòYÝ~¸ßuÕºì��“DZ xÔQÃ`es¿|ûbö;UÿÞ 1"xümÑÒ5êÏ w"[çÀG ½ÐØŽ³»0‚¶�¬¨oª;œÂ]ÙPÄ ßïw$˜À5cÜŽÅE¯x°þ~ëÞ¹/k']÷SxËÅ?U>ÆÜʼnБ•±±=óÞÁºÚù¢™»ñØLKÀÔËûKñS¨¯X B¯[…ÄȲ!Øìë–çY4!í¢�GO%òé�LÄÒ6ÎÒ³9»s6¹Iÿ?2šÅ�¼ûoI>õÿ”LЩ©ÿÁ®¯ysx+>�לt¯—Éf¦£9•>-ckz‡êº?\ä‰ }Çó ç€8ÖÙ�ˆŸòi°_+ÇŽUžfìÉJe¡$;“ö – F²>É)}xPŠpƒÃ<8\Eš†òà ø¯= €œþV,8) †@a®9kÕ‚Xÿ,L ×í¥ 4¡|Þ…5‹G¦“KJU›Ø­Îñ›|Ö€�˽û?81gŒá#¦Í¹ÿª-Ý€`áxe?—»¶+ºbÞLòQA8¶=3ùA0Q“¼' -V%åMe”Ý­8Ó,–ŽÛñùT¬€¾uõœá›©þÿ¡ Î0àŒF¸4RPÐ]X´oÜôlýïVIlm0 ¡åI.@o;ÿµJ¦{X‰œ-ò  Èÿw‚:Ä %¦ës\ùÌM™Ò§w*ÄW\ Ä|“iÌW�ˆ™H{¨ð�ÆV¸kãáëÉÛo)íÂäÓgá) '·ìàu¼�;ð…cæ‚ë vâÕ ¥æYêìfº/­ ºÿF ÝIä"BT3qøeQÀŠg„™+°fËšŒú°ª©0¿?ôQ‘”øŸdÐõRÁƒHÿa¤.¨ã‡qªã/§a>`)À�Êô¹I‚W«äó1Aô´]¨,ø©’Ï3¾pß x¬¨ ôSz¨I®JÊ«%¢»˜¶—äÄa.ø‚Á¯WŒ~¡Pá×é›’ )âqûµûð‡¤,~mxë>üá�Üûí–‰®²-°»~ØœV™��é®G ÉÇò!‹Ø2ÍTàK!†ˆæÂf¶à:ÿ¹–Á}ß´zê“»s‡ðÑjþ²m*öö�SR:;ЉBa¹ØÖ¸I˜×+=hÏ’¥uxãCœ�ÕðG@þ™ètæ�Û£œ‰×7/þkçó2 endstream endobj 142 0 obj <> endobj 143 0 obj <> endobj 149 0 obj <>/Font<>>>/Length 12549/Filter/FlateDecode>>stream xœ­}]³lÇmÝûýó˜TJ“nô÷£R¡Dzd‹Tå!•[¢Ä$<’%Fåò¿ÖBïÝÀœÃZ¡X¥;s¦göG£W/ Ø|¤g~$ü·ÿýõÛ§ÿøËñøÝwŸÚã_>•ç|üÝ'~þøå_êRuÍÇÛ§Þê³ñõ·Ÿ¾Üþô»Oü”íõþç×o�ÿô•þà|ŒÇW¿ýd‡È�&Ï©ßÏÚë||õöéß=Ò¿ÿê}úâ«OÿÀƒŒ‰Ÿ¿cïp øû¥=‹~­?s¾~¿%ü/$§‘ÝQöÛËaæs¬ŠoÖçÌÍ”¿þ©Çã”vnßü[ŽQž­âú¢öëÏöþ(½ºkÁ›¿äJº<óuyŒU³·ÉÕ¬t\ÍLy[_õþÿ>†ŽÐ£¤çÐ9Lãñ“ûÕûSW¤>jzö©ÿâþæçóÕ}øœÛضýv¿ù‘O"çùÌSÂIüì¿øÛ_ýý9�–ëu|ùcŸBÓÅ]â)üâï¿øù9�9Òu|ùcŸÀ\ÏúrýÅW?ýê«_Þç "ýž‹ëÍ�|"í™^æâ—_üô?Ÿ“h°™ë$ö›û$:�Nâ¯~ö«/ÿË9‹UÖu|ùcŸÁêÏR^oÃϾøé—_ÜçPdµûN\o~äó(Š)ëõNüâ—jßE{OúöS©£Ü›Ró¹s˲ONáé'À©õº+ÕǺ‰ôÂøùŸßþéë?=þðÛÇ_ýÊî‡è/KÓoðë¿Ñ{õõÿüõwÿç;|ÈßMø²f™ÈÍÇ�~õ¯ÿüõw×o>ü÷2êS¦»éM°ŸÏø»Â§î›ŠHÅþöwücØüÌøßñןH/þÇWÿõ\˜(èLÝs֭İ×~á:I‘„ßÏ}Ü[�¸CüvÉ#çë ú•Á›‘ìtÇLË+ÑOæzÌÉ¿ÿÓ?þúÿîOøóïóÐËýó×m¿û”G……¾¸·,ÎåãO_ú-¦ïãÏÿíñûO˜‚Qëj-�™/²â¿¡¶*la¿ÿö~¿ô¦ð=G_ï¾ù”»®=„¢T%êðÑ’ÊzJç¤>`¬·çÈ%Ÿ©ê˜œž4Â<d“Îú,zK Ǭù,8’ÂH_3ó³T“槪8§_Zj35c>RkС:A�Cô3½«š Çè!–ÚPrE¾¡‡(ÏLœO59ŒÑµªÇÆ™Ë�¤œuª÷]ámøø²õî(C¨þ²—ˆýÈuÙyèŠIâ/{©ý¶á/{&¥fÙ_öFw.{‚$,wÙ’Òxæê/{öüœÓ]¶ÎK{ê †ËVNÛÏeKêÅ&ê¾lL÷&Jÿð½Ö÷å§‘ UZU˜j—E¾ûëglñûöiôµj¿¢½íÏ·í�¤ë\OÜœY+:1S0Š.3ý‰ª§º:?× CRZÑ„?žouþ:�‹_ʹ—ZÐÀˆ�Rõk©ww�†=·øƒÔ©SY§;HìÈ9HË:‘¥ìûê¯}Þø|ý×û¥¢iMû£ ojkû6üÑgîµû‚Nµ®ó}¾ÔFøšcö»o`±jjY=�Æ/)œ €ré"5«Ÿ†7ZŽlc°ûé*Õ~33½ì¬›�L[ëÊW î‹âm¦Á!µÂðFRÓ¬Æit¹êªÕ3QÎ!C°âº:#Ø0DW½nø:ä‚®”Ÿ©2šÞÀsÍÔýV¦7šª(hÚe4ÀY"åe4UQÐfiÛ €i696SÕWÓ q6�Íe8›©+“ÄVg2M!‹ç˜ 0V¹˜3™¦žº¡Â6l^kNg2mÀåg2 L¦+âô2œÉdì¦ÛÌd:ØŸˆ3™œ:·¯c2]çDñÞ™LN‹Ûà1™® Uçt&“³p;=63ôÖ�QœÍ¨·§7Ò™ÌP;KÜŒ.“QÏ�›»³µWâòe3Y¹¯|ÛŒú±Ï.×FMï\±=EQP­øÚR<¾ûóçÐï 7Agqc^^؇7òé åý—Ï™6ìqžš,üÀÞR³‘µa�7¦)Þ-‡zK�¦ C=.¶¦6\< ·ôË š@½Ésjj4jäõ–M®õx{»®# ã {%©Ñ`Ó&ì5ŽQ£Q.r`¯¤º°ëìqiw5µóƒ{%éš]Ëp�·«ëJêõŠZ!¦”¨gwtèR2Þ¨W²ÚŒ3P/““ÉP›2Þ¨W`QcêM±ß™ì8Ô+JK`ÌD½Êß™º”€ŒêØ2Q¯Û¤ªMoÔ+:³Ïa 78™È•è=?˜2Aoqª¦¾.Þ¨WôþáÂ�z5ñö½7Bž]Í6yÛ`yvWÌ`âmƒâM»·Ûbäm‹æåé ÆAÞ6@¼—c0ô.ƒ!èy{9˜wÙ 1¯4g/ô.{!èɱ—y—½òȉ/{9�wÙ oÎáìå@Þe/€¼l«wÛË�¼Ë^ym8{9�w !¯Lg07äm{!âIqörï6 ^ZÎ`ä]Èk«^�wC˜Q¸ò~@äøÅ‘uOðsôo'õŸ¿þýoþçï÷½åù{=ÊwŸyl}€ß®©@â<ʱ£Æ—9vØøö0%9�òz÷Íñ¥zã¦õvœ­±Œ@6Û9;Œ�.ÜPOŽßÌÀNÛêÍÙêc¯â㇚W‡1³b•èÏx@£˜çp¢ô·Ç!S«Ç$¿9_$ÙêR¦6°jxÉçA‡jlÎ@Ÿm”�LÇ›�Œ%ð¶¤íBê¢<”éF ç`¶S7zÙ—}ù»€I»ì¥P�àëön—=•'™ ¨1âaŽßX²/ûò‰Üo#'Ë6ú©ëÓüñƘ…žB3Æ·^§iq§8Ó¤dA1ÎMÓRHœ#LS¶Uz¦ia3)~šÆ"ßrÓ´”êa5�iR”åTžiZÜpü4ÁéßÓ´2®ÎM6ðå§i%Þ#7Mj­/Ó4'ïõ5MØá{Ó4ŒïœiÊëêÓÔøsnšÀJ Ódûš›¦>Ü–Ÿ¦Âk;Ót<ö÷«[=öq¥§^|ö÷ÿÌz?£ß>én}û®÷kóݯQ{�ùnO^¯¢åq´õëì_ <¢|Üt9©tœukåN<•‹çl÷ ‡\Ç(ÒõGzQ—0_ÒžŒ x:p›^OfêîÓg='¥èÍ?'3¥‘wœ“ÞÃÓ8'3‰ÂâN¾PÒårNF½:=Ät'Ãh@¼§W4`œt"âÊŸÒ™(ÝgoÐþàƒÏ!öŽ\Î…Úoª(F·°¯Ã „%–É¡‹©è¢ 8ÑxÕ7N�¯:ò²S—¬+l|ú{ÿçÏ‘�k0Ö}ÍÑÁËî㈓ô€¬äŠÝhûØ!ÈN�zÀV5ƒP'ä°• ¶ZÛ!ÎVÿ!Î"oEÜ­Î2úܪ†[m$â=–#ÂP 05 [ ÙFÅÜhƒ-eÇ.FÄéÎ>Œ¿BϘUö*H àLµôe˜Õeø Íjù@ÆèY‰Ñ›¾—7´Ä@«·æM´ñácQÒfMkAVSqáaÛTû,>…1zö.`ÅŒí *@¿¬¾™-î„ë^Xœ¶‘ér+`„ž¼‹iѽc< �Um)dG;!+¹zf.ªEÈø¢§YqာaK¡($¤mïŽyÀø"‚&£ã‹°T×ï&±!zî„#©¹Ï݇ƈÕˇÏè†3tÄ*f pKn“wŽþŽ Ÿqï>ÄÆ,3Ã[À¬fZ�·YváˆÅº†Ôæ£pLD¤Ù�Yjs¶#.ºÐzî;�°ï Ãaˆžü Ô1tÓpyð¸²A3\xî}_8\r©#ÍcìFqÜØM­6FO¾nÔÊÆ¤"D,ÉÈ lˆ¨ ÉdƒÛ-WÂNå!¢Nª#D(^�:ˆ¨ƒËÜAĤY"tj#" »È"ªò,€Ñ�ˆÙHúDT¡Æâ@„r ì "jn"¦�}:ˆ¨‰" 3‘Ä:ˆ(`Yâ!b,’aeP¨q ê Qt_ªÕCÄè¤æ"Je<ÉAÄPz©§ê ¢¨Áå£ÐSpQ@³²ƒˆ!ô7DeYsxˆ‰ÉšUB™‹²@Fíl†ÅüºAEg‘w‹2Ú˜eA¿½‹éõ,únaÆiÀ¢~Ç4莾3Ìh>bQ¿ÎºŽÙÑw¸ËÆ‹úuÊõ }ÐVF«ÑšD}ÎHÓt>º%pZ”ÑÆ¨™@ç3¬,ˆÒ@®C‹2Ú�Pê1KY”%s‚l^£v‚ëV9„!Ã0õ6DÃ�.�^Mݤ háwT"6ã…j&[-fW½vø¾ÀÚ´ñªÇ²3Ù±w½ïvAºL‹eÅGb¡÷Œû¾‹KPQDMW6q“, ½gP8«©@ž‚Ú0‡*ÉbïTЮ‚k*­ê²«Ö ÎÖ!¥]¶ÞaSlYÆìØ»N¿]5ê÷p6c˜¦« ‘?¶†º›§ BõØbBàÛ÷TAVoZ  H¬õCJMëž* ±¦»ØM JàèÍÝT�‰µá¨‚Þ«íÞT™5Љ›*(9*9U`fm9ª `öiyª�Qõä©‚,DÈT!éå ôö¦ ŠÙÂÐÅMÔ*˜º?TAP!†ÈM -uSA»ñT�U'ÓQA-ZvT!/½âÞU –~SÖ· ¹SÝ;TAÝ‹F¿ï¦ ºã0¾v¨ki¤8ª #3Lw¨‚în6y¨‚ÞÜÅ+¿©Â†ØÑ‚>0¼©‚E26UàQP�øM, ÒUÐÝŠ¼nªpÅUU æW}S…+µc¥z>µƒŽAÁ" eAÁbµz>fËj¾ `t}ð î»^ÁbÕ|>µc!µƒ¾AÁ¢4 G‹•üùÔŽ•ú˜í+DÀA»,‚ÜzP°ÐÉ Awƒ `ÑÓ—¨`Ô8‹:œ3æµAÁ¢7³z‹ â"(Xèü‹ pÃ+XèB‹ ¿ŒƒàwP°G ýù `QKlQÁ‚~4QÁ"h.á,‚M)f+®?¤u°¹‹.¯,Œu‹”µ¢‚…1“ `ÑÕÞ‚‚…¡— `QÐHQÁÂNP°(öô¨`Я`Q“¨`��˜ý-2£‚EÀe‚‚E!µ Ã[^Á¢¸œ¢‚…Q² `Q|ïQÁÂh[P°è>‘£‚…A» `]`QÁ" ‹^Á¢[V‰ ë YQÁ"`¯AÁ¢h 4½‚E·á,Œ‹‹nç#*X^ Ý©%*X¡}§`94å5©³²(X ÒôAÁ"�¸{KA¶?(Xô†Hİ’…4gÌ,E@,<†M…,¯`)",ê²×¨`)RzT°´AÁR¤¥¨`h.‚‚¥@—,jÞ#(X ¤AÁ¢»_Ž –"C ›º¹‹RÝ,ºÑ® `)ErT°èâ.QÁRJiQÁ"ЉK)º­‹@),ï`B¿4Ž‚…‘Ë `Ñ—¨`aä2(X àAÁÂÈeP°°Þ?úBÈ­K� Ý)XØY (X díAÁÂÀ¥W°èÔJT°0péaBÿF ã–AÁR Æ-ƒ‚…Ý‚‚…qK¯`)(xñ†pTOuؘ!(Xô*WT°¤‚‚…�Ë `)H3 —^ÁR�­ Æ-ƒ‚¥ ã,Œ[KA�‡W°0l,lm½¡>kT°¨%KT°°‰†W°$ƒ¼‚…¡Ë `)È) C—AÁR�› Æ.ƒ‚¥ Á,Œ] ;ƒx C—AÁRІ.(Xèm =’ `¡×â,‚ôŸW°Ð÷ A1(XèB‹ , ]‹ §ùNÁâ‰Ë Ù)rwhC—* í€ì|ôÁgÈŽ„¹ÉÎ~³¿ÞÃìÍ7wCÑTv)¥Þ*˜ê¬xC.ŨϰRJ½ß4T¦| º úB(¶” ÓicQ%3¾–+h Q¬�N³1¬ª|0ãKSXfÅ$ê3, ¨VCeÊ×н›rMXI©HH;…Ûa•”¥L“ṉ+)Õ¦i§ÌøÙ) U`ì$v2,ª|0ákd§¢WWe_=«¤Ô�¢Ê¾Fv…HvÐ"í…J;eÂ×ÈN-”n4´™¨Ö§&ÓN‘óµRÊR›I7ÚÜ¥”br¥–ÌùÛ©húø‘]JY2«*ð5­”² Ó ØÎì»”²dVU>˜ó5¶Suµ¨¥BÝ–w/›aÞ!’¾FwZ¢xƒ�š�Ïd Nf}�î4¡x£cì!Ù³¾Ã†L²yûTñ@Ð0!ÙÕX0Ù±­ýްªòÁÌ/Ó)êRÀ�E}í9ô¿™ø]6d˜€àÐm?A¨šáàjE…¥- 8Økï9ˆx“¡M«*,=QJe¤Ø^+VU™™ùåeu¡‚½9¬˜²ÖU>XÄm³þº¬ ú"Á'º–• gKwËJO�];ܲ’N…ÖYVÀ>¸‚gYA–†%s–°¯†eÙ/–ÞYV�ílϲ‚xë÷,+`\Á³¬$³/®[VÀ>(Ÿe•Ñ™È/+³P |–UžLl»e…˜ ”ϲRD&98Ë ±5”fŸe…æ¾ gY!FWò‚Ðìà,+ÄúPš}–ã`gY!d¨$Î-+ô?êaY!oƒ 峬J"²_Vˆ`’ÐÜË*)[Á.y–¡¨P>Ë*)[=8Ë Õî—UjÌm»e…¸,ÍYVP÷ƒœe…ð.ÍYV¨˜~Y!J Bs–UÒm üà,+¤nP½–•n“ÛäYVˆZ[7½¬ÔÓerÛ-+,™á—•nïÊL*QùmâTèžÙÓ-9ø#B‡üQЫÇÂÔË §åÚ-)­9Ãe“¯­Z½‚µ/5Œ|ð9;>ÃY(—î5³ß\5Œ6îÔ0Â.çÕpÓŠ8\�ÖŒ ]ö=ZY-2|�ÖŒ\==Z­.ÅõhÍŒ­ù­Vã{´fÎ|�V+¶ñ=Z3ƒb¾G«öø­!¯æ{´Z ‘ïѪçEÐ?=ZY®T]�V%TÀüÓ£Õê¢|�VÊŠïÑjX¾G«I,|�V«öò=ZMÎá{´Zá¨ïÑj²×£ÕjB}�VÓ§ø­Vñéz´šÆõhe1gõ=Z)ºI¾G«Ujú­´gg�¯U¹+…nœÇ¢?øàs} §6úd4ö›ËžWrý†(æWÏÿµû¤\�Öá„ßi��Sè´«»Në–ÐiÎÓ �Ö!jì¾Óz/ú¸žÃ�ONßi½«¶Ði²Ø:­ë´¶òsÒÖ÷”\}ôÉçØï5žZ—ë¡2|yJ­0ÆZeÜÂq‹¥)¶aWÍzµ*K ÷¨Û@¯èÍr¾` uoÙšÑâ”ÛΈ1¿L±Ø¸:‘5Æi`ç;õÆT6Eik7=›dÅX-;ËǤ9Ì‘vs5i†Þ>]ÙD&è!´«Û÷É0v #o�!é:‘¼l1c¶ˆP!Á¡à¤�ûwz/¶,ó@oÏ:¶lRx�pÇî9c" 5 l™5 )(ŠÜ+8Р¾Ô½'™`”aðw9ÙÅ®lð„ÇQt±ŸaŒû‘áJï.ú�Z+ìæ¢Þ¶ª‹æ©y�Ÿò$LÞVÓrv Ø�xe€ŸÊ¹c&ÐæUˆûhîM.¦Î!‹)³×ËØJdj^»’$4²ÛR*¨ËÕL²eµô•èF¿m•”^9û�$+¬t¡Çþ¶%P4F俵 }ðÿº;wš¼éÁ®<Ö%þYA–´ï¡T.QòœIÇ0D8ƒ xÛº$Ö…±Â•RxÃk]Œ¯¼mÍQ{X_£E÷ »£×¿ä­ºçô²ƒRÛú~†ø±»/Ùú~N/»5Ygjļ�õi½3!Åû,)ýÖêÔ�;¥³½éŽð³a�ûR˜"Á“ÅÞlþÍ^ƒÂbPŒé”üë�åcŒ®æßL:â )³˜ùp“…(¡¦¤àY¹¼Ä�^”“X•J >øà³îû=œÚ�uoÈûÍ%1°qGb€”ØM0-Çâ ½D‚ÉdN ˜z ²'˜–6ò(yE‚i ªð¤,Á´\Xx@=LË»…‡ÔT#Á´_x@- &³‰ž` úz‚iiËð€:W$˜– hyD‚iÉØðj6<Á4]GxõŽ`šd#<€b‹ð 2üC¨¤ð€Ö"LŠ$Á4!Å+ÁôÖùN4c½>ͼÿàs}†s·Û¢÷›[4c= �.Ï—¼-šQAoÑÞ`ÑŒ?F‹&€‹¶H§·hlÁ¢-¦,µÁ¢-~,[R°h‹‹ÆÖ,ÚâÒÁ¢±E‹fWp= ò׳0væ`?ûâ�ßϸ’ç! wö`\«±º p²×îÌÀýp„“=¸Žpeî'œäÁõäƒ;3p?ØàÎÜ6¸3÷C îìÁýЂ“�dÏa¸²Ëò1WðÑc 2Z}Øöþƒ~À$¹¯1@}zˆì7WÝÆ�ö÷�cù¦Ö“=è\û{ª¾\k{ô\‰­í©/ómëÙÜ%´­GH6´¤g™Ø’°ú̓õ¼ô›ÇîzÉg´Çi¡C4V\èÏš*å®O<¢Õ¡|N»Ýâé�M/ôwÏè/´Õá—?Ÿ_Z·gk"éZ·³ÍNhÌŽ®I±1;[úø¦ëÙºbº¦ë쪣Tl¨Î6E® 2ZN…néÈOÄNèPQÆNèl½dOõ)ÖËLY,W ­;!êíô5ŒÞÓGõaïÿüCìúú’µx»Ãèý®ãˆt„{ìšâ‘ϧÓqï/5`YÚK  AR;:!+;:-k æZ0 ÿ�ëÖ´¬7˜k¯€§Ð†NLVqå»,!#º,Y9Uh¡„Œ o¡ÄJ©Ð!‰â7ß!‰UP±û‘à…îGy÷Ù:í �Œ��òî¢uš %_è[DWÊAÔkH}|ÏÓÄ?øày»ã´áž·ßÜ�õáƒ�¨ç�мõÊ}3ðG¼ºÍ;ñZXŒ²­r? š7‚B�³[£"«ßƒ&àR¦áëd2ÑÊ�d�‰4| L%V]ƒÆ8ÌÅoÖ¨’ªçaÐc" ·Y£jœ§Ac Un³^B¬º�d�ìç›ß»5ôå< šyÁý€ó{·†Œ³�‡AcŒ%\U$£ó< ASi¸Š±T­Ðt? c,åÊÁ „­çiÐÌ®d+Òºj½ ¹÷à™IÖ•ê.ãÊÒM£lƒffpZ(¿[; H„¤Þ³Î÷þæ|‰AëSŸ·ùrÄmÊ Ó— "js³Î‚GJÅ}ÌÈ: z|Åþ W:Šî]¡÷B6�u_£d>ßð¼ß\Ñu»ãëÐG†²ˆ}/ï²´» •DûFº’ˆ#c•�ÝÉSÎid¬Ú7Ò•* m,ïá� å=è.Kw�½Ž¥;GƲ1é «€>2–ÜìMÉÕ çk,§)Ô:Ý?ʱTfoLNÓ�@g¬ƒáÖê`Ј5Ö¸ìÍÉÕ¸ É*‚\ÈK[Ñd5!ŸB¸®Àª·ž—{G ÁU,R�7—yŒ cð{ÿ©çšl endstream endobj 153 0 obj <>stream xÚ+ä2T0B™œË¥ï™kªà’ÏÈJcŠ endstream endobj 155 0 obj <>/Font<>>>/Length 23133/Filter/FlateDecode>>stream xœ­½]“mÙqö~Åy$#€Ö^ßk=R6(Ó¢@ †aùA‡3’o$`„ÂÿÞ•™ë£VÏ�ëAÄÁ˜îÛ»OŸ½ÏªÊÊúÈú××ó^þ7ÿû»÷Oÿæ7íõÝŸ>Å·òúŸŸÒ[ý‡O¼âõ›÷©åñ*±¿Þ?µþØøúó§ßÎ þøÝ§ýôõüÏïÞ_ÿö{Éþj¯oþù“þHxÕò–í·Ÿ·\s}óþé¯^Ï_ó?>ýê›Oÿ‰¤=cÿ|�?òS_;½µWíoe½t¨×K÷ñì—Æ×ÉK?oñÕë[]/ËýÚáiÁ^v½üüö/ø %¿ ü^~ë¡ðOä_<ãÉ%ú?¢oÿ’?ðôCŒocþ‘Z~QÒ‡¿’SòEßþ%GûBoÏü#áOî¿(íÃß©!û¿£oÿ‚¿“†}(¡Œ·°þNýEkíñÃçÚ(þéÛ¿äÜPkoqþ¡Xû/r*¿ÈîôÒ§…à«<êÿÿß°+쯺høõËô¦«cyø¯v– {Zà_Ë£Å_é|VöF~‰wÆÃÀ#$;&3Œ:×ÿÆÃˆöš!u O ÅæÞ@3ä׋ûïÿØßïÂnÏÞÓ/y—öïÿç_5ü¹_F»2ƨïþ¯oþ÷Oø|^¿¬öʼŠoê—9!°úWñéÆùñ¯[oÍBÂüjý­—ª›úõŸßÿÛ·|ýáŸ_û�:øöÒ o$¬·ý›oÿõÏßþéÿùÓù«Ïøn=}tæ-#.¶`ÖÝ¢ÿãåµö_þúþåýø,`­Ý ƒa�¼oþßùöOë]½Ö;Àïÿ²Ú‹%¿Ï ^ø¿ý×ßýßßýñþý?½ìº?{Àåõ�=×Á@ª·øŠ t›q€o?ý3Îå—öúϯßâíÿO³�RžÖÃâþWÌ5=5êëÏóë‘ñõºJß}oßú`fi@ºXñò1<ö+¡Ø¿t¼–ˆÀkÌì6£Ho£ñóX¥âÆ�’$^Óã›Ùl´�õ­‚„n¾ãáXÜ ߢ}’Á.13É�—X´BKãM•—ØñIxwv�߯W‡<ìºÓöV�§Æ\ìàƒV ¼yÅ8x‰Åª£Âôí—à›ì>í_쮌™Y`c~3ï‚aG‡×Ø}ÚW¡ZÀÛ¯Uˆz£óοøøìeíaeÿøð§ùfÖããÛ{’|¸ƒÒÜãã]¦àßf»îñña•áhÈþñu|w��ŸKŽþñá³ õ<>~¼üÀ÷ãÃmgÿø"˜Ö÷ã«xXçñÅ`Ì'6ÿøð,žHˆøO“(ÿ˜1üoG‡°mä ?øª�¬ëù9õ ó{›zŠcmæ‘ìC2§:¹\öÌÍi{áù$R­o�]{ ºÆB™ÇžD6ÿx�Ò0Omìö"ë0~m¡_ÈöÌõ¹d³ŠjwsÉz‹£öÌù^a×ÚowûpSåi|ì‘wûtùò4üÉ_ͬÅîœ×X¤ôãmòcÁ[·§ š?ô2Ýð (a·ÚxOTm¼¬%ð�3;Ï!Ù3ߎyDûö)™µÌO×`Æ>Õ`Q‘… ¼ÆÞGª¯ kÉ22{vžÉ¹;wµû©ùUíîj¡ÍÛÄ�6~�ß*Ͼ=ÜzµG‘t"íÿðà‚=Éyë•ÄòUì—™û0Opžƒ™/>˜™}Fˆ ̦úCŠö¼@åíñû¤íÉT¼ód7hçÙ0Ìž’œ�‰�!µ=Š˜hf)UÞùc¡qËË& …:ДOÙ°ßÐÚܪŒìÙ>éôÊö jU`=|Ú%æCª|]¶ƒLâA¾J¶§ÕÛk ;?IÆj<&‰·w0ø29ø×Ñì>¾ñ¤7;SÉ ½>âlËü´}(vÛ|EÍb-{%ñ{ZfŒ#à—ùü¾l ©Ø¯èÉ,[0 lÝÛBê�œóØÂ°4]¦l! 6e.ÓÂc�(•c 9Û¯ÊíNc0÷SqzŽ1äf¿«·;�ÁBH{äÑCAŒ#P’1+O8<ÇJDl”�1ðæ<œ1”b¿+Ÿ1�! �Ò¼1„ÑÙB½ãô[@ÂÆŽ…³…`?zÓÉš¶P³ýòð¶`î6¿É L[¨ö�Wâi !6¤¨œ1T;7£4g fÑæ.�-Ðâ d !ÙÃÈÝCCœ½1XèÛæ�Ochf =$g öHê›ìNÆH{ôyNkÙFJκ Ô†³†�íaÔè¬¡Û ª5k°�Þ>ag ÝÎÏÈÃCÈcÀK9c0Hƒ=c0¸j°yg v€ AÈåÈîðEÀŠÍàtý3Éò¬/ýàk€µ¯Ó|ž WüÒ”2£¼f÷=0¶ãìØù†qÚo6þ¥ÇÈd”ŸþÆŸk� <âÅNdÅGc€›‚íëácPÞ†&‰+2}]ï0;]Sù³P�㪼¦ÑgZHoŽœŸ*>œðÜá"xÍ ëí^€¯3"íÕl<½ñ3‹öx»qû_NxƇƻJ…HÐ\OÇèA'|vqM'¢4{뙇5= Ö<p×ä@dj¡Øí‘ë®#Ž£ÈûÊ™gÔàmЖ�)ÓbÍGyyM%RVû8jÔë Z¬á# —× "nM�Ì=)§ xTnÕ`’°]{ÙRxI�½Ú…À]^RˆþÅh®î)4š«acŸ÷]:bˆ’ =9ˆúCk5 ÔÅ%50)`yOâ5‰Ö|o©&4Ù<Ø"ü•æjؘáøqMe`”Áœ’^gÐ\ ÁŠp‰E“ 9X{]º•”@”��æPùa6;æC²E—ödyI¦¹8uy�!gz%3x˜ .i´Vc°¤°¸™êñJÙ~0ø2v pêʘ:î;ù��/“�VÛa†C?fRÉ®(½z“²'þ$oRÉþPoá˜Ñ=EgSÙ°ygS ª3© œº3){š<¦Ç¤2°žÌ4)†,¡9“ÊpÀúœ¦I1òÉÕ™T±·§¹È¤,‚jøÀŽI;…ôf™±':“*v´zΤÐ%oR>˜aô2)c†3©é��E™ý𨋪f--gQŒSê,“ªö‘YálŠáLv6ÕìmÚçælÊÜBó[FÕì3+:92*Æ3ºñiTÍ>3 ã�Q1 ñ6Õì]ÚŸw6Å€¦x›êæÙrð6e¨ÖwǦº}díIΨÐ�†L£êö‰ RŒeT hèE—Q {›DóiS†é�Y„eSÃ>¯R¼M!žñe£®ePŒeÈw·AÙ;´�w±¾�…à††ÂΟPý�¢±ãš hp2笺ҿ|ûûúï¿ÿî+)—–~<åòág@¿ÌQÚ™y\)—–NÊ¥¥“ré�O¹è»ïO’ Ô.»ÚY<”ÏŠšAÛqĺ* fqÌŒ€[åÅ®‘E(ƒY„÷“i@a.*Öªá³XŽ 4³ÊÌw6dU;ÓPc‘qždNd6â³ÂoðVZŒý�Ž Ke¤ÅÌdD-Iæ{Ò=…ù \¬F…r¹û •·ÝeQ+[Q{˜·½B½?ºm†ðF¨B]þÆþ@a–¦›!*@Z�9��4³Ÿçwø$^ŸŽÄ˜ÙjÑÛ™Y�–ú¼ë™W©Î»F9/²œ9³4 ö�™1ž%W²SO£2wòYd!á“[ž�'7>�CÐçôñÐð•yò硱nNð¾»Ôü¡Á à–ö¡±›¬$IçÐàAð@lôÖ<Ý4üìº;4üx³;4<µºCc¯×îCÃc„ÛÖ¡±s–xÛûÐð(â¶÷¡áiÍšÁâ›;4<õ=ùC3ìA<ÃZOîÐÀÀ†?44B%÷Ö¡�¡vwhhËù:4öaã®÷¡±?Б}½MUêl{£)QhìàíCC’ò#.ï·æ`Ë*e‘Ò[�°}áôUWx~¥sûç™\׆n|~ºf~÷=+ìx50F�J û‘ÐïÒ¦òÌH1Û•¶óXd¨ÏH{à`”™�HÚð�>Б�~05ÄâxäÙ®î`<�Á�Ž´±\{ÐÎÆGŽôÁgŽAG:dúÁü€ˆâ0fT}Àg‹wõéšÝ¼!e èñ§ÈéJCèÓEéÙn;'P ^cWg¶¿('fÇ÷ òJ^Äæ"M¡»¶Ç7˜kš!}±kH@Ï'Ý è­Ù)®A‚¼•™Êà'Ý`A䡨#z˜53² 3Ý 0ù¼¹Þr¬ð‚%*áôþ©ÚóI°Ù@Y·½`±PÀŽ9®AÒŸ©·Þæ�Ž�^°då¶ìš¤Ûî6N/˜f�K�“Á!Òàþ‘3QJ"ÙW.Z�Ì«Váv·Ï¼ïd_ud ŸÉ‘2y`NÈ«èÆßÛ{­Hq“åÕ�Hï§ýp‰=ûl«±‡‡‰dU"\ R/3kfÁŽ‘±!‹µØúÍÛ ×YE@~Ìþ¥QIŒ%�zA!šéÝ:x‚Ýz­ 8 -+â·.óÖ³}U‘pµÿÐw7»º ™Ãá§2î 2÷ÓD ì~Ó,ŽdûjÀQ¤ÉíáCPûTš‡—Ø#x@“û¤äýo°û o+qçæyìÎqH‘åɤɽÌ;%1gÝ2¨¯Iâv¿Ï,ù _gwÞ*úÝ`/È5%¤‹tç -vçÍÎYeþ·Wñ»ß>ïÜ<’Ýy³cÖ ÿ”=¦‡™zðe¾í«�L Îiï¢(öÿu²�÷³çÕC›d)¥Ø‹ÒN]Iv{vë=%PF ‹±ÛÍóÆ‘DMÀ¬‹Ÿ8«Òmæ¥fÆpèì&fžfdðfXÒ,ÎUû e;c•©µaWwÄ1Ì]ñû¢�@qŒG²› oÊqVûÊ>»aG¬ÓÈ�2Øm#š0¯|õ(¹Àž(>OdÀY,Ðm#Q ·�ŽœpeÀYÀ¿øIUt7Tñkíc—ãÖͳ¿%9*2£C·>v5,¸‚£ "í+ó¼dòÂô§ zŒ ¤¾)-Ûì+»õag¬e]ƒŒ(BLð8Åyf’Ÿ£OoŒ½*X¸0ì#N¡# DnáTeèup* }4D”*Rä͘¸[HÕí™ ¤A6R™c†î U·Û™º[Heþa(G¸� •[ÇTæe”¹ßHÕQÄ(Á!•*�·¾� Eb;©Ìé5&P5”K¨Ø³úTT(GÛûw@eN¢3[»�ª¡4ÓN¤ñXGX8Õ³¦Bï{ÃTC è»qÊ€¥*Ÿ»p Evd%N…d�›¥†‰SÕâ{ ‡Söë�©ã�S(ïÛÛ:0eÑ�Ê9¦ªÅáÁLòÀT@Æ�¡í‚©Z�iɦì™Þø†©Š ZΦìUƒ2â ¦jTRçà”}F¬Rm˜²_µ/†ƒ)‹ÁËK¦ÊPþèÀ”˜¡¤ù‚©bœ)6Svî ï|ãT©JUmœ 1Êan *>5: 23¨*(, BÝI±T�½IùU1RÕØ£»€ÊlŒ…ù�S¨, ûvpÊÂm¢ÉÁ)tŸe`ÐÁ)³ï|ã*@RTá!Ú BÙÕ h B Ì ¨þ¨XâiNUF§H÷HbƒÊ1¡ Æ …ÇÜUMæÌ î¼iÞÁÍ“ô:ö‘šÉ'£úD'oA4`'ZuR¶=S"�l—,ê1w¦^ˆÄ¾µWfŽJëC4 å ]2PëOB¦xÄOsš÷œ‘¶5¨E¯� fK…¢ˆX!°0i‡Wȳ%‡BT£æ`uV¿¶� vKõØÙšåus†0&! — Íê6^7pº<‘ †KÅ„«R쓵»†i ™:JÛàP³gÅœ›}<ô¦|,UU%5Ht™l›£2ÁrÉ¡ìÂÙÀ¶7XØYÂxøe‘–Z‰Ûn~OÐ4XŸÁÛ17®[bÛ_‡ÿ6áH‘CÙ)š·Än/xaa —*¢B,¡ ¿Ø0÷cgŠ e95c°ƒÈd ›z€ÛavH™'Ä­]&8áLÅ¡ nˆ1�ó,tzX r?óÖÙ†•}@º&3 ÐJ¬¦.@6±²/tzX1²kÐLÂKзñ"ò ›0~ƒ³ƒª¦î� ŒC2KØôð‚Xçm¯ívLd¡ YåSÝ6M|®,d ,:¶a[ ï;A¹Í*=Ïîšna¶'DÜ5B!S`Y °�æMÓä�¡[KÈ„3…cL¯ÀK*szŒ³&0«ŠêY¡17ˆxm!é^d "“‡ìDзp‰¥-ŒýŒy×4zŒ?å…K8PàOð ºkX½á%‚ЉK8PàOô JšÂê_e',á<‘9v6V2¯J€ˆxÂRd‰  ]Wš·�H0°,EÀã¬ßÏ4/ŒÞPÄ,kÂRd  �ç­®`eŸ¤ˆ¦“?Ñ1(Ëty|e˜½ÇGëI¯Îã+Á|yüXyÇã+Á\¼ÇG—‹ÝïöøJ0ïòc"?._ææ]~4Û·‡t\¾’ÌÉ»üø°±ä¸|%™»sùpÒÛå+¿œ½Ï�çìø|æ—›wùhjѹ|å—/—ϦÊî\¾ÌÁ»|ì(—¯ óåòY¨Îå+ܼËg½Ã»|cêƒb»|ì —o.�>ù|_šsùæWàzœÇG=Áìæx| sËRÇã³Ô�Ç7'—h-Ç㣢`w~<¾E]ƒVw<>* Éy|ó¹ôËÎã³¼U�Ç7ßýðÆ·ÇGI˜ï<¾/-j{|Ûì;�_ìƒlÁy|Ôìbçð‹Y�ùrø¬ý ïï‹Ù1aù{Ô8_ 3qãËߣ¤�P�>¿  /;‡Ï¢R½~A y;ü>Øçæü}F¯_uþžæŽvÒãï1“A/¼ü=ì�×ñ÷qlsþžænŽäøûœ‹ aù{š{IÞßgó–D–éïaíˆ%�¿Ï¡ÉU/Ok7ßèü}FÃÀö÷m¨4àü}2 h,O{hŸ FZtþžönçÕùûTÙpü= Ør~Êu&§Ã§ÁÛÃrß ‚÷½> ¿ï~2Œ ÞáÓàÑæv~B Np¿¡ ËîÇ;|ÃüÞœÃ'q¤‚%þ4Küö–Šc®Ÿû ?ø* 9׿+¹»IH¹:ºuÝééFO3»VÙ?9Ø‹’f_+™F€¼}{$Fæý†…Pu¦’ó#þÑHkív«œÞWæ‰i“ÈÛ­fÒHþ ¢Fœ]Ô] Dù»--öÕì�e¢˜"ÃzåÁ 4e£ÞΠ£Aƒl3HT'Ùì¡e i/O"„ÅÈr;OÒô3k¹  à©cˆl5›=¶Œ3‡ÃßEAW^qf‰é�Ùb;¯™íh³ —qfQCÈbĉyEµ²œK¢¤ÔbÖm÷ê2K\H@2£ßEЃR‹ºiŒw�€(C¶ˆþª�Í,1a)û:CV$ ”Z¬ Sÿ@®î¼ÃÊ-*bµSBþ¡ÄßL_0E‰„»BV;%à,݆�‰»-˜±äCþ¡<äJ¦Ì*Øì'a(�¦à,ˆeN&ìÆaF›]ô£²9{¥vÊL-*t‹ŒjØ8,ŒE†(ŒÝ\Ìh³‰~d¦*W¦)ÍÔâ¬ôÑåzgÂ*·Ý€Œk*ƒµ”2^‰/¼gp'…­vRš�gÆù³ºz”qÅ`䨲²×+ §ÔâìÝ}šHa6xeóòncÆ51Š€ öŠÏ¤`˜50õÞ£^Ân]ƒÜbܭθ¦þ<…,v±ý9ùçåÏÑþ vqü9y¬÷ç±±‹íÏI‡«÷çl–éÞŸ“VGïÏ£½°‹ãÏÁΙ—ÚþM½Éûs’üìüyŒlVuþ¹Üøñç1pdÎùsæ.މ\»qçÏ™¸ÞŸ£S™ìbûs&@š÷熈¢ÛŸ3�’¼?LyO®÷ƒ~îáýy@êÜûs&u²óç!±ÙÊùs憼?Aã$ÇŸ3ÅT½?{¿œ?gž*zŽª.FWŽ?Gº«vïÏŸÆF4çÏ™5KÞŸ#¿ž/Žìnüøó'³-Îùsfñ.þ$¶×9Îl`pþÜn«áÞ�?gV±:Î"¼ÝûñçLNFçÏQË'ËØþ)ÎÚ�?-O’±:S¥ù8ô�²8ÆqèÈ¸âÆ·C(�‘c‡ŽÌ­wèe6rŒãБΡ“?86@þplNÝ! PíÞþàëý»ûúuȃÐ7ð�üŽ×Íï¾— Š+4�¬ï�Ù˜³êy…¥‰¥=LäÁM+¬ù£n°ÂÒÂÚžùX¶’0éU¾ˆ;,E6ˆCyŽf÷*Dª;,EN (âjÃ|Õ/ž–Ž<U«#±‡¬úEYnŒé-ÆþÏnÄTCÚ J#+{á)3ã˜T¿H,°¿ÏD�d¬ÞÓÂz?ª+"Eº®hlRO½· òEØ©Å�h¹|F›­[½³à�2ÿŠHëzœw(s‚™ÿ‚àpF¤ƒu=û¨Ê¼i 7±|‘WDÊÂSÐLDŸcÎ,ùÃVHŠÂq"Ͷµ¡ÖlØÔŠIQxÒàéìÝ-Œ%a™+&-,ëÙç×°¹:³aà+&­¬ëq´B·>Ô™�:ÿŠIQyBŸ•Qʼn¨øWTågHjˆi¨¯2¢Rg6ëüò`¬>±?®Ï.~œ�¡†4!:‹OS,k(0So6¼è HíüX3æ5ê͆7^)ŠOYCš9xÔ› ¯>Òšxß‘l^¢ÞlÖùg D“{g!\a" þ mU�(=%’n;¨5›eþ鿦ßá\+o;¨5ÆÿÁ%V÷yM~Dží¿¦Lìà5}üjšVª5k�ãò€V—vÜrÓHIž£zQõ‹8'w�wgﯬøw´Þ(÷s@"ª âxtÕù5%,°Aºªª$qÓ< ”ÛH ‘ž9ÙV÷à”Ù…!¡‡ JµxP@q…9œ ÊØxPÒ‚Ø  ¼Oõ €1HŠj,PPþ(zP@ìÚ<(0 E²A10³< ”ÍJ†4%(0)r@#;H·mPPríTX˜ÂY  $]ð € ‹2A”ìkjþZ£TQÝ  œaô ¾ÒªæA@(t XPP 3{P­oPP&ÔƒB£ÈÅåS«Y�¯Ü  ¼lô Ð(„á@�éÝÐ.P(ì=  4qº@!«_wƒÓÍ}\ Õ¯»AA8‡•�Ép¸[LFZd‹°ØYLæ ?ø*“9׿ϜãV·á7A³ÌóºùÝ÷R6L%®Ä ìµ�2»·:›Áeª$|hR†a¹ŽãhU¥�gÒæÝ+s†ä©L^tÇŒDýÓifÎ"’_ä2}ÑŒ–‘ì_ž¸vQ™¸èN³¯Q¹BEŒñµ¿Î (Ëö/R.@É9Cc¶ÜæÙc��\i—)‹ìÀ}²UùÌ\‘™±R6pÃ,¸@&K²9/’™´O:ŠBrŠ˜ã™iìòePª#�r‡T�ýb)$,ÂS‚,P·MQOàVY„( Ê(b�µ�g¥l€v,> ›«IÄúˆÌäEx€š&¯ijC„–Åfú"<@_¼å6)Ù/’™¸Oér?a¹Å'ŠÌÔ�´yäÆà-¦€D¨¬…³`�7zX�¥#ŸY°@šË|Ú‚ƒ¶®’Ê‚…µÜù†*4e FsÓÌrMX0}Hh&,D¨’°„1a� Nä3 ¤�,´æ‘Ï,X ÇekÁB€þùÌ„RÜèaÁâé$:³`�—ù´ y,¨,X°€G£ø˜çÏ"d]”ãš°@¹(Ò™ \=*a,X0¯ÝDg,D(Ȱ„±`��Wä3 Èr³ƒ»¸«ž²`�,)ß ‚|¤3 ÈrY»Y°`oì!�Y°¡‹3Ú�êR‘ÎX¤ì1EÑ™ =0!¾a�ÚU¤3*{½,°ÑŽtæÀu, =ŠlÆÁB"7;°@6㘠٠%>ƒÃؤ%ï²Ìþýk\Æ]þ>S Kúl~#é¡yYSMÉ6¸N{g*×\V™‰T6¡ô8ÉÖ™Æ ƒ 3Ù:ԛƲu¦qñ'ÆÌ¿);eN®¤eëHè˜í¸-1™o„n+í7RØRïßÈ`Dá߈2üi”5ro$Hgãz#è_uo„2;îÑãÑåM=#ä ÷‡¢éÑý�}ùg_ýÐί¼ÏPo}hú†$A±-¯ÜßO©æ†f)ºx)ªP‚f¨"z@Cãî E70jÑ U¦ÀCÓê EO1'{Û˜c{.ä¡eu�BÁ ãnì?Ó›Í Â{œ¤hxŒy»¢Â’ÚìR4NRÜ1²è@±*Ž¥±[H›z‘XP8ÜÖìRôpVæŸyÓh[�»�½ ˜'d’c(lÔLÒÓŠ©‘îÀ]svN!aÔLPÙ ¤­kÊ�)Å„‰3A¹îRô¸RCyä)ŠÅhšÎR4ʦ"Ø�ÚZ•3AyìR4ÜrZyd^Ò5D�¨ÙW¡HÎ'*š Šp׺¦h”’‰­-®š›ugŠkp¤•â­¸&j&ø¦ÌOÖHëóÖkâLPáN]c§m®î¼ŒÁúŠòETZÉÂ]IÍU `ÁúÚôžqŽ«&pM×HR;Ê/ IÈ%o¯ ©[t¿K?F…qÞ9šÁCq’ªÞthˆ¼uÞy‹ BD3›�³‚�gjßA€Ú`¢¢&‘õ~g‚¼úKmùÐï�ú\"ùv.I]¼kø~j‰¿«Ü[�ÜøgÅ/,­`bµ—e‡:Å!€%7þ®jï8’ä¤aš—«Rý!‹˜Å€1—Å!U‚%IŽk‚Š S¶×HÜ éð‘EÈ…£wiÒ0ŽËMÕr\1�` ›ã)-@šHïª÷²Ç´„yãˆYÇQ6WÁ·õsð• �¹"‰¦w|Ù^Û†f™Ì/ùszMÂäTH'ÅÒ¼\—`�¯Ðõ½ ÂW8/·$ÒqÍDm©¨“…i\¹ºi¥I�KYŒ¯k\nª¨¿«Þ[�Òúgq°ó4æë½€dèÃêÎi€Giý]õÞqÔØqMÔ¼\•¸arÆF‘rŠ;Ñ·;ÑVÅÃ)ØŽK Éf0æìX™‘j|âN°@–‰ŸUx�ßuÇ%]sqÏŽ•8¢sIwÞ?ެ;ƒŸSùÝ.¡ ¢ãu��,(†-�ãt¸&2?>ÅßqÉ …ËÐk$æÆ‡ò^„…Ó¨îIÏûF–5 �ld)R8È’ ÊðD�,EjYV_`Ðú K‘œÀA{NYͪYŠô²$îÇðÈR$'p�%A²"_ÈÂÊŒG–ÄÁ!‹ÅºYÄ3BóÈ’%'p�%qÅFòÈ’%'p�ÅôPd³‘%KNà KÂp${U7²°ö•²$ŒGV�,YjYÆ#Ù«º‘%KMà KÂx${U²d‰ dI˜Ž Ý#K’˜ÀA–„ñHvénda�19dITEY(8Ö²PYíBÖ:³G*´�,¬™zd¡Ð[õÈ ¶‘…zqÑ# Ë·Ñ! eçºG�A<²P¾.{da19yd‘ žGî¯Y¨¦w! ‹Û²P”/8da�Ü# ¥ýšGdPh>ÈB…Àä‘…•¯è‘e dQõ«{d¡`avÈ¢êW²(âCïëpÈÂâûf7²P>±:da),_ÈBÆx�%²+"xd¡šcsÈ‘f;ÈBUÈä�%²K#zda‡ñpÈÑíÁ¾Ù�,©ôÈÙ5’=² Ý™)ï…,‘Ý'Y(™Y²Dô°€{d¡ôftÈÙ²PÀ³;d‰h§A¡ù u@³C–ȶœä‘-åÑ!K@wÛf7²P•Ô# %ì›Gj›†…,��FÁ! õQ›CR+Ç’®5#¶?¬¾ø£¯2«óﳺ°Wuñ›Ã¬t¥gV=>ÿXƒ¾˜³žY±}3+å<³B>þfVÊ;xf…|üͬ˜w¸˜òñ³bÚábVQÂÿ˜v¸˜P.f5ÂðÌ 3,7³RÊÁ3+ÌÂÜÌŠI‡‹Y¥Ùwsð�I‡‹YQÄùbVL:\Ì ùø‹Y)çà™Òñ³JL9\ÌŠBÎŽY%ÌóÞÌ*ÍÞ¦�‰I‡‹YQÇÙ3«Ä¬ÃŬ0žw1«Ä¬ÃfV˜â¹˜UÂøþͬ(ã왕ŠýfVY¢ÿRxâͬ¨âì™UÂ÷Ŭ0És1«„öå›YQÅÙ3«„öå›Ya6ïbV Óû7³Â$ÏŬ¦÷ofEgǬ”ž/f…9ž‹Y¥ø„ÌŠ*ΞY%ÌìßÌ ^êfVè_¾™=ÝŬп|3+8Ì‹YaxÿfVt»³ÂðþͬªÚ:³‚Ðóͬ€7³JÏó�YL.f™†›Y”nf…æ›YÛ.f…æ›Y#/f…ñý‹Yjof…éý›Y²/f­ç‹Yùof•ÆøÀ¬@\Ì*‡ô�Y!¹˜ú—ofÅpæbVè_¾˜£¢Ã¬0¹1+DV7³º‘%!Wz1+æÅ/f…Téͬ˜_¿˜”MnfÅ<ýŬò?0+¦û/f…téŬP5¸™²¥7³bñábV�K»˜U‹>g— •v3+B.f©´›Y± r1«45g²°.s1«„�¾‹Y©¸ã™¤Ò.f…ÑͬâTÒ9ÌŠµ¦‹YÅ)ȳ™KV³ŠSÖç0+•¾<³Š¨]ÌJ%4ϬâT:ÌŠ¥¸Å¬ÌæÌŠÅ<ϬŒ#=˜‹‚YìùÖÌJµÅƒ,)Lý¥Ã¬T¢<Èbn§`V¬tzfeX“?0+L=³bmýfV¹?7³b‰þfV*à:da�ÿbV¬;dIÏTÊ:ÌŠådϬÒ3·³Ê1ßÌ*=s?æaV,o{f• ët3+VÈ=³b7ÅŬPh¿˜[2nf•´ Ð!˘²f›Y±ì1+ˆ^ÝÌ*i¢C–1÷‹fÅ.„‹YA„ëfV)<˜Õ˜¢o‡YÙK`VcŠÇf{¼™ÚpnfkÿÀ¬ÐÎs3«XòͬúTÄ;Ì*æç³êSYï0«¨µ•Yºôù6²ÄÂfù¶‹YÃh7³êS)°Ì‰´žnfÕ§ÚàͬKº˜• pö†9uÇ/ýàk¬j_ÿ>s“SÍo¦š#¯ÚÊŽéÑ ûµ’|F¬}K�¥GÓÜ�›ƒˆW!¶µÀ¸xÔí,gÀý^sFÆLáP Lƒ“ˆÑi�q;©[l>V¯–ÕY¥¦¹ Ä«h\ØZ`\`zvŸÏpÕ­GgøÌìÕÀ…SÄ|5°(кףÏxÕ­Pgr™‰6Ê�ÅɪYR>z`܃êV¨3^-~Í:³Ë´uê�=›à³©hé�qYªÛ³>Ö³Š�ÙåÀ­Å»Ã¹ò3rr`)R¡uobŸñªÛÖÎè™~�r`;\eÎ’ãÊÕ³¬—è:j`)R¢Uj`¬hú„Ž·²º…î3ZuKß= #PÓÞݦªïRãÞV·ò}«n-<®IB,TÇ4WÑô 5°”(к×ÂÏhÕ­ŽÇ5UŠòØìêÀ'äÕÀ¸Ö­Ž—í»õòŒŒa-­±Š®�èˆ�qQ¬[/?CÖ³�ž±³¦E ¦æ$äkvr` �-nýÌMº-õ žèPl6'é3:r` ó_nK=3¥Ýo²Ç5MÃ4(�©9iðC:j` Ãhg‘ýÌÛº]÷v fÚ a(¦t— '–0Ðë–ÝÏ42;d—XBc vµÀýŹ]žy‹�%4¶Ø�S LÍICŸÑQK¥¢ËGj`ÏLŽ $¶˜=Ú”Ë3ÁN¬Yj` ó¼�© ”%œYz¶/1°„q^»qŠ�¥�ígkðK˜ç-]b`MÝ|YR°[ ì‡N=a5isN�ÊÝΩ'ì7-õrêÒÖ8N=aÓ‹ÄãÔã�¶Æqê c¢ìål8þíÔ6Ï„tœz”5wN=A-x çÔ# z8§ž :ܽS�CâÇ©Û)‘Tørê\ëm7~œº�GI…o§5ß�SOØí‘ôíÔ¹B<%çÔ>çèE{c§½sêä ÐÍÞN�ëÊŸìœ:x¬sé!Ùp.=Aè²WçÒc§¢¾sé¤ÔÜ<²\zìTæ?.�Ì·½]:÷¯ç~\:ù=D³·K�MÊÇ¥3O‡séÜô†séL7„ì\zl\[à\:ÒÇ¡ÇÆÍΡ']r¯årè‘|kΡ3…ÂíË¡Ç&Y�ãÐ™Š¡0ürèÌ"wçЙÒÉ^®7“c±úvèÌ qëÈrè/�Cg‚)x‡«t5ŽCgž ZáË¡Ç*Y�ãФ.µQd:ôò†­éÛ¡3mÖ¢sè°&çЙ~+^¯—¥e,hß�Y¼œ�Cgy"óÛ¡3èåY1ˆÎ¡3¥¼C�8vöɇÎÔ$n|;t–ܱk;ô©Kˆ¤µ^�u{_Ç¡3SÚ’Wëç¯É9t&\¹ÖrËõ"w�‡sèÌÛfïÐÙ��n‡ÞPã;z½p1x‡^Yásr½ð3O»zfRÀÉõ"¯2âåГ ·º£c^ÙѺñeöð…|•=¬ëçéÞìAß,ö™ö]ì�KR.öÀ¥Òh¸!åb×¹Ù60Üì¥oöÀ ){€ùͰ‚áf!¿Ø–0Üì�;¥/ö€- {€ùÍ0z³J�{ö€Ó›=`^çfØÂp³ì ¿Ù¶0Üìä7{@qìf ±7{À&†›=tJ8ö€E {èµ|`˜¾ÙÈ/ö€©â‹=€ßßìk.ö0$MàØ¶0ÜìaHšÀ±ŒŒÞìY‹›=` ÃÍå {À†›= ©8ö€ð›= ©8ö€Aò›= ¥s³Lò]ìÁð¨}`XÎr±Xþö€å,ž=0Qu³,g¹Ø^{Àn–‹=0ov³Œü_ì�ù·›=@:àbÌâÝì“|{0·\?°lg¹ØƒYôs³,gIØ ñâbXÎr±æ8oö€å,{`ªôf�[Ñ/°‘8�c�[Ñ/°‘8�c˜å»ØƒAqùÀ°¡åf‘ú‡=`AËÅ¢Ô {è܉îÁ&J�À±,h¹Ùã7{ø�SOP‹qìËynöÉ™›=p ×Å ]s±ö¥Ýì8{HAoݱ‡ÖÒÅRÐpì�é{`[ÚÅÐÜÞï”Pù�Jh’÷ì�]i7{€ÊÐÅØ™v³h]ì��i7{€äÑÅRÐauì¡¶|³‡„uU7{¨õñ.mi{À4ÃÅØ–v³LE\ìA Ó³’PÏQ=ì�\Ö³ñÝ‹=LJì\:7þ]ì�Äúb“|;öPjpìaxÇHò/ö0Ž=0Yp±&.öÀ¤Ãņ®v�É‹‹= ýUçБ¹ÙƒÒ$Ρ3“r±f[.‡ÎŒŒgLÚ\ì�‰�‹=t}Ρ3At±‡®�Õ9t&š.öÀ\ÔŘ¯ºØsZ{PÚ˱fƼCgòìbMçÝ9t&á.öÐd7Ρ3™w±&ü.ö0“‚Ž=0qx±‡™\tì�[/ö0S”Ž=4¹ïБêtìa&C�Coý{˜9UïЕvuì�©Ù‹=ÌìíöpØ€gFìüú‰úzþçwï¯ûͧó¸¤×7ÿü)è‡/è?¨ñw˜åõÍû§¿ú—?þáwßþéOÿý÷ß½þõÏßþùÛ¿þæ|úÕ7>y}GŸ‰«ã‹Û!^íÙåK?ùÀP^Ð?{Zd(ûfŠ£è»Ïû»‘ãtÓëkT8šÂžñLæÎÜXä¼ðœV@ƒÑs•ìñyÚG9˜,ŒI V0æž÷Ù1ðŠ‚ž�æZp„òPй@Pa—ÄGB¤‰¬¿sØ*a¼uSNv+'>7A' lãCIžSäù53ô˜KM³T´sƒ9°.pmÂ~HPàq¬¶EÃØüŠôD‰¨/,Hÿ¾êÖõTÔm{5:=ÖbôÄE›{-:2ÀõìAç¡—nRÊêú@—àØÔ&bó…K*Û,›\]I‰mYM�Z£9®�Àin)EËú?µ°Ø y ̈§#OI&ô™²M‡«Ÿñ$Ý)Ú¥H“Ç\lj҃ÅF/Œ¯m§SL‰jZƒbv¥ºö\)Ë>'æåæŽQô*Øu/„!s}-›˜ð4Á O+ªÐé…(#L%]„³…T«rQ(*�êäk7mï¤ðˆvÓ�Q�žkp‘¡®ÔœMs .¬=TT¾Ó\%4´xp”)ʆʾyEô]e8Â:HÏÚVܦõh´Ci�¡G!>R¼žJ?”¾Ñö(Ø…ø‡ŽÊ#”ö*k1@¸uÊý×$$dи`IÄ!¨{Р޸뒒K ¿0B¦XúÃú'¥H´‡½1Hv¸)¨^w%´>ÅÒ9*M9$6‘ÑN·ÕÝûC�Û|i{èþù«º®–Ý{CëÙZ¨·;sÃ\�´—„¾Ï}êÒŽpîa*Ú(´FƒE’8×^îGmÎ]�ïÚÂñÌÎYmÔÁ œ­zÄ\±QÔJ¥ë\eE˜M‚k®ÏÈêÚ’·œ�Ç@Y¡5WcDÉÑk{rX]ň5tn0t<÷¡hgy˜-ÈÄְS¥ÝÆ\�Ì­c™(…Ö /„­æö¨^_ ÃZsÃYU3Ÿ6>s—š«ªÐš»Ô²ÚuçQMº„Y¡5÷¶%µ'j›sR.qV{»T¢ Ô'?Àet’üêS ¸ê¹”àÞ»L -Ú.�%î„îNy.Ø‹ÄY.ØãbVéñž‹ü¤™6[¸È¯¨cU~;Ó ÎÎvî Lꎭ{?¡ýŒHÛõ:…²åhÄ•€œ‘V©~îA䆑¹�[k �v¶{ wãDNúÜH›´K²3SâÓϹ.Õ‚cn?XÎUž/®æúøÏ_5Ïuµ¼Ù^ÊÕÓYÉeWœ…\AlxèàpÍ*ãÂ:Ç�%Z gÏPõ "gZ+¾£è=VG幯 )–~Ê:Æ™ugh@Ï`eg[‹Ë16ntÚžÙŒ¥QS tæ¹!�áh²Ï+”æÎRvK®eìÀþŒí£u…ÒÜGÊžÿµø�àoÈYú ¥çÐ8kZǸ³"[˜Ag¾y*•²íbK-…ÒÏÒ%þ›q"[Y¤½–%½L˜çXÒØÐpX­ 9Ë3Ï1[¡û zêÞqåæÚ×9Žì‰ƒrÊÏAHÊ•'yÂYQr-ÏTC‹2ÎZ&œü!P–4N˜bˆgU[ÏLñ¡8ÑmêÆ þ/�Í©s„h�¶Ù•ú öÛG�)Z…Ò1Îá:ƾSÔ˜Ýc‘-S³/ÐiÊ'3ë=…¢@@`›0èŠ�ÿüUó]WËß­i¸ç ge‹× 4g„µvâ}.:E�-ÚXvÊz¨†¹3FŽeÃ"«B' \¹ ŒàºP \1•‚ è\òjÿBóݨˆ*íõ ®Ü,FûM³‘ž ‹œžÐUb³N\¨ˆåßPÄë©ÅQÔ/ˆ†ê07{'Íþ¤‰®Ô·¥oTD«ì·Lpå*/ÚoÔÄ—rÛìLÎiú/�©q9‡+¸q{`vªOlå .šïE¼€}š5?[µ`‹’Ùsf„«² ö�Fa«vgqñôBE” �ŠÈ¤Ê|q3Üp½@Ò»LÚê„>2ß�‰(3Ç×&¶Æ<Û�ÃÆD”…�‰ÌDkölv;?Qô°ßga+ôÛi¿í™Þ'&‹E†]œg÷£•/Ÿµ1º`¯o^àŠþnŠ¥éMP‰íP…- \)©ŽIM�I[!|%V'4X¦&xðõÛ£„š`—c•xÑx ûE+H<2ÌË  Âì”�ôæ/üäkfì~A¾q2¿œ"̺äˆ0kErþ,b å˜ëþ,' 8�‡¹¿q3ê…sÝWÞZ-гÀêr`×ÍxYãìÆw§š’îý±Ÿ~õ1d?ßkgl C=nËë*'kL™zîK“”â»¶Pkj,u”€9 „.| VÍÅ«­®õÖ¨ïb Üȳ!Ï%€--ax”n[fWÿêׂ¿öÌ$>³´˜îâ&») ¦Åµµ-¹{]¡6vø\ÌÇ1%^‘Ù£Û¹ŸO¯2×ñÖ¸Väb!Ü¿˜›êZ¨7Ö¶€ñ°·¶cëàœ4ÌUóvu¯rOìœm\p8µâ´Ïa¹V`AÑœ`™ÚÜ�\žµÏx v¼6.nT·ôÜÒŒ¸\-…ЙBB˜SmîƒÎeÖᨠÕ9´û´y Cu R!ªrØhö&Ï×È;ª“âO(÷Õ¹O;ö¹OQù\Ô“8«]°ÉSó+]›»”?sy$‹¹˜ÓZ£2�Zõ‘N•”kè5^#9ZDΜ¬fWBÓèYZc¥C;ÏC,«O•RJ¨ÿ–5Â:´\�)â±×ẩº5Ô²¤2G›Ò³Œy‘)ìk|êÉLu#a�4D”8°œ¹¯vÎF)ÝòR•eÈ«yDhœ¿Kò„½6a)ØR™hpôq�ŸÅÕ?´Är9eØ^¨#Î1·PÊÔ_º¼œ"¬¯È�‹ê†èjýyâ”!¤#ò.Å‹·Õ¼«¹E~ä‡_uCçwÞÙZ¹åÛŠ—ÐU^b…›&?ߥx /T*}V¨”*i 2‹Ô³.”A\�Ĉ•�Ÿ émŽýÎ5 %Má<†J¢ yæ)CÍ6«9ðmG º^J-RcZ[¤Ã:¸E �P?ÒÝ¢ëDÆém úG¤« ¤§Ôbìs¡FŽK_A‰ùÊ¢Õ9r ‰ÃÄ`‰×$F€T`“‚®³ìqé&#VBÍ òC}Hº1å¥ÐŒX ez>ù!Ì“QTÁg×Àc _§Ì"Å–á†bŸºÓ•P€O�‹”Q®L“,…kÄJ¨õ?q&Ó3×ÇĸĴ†>@å¤Ì"õ�#³$K:¡RBò±ÌÌ"µ�µÝ~I”"TB£üÄ3†¨E=£9:Éø�;-$ü‹Ñɇy’¥¼ ´‡Þtæ’Z�²”WŸ^¶¶¼ºÔ±©C“²$Šy’¶tìù.E„4ô=¹A}Š¥]‹Wt_¢8(_“´kŸgÉäÖÄ�@òE£Þ/êÿh�®j—תÈÅÎL;Õ}Æ Â.3öê"iü¸éÿÈ¿júçw4̲õEXïßê"9v¦±¼Ëôaw·éG©}:Ó‡ùÞ¦¥åyL‚À·é'Ét:ÓÇ+^¦Ÿ¤ÀéLïë6}zöËô‘[¾M?Kºú˜>å›oÓLjøeú¼M€u™>EãnÓð]¦OíëÛô —éSìí6}à°7} ¹]¦O(w¦O�¶Ûô\¦�’Ämúh•¿L ÖÛôžÜ¦� ÉmúsnÓG¥å2}ÄJ·é#o|›>C®Ëô1Ÿ|›>C·ËôQ@ºM!àmú(Dݦ�ÂÖmúȪߦ��ô6}ÔÅ.ÓGd{›>Šk?4}oÆ~üµ´Ëºýì—~ôÕ‘óêBÝ#°c½Îkv¡B�þ»NÁ6ÿ¸ _ˆäW§P¡‘‚< {E:AW¡BÓ q*t^»FÄv¡B“ªSè v%œ:'2Òœ.ŸJ­`ØÑ*8ýAífÖ ‰«Rˆ&é£h,l´X {ªhɳJ1u!ØÚxªž‰³J1·]pÃÛ©RhP'Ì*…Nt§0Ñ©Rp 虲9U]`�;ëN•‚ÃGܨ6¶�R’¢ÐªR°é§ÎÑÏ\0!µ ]¥HÈp�2Ë:ÐHÚôS¦ÐàVše 5ìE ýì2…†Äâ,SHJ©hkê.ShMU ]ÑYº:E ν±»_cIkÆ.¸"gì8²€}¥jòħ抜å«EUŠ2ç¯Y¼:UŠ„×HªRÔ=[�~W)r[˜ àÐ Î/›»Mš×Oöƒ&?üÁWmô\?�ä5Ñ7{Ô„×;¥�M=†ÕK3ˉ¨ñåD¶îE_N”úŒ+'²K°ør¢”e|91A¥¾ûr¢¤c¼™æGMª«œ(ù?_Nd—eöåD úrbâÖ\_N”¨¡/'&Ã_N”~¢/'²O5úr¢”}9‘=±Å—©9|91!3Ó}9Q꓾œÈ>ßàˉºtåD6g_N”¤¦/'&îŽuåD©wºrb‚<úðåD‰„úr"Û±£/'J�Ô—Ùù]|9QÚ§¾œ˜¸®Õ—%³êˉìg®œÈ¾ùìˉì›Ï®œ˜»4_NLØ Z}9‘cL�/'¦Þ¥={•½Ù}((þå]�ˆëàµ1Û7»:ÿü§oÿøú§ÿúíû~ÿ…†Î–~¬¡óÃO¼'°?gþï¡#€: ¾:��-ùÆÎ–|cgNc§¾þ~wr²þ:µQg«g«³½QŠ EDï§Õ³¡÷E"Vjã UúBï®ÕSûâ>¯6ÎPKz›©�ÕéY¸Cúóiã¬Òz?­ž]{ô>Ÿ6NL·ÍIÓÙê‰ñ'µ®®>Î&QŸ÷Ýê‰bfÓ˜ÖlãlRìy?­žlÚÒ¬ùlãlRãy?­žlþZý"_þ,‹F›xÂ.ßÚù…ü”Oxÿ.Ëöøó›Õ踶x6zŒíÀX��àLJ7Œ­ŸlµsE —ÏâF‘hC×Ç0jc/šXÂÅk@F ÝßÊc«G�K/„Ç?^¨5um Íúx†dà!TÁ}ÿ„å¤ÏФEP¿Ð  µü˜¹†ªu£àí¥ :­ ¸vI•G$TÄÎÔØAâ>p`ºZ­å‡–`6~¦Èÿ‹„a I¤»—÷CM ¸$sÐ €pt¡¨ˆ�(SD%QŽù@–¬A6± Z°R3m¬àâu°Š÷цUF7l´`ß:%í8¡ÎÄ€4õ=,Êà¢Ö4¹.Ä5¯à%9k[Jdc”]‚I*¶žö¢^䎆!2”p973È9†ºüãÜKa Vpñ2˜I*OVÑ*ŠÈa Äq7â *êÎïªí*bP¢—�˜%Rmt¨Q›«Ïc J=1BÚE8µ\–d$;Ìî ±O¸­pâÆ*�þ"b›žÔ~n'êw}mÄô £¨*FU3†Ä% Ú¬-‚ÍÉÜ_òh�÷ rVIêиœ×>D‚ÜÅ:Ù±ñ»Õs·£¨·Ì7{~éG?É/¤Óµ’z:~A߸ÖOö®ìÖOFQœQˬâðª8›A?«s™cÅi(nC§ÕÞƒBG†Ãòî·G§F›�KlÛl“k;�Ÿ» åN­|é?É`ËîS¡§Ý«ov'h퇸¬A¸JÍ=N%€mE—@Àö¹K€mE×tÀ¦;?ÝϾ"?¹žQîÉýPG»ÇòÖ_cùì+ºFîÖK^#÷ì+ºÆéö%ûqúý¿kV>@‡úš•gS±„�˜¾áÙS| ¹èG_Cîì)¾FØô¡¯öÐG¹ÇÓ–Í_ãél*¾FÏq¨îÑó€ÄÇ5W ÚìçÊÃÐ8Ñ1 d¾fƹÛûš裾æÁ#2~Ø; ûöŽ�†¤ÎÜ_€Tò5ȱ-ñÒ6ã÷�v šÙ:ózlWvØrp×t5»•¯éêˆ%†0U&ÞÕ-ÿ¨±—ÁnÓ.®5Ì÷�öêlÒw‚þð?ÉX×ï½ËímcÕ7»/”¢«/ùë³OöP›ègõ3cÜ÷™ŽE�Gž{¶Ù_Ì©îºÎtI3îˆ3âF棲q~éÎ߮իŒP„©ii”é9þ\ÇŒ¹�õÄÔ°�tâ²qŠÎ*æFâ†Ê͇:Òµj¼9E݉�¦±‚u¤™Õb‡º"ÏkáÆB�i°  *&¶t^Kªæ}¦Á6ª¤^‹ ¾½UÓ>ÔˆŠt\»:Bª†u¨=ÀTkSÔÍc˜*×îѧ<µ½çVôÆ…‰�;õ:ˆ$®ªÚòàjÆÆí~z•Á‘**§Ž©¢Ùªyj¼Læ�íª‘S0sî‰EvdôTîI¨8ó>ƒ‡,9Ó>eH¹G“'¨íÑ'ÐVƒª¹™+;y„Ê}ÊS†Tª¨•ÛA lꈮœ©¢Äè\œ:ªP5sæ]+Á~ :´æ%ªÎQžmBÐÁGU•Q·ÚB·mú¦P;SÙ™ìi ýÒ~Š-ïß{—_ܽ úf6†òªÝ$ÊÁSÚrœ LœFBí²Ì(z’‰¼ÏÂLp\T.¡ë"‘7ô$Ó »š©@aeRmù¬ždt�“ý¯â¾ÛTw‹N’AuviJ æœW£O�2gl¦Ò%K“‡R~z<ÂÝ0h�‚›M»lgNèÞgÓŠiœ¥€òY=É4ç>'åÖÊl ~�`£9WVºxbÕ´%]òYMÉ4ç<Ó‹�sݰæ<î“ÔœP �ó4j€v�iÌÁx®uU WjX-#;‘ufÕ´š¤òY iÎuŒ‡9íÏÄ‚î8hà^l\�n5pО¿³8u6¹µ¿Q;üÎÚ߈Üòð;}ùù�¾éQg“Û×µ|ïìëM�:›Ü.Þ¤Ízgoâš§kÏ.C?·ä>¨¯ÉíÐEàW¯ö\^u/§Gàw-§jlÚ»oõÝ‹ç‡vŠ�ŶŒú®­òÜý5å}æFD}¨f„ÙV¤ÎÈìfL|gd9„áîŠüá~’ÿY¿Ç¦Ä=nRéäw_$_üJ[º"·zi4�M{™ýÂÚ¶gîÖò 5X¹•Ihº[µ[‡˜÷K+Ô_å¶q éÚvQªqïˆe>Üï›èê°rkŠ8Ðt-€íê°r;ˆ8Ñtmw Ñone>Üo�ê°rûƒóá~Ëú‰“_4GšÜ ‡¡+·ù‡#M׿Ÿg5X�}©ir[}ž,É¡½²'3îWö<ê°rëx²òá~Ñ©Z¬üS$Äýª� +·ìáC÷ktÐLœ®9…ùp¿"'¨ÃÊ-)(eªvîõ7h`×ÒPfÄýj›¨+·¶-0"rkk¢¬üJ¶LÕS·ìsÔëÖZPânLMò"­ð½ÄÐlCUWÂê‡,~(åôC¶úeƒÿÂ~’Á¯ßcßûK\ ´»!y¹Mk#Þ?G ŽÁ#qy<' .ƒGËîmð�ò�žÝÛàIYœÁ³e÷6xŽ@yƒOØj}åòÁàÉZ¼ÁC<ð6x°–Ûàqdnƒk¹ gæ2x°–Ûà¡t<Š<·ÁãÈÜÚr>stream xÚ+ä2T0B™œË¥ï™k¦à’ÏÈJj‹ endstream endobj 161 0 obj <>/Font<>>>/Length 26324/Filter/FlateDecode>>stream xœ­}]“mÉqÕûýýhGHÍ®Êú|´� [Íu<€<žî•l …ƒO®•YUY}{.£`¬pL÷íÝ}Î>»2W~¬\ùO/Ïkzyð?ÿï¯?ø¿ê/ßýþC}ùçò:^þæþò«õ¡—ùRóxùü¡�çµòëO¾ñ ~÷݇ú�ìkÿϯ?¿üùGýƒã¥¿|ü‡öé¥Õ×¢¿ý¼–VÆËÇÏþäåùÓ�ÿóÃ/>~ø÷|‘þÌý"ø/òcÿ¶¼ö—6^ëúÓ©]zÌgÿi|ýÇüéç5¿ŒöÚÖŸÎõþÛééIÿìúóþíñ µ¼Nü^y©ò%ÊÏžùæErÍñEìÛ?æE>ý”óëôiõgUÞ¼J‰¯bßþ¯R²>‡TÒëã/’~ö”ñ³Úß¼NK%¾Ž}ûG¼ŽL}(©Î×´^§ý¬÷þ³üæ¹§>k|!ûö�y¡Šêý5û å6~V¤þ¬„S0êクÊlÿï×Ð+ôUž×®§åé/?ß_}ùÅè¯Ery)òÚ†þïâ¯~ùW÷˧§&·ËÏ뛟úMèÿ¿Ö‘¯7ñ×û·ÿöïþÝy¹ÊyöÍOþ6ríoÞÆ¿úÅÇ?ûøñWç}”ZÏû°o~ò÷Qúë|ó>þâW¿ø³�¿8o£Õ¾Þ¾üÉß‚º»$÷[øÛ÷‹_ž70êrÜüò'c¼Ê›7 Á¿Üo ?-ùà—?õÈ�:|ùâ0üÇë4äÜò> þÍOþFòÀ;¸ÞÈøÕ_…Ã�óλ°o~òwQÆëxó.þò›ÿôË¿8¶Þ¾üÉßA›¯Ï›ò—ýwßüëóFëàËŸü †/Îä_ÿâϾ9ÏBž¾Ü5¿ü©ßƒ<ûz÷Ë¿þ«_þÛór?Û¿ùÉßFž_xì¿üÛ_©�Ü9Å£ó>}�Ò—#ÿt_óµ÷–²¿9EÍŸ>çk×�©¼t=–µ ßÀ/ÿðù¿û»—ßþÃË_þ�=’ö:zÕ_H¯Yýïõq}ûOøö÷ÿû÷ÿåO>ýö;\Á?þàOk™q±{vmÞ?÷¯/ûgÿåOï_^ˆž4 k£½$‹ö¹|ü?ÿøíï×»zYï¿ÿó^qµè§�ø 8­¿;ùg+‚7 +dÔloêopARç¨o5¯ÛÒðký»F?×Ûæ?kTÂÖ¸LÕkõ‹ÿf½Æ¸>Ò4ô>3üu>s¿�u—C^ÏéQ´Ë^‡½Î××÷û„»I ÿ:û«Ø¬7…Ð÷ç}ßB¸�ìóÖ¿¬ÿ\ÃŽ×RŠ}÷_?þ›åáýû}þg»ÑŸ×j—=ë²ó|~žXÅ©G£ÇbÏÿo¿þ_ßýî·øÍß¿è3ù÷Ü^¾ÓwÝq£|öiNÚÐËï¾ýð8¥ïÿìå?¼üæþíŸÕˆj}úH+͉¿Äì íûOçûfÁ½_íß}¯ßg½³‰Ï½ã×»^ÞñÒúÄrã/h@Ô�šŠZú»¸Fß×SôýɼF¯~ôh"Z-·¡�ú’4õÏ7¤DI�ûUô·ºžÈdoU?Tý¥¡Ï¯$^"ŠG¢—dMå/Ñã0ðîÔC'á5­i& Ö€ˆ˜1ÂÔ[MxƒúÔ.p�þL_»5=“—doþ©ØÇðþm·™^{¹nÆ;ãmw=^OŽ·=¦ú�o»+¦IŠ·=³åxÛ½«ßœñ¶§æ˜©\·�ÜjÄÛžê•J¾n[s�ÔÎmççiþ öm7&QðÑÿþOß7ú²ÉFßù|pBÖ¡|ç_;‘ërÜIIî�ùe*ðîüN¯Ùßé9ÔƒúÚú î¯ÛÇ”«¥X ÏY#/—…›òORŸ‘~L/)EaôeªWJöòxBú!Õ¶žYîú¦51žø„ýüÐäSU°èü3òèIzÁ“o‰§yâ éC¬�Ø™€RšêëñÑçmO(#®þ<¤ê5zpnìïà áS(ÍŸ«z_ÍÐ_`8½eFœzø™ÒªÃ²óQ’Ú™â\yï¼Fs%N™�³¢¬ÞyÏåUoˆ×èŸÄá íÖ \Az�åÌæ•“Ú4§è²c_æÀG Ói™GÿO§ÀSò¾ªòg¼4Mf¥ð� q8³æ›z$q‰žqi/Máñ©•×讟ƒ=ÞUÕ3®Ÿ©Bý«ÝTV )€Dµ¯Æ›Â¯O…°Z^�x¸F�7®æ;Ã5zÆ3ÎX{Í�ð=B  ïê1[F…E�¹æ><YÔDDï)!M6 QŒÞwQ?Ó„F¤èG ×hi÷ÝõDêa*%é}ÛßÑÏ–…”‰ó†K*OìiüˆE=JVè±5k ÷-£¼ÂfV'E;¤ªzlíÆqdô,ImzøgŠ&núNç,…OálJô#›)ÚTzô&ŸlJàpç F•ý°$«8nó¸nUéiúPƒQ}ÁÞ�M¥G?Ž1ƒM}¸O�6•À¾›*úz"Ѧ’-žÊ±©ª/ˆ{l*©ÓÄ©>6Uõ%qò�MéKUXDZ©ª'tl*éQ€•›ªú’ÅnËm*e ê 6Õ2"ºl*!È#ØTS‹†g86•aJ FÕô%ý‰»Q%QïQ‚Qu}ÅfèèF•¤ø²cU]_q̬*ufvënU]ž 7* ×ô¨›êúzð½Û¦R©Ó`xÙÔÐ×»LJŸT×X9˜ÔPSÐÃL*U‹ä¶I�ülÁ¤RÕcX$˜”>É×fžÍm*U=†=›šíÁ¦4ŒNÑ ôÀê»8¥‘Á4Àß5�ž²àsc!â*ECÃN}ÁU¼y‹žïÿè+ø~�o´í¤Æ¿Ù¸éWFÅ#JÁæ³>È¢x>%¢hÆ#ÌEŽC@ÑŒ'X/Åóy"Šf ïßÅó‘€¢O0](ŠÇS#Šf<Ár¡èÔ1"Šæ¦®¤_(ŠG”.mêgDÑüàD\(Úԗ䈢ùÁ¡¸P´©/©EóƒSq¡hW_2"ŠfÔÄó…¢]}IŠ(ª> ã‘E Z"Šf¤|ãBÑWP4kì‰Ïô èP œEÕ QhŽ(ª â# (Š´FUP"†N}W#b¨z€Œ»Š4E Uðà( �êHJÀÐ,‰wÄЩž¤Íƒ¡Yô@¦ˆ¡úÒê-#†Ò4JÄPýè)áÁP5'ô_†Ê£Ž¤^ú®=u{:ºì) ¨ÔAÐeQAÝ¢6‚.ƒ:jöttÙS@P·§ƒ Ëž‚º=]öÔí) ¨ÛÓAÐeOAÝž‚.{ êöttÙS@P·§ƒ Ëž‚º=]öÔ ê è2¨€ fPA—Au‹:º,* ¨[ÔFÐePAÝž‚Òž~º=mü\æðÓÍéàç2§€ŸfN?—9ü¤9Eü\ötðsÙÓÁÏeOŽŸÛ˜6~º1üÜÆtágDÃAGš×òú?üŠž_áz†âKýÜ­jéWíï¿× þwÀM°†ßÕ�Å5ãd�N?:=.¸ùi :ôKšZž}^YKOßâx‰~Âî_vHBU_?cõ2ý L”ªú\ƬȤ?ð�É=jge êiôg§¿£G‡bؽNµ(Tôã0(Ö·Òqø†:ÇÊ3 Ñxai èŸ.v”qQõT�µ(;£É°8ý-=€8æ“p£A_¢Û*ú§‡ùTý-½ï®˜Þ¦;Õ ëWœ-~ãµL6Î_ 1TÔÕÐs‰z^Ãâ¢áÈDs\_œ*úFðгê*y_U+7z"›$µZ8.Ô² Š«þR…3A‘�J4°–²þe¥Ú¦WÕ.2ïJmÏüV‡b5}ômÓ^*«åâÎÕÔ‹›þ–ÀGêkDÕë 4©8Û”ZEÇE]­¾4aT$±Ž•Ð3,nCýMS—­¯MÕ°YÜe?ŽÅ]K'\ÿ(öw:ËjIÿÏýG×ßR³+ê¾*qTQ‹å9ÍPä•è¦.R�Ž‚¤zÁl@ZÔ²:p¨.W6Ð-gÓp´Tm3,ÖC‡»Eôn ZKfsn§:Ôº4uìúvpMM,™MuÑb·ýCf'Í2‚Ùék?x¦Çì )ÌNcàÎŽÝ!k˜©»Ó�C½Þ1»М3Ø]BuXf°»Ð$`/»S»ÜÛ±;¤ mnvúlÓ«‡ fv˜Y£ÙéÑ”«³«ÀL‰f§f0�e³«úƒìev*LE³«ú‡l7;�0ë+9+Ëì0sF³S Ò—Áì0³G³Ó;O¯v²Üî@Ó ÛíN£Ã‰ ñ»Ð4Èv»Ó„} Ñ>†×�šæ­Ýð4�o~ïnx]ÿÓžhxš¨9»ëNCl·»„Ñín8G0;õšé•EáevÀi�íf§Ùº¾v f7z¾­N“õŽ,ûX¿Ç\›[�f\êpr°º™ç‚m³ºM8¡ÑMý›ŽØnuŠIIv°ºQb»Õ¡à‹$ûX]zô¯Ò¯‘#¶Y �MêMƒJO© ’CI¤Y—ç¿ýÍßÿ�ß|÷ƒM�ÎÛ{¿ òÅÏ"Ø¿è×ÌS?áÐéþa­¦GwzÎþ¾Ih‚¬ï¾?åÿ:ÅâÝÝèâE;:y ~º  y{€ï:L²E…»‡Ð­Áª·°Ø¾¤²I�Ú)JV Z=„V šO{=+fb—þv±@–Õ–üÂ*G·¢µZVïNÄ@wÅ>õéÖõÈë&d¾¨Á±äÆûýi~Û«W1ÐűÄe�õW“ß6Rlk�è[²üÜ{]ªßöêg tŒXR˜™È¯žd¾Ú{‰uÜ�°ÁJA_<¦™,yX�©hÃc‚Õ:ÃcR‹áG·“š Ñþ<¦ž‡=‚ý˜ZË3>&.>Êý˜FµŒè<¦þ&$D3>¦!–{�Çû½ÓPŒØÃ¯–âcñð˜Z!æÇǤ^·}Bw”ÅÃcê–PžÇÔÔ¦“‚J‰�é4™¾´îoԗȪg¡ÆzÖ2ûwô5«?¿Yë»Pæß¨¿w`Wîï¿ßLckA‚Œƒý<ìèóO4�É1E0P¤}Ã\£Ÿ r}}òV+H¢aAJrüäŸÉÄ åÃ`¢d”-PÏ Ç× hŒz€>’Äð² цµ>úl?yp õS-Š6¼FÏôÓ‹17'-…eÖN«_ gÏëQ¬á�Ó\ñ¥(`6FEϳ°d GÕî;!‰-/SV< ¹‡W¿i=à80‰%¡½êin8 i­•iÔ€·Âk�Í#ÕT¨„¦¸yt»Õ«2õ2„ÁH†5„y’ÕMjµv ÆnXÓ[Ü0Š%¥Á +N3=ûvèn£tÌ~øVP`\¦'3[ÿB TÏAE Ë¢HÅCC8�ã ö8Ëx LlªŒ¹ÔcWë.N–[�G?t ð2HJõ]$¿mÊQÁa² /33â;uÙvã,�ü< ôMÁP K *YÅtTI\ н¡SM®¡‚£¤AâXo*�gë“Á´¾Q†\¸¼¼0�`g¹áÑ¡R.êµíÖ¥³²Óð`Ì¥ë£CÀ­o´ù­#¾FµÁ³(xšÎ.¥¦-ͺ.÷ꟗ˜ÃÓ �¦a"B76f&î\ŸŒ­ÅË ‡ß9ؽÈT‘MT¾}z([j )~ç…DÇ—Ž'3a,xgÔÜì΋¦Èf‘¹0Ôíxzp›%1d‡9aÇ“aœ5P5aY½4ë«NÖ™€Nô¬\K„Ö1}H‘A¡Ž—Ha2’`ÃÖÜÑ)±>á)EÑ9B‚ OžÒª1>JDú\ áéOBÿõ½ÇþNaµ E+âÉÐG?š–Ý6’T‘Êch‚üGõ?»éªù�Æ÷Ï„.`êskø´»ØiEÄʪㄢDè-"�ôÕ"ˆÐÅ5úà�Š$ØqŸ'.aaitšŠ Þ×+c(�•Âkðà=T„Þ±ª¬Wá¡�:‚d éSB©1t)R%Tdô�ò„N<8<)õ…¯VEƒ² ³º„”­±/´‚ÇÁÐ…¶'I}v!jd<™¥¯�ìÀ®¶ŠaÈÝù0V…Ãs™öJzfðÀ�íλì³f´>Íf �ˆê3˜$ݳ`åm/0z¾qv˜%t X@¿°,åq߈šx˜Ë‚âÔ²Žþ>Ëè­#m,ëjþ0ífêô2ï|ƒYG¯¤¶f �5ÍÌà‚áj˜%R­0ë €é9>`–�Á�l0ëê»,KˆëÀ)ØXÖ+´ÊÂCÜù†²¦/ | Œõ(k£Ð•,Óë`cYÓgD8X¦¸>A”ØP†7ŠrÇF2}ŸÆoØH¦AÑé ™Þnâmo$k˜@��L?6ãRl$k(€i´�L?}!bCY�“oô@Ÿ"h ʪ~$¸ßezlThCYí‰Û�2=T$ˆl$ÃÙT·t�L�fã}o(«%ón(Ón<”�e…•’–©¡ œ„ƒei 0sƒ™Ú›q^6˜Uqôd0£Ýâ¾7˜•Ñx˜©ù¿fƒYA½•ž f cG#‚¼,î€YÂüH‹`†f Ê<ÌÔ« ï}ƒXpÌpÇ34càG"˜¡ŽT˜•'ÑE0Ãã `†þ‘:µˆezjgÄ2é(¥· ËðøRÀ2fŽ! d§GoÀÇ,ãn•�8¾û£¯%Žç쯴_Â=Yjá —l #š¬G#"dÀ�ì^?ûÉÁ<ý]–ˆÌ ‚¼9CËÂ3N7êÕÈ•…ùu?�!¬ø�'K’‚Ž3Ûðf°9ÆV|œoÔ´³×ÿá%p†õCm^|�ÌZsyZðÿÐ=hñxõ­T¾ÂÆà³àô ¯>Hei³:œ|;¨s‘fD>´lXWÏ@ú*œY2$^EÁÙVœEÉ�Æ w&${¡–lI†žm–ÏÑ8â5(r!NÑÛõêCyXÓ.è�ó¥0%…+JõQÕË*ìÖ¨¶Àñ%ŒÝÙ]m}äè¦Ú��Ð9è{Y5ô¼X„G7¬17t$ÕY[¿4Æ+z°d83\�B·Ñ±Êx¬LÚ1/A‘‹Ýîļ‚Ùk±µƒã`�ÿCŸ˜P ·Û®éÄUãÕ!x7pgp $çUge²¼Þžâ½9„p z�èq3hVíŸÞRCP¼$ÏxµÒ—jrçm@x³‡Ý‡Ñœî�þ$;ÝÛwðf‰4õÎDë¬Ò7tõ ƒí\é*ïvë¨ã±k€é`‚0G‘ hœp”òôí ñϰ Î aIBu~q¹Ój,LžPÄ�ëÈì–Bðœtô9'# ¤µöäwÞŒ¥Ñ (¾5ćˆŽ�¥�-õªÞ²¥;ãdÃÃÞB%���„Ò£q#gUX„5„Bßsœ¡Xr!”~šø Bq˜%]•�CH@(¶1È5ßõàd̃P©#ÍK¢žAJÝ�¨²ií¢¤F¢8Ó$B:ôúYˆJäSŒQ2µ| Šc3R"F=°¼0*�r‘#D=‰‡ä@»VO„¨ 70#D%°28° ­I”vD©_¼ñQà Bt *�¹�ß5kc¥é@”ZÛÂƆ¨‰Ì<§Q ìÎ:,ˆ‡Hoü T‹2€š‰§äà“:�aC Ÿ&Üþ¬ Ô ‰Æ Æh¬ä€J䈌P£9á”zÄêTn¨QyH>%ÒHfÀ§�BLžŸÀØ”ˆOoåÓƒO š�î½ði 0²ìÁ'°:9@¾ði Àô\: ™å  Ð�Gñ6TA®6@õžYÊ n}TÇñ¸ªØÓ†¨^ +Ò¢Àj‘ å4T¶D�BŠ[ß…²*䢤?ÆQwˆBmuöQR™äˆB‰åúQäÇÌQ­ «þ¢$w£±/ˆjð#Eˆ‡¦�BáSSµ ¤&ÀR( ¢™qj0‘<8…B,š"§:ÒƒS(袷ráÛƒS¨ ³àw`Ê( ¦˜æÅ”M6±6à7< «8jÛ)Þÿüµôn]ŒsÒ÷¾Äç×z…ýý[,Ò„Qz×';=£ŸÙr6«Ê ÒþÉKÉb5X¦f­,&žêÄùò”b²½@´²ÜÕ ù9jIÕÄWa#—Q3‚ÀAÊFvÔ$I;­.7A‡Bëœ,ƒ�jc¬€D«Ë�ÈÙÈëB™¥Z¤Ïiþ2½,‡Ê;žjr21|tšxMe÷IúH›Žšä�"¢Õä&‚@æ¡ð)–-Lâáh%ß‹~•=(zW9q°æ©«(÷€z5ŒÏfÏ” Nz=«* 2*)×ÕM›¾½*÷=K�ê\íôjÃ@Ñô€ä.@4<·µ%ÀÜ‚¢—åPxŸÕxzœ€Én‰›æHefµ6ï8¿âÞ�Š]<°~XY'Ðî¼ @ÞSVaŽLÔPQ»ôÑ3=FDE«Ë%c‚‘|hL±©#‘U–šCTÁ­)�ÑKÛ¼.—@3QžçÛ`F‹‡ÖïÕ ŸÀlo-PJF'#¡2;iÞg—¦×åõ P©­žÝpžÃ0ÑërÙgänÚ "½,â5n[Ю°0ŸÝ-`¢Wå²qÒ’ ëaéBµ ¨ÒVUäl‚oòÛæ�Š¥l^”ÉÌ*µÍÓDÁ€_0†ûÇb_´ìíh4­÷Mf…ÑlÔ6r_íÆçÃQ*24¬(¢7ë°èN�£7“�èU9ý-ÏÖòº)6oºˆUå@o²ožápÊgó´ê2z!¬q=~ï³ùP–¥Þ„³Á{G}Ãî�Ó�˜ˆVA‘D:ò‡Íu�¸iy[ÏöRú% ¦ Ÿü¦¿�H�’c™J‹D*0ìšl³]àõ<ô¤TôµHÔã…Sñ>éxj¾Õn÷¸6_- FˆŒ@SvßhkÅ�‘�(Á'ãy#Ÿ�/Ÿ;Dfܯ®÷±øH|F*#§(\ðÉxÞ� •ÙADŒÌ°_‘À;†kêÒƒä mðÉhÞHgà̭ć ™)�~ÒvI­QÚÀƒä ðÉxÞÈfpˆ­Ò…(yØÐÉØLï ~àArPH`tKÓFŸZ¬Ô•1ÎDeú�ƒé£ê®Q³d18ùƉ”qÄŽ(ùG 7¦j¡}–gD] ‚Ó¤3>} Bñnò€é@(#JÄg@(“_x@(gï;J$ÊÙû„@Ô`å­o!ï;Âg„ÜiƒPFÍFÓ!|Ö-€PFÎ>Ó!>±B9yÓသ;r§ B9Y×á€�O ”‘[<á"wÚ ”™£¤B Îr@(#ÕaбAF�ÔiƒPFÊÄ>Ó!W‹ ”‘z±Ï´@ˆ6šedpl°m‚¥#sÚ ”™ F*IÊÈ'ŸA~‰Ó!ýQá > n)’Æ B¹-ÓŒ Btƒ„2Rdö™6 #éB©6ûL„è•s!äìr�œ;r§BÓ»„È�¡†ÀDcƒ�0’Ž 4kµDc�Ç6çB�‡q@È^4‚Ðô¶Ã!¾wdO„¦µ6ÙG�# o;lâG‰ìé€Ð&€¶AˆOÙÓ¡aÓŠ„ø`‘<ÞuØ ¤„ ÃBÃÛ „윥B¢$|,âqÕXù€Ð°¦ B<óÐ�; „IMBÙ!ÚŽÞw¡><»Z DÌ%‚aD˜BfÊ„ú*P-â„òl„ú*t-2Ï’#õU0[ D…$á€f]ÉÃ_ D/W%‚P_õ»Bt– Çò2à!:Ý|ƒ�W „Ìs§„¬$¹A(Aå-­Bœþ= dsh+Ẵ&ôp”H1ÌGéðË|-A[—óÜ.¥äOë40-Œ/ëëïmL0ƒ¤‘]‘€:<˜°Qý,8OßÉcï̼Ò"+ —®hI=N2À ”%^k„éedë;É£RL¼Êaœ�˜ÉŠ�s± 0+%Vèóš"F’¡F€ÖŸ§ M<óZd$ÓÈߺ“  `ÄÔk,®Riè@�·z“2Yêe1¸ ‡°.†„’˜w¥5Áˆ®#ô 0£`y¦¤,ïò ÆŒ®cëäê;ÃcRL¼Š32†ŸÕ`ÐÝ)“bâU�© `0p×0E§@ æ(î.n£�ã¦X<ýè–~ЇóPÄ‹ðYhM +ò™Ô¨´aYLû3ñJNTÈ äb.S â¬vË>@ÖÉÌOfù°Dç`LŠl}�êLb!1ͯ˜R0»Â˜Yÿ`ÕY4Ÿ™æ7Ž�ØûiÉ3/ã*dŒ=‡8=âMÖj‰×p®BÆÜðŒÓ#N2°ü‘à´x¾3Ëoœ)ò[zë’ãašß8>b×$K@@oµ[¡8Íñ‘iE(§ë‹“2ˆáúR˜S°Ò.椈VÕ¹ ôr  ÜYµJŸ)ºYçôˆ]Ñ-ÿ@¡ÏîcÔá‹aY5æ]Ó™ „y‰0;Öw9Q!ƒwtÅ�‚3\ºÓ/Äïì}`4§G¬4)ÉÓ.Ô͘PüÅŒ‚!ØÄ*�êL"3ÍïœqÞŽ)â4WîÍã4d1 à¯-ïr¢BÆÐÉú}1 à÷W‘ÏîSÐCåôH^ø�øüÖäJD4³ÁéüԜ~áŠÄózÚ§G ‡äñÄ«Y« SÝ(uLyˆ»yÕ‰ Ó#ùÛ` “ð:,ïjÎTȈä´£2k¡ŽÒ+äÁyë¨ ‚ÇÁ鑾ОyZb&žÔhg“ã#cE –wu«(fÔ*1yVXâeìQ-óÊ>Ê•Qñl…lýé݇Ì�"à·’¢‘Q8íè.a|Ä‚%dZÅä‹ìÎQÕó69?âÔ<›¿Õî± š{O (–Põ+9¢Ø¦K¨êA (†å=K¨B‚Ê~Pl‚�3Š©�öˆahí•0Œ y�ꆡï0Œ,ûž. 39؃a êS@,`º0)`XJÃõΆ�ðÔ†™¤ïNú^P-ñ.^Fù"N•µ#Gøî�¾’(†_05å%F˜=D²øÒ4KøÝ÷.S¦ðª§qX�\–?Ñÿ·_çìüõ´Ü ý`’õs±ñ½ŒL 3g¨ãÚ4asÙ÷ÇflYÒ­6s†ÊãîO³´i³º.xÒ?ÆZ»œFG@³á1Å3áôà¬&×@zŒÒ1œº*š&” µT»J×PVÆ(²üB`µqB4ï­êÂÇ”MCˆÊîX'WÃæ¡'>:C‰yx¼¹8ŒM—´Z§fmΛ‘@îHelÊ`’ÓWˆ:ÄºÓ 64&ƒ¬�/ùµF}ÜúØ�}1.K²añO&Þܨý׬)*¼ãYüÆ!І©3DQÓÃM#ÖÀ$Ši'v_�A>ŇŒ�Ëj’òAÀð|L( Ìa2¸Äé�kaî¬ Ä|6J!ÿñ;‡Ð%ä2Eb>“¥1¬~ç|Æ~D®¢‰±ÄO§c¤T›:{(CK%оK,"­$„4*㸄+üô�¦þGµ8ôû† «‘åCí�œü¾‘kaè̺õŸ�,$L]E×ô䥙M󗤣«ö¸p*OŠh@]Â]”ª�ßiêÂiš 8qÆt µ“:™ öJ�%~b•Ý7êZœ2&ëa.Øü¾[çìU'±ÂKÌ,ñ:›kFvÓÄËK3ì0Ü9ØîÉfÎ@ôx¬ä�†‰€B&Æ”é QGÛÕ™AV#ãCüÆQ:,& *=a´™L(äyD©�§ #é+ ™0ÏCah1òQ¡” F?i0ön@#e®ú�S'O± tk#AÓ�Ò¦à4ðΑkqê,­>fz„É À—–^¥¹«[c¦§°Ú]Å2qk�$dK-„5~Æ&º‰r1¦íÈ5²€šlÂ-AT�1w†"³µ‘0Ó3˜ >~ë¨^Sì/y ê‰sÁ⺜¬H’@eog C@Ðø¬Æ0wo#a¢‡(º”Q�Z£ÂìݳÄ‚”£I–¢¬�Á3£„±1Æ?ã}»kt0mgÄ2†È¬ï3k°›&h’óÏ #íÁ›FöaòžhUôdÚ�Þ<ë,ð3‹1Ö//#N)àÞ¾ž ³¾ñN8÷|ð.Ok¼ƒ::ØÞåi톀wTïô·»:x‡Ê-°uã]Få—š\ï l:ÞåΈw©É�wyX+æà6bq„má]è礈wPbÇÛÆ;=ÕƒærðNs1ްm¼ËØ1ôHÄ;¨µc„mã�Ù¤ã:x÷LÝÛx§Æj¶pðîéÝ;x§ÁJÂ�¼{0ÁØÞ©ë R|À;ˆ¾c„mã�ž1,ÛxḬ́m¼SG6 7ÞAClïÔ!šÃ9x÷<Þ;x—êµ3à]‚|üsðNÝs»ðN=8qäà]n-h.¼S$ ¼S´0_¼ñ.ÍÊÙ½�wŠ9æÒ7Þ).ñâ�wòÓ„DÙªñ™¯yðN°².¼S”Ä[?x—ët Zx§X[�ܲðNáøÆ;j‚+²ñNÓm‡Í…wÔådã]®ÆÔ>xGÍÂ&ïr5Æ÷Á;îêæà]µnÿÁ; g8½ð®kàà–y€�sð®�Å~ðNƒ+ù€wÅÈðï( ‰±²ƒwÅHõï(.Ù{Ä;0-KxG‘Ê&üÞAé†ð®Ø°ÀÁ;nU‘ ïŠ l¼K=Ñ=¼›]8x§5Ý\À;éÓn¼£4éÌïÄf)ÞqULïÄ&2ÞÙlX‰x'6ÙqðÎFÌ"â ÇCâÙ Z‹ˆ'6erÏÞRD<›U9ˆÇ¹¹§Gij‰—ƒx6~'âÙäÌAiN[Cd…»>|R„µHB ;v�ïðI‡UHåñ¿SM­ðJfSød.Þ"+ TnB)Âu1*ÏÊL×`óIóS÷¤/öB+îæ“"u@ ÔñÆÊ©-2J§•@æ™ÞùÐËg$”În"ð€o|ˆi>B) ·ÈA�;”Õ´#6—GP¦òÉX«®\I$ó ÉHB<Öù`Ѻ2�  ]Š‘y’¯C³èr“y…m$¡ë|°€Þ™GžjŠó óXëÑÕ \ý¸¬R .�mAÀÔØS—GÌI€Èã�¹ba·yÕ~jŸtgneVTÖ^DAÓ€Û"Ò^HÖ»+t;“ç Ò?œm}ÄF ú˜²‰#�¾±±ÒÖ…@HZ@ �„ î�K±Æ¹HP¹@§á b) ›ô½Xª´ˆ?è� 7Úø#B§áà"©ðG0!ÔÃ<㨠ô±¬ð�²Â�?z§•¼7þ �¢°ÉÂ=ÒüÄþ ’BV¸ñ'£T•.üA(Ea“…?܉�‚ûÁtÄ l²ñ'cB(l›údÁÔŒøƒ¡FJQØdãôq¸$eãB)d… ³SJÄŸlIBÀŸÑ¹Bëà8¾H þ 6I¯�? ù")<øƒ'E¼6þ  ú\ø¢gÔ}SæàtŒ¸efãO²$!àä�êŒøž/Òƒ?}&_h³ðD_J›lü�8Sœh ÏyáÆ£¹:gãh¾9àO/¶ñæŒ3Ìn3Ü:¹�×<à ”ü�hn; 4´aÊ&  }EÍç3ÏP l ¡U.üÉIáÁŸFêä5Ð�‰²Ð}À}üË7GüAƒKŽ•_�uþ yÅ禒¢{…¤ðàz`açËŒ@þ ‘vqIQ7CNxðªi%â)¾È þ@}�5ÐÍ%EO.ü©­z-u‘IY L*©»‘LŠª""ûƒ?•àH&EÃIáÁ´=Y(ÝdRT8‘üAûôâ’rI¹ðgÚÖªÃ%e½õB ²£7•”{RÚ�@Í jSIYûM‘ªý†Kz¥\aoY«iÏô];ËÞùÁ×Ò³u9NÁÈ+9×g[Y£ÀÙU ÷Iâeÿ Ëñ-Jü}½ Ë,NtÛFø¸¬K†‰sØOÖ5£ûÞ´ÄH�e((Á¯EÕ•gK�o±¥PÖá°_ZÇ™;êÞÆÄH�coåig àaê"´?9gýžuœ¹B¡¬�M Ô+ç,Êà峇‰cÚÀc‡™ òÞêÄ8]lÜ/¯ÃÌ Èb -b‘ïé7nu²ÃŒJ©áž˜ rFU‡ã~Ï:Ì\¢ÀmÝd�3ª:˜÷ö�„{æ^ÅÎu+‹—–ÀØÅ�ÏþL+6ï'ë@s�Bߤ¬sê­²–ê³,ÖËϦ,Âî@¶�¿äúÙ™«ÚÞ2Å`�sÌ�ƒ·Ý—«ó²¸êuFEÃ~¬ÛÍV¼ú*†ê•Ã~Å©ð\%Ì]Ž&,ÂH�#o\BåÃBF–ð=U¸¤‰Íúebà…n˜—=Pç”8×T�„KÒ^e…kf²Q¿g‰1p‹QÏe¯Â3€iÖñ�œE�-ÓÁ™Mxh<Ù@æ VTë«× Û¦+q^V7OuÅk�Eˆ€:F#á…l ÷X¬ß² ú%È\ Ð÷Æ,éìÁw6J¬®˜Œ¨SLV×LV lc–Õ0…|¶µU‹¡z±I?ñnHæ ]qÍk�Qï<Ã뜶ÖÖ6oá›ôËÎÿçåLÁ¯aÚÏ›À¤p§yÕõñ­¿bÈ›à¬ßãZ ™;šÁžÝ:fj1ëÜ©E‰ëq}….,XÀ™$™;€D6Þð {É„£~Ùµ³3W(Ì½å —$vá!äfJ ™K(ù%.� ³à¨Ÿï×ÉÜ¢Ð÷&0\RXÍíÞ´2·($=»q˜&ý°ŠÇŽ(×(Ô½- ×ôb“~B}\\“HÆk6Š‚K† ˆÔîKU¹D¡¬…bzj9é—|Ï)W(p€bXCI`ôÃJ±î� ãúÚ1\#¾ßþyÖØn<ÅV]óú ”ä%E”ªT9(%H7r¿PJ†M.”¤a ‹d6n¾QJ˜n̈RÒ9 ¸PJ�pŒ ¥ìcp£” áè¥�3´ˆRBI³Pªr ÑA)AºQrD)$0Ü(%H7òˆ(…ÖçJ Ò 8œƒRh¡ap£”0ݘ¥�–qp¡” ßJ[Ú~PJ�oôQ ib‹(%È7A ¥�mr p¡” ß �m”BÖŠ�À�R„cD”B¿“� ¥9f£Ú¦˜\(¥©¿D”BŽiÀ�R‚|ÃÄ“J!™¥ù9ž¥PÀ”ÁB)AºAÚ(…Ò‡¥Ù�l£ ˜Ü(%Ì6fD)4·9 ¸Q ùf¡Ù·˜Á8(5m¹£Tƾƒy¡’ [~l(•±6aD”b�>”ÊØ¾€!ƒƒRìõ�€R è�Mn”rÊÀA)2o1 xPÊ™¥H½ÅèÄA)2"J‘zËQÀ�R˜(|R@©Œ-óB)²)úA©Œ]Ü(圌ƒR+70 xPʹ¥4‚K6 ¸QÊ9"¥4Zäd@)äPŠô[Ì”"c¥”"ý6E”râËA©Œµ&˜<(嚃RËQ8 ¸PÊy8¥2V¬`ð ù<3 TFi£€¥È Š(•Qaä(àF)c”"7G”rŽÒF)òo9 ¸QʘN¥2¶Ø`0 T·íw¥2¶áp‘ÎA)c^”bŠ·S6_2½VSWùÁÅÔïýèkiÞú…Ͼ|¯¥¶6ÖYL Åÿ�êAÎ=Ÿu¸“󤃢�sçèà\•ªìk,ŠbUM=s÷Û&˃¢XyÃÙÁNÕUþâóò E±:gœ­ºŸm6¦ˆ¢XÀ3mÁžñ7¡£ÐsO{÷.ƒ.²Ü 1÷ì(ê�j_dyPjîr¶ó2ö·E–E±›ãƒ@Ñ챿É+mdÏmoðÅ%¾Êrƒ¨ {Æôà|^Wðß\ßÙ1T�<ϳä×ø*Ë�¡‚ä9„Zæ„íù ¨ sÎg 0c°Ú*Ìœ‡!¨—ðMk¨ s®gQ0Cÿîbc‡þÃFëJí¹ý äÎã,fèïâ^ D¹ó´ žÚ—±4ÂE…¹óY8ì5�4Œ rgà`Ô²=î?ˆ8*È�å,%öSéG¹3à8jUºê„å“í!yngq1K^FX> ’çA$õªF5ÂòN÷�9Ï³ÙØëoO‰ùHFì+µçöƒˆ¤‚ì9ŸíÇ^”ˆ¤‚ô™ÃƒuåöÍ Ë'ßCþ\φd/O¶ó=$ÐñÏÜPc¾‡zì5Ê ÿmìN÷�>O[@à%ºæ„å“îÁ={Ó²WnSÄQ�7Âô ,�Åîtå“ìÁÉYÆüÙêÈ¥ÅlΈÃ[k±;]ùd{È Û^ØLp3¾òÉö˜@OÃQ¯G;aùd{H gÙK�?[…ý‰@*pG¬>âÏJ=îü¤{pGù,~þlÉ1݃;âð ¬ÊÆpÊòÉ÷à�ê^ýÙúHé3Š©=íÈ „åó=¦Ïg…4®qÆòÉ÷�?O_Cpš*ODÒ/¡J�ž¤ ªj±ÙÀUž ˉªdÚlà‚*Avr—%±ÉŒÃ� ªÙ Ë›ª°É p¶¡J˜žÌ«,9» .¨¤'¬9žºä€\Ý�*Av"WUrÞP%ÈMÈ<=eÉZm>pA•€úÜeIô9{€*a~2b‡5fœt¨ä']b¾‡5f\P%ÌOfL÷°Æ¬–U‚¥D¨ÊØ TT ò“X’¤úO P%ÈNR‹É‡ª³�ÏU‘¤ÑP%LPFÌõ hÄÙÀzò{ãÛž|�ÊH3@•0C™1߃ÂR�P%ÈPJ„ª ¥&.¨d(’bÆGŧ J�¡¤«0 ‡ÀáÀvR|£Üž”�T#@•0E1åƒ�‡ËIñ�r{²>bõU‚ %æ|ÕŠP%ÈOH<ÝI´¹8Øw~_¬k’>J|õUÂ%–&3 €ó�õ$øÕ‡VÒGɱaPåµ�Ç·'é�‚ ª)ÊU h=@É D¼•óQF­¨"‚ã;çƒgÛÎñ}Šb§|ÔtëªHÈ šíŒŸ$'T‘ØAÞÄNù(17T S”S>HÕ�Usôª2ï8!¸¡ |cƒÈží2®Ä�*Ð^J¬Lf” 9!¸¡ ôÂÐÎù(ä7"TM¯ý�œ/["@Õ´bHú(y€j>¶ue|Ù¸¨†¯WÝ)$9 x€ÊJ¢!å£Rb¿€ÊJ«oR¾“À�„�埽‰<¬!xï_IöÂå<µu§{þ�¯ ðëöB=½OP�ýEÖ>Áú˜÷�~‰u«N ¶Ðä¸�€Äf.ñ[ªÓ‚yô÷¨sh·ê´`½Æ}*ËÜ]¾T§óè=î# ó‘ :-˜GQušÌԃ괞©4§É¿”¼4§»‚RÜF@ò%‰7KsZ°r(Çm$²· 9-È™K\F 'ÖœèÖœ$Í5.#ÈÐWq� iîq¹—O\F HšGÔœ&÷2Åe¤9.# ûRâ2AÒœâ2²/KÔœfÍq'j\F È›K\F ¸h£<[sZ�7׸Œ CeyÄe‚¼¹Íi’/Ÿ°Œ@�5�¸Œ€ÜË—Óæ¸Œ€äK šÓ‚¬9Åeä^–¨9-L›Ã2ŽªÔ¸Œ@�7—°Œ@#l‹”¶æ´ o®Qs:CayÄe‚¼¹Íi²/Ÿ°Œ@�5�¸Œ€äË—³æ¸Œ€^I‚æ´ iNq�[‰ËIsŽËè$k\F HšK\F@WÛã2AÒ\£æt†¾òˆË„IsÔœ¦ßâ2AÒ<â2âGŠšÓ¬9.# 希@�7§¸Œ€xVâ2AÞœã2âb�Ëys ’ÓD×5ÇÏ�¬¹Æe‚:âˆË„Yó ’Óû 8-H™G\EÀ€!EÁiAÎ<ã*Æ9®"$Í)®"`øRâ*‚ÄvRmH¨|ëĶZ]�À¸ˆ@h{q�@t¥ÆEÂ%[$@»¥ÄEÂe]qAÆ6°ˆíü ��Þ)B‚Øî° úðS€á²½† c؈k„KÌ₌E`=®!îB ��Y´�kÄVªHÈØVâ±Õl2V�帆@¸á-®!ÈÔR„ᢸ¸† #Þ{â±…s2ôzF\C ¶¸.@B†îO�kÄàHÈ�ªq �ؽ 2D%®!ÛÆ !c˜H[éw !#2Oq �ØbÀ ¹Û@è�á‚Á  M#®!î)Œ��»Í§nH[w !w›rÝ� ¶11@Bî6+{ A¡Ñ¸rçÈí�Ã|†5¹ÙÔî�¡Àn\CÀ~ù×Uz$äf3Ĭù×°}ßã¡hp\C@@�k,þ×�JP"$EŒãRÿnH ̸†€Ô†Ô$†F„R$ž A¨Í×äj£ã“5®! cCc¸ B­è¸†€Ä�!c9l! {¤´ Ô­Ž[ÈB‘!!¥ ¤²¤~A‚ž©qm§)V1‹�0’-0ÝÛiŠUÞ"$4ãy];bBòf Kï&1ïüàkI̹œõ–~’ûf%1vÝIb²:Þ“Ä€r’lj¼“ï$FÌ¡†$DÅ;‰Á™;‰QñNb°ŠæNbÀF¾“¬´¹“ï$åw¦â�ÄÈ…Xä)†$‹ï$,Å;‰`ç•Ä€¥x%1Øt'1 )ÞI öÝI ˜ÈwS,$I HŠwƒiò;‰IñNb0M~'1`)ÞI 5ÞI XŠwS�µ^I XŠwƒ yw–â�Ä`CÞ�Ä€Š|'1Ø�“ð¯$Ãäwžâ�Ä`˜üNb@T¼’LŠÞI ˆŠwSg¿“ðï$ òbCšâ�Ä`?Þ•ÄÈãiëIb°/&1d*^I fɯ$†LÅ;‰Á0ù•Ä�©x%1˜ ¾’ï$¦YÎ DÅ;‰Ár¼+‰!QñNb°ïJb»?î$ûñ®$†LÅ;‰Á4ù•Ä�©x'1ÝÒÖˆXPÆ»’Œƒ_I ™ŠwÓ‘·¶ ±Æ|“Ä`EÞ•Ä ¤u%1X�w'1¨ŒÝI VäÝILf]o'1%¿“ÔÉï$£äwƒJß�Ä`þÿNbP1¼“˜ ?'‰Áú­;‰Áú­;‰Áú­;‰.8} ë·î$f¸àô�¬ßº“˜ašÓò“Þ$1Qº’Á¦å;‰�Ó•ÄèטÄ@Ñé$1‚Ý[wƒÝ[W#X¾u'1X¾“Áî­;‰Á4͕ĖoÝI pðJb8Xw'1Ð̺’ŽÖÝI ´·®$†£uw ¯+‰ìߺ“ìߺ’y,ª I p]I §ëî$¦yT{ ãuwƒ9¬+‰á|]Lb “v%1®»“¨­ÝIÌ´�6$1m»’ôÝI –oÝI ¶o]I voÝI Fë®$swÃ�ñ$`îîNb0[w%1P�½’n°¿’èÐÞI ›ÀW9Û+‰a/ùJb Š{'1ìI_I Ôuï$�í;‰ÁŒä�İA~AF-ï$†�ö+‰�jð�İa%1¾“6þ¯$"ÆwCÁ•Ä@ ùNbHD¸’ˆ*ßI ù 0{%1Ί� ¹½Ibœ] AR„ch\I Ô¦ï$†D�+‰�hõ�Ä8_$BB›ï$1!!y“Äh2¢ÿûÝwÐæ·¯ý?¿þüòç?ü‹_Á“¾|ü‡É~øÂ%ZˆhÀ�jõåãçò�¿ûí¯¿ýýïÿÇo¾{ù§?|û‡oÿôãÿüð‹�P~|ù=e¦-Ê£1¬nô qýÀOï„é]Õ£¼œäŠ¿ÃÈ»­ï>­ïPŸãGä×ú÷ß#q¶S¨Àm¹JxQíÁAsjü0™Læ! ÓyÅ@Ì´ºI`²0žI�„Š…nx[X1âžäUo=ç/”ËðbÀ4w�É®áUoâ-•9¼Þ’Í3AÈ(T£q™DeÉ¢¯ÐykTve`OÒ¦}*õeÑ/èQ|ƒ {8œãÙ©÷ξòpö培jr-lH »õ yÍþîû…•a’^’kÃ{ûÔŽY£Í SÁ"ßøµýîÜ<·Â’n¡Å˜z*…ô»õ>9:Žî|O¬¹´>Eò�WËaí … °)øSü¾X/—Cáø‘|Ͱû¤²}¶¾1‡°Am¨æÖ\�?» :Ôs‹b0ª–µöÍU“=ÛMãΘÁ]¯u Éöyâó l>!õ§D†6}Ý‚m¶A‡Ÿ A`¡h˜A*¶ÄŽZñÅØ͇̉qäg¯mpmôÛ)|nM¶P€ïÉT‡§5"¦1SL”d Ê9ÁcVB?ÛIÒ*{1Ý(ì„0©·µ]£.1‘ÒL© $¨¢~!Pl©å IÃô°@Æ…J8­bëo ˆÏIP� DÛ‰ÈÕGû3ÓÄ¥�yPê fIs‘äE!ßêÃÔ–CzåˆTks�ëÞƒwd»[ò,ʃä:ÿF@îf‚Y�ÐK™ø4ùć݇gL• ÔÕÂ0¿›ÒBQnÎ� ¿%ÐRÕ ¡¤Šˆü³mœ&A-§­æü±m[ÇÒÜ �Ø“µe{‚/þùk~`]Ì]#{·¦�žRmï� dú€Fu-,œyÌXùjÅç´ÑµÅ`:tz² &©šý§j³ð�ŠXPu”ײ·qs·ÁðÙóNµ+�5êZa*=ûâ‚aÓý°$°{rí=Ú�9ðap …ª�¦Žµ—µä᫲iÀ° 8Ÿµû¯³ûAú8Pn�Ôø¾Ù2ŒQŽAwúô/A¨�~€ï¶­ÉØâÔÑÇû�¿Âts}�.O\o5¦9ø<°Uqž|eoíFôævî¶™cèMu×;67D èpÐ0‡Cû¦Y T¡xÜÍÒ�löÊkáq«¤_COÙDÀžL6,lͤ·ÛpnuY«ÜÐÇÃÉ�P‡+ñº÷ƒx„ ›�©ñ"ˆp˜Ú5È}ä‚Ïäòq˜Û@¥n®ÕԽ݊vEaøˆÎ°oÁ†,}€†Ó RP�7耞Ë|ˆoÀbT §è ¥F52¤—çfßê;ÄÇ0~1ÄKºë€3بUØÎ(Ò ääZvàåéŸ�…m'Á0· y„°µÄ�á+°¦×ˆ›ûYú€mÕ6a!{Ëné%ÆŒ»¾ýÞ¾æ Öåôâa‰“}ãõl^µkÛÖVÍþl»m£‘»H� á>­¾Ü´”k1™>±Ë“ L9™;€RòȦÈ£Ü,nÜm`oð°ÐfÄUè{!bÀl’;(Ë4•ÃjYß™™+€vqsùàì'™ÃXÜR6ÏÂ-˜çt(M+†ˆÇrÜìEóÜ‚ëGÌ0 䮀[Ä\€ÙÄÝÑvQXĤ�»Œ�dÒ—&"�OAö+Ëp9§œ±KQuÜúÕÏ"¶azž.ŽÄ´AsWÀ�oͤCM†M²Œ}‚c¹.—£�ÊÒ½WD-½ùð�­±£�îíO·2yZ¾€ó²i¯šš¿¢ *àð»ÕUøm ï^—ÀÚ—‚4ÕîÏ@èÞÌÀºÖ ´ÄÝpá`7åZßÿ�™wB·Ü[\nXM%××.&ÐH÷^÷(B1imµ`½©¾`ó•÷DXo‚}vntñmú¾ ûîýÖ’ã&£Ÿµ){[ä½'»/FÜ—›²ßûÑ׬øüƒ’vìØ¾ ³yeÜ™�󟶜Åä‘ÐØ^?ûÅ´'}» DéXþĹYG¿c".ûCÊÍ1Ó}|�!uâ2õ4mþ6QKŽYuZ«á©ÜéË©Çì]|9#7¨ÅC ÓWÏÉjvÖµ1SvipE­ý�æ�UœuòQÖá6\?ÖÞÄåÁY'jß(>Y€>§ÕZžµIó±š wüš«/«9�×êJá°"RDßRM]5–�Ä„rùƤRíR!yVǽú.Rnù€ÄtÕ"Ê¡‘’Ý×òÏLéìÆm̶,¤‹  ×¥JY¡Ì¯K¢ŒEWx\l”dBEaŸ(£NkŠy |>ÕÚgmËŠ—EÂ(KKTL$Ù…¬ÒV(­klcÁµpE·ÍÚ=Î,yúÚ;;9iŒvÝýËFbésé°¢ã¡Ðν㦫WYæy=ûy õ¬]{mõì¼4VѨÈÔÎv™_ðôY;/4Úhém�1Ä� ¬�êK&�™¬Ì„êª2äÁšíƒ×nÄDôÇXÄL~ÆÄ" ¤”ÁA÷RñXg ±pÃ�BwàΘ¡�×â‘*bê‰~zGã°s3—J/¨‚Òâ½W´¤XþŒø€¦þõÙhî´ó6=LE–€¹F �ùt©98lû³øœËGÐÞn«u�q ÖëSö¼˜›E4Œ xšk%{Od”-ÝÌ­º…2m.Ëìý—Ú\ ›+AÔŽ) çÐlõ¤<¶"5çä Åç|�™·”æÜÚלÉ/T87ŽøðÞU_:’C ù¶MÿNl“%,¶ÌËr4øj÷¹Z·Xo*“L· pÏšÀL BcŒ‘ËÎäƒq[.ö쌣“wì¼ý篕\×Å|€[<‹eíµ]g¤³[‡ëÓ)ÎÌÅŸmì ýS¯gÙBg(»&×›.–зbó,ÿ!¡¯âíbJì¶ÇE´YŸcÕÕ|·Pgݼ…¸^7PvuÁýBus�m¯³Ê®O÷ƒÑ-£Ç°®ë�#9BqÊÕô¡uƪ³&J�Qå˜Vó”T›æ-²=u+ÏutT³sþm nºŽ;å‰ñ¦¦k½×dE=4Ú]2žå¹ŽíÒÕOÆt©×ÇÆ`Ò4aá†ÕÑÝÕé»åóÃçNXÔÎ܉vfY™Îƒ©À ¬<‡6œ'„P΢úÑcÕ9™ÉĽé,²ï �q–ÅÙñÙ—†sU¯1�^ÎÍTßW`㹬I¤ÇªsœÑi¾Á†x3÷oášdúºrrÎcªéð6a•L;—“GÓ7>غ nã%¦‹Ë'礷ìK�ÖÔX6Ñ[NS™' Pf7o‘}c�*'·\L$ÙPìíl¼ÆÔj9%æ“=Å&{ž²&ï²Í˜pͧˆºóŸ¸kŽ&I•YN¾ù Ö#Æéj\r¶DÑGbˆ¢èC® "J¢¿÷£¯9�õ ô}AŠÁ¾ ’èC®t�ƒDrÒ…LâRõŒÁð°f;cÈ$%Ë|E3RŽ•/dò�2óþ°pÛI2™Dž+ø¢ [ý¶“…Œ W¦' vªÛ2·“…ŒØ™Ù¯&ûh’…Ü,ð°dÁ´5+ÄN²�ÉÞ)ž,˜(Èà–¾�+ds²ç <°‰So'UÈäÜ$OìPØ�T!ƒOóLOìït®ý ©Þ¼ OL eÚ.Å�*�Ó£jÛiÉ×°]VÜB-Üc ÀŒ¸k8]ÐeµmmB#»Î¥³L„OÄ›„¶>šÚÈÃçulâA¬>ýÉ7CnÞ©Ká›Úyyx‹Ð–>wnø1~Éc%1î–u ðF5ÝJ"¤ë›™ê]fÑý“ïjî-²ö9é¬LoÚ"æÌIÖþ#ÿ�Yƒµp 7ÒH�8-i(Þ!$c ØŠát ÉëêΠÄr!3ÖZµ¤aÈZ4gŠþXfeý?+0i¨ÕwÚ™X¿�ðë£þÙ’†ÜÖö¼É-6Br±éXA…Êæ*™ZØB"³ý+ìN¶|VÝ0šùE¦Ñ~È5¼û£¯¹†ó Ÿm^y»û&h2�öÆ5¨—¼]ä8Õv Xrv»†iRÊÁ5è9¾]ø2—kÐñÆ5 \º]ƒ`ª,º´Ý®Aðþ£k¸¶Û5”Tn× po·kÀÔþåîív N1ºA {»†2çíîv 5÷Û5Üíjmo\Dàn×Py”Žk€{»]VÝ®îír Í|âq pn·khp‰—kw‰Û5`±ÒíàÛn×ÐmÙLp ðm·kíçr �:¼]C·1Á5À»]®;°n×ïv»°~n×÷v¹†a‹[‚k@‘êv Ã|bp ðn·k˜¶q%¸¸·/]C0óË5�žz‘ÉÂôþ{?úŠk¿@Vù\ƒ/ørÏîóšÝd2ð o ¶QöØd" ±5¨·jrã»5Èd*E«5¨Ñ”Éš¯Ö`F@ŠšÁn 6D¶Ðd6�°[ƒ‚�#¶™ Äæ À¡¥Ød2ÐcsPàÔJl2xbsPàÔzl2�Ø\<±9Èt Åæ À­Ilfä 36…n-6™äظµ›ƒÌJh ¼ZŠÍA¦=6^­Äæ ó�'4N­Çæ Ó‰ÍA�–ËšƒÌZl |š„æ`Fº9csPèÒbs�Ù@ÍA�O±9Èd Äæ À©¥Ød2ÐcsPàÕ°vf5™ <±9(ðj=6™ HlJÏíMkð²É{|mn^ß5¼ööŸ¿f¿ëbzáEöã—{hM¯8¶‹BÔnë ’Éeº~„mNû˜.ïÍ—ï­#Lýªcºüˆ|Ïß:Á…Ò¢ÇvùIW7^›ÞM”� Æ‹'Ö|{¡Ÿ`dŒ%Z/žÆÁ�Ç\³‹ºa._‘(Öo®Ã°"¹dÄ}ð)äÍúÖÃDgç´¡BŒóPªn5m(¨–½EÀ¤NãêÂÕü¡ZS«ë¨a _¥²zH‰}M¶Å¬Ñ 5�dû½�³Çºk6ˇ\_¥²»Y1£ŽéãƒzHö;Sð݃@¢ôúˆµ“¢×ܸºk¨Œ¬ž¡1…�îsçSsy35E£káŒp„tÓ¡»Ù×Ù‡E‹ÍÆâئvöjv[c ܶ¡·”\œ¼�Æ£mÌe7µØðC¶ál[dn‹²Þ¡s¿óƒãί}6âÑö öÍ¢w{t·ÞX«ýB&ÁUq¾7Mƒ|/SÁá´KåÀèêç@„ÔOu095Ãõµeõ…БO‡Ó¦x´¾¡†@/æ·¹Â*Pk!DpˆÇ$BÅwVA´ØHh£oçòiŽ÷K2¿� EÑmãÐä„ K35©Ówa£ûP¼¡ritå÷þê¿BFÅuh†hJá«„|Òè„PòE>\øÚ ¾ÒªXì’ÀÃ@GrAlå"éIÆêÌÎn„’&Z2”&ÂIâ¢f¸U$”É÷I“óE $ã s 3G§…¢ Â+�ƒ�Ö­¤, ­˜“1ã ç ®Éšž\½˜™É/$¤+1¡ŽMuF††�+…ÙÓ"RBµc÷X´à#9‰Û4P_„L0o0YŽQCëÁP=IIï'J&›"´–0õU…£}‹ µH´Î2è�™õå?4?­AMŒ™¨NÒ+iÚpŸ5º¹€--nµö�rÆúªÃúå”3­ÜÛé ¾ �¨Ü ùøÀ–hØžn[�gÙ=8÷>¤Px¦N· ý-Ç›C‹ï¤�ïýàÇ8‡ók>�sØÞÊ8~ÝN Á 8ƒëÓ0ÆæÖÉ¿¸dJ¦ãË™IO`>\$¤?21_óæ©…øÌ’'ò£¼y%—€H"2 ˆ�žr©ƒpPáRI ?\Ê”ô[ù#�þp©z¤ä³G¸S7ñÏNÉwEìñìúÃ¥ÆÁQ…K�# £ŸÉê”dödµZH¹•4Rv�ÙcÓ ü‡(“ÁQ…K&#�þ%0ôh×K#�üpÉ[$#£¼EšæÏœr’µeÍ)'p.YŠ„Úè%K‘A~¸$'J¬—äD~$ßr ¥ÚKN"cKm”ŠH(øF©ˆŒ2Ë%‘Èj83¿P¸$jÏ—ÄCNÅ„°ý£ÛØ›oþ©}˜_ Aã|“&Ôñh©ýýðÇöùU›±Ùäï–ÛûU‘Ë�ªäµÜž\à°Ü^ý·›ëIŽ›ë( ÷VzÚAØ œP’¼6Îà âÆy ü¾Ù&#¸¶Éë»)FpmŠOc¾ÝO.pÜŸf~³ã�¡ùµã]“™7ûÛiq{šýÍnvÚÁ½›ŸRÜ»N3¸÷®?òf§:ÍàÞ©þ´{a:­à^˜þÌ7ûÐi÷>ô”ï]ç Íï]穼ÙcNK¸÷˜§~ï(§!\;Êñ!]ûÇ>È{ÿx–7ËÅS�o—‹çöfqxjùÍâðœç›¥à åµ;ùy´Ì+²åiê�ùñžˆ]íXCçt8ÇÐ×sb;�ýXL�%6%�Ü|õ&¢W7“GC·øŠq[­‰Å6…–»7ššÉ•p¨Xá�ÿìÆ`ªfh*›<‡“ѯBðjC¢ÃË l7ŽíÜv‰àÕÇ;M� MnÃïòø*Ktù§C�-‚îs©ý‰¯©¤Hÿg˨¹Üë߈ç&óýi‘ ÖQp›vÖóŠIbç˜×ç$›é�`Î!rôÑã÷éN÷�À¼_ ©NàñéN*wA×7v_úÅ{~ÂXU‡±|Íâ³h�$>}¶éN„6­÷Øoã~Kù–é[�ôýÎ~LÑöüÚbço x±,º,ç»ï)±ÿ‚eÝ"¤�y³Â©b’áöXÀñnÂK_0¹QNlÊ�z;ŒÉ»?HªàxÚ›î;iî ±³TLá‘Èš‰lg¢žI¾gû1“ÿç±H7¢i]xÚašLîˉEË|L£­ìŠ #›&t Š©wVÓg,b®ÓÜÈÂÝÓ`f�N´ø”‹±M ù±Æp2)ð‹Lc›&ô ÄNS1�ï‹Lc›¢$cšdU °?±È$Û”…™Å;BfߊØlX*&d„Øôeq*àdÍ}×4!/+.0kÂÚ;!¹¯2 /~ß(Ï3ãÖšQMÌØhàT ®g$b£2™Æž�–{åyÄõˆDŒó–Œkš°k¥mRE!Ã×ù²É¸¦¬Éø>7v™ÇÙVŸ�jš�”%W86 j„"¦Ð’�kš�”³eÖlÿ³HÀ”êA§B²dæ0×Ù!Ÿ�kš�”=Þ�¾i�èȱ rM’211.馵†š /!Õ4aãHÛý„à Þ’Àù¼?7úþ�~Œ 9¿È9—À³oÜ® I´e-ƒ°ã‹üŒ“~2 [V§¯bü]jH!2Ú”¬v?¿ ÏÂ6y‘Ñídõ°z(M†p>9U€áD`·~~Q!…Èh‚‡Àl}i¼TËÙW Á=Œ¨Àl}³1T=)7>²t8ÖùEü͵?+… ^3K‡}àÌPõä\dÉÒa]'˜a‰9¡p#°\_˜J1‰€Þ5ÜL×OðSmÕøN"Ð e}àÙ'B0#fh…vK"’BòÅ©+‰@'”µÃ¶ŸÏÇ6´î,bšeásIƒÞü$(Á‘Àv�ˆ— Õγn‡…#¡éò î½YUÝYxÖ~uüyêQ® BP*–@ø¼˜$KÚWÁ­º¨Àh}Cx�F0\ 7ø²nX–Œn¶–vgÜó/‚$Â÷|$Jðy!( ‘ï•öÎnt¿ÞäÑŠ¯áQn£¸Y_Áöà‡?ÆúϯÚPÏ&‡s6jñ?íªÈÿÄî‹~må„VΈ«Î ýö\7¡¸sï­îó±úÁÞ¦Iåžk›æÿ#nʤþOX?†mãÚ‚ 1´ymÁ�ô®³áZD9n¸Ô“LvWX_ M£zíÈ~m§„6ÒˆÛ))sø\«')±WOª�ÝÖJR©éZ+ùÅ#¬ŒD[¶]+#±va\ë ±Êi^ë ŸNzWXõˆÎl¾V=¦'-ÁD÷!hÎÖk“#]õkK#±®-�Põ|® ŒÖº60&¤Zq»"z³·+bOX�›Ñ™m׿D¬$×ZDh{Ík-bîÉ*k�³ùZy˜§Ñ»ÎŽ(4fëµÎ�qòµª�êgתB ”ãn'teSÜ9?8âö6¡++ׂÁbqŽŒÙÖNtes‹tz‰—±bøÌG îrïüàÇ8†õk¤e/¿>stream xÚ+ä2T0B™œË¥ï™k®à’ÏÈJqŒ 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 xÚÝZ[�ã¶~ß_a *cE¼Ibû”twÚ4MÒîN�‡$›«+[Ž$ïfòë{.¤nÖì΢PŒÈCФÎõ;¿=ªÕËúÅ¿à/ mü‚›ÑŠ_ÞÁT�¬òئ©^ÝíW™\›Ä*ÍVw»Õ�ÑíZ›¨|¸4k•En½QFGæOë�6zYî×"�öŽO›¨{<»–gÖ{~ò„_.®íZ?éPt<öÞ k›èa-X hÂDEçv<éþqýóÝßá;6"‰­±|¸7]±]Ë$z»o¿,ZXAfyTŸøùæÍKnìë†ÝÁá*Ÿßfã/ ¬¨¬MkîËʵ›f·Ý�gOø“fqbD˜ü¾nÞVu±»� ríäV}¤³n̵VO�\¹=|·4IÔÕülʇƒ'•'?tpeÃÍš˜³s¡»ççŒMe}ŠqÓ^‰>¿UveáÔ2ÅS#ß²X/ÔW¿vY’F?%&QÉOR¦:eJw¨/mqÚqoÛ8Bûyë¶0U0ñÞm‹ ³;�ÚcQUÜ<¹µ4Ñûj�•€7¼'¯„Ë‚8ËS½CÁö¶8qãW4*r{\fï¶]‰�wø‰õ³·‡a~¾þ⛘[w‡K{³´{�‹ðJÍÁ;ÜÛŠˆ¾cÇíûG~¢–Pãöû7¯þ¸�ô“ajƒÚ¶yKÌoN®ò«ÔÇãåTn?›„Ó²Ôà×sUŒÍ�³k@M�Åië ;šûлAº Ô|&Ôz¹·TP\xW?ðÃc500]ë ¼·hÖþÃ�öP“[îîJ/ІŒ[jŒGIáÙÃ&­÷{L˜à�=Ï£‡:4Py½}CwwiÊÓ·{3uÎ.¤Š­ø€™N¾43±±io¦(00Õ�7Lkc“ØéÑŒA‹r�ZTÂ'j™÷/â RlFŽ®CÑ›òÔ¹S;ÒTïm;e·¨õ©M€…5È_äž·*a5˜h"+çg¡½Ö`güJYU%º;ì诿œÌgsÅæ>¶ŠÆ-¤qg²M²1 |áì¸ÍžÛªSi• ªÚox|¬:6ñ›bëPTûÉ®©7I¯>½¸A€à0³D % P¾^oR½‚ÿ"ú‚Ú/„ïä: ïôjI»¼÷lØïú}‰p_lß>4õ…¾ോ¯g­±Vv®ÕŽm¢�m°%Á`p[ÄG´•š©ýDàëŽÔ;´ ðS%h\¿TÑRƒ×ÊÖ/ƒ¬\Ûûƒ;áëô¯‹�FkôHa�€¥DÊE*�Š^8Ÿ«’ýTXndÐWºBÎS)TqRØš„ Å ÂÀ«ïn×yÝpÝ(O6ïß/øÑ>ž¶‡¦>AØYЃ$–zÆ÷g*C'ƒùO†¦XSnÜ|¨É›A‹„…O4aA'è4ÑOu7Ì&�í”ÓƒNËxÅB»D©Kï§yè\ÐáLPKˆ:ÈE¢U[s+0�'a—·³¿ŽØu·VÈ3m¡Å}{½À> Ðä×ìð_¨YÍqËXÝúÈ ”¶üÍÅÌ'•Ä)…kðæ´:i¿†“M¢ fQ�‰ˆçâƒàÔÓgƇ�@‹NgšEaY§„+L „ÚüíåKn°mäÁVåCy_¹?#1ïg½á–÷�nˆ€ÑB,ŒùßÙ¸ªè&�E*yÍœJÇ�Á`I¦ –"¬“æ3Ü`xn*à "P^8Gé1¼�±a =¶¯,N!†zv£ÌØ ëðîe‚ÑÁ¬"UG臨ŸøŠ$š«<Îólªóç Ù§b‰‚Šß¡C*î !Y+i}=8Øzµ€S�®K¦&èÁwç®×æTM´t�oW;ò̴ѱnSÂÇç}*d}º”Oõ Èħ8I$Ÿ-mK~]K)ó6ç=H!îb£ŸÃš‰“àËÏs¤í™“ËÔ›&Í+ñ-E+•iþÂL‡¯É ñ)oú„j¤" ÈÏö tw•S^k•Êb!{×îã m¢tÎMàž†P Òør-ŠÀÙ'ÈÌ'‹r„B'§Íe,’„¶ÅÑ-…gzl|ÑÔBäñÛZðÛ»]‰ÚRTþ̉,£¦Z"eù[Ð,â94Nr‚Ñ1¡}_v�,A&°16�þo€Ïñî§ÅŒ Tƒt–D÷˜Ø\aFѲÛõÉ (‹Ã|WC·ì‰3HwókG¬ä¢'Îa+kçHÝ'Õ¸ ©O¥‘°¶™�T µ´O£ÜŽ»š3[6øHבïÁ6›¶&ÆÆÓžÈä|Ϋ£ã¥êÊså{½ÚÉŒ!6QOÎíD㌚ŸÎlYaI)¶> ¤®ZøJÆ©È>'ÛA‰ƒþ/¥˜“ÇFú<3›ä™JE/]å:·˜i¦àøµ [0¼…7æ %˜DH(a”2 AþÑôi³R!—€LIüú󧔉RÊD>‘RæÀ‘Ouçª' CžÄ™KŠÚò†>»š xÐ0Ÿ ô$¡ïHBüÿkúÿ=Ñÿ¹äó ø°þ¬7 e1daÂ÷´Ü·ôŸ7ûjDùzi5–ØG7¸íÏ.¼ÖMqæ¢×· 0¢±G)8aÒ"‹4?ú¼VC¾âŠí�{ Þ%›íWÞ©=.%’)Àñ_ð%�¥J¯€°JyðÜ×Uåž×½û¥“X é˜AžÉ?§¶·ZLÄqâL)8ÇÜÆ&›ùFÀèG�=ÙT.£1 }dRyÚÖGƒ¨íšG†Îe�ãSZlPòø�›/NeQÚè7î݉¥Éäör,»ö†óîêöp‚XºH§•:!wì¸9„vìá!ÄñÜ@¯Ó`Ôµ ÚL>Ï4õ°ÁF õWsm×�òe#]€çàÖ•Ü,y/),x¯Ù}ÞÇTÖ͆ äå=ºßn]S:;t&¢KOLºýM·Ÿ‹öï) t âpï ²8IÔ4“ô‰�°kŠS[QºLÝš­Õ_­! &ìê#·ß7eÿ&iy" ØsUoßò®ø•jvuXĉ;»²Ý^07‰ñ � k<¨ÀïJÒ�„KLøìÍçïÃè\/*àT2ì@±Þ<øbøkp¡?Ò'ýØ u èþA+Ξø]B\c«»¾°®€¡ 2m@¦É§WêõU¥>¬¸-y]ªWùä Ì�<ê“Õúô·Z? ó\­«ørµÞÚ8ͳqζ4ñÎ5Kµzk9/Õ_ÕÉ'ù®€wD‚ñÉĹF ¯²vn`5Ñb™ÕÆz£¡V† ¤üÕʰ;ËŠ‘¤bý¥ >'î}ã7™8ù�4ë<õ"ÃÕ\©1$ÈØ ²Î³§j®&.¤Or{~¥Î³Ÿ´Dl6µägjL_ì܃ê,á ß7ñPçßò^"T[ñ¥%'ÀqLÚ…-…åðm [fÿÇØòX”Õï†-ù¿�M ,ù\l™ª8·fŽ-q� bŒ-‘:Ã8ÃKGQ*HªÏUúå'6;c”Ézqy\‰¤qáÅ ¸’g?W^qúÓq%þlé ò ¶�Pö‰Ýmçê™ 6Åû5ýDuRŽÙÒ-òñ€¸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 xœmW TSgÚ¾1äÞ[TÒ;—„±­¶®h«bë.­¨ˆ€"‚Dö$ì!d%aýHØI„ û"Š+b¥Õº+jä;ÓmÚÒÎô»ü󟹧g朿çää$¹7ß}—çyÞçå`Ó0‡3Ó72Vœ°Ò["a¿¯ pè…ÓèE\€$¿LxðažUÜY`&Ìt8µ�Ò9ÑsçÂîÙÐ0ãr8ò¢ÓîRYj|dxD¢Ë»‡¼¿·|ùŠÿü²fãÆ�.¡©¿]qñ'D†K\–0’Å1RY¬X’ø‘‹;swLLä —ð˜TYD‚KHX˜8Œý›_HŒ8ÚeWdL¤L&Mvy×ý=—µ®®kV2oëöGƆ&%¸LEî²_ºÑÅÓÅ[žÿÿ¯`¶j»D*óˆÛ¿+aw➤�Cö†z¦žØ¶_|à¤W¸w¤�oô¡ØU®kÖ®[ï²Ám9†-Æ`^ØAìÌ[‚ù`K1_ì]ìöæ‡-Ãv`+0wl%ˆy`«°�ØjlæŠíÆÖ`{°÷±O°°u˜'¶Û�ÍÆæbNû6ã`Θ›‰­fj�9`bì ç-Ný4Ñ43w1WÇýÑ!“Gñä¼ð`ÜJl">'—’Jrò ß7®Nß6½m†ãŒÜ� =F¹ôbªÐTšWH{‰2P„òà­Uùg‘Ja%üó•fÐF³ąs5æ@ÔÅ|,BbxªìMaV"°@c$L%¾ ܣػ[øŒ0S#µ¾iæ‰:;½ÖÎiü –Å…&ú8…þຠт¯—@'èôÝ? Î[ý-zS¤–R£7–£Eˆwl÷¶°“u]É"éå´{à>ùíùáûBæ,[©¨J…±ºfÚñS§Ç£0il?³„^D•ä�@ž-ÒMFà°Vë•Aò—(`&Á?VElËS—�ÏH¸†h�ªÓõNÿ+t€ïÀ9;_-ó Ž?,!2Œ‡’#Ô¾ \¶�:3ØÖÿh`+"7p›ûQï¶3B¶A6y;ý²]nsúeœÆ!g?ïÈ¡€»F½5“äÇÈa;Ið÷–áÁ[7Ú_�ïÁW±O}¯í¾‹8mh Q-Î_('žJÒÁvæþñª©¬¸{ìVZäáÓCÝ뚺áãþ’ƒšyBSÒ,šÊ½\U ½oÒNv§º1˜6:�¯„“ôf*¨!¶$Œ9yîrä€ÞFN·×~3t­þBŸyÀ'UéÁÄ5 €ÚrÂ׬/=$ý­–Ø�þD�„,µNŸ$�ÒÄ€ +M©ŽnL¾n3µ¹òèåpSÔ¦æ�ÍövÃ’&éÆçñéoàfJŠ ìxz �2<„Š2M9e ’„®"^«ÚâFÖBe"nÍRjUj…T” sŒÇí…… B¸‡Ú³Ý„¨Bg?c| ¨Õ-­ Å%¹E¹&`˱ä‚vÐemjh±[[ÁEИY«j&‘ar>Õbxž1È¿´¨Ãn C¼÷6öÕYz.Š à×Ô {kS½"¶BXaa¤�$"è@ȭ￲ØèŸÙZŽ�C5[Ë‘‰¥6JlJ)•œE¡°Ðù ËsKCs½­œ½êö¸Fq·[=[ÏFœNN<Ö—j:Í6ðgÀ0œ±lÄ ¦£›<¸çûO¡Ç({Yqœ;t|e@rH¸\‘±<‡µ* jfX[«á¬q§§ã뙉þwèή;«}yJ†éf£%¯ê¦üª’î:í.!:+ñq�¾”}$ø´?L¦d‰‰RiM¢½±¶¦ÑžX+aìÿU[R5�º#«�î�AÕOóø i†ÉxV¢V«`ì#²Å$¿¥üäÉâèÇA°"J“ƒ�ú| ƒ×ñåÐÓâuA2H ÷íXëy :ñ3(‚Wƒó=myærëÆÂgÙ ÌIÊŽ.}×H¼zöó ß[Èù¾hñPH¸J^ëé>×#o6E—ÇUx1xj.ÑëáÀ"Æ_M`Ôd6Ökµn¬Îžc,F¾ÊÂZŒâ«ÄAMj-šFÖáp oò&ž�¶ðêð:È©µA†�Skª›•ó‚qú\Š©[^) [JÕGD“ÉÌn—�íÎ:}µ•HÉ;ad�ß*€žtALYÆlc¶)[P¬3e€L2==C#”+¡ÄŠ›bl!—ÐJèçÜØpÿöpc±Àš_ndˆ\lEÇUxgnYP}ºJ¥a–PGgÚ�È2Š5ýÁ4A¬žÇŠR=aãü2ÿÙÇ¥!m¦À¸¹âE)£ªJÖNT$�¥Ì†G€ÝqZ¬ìÈÞ˜mÀÖÉΧ6ÚÙõóá”!|ÎÂ6f Ì` áÝ"Ðö/7Â-�ó¸õN§°®§¤Œ0"hcʰè2glz²/®�YØ-¦bva¯/I;"B…8¤Rúä2ň·~Feè$a+ŒÅ¥EE§k{+[ÙW±S„?à£Õz³ˆK´ÞyÊJ0LÂâLoKU? ¯WÉÜD(œÞzýAs“ÔJÄc�ê*Ð)€¡œöé–ƒþq S¯G6Á@ªró$3»¾¿œÙõ•ŒÇ4i«9pî�Tl|\Œät|cSý鯦¸úXv}UÕO8Õs꾃–ïX€¸Q¾ Dq2â �½§½qÞ§=øR¸z+ÛZ‡®u0«4œEÂWøG4O˜G�žcF£‰ƒ]Ö­ þ†Áˆs�;&z ™+å÷™"Ǹ°�{\y*Â\P–Ÿo¬*ªÌg tªD-b@”>1-]™®Êak×h%6奕‚ $ý=kßÀºöþeŒKKá"J]pÒ[�~ �‡› Ç«¯;Ÿ€§‚?yË÷pÒ‰“ÂèHe´ÂãT¦s×ßÚšïrôº÷†ÍA«6¬¡]è OCÏgOUµÓןqàÄ=.ü˜~NA¼äME¯œÓ‹”ɺÌdæ bq�Ž1 ¹ G�™Ÿ]ÜÜePw !qòÊ>ð.¹|ÿ¶Í)Š¢šXatmb)c…%*M¼ø|ÂãÑ —.ŠúÏ�ºž€òþ€‹Á}Þµhú)–M*;íÐÏ9û5ÌÿŠK{Ol£®;(ßá�°-^h>ø áýÞ€Žà« ÃÌD�3ö-Â7w|‰ˆàdƒØSÔ—CˆÁ5õ$ E�ÔØEw4M Û¿óýCßÀÕ—ŠíÕVÑ©Š¦’Vv|š˜'ê«é‡�8ô¡‰eÔ$Ž{¡¥•úÞ;U–k@cq8ù5ï#&󦢛p´; >ÙùJïú>a$öÒõÕÖp‡|áþéRÄùp�ë'6ÉßW ù¯¶1)f÷üeÏvCœ9rûg!ŒD Y_‘©oS×…ò“cÇ>Ùê?ô?Ÿ×ô �ŒPk‡ÂûÁ 9t®û³;½Á»¼¥Ç¼ÅÂÌl²²™ÝÕðèm4ÞæB#ì¤�ôc(E²ÛP¥·‘Ê>ÆSªi¿jè[�Ÿ™þrÆ™â™3_VÍœ…aÿb— 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œ}XiTSçºÞ1dïíPª`”¨M¬­Ú:kµBµâ€C•yT&ežç��$@€äK @ÂeTĹZ«8VÑŽzô´¥íé·9÷®»ƒ½÷¬»îY—Å`³¾ý½Ïû¼Ïó¼a`VÓ0ƒ1Ë#264yµ[|lpœå÷eÔBµhõ ¸ÚO8±À,&˜eÕ±È.Ôþ2Jß…{gcLc‡ì®ø„Œ¤Èðˆ”Åyºy¼råªýeúõ‡dü÷“ÅN¡É‘áq‹—Ñ?¤…ÆÄ'ĆƥŠŒ IM^<õòŇâ;/v O� Nú¿O0 Û¼#Î'~W‚Sâî¤=É{Sö¥~| Ä9ãØÁã‡B‡¹„»Eº{D{ÆÄzoútñf{‡�>^µfÝú Ÿlİ%ØaÌsÁ>Ä\±¥˜¶ sÇ–cØG˜'ö1æ…­Àvb«°]ØjÌsÂÖ`»±µØl¶[�íÃ>Áöc±M˜3ö)v;„Ùcó°ù³Ã8Øl:6{{›ƒÙ`¶Ø\Œ�ÙÓÈbVX(vŸÏ8=mõ´6æ{LµÕ4« «k,7Öü#¼‚`[ˆ§dy}:{º~úÏ3g<�é8Ó8kÁ,þ¬Wï Zj­ywý»âÙ3g‹gŸš>ç7››'6ÏlgØæÛþcîgs%s‡æŽ±·³Eì¯çùÍÓC�õD0AŸê}cÂËÈÐÈt£HMÝ´KÇÑñIÉ´L"ôWpøÐÏHø§—6•jÊ Ëxp: ðž•¥ ʼn@ÌI‚l/%ɇZb2êØ�€fH"3ËšÊ&Š}‘ñd :�1«æÁî«–�vž$OÕ–žä™º˜/x(”Pì—ýòIq3¿Jôwă ´Ñ­GžÞÏÍóÉ£+ ׂ -¨C}Çœ ?²ûZ|Ò·2 ˆ8 C(‹Tæ©Rb଑ð*é‚F�l´ƒËàþ›�L¥7 8423µÁÌhú–ÿÀ„*ˆ�æ¯_‰¸hÑËåÐÚ¼þò ÝÚWh./3ž=vy%záû¶«ëNãÅ ɿ \»ËµžX+î§~ëfÐ 3'0Ê›�SYi¸K6+H´&áªæ‚3 áB…I\±�¬Çóá¬I3¿—[š©ÞeAB±+S¼+�äS„5|A§½‰ñ`ŒY8æð}ja¹â2 S‰Ö޳梒\™ž[!Òç–²ÎPi>‘fŠ ŽKÝåÇû‰ÈU{¥†gºðév–kJT¥€¬/ò�†PxËåÎRš2çÿWIÉPȦ¯LH· Äô•—N]Y£1«H¸èÿ¹ònBù©Lê˜K× #ᨗ+ï‘0.%ž*+Ä¥ŸÑ/âÈj$&jS­Í¹kÐáÎ|šH·á-v|�%ÅåÙ¹ù¹@djiaŠ6¥0�[ݼw¹·{îωjK¯L1œÀèxŸ=�ã)\!ZW†ë ÔtE¶>zPª¨µPSÞØ�gZøèúÈ�³)'µóv#¾BT9=-�—š£Ö×Z8*î¦þìf´BœZü†9á ÿd#mþ(W›­v$ѧDôá„�hórˆÃC¯Ì?öŸáöŸ¹Öx ƒ³üÎðæ¸ŠÄúCd-ž ÃY©¸<=#3 È€° £(ÀpT@sïú-GA7nvá}¹çM(œ¾pv[w  õU}é¥Ò¶È†¨Y­ŒQšº¥”{$q�B“ËuÝ'�æÈå4$ù*…FAžGðÍÍA—ÏtÖ �àfêS…Y©€&j¼Îƒ]¿o=ât?l71þ‡ÃãLã<ØbÄ·IJ•wI‡‘7Ý£,éç–µ‰¿žP.„êžN÷°˜4¢>ñP®“©v�È C¯÷dªÓS§X¦o„²1Y\cÏ“�eçâ~ê­r�„¯Ñq-¿T|I$!@|®X,MH�‘ÄòxôÉ^|Œ–‰‰AE¹XåO¢BbëiŸ{]��ܾ>–=Q 8kjן+çLÑßb�·8ÓY#î —+F-7Wß/+}¦¡ïw–O<ÏÕËþ’G‰t3m2”‹ì’ÛeWg3ü ~ô Í8êЗl�X’+dJNy?z`(·IT—Údtäê~Î)ÆôººjSM�²PYÌS”(µ ˜ll­é>ÓçÉ=D 5ÙA¡©éâHE“Ϲ?ðjOõÐU®m™WaUzÏ“ º´­“~„ÖÒ²›+M“$‰²Ó²�W@¨®ôwÂé=ÿ²A8�½óÙWòµy ¤¦Äzø Ýh“ &T÷u%ßÑEvÐMÈÕKÔ;ß6Aú¶•mFb[¡D¯%áa¢¡úK8^Ø ’9@œ™§ÌR0ey#FÂ[%Ö­{ƒÄPcÝ Ëí›ÚÛ…#2–V¶R3¯3¾ƒéß1áê‰ÏÙ¹ê`QBö‘LN\6KH© @1 {´YÁ¼É "f,êh7§ÁàlǗ˹Fø¦s½¬ºÛ‡Ìõ2~5·5¦f/ØE"¦ÿ†)ñì¢~1YdZl¿íß*^qîd%áG–%"v¹ߦÎÖ(ÛI*–Pß++{T0åsqcÔUƒŠ§ç-á­YÂ<¥éá!<ßÀø½` ‰Ø�×@æ©îŠ–vnc­ÑÜ|™´þç;‚ÑOU�3'~·àä�£ÄI5RjòããOóôR5Mô„âýL�ƒ…š¢jÅo$µœ€“ƒ¬r–PwX“¾SDÙú—.ï*È,WLͼúniٽ©¢˜�/`:=Ã’v¦Ròž­àQ7hñDÈX�VU´€ì(‘…ðÐ:"´5AoqZb Ø– ¹£!s¸Ó4x’w€(ȇˇXhå6ÈɑȤ‚ôDY í=žÀw!ëÌèƒ §�xñhþKMY–‚m,Ò?ß–?ám)YÂÇŸä– 4ï“èb’MñYÈ‘�÷�òìî#ääÁ[ù"Â2àtí•T-®ù½¬òqñ”|ãZ!ÑΠ6@{¶¿cPÜà‚šâ.etæ´*®‘ð*ž}SÖ”ÔÛ~´Úø‚#¡‘GBœ€‰¸w7AâõèeˆõrÑ#¸Š­|²ý*¸ êâË6ZXÜNýg;ã$í%Û Î„ÿ1aÏFîhí«[×^pã�8ü;Úð}á":9ü÷Âã2Ïù«Íí+i�­À@F{ô¿–ÕÍ.™{Ò½³’I))^à(¨ oñˆú•Î|`Üü¦w�ìê;Ss�osÁ’Vlf@’¶�û–Qx—ö�ËÆæÎš2Y\·"±TVI§‚ªªÚöÀ†ÃÎÞ ‰¼Ä€ìpåÒ!ú)º…+¶Ë¤N–0_f 4R=¸OÂ[Кx› ª»áÙÆ/ãPh s´>�f—d©þÒŸœ,Çœ·´ÚJ ²Eö ŠJex Îëúê®´Ò@} zÅ� MÇú7šWÓ\©¤-Õ‰ÝX\Ü^;òá _D¤‹UêîÔL_‚×ëaTW¡™a¾…ÍL*вcwm#Ò€X“^œªµKÐ%&rͧµÎ ¡·¢x‰Éiéi~'-U.�ª—ö¦ïòNŒa¤×ÃÀ×÷5ôq;[*[A'¸v¤w‡±‹ì<ÕÉ% ˜N´5jÛó� 5è݆–ÆfC8 šrkÅ­$Ê™\À>™óX~�?žÈ wu<ŽXÜšúkK ݧy…ð%û²¹m ¥A[Á5FèÀ1Ò=>âèÁ�›¯-ñŸîÏxc|fÒðM,7²C5麸“(ÙAÛú gÁO /³#±)´Ç¾ÁOÍÖýÂY²íráæ)…/µ*_bX ³ÐUÜ„OúS/Øf½¶Î Zí›ÎçMŒ�¯TX¢ýî‘q›ç㟎ͷýªv”ð/ sJ,‡@"OƒÖz°DôD—ªËT%€S7• E„bG–lo>iûZM¬c'¤¤ÄÇÕ¤š›kjššRjâèÀ}^Üžj¢PO¤ÉæëPüë|ÛU”;Íù4ÜvQJžT*X(‚�–´=Q¦�Z Qq1ÁÀléw‡V.w�«-É,LIä¾Gw®?xZûrSðfÁªÁm��ªÒrÃB=¨Ì3æÐ'‰:{²»Bò»Ç¿=õ¸‰ìîò–\ îÉ‹½×NõòÃÛ¸-Ñå‰.t0�ÊèÔ›^,¦=ÕÇÈv(È,£«¦´:¾V jƒ¬Ãåpkò*.GÛXux-dTWBBM^˜ÌÇ•›²d›-ÒrŠx»¯11žŽ1‹çÁLž® ÖÐ^ÛÁ�Î\Œäjr5ù­L#¹dV–\Âå‹`œÔăϡÕÐË®©Î�V�7 ]J}ÈYY™âLzy´¶£ì‰Æ¬ž¥ÜY#Õ)‡-+SžÚ[*ÛC›B¡W•ªhWhÕ‰é51‘PzŠÅóèËièì†/Æ ³åÛ² &p•P¯ì&aÔZ]qq}m_e ûk"vóP,¡p“IÝ-r”b Ü�¸BA/¬…Ds_kÕ /U%ØóP8¡p‘ç¸ÊéŠ7‰êèB©tq`g¿²ÍÅ7ÑÕ“›q)²Ñ€ÄÌÍÈûDŽÚ‡)õqD™Fkù@¢¡DèÏCE„Â=SìA‹é?�¤¦‰wLŒÚ[P¥]ö\n•$€ty‚,ÍA?Ù!;øJQ˜U£Ôp²ªåF uµº *QŸ¸¤Ôe�ÜrÂÁn1jCR³rªò*�žjÊ‹ÏYò©‚OœË5dt¬†ž“'í 8�%¶À�“[Xü9,×™!‡ô%çuKwP—3 u‡ ¿ ž°¡^ 4*�¶ó{»¬bQz–œNþ(G $S*€(8ò…¶µ+'³— ‰°¡C`9¹òðö­éÂâšXnt]jI ãÅ’¤Ð�äÏî6ž;Ç;uªúxîòüÎö»Õ¢ÕSo6SVŒ“/aÁLÊmb;á2WþN„msA8@ ÀÆÆOú|;/$_£=mö‹¿A.dïz‚¦¦ç„:óáJh1¸¾�D!¨‹ýí™]4xÓŽÚý‰ç+¸öœÖl2ðª+ZJÚ,¦¡ß˜m¢î�2(öIwAË+³{nˆU‹#¿É—¬›8Œ˜XšºÝ„µÙføÁîQÿ•ǃù¶aE°>ßÖ n“Ïœ./CŒÏö­ÛoŒûc-×ö{İO‹Û³àãGûèMnÖÃ/ãÚ>�"Ñ;?’²ïy×…wr@À~GŸ‘7«{.ŸæžyÈÞ0>†É‘S=×o÷î9”²7ÐbOPÖGY™Í?1/§²¡UÙEãí3¿?¸ g¸�„ëàt4Íܰ -DÖw?ƒØÅÞŠžóÜ´1£U‰$¼ 'Ø =/KšŸ&¤£ÿ}8óRÅ•ê^¥©^ßÈoOmB[y´µO|hbœ~Á„§imÝá›vÔicÄr€¦4·cÅwK{üR‡¢K+ì¶\�oOM¾%½~”=m¼f¾ÖÜ~w„üëèÿ‚Ù‰v³GÏ4×w |ýmÛ/NpnØ›OÆCN'Öx·J„vOœ#ÌÛëöé·ƒe`I¦}Âáç˜ð]®–ÉMÂßmຮù¶AÏÐûì['N]Wȳ]É)‘\Ûêè~Gq±JUĵ Rª€j¡¶HžæFW¢‘B&ãd2áœ_رIIÑqõIM- uÍ-‰ ±–OpÄ 6 Œº×°ì5Óåz€`aX¸«{("¦ê�v‘ƒî�ç’GÀ9ÐWÙÞ6r±’¾CÂàuð}4Ÿ›ŸÈ;E§ÐP¸xÓ¦À?áqy N{Á›’ð‰Ù4‘4š3æÁ&¾ ôÊÓ$õ†ÈV£}ëX´$êŠKY]"ŠæÑ‘Yá,;*-óPµ£ øã &ßcg†¹JsŽ(9(‡[¡Ó÷/»€ÇœŸ?{ø�‡wê±0nt¤(ZàT�k×ý÷¶Ö;€|>ì¶yëѵ›7ðÐäÊ’P ,¦BgƯØÀ¯‡Þ¥Í®†ÏØ—A­¢6ëzJ§;ØC~ê~`G|zq]—^Šô²*§Eô¥Þyð¸¡ç4o°§~ÜCÂ�ø–´~i�‘6ìÛƒõõhÛÃù¶/©(d/¥\qtkÒ•užD[Û_Â-ã8Úwƒ�rp˜_³¬Åå”—”ã�3žÍ¬/((ÔX¾fÍê,4èf½ƒaÿÂêäƒ 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 xœmX TS×Ö¾1äÞëD+é-DmB­U['´Z¡ÖªhT@ ƒ a&„Œ$Œ‡y !L2¢8"­UëˆÚVí<·´}=—wxÿÿŸ‹¯ë½µþ®•ÅJ¸7'ûÛ{ßþöå6S�7Ã;áBxïó Oâu‹X@ì!ÞÄ"b/ñáC¼Il&–®ÄRŸp#–[ˆåÄV‰ØF¬ ¶o;ˆUÄjÂ�x›ØEì&œ‰ˆY„!$^"âežà„ˆ˜ML%¦3 \†�x1¼¡)NSù‹øu6³m6‚8r*i$K}N¿BŸ›º{jËÔÿ�¦™ö`ºÛôá+gÍœ9óèÌÏm_p}¡öÅÍ/ÌZ0«|Ö;½ÐVø†0Gxï¥Å/õ¼ô ÎŒ2�_¦^Î}yÜ~½½Þ~˜Í²èÛ˾já�û˜™ƒùº²°{(�½î�L¢#š�h�&5 [$‡þf* Ùh­È¯,4JáT4‘½‹+bŠc�JâzŸZK¨ 5,c ­�FV�-›Lì싼ÇO Û~;�)Ê/Ë-´µTé/A¹ðÒª|3i% 3Q¾Ê ÐAÃÔ铵m€ª�|O‚¤pW+ü¸›Ž˜(ÿBM¢a õ]à𦑊�ÛÄ�(CžJ¸Ö;U4 i| Æã>þ&ƒÒää…ì*HJmJt( ±CðåÝOãûA­XL%m¹Ö\3º(§®gÕ(BÈC«Ð ´wå«™¾™ºÊLy¤”€:`2ï„Óá"‡ï‘c›M8PŠ@Jª.<'hs4\Θ)Ÿ"eYÐò†�pÜqý¡¥âÃN…ÎÊ®´ò𾂕_ña>Ä —�#1šóíhí~øCûåߣ—$jóäòbô ܶñHH}O’Dv.õcp›þþÔµÛb¤yœoáÁ›cüñ=P™œ<—S­ñ@—¡IS¢×P’Zã´UéÕ \j*K[ó @(ϥͨMN�ήTý‚^…öÈÛm¦À*�Î)¸l¦Væ©*ÀúPpLºúECíYÿørÕû[W–?N°>LL$‘éI©šd�”ùÊ"ÿ*¿’ýÀ8GîòÞ²Kº  )`Yóê³^Wv|#ý@øyðê'tJÍ&·÷¢œ�Èì±uyE~ Ÿ†ï} §Â×/�K:Ü#n�0ÉÌ;hœ5U­¨I�QºVÖöŠÝý'0ñ™½0£”}…)Í-¥€>Q¬Û/™£À>­Ö#�.PÀ Jx°†Ú˜«.ÐpÕ~´^×h8íh_‡/nùòÍ=�q{%£TzÞÞ¤0µ·BßÜÈ4w ÞÚ€hÄ÷ßèºß«£ùy®å�ìÓN¹Ùî÷1–„<{aîï�ÇW�zC-Œ”ÃN Òà�¶kÃ×/w~ ~_E=ô¾¸íâu W�êHá\9õÈPš6áûÇÚ˜–ò’Þg×SÃO‹îí] дCkÞÙïí©YèÚÒVÉ$öJU5ôºÊÚYíêŸÁÔ'öB%œ`×1£J�à“g-F6h>²ûhåw#NH�ö¤(Ýp\C ¨­¤¼+ô% �f¿×R›Ñg ˆÏTëô‰ò£šH bÊ’-MI×ÁG87çï=½Ört»Ø–…bØß K»0èŸÇì… ìwp##ý�^t é‚ ÅùÙå š†.£>&µÑ™®ƒÊÒp(S©U©2ý~æ2GZ‹ŠÅp‰» VY½‚>NfÁ×VR˜+§î¥U` =�£ß¢RnÆÑ»ÉÙNÊ>Ãú±ÎÂ{ð„_ÌÎf*óKs+}¼45P‚ò)àg0ìÔ`]0˜¨mù ¸DÃDªµÿLcQi†®\\¥*O7ºÞTmmK²„G'¸ùK¾¡2ò|CÕrÌÉóÀ ¯þÎ06¦2¥Y›¢\‹C� ½� }îß„>úŸÐ·PÀYË5„¶™©õªJp‡†ÑðuêP­¬x÷²HW«±°Ë,êZ»³× ËÇöÂ%ð&¼Ád¹-™��fÈÁJ"JºÕÒ ³AVnv~6-¼u] ×4]êª?×&V—'Å)t‰@¢lü@»)áÓ_ÉIJáØiæý9‡ÇøP ƒõÜ)/-ÆÙ"§F åZà:Y×5:Í:®®-fjc‘Úˆe‚Ãhßß]a=þîäCq`Ä˾S­ª´»ýnÅØªÙø3Ly@[>(�? •”°MA]˪Ð?i( ËP©´1‰‘š(@‰8Ñ'VÃGh�Š:�U©hTH½{Ú÷ngwUc£¸¿_àL Ý ²ÏX:ÊÏVŠ8ò˜Çm̱ždwÄ(Tš %  •ˆÑŸËhRÖ'v™=½t“¿{‚%¹®þ˜¥¶ §0§X’]šSŠéÆÖÚž¡Æè½âÝZ¶K¡’&&«ÂÁQZèë>xu ÷ع«b¡q_aMRïœàXE{¾„–c­ŠÌHKÒÄ«diI€“�è—à.éí€3èç#�÷âŸ]1nÏTä”�М]¡É 1!ÊÛmA«`0X^þIØ)§¦W¨�Û_l}—«]»™ZÇ™Š»4|Ÿj8ö�y6^pñ" Rd9@ &'ûˆ™Ú—«*sú©`¾ô‚7¯W•Ü,™‘i²¸­ìôx·žÀä/øpéø:&#/X£ß¯Eë©TQn(tOiZ°d¢ŠŠ|zô1tƒSàkð… ß-ÜíêŸ,ö±é>Õqîá™uÈñvºì;XwüßzÜÍþú\¢bØ�áfF!U%(aG¼Sœ½�ܬ.j—°Q¸]Yù¨CmÿoMþ¥ªr¶�: 7sÎ E?a¯Zx¬ Ó ÍQ’­Ui©™9éYÉ›¨ Q°(½2Ó8éLÅýy´ RQ ™ÕÚ$QŽC¾Þeõ« å<�2Á]¥ŠM”«@:HËÓÊ‹ Ü)ÉÉñG[ãúnœ†ó/Hà2v‰±µ¼¬>_ÄuØVÐÄ;>ÊgçA'&`Kh¼ �v>†ÔooÒaÔ†”IŠKd5)Ç€¨¡Ö\7¼åÔßäÐC¿@Ù6ð.�^~´ òOöTµtˆëÍ�Í—iÛÎüw_ðØìŽÞf?f&üpµ5Ï«�µys!ÖæçL½m4Þã:#€B±y(•Í 9ùi†Q6ÓoR`¾J¿§á4]Q~¥Ù…,˜8%¨$¹ªŸUì4+¯ñL~‡?ê¸ðœ ŠJÉÉY€Õcf³â‘ ÓíTˆR©’Ü"PèÎRÝ! r¢¤­1凱:R˰9�‡^º¿ N:!Ù‰)k �N›’§‹´³÷cø Ý{p~h¿�s@kIãÐÚqhßàhÊj¶ŽWÊ:ÍÆÊ²Ê‚.ŽÙ9Õ•U™iJ³¨JCÁ.}EM0¬\€6ÈÉ~P©ïÙOO좄¾‡v.%4²»1^®d·`t+¤:xìèÌlŠÞ ¼@PSô¥”.C[öU^%õ×uMq­QŽí~`Š4|ÿ¡7àB#ñ�Õ�úþþeHô‰ÑC¸„)x¢ó*¸ êeÆU£UìÿtðNà9´’|ø¯qgíAs±Á9°´Õé‚§dÄýË#_`ççBGxàçè§ÞW$î·Öt,Æ©¶ƒ)ü[–4x¨·&ïK‹SÄ%$„…LñÀÁš°–}ƒGÅnŒYì;Ew÷Õ^ôsŸ±°[y¿á2^ã(ñ8#æ–®c•ºèqUl…®Ðu暺ŽÀ†÷wùĈ•ÄêCsÖÒ.Ÿ¢$جոr[ŠÑ„ÕU[îÓ𴥞»ŒÚx†³�¿ŒÁTÎBFƒp€iÈ®ÎiÁ…²þú+­WÁG OÕÓtx`•u)îŠjRX�™¬/Óý5Šôº †çmün¾’Spa$›dÓX\Üç\Û?ÿM?D%«róÄ“¿ß²@ûãðhw¡•gý¦Ž6ZùìQÖ�é^O%cמ\œXâSS èe›\�Ü¥•ÈSRéG£ÕÉXL“*4½ÉnûbŽ‚Úçaà÷÷6ô�wµT·‚.pmߦ|Ä9øäÅ•‚*`iko,)Í)ÎÉælcNè=¦–Æ6«©œMuªV&f3m†ÇéC€þºMê¹á¼åÙ4PWlì;#)„ß2—­íƒ- Ѝ*qMXÅp„Þvàýàë?`¿²˜Ù߸\Ž�A5—ËÑñ…fFšŸ\}‚E7ŒÍm�­ æ>p ô«;c›¤½Î \>›HáI9u__¦ýkè4¹†oÆ _ˆ8¶l~ÔpLCWp5)ô�`Ÿ1Öò’8k$h©_Rp¨\| 6,}q6gUp×L7µ[àÌ1»‡coã‰þtå»åÞ%fzEž1·ˆê'ýª’®:íV®Ct&ê½B}÷k�²¾0‰‰IH�Éj¬MuµMÖ„ºhlÿÏ«:-,ê ·ØÝ~U¿Ú ç²{0'’ÈÌ­V�íÙZØVR1'*ŽF‡E¦ƒ}`íÀhãqGzîÐqi©º0 ÄÓÛýl^é~Úú‰Èf&¨%…îæÜŠJÓlá3Í|’²«Gß3R_>úíSïëÈá¶dÞHð¸@_ìëºv²OÚ.n‰¨Œ­òÀxr.±?õñ`1öÅã3‘E�·µZgNgOb‹Q 2r£äIP›R‡¦Ðõd:\/˜¸J¦£õ‚z²òêÌÐÐÏŸ8›xŸb§?ÎgpÞrËÝV¦�L$áÝ.+Ë•súj•œ{8w~»ºSнŸŸ™—•—•Ÿ%*Ñ姃 :--]#–+a´‰ Ì�4ŸEK¡�CSãí�® 6•ˆL•y˜È%&¤"»sÊ3� èÓT* ^·mXg*3Oª‰Ö{¦Š¢ôN”Øq3ï÷1ø¯> Ù ŒUT}Z†UUÉÙ‰ªD°oxØf�¦FÅìŒÜÜ€}Ì©”VC'·~Þ�4„�9CØ�·Àtl7Óè:…6}â×CÞýö›Ýâú¾ÒA0ú¼¥x?=áãõž)"Ës+rñ¬h-Sá 7–{Uj÷ œ­‰r/Д�‹4ûŽwŸBªÛªÀ+ºçð•s¼gO ;÷â›ÙyŒ1¿„{àÒPš AEÜÊ=9øŒ8å“§,Ý4l§@^IYqññºþêv@Ô†m‘ l&öhµ^\»&˜(¯\e5¸FÃBª¹¿­fЗjbœ%(”^z½§ß$3Q±yQyêÐ-‚‡(8íÈ•õž¾±ž{Å)—Â÷‚@ S9»Ó÷)Cž¯<\ë­ÙþÓMkŸiáýÓ™{„�çîÙŒ-ˆIé±:š…¾q@ð»ì´ڜ|QÚ±t3(õue¸G9u)§,íÄÚ6GÔŽæ³3 5™“Ï:j+‹Ïæã[²åÔÙ SJçR¸w℃‰Äöc-\5±V`"ŸÂÊ2+äÁSæså¥çËpÞóµœõ }<®©¥áxSKlC·†«Æíxõ?@ã\£;3Þ Xæ¹GŠ(€¦ÄkCSOíé <?΂þêŽö‘‹]�p& ƒ�à«È^œË<9‰G¼IW¯ü�a'!ÿ™äy럯¼�ƇÜØÛî$PQ…åy5ÅÕ˜ ÇJ•ÎÉÕ'¤¦)ÓTYÁ\›LÔ»¹©eà4ÍþÈÙPð€­»Çƒ_?ã³2ø £. ñR§"¤'á»ÐíËo»€‡¢_Þ}Í{_âáqD¸2Báv,á秎Ö[€~rÉkͺËÖ¬” ­ÈS ags§âÉüõ;xç‘ô޽ð\ ?c.ƒºìú´k‰Ý^`+½ÆkǦ˜äâúqT�¢˜s~JURXâÇ£�zOINõ6Œ€àlê©è–äZyE /n·Nï¼0û“�ÃËý¡â¨elâû¦L‡Þ»'Û>ôõ“�î¡Êи8IT”L¹-~R#,pá‡ì:‹<ùpý¨½ð[6ï믳ž�$º1á)Ø O µ”ð×Q¸vŒDÛ?d��„øçwU�ì¥G<8þ1¾Ç>f /Y òò‹»¾tH+V&é2’p–¤$â!6o9 [”Q�UÒÚcP÷Š!r~XD/Þ½q]²¢¸6JQ—P†×’h•&Nz*þþ“;�gÏHO»€;òA¿3�^uhÚ1.j••µä�ø|Åg½Æ72ˆÔyÊ7û"b½"š V5¾Õï×x!þv7/>ûŠáK›?AT`’Aê.i„‹¡ $àŠBÝ̳3®˜SŽìÞòÖÞïàò³%V‹Ir¬ª¥´�³2ùøõöî=»ój‚$=ÐÂj}ÿÍãE ‚Q$òŸøVp�„aãó&ób·µÚ ?ØrÊny?Àãö³óóùö>p“þÔõÊBÄ{g»ÓsôËÅÂ/á’¹mö›�¶Aœ1úÑobá( B3¿¢Sæ3w÷Õ‡‚=ôŽƒwlðùüÃÚ¾‘Sâ¡QfåHè ¦GNö~p³?p«—ì —Tœ‘@f—"¨ëgm¬¼æoø—hc¼h¾9ôûƒ«ðEçÐÐe9œŠ4}å4ÙÞyûªzÏ‹¡5ˆïˆ–ÄÒð2g@rfš6M¢ô†€ûpú¥ª+Ç$Õ–ãåM€þüäjô®{½ñùÞiÌ´Ó˜i›¢bC¸­ [8Édaç_¼ÞÐ�x.¢¢Êaí²ö˜ûñ7´À/àã§�׬ך;îŒÐÿ><ãw¡-̽ÓÍ �ƒ·?oÿÀ©¾òã[c‡NÇÖîkÕ¤:B²7Db›la},ÐÛB6O{:½¹dÆŒ§53fÄÿ¢‰I endstream endobj 175 0 obj <>/Font<>>>/Length 19438/Filter/FlateDecode>>stream xœ­}Û²l×mÝûùŠ~”ªÈ�y¿<*ÚQ¢‹MRåTÙy°%JLr¶d‰Q¹ü÷ÁÀZè³Ï Yfñ�»O¯î^—910€àÏ�ô’ ÿÙÿûúî?}9øî]üÛ»ú²¿|Ç÷_þí»Ùö£—õx}7Wzéüûý»¯ì€¿üáÝŸßeýÛþ÷Û×ÇþZ¾p=æãë߿ӟÈ�Ñ_š|:½´ÑÖãë×w?y¤Ÿ~ý¿ß}ñõ»¿ç�Ì´ïÁßø‘ïûÝõe>Æzé×Wç¾zít5þþ!_�^Êc�—q}uéñ»sšY¾öúz{ù~¡·—�ϵ—•;¢}–öÓ�”^ü�èËò#w?—ò²íGFÿ¬×§_iµú_Ñ—?àWZ‘ç�[~Iö#ù³ÔÖg}>ýÎÈÍÿ޾ü¿S·<”Ü÷K¾~g|6çü¬<=÷¯³ÀŸ?ú9ˆ�ÉO·â×÷ůΠì<Î�Ð?úIìö’žnÄ—_üì¿Ü'Qòv üóÇ>�RÒKª<‰ÿE‘�rß {ñ£ŸHë/ûéNü×?ÿú‹scßç€?ô3ƒ¿ŸnÅßüâ7_ý×s»·sôÅ�~²áÖ+â_üì«s'jÉÍ΂þØçP‹øÏwâ×_ʺˆVyWCLs-Þ¿«mÖÛ·Ç|êÜr±“Ký9Lö~™Óí!FxõQy¿úëë¿|ó—ÇŸ~ÿø›ßè½/kvù@~)òñßÉ}úæÏýæ»ÿûÝ?ýäýŸþ€#øå _-^KÁÁâ`è±å~ß~¼?î÷þé§ñÊdq"Æ�LEïË×ÿþ¯ß|w�Õã:|þóYä.ÊÙ Æ7ýâ|}ïÆ×–üRò¸GíoÿãOä¿üéçuoY[^Í_þô~ýßÞ5¹ òtìKä|‰ï¹ïV^ 0ÚæËVµÞ¸€�_†à'\•¡@xÕsêpb>ÏI®4»“3!7?¤ÿ˜p¦øw¿_R<·Òð;×)ÿ£þûçK>?ç’WC/ìœáç‚4b ÷£ÈOÐE“oû—þíÿùÃ_þô×?þî!·õ¯ßÓüøÃ»R&V}^|€Yî6ãã/ß¼û½,µ�¾ûø‡ÇßáßþMöBïi®|yÈñ3°tbpíÕûëÕP¯ð>Ö^+ÿRÓË–¿êć«PðÓ«Èñ#âè±ù+ÉmÈüq{“czãÇc–lTù8:­ª¹•U!�wË­ð¦KÍýEV_ž²°²ž¨œ…<Ý%‹©eÒš€›‚�5œ)Z´že1â[Âàše*‡xN›‡ÀL_wEoÄÛ—=d©Í.{pûËžŸâ/{m1Ó_ö”Å_³¿ì-ûfùËžxÛ_öz"vÑ_6Üòå/{‹qi%\¶¸ÉyœË.) {P÷eúß0µÿ‰øÕ»¼ºšèŠÝn«-Í·ßúĺ¼? no�ÙW{‘ÛZ\ƒ<î~õ­x�[^§ÄM‹ÏNZ8q|øé"$BžÇž›Æ>N*/I>2ä‰ÍÌcäFÊóØB;†ºAò´ò³Þ*¡‘~lYiuë1}½ ËŠå)‡Ô4ñ8–,4ñjyˆ01Ùì¹Ï†õ‰cÄ«h`hò†â«p�—Ԍɦ‘GŸÁ€+/jŠéØB„{–¥VU¬Õ”‹Jp®yQ+Ó(Õ%»xë÷`7'±HSwN£Eª]>™uÇ „DêÄ Ã1“©9ƒÂ/é`ï[L®’—´“\�ÐMü¯ñ9u1ä²Â7þ·ù[oïÊZlÛ¶”8¥³-«¬­¹ºÛ–r §tö%®0M·-å&ȃ8»²ÉÊ‚»qv¥ÜÊ yve“¥5êt»2Ëæ�‰<»²ÉâÚ¥¸]™A¯õæÚ®l²¸Šž�íJY ò šÛ•]WÓå`»Rš<‹âve—Õ5î”õ*ÏÂïJ¬é¤[Åv¥¬ûüÂPÔµ+‡,¯ª;×ve®Yàa¹]9d}�ÒÝ®”M(ð0ܶî|v¥ìdzAgWqȳ>mÛ–˜WªÛ—SX[n[f@ž^¸mKüÃmK1P²ŽÎ®„ Kmº]™�xÉïÊ%«³Ú^Ñ]™�x׺+¼Åß›gWf ÞènW¾·ÚÛ–b½Å�T·-—ì¸LÏáÚ–‚²œ‹Û–²jdql·-L’9\²~€Ý³7·+�ÄaÚnW³RÝnW ¨M¬ü°+§™Û•yÊÚ­ÃíJÙdr•ÙðÜ3`Y�¼¬]¦Y�*_¬ .ÛP½Üž^Å壩óYÈŠâ]ñW ›ÜÓ#©¼nXiEñ©ð[†ÜQù…¾Êkuñ[`£ ârÓÕ+û„ý ÞŸèþ‰…݆âCáW.R®& ® 4Î;Ü+Ƨ±„%÷SöxC˜­òÃF+ŒoE`YÆ{¼‚†6~O¯M#õ„_a¼v¸´ú%ÃÐ÷œ�rË ‚¦²íÆÔ/Ù†¦rÓi dOv씚àÓòAÁFÆeõÝTÙ›òLñmgkŠ‘¹Ì—mÍ*Ëq{Ò­)H~™/Û›Uîp62§{Sn„ÛÏÞlòœ1øÚ›r?+.îìÍÖÕq{Sž‹[ÜÞlò‹{·7åùʱÙíÍ&˯Ìéö¦`¹¨íöf—EÜu¿ØÞ”ÓŸÅïÍ.?¹lÿêÞ”U+Ç·7»l©¬öÄö¦¼’c›Û›CîzSëf{SöÜ·7‡ü¤ìX·9Ë÷ËÎnwùIeÞ¶9ÌM9{ô¸Œqö¦@9|·9Á²{ÏnsŠyivá¶9§üÞª~sŠ™‚Ïr6'8&_›S¬�ZÝæDì ©5±Ý)�.‹Û�ò3/Ã6¹îNAs‡Îæ\òƒ{úÍ)`>^òr›첨é·Í)` >Ët›\¼ˆ¯Í)˜R° lsnù½¥Æ6§Üá_ ·ÏûØœíb~o¼ñ‰=Ž4p_W¼æÆŒì{=æ~õ-óÅ/p?†¹± y‡³˜‹…9ÄæïC×v¼ `^ËPÿ(„ÅÖÃkU—¹­Ä˜øP4Ü8Fþ þÜ|ÆÚnÌå$À¯¡á¿ê¬É $ñíisÄ×ÙFÌŠ¬•(Î ˜Óªv),Ê-O “×ö:‰KSÃD²{ðÀ]è4w¨$àguÉ1ɸrðT%bÊD—©Û•ÃÒÒH“°ûÄ>€Ë¿Í¢�ˆ{ÐeR‚ƒ ‹€eFREtAÜI\&R2,|ìÙ�•…œ3Ýæ\ÿÉÌÜUnìY€ ÜÛbW^ã&{¶`ÓeúŒÏŒ&ßø¸ ¹e±f‹|Šžµð�¿¨Ã ]ü) !l_)Ïp@&øBQ†ˆ= P�•Ñ(�ü õòS±caGŠú�ŒñT\v3¢L{¼Xnì´Ënr'äKèÈòÙ²²fä�e�õÜŽj�‘¶æ«òË£ñĤĻ£«‹ÊýŠZÓ¾£·רÎÙÄ¥/ˆ}&É9à°T/Χ<âE€=µÅQp9;üt.Ò�p]äÄ­)vYø:~ i% �o9¨„`¦“ø Øw}4ËDÌ„`˜¸ÑE©‹ØáEÄéÈ<ñŒ§ü‹\ù&¡ÐcÄCâ«»Ïx\�ϽN1Nâ!áî ¤§4 'ÿ"®ðéà2›££$K°ÌÁîX2 œf#�ÊKš“„q“”è yg¹­[�V<„�«Þ²)2iq–EÌ«ò)½ê…ãzlžŠØs^öPZÁ¸#srϺ)Á®ÌËFÖ�þ…à¿Æ„ÒÅnÄwõw@=ø žOL§nâÉ¿ "p#^Ff!‡x™d÷ ž¸9$:ˆ—ä_€f7âÉÍ( lÄU*Þˆ'÷|7â�ç]oÄ£û†@ÒA<Ðòá> ƒ_7â%âeä †¼Të<€'‹Mïè¼éDq€—‘¦ªÅÞÞ“@wO0L#z7à!ö¸!V»OÖÃæ…߀‡¨Îãžx—=¼‚\μŒ„â�à!€‚€àðy³‘ Ä[¼ìñ&@²¥âeä›G<øêˆ•ÄËHñ×êo"Ù$ç ^M£“}!Þ@Qðí ^ÛKý â¿‹ƒxYÅíoôI´=€—k«¼ðð†ü ë^�Åžü;ã²ð2ˆp[ð†ü¼ˆxtºzÀ)’âeÐòìÑfø4ñ@ï“G¼ŽTLñÄMØÄëHB"ntO?œ‘ƒxYÙ;ñ²Õ!^GºS.Ð!^ÉŒÊÄëÈ.É®?ˆWO̯§BßÓ!ž)©nÄkHbXâÍÆ«¾‘o1ð:ƒŒðòex¼ðZçU߀×äzíð*š𘤺™äbÚébžâŸ¿™¦zë�O1Ïëpn£Küþza©)u§©(>‘ïWn·ç‡3,¢Ôš^ǦÅ�͉†\ýþácãpë«r‹ŸÓ­O°D@aÍãOÙJ…n‚r#(ââçpë³Ò‹±Óõ_ÀD»U30WWz�hÊyÌ*.ÆþJ»84Á0<=ÿ�ëÆ™«<æ•ì Ó’ÃEÎɇá_i¥I,TO׿,qâKéäÑä¯4åêúoª—cúPz`á|#¸$×€¸ºj.ÖL4äôI]ö1}8_ŽYMé�…ü™²–u÷@è]å@B²ƒLc®ž÷ÿW*}dË Ðõ‡Œñ�3W% €™ì Ðœó˜Ò|Vn}¦¾2tý.g¾•È!=€ B/]ÜŸ9€ë¿•Xv�®ÿ`åŠ<4¦ ÷ªt‘AéõKVò©…W:?ä–~ ãß`|qÞ*Ä¡p¤1W¿ùìëúb.C�cäáËuã´Íïo�ª´åê÷O— À!½ùóðP�"��� ��UZrõú»ObЫ/.ÏAÇ㲑rPÏ¾î »j€™Ës¼ªÏ|R!ôû'g­z)ºÞx’�vœÇh\òJ…ÐÄmŸ.¡ßϸ$Î[µY²À5†ÙÔŽã9ît ÓgTpÂ’æš5]Om´å‘×p©ÂgqÙ"�^–72)&¤+ð·�:Ř àÌeoæÉgxpŒÜyÙÓì!fEeðNvå4—áyÕ˜•˽W€gÈŠBE¡ë1+$g�’Ñ\j*éÎá€:}šTXj°ék§¦èE“¶©-Ÿ)Â1£ûlŽ‘[ .æÑ”U ûA:¯éá„ÈíÉ%½jÌÊå›pŒÜ€I`J&¿BÌj2Sp´g¼›—.»P.ÿžœå\ð€b¡ð @ŒÉàðð&À켂÷;€‡(Þ€Wð9Nàz^�fmOxULøv€'+ 3f~º¤xy/*Cà•Å$ú5‡wyË3Úï ëÚïdÓ^øÁ;„ùYˆsá�xŠ…É‚ƒwb–°ÛÞ‰ZLó¼«qðš#f‹ÞÉ>Å¥¼£—~ð.Ã7ÚïĶ^úÁ;yÆðÆ;1€™°ðäkݼO ý4íÜxÐà!Jzo®JÑÛ x e•ÅÞDŠ#^BRl9Àƒ$‡êºð’p~oÀ›²°á™ÀKB Š<ˆv¨ã»/ 3Hð&Öõr€ #B›7à�Má­¼„”ãô€'ö�5‘àí5IÌà fˆàm$@!>€'4Ÿ—}ÞnQ¢<胰½O¸6é¦C¼Q/üF<ÈÈ@Þâ ¬ëí5l ¿ñ:jM<âAl:#âõÅêÉñPÆ1°=ˆ×Q,;â-¡I õñ F‚Ãz#Þ‰Ù!^—u�dÊ…xK‡x,A¶z#Þ$A¤Â!^ÇÂÞñq„\Õ!^—…½<â!r‰¸‰C¼¶XpP"⵩rÃñ¦à …ŒôZ'ÿ= 7µ r u”J7è͆rÕìA¯UÖ5Лr/QWzc^û¸ñeÄyâ5YÙÐJ܈‡0õ¤RøFÀí4/ò‰?/ê©Çò‰hJq`¼gÓàò…ŃüÏa±XU¹¬@>Øéž|Ê+Œ3,†øoxò)?Aþç°xfÓ­í±6k{ò)f­k˜øÆbĽ²ÇâÔ·F›o,Fø¬,Nbn¼½°A¸êɧü´ð…ňåuO>å㙡ä‹'øŸçž¤‹¡Ô\ž{~×>X ˆÚž{ þ4 ßXŒ@göX,ÖG£Í7#ZZ<÷“Höç°Q×ê¹§üİÊù ‹—ò?‡Åâ1}p°b×á¹§8 �—~°º¿å¹'�޵<oe€‹K«*Ù¼°x+tXLùàðX¼•:,FÍjõX¼•:,†Â°,ÞÊ—Mè°x+KVþç ¸±—‚ƒâ’•ÿ9(†f2{(.�k”Å(»¨Š %“�|b 6O>KVþç ˜ªO>KVþç¡8“ÿÝP\ŠÒ¿Å¤Š v×nŠ«®¨5R Ÿ(ðÈŠ ä%�O*8ù,Êc ¶@> ) Cbª<ý,JcÎ@?«R@‡Ä”‚ú‰ýµ=ýTÕÝä“:Ð@>‡ ·ù„T£òi•—Ž|>ã]©u€×¨™rä³jlÕ°ž|V�ÑzÀÓ0®#ŸE‰¯¼‘È|ù,J}à!wÐù„P½ò‰ÜAs€'+ 3?s¹ƒx¬¶Éž|"u�=ù”õH⢭$¾ðJ!ñõÁÖLâ{O¶Çb~Æ[�’ž|²‚hò‰ôA÷ä³de¾ð�>hðX¬TùDú xòY²2_xHdO>Y•àÁ{Üž|ŠwY™©8€ýýòä³$¥¾ðZ"õ=€'§Aêëýî�õ^Í“Ï:I|à‰¡ŸLÏÀ«ƒ%aðXZV<àÕFÞ{OP‡¼×´þÛ‘Ï’”ø:À«™Ä÷Ë$ï=€·•ö:òYy¯¼MÞ뢭¥‘÷:ÀC`òäS*y¯¼­Ä×E[K&óu€·•ùºhkAð€·@}=÷”µJæëU�ÍsOùì`�ï¼ê¢­y�ù:À[ ¾>Ú*› WîJ‘ä¹§¬j_x¨4Ûž{"�úço�ù:î)f…y7xÌ×sO±<Ìß9À›d¾>Úš&‰¯SOO$ùÿüðK à)²ã�OQÏëxn¥qòžúBŽUÜÏëïoµ'âÀ¬ß´ä@Q&g1t%®lôa(�kÓDUî 4ËOõØkRõì€ÆýûÖ¼gºè ²æT1Áœèo)ûƒY½èLWÿ6Á*©[¯ôÆù¢3bŸÈäR5Õv"ýk¬51”ÈÁDª_ŸY7�”°²H 4_©®6¨Ÿ`#$\¦9È”]Ëî&ÚNJý˜öîÆèۢɊj¶“R?fÏ•Ë@&�«F^5ÛI©“ðúK"�ª¢eÒz„'‘òD._¹ÌÌZR‡ o>= Î)0.#€F8TŸ^yE&‹±žVOñ^!—Ïd¶BR8­¨À!Êû¨qPÛA NF *èõ³ˆžR µí�ÅÀ¥gA…ºôà}Â9µÅŒ²í<`tûµS”FfÄû ‰cA½~¿ÁúX=eЀ=­¨x¯EÏÈxBHbd !Ji÷ÕµD©)W\1³ùC¶¢ ªôIý(l±¸"K�-»ò¢Ü�ú‹+¢žà¨5ôèÁý¨²¹ÂŠl_’­¦‚5uÜë—AÉ54é…¥~Ðü\\f±S ™^xUêGí�qH€ŸpžÕ©WîG ’..HÍÈâK­­6YOH™Ìʧ uEÓ®~8²ž�D­[ù.a••’ûQX¥Æ:pè³ôÊ«r?ê³ŒË öšá3³î1Êý g¸�{Q‡à•ÖédîªÅôkh÷ʴˆð)O<@•Å@\Ȩ,™o´”ç’”^hIçs;´,èVCx¡%ÕÎ-e‰('P´¤bÓ- ºÙÔæÐ’ÊkdLo´6FJp£eFÚÓ- Þx´ÌH; cz¡%ËäpÑ7Zfd�0½Ð’Åv 7ZÒëÜ-e«+!¸Ñ’ÂväKo´,Mü-©�g¾ÔÐR¬ÎVþw¡%eöH—ÞhYÐX§8´‡“tù eA¯ð�-ec‘.´d¹‰ï…–²ƒI—Z²âŽ ÐÐ’5H—ÞhYП‡ ðBKÖ2 ]z£e©UùÀ�–¬‰@¾ôFËÂ&>-YZ�|é�–rߙb"I—Zvú-ø@—Z²àn‡–b±·–¯\hÉš;êû -Yw„酖æÊn´dý 2¦7Z6 Ú-Y3ªCKq²RÀ -YMƒ—- š �Üh)˜ÈýqÐRæÁZfT,‡–}‡vuh™Q°(·ë eA­ïÜ-Yl$÷ë eas¢æÐ’Kré7ZŠÇ¤œáÂKJHFuxYØ¿h8¼¤-Žo¼¯”5b/©h©/ {̓—ÔÅȇn¼”»·yÝ7^R^ƒœê�—…��¶ÃK–!}{ã¥xãY)à…—ÔúÈ:9xY’æænĤdÁÕ1ÅŠT%�bRzÔfRšRŠÃL*˜ê=˜ m äS7fR %î0=—vs˜IAÒ¥3·V;Ìd1!ã¸7fnTMz̤Àkn�™rÜì0“:±Ñf¢e:̤ެÔD)Ju¨©}in.«½¦Œý${oŽËtÖ]hþæ[Ÿª2¿>ðªÍîö4ú‚ ^-¬Îã¼úV»ÁÕÅr™ÌV¹j€µx Á`£u_N‘<0×¶ŠîF¨Ã5Öå ”¡€Æ*º—ÊœÆåÿÂ'R™q±;Œú–Š¡2ÿ>[}aj1vR:FšLÊ£í� ÁÔF#0frˆhëѵ»‰®švF�E¦·Ji±9DÚÈcÙu£,„T`øDÔ€­« ì3X𼚑ÈBš*%ÃúS·t’ÂnY¯¯ÎuÈbm´ ÞWßY×Ý‚tkÔÔi€äFm±í`½ú«¼¸ .ÿwo.CJ0õˆÊòtX­k?£›¥­W'„pÀ‚AH-ö‹xӼٚϑAƒÅjé†.hw6¦Vúh ;x0©¢NB@ÏJ}ôÂá €Ë2Ù&ÅC@ÏJ}¬CMR:˜¯54‰Œz/k©wÖÚc’Âp-Cl"«öÑ?p µ¯ànzȨ¦2®Ú‘Ž¥\ôO�TªÊøj&çD¸\Í„Jµ(¡WDX¶G�Úæ, Ó_m‹§îWï6Ó«Ìx[Ÿ%¸ÜàÁc]íÔj3�ñÕ ž;hðº$±¶iµ�^6€œ‹¬’­mÐ —�bž hè ìŽ´Æåô¨ÊxXï(vóF9i¿š²m-@„OЭ/ƒ%«^-ŸØò@UÆÍ®qyð`PRë*�iÊé¢èe#v<®öRlÁ0¬ØG[b!v,ûC«ÙÊai­ëo BwàÁûêd%þiV•q1âSº“ëˆh‘"ý\Uñ©ˆÝAú[®®YlÂ’SYb¼ôŠøˆ°ì-Rd\:ì p*1àÂØɺ7.“O-À‘û%?4†Õ(²û‡jŒõ&8À Më"× ŒÓ%ü]jbï‡.Èòd‡.5i�.IÞºÔ¤}HºÀûbÕÈ….5Y?“ƒ.XÊò×A¹áÍD½º`G€>ÝèR¶õW9è‚,ï>è"ODt�óÐ¥lëþqÐÎXã�.e[÷�ƒ.ð¾Àot)Ûºt�÷Úx¡KÙÖüã  lXã�.²ÅºIz/t� LÍ¡KYÚýã  rúÛ¡‹ìöÑ®XãA—eí?ºÀõk<責ýÇA¸^ �]–µÿ8è× ¼ñ Ë²ö]ð�à�]VR÷AœY è2Á`<º@ÆÞxÐe"8<º@ÞxÐeŠ•QAï….(¨o<è‚ÎTôÞ肺 ðƃ.h °ªGÔw€8tA\úA,¢âÑeÊê]°S@6%Ì] Ýq<è2¦ö :èçÄñ  V�.ð¡AotA› Õô^èW¼ñFö6l]2\zÐÆƒ.hº1ºd�âÑ…íºdX!�]ún&é5t¡N äéF6Hœ](÷g<èÒå9«¢×Ð%ƒ5�5tAcí�`è’A¾Àº =Êj]2H\ èÂF‹]2ªÀÀºtðŒáÐ%£š äé  {1‡.ÔæíâÑ¥-qßèB‰h£C—¡*î]2˜2x£Cl¢íÐ%ƒo÷ˆ/˽ìÚì7æñENK弆/ìçs¨ˆ’Q+Mg¾Ù÷óÍ·>E­Î°�òM­f>}?-}zwþÊ8\‰I.AÖÊqAÖZ€B¬…¼T>e*áð%&-EY+ÛÈYk•O™Ê8|‰ÉXQÖZ¦2_b²j”µŠ¼Ê8d­lGU>"/k-K)‡Sù‡‚¬•났µˆ¼¬µ,e^åÓk”µ–¥ŒÃ«|ÆŒ²Ö²”qx•Ï*QÖÊÞw9¨|öˆ²Ö²”q8•€(ÈZÙ/ÈZ €(ÈZËVÆáT>@¢ ke ½ k-@¢ k-[‡Sù‰‚¬µl¥G僖^ÖZ¶2§òYkÙÊ8œÊ8äe­5)áp*àP�µÖ¤Œã¨|€CAÖZ“2Ž£ò YkM$GåC�.ÈZkRÆqT>ÚKÌÉZkRÆq«|Ø‘,ÈZkRÆqT>ÚÙÌ©|jVÂqT>ìŽd­5+á8*vY ²Öš•p•{µYkÍ$GåÃ�L�µÖ¬„ã¨|´uœ—µÖ¬„ã¨|Ø‚.ÈZkVÂqT>ÚÊΩ|jQ¾qT>l‡d­µ(ß8*Ÿ ²ÖZ”r•OyYk-J:ŽÊ‡A™ k­âDYkAGƒ k­vYkAGƒ k­Ð‡YkYkeÓY/k-èhd­µ²ÿè|ÄÙiQÖZÙßÖËZ1U%ÊZkm=ÊZ— ²ÖÊ^ºNÖZX‹qË|*2hAÖZÐÒ ÈZ+özYkAKƒ kýðjÕxß¼¡aºxl›d­eh¸ï^­}t€74lx¯Ve™ð††àÕª<ÓÞÐ(æ<¶ƒ ²ÖB»ç¯ÒêyY+ûÎÀcãY/k-´Á^ÖZ‹ÒLx´å^ÖZiÊ=༬µ¼¬•Ítƒ¬•Ítƒ¬µ¢¼¬µ%šðuðØ·7ÈZ ?ïe­5+Ñt€Çóð²Vö²V*‚¬µòr¼¬•Bƒ k­Y¹¦<ÜÞ k­Y¹¦<>%xl}ìe­…ÏÚËZ+µ—µ²Ër�µ²Ë²—µ®Ü”¡�7îÔ‘”ÐÎGœúäÛáÓñŸ±��˜‘»Ô¤ìÏQÏZ–o™OÏ¿Çv>¥6Í8ÝH\韣ž(4žz²~ènÀ–ùËQOáз†z{êY“²?G=1Ð/;$®IÙŸ£ž˜ËS<õ¬YÙŸ£ž­h¾éF⊈`èæSå‰ÙxßwóaFwxêY³’?G=Qg¶<õ$î†n>Äæí‘¸feŽzbPòÔ³"îºùˆ«P,ÕfH\¿ Ý|J/ÃÏ À1ÊÿõD¡™oçS‹Ò?G=Qg6<õä€Ð·“|;ºZ¡�ݱÐΧå‡zö=c;ŸZ”ê‰iD¡�O­äŽz•8ꉨhçS†jõ¬Jÿ£Ì,´ó©UÙŸCb”™ùv>t­C;ºß¡�OEð5´ó)˜{ÚùTäUB;1&)¶ó©�ìÏ!ñ4¡Ä¡žMÙŸCâi‚‹C=›²?‡ÄÓ„‡zB‹špB‚oçSñ£¡�£V¡�OmÊþOÓ£êÙ”ýy$6]ËM=»’¿€Ä5¶ó©�"´@=1«)´óÁ …ØÎ‡ÃB;Ÿ 5BhçS–‰~õìÊþ/êÙå):$^¦?:ij+ýsH¼MÇtˆçPúç�x›êOˆ|;Ÿb•‡zBŒÚù”mÚ¬C=!Fí|Ê6�סžÏ€WÇ¥Á¸O£¦ŽzŽKÊqO£¯ŽzŽKrOƒ¸Žzö[YrQOJ®õì—>妞ׇv>كзþ£oçSÑë4´ó)ˆÖÀ«]y¯‹µ¶ÛùÔ®´7ÄZglçS;i¯�µæÛùT²C;ŸB�] ž�à©'úô…v>µ)ïuÔÞ£oçS›ò^G=¡ í|jSÞë¨'ˆ¡�Om<ÜSO(C;ŸÚø³žzBÚùÔªÄ×QO*+õ¬J|õk„v>b¢WhçS ó í|*Z‡v>jÑÐΧ²5²§žÐœ†v>µ*ëuÔ“ÚUO=«Ò^G=!�õí|jQÖë¨'”´¾�OEåFhç#&oÆv>µ(ë=Ô²^ßΧ%½ŽzBÚùÔBÖë¨'4ÆÃSÏŠ¢–ÐΧPªì©g-J{õ„ä¹zêY³ò^G=!�.ðjVÞë¨'¦¸&O=+J‡C7Ÿ÷öÔ³¢v8tó)�ƒOO=k&ïuÔ¢òá©gÍÊ{õ¤8ÝSÏš•÷:ê �{õ€WQVå»ùèä‹§žÅY¡›�8Ô›êÔðjRÞë¨'‚ŽÛSÏš”÷:êIù¿§ž”¬„n>eÃSOJ_B7Ÿ‚rk¥‚&4ó)(i¨ž|R‰šùû!ïõ�§¼×‘ϲSèæS8.ãPO„˜w�€·b7Ÿ‚âá¨çVÚûD=‘ôÄSÇk½I=ß~ëäÓ}€¡Æv͈ǟF7혛|bœ}Ì{bvŽÏ{Ö¢ôÏ‘OŒª yÏŠØNÌ{v”ExòY Õãž|v›�|ÈgQþçÈ'ìQÈ{Òfż縊@oòYHùWèM>«ªÇù6jù&Ÿ•òqO>Gk1ïY«ò?G>‡Nc>ä³*ÿsäs\E 7ù¬ÊÿùWèM>+õãž|N”�ò‰»òžÓ†:òÙ”þ9ò9ËŽyÏÚ”þ9ò9­ô�ϦüÏ‘Ïi¥ ‡|6 È=ùœ6ú�ÏF¹'Ÿó*½ÉgSxÈçºjA/òÙ”:ò¹®ZЛ|ve€Ž|.­=ä³+tä½�cÞ³+<äsY)è!Ÿ])à!Ÿëª½Ég'täs]cªoò ?4æ=×Þ1ïÙ•º0ð5Éú&ŸCùŸkè!ŸCùŸ[è!Ÿ¸%1À1ï‰[óžÛfbò9Èÿ|xÕ§¼çPþçÃÀW!èM>‡ò?‡Åé*½É'îJÈ{Ö¤£µùÄ] yÏJÙ` ŸSùŸÃâdã·ùœÊÿS9èÉçTú°¸<å=Ñ8ä=+…ƒ�|â¶„¼gÍ6Æû�OÜ–�÷¬ÙjAù\Êg«=äs‘:,ÎV zèçR è°8[1衟K)àÁbF®bÞsi¹Ð�Å‚T¾³^]Vqtcq-W-èM>·U.ÝX\‹M¿±øÀ«Kƒ¢ð4nêÈçÒØª¼¬ñWG>×%й/kבÏõ,ô©¹Ï§¼çºC7àåVŸòžÈ„¼gEþ ä=‘>yÏŠôAÌ{Ne¾ð²Îmväs*ñ ÑÖñ”÷œ$¾>Úʺ?O>‘?yOH•ŸòžÈ„¼gM:ŽÚ‘Ï©Ì×ò!ï9•ù:ÀK,Šôäs(óu€—X\éÉ'1ï¹µDÓ‘O4 �yOËcÞs(õõBVŒzò9”úz¡ OùÊ|�Ї嫞|¢}TÌ{n-�uäí£BÞsë„rG>»ò^G> rùìJ|ù\¬ëuä³+ïuäå!ï‰Þ£1ï¹tèº#Ÿ]yï!Ÿ‹ÅÊŽ|v¥½Ž|.ïîÈg'ïuäs¥óžõ·1ï9u�¼#ŸM‰¯#Ÿ¨ yÏÚ”ù:ò99³Þ‘ϦÌבOÔ‡¼gE먘÷DçÑ�÷¬hóž3ï˜÷¬�ÌבOABÞ“b‘˜÷D‘OÈ{ÖªÌבO …¼'…+!ï mKÈ{RÿóžÐÈ„¼'u41ï ­MÈ{RŽóž�센'e=1ïi*TxE©¯#Ÿ�²:¸+à½�zšÖÁ´J1ïIY­§žÔ<ż'幎zR9òž&ò €·žòž&ö€§´7’Ï@%ÿCÃyQ‡¼8.¢6œ÷/úí7ß}÷ö|^\׃ÝJ?œÎû‘÷"Å’Û{BŸ`P\÷ î”EÚë÷çõȆäñxî°3S>M�ô…¥ ´;£T¡kÇ”­kŽÜ«N�˜T»lºz|ÈËAÁµkÖgÃ>àØâˆ¸³ƒs·ÑÚ, ©œ0Tlfžóˆ+è1ƒ�ðiã™[�l ›ú°õѰ37v2Zµð õ‚!�Å£aÛmŽ�B¿L´ÛÆ‚i:.ªë³aOm\;J8ØÚ O»ý ˆÌ~Ùì��F—uðú´kPâð0í…ÍÞÕ˜%6{¢…“51ª:SËJ'„-mŽŽ¾I{ ߇ũ3ØÄFÑoÙEYé²!X~…éMcÚ„xV,è„ÎmãÕFåh¦�N[6‚­meÑÕ&{¡Z ?�ÀŒ^,«6K*×Ì8=ѾÖ5» &\i¿Í+ì)\/…Ø€0ÀÊoÚ°Ixèƒ71�5_³È€L�ݦ–�™EaIÇ«¶ÂXt5·ÍuM•,-e:θ0ó=‹ÃçöÝøÁ/±ØO¨òU»þêtëªõ1Ø2#Ç8)Q��#w­IÁÖCÝ"-|Õ5?ï‘Ý´=ØÁ™É\Ü%mM…ñð.–VÙÀ4z24©®0‹F#©í�A™ðá 4ÓÙŽ ƒF£¨ñÙè" ®]U4l�»i4¬Zæ­ŠcAsžuô†u0ÊÛÕøÀLö­­©´2ˆÁRÙ1­ú ævÁŽª�ˆ4‹.îUð„‘œ”«à)C-@ÑAN6'ã6©’¸Š«|TR,+ãBcj1mø¤J¢_åb¹ mXv•‹†Uøa…iœ�‰ÞhV—$§¸�ru®/jAúf_-�ËÈ»S¨2¬ØŽÀ±Ðñmr>T¨J³º>Ž¥dåÐU×—‘1O4Ŧ`zà­–f¤Ã+m†U+²Pž`ûjn�IÏ,Âf{j!ðþµì .ßæ¨ìyÏ”ææ†¡¾šv`N3+K÷5%gqsSümíAµtÈçdë‹Â½M�¹u"Ù–¾hVÄÊ�²1¨g×"Ö\Tˆ.®Ãš½Ð7¥tÞú«4MÉ,æÞVÃ[�8Ä`å�Œ0øð�OY�ëp.Ët}q�0XùX ¹ŒéäulÈ™Ì×0³Á‰¿ð#ŽÙj&o68ÎWu› „¿«7œÖ;¦7mg6¸¹�ÙàL;o68ßPî©3Xç͆,9Ô%{³��sófCV.7·3Ð>Lo6Øçåc6à)¥`6Ðò³�Pp fâÃÌÇ¿³aáöfƒE¥Ë› t—,Îl°ž.³�Ö‘Ý› Öʵ`6 ö[Çl°"w³�–�É› Ö¸¥`6Ðαz³Á¶êÍôwÛ Ö4wo6€Û› –O¯`6Ðc±x³Áš²Ì(ö`6àȶ`6 y›ÁlÀ“�Ál ña f£Â¢£�–†5 Î FB´Œ‡�£ÜØÁh@ˆ¶>0Ç“Á†Ei>ûö{Ÿ2çÚ˜ån?+^Ígõ˜Ó~¶pd¨¶ÏcË—Dožm0Dÿ@cRSú˜1úÞk¨ŒUÈÚh¹0J_9ÚüÖ×ÒÙ@ö€‡tà+§¨[¿‚É8k«‹íZÄ'a·Öm 5&̓˜iñv⩵WßÞ‚<5÷zûÍOØ÷>…}·÷¢¤ènîÅ£\{¯Œæûj·òªŸ…¡NX€÷:/Ã8d ƒ°˜³3ª:¬]Z`3rÁw¡æbüvYg6t˜¸”fa�‚±ÒH4ætõìL‰ìö°BÍ­óÑc@›®¡-\Eç…eaFb[/TkŠŠtâá`ÿ«ÅCÐw3ÖÞ_lâ GaP0L!1ib ÝÓv§ù˜Ñ¶¢Z„¡ln5dÞ¬ú…ÍJ©yÐ<6¢ælãÔ’µqE¯À‰fâ eŽ¢ÚñlaÀ’GWyù²0H™;©~Y�+¬CÒ0Ó»w‹²Ù"»= ƒ0Á¡þyµWn:´RU6LšdN@´FΓÝ2¨ºQÁ’6¸rHÔ¬wrÒY»Hø¨`ù!äöZ¹zWö¹€ÐMà –Øy¦]m‘»e·‘, R`•©Æ~µ`Fºá�ÞBa~m0«9µÙ3úŠvôíia&�B*¤s¬ø�ãk+"šÔ€‘Ð ©Z:¤ÐŒhZ„ J¡È/šŠÑ}1H|h®†\3r‡ãV_ùìºNÌk¶÷sÙÏo|j·_‡S³NÙ�¾¸Ê~&gÛ_e?©÷@C¨°4DÖ|‹4¤LÝ“‡†ÈU—@C¨Œ4Dp6EBÙ»§!²âW¤!T´"+~FR–îÉCCdÉ÷HC(F4D©‘†PihH)«DR¶îÉCCJÍ)Ò�ùiˆ,úiˆ¸_9ÒYô#Ò�štSÞ4DÖ|4DëŠ4¤´R# ‘Ó‘†È*Ìž†Ô¬[òÐ�ÒVŠ4¤æQ# ‘5¿" ‘ÕŸ ‘;<" ©E÷äMChî ©E·ä¡!bïk¤!â$�HCÄÞçHCjÕ=yhˆüiH…È3бø+Ò�Z)ƒ¸hˆ˜ûiH…r5ÐÙB-Ò� ‘l !4÷�†Tr? !ÎÄJÁ¹^>V+øÖ[Ÿ2ç4£ëlâÏ»Vp:ò-V}AOj£Bг`jÃðfƒº§ô,˜É°œÙ ¦)= ú®eo6*Ìø gA«áæÍµH!èY0(az³A�QztCKÞlPD‚žý«7PÅ gÁø‚îÍ@!èY0› =+z±„ gA²ô¬l´Ìšî† geo600À=+:¤„ gAS°ô¬è‚ž}p]г¢·IztñAÏŠÆ%!èIèAÏŠ¦$>èYЇ+=+Žx³�V²!èYÙK$˜ ô‰ AÏ ÿ3= šc… gEÖ<= Z¼† g…‚ží[Cг ýÃäAÏÊÎÁp ñjzVx !èYÑU5=+<ЂžÁ ­7šÑÝÿÜ]üéŸ?�_·Âûž×Ê?/…w©Ë™‹®™²Û\TL¹¼¬……0¨à¬Š‹©h× �÷޵@ݰ–¡]óZFg„ÃY ÔC¥Asa%5Œ”8s�‚_*BÖ5„f"™½¹€ð�ⓞmîËÔѽÎ\ T—­»Ë5Vgê˜`g.P‡KMͶîiT¯áÍôh¼—à Ȃç(g.P?K©PµÔ´Ü/æøœ¹@q,U÷ÙRÓ²à9ÜÊ™ T¾Rÿ´,7]�å=Æâ/ª¬”¸l¤°—·(W-f(¬ùíX ”¢R5¶§]2Ðbuo) Èâ¼�a9iYèlç,jH)†k–“®ð^[ñ¦îk­j*¬­)—;S�ÚOJü–¦¤‰b!œ¥€j›¡Ð²ìÆ^ÎPÀy…'MC¡_£sß�¡€÷J…ä¶œ4Áb5o( Lš—¥°g.xg)à½2ñÚ,)]á½¶ì-¼WEd‹¼,„:K3@HÖÌÝ-ʰ�¿è.üd9JNÊ~d«©,ç¯ß}ó—Çïþù›×?ýñ Eªä>¦Èùà=g�äíz+⯣ÌÑOe޾>ʜɄԥ̹^}{¤8ð8§ú½¦Õ™U['™$Uþviu¦*_ÞšUV«:3­ŽÎeyëpàmªô’ê`U-=WÓáÀá\VI§Z­Â­ÃA³OózM«NÔT›oB\fShW­ÎVu‘Wæ|ø8¾Bn>x“^™óæ[ßã1Ý|ÕTÏQè´:8Î)tØ€•5»ƒJ�×w¬\ušvû·Íô,’åLº–/½Á²öÕ; rµÚÖTm슊Ö™J�×w¨ýÅ_ŒZ„\ÛB°É ÷@H«!3LÈcÆÝó!lPV€¿˜DV)<)ös̘àVœè僢kÖÐ,&2A®ÔÒ%‹ƒØ±C¡RGŽ»ÊìJ»¯8ú´& ™J9qo„ c±ɵ…›á{âçZQÚ-¬ÏXÞbXš—¾švÚ©Œ óˆq·>HÀB[�¿˜F¶Pû¶Æ�R�×wô QÕÊ@5Ž�'ŶÅÂ`ôŠ£Aðæ1Íz$ §¡sòVxœvåp¥0Hk[TÒ’L!-Âï8‚¡<$&¥:¯HÒêÄZ$4SÊPÞdbêx0L)šÖ2UÓ"àvÖÀWPÌÀntæx̦noqt¿²›Z5çamU³ï'‹'cveùƒ9Ó&S4”æ` Åü‹ÆÇ§UÜOS¢AG”9@£^CÓUNÏr: ÚtZüÐ!— Ój�´G*ŒCjvÍ(­{`ã±^ž3>V[øö[ßÇ~œB½’®CþyËtF¨1äŒ;_r±R,1Ìð¨Bù œ®ÁR÷pdxT¡4N×Úqðñˆe Å®f¸‡ï§š¾�ºÚ>ýÄbøU¡`®„;n1<«PŒ·á·•0jsÞB¥Ý†ó—ÂaxV¡Š.Ãû UtžUxÏØaxÏÀ`gÏàagÏÈ`˜U�àaœUÏÈ Dÿ+T®eøVqÊ|±,� GÈ#xèk΂q<Ä&Ë¡³çv…ÎBl¡ºqèhè„|…·Œ ëÁø`°Œ ëÁø`°ˆ!†^>lZ¼‚õÊì¬Ç±Q°³êËG;o¾÷},Èùä+SËWª-q¤Š wxÌ-Ü))±ÖßÏ�†.çž]èi˜ ]¡Êñ3¡eõs››÷Œr¦äç=ËêGù½›åŒÂ©f9çÌîf57¨r¬æÜX6ï1cxɃ˜3ŠÑü”eTž•0eU%ŽP6YΡ\ ‹ÙÝ|dŒY~>2"†+Ì>î¦Ê9³�1³:…Áƨ¬a°1b†5-¯C‹3a"1¦xì0‘1ÃÆ £Æ²øqÃhXÂ(á]N%Œ�ac‚1Zc†1Á.?Eª)Œ†s›Âx_ÔÃÖ0Þþm�ã{·6Â<ã{áߎ0šw™.çÍ‹€áswQP\ÂÜ]ø·%ÌÔ]ªË9SuáÞúù”‹Ì03Þí ópÑÏ5…y¸ðnS˜u ÁH ³náÝÖ8ÇvkÓ×3Çv2�ù@}÷ÈÂÍøÐÒYƒªÝq&#jwÐÞç£Ú��¼ù=L�û(›ž”ËÔàÏ£áÑ£üˆ¾^XÔçGô!”ë†(��v?~aóÆï�Œ®0ZÑ÷Fë Ìqcó¶M݃�„ŒÒØœ¡EÉj¦ÎÐ"ÒáÆÝ•d5Sg øèö£ìJÒš©3l‚ëÕYÍÔ%4aÞ� ÊV3uÆÍI»ëFe«™:#€V¢Ýuó}²ÕL�ù>«ÒðºÙ=Åj¦ÎìTŽ0õ­XÍԙ˳ ¯›ºS¬hêLÝÙ™–×Ïk»ª¦î‰:»Ñòžq9õªšº‡±¡Gìò³pªM]³p*p,ù)jÕj¦î97HVÄ´f5S÷ › $a>MÓš©{>ME�à&›5«™:“Í€d%N-³š©3µ,3¬èfÆt+™²™d@1DýUFÕ­^н׿»Øëwb�¢Óï|øÆ÷Ùñó®_,ËÕ/Ú‹[Ç£Õ‹–a›ºéÜ䘽bûÞ¥{ÎuGBê"¶æ]ºé\ç£Ü{¤'eqÓ¹®FyÕHOØ2öË-9GzR¶n:×�i�@OÊÖMçz !Å艬×ýÔŶìñÔÅ6é¦sM‚�­Šj“n:רöúÔ}6é¦sí}êÊO½e“n:×»§¥ýÔ86ë®;�y�Ä‹]asÛO-_Û±åkÖmçG‰ìû¹Ýu®]R“±Wká®s­p�áŒ}X‹î:×cµÏýÔcµè®s T� ±�jÕm皣"sš£RfŸŽÑžŸV-Tôó4vyjjÚd©ûÖá%?5,mZ¨èÛ‚·ýÔŒ´]…Šwçµ9çS«Ñ¦…Їž> '΄l|úhñâÛo}Ÿ$XrEŒ˜œx zN£s:°%-Z<ö£†²F~z?uWƒ´?vWKZ³èìG…‡Îi™5‹Î~p x芖µfÑÙNø-ϲÖ,úfÚ{?õ3+Z³èì´ý±WYÑšEg? í��ÈŠÖ,:ûÁ±ÚÁ~­Ytöch]£³Uk�ýZ×èìGÕšEg?ÆØO½¿ªV-º®Ò{>5öji=uíšZØxìGÓªEg?&ë�ýhZ´èìÇÔÂFg?‹�ýXZ×èìG×¢E?-A �ýèZµF!̧X]«}se­l<ö™‘8³gka£³C‹�ýØZØèìÇ`(ÐY�­u�΂ -Zt 6RZOý¤æU´x·ÏHu>õ‹šZ´x,HMZØ-H°QÑó‘2Æ·Þø^Iô»œQVì)g´·ÂÇ—3ÖªÕ‹Ç~ŒPßÈOï'ÿch}£³U‹�ýZßèìGeñ¢³Së�ýhZ¼èìÇÔGg?š/:û1µÀÑÙ�¦Å‹¾×¡8:ûÑ´xÑÙ�¥ŽÎ~t-^töci�£³]‹�ýXZàèìG×âEg?¶8:û1´xÑÙ�]Ö“ÿ1´|ñØ�­ŽÎ~ ­^töc¯ý�¡å‹®ÃQb�£³S«]÷¢¤ŽÎ~LV/ºÎDI �ý˜Z½èÛìi…£³KËC?Ûñä,-_ô½jµÄñØx·Áÿ¨Y+�ýXZ½èÚü”œŸüqoC Ÿ–žü�­Õ‹¾=ÏXOþǾªOó�=¢ÿ!Ì|Fÿƒ(ó�ÿál�·â–MYÌ+_ØV‡²äÚ÷á|×ÿöbS endstream endobj 179 0 obj <>stream xÚ+ä2T0B™œË¥ï™k¡à’ÏÈJx� 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Ú�ZK“ÛÆ¾ëWìŰJ„ð~$'[Ò&rÅr¢]ÇY�’°@@­W¿>ýu÷€«¤¶jÑÓ3Ìôôãëz7‡ïæï/¼«§Oÿ½ÿ&Í]ß÷o/tC?¿Ùž^üñÂ�3/æþ Åö%e¼º=%7ošÿ¦?ÛµÖ ×“¸§¡‘w“¹y’D7÷û›4¸‰sÏ “ôæ~wóѹ]E±SÎÝ*L³Z‡qäd]­c?wÞ”û•Ÿ9{#�õ€îØ[ÓËÈf/OðÇÙôC¯ƒŽÅ }æ2wìV¾GSÏ��b0;´y\}ºÿ‘ö±ö=7�sYÜÝPlW�ç|Þ÷?=ÍÄžÓÔò¼»{#ľé„޳¼ºM§;Îs7ÉRšš§|0›uoº/´:Nœ¸^4ŽlºÏUSì\ OïÕm˜ßäôF�à�µÇn¤Dл$\~uG‚ bŽ…¤¾Ó�ÒAëÐ(ûQ@ /ÑN�‡r8ÊÂè3©›§ž�ÏøqàúIl—öëj�ÎþÿŽÿßÓßy;¾zYa�ºQ4n_¿¿1e}R…F ýIü€ŸN –ñ§â÷¦+‡ÇU;.}Ãó�™Ž$~*ê-Ž4Jœ�v¹Ã±G©StF‰ªo„êËSY�46fx0¦{ò)ZŽ8¤O мïŽÐr=­!J"ç äû`ðÿ 4‰Ž3òbèGNYË›ØÏǪN¿ò3œ[Ho]ÞŸ/)—DƒÌiÚ�vñ•µ5ÈY/I'néª„Ü•:¦n´³yIc[5¼I04KRxûçѳ�weØEÙ˹Æéä\Iïèœ={Le5Së™ ¤ž'Á¨×y’âÈw¶Í©¥“Ûé›…Ï­ý ¦U^©Ç¾¬ÌóßMÈ4âÐ~—Ž.¥Ùï!ÓÈKÉ"ж švHÏÌü¾©v<ÜwnË®h™¤ÃXæZtUgž­Ew&v@ÏÔùÍó‚Ê«œkJž²ÜžtsûXô2GQ�š~æ®9oì|Ön®Îïd†bW  ¢Õ7-¬»lê[ Õ|8–Û£ô•õ"`WJr¹ýåî­¾„uèbŽFеjÞ™mSãüÂ(rÞ½ú:‘­}åùH­Å‰èOEUñ¶¨Á¦AÏQaÆ=Þtq§’¾Ú]ÛM_BŽ��$3ç\ïLW=Šg¡QeP⪉h§¾ïõnœ¥3‹ß¤Ôó÷ÇrÏT}=›f*ò¢ÛÏÚÑÈòtU)³‰RböÈMýĺRòlfC§“‡$Ôú÷…cHÏq—ô:t“8³z}‹èid‚ r3GñO½p¯ÂXC11,»ýµN?‚ Q^bš‘³;w,rt�pf»¾Ÿ»Þó!p¾·ÈõòpÉW¸&²Ðõ¯Vwµ¢¹³Ží9–‡cõ(4éýn]Öƒ©ûòâ‚Ñ:…Ž7àýÙš-oœ}ל–„l- Óúu•Ñ©mfZø¡"Œ@O¹e½Ek ËÜÊûn[ bL�gâ¨0P”8d½d‰V›3: ^ô¡ƒ(§s[œ{ÞBÆ0‡Ÿ@Ôd¤�Ùi/ý$›F¨ñD ¨Ì•x"�4ÿÓ£ô3Šçö$·UÑóä û<ÉrŽBýãÍ!ĉ ‹u…1ÁP`|ÓÚœê¾4[+Î2ŠRQØG²q‚ÁÖ †x=S˜‡¢ž`@OŘá�LZPò[ðÊ‚*OL�v®ˆè*‡ÞT{¡ÉwEY³ Ñ`2táÓIuv"|°w—¾7C@Ao9sŒ;á2–cjŠÐîËC]"8m‹z`£ f³ˆŠä�ù�@ð!� Cz)¹óóp =õgOyž{(†ž«¡l+³ŒwtÓëŒôþNøŸ�rËQ8ñf›A÷̧ƒÑè{²`"¿\ïl¾(GNòÝ‚ª‡¹‡#(‡Yô[¡Gyô[��ÌÉ yך,rêjЇ˜AH€ ݘª4×c- #÷L09O¯¢~Y³m�.]éÂI2€ GhýÑì‚L£ÿ,ëóŸBþçöN;éPœß‚õ0h�©*F˜æy™¥]DMÝ%ê–0»dtÔ;â$¢ûÇ~0§^FbÆ%�[Uà$Ö'lw'䈿ƒ`®üF¸ÛbË[$ÖIâ91'�w 2Å’r>¡'A”Y`©L#è· ÚpÕÔæ¥Ð0Àæ-jT%"ŒÐÅ@@Aãi\" ‡ræE�1èb8úlÔ¦è_ïÄ)F¾ÿ²ŠcäÇ��)”EÿÎÀe -î—Mßb˜¸‡O�ð‚ÔÆ% �ÉXŒûˆÓœ;a|®Å¨*³;@…£Åvë˜ÁZ0Þi‹VÎŒ:úá¼[”~ÉêA­oNF¨¢ ê¥ÁšG®�6Oiñ[W[šp…^ä|(~?¬�JËB'¨uοr±å7ü:R�ê¬ROÍoÒd0Ð%�]?80yYú6%S/ýƒôÓ¢¬__Hœª $â´™cá‘ ìl&•gÍëjý‘\!-ß" ¾Åd;#Ȳ=äFŸ7¡ý m±„ë)"’0� ZcòƒY« ©AÞ¬9¡BhþQX´Ê¡è†~IaÕH)Q½TUãI¶�ð�©à �-¹‰£�Æ“�Œ-& ŸfÍÂäÏ,U/žG®û=y™G¤yùh3È“�šš|™äYV(«2y*ºîQÆ”õú³”új:á…�öÈ .ù¢c7zÜ8£è“P%$p”† ¾4 ` à@ïŽg- ñš3qœK•äfÇ5Ö/™cT�àâeéÜOãÏ•ÖÖ%ïO.‰š° ŒTtÞb7KQ2"ïQl·†«ED÷CÓ#��è¶ÑØótd¬?Ôúè§¼Í(FÐìõ¥«s^/—ͼ„YˆûB#%qŽMY8�´h²¡±w�™"$ ·/R²?»b�õ’Vo«óÎ:‚²¾Š¢\U)kól^–ri‚'J5/{ÝÔ4'ƒ¢åd,vãH¯ é5FömÁ¥¤øb\ /:Fx´è”Û6í™ïÓÐлÏd” ôáÁ9ÈÅÃb~°3…^>¨ C{Àâôš–Q/ A¯Ä˃¾·;o*Ћ£S >»îÅK>¾<{?áÙê8—Ã8ò�É78�*uҲϋꓶÅ�ï|_!Ó?íKšä.,`æˆÃĪ\ƒ¨K£|‚Æ�Bñ“HŠƒ“ãBßņßÌ‚¹"_ÒZº'i-5/im=Ik#MkmjzÉ^¹‹6âJõ³ ï´F—rœ=s8¥çILUR_ÿr‡†BÞ¨�è`COË’ó„”\�ï±dŠü<·ØÌ#,|©ëaN@5ú‘eà-[AðÂ×9¹¥ÕÁkBø~¢bâ-öƒ°.¶d725ÇÉî1Xv/ü}Wœ–=™¢ðƒ”iÚÂb ›¨…?ëÍFÎà�MÇÅê�ÜÈü¢ o0¨~F¿ºò«½pÐ’g0¢ÇÀEÓ"+]Û+Or‘;Órðb.�²~¹t+5«1»Œ¯€;ºZ¨wWs½-Œ/bˆ�éÏÅ2{7gÖ‘åËÆ›<½Žêù?àÕCbÓ+zoL” 9;ârO ¤È¥vÄß=¯AÞ“Ê1xZ9òä?EZÕÒ ½r• €%.�ˆs½§”¦Þ-cvö…yjX®×4`]×Ðɰ÷òÅñRníËéä’Š]]ÎÅ©²û K~0�z5r=T?Ñæ¥Q; ¿ƒ'ö"òÄ}óRrkI-#è'#DÏÙšé+ˆñú_¿,}ø<”•êôË« Ü¡ð9?ŽÝr™në³Fcy© >ô¿{°�ßnD±¬ŽŸ\‘#bÛìŒPЉ¸%ç³15ÀšW§�\8â'èݦ€—BRY)ÊÄÏ™ôšóÕm6ûmRîf—_‡¡ýëj�&ΫWä Éô³â¡é0Èa‘I‘ tÀžüÛ«P’ç®—&—_i<½2'ÐBëˆ|¾9÷s›œ) §Ƿp«œ¸ñå—U÷GFjx©ÔŠU!Møb,Y .]Óœ¤CÜC–.^¯ÈµŒ|b&aAtcögóš-ii2ñLäÅ*ö…q¦DòÌ»�cÉjæ¬Æ_¤\ޏ8€[Üð&? _mX@MäÙŸT %\ÅFú$u™¾Ü�Q ½x©ëRØ=JÔ§°{2§¦{ÚþòŠÓÜÁÏ[IõÁ^hÞ/R†åˆOÒ8�k +þÔüýEoxG½% øŸ°y<±P/;-9þ¦¤‘rjν°nW)¹¦»{iušÅ4f$„¶Aýlÿ ú£i×ËwBÝN@á=~?yÞq™ŠÒ×ŸŠ®,/Jí*‰Ô¿rÿXPÖßE,4ì›äP.¦¾+Äc�`Q~Ä´3B‰–TÚ*5$´ôV½\ 3­Qå�©ªõÛŸ^¿\ ¸ïÍð}‹_˱�Ê�|çÝ? ¡Fñ7‰„ïïn…]@ú²ÄŽcñ^¿¿ÃOÈ|?L«3ÜzA%ZÚUN&žrÆz.w%A�…Áßp1à?wQùóûZ¹™.IX~àÅqš„îbEöíý‹ÿ@ù¥‰ endstream endobj 182 0 obj <> 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 xœmXTSgß¿1$÷ºP‰·µ µV['®Šu ŽVT@dŠ CFØ„� a>Ì@ HØaÉÞâ•Öºj­ú¾]Ö.Ú¾}.}ø¾óÝ‹oÏûžóõ‡pŸ<ù�ßï÷ÿýÃÂ,¦a,k–kh„(vµ‹8Â?’y½ŠZÄ¢O£Þfù§Ý„çm̱’=ÌbƒYU‹­_XQ̃Ãs f.Æf±$Ú:{qTRLhpHœÍûÇ\Ü?X¹rÕþ³nË–-6I=±qņGÚ,£ÿH…‹£"D‘q[mìéÓáá¡'m‚Ó¢BbmüE�ÌÛÜüÃEa6ûBÃC£¢Ä 6ïÛ`³ÞÖvÝjúצáñ±6S‘Ûo±q´qLJûÇüÿ'†}¸;ÒCå½7f_ìþ¸ñû pL:y(ð°èH�S°KèQ×°cáîkl×­ß°qÓ‡6›í¶¼ÿÁ* [‚Á¶`N˜3öæ‚-ÃŽbË1Wì}ìö憭Àö`«0{l5æ…9`k°½ØZlf‹íÇÖa° Ø'ØFlæˆ}ˆÂcvØlf…ñ°ù‰½…-ÀX˜5ÆÇbÓ±Øll3ÝÌa�XQ¬ái;¦ °mÙg,Zdr„œ6îù¸K|?4zW@ß…"*¤•I0BÝBY^³zøÆ¿\ÀK/¦Þ&‹s´ §µêãÂɸ«TNio™¦ã¼•ø®E ø”€ëð¶Sµê^@ÀßB øœ»÷«G}cŽù Çð´Üc ! W)®ØE6]n|0¼ˆíµËþ¸K{“€)³QÒA½è�­~§¸�µ€—ód‘À^©Ø™NðÂ%°‡ø½uôò�«_�À×�]/í¿�Xíèm@ .o±¢)N»éóã­dsIQÏËÉ¡g��õlhFÀæ�Ž{D:+7⤲¸E8•{™¼º\§¬ÌVµ/aòó<œ¤¶“> Å�ôÍóV" ´Y}¾þÕÈ¥ú3ýB䄃£I2:®a)T•ᮥ©E — ¾Wá{З$ˆÍP¨Sã%§”á DéMa� 7Àçtm.Xá$¡‘záõÿÊ3„Š…É$�®Üš$ÛJ‡þzúâ¿ }ì?¡ïÅ��Š„¶ñùò2p�€‘ð=ü P!+ýˆ°¤øêj¥‰ZcRT[�…[î,à­‚·àM2.樸YY)šlš_ü4 ÎU¼Š¢øøüèEÛ\<ì�¶œ|á-9Õ–X Âù¾ab�Ðp}µD�P—R£¸B$#[=W«ËÏ¥«Ãs,eY54*ÒÌ •‹Æ>¹s6¶õH»aŸ‰Ëeu �ßÝl¼Òº¾†¸¼›ú£›Õ¹”Íì Oø‰Š’¸}™¥™¥©†”Â8àG ñ°ÃQöhórÈ…‡_™¿éô�6Ü—Á°¤+¸I\Uw˜¨á¦Â`N<7M’$Oj�œ—¤=að):AWò8z-G~4ìºì$¼¹ïµN/œ×ÖÝF@_\-Õ�–°Y}žšÕb¥‡éè ø°ˆr#y·—A‚«ËÎKhRÒR4j‘«ŸwrÁ{¡Ò¤iÒ‚Ìœ¬¼,‚wûºÈÝÜäwu¸³ö|«@Q’#UÇ~�¬áS!ìÂy/~áNQ÷Ã#ë�qxyœ E‘Ð ÷JJÆ´„5Kð1M‰ ØOõu³Z¹�ék³ßU¨ÐÓâàeäþwO(§¿»¹áŒ,ޏ˜¨�*äeVwŸÃ}tnTìY2�ë£*Â×h=Îk•⣙¥jàI %Äér¹**>\ˆÀ°Ó½B^|‚–Éñ3™e2àC |Û�û]å ‚¾>ŽÎsÌÏ:kj/9WÆgÈcœ°0² Ngˆ3еK¡ÜœùF»·ä%—�ûSáÞ/Ó?ϧÃ=+Á_¤—ªh�²¤œÔW\F(ëZ«Ë_Â÷¿XÀ NJåÊt â4eýBHg>½QVßîgtÄêÝ^Žq¦ÄšÚ*Su~vA¶V˜Uœ]´DCKu÷pCä1Áa­9$MõÅ'ÊCÁ)‚çáØï{½¿§êüuOï^P™Ð³è4¨*m뤡µ´V…§§$(cåâ”@„ˆO÷ ói”ô´ÃÙýÄT§’›;ΦÖM, K³u 4e•¦‚Dáê�ö¢MÖПN°¤ä‹B:Á þ8­Tþbë6¦wmF|;3jïð^_õ¯%�v]t±| —kÄÙé@¦æÝˆwÏ‘ël@r˜g ] Ó­åE· øFd˜jn 5óSÖíç0ñŸl¸zb;™žë/‹J=®àG¦r’ñœ| DwqŠ¿p²qê)´‡Óà»pÎÎWË;{% Ü,º†ÚÏ?>»Y"¶÷Á-î'jêþ­Ç]Ô/o$*Šº÷�R‘¨4hûr  �ãõª")ä¢lë¼TC„Ù³<˜q²8Gi„<:^"i %W] ÑJó¥4RcOµÄôÞ(å'ãE9… Åê!²ÅE-Q%'iuÄ×Жm šÿp#œv¹Ó4tZx�¦¬Ðh”jURbŒ:v®OáÈ~ðèÂðq7!Í•)…ÉÖŠÉvC?CSJER58¸¦ë0êËteù� ³•¼3³,Ã�b’ƒCúŸ$) í”pû@Yj÷qbòÎóø»lã<=u˜Î—iÙmÙñvµ Ú‘Þ;ý"à×y%©SÓšu�€×¹©7Ô�1-í>UîÀO…ˆr[$¸· âß?¼ ±^z W‘%�Ow\×A­X¿‘a´¼�úßvÖizí€\6üŸ ;E‹iƒã³ºÅö¢³pÄñ«ÀÒ>Î.†6Ðç§È®×„Ž·7·¯¤Km1“ÚÃ.z5¯h&pRìKtO‰‘ÆÄÅ…„œHr>àDeH³ûà©_dƒqó½CDWßpõ%@¼ñË[ ¿™õ+ÝÆQ†sè�3blî¬*SGV Ê£KÕ€¨1VÖ´ûÖ9äå-ŒöM ÎÞJl {†nrÁ•Òžñîz­®ªð�€7¡%þÆeTwóŒ…üy&32ž€ýd}VEv=x .êúj¯µ´_Ÿƒ^ygTãÉþ�æÕ4**¸¼ šÉ©:õ_£(U½SóÆÛòdŒ‚ó©‹­¶.=¾t…“'Âå9¹qSÞ9ò Ü`‚ êà©®3Ë|&�5˜ÙÔ)ÊšìÚ�'Y^¢6¾È:JU ˆ5»ímDŸŸJ’’¤ié§"‰´˜&”*{Ü£N� Âí±ï÷×÷žt6W´€N0z¼ww" ­ÝrcŠA90µ¶5gk³ó€1KŸ]:@·¡¹¡ÕlhgAcz�¼…@šÉ…d«æiÚ0 ¾iU;ï Dœ Î�ý5Z}ïYaü޼jnl®—F” *CJ}@ q42Äçˆÿ�×´_Y ŒÔ¯L-ÇÇ¡‚©åØÄr#)ÊKÔEžF°Ðú¦¾©´µ¡¥ÞØ †@Ÿ¢#ºQÔcWÏÔ³‘Ë�àSuª¿†€Z¹‹| øz€Ó–Í¿œ SÐuÜÄåyLzS/IsIQ7œ7â·Ú3Á?X"ð‰I[™ÅX53 m&8{Üêñø‡ôDÿÚ3ëÎZWŽŒfzi®>§ðk§üª öjÕ>!jþqAªŽù4ˆó(˜@FÅʼnÅÕqæÆšêFs\M$mÿ/ÈÛãMê 5YÝ} å¿,à-¦ŽÒœHàfÄ©TRÚ^Ñ"[DðZË‚‚ŠÂù_é©È�ð$à¶ö…N÷DçêDÅŠ‚KðôÙ³Þñ´ôÄq›P§šËs4æ”–Ñ>è¡o’uv§v/‚øWO~}æzYß.ñï‰K½�£½’à6AsXYt¹í�§æõc/ ji¡�ÀÈÉL|¨RÙ1:;@[Œ|¹ž±EqÈÕI5hQËMƒ;8“×¹ih§–[ Y5FhA3pj¶3°žÑN‚MÒuËÑ¢U§ðN&л]f¦=ãô<1çd.�ü6>tÄ¡ :’—‘›™›™—É/Rç¥�t"%%M)�È`¤�ë›nô?‡VC7ëÆ†»Ÿ�6ñ ùe¹4‘‹ ÈOÎíÊ.Ér�š"—+é%ÔÒš²Ã3rEÊÈTçd~D*‡¥~jÂÈúmþO?›‚T) ÆKËŸéhU•1v¢<,§7<ì׈’#¢¼†ïÀ«6j(©EÓÁ¬Ÿ÷§ áSƶÓ[`m÷èŽv±‡m·ºµ½Åƒ`ì ¤X?>gérKrJsèYÑ¢“Ón4ŽÉŽétTÜ1_©—꯻T¤Þ'å[Né¾}žõò9td~ØFj ©Ï+b¾†¨/Nö¢BæÙÑlúŽî–++]lÃAn‘N«­«é«hDuÈ^!¢ÍÄQ•Ê…�kœwÉ‘U€QàM}­•ƒ€¸Re'DÁ8pIMuÖЇÄ<:7"WQ ºø0‡3¯ípöˆv>&HºÚp ø±ÜΑxˆkr=$¡*WßòO•ib¶‰õ§ó =wÏ¥Wª@HH‹V‹Ñ<ô­5²†¯² Rª³óø)UiFPjktsèRš$ø•l]Êé­­[¬mPZJÍÒTfT0~¥ºL{.�>’%ÁÏ¥’:VÃc“§­ \Ú~l…'·r ܰLg†,8d<_R|AG×=OebÁy?“1Ñá‘u1�Íõu�ÍÑõÌ.¯Ÿ°ªgÕ¾†ú× ÐíHWà/ q>*B8@Óbµ¢éCG;|ÏÅŽ€s ¯¢½mäR'$œM@[øZ ÈŒ&ŸÐ#^„D¾6›6ùþaÈd¿¾�þ…²»t¡/Ù°Ÿ{l9r¼´ $??·R[‘OS¡ªX&dœÌ©Ô¸äYŠ<ÓŸic£ß–“¬gêƆ‚GTÍüæ%›÷IEA�‹"åà£T.ܾú®ëxÌÿù£±w]ÝãO ÂBeaR‡ªtëîÛ[nâù—ÍÛ}Öl^/Dû�3GI-dn¥'ó7׬à½'¢{ x·ájø%yÔdÕ¦ŒÆw¹€}Äf—OvG%jkƒ•R-ãüdò„�¾ø;cOê{†„C=õ#à&8—<ÙœX-)õ5Ò‹Ûí¡ºŽ‹ ¿8xy­§¯4,X%‹Ž?bȰî¹?Ðú) n ø:Ë‚cb„bÙþØ)�0ÁåŸQÛMVpàñޱ¼ï¨pz_�rö墛“Μƒð4ÚŠó~ƒ[ǹèÀg$Òp¡¾fü®¼ƒºò„'î°áÇÔSzpËA~nž¶ó+ë­,A�ž@WIÄE,¤¦Í[6Èâ§çgµtk=ˆ]8Þ'VÞµ=Qª­Ž„ÕÄéèµ$R®Œ Å>|~¯áÜYáà@ÕðÜ“ zžõíw©A3ª˜¨åfÊb�uú;˜ÿ5›r™ØE"®ÚY²Ça;œ …`cÆ>ÏNß‹±£´»™ûò{(€ó÷|�pß�ÈQØWB ˆÁuõ @]ä˳ö4;¦Þ»áØ+¸ö\‘ÙdV•7·1V&�þÄTuÿ‹:Fój’ËuBË+RûnUê/>Œà"¯Éï87¸0dbÉT]Ì–f«Ë�ö>€âÛ®�èq û(œüéB[/¸E<³¿¶±>:`û‰1ò÷µÞWÛ¾áŠ'û!ÎûüWo Œ…£Ù_IKÉûîµÁà(ñɉŸìôùÇgÕ½#C‚á1rýHð ¸LŒ ô|z«ÏwŸ‹ø„‹H�ž @F&S"¨î£,̬¦oÙWãIh¡¿d¼5üÛ£ëp.€‹¸e-œŽH4sý2´YÞûb—zË{.ÐfĶA«¢ xN� 1#E•"Ž Rb§÷C8óJùµªza…©®¤ÿØ„¶ i¯7±ÔÄ:C3í Í´ÝÞÑA>C–O1™×ñÁ?ßëñ®�?VZn½õSq[ÔÃØ›ªGàgð»þYèy´©ýÞñïK ÷Kv'ÚK>8ÓTß1x÷m?8ÀùA?l8]íÞ¢L¶~êØbÞU{ d'XÞUØE;FÛ;3­J3%ÿfm»ðü¾Dï�7[®ƒkÄÙ�®!±q¡^UX�¤½P›“S(àùåjÈYTT˜–&:$´L4Qn&èjâ6Íx1³©hÖ¬•³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 xÚÅZÛv£È’}¯¯Ð[¡µ,Š$¹ö›Êåkû6–kzN×錰Å2@ívýìÈH��wÏmÍ‹”ä�ÌÈ;"q&ÏgröÉÑÿ_>}9•ÑD;ö}wòð4 ÝI(Û‘áäa9ùaÝgOY=‘••iÖL{¸ìGch<‰í8péÙq$&3áÛ>þÕàâ·ÁˆÉ�™ï8Öµ=�ù®kÍÓ4kÛäOQlÝëÚ¯I]•T;Ö/ÓØµT½°¾VEÕ¼L…o½MßÒ=¾éQgU±}<¢·MD`ûq„•¨]ém ›'ë>iVùc=?´æºòa:V6u}ëwúIÊ<)U—å%÷¹Ö}ÿ1±ªmùŒŠ(Öu’®~Rïu†¯œOgRúV©&~¥‡ÀÂòñ¦ºÌ n|ÂDˤͫ²{®¹ã÷›‹ÿથ^ö�Õf�•­mzÝEIµ_N=gïL„kÇ"BWÕ实z¾U¥Y¶ÌËç <«z¢iµ«Œ+ÛõG®Êß'j!Ôá�Î"Ki!«2Ÿ©5Ìô +IÚdu\•*ððò� ;êWwDûu­Mò œ©ñ±ü§ëB¸ªIZó¶HJ…êx6?ân—Û2ãÕð|¼˜€gqà¤\ßé7CåyÓTi®$o!:ëáØŽ£gùá�ü dæøÖ|¨²g�’„úsµ¹Ãy²¬ª �Ê“ÖeRn“ú�[\êÆ²‰œIÙž::ŠWm»ùi: ëË—)Z\k¥æÅK ‡D-‚Ë•ÒÙgƒÌcaž× ýÝæ�Èv=÷`÷Ò¸ûK¼*tbë+ ‰�E®g�骳ü±QJ¹rWYçKÀÁs,Ýû«n¸N�‹¬˜�*/N�TÖ±uõd�7«)dúç[Ù¼äºÛ¥êá[7€ÆŸª.b FÝ]U´™îGêmÐ%Õû… U™Â(´$ÙÏwÅSƒCBI*NÝ õôeSåeKÏÂú§ã¸EÖ¼5m¶æ¤×†÷l’:) 2®ëàü6Ež*Ô4ÙØÓ–)…¾)¥¢^÷Ù¦ªñ"Ë¿šÏ¾ßsµÏLop\!BÒt¹šß\QÑ�åÛÔ9)©NlÄŸðl? ; ¼‡^^6mÞn[�8RÁ¥çŠ4à÷/ÚBèy†‡ ¿À‰Ó�½` œRÚ> ;ĦgÄ&A‹Är ù&Ï+eÏaKúú;ZbB?¯£ˆÁã*û¿ì;1ØèaÑ&ÛG(˜: ët1Š×W㲺QvÝ�|Kòß]]µUZü´ØdiNXI{K ëþô˜›E$äÃà&k‡§«7ÏЯ_ئý2�ÔVUœÕÕ–l••‘T%Çþ‡6Oïâ‡o”ì¯$€Æ=©hê ¦íº±¥«h€uà ОÚŒÏu�ûdÍÇ�¡ßtÝy^,³Çšõœ:wŠ9¯Þõ‰M ´~…í{A9€¿¼-¹Ny1r ›¬†ÒáMiÆ-ìÚë¼÷¶ÌMëjiT8j2®Õ´U ·Ä~°i“ô…T82q»‘ó‘ßuý®k ¿]i•ÑËé]1 qàXQ?^rÛ)½+/2~bþB`kÉ%(Ì;ð DC¸aß­¥P‚w©A9ùe öÍwàå0b¾xÀƒ0¹viGrϵӸyo.À�5Ìÿñ\·Ÿä¿\'uªeÁó �þ•KŸÉÀ±ÚŠ[`X³¤žú¾õ·|}`Ä=1H7À}­@ î ëìYºú¡ù¬ô!еýˆ\kѵ‘N¼ÒégÊ ë[ÖäÏ%·öÝóõ¸ Ü1? ^×�~\W#ž*š,­Ør�¬ÓqþÑfå2[r·}ŸDâ�7B÷À¼ƒ.­XÉ æW£‚1WJš–«¾m[Æw½([ #¬Rí@ù2ÐÛÚ¹MÕäÛ5žÚ/þ¯òrû‡ h� ¾²õ]dIÛÙQgì÷\?}ËÒlýHWCï‘´qŠÐÉäé*!ÿíù1iå2O[E- ¥�!·@t=ñQmÉ+bNÏc¯ó,¢(Æ#éÅÖI²®Ê’Ë×é5¸$£ž«©«AˆA]ªåÊ–·o&I¿æ0:`¡:!ZÐs ª³äºŸÉfvsÁ{ÞíŒ*½ìÁlþÄ€~`0]Ô ; –¢ño  tÐFÅ!¾Pèô(¡!%¹ÝdlæZö‚ª'a¾1í¾SCÁ[JéY롲Q#Y¼ÛÅ· ~"ÐŒ˜=º¶+öc/¤3(»�ëöÁ2 Ù~\KÀ<îðz£)aåcÜ�Yd¦îÐÁ¬ˆ ÖqU?f­ÍþàBW.ø—MÆêDðOÒrg�Ëœ+^¬ ´èe¸‹lÓî­|Œo†Â†C§›�þkɳÌZ]=¯Û<…aÓ�ÒÇ„‘ZRb"–cÜÒu¤ ªu ½x”\z¾ ¹•JgQ+öB4©ÔY›q îÀóÉ\ÂèŽ'úÿ뼚EtzL’Šà%o$n’�'TÌ|oô¹ûÉj dTé 8e‚Ðk‡‰\ª\„ ·¬,¯ÍA”QßýЖ®7Êvh ü3?ƒ ç%bà‚+µW ¢çì{˜yàHÈwY�pXw¤uzÒÑJ[Àï³MHIF/&løp"A4ð"²ËDЫDL™­Âºó�“D:xøZ�,r´áY×J‰!6;Qü=›£·ž¼ úƒ|„+?ÅÀŽÙA«ól p@*°n¥bno8}Ò›X„€Šµ·ðÇtTf慠Ú�(<©÷ Ø'…Ê%ʤNÒLžÍÛOгÀ¤à1N6û Þ 5üõõ• køÎ� ºë²Jux©gšõ*Ýö\�PëÜ/óšyòö�Ö„ )ìÐ�GS%¾´¥<´·Âœò<ù£õHѽáâÌ�7ÊÞÿ—œöybgT5›ô>–c <¯äC–R ËœV#ëô�^QÆEŒ"J çQ=ƒÞl‰yñÚÓj=اzK'!Ï>LS :±ìó—ܰ{1¶ùгcq¸usN�BéyÖÙ*[sz‚Î7!R)Aoλæê1‡I…½yR-QGe?CœPù*ã|u€Ðƒr–cZ}VUÏÊ1@÷yï\îÆؑc¯k;a<ñbñâŸ#^—H G¼½zaÛˆ"£ÝUÄ|*Á‹®a0½!ÿó4ÿÃ+ùŸ·ãêá®ÎË4Á3òA¢y‹ÛŲÀúìÈ–ç…¶ïìG·^Ô» é*wáIÝ‚ e& C‹ƒÂÒtËÍ?Tî„ÉÓLO;XÒmÚVûÜIêÈwN V xçâìön1ê8 úŽ×áΜ/;ψÖc�,øyREKŒÈõ!Žj©Vëm»ÒM—b–ò=š4ƯòlÙ²}"„°ô2#Êé…®ÎUí.,r»Ë´.@)›6ç΀tºªÊG¾†z6^~p"Þ�‡iªà4‹sÍð‚lÉ]´±û/ݪ¸ÂźŒ¥z-ý3ßAAÊÝòÃxUç’ÿo7ûnw¦_3Œ×ïqM{¸VÏ;$ÓÓç8‹W¼Èî`„µHT.›†^'E¥áÙõ,è´&YëXeV„(᬴Ë: sÚ±O2RÔyŽÈD‘¬ öÕœ°#ºÃêÀ:Û.u�‚õüU7}­9õËnØh�WÛò…óýŽ×‘'â=ßrÅ´óe6ü3pÑmiçŠUü�H²Þ‹ÞLøb".c§#â3IW¡Y‘'�yAA»jdë«ì’ëTÖ,rÂÿƒœº[‡ßà‹.·„Ju'[Õ/ͪÚèî%·œW-W(Â^mò´á†\[gìјïÑ÷$DY7¦nëTEHÆÄhágØÀ`̘3Úeo/D·OiHóˆÁjÌ7½÷¿i{{h›3‹g7ßyªóm½4†Æ® eê¶5 ÏåÖÄûšê©eæPw¤w…É÷Š™Sç�7Ê€1ÛWß{ `dN Þ<œ.fòÌ„‰€2é�‘³¶P!µâä#ފݘ—ÙýCÐÿ <¨?û endstream endobj 191 0 obj <> 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Ú­ZK“Û6¾ûW¨j¡ª,‚/ïIž‡ÇãxGãl6N #q‡"’²=þõéFƒ”Hƒ³®Ú\D°A‚@ã믛mflöê]_Þ>;» ÒYê§‘ˆf·÷³XÌbÎ|ijÛõì£÷QDÌÿ¸}Ó¿2û¸ó.Ô\0ïS¾ž/D(½÷Z5ú9µ—uY•¶¹Ëë¹džíy{ÈTCÍ_æóò¢Pxx7Zæ¡Ð{YçªÄOÎ÷Ã8�-8÷Ó0¤ù¼Ì›‡9gž¾«êÞbæ]çÙVéndèÝÀÍ®*×¶O•k”GÞ²mÍ6·7wÚ7Ÿ`ÃÑo·z¾�LxE^jUc›{­Ú[é¶›Ç¦Õ;¾Hà£?š Ÿ]Iv¢JHÞ‡o˜±ãŒ^ýñòò’†Q»5óXt¦³zÜí«&?ìàix¨U)¥w­š†$«¶ªç<ôªdcôb;ÌììSFøâí<žÎð�íµþ²**3T®Í>1XrÈ®W«[¸rZã.Qä‡i·Âçô .Ôbf‘$>�p+CŸ…²ƒVì„Ör�·�ˆ žx7ê¿›9¬¯ÞæVb#xê-a7›- _é­*sØ ‘rÀb}_Õ;UfzF‹´�ÊøÒê²ÉQ½Aj¾§®C£kj5{c™ÎFLJ†ÏF"˜À@ø)‹{ „ý~ÛŽ©ý8÷~Æ qá-÷û"×kžW»ý¡ÍË�c7¸>ú¯ùôÆ-ðüú9 v­ê¬›ƒ}|0×îõì^âܽw¹±ÏªP„P,`Û-LEŠÔ{›7- QÉx½-Së·6æ½’QÜtHÆDã&o'·u¯6‘Šk ®…û¤§„ÍÐS$QOaè'iЩiÛ¶ûæÅ|GÞÙÙÆ€ÿv{¸C½ÁÄyäeÕÎöùNÙy÷9ÈÏHµö ƒÉ]å…îVóíÞÉÀg"=nÝp"éG,ï@êÜ�WÅ>Rß7®¥Ã@\ùçÏŸçQh—½¡‘æa'@¶I¼Í™cþIè§"˜š?™Ï™° ìæ\ÀÕ<1аù!{ ²Z`ÐÛûZ5y 7!€ëÕû«Õ ’/éÒlU­×‹5úŒo Ñ$zƒ#ƒµ9÷ôŽn�E¨Q(Z·y,D4X4½iÉð@Oó@hÕó¼bèU‹#$fwOÐ’i½†O4ˆdIœ$Ó¢ƒBÁÎL M EV—ï~ü•ž;¯Ê{ظ öt™ÙW ¿õ¯Úåˆ]�D�ž;N}ÈÈ]¤ÜèÕœCçruK¢˜˜pŠˆ''î#Ÿˆ6lGÿ]ˆÈjÉ>=d+)Ñ뀡^W%l‚¡óGD°].±zx£Êƒªñ‰� Ÿš�Ö°½lšÊé³\µà¾‹îõÏ{]®õú°·^ò8r™Âe­<€IDa§¡�qVÝ€Ót¨9})ä”e ûA’Ž-S¸£>ãR"@‡]ã†Ò{c…?¹º‹÷ÐY’½òØ»îÞSàÙKU+ü5vÞåýâIëÌr]Äe’K†¸sè¡÷ w?ì냳Tz™ÊL$bˆP»~DÁ-ɱÓÍ¡$#ÿTVkkï9"ë�a€±ò©ˆ�q_Dbdå'– ƒKCkÉÐXvØ×Úaø8•�Œ0ÏT�b6¶z‡Åé(^Ãø T[�ïÌ3c#Róì`2o¥&Äò4e>51œý>Ëœ Z}6ªÝå% ª´¼(×€“ZÁþ='ð¼U_v]7¥�ÚíUQäÏ'‚e¹®µÂ ?öÎ鲬!šËÀó‡¦Ñê`2Þe 1ä"»¯95__qàÅŽ�ñ 8­mã™$öÚ ¯‰—ÕÊ„© ú a oôâ 6_‹Ó¿ßeˆ8±VB@ÃFKο˜À]6òæ•’®càá{��sé� OÄ|”t¤Í8FNïÑsŒN-ò1–‡‰CIºST(—)­Ë�/�à¨/Loè]T‡L·­6âÐû7“íz}°Âs+�k¯Êiˆ!· Cà É®j+ãp„u¥ÐñÊ>ð^g†ò`²ê./ Ñ¡¾¼¤+m4~½Z¹tÞGÆ�Íõ(BÔ ¡,XðI:ÂA JàJ†Æ²¿TPÛRE´4Ö0]vÑ'°=ÅD.ÆI0`¢#J` ãø¹´+´{_äfW7Õ˜­ìxç1p±@XÑ“,Õ»¾Ð -㪫¯àùÖ˜kF0ê1¦§^ÜÇÂŽà¨ÐÞöà›1†ò2íôï‰ðã£Ãø6G:ñ­ÉGÜçÉ(§hªC�é{ëü5…¥n#?8~ÊÚÛ•¾«OÃŽuÇ~*ùØüÜE¡_æâpTÐÆ-Fñ@àM…;ö©³CNVŠO¼:ì[…2–z?YÙ D¥¥“Vý�AèÕ˜ëÛ´±)»Dr À’~Së í.b! C [×èD»•U›2o(]F%Ü�âûZe-Û*v�½8̲�KúJArR)HN+RLÐ=|É{c}]µÎGû�‡8á$;;Ä”S€ sçiÇ3ÀÆÆ€¤/@h±ªšmµ·ï•ôL‹Æô«ýÐ1X»Ë3Kõ†ÕàêZ‰ Ò—2,¿UÔ<‡4LY1…õFŠc ý-x#HªåØÀã§Á Ä3^ÈG ¬D++³T šëVï‹>qßHwÀ…Û˜Ú@ª1‰[ÀM@U©üÎàsq�‰xM¨;C,C ª<&Qx¤#á™/îT IòÆw€nãvé\‰³L$ÕC9$µ:°}MÛ¨¾æ¥3ÆÂb@4,ñ$ÇÔø‹Èp»°=§)ûêM°¯ßIÜî‚Ô[Ü«ÙÒªþ„jTźqé#N ÉÙ©7û"ϰžÄ&X‘I|ZnK0 Âèº4ió]$-…yŸ45)H¸® �}.ƒ¡'°¡ØEwªóT Ç�µð‰Q‘Æ<�iŒm‚à «Hal2?ä ëÀ¸��p—žÞæåá •Ø­º)¶7ê^D¾­� ïã^µ°ïæYv&iÂkn˜ÖÕ…z¤nBw†ºŒÿ‚krËç¶ÿâp±¤ÇÄ­(_Úþ—Õ¶VÎÓ›×�ëZQ ZÑåu¾Ù.n·uuØl!©!¿ŽlLÝ«Ž-¡Mtjý¿küÿ\Ü,ôe‹(ˆ0ÌmuÙ.–kÈ1›F¶ŽÀØÑÝ©�¦§Vãì)êëÓÙ—3˜/d4º3ëËñ|ÊørS7=Þ¾3 çRúA<ŽÃ]gÂgžR :íh@ºk]+³zžJˆ$€t^˜b[jø¡¡žOöÚG¸ßeà L‡Æ™ÞoÇÕù5•…@1!0_«›³ci%2‘ÀÉ~8|6ÂÙp�šTÐw˜&ó>YàŽ…d?ÒŽ»ˆ¶¬ ÐÒЪ«ÇÅÁ”@Fuˆ4òÞTT Ù…*s]4 ò×"�%.�jÒüîk�å/L¯!�4�¬À2*Œ6œ˜K±FLbGAÌáÕ`N†¼K�’íûƒ™ôE锹ÒE�ªVÜ”%ZéÍåé˰¥Efj?¸Ð ®ŒŸ€™¶ž„ã{gƒ) ³Ôû¹.€Cq±÷#Ë b¶Ö…À‰OÍ~9‘ÙÇ*Ë•»6òtµøwIìJùLŒb€¦•z§J³÷‘ÄC4+z8FU|ŒêNزçhØy<¯Ž½““§‰°3dx€…g)ñéAZœ ì9ƒ°ª4|Âqê’LGÞ�”Ë‹žœ›Ù'ÎÍŒª.oŸýù �5›ñYK? “Y|™²t–íž}üƒÍÖÐ {&™Ì>›Gw3#C£˜­žý‹þø0XJ‰n(i¤˜ÛD¦t|+ à¢ÿ†/&‰/ƒ`ðES7Àò¨æ]~Q»=Õ §骟øÿÿiH<Ãé`&gi\À±žô�‡ˆR_†#|»ët&‰ %QÔ¤ å�í{—kä÷ Bw½º}A½Kê,„1ÆËà�qÜØhZ•=LŸ&�‹Fní& ×cržˆ‰BÀ2¦ i8¢©ë§]]f¤÷ÝÌÈC'3Bû×óºïÓ´ ?@ÃÂS­˜Ùž•ýc;7¬dŸ–Ö†)vWôèʶ}¹ ì‰ð»9Ï]`û =gwÓfÇeN:‚Ê�Žÿ¸—}½o(, €cºN�j˜xê¸,eÁhEîrØKŸþëôÛö`ÿõ“•¼Í­À¢^z¯mÏ{ãáÚÖ�}:™XÎcˆ—ÐéUùÚ;ã“öAãÉãí»ªm ]j¬–ýA 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Ú�·T”í6ŒtJ#È €4CŠtw7’ 0ÔÀÌHƒt#ÒÒÒÝ%-)Ý"J7¾ï{Îñœÿ_ëûÖ¬5s_»÷¾¯ýÌ =­š&›¸Ô ,u@°q²’ÊÊòœ@ÈÍraÓÓkAvàɱéuÀ08ê ð‡…$ B<Ȥ@ˆCe¨@á­€“ÀÉ'ÀùJp�¯ÿe… ¤@Î €2;@ê†cÓKBÝ`+kÄCžŒæLÎׯ_±þå·à æ €2a ¶Èh²hBÍ!`„Û…`²F 88\\\ØAöpv(ÌJ„‰àAX4Àp0ÌløÝ2@dþ§5vlz€–5þ·Bj‰pÁÀ€�Äìpyë`†²4啪Ž`‡¿�•þ6`ü3';ç¿Ãýãý;Äá/g�¹9ÔÞäàq°XBìÀU%v„+‚r°øm²ƒCüAÎ ˆÈìÁà¯ÒAquè¡Ãúƒ›Ã Ž8;b÷»GŽßaÆ,í`! µ·; àØ¿ë“‚ÀÀæswãøçrm .ÿB– ËßmX¼uäÐv€8½ËKýcó Âþ�Ì Œðù_qóóÀN°«¹5ÇïZnŽà¿”œ¿Å=xy8B–m€½ –à‡l8È @ÀÞ‚½<þTü7ÂæäX@Ì3°Äû?ÑÄ`Ë¿ñÃýà ®àý8À߯ŸŒfu°sû�ù_WÌ¡"¯«¡®ÂòOËÿVJH@]lÜ\6.^ €ÈÃxõpðúï8j È?uüá+ï` üö»Þ‡Aý«fçHÀøÏ†0þ;˜ ô�º`ã˜näš?¼qþ?óý/—ÿ?šÿŽòeúÿV$óÖÎî/=ãßÿ=Èbçö�Åuß"Ö@ú° ÿkª þ{w•Á�·öÿ«•G€ÖAÜÁê�Òlœ<ì@ž¿å¸ Äl¡A˜[ÿM›¿åÚ¿ÎâVƒÂ!¿1^@àÿè¶ÌÜöá1àæß*üaå]äo ~Xªÿ®CÚÁjñ{û¸xù  ä†ýpùˆàÁù°¦`×¿Ø à`w€"\={,¡0ìßýŠÿ�P¿E¡×Èìßèw}@NøÈà°ür8¬þ€¼Èð!²Ýð5€Ãþ?ð�zÀ‡DÐ?àC"Ç?àC"§? €ö|È ÿò8ÀWŽ·Áÿš¢ù[ìaÌÑÿaÄÿÂ=ÐÀ`W°9öÜ4Ô\0À¦* å¢BœÒ…mkDí0éB�‹m$×Ñ#=n²£™ž6¯X$3×Í)clÓ®"át‘±nk“`˜w*wˆ$Šp_­^ôLÉýxuÈÉñ¥Æ<¹2BÒÝÅ~í̳ÜuÍH©ÏšçUêÞbÏ{°:Cø>* Éø´×IÎÞú¼ta£;äôY ò ¤B•¬â«_²á^h 7¶s¡oÄÕ¾ûí>r @۱ƭH�TPg¼ÝН/»YdŽõþ—HS¢ª��½8pèVƒ»nº‘™¤ß£�%›¬i“è5áZ äíÖ¨rܦª¾µñã{=N~LcÐfBsov5!ý)A¥“»rÕë7ˆQw¤ûœæ€y³.=µst´ }#W�f ˆË¥?´à:jt‰Pi.��9•ò:ý‰¹�Ý£ÿ¸å ¦’ÓæM™¿UácôvN³¶Æ4…"�§i›ud�Ù;¦Ï.úþ‡æ @›¸ŸUzH¯Ü.¬°‰“¬)4ë³ÐÞy9Þ±�ïYN@×Ó&Ø=”v<î:»Ç;Ç«íÔ&‘`±òjfdwÏ„èx]{ýë!¦÷}É©AšïWàÜ£QQ¶Y¬Æf1)?Ý1A8ƒ�<&è{ÄhD‹×½#Wœ‡,có„�ð¿ëÖVq 8BÓ¤®ÓŠCQÚ\E,g䪯 hŒ´¤Ï>Û¤hô‡ys°\ãln’íR’–ìø7Ýõc«N2SÓåhuÎ}-êhë|-x²s´òðçxX7®œI^˜+F1/N ²¸�’bèE”¹ãÙžäªO¬¸ôˆ€œzÍø¶8#å¯G EÁ_§Î£…Cö,ë„~Ú(Þ¼Ÿ ³m°;[¦79±§3"H~½ÁÖퟵõĤ4øîéâe’Ö¨§ÇW_â§$Y¡ï§2dæ=Ì´Z‡Z,уÖ²J=B•Æ÷B::°ôÒ_o ä¯^�ÿ¨]õ%žß¬ÑÊší‡þÐpI™XÀ~– n<Äæ8 mÚ¡¦úLNæv}ÐðØ+ +±=¯—íßôü•Ï‘"`ÕòÊ«ƒh{,Ž©"ˆUScB/Þí ‘P¼†Ë&^Õ¸eÍ¿‰€¾7J;½)pÕCd2’#«¤ü“¤=te 8B_âõÑqá‰Å7k2‘0¢0 c©üŸb`õ‹ÇÝ({ ˆ…þ˜ñªX{­(¦#.„[�ªÊW¢§Qœ|}ý¬ïäeìy©¢ùî¶ 6ö‰ÈÍ—-è˜p.3q×Á+·\Ÿ¹ŽÄètÉÚ#T |Ÿ*Ÿt^u®7Üäéõ”ýBú²cœ÷æ:ò(|Œ&0å硈@ ÿ¥"•ý .#shíŒçø^ø�z–Üìì¶PnmÌüYNq®ÒÓðdV?Ô…¸ö©ò~7+smw˜3¯{QÞëü'™Ïù@-5„�Áú»)^Pø>qy)ú˜èT��4G`, qðux†�l%bBzïì~ˆ¸Ä,ëí ­ËéGVô¢º:µ{ùlʰѥ>O5#¡e¬u·•R×0CV÷=ÞµÉmèN·ÅÙT¡8ã)�@ç¹L>Y©^¼·gN5µV/ª¬ÂbÌÿ&8è[¡Ž§M éh¶3,&xÑ%‰ô¼Ë cÀŽ�}xùá2_t„<†v�ÔÒdrRˆA8n©Š©»üy£0³ðí%pé<:Ò–#¦Œ¡œ÷÷ËxáeíÔ,–o%ÛŠ’¾Î›"³ïU´z=JÚê.>öEk'Vœ¥n”ƒí®´ä¨úÆïÜR»ÁÚ½½÷7ð@qÔÅ´0h 7͈§  Ü(ys›Ò½ÑwI¥Œ!þiœì”6§Xm;ÇkdÁ¾1ùG{£2îqtùm>Ú³ŠÈ(v3–|®N«YÔXnØU.^•~rrÕÌôW fñ¶±å7ú•nPׯu6e?]sª4[“P Ýj™žˆ6eèìø)ÔQ<»Dg¡é§´f�¹/Y&Uú%ÎXÊ3/XR#+‘qO0Ñ·üúTFëTTV§ÊˆÖnÈö†6‚âYƾB¶LýìC-µ:ïYÎ;-r3%/‘^[¢ïäçÂê.Ùªw¯ÈxoB^P Äϰfk›�)©‰F×ö ›‚NáÍ‹Ä?&ì=ÙÂÝúÅÍž4H?ÖDàåi›ó~–\ ÷ƒöðô¹*I ·‹'…Õ½»íQɧþª� P ?H³ìuÝæ’bLðrȪšŸN[€,F�Ž}Š€ãu͵Dú¯_±Ã–1+PžK|bC)¹­ÿ~úxÇ¿Ð×½5a+ V††¿·:N—'Q„£„Ìöá›@ƒÙ)`zy†ÁG–2c|„ó-Ðnê‹sï™ÒËXIÆ“¹RÀ¸ûS¢ê–�ж¥¹1£7Á6oíäºYñY™}ø’زI®øË홎7MD˜¬t`,ûI)”ÒÈŽHGïÁŸe?CqÐõcÅoùíÅÝçN¿¥¡Z´©>ßLö&G‹)ls\i9K$m �”Íì«ò5³â}÷Ч @ãA‡øÊùdŸ©éf›�ò¤7ÕQ>÷wÚùôÌW|”†³ÇuÛk±óÑB{[jtŽ(6¥>½».]ˆ@Há2¤,W¡h2£þfЪ�×3ø¾£ß”nè•�m؉�“ÜÃ8¸|–Ì�-µ¶hÀò€€»7p“QJ„>–S¶í�Þzv²{$šWÛ]ßç„0�Í¿“ÄLbù1LÕ@5÷¦áΑÀð‹T€_C']##i�Ä´òd9—­±¢±Iµ£Ò»ÚÒÞJ& ø¼Þýf2ÂÖìeë­4&öí ¤oPV¸Û¸Øzv�ɶ<µ‚Åo6}!7~rá*{Ï„‰¿O®z”ò&ü‡Mù† ‰ÖbËWŒ™&‘¤Ù9•2r-µ'«€)Ówâ€ÕÔßE Æ9ÎáG&=&!%4UóÖ¼§V\º•¾ÜV¤LMe¨f9Í�ÒqaÑÌDp¸N;r·!í¯ëk,qòG«eF6Í‚>�‹ã”Æjó÷öõ@?0;Âq©.ñ¤óÎìl ÌÄÔYއ5¢#2bB¹ÜFƒÊÉæê¼ž5ï(îÎ*êhù¿(溑ï(-Ðæ2�ž1F&mN„›ÙUÒ%,ºZ ÐgúóKœ“†ëárÌî”nW,Þ1öyë˜MRr{™sÀ~dóZïÏ�d y¸A ‡¾yN¨d½ýÖnŠK5w2‚Bú÷™_o¼»<�ŠëW°& ‰O´8`í·ù4å‡âÝf{-}95×›v%ôvî'À�7ü[¬”š¤ �¢aÝÒѶ¨ô‹_ãçñÏ÷Öl_,ežÄˆif]y*à0ÝŸÈ¢R¢“x±Æ�;k‹J 1ù &å¦ÞæþˆoþS²¾¼+ûµ�ðs,R}ŠÝ޼òÙš[8R ?‡2µgE}û‹LaS¾§½hÈhÑ<â~Û�g�ìt!³Ëø´ÌÆGØ™ä!,Ï…ñRQeÞ½sç'x¥ sdª¢ µ=ÝÛÀ¬ÍO )û„t&cZqúºE �ÀJPÍDÎv­ÊkêA ŸÇ›Í7Ùî¾�%¸eI,W}½$î5DþÑgÍÍŸUØÕ$âs±6ZsTÇÊG>UÌ`‰ù ~Ñ@Ñ€o[RhÍ‘HÑTïOܤâæÚ1ìuóM^Ę…ƒî<]˜åMWñK» �'¨ÞÊÆ®�®åøœ»_\ŒaÛM¬õ€l}Â�=¹#Êq…{ŠãŠ|Ê2DÆüªîPnÔäB]脜Ó®êÓè¯õ¨zÁvŠ7ÑB~• ÷¾ÒßÂV×ñÕ–“›Æ¸Pß³5Wá¶4çÔÙQ¯ ýÆîæÉ“'å£lLä_ö:Ó+Œ%J) ºVáŸÝÁF„9*ñÛ8e´¼¤�~µp\)Ф§bPnp‹ÌÑ—Ì�Ã2»ÜhÈ�dÁw!UÌÁ>oP•F§aåHómRÛé‚…Ðyî.”Lži…${¿Lr.§¾UwöY üš‘»÷î3N’'[…¹jÀI�*aæwï~BBä´{J¥«§A¯&óJeYÞt fJDT®„µï 7`23 ùj½*æ÷~üáEÒøjo»]|'? iMUOkƒµÂu}þç,ªlF›È{³-f2aOD%«ùx,�¨hWXQ3 ÒirA*éã�;ÿHÃL%Cá”ÈVصP}IøÎÊëߟ·X\mQ‚B ý.öz€¡‹Äo½· ÷â�R#»(°f‰mjc^ÓTÉï•X+%—¬@È,ÇÑQU¿<^�ÐÒU5 ¢ÿÉîêJçãú�ð×û ½Ь’A+~EY“ÀjZßiè‰{¾®ÿÏ¡Aˆ@ºn Ëj¢buKûÍ´ªË·Op§`­’6k?>ØüÞ‘R,ƒ€®~XwKr4`ê(·VÉB$"4Y#Oìš{Êð‡¦ŠÿDz—V¨»ù+˜Ú¢ËL›“fôc×óЈzŸ¤‘0>¼�î>o¦$,ÕìâO}z.¼ÃÏ×ÓGÞ�¸¥Îÿˆ}$—àiܾ×1·Î0"·cXXù(Óµ$ÐØI š»K÷¢? “VJ )œ)�ž ƒD¾‘ªì{Ûß÷ÜD)ñJ”ªÓ‚ˆùJ xxÈeôÊ•ñ{�#N™ 3;ª3/u|ÐLèô}µ‘’zð�ù¢Nñ ~†¥^LÌÎ6-šˆÚ¹“¤(£ÀGMøØëc7@pØ;fèM¡ÁBJçÜM�ÊKž· ZÁ¼só½ÜËÚ/x:dÆ2‰p&|¬xö)ÃäÒÓÚ9\Š·ê9©âÅË£ ­¶ÆPöG²ÙÒ?05Fu㇊žªà‰£¾Yƒ^®oÐ~�4�}Ï}žé¯w+3ÞÅvqÄ”…Jg¬ÿx­ÒÐøÔ+ŽÊ{/L¨jµ7,éâwg.áßñå.bMú=Ks<6©i(ð¬b�™p'uPBÅ{w^F/÷QË�Ÿ’?¬ý&xú‰®Sí<1‘:™}ðót‡Ôqø N§±ƒ¤ûÍY€a„2zœØ¨‹ ;ã¢Ñ×Bç€/óéî­ãÝ$ ærb _&_·Ý2 uÚz«^-ä¼£/Ó`AìOàRæ´l¯€ ±ß“{0o'ϸ­Bü(K=a#ò�/ù—q�ƒ^ óÆ¦Ôø–LJ^½@༠q‰÷­ÙvUÛ¸}_[A®3ê�˜VZ?$ q‘‚ÓòŸ¬ZñWÚ:÷æ�øÛËg¸í³h;i.0,*8Z”'ô�†|ç 62ðÏO0ò?nÃsÍŸÿ2$á á¿gMÁ.óœ€i~úÍõÞQ‚8aÝj^õÐ_)_‡ Y¯ÞË%TñR¯ïI×�HMôõ®N\~DAØd+Mšr1`Ûãk€�µ”YeëÂ"[!Œ¨¨· 9C0Ùz¯ÒŠÇ—3I³“š$"ƒY>ºtÓǺôÌŠ¡pÒËf þät¼¯Ïp¥êu ’¹pÓ}ì€JÅí[~Á§êkv&�¯wÈKruC拚) 4’›ÈüTK ý˜ðr±Eç¦aºضŠj¡­J“…ž¬ïœóCnßÍúi§.çí&^õh¸˜ùòÇ;÷«Õå‡Qþòê4‡Ÿ§š5º‡ëáì:a"ˆ$TÛ É›á&£"‹Õ4Ý®´I*¯÷¼¤×Ñ7¿ºe»á_í‹:ôîPÊ;©9Êe t»‡’»r1;áÑ®B²÷£fç�£þªÝ´‹ ÉK#þÉ?žÂt¥Q{Áˆ-¨›%·ÅI:ò–`}T�ønnç =+rÖUÍfÿ:ée™")KÁ@¶1,ó„ßÝ[>ªz@ÆrÇòæ¡M#£Æ%¦á@§VyËè³5M|âçä�Ú ¡ëoܱÄÞJ¶úf˜ò�EcXŒ½Né¹H< �öåT§q˜öÉcJme=nŸú¦Ê%CcV™ˆô&޶ÑÈyƒ÷î¸t` Ç£*†/[ùžØž²±;Õv÷‰¯QrëŽÅ£�.5ნrî˜.[ÎÓ1Ê‘ýëëL&µú‡µ5o6x/œ4b_n+:ôøi�Gøx.èö²Q›Ñ‘øb43òÅ(ÒÆžrE––¶Ö ’ÝS|;[á�$ãyÿ™AÔŒ䦹�8ÃBRu~m?\MP<çØ»xdçO£z›T‘Ú¢5ù–áe�úÎ̾þ樅ê¼ê)‚üGתeÕ!Ñ=}yìˆ7æHot‹BÕ2µï£[«ªx — 2•#äCtÖ„–äþ)™}�£Uýô‹Ð‘éf1™Ì[[Ú¡Pîõò¨éŒrÙ>£è.MÇ5Ô ¤àCyŠã¢'×M_¢izG¦a)KØ;—nMÍ«û.<¥»Å´ò-4ð­3FÜv×7‹x†el‰ˆ‚ 1ÉO}Ș5Çy�ê‘\?äë\7Q{:®þ€¬?x¼\&ì�{µW¡••ˆ´)ÿ’b­�ߤëèzq^%![zö£¯©Û†3•^КÅ-ÑÊ*Qtƒ1�Œ†C‹©û%ì̼Ùì§`ÑI] N}Ý_uô¼5Ffƒƒ¿®Å=¾àHûU%q©–v&íI;îÇÙ�ñá˜é“÷œ›å›by³Áµ×û“A—vë¦0“„ûT –Ð#&¡'Aösa²óê¸3C¼¬#|Jм2Ýoð?ÿ�;ƒ=Ý]±eãûÒ5¤v»ŒÖø �ÌîK,SOzóÍ+ì·|¶ó£¿*€^òe*õnJ7¸l@R´5Èa3ÏÏ£‘¯|�êhýÉ*:¿Ì%ÁËñø„ƒžt ïu› µàºŸ¸[ô%4ŸUGáF±…"Û†¸¿ $r�–»¹•[!Çi¬#’·Ï»ëzÑÕi罺ªù#âeÚʦÇòHmU;¢ ¬žÈ?‹SñeƲl~ EzËSíÛ�1-öë »;žç‰›ÛõÝó…)ír·�qFÅM’hÝ] À­z}J¥1Q¥U©·kfˆ_@–„yz€{íÐÌ“žYúÙ£×c.#M–öS}à!Ú/ìÞbÄs×Úû,&@ŽÏJ2]õáePf™Wè˜éÕÝ‹]´¶ò°ù†·$SWP\rÅËà À™gvâùÒø!bÆ}eë )QV†+›%â`’{“®�¯'¸­\�µb¸øõâÃÊê¡ð@­Ã� v?¤^h³þú"_›uØ”‚“�ºEÜmãù/Ô'QëT�7Þüâ·˜Ðؽ‹í´ü.©SÚªI*- ;ÓVqDëË?Uî-4fº0…í À÷S ÁÛªÙ&¹#´Yü±éÛ…ùu ÏZ±ÌW[CËs ÅP�/)›M˜…Ä,â©Oyò†ß–E-fèÈfbã¹k›÷™ •ÂüÁpÈìRé,Èû0È%§-6óð§p¹?|Ç`�«n÷#»ŠÙˆÄeLÄF±‚‡wßãË…ÿjívWarÂßÑ?œI5ò”KDtZ|«›gçþ0¶²:D ÷Iö0×<"Vd‹À˜ xA~€>"þúEü×r–‰á“…�ìcÁ=Î@a6½Dš-Aöï$;ãeÓ? ñ·6eë.H £é÷³îl®i¸íí$ôdÊì–ÛûoýËAaõ)€Æàv<õŸ›éS–ÒðSç76ÇŸ(P[µÀ(R(}öK �”Ú TZE=Óv§Î׌WÔÍÅ’èöí/Ùoà‹’1gÁ�Ð,�N©¸‹ª¥~.Té¯ÛV®¤šådôÿ±íaŠy ¾ K?_™M –ÉÅAÓÔ¹Jfñbý…ñø´³|)ÃHßæQ᎘8uUÃèØ¯¼v# EÄA6¡¬Ê�“)¸ö-¾/èÔ’ µQ^£3C½îU%�<“ÛúM`¹�—�Q†þåxêdzÚ)xŽÕ(m>ÿ8¯l«!}<‚¥4Õ ÷lxý=° Ù³FÍþàU¯ ÝLs¥®O»±¯(ó+¤Ë(¬¨ƒ”íÅ&hÎφàæ>Ö]Ôí¾5”5BšïóÅÆsK?¿¦®�~ÉÙSœu6Îu/Y�&»ë¨ÔÀTÌ´%âYÎÒu’aᔊì5.PW«×Óžò'¢š²ý´+Ê„ck�Q²Ëâ¬juåî„P៌é ü´å9x†Ó…ÉLŠ^pM¶Â’é¼�Š:í=‘ww\©vá/8ë¾h **OLmW=0Î ¦xßw2gQY\ºaM±BÊ¢\`—~ÿê ·Ú-7çãbûð¶‡åÙŠæ™2ªìß¡JИ .O¤H˜™�–ýBQë8Q�·|BS8ÕóxªѦH*5|áIÐëšo+JŒ.2YQR:½U.„3S¦è÷áƒ#Ðå‰úVÈå)ë Ä&˜½* fžžÞ¬ÍFst;ÿKÕ\ímãØ´Ùù(Â]%ÂKr¦È*u2ÝŒ@‹kC–“z5âK•c4À•¢Z8¨ü.…pF±Oqš^ž%R”>¶Y¾6j$k°²›}=A®ØZR1Hn\YÑò¬6¢v)ì•ó’ëËÚ®(J‡YMÇ»�‰$�NC9–‰V�«úN¤’xÜ5ÞϹ-‹îomç1vôv¶ÕäEM§ü;œ8=¥$äÇ–ßB¾#ùIŒàedÈ£2®Í r¿ù¸îÇ:Ê�˜/DŽôi%ÈÖD aΗmzº‚«Å§ž‘;üÈÒÔÓ��¶FŽÓA=¥�¥±C7g[Ÿù¤ñ-þ­]ÕèsæûšÝ ¼Î0¼x)9ùˆ2™ØÚ73¸‡Øç¼~ýšÙeúó~4>h#:¦¿µþKÑ>}o¾®·,OO‘ÝŸ¸hµ²}L¿ÜWàIaZ=¿ñÜ.ú?Dð · endstream endobj 94 0 obj <> endobj 196 0 obj <>stream xÚ�tTTïö6)¡€H—À¡c†îéNE`b†$¤[PB@éN )iDBQ$D@R¤ù�qïýÿî÷­õ}kÖ:söÞÏÞïÞï~žb30P²GÙÁÕQH´D, ¨èêjJ`°ˆ ,L ™ Юð¿nR�ÜÓ �BJÿ/€Š'ŠÆúT¡h,N…´¼]ˆ—†HHƒÁ€0,õ/ ÊSP…ú ì]A@ …„{‘‚TPîþžG'4ö˜½Ü0"%%Áÿ;Prƒ{"`P$  E;Áݰ' ®€1 †€£ýÿQ‚[Ö �v—òõõ„ºy ¢<åyø_Ú 0‚{Á=}àöÀ¯�=¨üÏd‚¤ ÀÄ áõÇoŒr@ûB=áÖኀÁ‘^Ø o¤=ÜÀkêúîpä°Î?ð÷nˆ äßåþfÿ*„@þN†Â`(7w(Ò�t®p@_]Gí‡æ Hû_@¨« ›õ�"\¡vXÀïΡ€º’!ÅøwG8KJˆH pîsúUÞÄßþ;ùåÆNèŽr°CÀƒpìi Ô =½áÁ�ÿ;ðO‹ì04`wD IÿSë†;ü±±Ë÷DøwÁXîAð¯ß¿ßîaée�Bºúÿþ{¿B·5õT,ôùþLü2Ê€Âb`‘€Ø—àV1€"þvþOª&Ò@ÀºÅ^Ó¿:öùKî¿âàþYL…e-àþÉ­Àb`öùÿ¦úï”ÿÃUù‘ü¿R÷vuýæþÿ?ÂP7„«ÿ_–´Þh¬tQX ÿjÿ#Z]¸=ÂÛí¿£šh(VJHG,™ ¢‚`Ñ?~„—:Âno€@ÜþPæ�ßô—Ô\H¸Ê ñëۂ̓ÿ+†ÕÌûýðÂòòOê…ú÷Ùp¬œþÙ‡†²ÿ¥;a1qêé õ'Å®k‰�¬@íá~¿™  "Qhl €�9p@y’þZ³„$ ¤÷ËEú�²0oOO칿ـ=ó_öomÃá~péì4 &á\ÑvT£Ää+°2&K¸�yd!,0V`MŒîS›´ùœjœ›3§]¦>Û Q·vîÔSö8zúqf?p¹žµÁ_ôP€Uý«#«]Êôå!îTZàOföiŠfœçæéÊ7¥‹=ûp X⯿&Q°wì3QqÕõ`Ò|9©KÔ%´"Ûô:^×”äèÐ2K™m.¡[ìLVÄè¹ò–Ü’|I°ŠÍÐ{®-ÛqLšê[}ýSÿÐÀe/KW|˜–OøÊέ(4¥šÌ³ª(QµÙB>ùY^±ÏÆ“�v·©”5xîNò¤•¤¬d÷™o„DW¹­&®z¿�éuÞ(;ËQúÑÀ"Nážck8òfå{}í~Ø‚Öëå=~Ø•¶ä*‘ŧ77 ö4ÚÀÌÕ®½åä€é³œñ "}ð„d†5ÀT8‰­bf¨šte¤…¥·p“R|a›sË‚ÍþÑݲûñ=Žij&� ã27î\˜ØÓ)4óÒÇ*Ÿ¹¼+ɇN¨ Ã"Gb”òuu1­’Wl©[„¤¤ s�šX¯ºî:¼¨8°¿NNRq¾X©fÚÇtÞk3Awßákîï‰óOêÊã‡dÏbïÛ¶r»<ôRüÊMü$ÅRãå×ÒÆ˜ŽÀõRù×^S˜’‚<©ú�?Ç3 ¹�º ¬®Ž—6ÆrUÞXÁ÷xjBC2¥óCù!(²†(±kîJ³Ý.Ãÿ¦@G¶×À �’£ˆ»Y5zü,…ˆê+ýÚe!Áj`T Íõ®—j“Fv±;6U.½“\Ýn—üs…hq¶^ æ) 0»K;ôÝÈêš(�eB•æB<_-uÙ"À QŽ74âDU4G„ØW”Ye=h\ Tmö p_ä“}„å“\û¡çЮ—¿×Æ]þbXŠxÿŒÇÎ<€ÝëìξTõ€D çOC¢—4Œœx«ã>ÌGgB6iÂx�§Ì"s¡¥[Úb£(¹zlSQ’Ñ£d¶:/­xdw?߈ *ÙS%�]2;­éñ½5ï‘k�çkê^_Ï�.Ω•”;2ë}öüÀb8½üN¹vâ˜9)÷4õ’Añ‹Õ�$GkàrŒYMtç¶ýªð“9ÜE6¥ws‡ pÍt S\_1'æa>S[½EÆÓÒÝÙ›�˜å7Ç¡{ÅIa[Bé1Ì7hR"¨kŸžoHöú}ðϽ1}~A—ÝÿxNº²="$ÿ.µÎeNР›Œì¢®ÐÜ´#ôáæ6Ê)‡4KÚÜg¤ap�ý²¢Ž‚Ç9óù¤aÛzâYé”oã“çlð–Øx™z"Œºµ¸F�.Q¢Ûí;—R†>xök*wKEržšßcÏ·KƒÄåÀôÎâ4Ï…@ߟ2/âœÊ“×·ds¾lk͹;švНS|„ß`9:øš­“BG°ƒ\í3Ü&_åé€'l_“}ŽCÌÝ5êyÛrW4‡ùYmôÆùÁL_U¾/c޵À §{)Çç1º=öãœ5¾¨Ë�wêmü²^êç7¾;º�2Kû BÌHØ>¥–í�j‹¢2þD׿Èí<.¨md™ð£óŒ†Ã;êûã–î/�Š2�Fcï§ÅôêÀ_úmt¾_Ë» Žx~Ýœ•©]X¯ûêB³í%¸ôÀRØóÛˆ»ºñëj‡âkx?ó§¸É‹«KÄìD#e„[ƒoí2ÓÑwS’â«ÐxÐÒX¿³ÅyOhÖàg#°N°˜ánÕ7Wx™˜tùvÇA|à½K3Å;µÚDóÏsxÅ­�1¿Íä12kߢÿ…s,¥B Ly¾âó³Ì­Ûøô;¢z¾IômŸ%Т~�ôµƒ»µ42@£Yâ‚Î?#5eç;Ïå]¿s^ÌúÖmÇDNE‰©˜3ñä'd„†�ìŌΈgùP‰ +ÇÈ“ãõ•LŽì{T€vï‘­¬ôµRBõŒ=w­î|l„Ñ»2“KÇðµ±Gãœ�¶ $P”•ñêÐ,wÒ“<¾ô¹9¯=²�ó¾òó*#½ªs$ä ~vû†çý|‰’¬¶2 ùV�²T·µ —øqõ­$-ã¬Ò=§üÏgÕdoìgûŸàeX¨ðÇ Ý¢JfeÝq¡o¿6.¥.6Ö bRZyý)üctgˆDqëà§©¦ZwòÅçŸË£Ñ—Wù¦’Š“bËïw%{ÅO—9ÆÁ‘‰dklÿQ8lâ¡Ù¡r‹·V’\âÜóˆu¸…±‰Vœ>Ò¬@±9X÷Ì ,»ÁòMІ¯p#*ƒã·µXD ôÓõŸ*‹ hrß|3·ó¸ä#÷û€çoJ;ë%¯D½¨/ˆg÷²9V™Í^—¦§][{ÿ9[ƒÑô±Uþu�C© Úl–ÈRÜ~CR ß–ð�sµìgüI74#æŒ óŽr¸�ÜPÑí‘)Q%ðGÊXÍ;Y¦Tøï�6o/ØÓùàÏq¿f¶›òŒ­;i°N¤Š“:j†‡ënòÄp\|J®¼Ñ½<µ÷�¯ÜÍkUºl5üÄÔ”¿½?’Y°%5.h^ɺI‰+†¬8Üë¡]´|“Bê^—%×.˜ŒìÛäÔÆAR Û4 �×”Î%-·Ñ…³t7Émõº±êÍWI7›ÊöLIÇQH£NR!W$ã¦u3Ÿ�"¸”ˆ´‹£_=�gû©éÌ…WÁÚØN®/•6©ð+%Sá« ~Éü¬ïú‡&¯­5øÚ¨42è%KO®ZÞ�Ù8\ʇ‡×£æVr¨ õÄ·÷«Ž¤FŒjÞ)äl¾÷ñð¾J¤Ô4ÓÐÚ¯·ªZC-FÃdM]rz8ªÙŽwûÙ“µ9ø =qOç¶éÕ3™ãô¹o—qáÒ…,íóâøqb��VJ‰GËÞ6Éîã¹�åÍQ ìHo½Jû Õr–kŠËŨPºM0Ùg�hO½tƒ=(2ûynøe7\�[†pâïõ¼ŽÎi›_”5‘äYM/Ç­>ô’6–ÖuXrÆ¿¼¾³‰áxe—â^ëÉà(á|S/ã&Wµl§LºIîÜRoÓƒ§Eèó�iu¶„Èœ9R’áü»Â¬o‚ù ®²žþXßÔ™—R_½ùÉÁìCÒÏ‚Ñ7ƒ{¢€EHgJ OýÛ]>"G‚áYúáÙZÞX·ÏÁÜ©¦ä)W:Æ-{šZOÊ“ò½.Ôº©nŸF?ê¨�+gY“–øê¨¦¿ŒSë}i˜ênFëÎ)qWÊcžÒ¥ùýü¬Ñ,� YWø´7ùèâÆa­<ûzTë0+´¤žìYvLüˆÂÈÌçì¡õÁ>ÁN îáHPo©À#wŒßí­ómürŠÄ\¢.¢µxÇÎ ­k]IZôÑÎ7þg+LcõÍEOZ”^ª¨Wf¥[º=�´¾º©˜ HU„ñšnMÙ–gr`»ÇŒ™Ñ¢|6ùNåúíóoúÖõ÷†´I“þ*ÉmUæ^³´_Èzj–8cëÂ4M˜(ÕGCµ¶:àÃû_9êà·Ìž�»€èêHzh·Ò}\9¹Äw³¯Æ×K¥Å“i,v(…c$²_Ü«AÌÄPŠÀ-‰çü†G–Wb„üîí�~“?Âõ°^±MÝ ;©ëÆ¡\½ÏUŸŒo»/rAе¾7Žº )Ÿžg½ß½0eä¬ä{ä]•ä@ë Õx<ß&œ //¸u÷ããÔ�õsÞêÓäS|XÙßøŠiÙŸ’%²¥ÞW>B”Þó€'ÎZ];,4XKðè­"Ë�hÅâ¤ãÑU‘[x. üaà�"š®ìFMè´$Áór†¸ãjfæ‡Qî =UºY—{Ê÷Y9 PÇT�?}dÕd`bnÌÕ*FþæÛu N%/ 7.»ÍÝò�æ5!³—K~ÁWÔ.Qƒ[ÄF�Ú/b"cI­ñQãõÊ»�¸=K©O›µä9?±Ç*‡ï’ÐÞÌÄ0Ü S [qS5MosšZ×�èò¸¼ÙÁóƒ„\)ƒÐ„Í™°öSº�´Ï&×lœ^/:Õâî&ºìeDw¶-v¬Ò›Ë}UHwŠ$¤§!(jצ?äøÖQ~|0mÓ)MC~Ûº–‡pɘò†ä@ÛÐŽÒ%'žÚo²ŒUVÓtñ «V/8SçÒ�}Z/@LÚ†ßâ–¸€Õ!µD猢R‰·Úß'Òh«‚-ý�x¸‡Ödvïʤ—d¶ÔLœMQ®ùó«}Ú=þôÞì´ïí€VH,ùèϾ}¢“e}�>§ëôM:ù¦nì"’„‰þ9íLðên�ì§“»ãË·üYúóæJùây¸S ý<ÀÚ?–ÃÖ{Ï&fÚÑ•±ÏÐÙi)Emì×…ÐBºai•Ó7†}_Íý8&…²HðÙ0›³ÞÏÿaÇ->Þ£0 ³sÎ?!½7ßnöÞIN ?œû̦ߺ,�UÚ6pT¡èR¹Óô”h†ˆóy+î••…ƒÃ© ’Y)�^Sá½c�uH¬(´Í~GõåÕ••×FGb>Ú«j'³�l'ÍkÇ- µ2�)RoR¯¢SÎôAæiû[Î÷k»·M-=Ú"V¶Ö’“Œ»˜ÓwÌG©eÞ¯!ôÛF¶ä -´“t¶…Ùû䥪oÅæ²HØ©”ùr% °Mq!U#S¯éÂe¦Wvvͦ R ›9‘-ónèОcÚfØd—;Õ”ä¡;Õj�¡Ü}û“Î6‡aõ‘J@êý‰Ø¥+ŒqSGó"Ýø�·©L[d!VÞ ŠrŒFm÷�½ä”ctK!7©û9ÏO¸¶“0!7Ú]Rþä†J.­uþ’3Ùéê'õ%ÇºÝæ@Ë¡c×Fø´��ï¢{_Tà��± ÛñWÁ¯²3EEYÕ»êzD¸§øaûiLšìcå y/ä ;Š Q öo†Ô˜ƒ³ b y�xoÍLÁ*κæfÉ(»5£1×Rz³C·ö &FØ Ñì]²3y�µZü¯½´ÖÍ$=¶�¯>˜RLþȇ°+¨gôxïàâ�֩ڴ󲨥xŽ´)РÙàKº™B-«¤‰¢D£ÿ1è䦇«oa^Ô¥ íž·?hôm!­+»!Š'Œ¿áð5[EEá÷89ó$”×Î5ž$ ·ìJ¿|ÊB}í+xú{“êGÈÒ’¶tŸÜ÷&æ[„ÅÏëdå µ"_0V1v×¢š^èLa‚+@·;[a‹øØ¥Ï ì¥{#ˆé?;<¥¦ pÔ(˜œÍû!²'΂¬.·ˆ:ãÑ*#$œQ«{¯4FÿĨ¡b?±©°­\DùVz�™œ~Oš¼ã`[°~Å×LäËó—–n»Þ-q:¶ Mú¸ÅJeòpiR–Q%—K½!Qº­—¥z£´;ô­.0}�£ö¸pI¦bN͹o©Š©Ï IݸåJz4…xܹé=´6°z8[¼¡0Çî�Ö²ù²½@F1¡¨{�YÍ‹K�e·çÖKº ¶7ãD2}fñ‚ÄÊ©_𠮬…Ä— ›¥¢#a‚2]o¿7Ç]e† ÅW»ƒÖB\Kž]Γðz³ÓëŽ8‹gò/Ÿ1ÅR‹÷},4”wv80¢,þÁhÒõ]gm«¯x޼�j*�Ø‹œµ¯Ø9‡»kµ´<�î¥0h}Ü.ÈðÐU¨NÀsÈßñv¤zù•69M™k‰îÄŽ-‚G6="šMq€W 8)˜åÏ ¥;‘%ªŒð|ýx͆>‚›sÀ 7ÔwB(ûÙQiá{åà¼ä+3‰´ Ú!8ï7ŽƒÝŸ;î•vi6 a~{à Ô’á1;üÙV{·«F01Òè•9òµªðáÙÛ½„ëÍdVHˆêƒ?Gemæc`M^KÉÑ�Ÿ\ð°çNÕÊÈЬR¥‰\”D:‡6¬þ„~?Ó| P&¹s0§QÀäóú–:é”Öîu𪂊+kÊ~“ Šþü¢c8¼¼m–Â$eK¹YU¡c‡þKŽùòƒ£[Gw+ÓoX¤ªBÖÑ4; ÚU>ç@ípàEþLë¤óÇœ¬‹ušhöAQP ÊF Þ¾c_™} bZæ†És]vY)"#ӛѓ-ÊU�ßyG¶:Ä‚ÞÐÁOåKÛc é«û9 w®¡�_y 7Ï^Ll"Ÿ_O#eúÖÑÜ Ý“µïìµßô¸EÄ@ÑÚìÄp·/)3Sâqñ msÈ2ÿëlèç ÿkûúgý¡fTxc{áv“å�­Yü{RÁ/N£ wC®F ÒN•§˜(QU¾(l:¾v3�  “Nd(uí΃˜×ƺëK�ÐïGÇ’}Ì}ì.YŽ*:Sɤï0§ì%ãiÏ’oŽ»Rsä|Ë'’¢MSÕun·{òMd²r®fàp©ÆÐbk²áUr·ñ%Õè\Þ[fâ:½êÅ÷pç%AÕ¯Ã7¼‹É® ëFŒAòœaÆ™ö% Ǩ»÷¶Ø»v6‚SÃzJoDnónÑR7úƒÉ6:ƒ¿gnl]¹(U½Ç�Ílûò)ÃZMzK×ÍÂX‚¹Ç”³Š™j%´8S¼Ñiù¨ÛáAJìq;£¢[_½7ünMy,$DТÚq%FqçÙÚ×C�I=*³¶MÓΨÉ��$îŠns¥V°;‹{HÿõW||Ì…tˆuãåNcçE©é,«ŽÔûóZ1'ÛòÓtOä™ð¢î��CUS2·1µ�SIŠ‚l�)á·˜ãÚ„ôΩ ©@³Ÿ.]¶‡Cõîýhó��–P¿ÃÜtwׯÅñ[\W›lrØYHÇ&쨴\™¨¤E¦ÕÉ�5\Œ3Äv'’tG|JŸÓºô0.nœR�ò¨KLÔ{í×$’¨W›AÆxÍÃÅôIÚQ)݇âÃ�¦O©¦o{væÄãÔuL¶¶MŽXIüžYK^k ‹ÀÁ¿Á¼ÁëÖ7¸ìô#Eæôä ôPaEøçº×U iN¤ pXT@ ;%HGÅÍM´g$ãU‹iÈ„t(ÓK> endobj 197 0 obj <>stream xÚ�tT”ïö.�’" )H %!ÝÒ% ÃCÌÀÌPÒ‚€´tˆÒ�‚t‰„HJÇ )*ÿ1Î9ÿß¹w­{׬õÍ·÷~ö~÷~÷ó|œ¬ú†ü öp;ˆ*†âJ”tt4$@ ˆ(LÂÉiE¹BþºI8M $“ú_%„Âø”A( Nhzº„DB÷¥„Ä¥€@€0(ù/ !PyAí:M8 ‚$áT‚»û" ŽN(Ì1ÿzpƒyB’’â|¿Ó n ‚t@('ˆæD0È`C!(ß”à–vB¡Ü¥½½½@nH8ÂQ–‡à E9B�„Äðk`€.È òg2N€‘ùÇow@yƒÆá C`HL†'Ì‚`jhôÜ!°?`í?>Àß» ý»Üßì_… °ßÉ 0îæ‚ùBaލ+ §ª-€òAñ@0û_@�+ŽÉy� ® ; àwç €ª‚„ðïxH0êŽB ¡®¿FüUsË*0{%¸›†B’üêOŠ€€1×î+øg³.0¸7Ìï¯á…Ù;üÂÞÓ]Ðõð„h(ÿ…`\$ÿñ9BP1 „¸ˆ„(â€ø€�•7òu‡ü ýrc&ðs‡»0C@ Ì‰ä ž�¿ÿø§E"$°‡‚Q;ˆ#FòŸê7Äá��Y>ê°b¸'þúýûÍC/{8ÌÕ÷?ðßûTWhj¨ÎûgâÇá>?~aI¿° ˆc^þYFýÛð?¹08&ãO»˜{úWË^ÀýW<€Ó…ch pÿ‡åV@1 óúÿæúï”ÿÅUù±ü¿Rõtuýæþÿ? 7¨«ï_†µž(ŒtàÀþj ù£Zˆ=ÔÓí¿£(F 0G ›ù…D€¢üP¤*Ôb¯E��þpæ�ßø—Ö\¡0ˆ> ýõqÁd�ÿà ì‚ù€ 1Äü!1jCý^ã/‚ÑÓ?ûP��áö¿„',vB @¾$˜Õc,1€ŸF¡öŸßÔ Àà(L 3sÀŽ ùµfaa€ ›ç/É?ê‚=ÌÁ¿é€9ô_öouC >0Éç)8øA˜sMXëI•Âmoþõiüý´3aþ‘üGD¨^•O6+‰†ÙY³Z%ªŸ{„T9·ë*zœä,N÷CײÔùŠñ³¨n:²ØÅO]aO$ù3±MQ4a噦(2K½Aôbé߉¦ì –³wì5ä¤ð¿[Ó=“äÍES¤*®ÞªÛÖQU”¥MÇ$i²»úÕl7`´.öƒþnîª[\èZŒÕ³TÝ 6-é¶S’DïJÊåþÁ�yªž;�ÑÁš^!ëß8ž¢¨T 0)‹VšÌ¿"¿È}㵓Aíg§vS~Ǿ·t‰'å¤F÷Ð }¸cÍzÏ£'§‘¾‡h·@[-ñIF^ì`¢üpBÕ÷«©²Ø"��ÐH»œK^�O%Ã�QTìéÓ‚ÁpE-¡V4𼊎cgåsÅR,ó ž+W•ð¡Oo_hY»™ãýE§´ƒ>GC+Õ®þGW8� uxxø^F‡|’!6<Î Õ[¨˜\ÜÒ&ÎÁ"`ŠŽ×WØ& ´+s ˜(¾¥‚¥wxˆN½W¼Ü0rŽ/Êk�ŒüúþŽü1sè÷áËÊÖO p¢oÍ¥HeAÄÏßDKQ®Ë¼ª›)¨ÛAá9�Ì,Ú &GÖšv˜Ì2Æ?.áȹȜ›P�¬CSBYáCP’M&n*½F»„ïáh쎺”£YÍOù¢hÉÿ³Pü’9©¨9uÕW2ü‡ˆž—Â�î.¼Eû“/Uz#Ò(«â(â— ï ­rã#¯!ŸÖ‘äÜ·TÕ{®Hï5=QHÈ”>�öyŽNŠ1«Ÿó-ŽÔªÄaŽz±¬Pv{K~³{ŸºÜ—âîiƒ.™œ<§ŽEsvz6ííÅ!kÁV²ÙŠ ¬�#®@�[ª•‚æúã’<®û™:r› þówžoÇä°�¿�¹©ƒ¨@Ñ5×S»Y4^ Ü;a¾ÐO‡%[D~1ê–CNºAœút™I³|nNñ)…Ó}¥|?'Bõ÷´JJÀÈØ�âÜèF~')ú2óÚÓÛ‘6^_öRÇ‹n‚6½n2Þ¢ùr�ÑûtëÒûèÈ�ütp8vHßþÌé#/Û*väMVÝgËѤ…¦š†¯òS1†CÕ‡™q"©26“|õ#Õk^,ﮩ8•AZV´|R¹wò×K{ÕÀÏ—¿ìå* �g·ÔYˆÔŽñêqʶ)[>Ú\tQºE¥4(°¾;~®:ŠZj ¼ï-z¯ŒÃ.Ë«hHOÃxÞìGvŶŸÞ­2æ6§@Þfy' ¦‘MÓ•·?pJл�ˆ’/}§@¥ˆ­5¢©„ÿ¡é~:A_ï6�ß¼0+Û¬ý pº¯°Œ":¢´IÞ„±ùîhw´íî†À‰=Î-#2’‡�.…Ïp÷®Ü×NÜâU6ßQptâ=‡,†¿–æŠI4eí¡CL„U~Á}‹í+bT«®ÏlvÓ=3)”¿·'•èJä¤�/(ü-ÑØ¦¦~‚ë)ée€ŠxÛ>Œq;{>-”Yʾ{ÐφE™h’´sæéùŽ+�\”@/0™uéS°×Ði³ûí<Ûhòçû%_òq|•·Ü*½¥×‹nÉÆgm¼›áYñí�œb¾á®WDìõ}–¬³(MjÃpýq£Öí îåšo9¬ù‚òë:º­uûø.¸PF{Yò§ Þtµ�b jSý"ªY³°œÔiuñ 0Ìb5�[Üä–Vìèû~ €šÃCćÒ8´ÐðÇÅz›ÇΈÙNl[š¹ÈSCG Ï>gfç=Çù•!—EÙœx?§ÐO+Áyf’mýš`?¨r½fÃy*4_íuj;‘¥±òS½òCÄ—Ré­ 3ý!o×ò„•¬çÜúu?ẻÁ^¼I ì.…*[�¨ÞÒÅÕõ(¿Üá-�É`¥È*Eô,eØ”|ÅhWkBË¥R؃’„ùüN~¹'ÁMý¸´ŠˆÏžØ¿ Ï^ãì.oË…a³~Ó¦Ù÷1³qôÍù*)P°)°ú)÷éq®w8•Àí]I.’�\âF9jâÏX¡![ŽÙì–«ÔëR­ß8—ATS—¡ ‰ÓJŸLð#)Z¼tq‰o1ð†®áy¥-Š)¡gõ?ò—à”N¦d£;»í\]øónÛr�,¹Ž‘D(,2%zþ°{.ÑqàZ÷ù¤Øêmè³u=°sÂÚ�“Û9Óï*‘„Ë¿½%,郊õצIe²PÑ…pìèœ}È•õÎ_ÿ(­aèäO– �áÓÅãàX8±+ò›ë¶õ€û�ò¨O’¥xmx»ãs ¥VüPZ2%WkÑĸlõ­g¥•è”·¶…«£ÞÙ8`³Õ[Á"Jó鼑žÇ -\• TŠ]PX\³ñÌCÙêíÞ–Ðùâ­Ó(·l~|;}’G˜8hi@ÂËð“¿t 9³ôâ(ážcl!Ã;Ü I��ì�±ù,ž×BȈM„ŒÛñVrÍ�ëÞ•Î+Hcl£’g¼;…™Å³¯\<ÝÍŸiïóNýþö§­Vî.y�ƒôK—|±%€LbÍ“÷2Ö"ÀÔâ1áíÆ…„÷pú’Ê4ˆr™#y{°2ÀX¶\xÈ>nCËO{‰<¢â-$è×,x~^-@·‘䇗ŸuÅg¾óXKŠpƒþ]éÝ—Î8&ý4Gl+Ø´¿9ÎÑ \þYk×´~¢hšE¬E"Ñ�úmÐÚ˜ïì g†6ò>Çœ|õühÒ,HÁv]ÝÉq¹BžÌD)ù’!ÚÊEªS­çg4`†}‡LòºÃ †åp_sý'ê¯òñ.e×ñ¢øûº«¹rllˆ¡¯O��žLȯI�yüx®é1'%ˆÏ«žô“ê«êg¤SASÌý¥Vu‹þ^ú{ÖÄÃ.²imjG-¬ÖòšØ öPö�pi©™‚3í!…··æ<"i™ª¤S�Ô&Ð�;ºú§X0‰QÅ™„–’è‹@c‹�ËÞ(¿3�f+�©ÐWµw‘qx�Ãy4Ã¥XÄ¥a¬Ò¤{Dáq^*´óožza¿[·¾á2?Ô1…‘7‹ Ãw6�Ðø”—iÇ}ØØ˜oxØZÒ£²a_EÓfò7.eJ7v¾<ÍSe2Hy½ñг$ߟSr1óª º–¸oÔ¨ð¹sêVul+SÊÊSÑŒ!›˜câ@|Ü};Þ~I%!sËžHð­r‰�¿_"-ÃâÜ‚©]½§jòþ|•È‘6Ék6—™�.YûýÖ–¦È,§ééŸ)âݘ³ oŠàjÛuòÈëÔµ&$ œ·° �ì‚ót¦_ÿNÍáäk…¶ˆòùR˜�‘Ñ=›eCÁqYI¶#vJ�iô/–Aôd‰Ûq(LÅÖÛ�trGóÐ'sÀ?O¼x#WŠsÞ…a=œüŒvÑÏ@©Ñ94»6(Ü ÿèlÁ­ƒÚ‚Z•™ÈýdXJ:u"k¿)'~§íÊÿšþ¾ç¸MQfd™r�t¥¼ûK³—›\ú¾÷Å?¬ñUzÚi�N>֌ȸ;Þkåà„>Ã]®¦QRuH'v=PÖ!Md{pa]ñú­R ‹?î\O×IwŠ`ï«LH x‘#~FƵI°R‡©ÿe‘bj~Zí®®§L�A÷ƒŒZCÓ‹9ñ*m··(©ȃIt@¤îcâHuPîMp¾ Ïä…ÊEã— ŸÊ­É " 'Å…¥öýª{:�ƒ%íÉ»n¿‚”…H±4¤Ÿt‚5ëÓñ�oZ¡3’_ÙûÜhÙÁK�{K³rA…Ž‘¶¤¯þ&TYLý…ŽÿÑw8¬=]„O|| ´Q7z§F¦�ªï�0«”ÌýKÆÞœ‹ b¶1G ƒ/;“ q~KÊ/ òÅ�hm×ÐZšùOäLŸÒ¶1U*h#h~�ù%C÷ãî<:s¢U«.€2„xW,»�hÌãܼ bGaíëÇnÙ*ùÖmf΋¦8¾+CKxQÓãvJX£8ºfæÒqÓP“{¬§ =qÉ�Ãßz‹ÃEùSYÇ�è©<"žõNŸÜÈ>’ºôŠ×óu ñÕ�ß'_‰ôM· Ç-�Óp<‡–$#»ñ�ù™ì‘ïÎðôSÚ 3à‰� �ù7|ÜÓ÷ßœ}¿Y\·;%%¼–£TFA†3ˆ`ë|u'Ïhì¬ûÔ²´?æ%(:šaPí28Ÿº5©ërê“dvje­˜üî¾t¸—Æjª4É=¸Ø¼Û¥ª¡d�WTÌ ôitQh†™” ùá$öZî¢hµÕö‚Tr²`§cÈøÂ;ÍEyË›çl€ ”C•¯-VÞHXðÜ2ñ¥›QßÂøò¶Û·f¼‚ÐÚ‹zÇý"7Å^a§ÍtÆõ*¥$[ŠÐ].©Û} !³Ûer .ãyžLKº$«ÕZbµ°:rjb4kµùˆ85~ó¤&h>œ,÷Óð Tú5ú¤»¹•M_“7QTþÄ.ÞøŒ§È°šŠ­êœÄÝ“ hcξQ±v-ÝP,|]Ž«ÑU¥Žö@Eá[Ç$ªÐ.ÐsZ¥…Øçp|hOÍâà ñ,6„R2”²Ü6TÁú™=”«ãäÇ_Q¬Ã.ý�a ÇÃE’œÍ[%(‡Ä|nÕ­iK÷ÄñèVÎ4×/à ·…ÎÏ™½uájÇ“NŒ1A«�Ùc¼¥%JBt¾êq·pÉ!{œµH]'²[¨ÉñpèÇËÝ Ü‹9&¸¿6énõ‹gzËE›ÕÇu„ƒ(¯IŒ 4ëé`›äúëä�N£¡g¸í¤ûæ¨7ŸD´fXMÐÙ6�=ƒ%,dõ Û¶±„¦ŽõQ´*íD³6 æ úy5 = §N¯b£+NQqP)>¶n*¬«ÔÜ�Ëö@dÈzJh펎\ï5ÚpnóiK˯L–ò(oR}&X›ýÐëestð’«DM¹Å·Ž·``þ‚=Õ÷“÷ýÄ>ƒøPÐ2WæÎ- øøÒã…G ø¡ö™Ü5Oú]Ô¬ã%ûØ”œ6ãâœã%êx“ûl*-­š=­º¹Ô³�7é­Ú¶êùÌô•±"¾7ÏÏvpý”¯€µÏr„Ž•˜LÕU\‘pßøô�g¥Þçì®ëfMÈÂ=Ù÷“)5r:;į’›[B¤g$�Ê�GLbI’Ú3èªbÒåü9u•"‰î¹È .c °¹Ø©˜AæiŒ´@ã‘ëBÈjÂãFW;q”ó;�ki‹9ùñv™:<=\qkxÊ·ë«‚+¬iLf‚ZB³UmªˆÄ»Ø‰£0)Ü÷9E ¤óÚK‘×­Ýs©,­­ìw×B0žš0d2»ô ög˜´ƒ©ý§,€=C¹™P÷éjÍô+»ÝìÏ$v7·£URS9UÉ_’=ºWu_ÿ¥]Tвvß�»£ón·-Säwõ6ϽçæiÜ£*–Úß½Þ/cD“$ÖÕwÜ\å%¼òBwC½$$Dý©²…tZ$:ÜÏ. ß R}|'ùmÈÊÊÄþCæyfÉÕÍúÑb~iÜ]QÑ0/¹§í�ã,Ü‚¾  «ªÖ$ác{ö‡ œ_ÎXÞQ\£¿n¶þë~I¦ýùMØ—ASÜ-eo¿ºì®—-ÚA“4MÞXËY’_jMš­úÆ”pb¸„W²±ïPÕGè¾4“R¬è™‡Vtœ�ÉxI¸–ÕÍô²è±¿ÍÌËNÕð_ I”Ÿ ÌΠ4’§2jhiëŠ5ao½ùððH˜rbÇ›~á[D“ëÌÛ0š<±Vêq“Ò�B›9¢üáô·�Æ]"¿°­®¹w%#+_ŒÍ{UãÏì¸X– Müšõ6pBÕjw–žÄhÎ'v«ÙPªcU™iã< ¼cÎZu­ú¸Ç[h@ Œúœå±¬®3î·î"÷^5Æ�D½spw:¯ËŽp‚Á¹kÄ9ÓVmÕç€@¡•¬×¤âa(�6ÅÁ…Pƒñˆ½©:+·úU÷3#[ÅÞúg}ú€\þ柵==ÆzÞñ%O)/ÞÈàŸë~ýqpo¿k)ã3ÕNHÌO›ÏKKøGoµ÷ ¦±LN¼ÏK–iË}FÖ!ÈHâ.�~—ªNU!·u]ÆÅâ‰Sªa˜ÿa>ZUþ Ëö�ÏUФ»"‘{ÒK2Wù:*”ät¸Ì˜�Mº=,ÿL#ïÙ�í8‚@“˜“Ï«,Ç9ŒG­´\Ô k7ÈGÜÔ(_Qã�©fSN)a§ÛE숡^ŒÏñTŸ&qÅêœ.kÇçÌ �©(/”öð›ÊwvJ·oz2ľ™Ó>´¹©+òa,J™¨eŽ-IËûÉrÉG+5¼É€Û*ï?t/¦-«÷à'éÕ¢õ<éhJ–‹¶í¥ÍqQ_P¼ÇXf.Osוêu¢Á·Y’ÝqÇiÉö^9nºË­�+ŒØen[‡3: Á¢à¬nO¾Y6Ž‹}Å/w®—4àÒZ•E©…GQÏ"£ÄèëÖ{çòk&¡ûóu¹¤j曼«Ý¼ë;J¯²¾kÑì ù@öqóE½a±JÅø½ÇÁ*mFÑy… et§å o])’G³²Ðcz/^…?¨Hž±îóØ®§´.‰P­ê‰ËºR*ءĻ:mtó0Í—d;õ}ßp©'¬T•®)?j£vLev‹LòA5‹ó endstream endobj 147 0 obj <> endobj 198 0 obj <>stream xÚ�tT”íÖ6" %’"0tJw7"9À£Ã CƒtH#ˆ"!Œ„(H#1¤¤tw§ t|¨ïyÏyÏÿ¯õ}kÖzæÞ׎{ï{_{³³èòÊÛ#l!*8ŠW€$ TÔ6A !>HÀÎnEÁ ÁvÒ Š€Kþ‡�"F]cJ`Ôµ�6Ôp‡„€¢’b’ P’ø—!) T{@í�Ú|@ â`WD¸x#¡ŽN¨ëkþurÙq$$ÄîÿvÊ;C�P;0¨ F9Aœ¯o´À†;(åý�\ÒN(”‹$?¿§§'ØÙ��t”á¾ô„¢œ€7ÒbüU0Pì ùS€häuûƒ"Pž`$x À v¸Ûµ‡;Ü‚^_4T×êº@àŒµþÜþõ6@>�¿Ãýåý+þÛlg‡pvý¡pG êªhñ¡¼P÷�`¸ý/C0Ì qíöCa`Ûkƒß™ƒ�*òú@ðu�•çf‡„º ÜøÜ °_%òÿ sýÊÊp{E„³3ŽrüÊO Š„Ø]?»7ÿŸÎ>�#<á¾ P¸½Ã¯"ìÝ]ø�áPWwˆºÒ_&×àߘ#�@bB@ˆ+âeçÄÿ+¼‘· ä·Rà|]�¿¯ Âèp]Äê¹þøº�= @ÒâïûŸŠJ =Ô´…8Bá€G¿†!äëæ#¡^@sÐ5÷€ _¿¿O–×ô²GÀaÞÿ6ÿÝ_~-uEcž?ÿ­SP@x}y…A@^APàÉÄ®þÿ £†þ•ÆøªÃ@‰?Ù^?Ó¿2öø‹\ 7ðŸ±t׬…¹þMr �Èîú#ð¦úo—ÿÃEùßHþß ©¸Ã`¿Õ\¿õÿ�ì …yÿepMZwÔõh#®Çþߦ¦�?C« ±‡º;ÿ·V¾y¸#ìïg„º©@½ özP”�Ó¶üÁ�M ‡è!Ü ¿Ö �÷º5ÿ¥»-»'׫Ãíš’¿U�ëÉùç•Êp;„ý¯‚‘H°7àºÉ×’ÐWàzí!^¿I äçƒ#P×.Àëòü�$àWG…%€ü×ËéøGù]®7q@ýø ýÓÍ¿a¡kæîö7p�%?Êñ[þGšvîÈkoÔo"]×ð/ù÷Z€@¼ v€ñ„�Tèã�¡uÇäïxò.÷>d_6}ÅÍë;ެw?%¹õ‚»4=xy(ÿ¢³ùöÔ¢2×O¹ æ ßÍêò[5Iúµg~çÖ‰˵€±~ê¶¾ÜMùO­Œ ¼Fr+~®~&AOpª±¿h°g¹º‹“è½¥8öĨz}jEOv‡�,믔Šjž£¿ñÆÇXå±gÛf Ó²â¡xñï‘ïy‘ý<$ÓwŬ‘ÈðߊÊó}4'w2ì3]d$èÖHÇF÷ˆ–ç'y÷‡¯ÂZŠͨoAÞTÛ˜Wµtóâû/§xoó­ ¦•B ¢á•-eÝã KY/€¡œwÚ(–’Ê +)­‘¬ºT¥µÖѨ2¡'Ƶ…éºC“&‡Ç/&$¾}º›9mV5ùž•»Nwvµñ…¿¬9î¬ìZlò7Í—m•epô¸§ìd55)™Æøò&Õs£Ñ¢Nyûþ„Ç ñó›à0ißàï §ô ¹ Ð#ñ›-ØÝ ;"Y~ßãü‹+ötæ†ÈFažä–!W!¢:W¶_^îíåÒ9 )Û¤‡se§)7=Ëž‰çÔ—ú© AóïÍSó)z3k=_ûÞΖ'¬®Ú²¼ýý�×QtKÐRö‘äL–Ñ€– M™yæk²‹yÜ,1aƒñíÖÈ¢ñ±¥‡9);>Ƨ|7 ÐRÎf å•,#ã$›»ì—'Ñ -å»9Žù¨¨Ñ‹¥�Bcq´øŠá%ˆ–î™ô·ô7n�¨ ßI:ˆæ/ì"QuôdUIŽ÷ünÉæWz„Зî]í}IH8`óô³t“¨Ð?õJºvÝy·¼òd,}¦Óio&+t¶x=¿¢âÇ4ÙN:Ù±”MjBëæ/Ľô¤…† úŽÕ°&H‰¥DS««ü‘šîëBg¯�±nB_S—«¡Š? úzÓ2�\>µcb·˜uÝ ´¨©YÖö`1O³>R¯yûa÷Sé9UÛŠ]4=h–ñý¾¶Æ‰ö3PQw¼‡¯è,mòˆÅq ðò�kçkV!ºG8ÉFßÌ4ù¦4i7:¹›îÓ¨viú‚#)¨fÖ˜½'¹H¢49Ã[uAƒ&/KDÕõØØ`gë§EU¼I4sæ�´›C�žÎèãvz|:ÍîQAvÇdÛRŸˆ#�nºÔûÚE‚ZŸ÷ç©YC¢÷^×Þ{GÜÚLü~àJâKoÁ¬,&G3™ÚŽ›ökßѼŞãT1‡láb\æÇÏhÓ³>i¥Ž-Ë^ÇB±*-·wB÷p¤O.ÏTЋyMÜ•EËþ[ÉâÄæÓ%þ˜…re?N·Y@ϛ̲>'lÛ'ýGí�ì˜â/�Tžó3ó‚–tË,°ÄúBVÝé+©ûZ¶‚óŽ �d… þXŠ=~a‡·èQpãÄ �Q…¸ ”V .b¸ïÉQÈ»9ø¡4SÕç¸@bƒöAçó%®î‹:õs'�Óòß%]r É+-»agª›ÐŠw�¬Ú[ιJÓáðbÚÜbç)[vÐø«›÷Nm^oÞÂd'Í&ñ;ülÉ€Õ³ë) fK2™Ès*hñ¯H£©wD(Њ™ò9³G0©߯�„\wkÆÞ„«à=gÅ�Æz…*îk0†xNÖ„1¢áZ²6Ý»a+ é‡Ð&´¦|iJ6{É�XO콤½v%ø>«ÌªþŒÊdÆ—ÓØÌæÏÀRùΜüYÈ›énꢩ¶öh¿j룋is碫Ÿ¾•<rúä=k³†L wÌD!ÞT�ÁÕ„;wʰcJw?{7h&×€œºŠ:¯¾V%¶]¯—Á·V¯…;èuŒûŽÖÚ¼÷¡I$MûÁý¬Rb#½«Ÿ!Y'H×ýç.—ô!ȧ¤Óª$wêï ¡16<0_zü#ˆþÑH‚µœ�¨½Ú¬ØcÀ‡Î¸‡ÊúÛʶGï˜î¡—ÚcÉKãµyÚm]Ã¥|§ÑÝAÅúBÔk&&RcÙu=‘ƒ$Ää%º|º™sÐûuââïG˜B¶ZÂÃß<°x0'Ǫ2wª©rl”m{ö*±Á$(Æs,iʘ°ýV;ÍRµ†Nþj1qÖ ùÐýø^bÁÕ$¯*¿;øÜÍêÉö[7û¸48‰Obþ­âœÕ\É­L:Ë8²=4’0*ï-:ÄCG©!Z[UL‚M] zÉ‘$?æxgõÆŽÐ ˆWÑ­Ø—Ö$XÞÔëÉÕ�“—§íòO ˜ù{˱Zql¶>sáÃ1A[Ïd; ª0wGBOëÄ Ôýqš°•5•…ééÒ{)1‹\O/:r³U€Õ´ˆrIÏÔZ9Ãë©êÕŠ£ù½õ@.&y"X%ÅÀŽ€Í”¸;ß�;ÏÎâ8ëé�ŒÔÞýŸÎòv¢¶t6Ë §ôÊ-˜l¤ƒŽÜT@Å«oghíå,ÐñÒ91¶ÂËÄûgÅÙ@«å]Ÿ§´/ó]<ö›ˆ3ÃSÇZ ø� ÏØ¨àUfŠÅЧÚ^îîQ�8Vÿ�ˆ¡hÍØYƒR9�CI° •S.<±�ƒ¨wØRsóyö—EÍgÛØÏ‹oŸÏÞ«‹’n{—ýb±•"”�ãÖøNBºB5žXQÙ&Ìdý­Ó\}'†�J?©W%¡W�Y `C'Ô³ ÕéIŒJl=Šu“ˆÀæ´Y,f"ÞBN˜žHê$çmu¸ þlO®d–Ãs!J·b4�ãö$/„ù®° šîR|ôœkÛÒ•°½ÊYfÕ}÷†¢«Ç´åž ¹å4ÿ;otŒ~Adg²…þ‹æ;*÷ÐSP#êï±kV:ÀC{ëm›�ÜpCv£O:5šbñ¥ø<©#[æÈ¼´ó³Ÿ­Ûf®ÿº²1¢¼è£1³½Ó€^lcå·[—1{ƒš!�äj1œ+d°éËõ’ª�Ï¡Øs–®RÒÍ ¸Å0 çYN½ð ¢2ºu3ΡIpóg£–C³©üpkø  ­ljB|®9ÀÇÕ¬¯ý¯Å:Œ¾š*³“{VOÒlgšáO©·m´Js,ñ'Á¹ÆÙØÕ­¾ç‘ä »Z³S5+o…“~¼b  @:Ë_í¸½ ln;؇?šÅ¹—Zû ð¨Ëíç"�ÒVÎ7Ñ{„ŸEQ‘9Ú—ÆŸÏ4àÑç­]¦ œpÎÖ%ÌÑMï•=ï€ÅaiïP‡–´Ë\ò*R‘_õÓ´rñµS¾NLÊg‡Þvï�æyë� >%]oÂÊz ÕáãÝØ8¨û9ÑòœÃ"N7œë H™Œ uôg¹À?[V!0“ó6´|ú=ìÍ�ÔâBad½(‰€9%Ãt²V¥’L4={ºS¨< 6� v8ÖóT Ë¢òÛ¸ez^.5©Ê4ByÛŒ‚UHá‡ÈøÁùÊñ¼šëà{s¼c�”ÞÔm;�c ´‹Œ ˜F­ÂÅA…?ÎNÔgG®…^Tú÷IP2æ% â=Iªn­UA’Ìl–¢”‘§ÎÞ%ÜÐ º(�ÎõÇ͇¦ÑZ+F0ì˦×'ë¬Q³ É�"Úù¥¸³+;“”»Q·(âj‹I+îœñ?Î ›kÏfñŸ±IÞÙTâ0eì@/�è?¬fÃS›Í_%íF©ç×t ó�›1|—ƒS½G¦Ü¶þ±Ÿ jÆ'nÐ=_DÉëÜäÕ"†§D¿”½i=Cme6éHù¼âi&u[¼T¬ Ó‡þíM…ˆ™=QæsÓsib@&y öEß%1œþýÛ€AîÆðÏ'yûü±R· é8‰¬ªJ.¡p5ÊËmPz½ÿ¢ÌRí’ê­¡šÔw½WØžüĈ³z/ó¶T¦t‚ëøØ’{ ¦¥(�ôé¡ pMŸ~Ë ’]Šî÷P4äidÈÑhyÊé¼a(ØC(ô^#E{¢+ôŒëû`>S ¤S™ßÙEGDS ÛôåÇÝ296ŽRK)ž{T=X*ìkìÿ¥³Úò£�Ò8Àò5ÅìÅÖÖ Ë¶:þ�ÙrÁà:Mö5»<åÒª-¦³´ ãÝê–w ñŽ€wkÈœHºÍõõœÐf¼ËÁO ‘—Þ` ¶ž™jáp¿“n,ƒ%ná�ut˜œHàóéÙ.zÀqz¢ aFKHe§’Ú㈷·ݨ�TÁ^S)€¾f™‰þ‘ÒÒì¾'/K&`)Ž”Ò»Ò«¯?ìC¸–T|Òl*Û+eß.ªÛaɪq¤H_ݬ{¾ƒ ñ€c‰Se¨3X,𔡅ZÀÅò,ÞÞu‹’ßy(3íXr¼ön¦Ûöi_Ž<›çwðšMIÛüú®}‘Uµ0…¬x•ÓAÛmàÖóCSã ÿóÊÊ*3LE¬aàÐ(ûãžvµ†Ýh]µ+üΞ8fë“ÏÑRk{÷4ª<²I>YNݰ�ßB“Nr*:ɉ¤J‡Ò^0ÖnýÐô].©˜6ƒà5¸¨<�—2U>À.*|†0Å.׿Ú�ÇCbUæß�´퇛ù>ž´òƒÝð`,±©áT‡e]Ì•±,—ŸgÿÔkîÚòM~‹§\új÷A¯ xÍŠ0hÌiS÷ ŽMFåNÚ¢Ëñ)Q±¸»÷r?eúà…;ÀÁßε…G¤Éû)ËÅ´åpÆé�ãÆ-ãûÅØ ¨,Ú~Vƒnf’«Ä¢´Î¨bÒpéÚ�G-Sä¾6‡áU•ŒœÿŽñ É KS{dÁo¼í1ÖˆÅDÜï³hE;÷U!Ö›=PÇh¡ê³ÐÚ’‡›s²uΔÏ�©y…B�¡‹£jrS A}!Oª ø6Ó~^xp¶;ó‘sö.6+Õv�üϙiÅ’¨ß™ýQüTÜê¼^aõ¹TÕ]ÄZ5íÖqŸÀ»3RÌáå\l÷Â`NøY™@1<ÒúLIÆß�gÅí(áÄÆxZЊm)·«}b3fõ­ZUóPJä=^®gûf-î’:ÒuW¾@ÈA>xÖŒ ê^Ø<½Ô²_?°»õ�Ü y{�Qéç¡d|ì„=Ó-ƒ<œi`’<ŠŒh“�pŸ’{¡ŒÎí¬qZè“0Êw¿Â7\¥•Ð|NJ†1Ò,?d[òtìLú¬b¾pÃ+úŽk{HŽ7®:WÊUÝãÛ"ZùhõF» ?'¦F¶D¥ ã¾æÏZ³Xžú‹¢G’½»«˜¾ÜÖt�/û°€qHã�vl÷c¹ô~¸E[ÌT#S‘kå¯Û¬&DïìðgzœÙ€÷²ÉßuG™—öFݶùÖЭœ™ÓìIßts Ìt‡(Ûgº¯¥!÷ÜõaµSî,'jÙ¿5À‹te×ôóÍ[©Ëð·¸W ø=_’R˜ì£BŸƒè]äÑ2U«âÛÌ.¼Z9g8»š62@›òöf›”·;Ó_:Ýв5_kÛ¬,ΟÝ{N5r¡ß5_ cëÆ3Y×0š‰`%ˆÏ7&¨ó8pÜpì/Å%¸—«d ¤J·P<<õž®Bõß8½Ww£ÃñðJXö¡ es‚p�Úëž·i£û¯­šú]µ ˆ�鯌·žå=Þ/&³ÅÝ–{�ªOȼQSP,/ƺî«n Í/ˆºÐnmÿqâ¶ü.ð쉄úÃÏr Óp®ú.Îx(Æß=TÞÊO¹ÝÁ·1ÏÒØßÂzOcÒPŒ¤qÂŒ©ŸaíæîãIbFŽoãòkD<ïW"¿T×â“O�?ø™¢“½Ì&êñÑ�ÞÈŒìÙÝIÚ­—W½ù;«²iX}œ‡[G-'*4ö&ªZ#÷yV©Ý¨ŠT/sç¬ø« ]Ë[p;±�bZI‹NN1ù„*¢äˆ„Ž ä¯ÓÞ¬i�ÉÉ<æ–6u²YÒ®‹”¹}Ûyõt2·m¢¤1ì÷²¦æ!©ÿ@¾"2ªƒ¦Í¨C¾c�Ð�öâÆ«œçÉzþR7£Xë4ïö&eU’¨�Z¬Ò_Y %á0ÒãJ¥4úm•,0ÁÄjîC¢Wú­ý¯83ô…:l¥¼îVÅ1 0vK¢Û’mO²W¡4oñËteë^í¤3"Mf‚šé¼,?TãÕÉp/ì¾iª° „eœàˆ n›¯f÷«Hݾ¯ÃQÀI-Œ²(ÓÑoRßWêùÑÏÜ(k$¹-7¦²K³ªsExËðaÓ4¨Lºˆ»ÖiÎt/¨^Ø¡ZE©Ò)~’oì“Ñ n+Û¼LapOÿ‹û„‘�tª”©ú±”šÆÜ„Tø4î Õ}³|Cm_^šÍ‹ØÄÓ¨<µNójŠ Á1Îô‹æ|ø¼¢="TUŽÔx䶨:¡sjèêԡ̹d§‰õÙ�N™áw÷ÔAþÔƒ¬¾cTø»BÆ>mß;Ý—TÒpºÇsÃ~êÍtq+'DŠ“Ÿ祟zr—ì9RD}¥r’œ³|7¯ºtŠ*Òé–k;a^z�‚˜·Zî9@GU,~‘µØO¿?âÆ útøhßÇÍ/,Ø?£5\nH•'è€v®Ëo–Ú�Ù3$Ä< K1ÿd_9–t®‘n1õ‰š©˜aŸÚnk‚6ðü„Ôï+ªá±À@[šü*ò2Šª¤q ä’®[ãù¾&³6Á~yXß “™„„tÀ«ó4ýÐró©i㦇’ ¸Á“²v<‡ìseÛ:µS †"áÇ!MŸ°cÑ™¬-#˜ôOŽkFëuÓKV¶…¦­øx“\ï±c<ñŠŽ×¸©¢b’ì(uX�Å-f>yÒyá4È—RòöêŠwlø#ƒü¼��Ø¢>_aû¤ÝQéšÂô÷z‚4yéF§Mó —õ¢{JäѪœ!jÌÔ)ͧþoÝÊ»‚cýjzbM4¥LÛfK¦�¼Uº:öCOâ&5Kv´*Äeïœ š¥Y ¯Ñ¤fhtýÁÖW`ö')FF�|!® 4vA=IÎS.UV�‡> ¨Ö¹,l%ÀÃTÒÜëìk(_±Ti¿„Ü–ÛísÝœ†‚p%'…eE�—Ææ ¼Ì8ùF´DãöÑ�CÞ&U®D^ÍJÞ.ÇâŸ÷Zsñîe‘n‰F“õÜfzo{ÏÝB}žJ’}s£±eÃðc€2±¸]}T¥† K#( �ôó¯šØû¡¼9™1Í?£Å­¯ßÀÌ�N/÷T¼æ»Ð—ŸEÊ™yƒ{þ 鯙ÌoðfšÏÕyñÛ�%³¿ô£Ñ~+&ðŒÂ ÐPQ™KÏ<€yòéë‹x;\38¿¼ðþJ0y"µ&åÙuãŠë»ÛrÁɃKIQ.b1ø%j€~a'€‹Tƒ§�èíC@ÿ3ÙÌ4!éÊˉ'ލzì$ò³5̆¦jNF†ÛFÊå~h~Ö*‰ÅÜ™âÝ'çÿÑi߃Tô´G´I¹›ýøá¢¦3ç¼¤Ž§T¬íŽ+k†ÅÄ'S,Àƒá\§Æôë²S¥‰ãU‰§�«¾#½ _b£*Ó˜_ý@~c\Ï·ÞÆ:Ë}EÙ Ë۸˕W�äí‰~®ë±i^$5Má3| Çj æÔû5Ñí– Xïã¼™ª°Á—r1”��µx$]Ÿpm#Lr ?³Õž¶ä7Ú‡ä_ª¯“Å$½žä"±h %õc·§êÕ‹ª~„«Zw·½»en@�Q¹d–r榚b’ÌÅÒ:Âï߆Of”ræ G¸ÌZÄã…cÁ1(é´¢Hé­´8erš‚÷ÉbËñR.�Fq«a0®šLËIh'+^¾ò"ñiHШ.“4œ’$VDÔÍáÒ£Êy‘¿pN�ßÍ«¯íÚñ8R4t¯?ì­LÎ1I}GCƒpœ·ºKxchÙa@¥—Ðt¤7Z¥�º÷pÆ%‡Íï‹j§e߇� êÉ}kÝÞpÇ‹Ó+p+)ôùvŒ¼*™~\ÿF¥ÍÖFµ‹åe=—¥pcÁËÜŽ´r1ÊPŸ�—„õF¤QÁâT[”›‰;:K‡ù` ÿÍ£'É#P+kD‚_¬¦É†¶¬Oßb¶3}Ûáv·>[±H©gõ—›$¢Œ±ØulÜÕJ㙤ñ´^tœ9B|ÒzÏÈPC!P%hö¥Äš¾såî/ü4!âµxxaŽJÿÁÒU£±ì©~Ä|Ek7•ö~YØvÛK™1¦ÌøÖ¶„¥±<‚‰ª:ýdE�™ò°KtTóÇRíQØ9k�ɉY`é×6:ìÊK¾`Å 'bÍNŸ7ÖJé³v˜|㈦àévHOöÌøPë8;ÍÏ€Y5¤bôT0}1ü¬<9•ÝÄÞG· �•éùJb/Ïgÿ,Ó¡>ùë»”Ä�°¡1¤™XŒ�“—’c\xWjÒ·HŽ”!¸wSFÈn?¨5omžã™sìk÷0ä*]Õ}êãWø!ut’$Š {ŒŸ�ü|Õ8ö7˜•Íê ×QÚÍÄ›Ïæ‰éð¾ [E„[<ÀËŠö›;> endobj 199 0 obj <>stream xÚ�vTìû6£C™„ÒÛHAéîN©1 ØctH(% H‡¤´"!- "¡„t—’* %ü§¾¿÷ý¿¿ï;çûÎÎÙž;Ÿ;®ë9㹡o$¤à€¶‡«¢QX!ˆ0X¨¤c( ƒE…Á`�1ëÿ£ð˜Â1ž4JúÙ•0p(§S†bqn:hPÓË B$¤!’Ò`0P –ú�## T†z#€:Â@M4 î àQB»ûaNÎXÜ-ÿ9ya|@ˆ””¤àïp ŽAÀ ( ë Gân„AÝ€FhŽõûW Þ»ÎX¬»4äãã# Ez £1N²|‚@Öh÷„c¼áÀ_íu¡HøïÆ„<@cg„çµÚëÅÀ�8…Gyâ¼Pp w7ÐHC¨çGýqÖþã ük4@ˆ0äïtEÿJ„@ý†Â`h¤;å‡@9np žª¶0Ö+„¢~9BÝ<Ѹx¨7áµÇ9ü. TU0BqýýÕ�' ƒpÇz {"Ü~uú•7d”ƒ‰„£°ž€_õ)#0pnê~ ßkuE¡}PÎŽ”ƒã¯¼ÜA&(„‡\Cù/œ ð�Î ŽŠƒÁ`I)0î„ûœA¿’û¹Ã!¿Ô¸úƒÜÑî@G\ ð „#÷ð„zÃ�XŒ<(àþ-  †ÚÃ�(À?Ùqj¸ã·y ÂxŒþõùûd�Öåæ÷�ûïå‚4ôU”ÌÌ~7ü·IQí ‘ ‰ˆƒ�ˆˆPwúw}(â¯*ÀÿÄj Ñ@©?Åâ¦ôŸ‚½ÿÚ>ï_Äàþ;—.‡X8�÷€[�ÅÁ0Üäÿæ¿Cþoèþ•åÿðÿ®GÕËÍí·•÷—ùÿ°B‘7¿¿ì8¼zaqØ×Aã€úoW3øºêÀ^Èÿ¶j`¡8( œÜþ"ÂSá wÐG`aΠòGoò‹`n\í‰øõ … `ðÙp¬‚¹â O›à8ÒüûJ íð‹]"â@(õàVŒ“Ä� ྿  £ÐX\×^Ð�üÚ§˜„{–~)ÿÈ¢@�»›—çß ÜÂ@Xg ü\) ¬ú·ü¯Z`^ މ¿±‚+ô?òoÚÃá¾p`j »óÀ¥úÁ›ãJV¡µ!™Qž5³4>¡€)L‹×)%q2ß«¬°Ì‘Br'õìŠ ï¡ü4ÇÏ€­Æ×Ä‘M‰Íg�ç¶ †Öš“# o‡Ÿo)Ôô°“² ˯þô4 u%h¼Ò¦É“ëáu›R?Ÿîا[Í·¦§læ}ÄÄšÁú+ -²ó²�B�Mb­B‹ÇxòìŸ�3qa…ØIøi÷}©Æ�Fis†/94AÛ�E ,EžœŒûϽ0ñlgæf¶db'8¤}ÿáf€âfŠ&ã§€’Âù‚1+¯¢hÑÙvÌé»O½0Á^F[WÍÙvþ\Réøuúµe‰èM®,22‡·’8ö1�¦½9d§9Ô˜S*nD€(8 (T)u^÷8‚�×Yùó�x³9o J;rZ!ât²ä=礉‚š6åµY™ ÷‡­ÃlòþŒŒ,ùYI¿Õ D¹:—Žâ»èùl¶Ìzlã“î»ÞL\·• IѻΙˆ’;*7‹JäËNLÄA×Î2ÄNPDúص+e=&Ùnç±åËú¤.ÐAœ-Y ÿ \r-Ñ}X ñjÒšY�º5a7áç8Ë»ŠjûÄmg¸çqk¥âôA“Ÿj^ �wû£Œ}rÓݵ†Éøvw„kBƒ�ËÞøþª]{fm‡J¹ šd÷K­Ù>™‹¢®ã£Ž™ö†pý~ãØI¢¦¢�P[î½ÏÔ/)ú½”è#&EŸ�¥*2[9úy‰‘of—øv.5--|Ð=¹{‘ ™dý¸œg¾äš,É8ª‘Ù(ËÃz¾4z0ykfÍ8ý’¯4ø·ÏÐ¥ÇâS} ®!ÚÄáMS_×!ÊNßžmùù7c3Yt– šÎ!{/—§eœ¦+†ÞIS·qÅ£í'¼›æéÁðV«ŸTy;W:ózØÁ‰ý›Waú¯ýzXòñdŽë 1_æÔ2ntA>µË; )û™cZ“•+ô,ãKTú…‡ãge¶yylJZ@"¦í Œ| ­,Ͼ|ìé]å]ØßAî51;61_¥e3|"f²›�®7ÖF€®­Ð=Ñ~úŽ-ŒÂ_kR‡YÅ1XXU˜µ>I*`ó¹aÂ[¡æ ­2p¡æËQæÍ¶½c^¯á«€ßÿÝìuÎsâ¾ÓqYßi¥Î²¶-ñ„áI{7|òFm>'’ŸÐOvNz'ñ|*ƒw~}3Ú\@"2Œ^ÙN•{¢\ã÷èHé¤yö¸œ�¤F(/·„ÄWegÈ}8›ö˜!>Ÿ_ýf©"-ÌbL  +|ú³6¤Gv8*ê–Lnh}¯†æ[ÀÑú}¤§§;*¬2W$ B z*£r>íR±…/v8f©ûN€÷êP+˜ß'´IîâÊÃóÍ]®”×¹„Re,w¯ ®òeèûQ’IFÍÚÔ"½XUw³&{ENcò’^Tú#%:‰îšÚh¹p ù›Æùý¨xΩRx›J�ú8o½gµ»¾»U1Ê¥…rãML—Qš]¼• ËeÆ™@¡u67´Çü–¾’KÒ´±\ eÁÍlVV÷ih$9m�’*çÓ›úºÓ'Çsª.™2¿½ËPìÚÀû,ëDÑÏdé&A#è³<ùXÒï÷(Õæ¬} úÄ¥ª3ê‚îÅÐâ³Üã`ÎwmÀi:‡R[ëìðä€|ãdÛ¨Ç!6Û¡ý„"‰›íæB,{˜•誡äcÙÕr*±›$j=r˜B«@‰ÌÊô>m>¸OgSÂlWš¢fL1¶1“�+ú°Ã�™ºxãõ ip€³6àzWþˆÂuâ— Q3E¼Ò[ÏæxÒ1Yâõ9£Àf݆›qFKrx^´'xÓÝä?ñ·S-{8*뒣⠨×+ãïd¦Z¦s{Óø¶j=_Él"­ÂBÃ’Û¼hÜlÔœuû8&‰ä϶yÙRã=)| ›O%®%N±UÚŸêD†Þ¢åÿBRw‹ ¬¨GbMnum Õ¦�Û�•]™Î!Øœ‰ ÈT9ŠÚž0ôEêŠ17¹.¬óÒãùÐe6º‰‚uN¨ËÚrfÖ—¬Tðb˜k0€ËMü× $é‡î?w±;~s¤, è*ÙÀ•€â ¨mê«z££öŽ2À=åôrá”]ì š4&•Ñ–Ý+dÑÖ¡�{N7L¿TŒ'–Ï»HšBm¡ýíß9…¸vFw׋Y…BO¯ޤ7ØìõRgî}å£ÙUù†xLÁZe«9©û²ø‡‰SÎ]×Z�bTÓY4“y¢?°§<솷z McìÞkñÖ]s刜9Ê6oðLzwÏ%ñóJÉ‚ôø)p¨<;7šzsÀJ\ZÊÜäÐ%ß0sÁ‰ËzßÌ£6kϲ¡$a¥9$£c5:š«DðlsÏ�3;šd«Ú…K w¹·Ï*}" q0é¾_òFY²õH •ÞqËŒ� ü©;‰éÙ÷³@à«Às kK‡YàÚZt뺃©&·|EàÞ£ë-Œ±dü_JXZ3ý|ö~RÓ�kåP ßø–?N ®ØÜ=&ðð&LV­°e7WHÉS :z$n¦ègƒOk&;6*⯗ì±NX\|ߣ2¼ –•3øð£ÑÜ?ËÁ],ë¹N<¿sX@t\i!_rÒÔW"~ZºI] Ñòd_–î½ßÕ�°jôˆÒë¹íp™vŹ݂7œ†Q4•€'Û~ÁຳÂ*�@úýpª±Ä„œyŒý{±ð¹ƒ ìxvûþØôe½ö0$xëf¢¶ƒå`Ð�H„Ù÷Lá-±â'á»Í6<ƒü…#ì5 ÊS�{–r5;$<1ƒì_yIÎO¡|W2àb}½Hæ¯ÙJwœœ;Gôå©,ûWze–9}ÛË=ì:oð»VLr¼vÌ-XYÌa=;Þá<é,ÛBdî#$½‘,}‡Ð³ØI®À„'äwî-ß3„¬Mç?J¶;ÔÊË£ë†PÇÎlûo„ÇzL'æT|DéærRWù Í©¸ØŠNò¥ =ýžšGsVsÙ/SùhdÃð"TCt_âá-¹�ÜÊ|›k3–€mh`M,³í¹N·Ï´ßpá:ÌûRõ @­ÜæÏ>g³À=áv þ,j¤8ùâÆ`ê·AÏùÛoH†Væ"(R’i SŸ•%û”Ï›O*¾s­½:œiG«œéèƒGÁ²÷�T¬B»§*Î&Ù%SÞÙ’5ü ñ7쎦fB(£ŸfÉææ¢¸ D쯙ve¶šqìÕÒî{ígØl7Z¿–áŠxÙ¹ÿà+I¿Vo¤ÂÐ,^Y�¬—=9²gòNZýÒƒ¼†ÚÌŠêâݵ¯k91øEŒŒú xï°w¯9_Y©íì\2ô~%ùˆJÅ/¬g½ÉRœ^†åP¶+ó$•8}¿g"‹þ¸€ëZ³³­¡BͶ¬H÷£kQr1{FD©d´Ÿïn?10ÚÖwiÕ7uÒÃ$"Y(0¾©i¸§äu“ô'Hù1W%¼u(1pà,èºæÙƒÏË£BègL™þzCÆ)JÖ눱^ÐéÛ/g@-f›Ú¢H"hŸÒuD^@,Ñ�+KÏKi‰ØGîÜÈט)Í üp�±P_¤NŠWãÞÒœê>KLÕ«•Õ¥`P�ù.LÆ£5»“ùÉlšŠrúó¼™åUòd/›uþÙ¸áú¢ø ãç�ìÚçÀ9Ù=ÌføQfÊNLìÕ‘ëjÅ_oýle—®î)-p¸¶Í`9Œ Ôxsh=XRàëÚ`‚�Dž7y"Št¹íÝSB>º×ß5±?sõ'”ª«níŸÔÜê�½bÁ÷ªoD°x ¯ ›á]X§qÑ­ÛÍýîÉϽ�žÉÅ ¼P©n"…Ÿ„R$c·&”ì-AÄREѨ›Ü®=åºyÏ�7#–|ù&¯Ó¸Ó×AÇoXí´sŒ8·^i<L5ÂÐÌ]CS�’zYÎè´z+UÛæ_€Œ#Ð# Bf¢.S–Jëdz:&|Ž„Gb={: —„RØ£ü í#•ósŽwøÄ¼‹J8âçÛ:T‰b§R·÷ïíì·ÚMEǽÛ�cl³2s¦o!Æ~LÁæ·™Ô]�–Ò¾ÎÈ€–”)ÐöxÜ7=mømŸœlÖ€9ÏXÍ1ìq3"oZ:ë†ß!®©ãz­ &¡(WÇÑÓ ¢½„ÛÜ ¿YDp~ m[º=œJ9¥Ðr¥C½¨c×ø>Õ7 u·j�Ý·°¦ä wà´;åõÇRõXAh)l¦Ø�xòiÊø‹üiŸÀùuaš³©Añu²÷Ø¥|äàô¶ÛÀ†—I KÓ%êP÷$cLªRƒM®�±¢ßta˜#~Š+|Àc‹óg¨X‚ª\#ïK„ô,íÉ))ìÛ×^#õ5¿�¿—X. •2ÐÞÈ»êÕWµS~bE”}mÙòGB5ß‹¸ÛîaE÷")}>7 òó–s6ß»Yî•/ÝÏOð “áµ+4H#“VRˉQRDy:�³=ØÏt=FU—–©øOßµ¯*‡’}÷óŸŠ\f ­Æýǹô~66RKŒßÜ��i”x�®*yÁøíäù8e»ãØ mb¼ÅVØ\½”G¬R@gF�ë³Ã‰íx4NÂtâò½{ú 4X±à§�/,A P�f?ü=ÜU’Q�ˆÓ ƒ¬º­X1PÓ87’š|p!-T¿2Ð]—¤¡f0qþ8Ï™oó¾îÐPÉ ÃJ™–,¸[d»BÁo§WL"-þ†,Zg;;c%(!ðxÍR·Ù¤÷Ç“­\ [¨”*S²5Ú�ÁëhÖdÀÀl˜en-ª7ÐW*«)jg\êùñ·¨~|­ýUF-F�# ò“ 8NîÜQʽy;^HŸÚd¨�É ÿ ušð†šCþ&å£Í�ká& …ΞWDQð²îúˆFY}N·2Ï^Qèk˼/–i÷ÞúÕNJ`¢wÄJø´¤�/Ž,ûçÇ BaIÕ&W¥uÐ"dRSÜ!s� ž¥ÖU}ÊîV‘Ò±„çf̺о�­Û;¼(oÕÂCð–8®d»-ÛEÇm~x¦ø­á–cya*Çàzµ¥î[ ©aM*§(Ȱ%2O¬èO±þ9�Ñv$+öSÆFç†Õ(‰JÁ¡«ËúðÖ,åÊù”õ“x±ËH$6øÅŠý£¸C•ЇRߣ¸:TS�3¥Á�ºÊî/S�ÙŒ%,y¾ž�¨“¨Ï{°.eßüEs²¦­®ù“¨k@à&¶B)Cö{™oóE»ÆA‹°ÏbSe; xZóç¯ljî“-‰Úïñ(²Ès—é8ÔmsßæÝòL|¤ÿÎ Vdq¹/-’üA÷æ7ÂÁY±´Ãxî<@‰©…wMç[õ:¢FF#`³†L@.®¼T¢UvÙ3`ÿf}E©<…¹? ùêY5ת/­ºº€2O¬·e°™Þc9SÑQ]2Õ‡£¡YR#Wˆs÷8É9›k1Èð¬¨Ô­´�€É± Qmɸ §¬g½5©o¶ í ´nWqXïïN'‡8‚�s«€!w+.oÓç=¤ð Ÿ| �аz£¿p²­Ñhó²¢=yÿÀê!7u¥R«ªýÞw7ƒ+þ�…9š–óö5f^áUÞnpô&/šZÄç™Î.Ô U46}JȨ^:cÁ(Ðî®dXè¯Fº·j2‹F”ô[<ü Í÷$ŸËé$¬å72°ÐnRÔ·½¦nF¨HÛmà临Ûoe f¥)y²}Ï÷ý AˆßÏ}�à�‹ k�Íôgö}G;Ù»æ52ànÓÝ*ŸÎåå3rWlÅžZð*’?¨ÌýeçCÝ„€fǃ\•�(yGÝÜE'ÊŠÂ ªªèY—ø°¾Õ^mb†æ¸I[+ïëM˜9Ï�ÂÍvW “ýë@†˜üH*+˜®¹Ì 7Ë�úf�à $+:úD9¥ àGZð-MÔΖÜj¢…?Ú j(zo9ÍîªI²Ãæu‘r¦øªå°Ö†à�¥!o'ª¾Ú@•Rdí¾Ÿg±vß,¶µüVÃÎýÎ"ßœ,árªè>ÒÏú«þ¤£¼@F³3m-ýöðK‰ùb^ïÚUmÕQ³é1–¹,ÇW)C¦X DÀ”sxIë™ó±Äsb}J¸7»ù™Úѧ0>j´Óeq3ý8“†�‚pšÌ‰òÃH ÌyÜl„õ>0C_³ÛiÁîúKÆPeýÍEý�%œl7/ëÙŒˆ±Èc²QF�-ƒmž°tʆ+kéÁ~Q—S‰ÍØ·’Z39»Ù.Èâ/¼‚Á×L‘­è·×%o~¾]íþ°$¬ô9ë«÷ôk­�Ê‘ª‚Œü ¤XâeÍQÑÅajÚ§‰Ô®×ë9ÕÞìG-•~qrÌÿ€ª.© endstream endobj 102 0 obj <> endobj 200 0 obj <>stream xÚ�tTÔíÖ/]Ò%È€Ò9H#ÒÝ)Ò 00ÌÀÌÐ-Ý-�J#¼tJK·€¤€ €(Ýߨï9ç{ϽkÝ»f­ÿ<»÷~öï÷°±èðÉÙÁmÀÊpŠÈ/( PÐÒ >â"bc3„  à?Z"6c0 �Ã$ÿ—]¡Ð:E í¦‡ÔÝ¡à#PT(&)(”ø—#! Py@ìZüu8 Œ$bS€»z# Ž(t•œ¶\ „„ïïp€œ ±ÁZ ”#Ø]ÑÀm!`”÷?Rp>vD¡\%<==ùA.H~8Âá /À‚r胑`„Øðk\€6Èü{0~"6€¡#ùGm·Gy‚`Z…Ø‚aHt€;ÌŒ k Ô4:®`ØgÍ?¼€¿¯äþ;ÝßÑ¿A`¿ƒA¶¶pWÌsØC `€Ž²&?Ê Å Áì~9‚ H8:ä‚@A6h‡ß�ƒÊrzz¾¿§CÚ" ®($?ý5¡À¯4èKV‚Ù)À]\À0’èWŠØ}ëÞ¿×ê ƒ{Â|ÿœí!0;û_#ع» Á nî`5Å¿=Ð*¢ÿèÀ(€ˆ   ˜v€½l~%7ôvÿ6þV£û÷÷u…»ìÑ#€ý!ö`ô‘/ä î`ßÿmø§Dì ¶(€ Ø#úOv´lÿGFoñ˜ ¢�þúýûd�Æ–õþ�ûïå èšè¨*éóüøß&yy¸À—ï‘(€OHDˆ¡þÿÌ¢ ‚üÝ…àbÕ`öp€ÄŸfÑ·ô¯†=þÞ>çßÄàü3—6�X0€ó?7´E€ÿß0ÿòC÷¯,ÿ€ÿw?ÊîPèo+ç/óÿa¹@ ÞÛÑxuG¡±¯G3öß®OÁ誶ƒ¸»ü·U Bs@æý÷%B�Ê/°�.eëø*ôF¿…ÀÀºp$ä׃à þ— Í*[gô£�Dãñ· Œ&Í?K*Áláv¿Ø%$" ! o"ôŠÑ’Àˆ¦¡Øë7‚ü08 @�ç°‡#ˆ~íSX €~–~)Ëè:(Oøoù…lÝ4Í~ÝÅ¿äßœƒ½À¶Dó³p[©P§šÐÖ³j9O¾ÍQé)¶Í§\|¾óˆ6÷ Rü4®ªœç+ˆ¹´Á÷äŸ>+qË.0_û~kªÃ�hNÑk¹ô»²JÒŸØl!ú8NÛ7öú›\m/!#Ÿ¡ì–ßµ›Ÿq°3vf‡:[¾›»8©nÕ™g�ŠWmoÙâpøì¦ÞV•¨Æ�«²I¾8£Xóàâi¶W6¹3t¬x(>&nÊ/²éã“)Ê—c·ÌêICÛ6²æ’ „nsúljëŸ!v~Z²³�IrÒÓ `S«ÅÄ®4«&»³$ã ç|R_ñRû)ÖdƒäÕI†Üê@ÅjH­z&j3Ú�¢R[iïuÓƒrÓë+ýQ”^u¼�jêÑ�zžaäí~(·ÀûIt)ýi/ ¬ž9“æK®ê:*¥J(9Ì镤+ ;x™z«™Éð³$ÎàL�i³ÌÐR8˜Î€ç§Û�íšF«m«CÓø¶Rn¤øøø�|µqßçnV.CǤ¢1K 2/¬tœúŸ½Óx;‘\<ª+1RŸ]0Þsß•ùòD5§�5b˜M;®EJœÃæp�@�*δ;­3Ŧßn•IJû°²ñ ù(rD>IEæ7ô,¯…(sA%ýïßV=Ú0!JÂ%aÒò8Ã.aSÑ>hŸë½Ë;YÔ&`=uÊš½‹­ŽKž¨#ôH|!‚ˆå³PSyn»Ñf/¶1T4üShnä^ÒB¡¿!€ôæKIi·ì!!» 5íJ-¥¸#Q(ͼ¯¨N„qE3¨Æ“#GZ§éH“ÎÖáLwýÝW�$‰wÊCÙ>4läÏËÎ(BÁ~ב:éS6û!Uôí/¿~5&,Ö YO¶ljì ŸŽhyÌ¥UÙþù1–Ë N\‰Ôð—IŒÉd•þ:v@ SƒQê/÷]tCìG„«§›¹˜2üµ¢²u‹·„Æk @‡¸áuåãÑ�,ÒïË®$éÆ þ?c}ë‹›QÐ0Š@Ôuž•=™Á¦4‰¦4mg z¸{² Iþ.†¹ÐD‡¿mš‡�ÅXº�6¶WDöšÏ(L±kÂEëÑhÝni(Áî9}d{aÓz •1ù�þ,¢ôŨ™¼eæÕ(ùËÇ»­ëõ3ü–ÏØße,†3&—$�O^“œu·´'5oU‰;µûЫM-î(¤³Á[¦®Êã³t`â ?õ¼�Rl}1Ä�7N.”Ä©Î2tè7?ÑE ’“R¼=³—ó�zÕYb¡f6„úì]p�âºD`@‚‡—Ïæ‘g“ÄÓÄ31,ÿܹ¯‹Rнo>3k…MŒ�onF¦Jïy_º^t¢æ.ã£~X]¥ —|‰N"K’#¾Ð²àMëd Cæb.ך¯Êº"&zФ–˜“ ¹B#ó#ŸÁ€î¯]íÌö‡ö Î]¸,PýÝ �ŸA1±V^a”­ÛV÷ÞÃ36û~‰—¢jz�wªQu‰0÷<~ÕšèζoU“¥Lby§[ºp#i›:m:w \!ܾ-ƒ�on±¡£VÿIëz´6Ö(Jöh¨¿çqS„¢îŠnuß§pk#Eq",ƒ“êì_õU’Ž@i CF)(¬ýØ�–Xšâ°ka›ÉæD�5l¼ÚÍPÓBÏ<¨�ˆZn8ûl¢o²Gk$åX+>- ^ÎüÒK³¹=&j2À}ð¾EH‹ÕÄÄÂLj‰qþÁ2Ù©†ûY 1ýð3̾<µ‡ fŸžñª†GS¾iïU[x"”5OÌõ-ÿª¹ôíÝŽ7u½>1^±¢E�.)a´ø&'ÊÆÑ©' J:^êáDNÊ.E¡Ž\ô&ƒmدgÆ#bÄëCú™bv^ø~vÇï&‰ ³-äÞ”*Ë,Øl®ôc@�+nüNG)d_÷LðQ0:}“³_—ø«ÝøÊæèU-!¥8–áå¢]��0ËŽqksƸæmê1mÊ 6.š Ç‘$2ÅZÚ{Ú«òïÜãvZG°³ß7Ym&‚ÐŒðw#0<ðpqR˜Ý,·Ñê¡”tÈ[ÛëêŽ8!ì1ÖùF Ýú’²PFv¿ò�ß„·Ë)ŸðïÐ�œ;öaÊ'^O/HãÚÊÛþŠsE6š°Ä‰ºñ%„j‘qìS]¿êMXXaö÷ñ6#½ÿR3(LÇÉîÉ9£4¾eµÜsÛ|”£ôÁÃ/3“§ÀÐr_ㄯÀY&öÇà÷¬©dþ5);_®™5WyÇ»<ÂÛ îF„w¸kÊ·±Ö$/\RÞH=fbC>ÇÂGôf}PÜ${„Ç•]øÄ)“fƒ¾þDDzøî�¡«Gœb˜ez"uO>slÖ"É‘×ÃŒ¿öxì¡G^ÉIô¯¶Äºª¤×é�¢O4Z >áÕA‹[’ô“Ì0…¢å¡OÌT_»…èqûš­�·"2ŸW¯�Àn´gÛø]ÇŸÄÕ­œTw ÚΧRæõ”ÜíÙ¼Þosº°`bÊßá´A¸=s£wÇ´-WerèŸïÁ {í*–ŸRP)ùN{^OŽÆ³u/|fæYÚ�àïzΜ~4ãï­N †NÅA)ÆçlðV#¡x–ŠÝbg&G=™„ÃWe\[Ñiìê¯î3SSMñ®ö/:Xаî*»�s|å^4ÉâŽO€”A#~Øk§R¥ûº™2Vq`Ëö¯ÚáœÁ L�¾×¬=ŠG˜·½Y„³Â¨EÃg dw%²nMü…ÁzÄÐ.+1ÙT SF£žÒv�7r¶ÍÜãT¥r]æÂLRÚS¾uxÌ·{¯®pDŽ+6:5«ºæ¥YŒEøï´çú#05Ö.™h߸=ß0ÈÄææÐ¿�Î# ’lD)cZùëóÑíÓÍ“_g)'IÿX�g’â6}ٺܕM®�Ÿ)ÅÏ)òÊ=ÜŒfLŸÝ#C¯¦»—~�ì}wi�Z�Ä'Iæü*屨†{lÖ¼.´åµ�¼]ò-ƒÕu$#]ë ôpdi+±ðÂt}æ%-Þ®J=·œÆ­?³ _ý(ïUª³û€¼wÍž²êR ê®&è›ÍÍx@êfTfÖ��ã;;Om˜«-¸ôâ(æœìaø C®ŽÁ䛨ÊL©QóÄO±'â’_y}#kj¤¯±ÕÉ”B„Ìž¾UlöUìûÔÂ$ÑuÂÀ¡´œw:¾yùx4tJ—œ€ñãªðÎõŽñ¦ÑlRB‘7�Z—ž+«Ýª®&¨2†Y'cœdyä´§}+Ý”f›âmycj„'DUzkÉŸÃXÚ Ü�½=XEÞ-*úÍbà¾7xº2ŠªçGÂ>[Ò<Ð9ÕЬOgûÈ™}ªu^=?ŸXØe”äÐìc§YÊ€£ß¨S•ÈÆÊ0‘„zý@\Óý�ã™Ù)"ÁJÒ™Ï/~nÐwY1zÂÖ:|wZõäpaØÅ¥M*)jª/b-ð•HΫI“à�½Æ¹· ›A­Â’œCæŸ _?cÆG>î¨Ío\}Ñ­Ý$³J¤õr€x�d‡£úƒU=_–!;Ž‹‚¹‡ëÓY™H}U¦Õ,½ Å-¿»œöÐÝ÷ Âo'P²WÛoܳ ¶¬Ÿ­LÓ´|�»] :„ö¸­Ut&¼UþþZlŒ·Â¥ë³Rñ×FQ‰'iSW%bªá÷äÒgèÚÀG•¾ŸÇßæÇÉO iòºêž¦,CG_Þ±wÈ“R»i[éJ“)`Í\”Ÿš�Rô¯!ÖÜÕzB¤´ÄÛ+l[4Ûå·CtÏ?‰4’wSúâK5uýˆ��ƾÐÕ>Vkô¥åæ¾åÓS#9c±·^z`šûJêÃö"˜úBÅÄNÙËý¤uÓ0Y,e²é,5v;¿æ4ôƒfc>ج]™kXp¦8ÎÚúHýxŽ>:4„¤"¨9 Pá6!€KÞ@›¼üHf.¡/+ w–Šê52±:·'Á Ðß8GŒ'ù’ôâ0ØcŒ@|#bÉyíSé–�º—öü½Òb¦?ýC(ûsêvò,l_}c™u (‹“ñg§&·1y�Ñè6QŠyt›Ê+Éåz4áüÒTt¦HéH¬ Va“GR#iúkTÊ»µó¥e;m‡2 �ÊhóÛ v2ÆÈ\pIê_»‹c˽‹!@ïõڻ˛xåÔ‘ÃÁžm Pܽ­²ŠwyÃn@å.=û| ÎjoKLš„yÚ÷¯²ï[³¿0c-lröF2Ö[Æf1*1áŒ×^³5¾ã$¶W÷‰þlyÿNvGZm ÖA‰> Nh$!ÚJÛR°ÿŒ’t6Ü´ñÕѵ)cÈÔ„C˜]7¡‘Ä”Àg¿WGSÆcm†V”´Kì÷ZeWІI3/}¨FUæTÖ¼ú·‰°¢Xkꋪ”O�á¸%µ�y¹“âªî~Ù‡³½Öî©@5ÛdÇr²joS© Xæ¯z_yecvФ¾%^œFw ÆÍÊ΂4:š[AyÇþð‡¯Êù~Q‚Œ5´�üewWH¬»ŸG¸)]3þYgwžùI©��R!©&üÀy›ÿ:²gB;�!Ž]Ö“|Ò +Vâ\8t\÷âGuøÀÄX mz}šmNvà¤-ïN?Œø(³³½mŸ•‰ûø¦Û‡šS›3o´û² ;Óz?‹“¯¥lÒéÅ…èt ·Â`VÉŠen"µ êá„e›þÔ­ý$c¦a~ìf·6UøÌsÿ„<«®î °/„G¶l#ÄÚ¿hÆãÜÓD¸;¥‘M2Îs…lFòp^b*U¦ yµRöªÙ69àå Ãü¾}úÉ$Ü“lŠ•ô¼£µíF_7(çuûº"ŠœðR•%‡k—íïáš9÷µy:t5×¼I b‹¹K»c�ºñ`U¦ÕÿîG�̃í ܾÈ#-¥EKqêi„úDärí&"V”i¥J|YÏ‚¯c9(²C"UÔ)ºÒ7Ý£6”›éÂ×ç%{ˆ5µø!9iÖ!„ÑE«Í˜ 0oó"ƒ§²Ø’]À3{V¾£p÷_Í}ûö vß ÚJ�šªø—ô v�Ô|Ó'n`ô#™u‰ÒA„ÈäAUÊcï¿ÌmŒͰw!ºí}¦�º¢>ñ ù“ª_‚·!1+m¯�¼Þú%žôÐO=XŒ�×ûÀX%cpW/ú¬ð³¨QÔåÀú§jœpAežÀÀRßQ}ÚzsÔJ¨rKC¯­ˆŒÜì±y­¦3PE5¾ÄõÑìä,('vú�\ÌW`6ôÎ8cZ >,ç“îãÙî.hAåQ «Áö‰¥Pœ†g„Çô¹œ”Úòä¼t}h÷=,°J‰ÿ\Ï"aÈü.hRóÅ;¥LRÈŠXkã:‡¯2£Ðµ÷#Ù[Ï\“˜‹Áe�›C‰³ÝQiV[Ù¶--òdÃüÛwá˜ò·ŒQ+Bƒ¬ß•¼^ÖȩԼUâ–ßq)eüäy§`É–w°Ú‘÷åãö-^l7<÷W4E„óÓ¼/w:ô1âħ ãÃxÆñ�œÊØÚúÖf/ç¶»n›/Õ«sƒ;kžW“uo�~8¥ßÄ?UÝMlý �ÂÀ/í˜DÃ"fv2kÊÄ/ï¡!"ì0RÅ¡”zºqR´²t./A,êð>f@Æî¿7¬¬™-‚ú›lç¶ÈH�©öW­0éêp+ ³YM�àëyGQñ‚y€m˜!ü—ƒ�¥FFÍ 2 J²Øîâõ¾Öc�ÆßX>Üc3V<,�ªˆ‰oΦ ŸÜjòÞc‰”¤-v²æ/enHûÊy.QóiýÊŽ�¥8UP*!á…€fOÌá“nðu»x‹\�'�xÒ>|\å·åõvLgEO¡~° ͙Ÿ•”T'³Í  ·¤“¡ÉCÔMk?¾�n&º_~5*õ^•o‡5$¼×ЎʽÒaºŒÍ]-áæM'}ë6–q„ë‹x‡Ê,ezä÷4šÞÈrÔíótºxgˆlÈÞ—tÍ›¤é=Ø!pk1²ö!Z%xu@Ï.;R§�’ ‰Í¿9“Æ­¾s�°p ÿÖÕñŒ§L£o1;8!Z¹»æÓ#Ðà£ïxnáÛí–xôž½îŽecåtÝÔk->ÉgÕ×ëÜ)6pzE ñ~ÙÚFš©˜”� “åu`ø2Ù¬ÅoÁj™r§úVS‡™ýè×8tl®-ÇÔ©\–5\¯KF ÅPøÃ‘´…4ˆ�ðAðõ�MÚ7=�¾G6ç²�}�S›é±[ÛC]IT"2VÕ´V.^ÂÛ¡ü¿ù•á9™¼� xW_õ´-]†õ`˜´ Œå=¾ÚʯÒ1AD3½M®&Ä«^?ûö¨¶-¿~){ü˜å?µg>åcAM]ä½þQÕ?³a|ï&Ç_5¸þjzh­–g4D¾\­%¤&ÃJ=^Dt[)þÀ¸Š‹ºN´–´Ù>§•E˜T mÜM–ø$m÷}¾¹'Ý…”{ªÈMË0£†Ÿû}C4C$Më'{@Í–LÔÈ B¥N5S7ø‹ÔRÛØ*ñ³³™9?¬ÅÖùzi…Zr«¸ï. ä8$xªîî7ä{ƒõHöH=æ5=ÛŠsè]¯Îvê›Ã Ï)ö~ÍYÓN8?S� 7 ù-§) Ê©b ?øñ‘I#�C›¥¼Ïûâ>u…ú”"ÎóžÐ‰¦ì*‹m…9¹ô–å[OQä¾Eæ >Ow›mûXêÖ3z`¨ø±ÐŒû%Á}Œ†]Òn‚·âök•ó«;1¯ú÷òŒÎE»qò*Ë-ï» IuûF½%JçzÁ{¡rAÕë”çdEì�Ú«gJ. Ò–ë`^]ÔÒe|lšw3`(ö=y'¬ÅêÇ�!Õ£á°Íg'ç8¦‰¶ò •Ы¹ôÍ|[qM…¦`�Å e•°ö#Á&þÈ"¿VÆU�Àp[Ý&ö(DÏ$•_éaˆ§’1vy”$–£Ïÿê³ç endstream endobj 47 0 obj <> endobj 201 0 obj <>stream xÚ�xTTíÚ6RÒÝn�Τ¥[ºA$†a€�a™¡ARJºA:$¤QR@ZZAB) ô}}Ï9ïùÿµ¾oÍZ{ösß×]Ïs]{fmN6cA%¤=T‰@ Š�d]cK‰ �@¢Dœœ&04ú·�ˆÓ ê�‚!2ÿ�Pñ€‚Ñ›*�ê"À]O8 "ˆHȈHÊ€@€($ý7é!¨‚½`€®p‰€¢ˆ8U�î¾0'g4¦Îß·„‘––ø(¹A=`0У�¡n˜Š00FB`P´ï?RðÜqF£Ýe„…½½½…Àn(!¤‡“<¯à C;FPÔà êüлAÿŒ&DÄ ˜8ÃP9Œ‘Žho°Àà0�„x" ¦:`¬¥è»C�uþ6ùWº?Ñ¿Á¿ƒÁÒÍŒð…!œG è«ë¡}Ðá𠆣�˜x°Ûc¿[êJ†3áŸùP˜;%„‚ÁÍ(ü+ f›Õ*H77(�"úÕŸ*Ì Á컯ðŸÃuE ½þ¯aÇ_c8xº ›"`<¡Zª0Ñ¿mNP4 ’–� ¨ÄYøW_wèoço3f†@w¤;àˆs„b¾ˆüQ`/(€öð„úÿ§ãŸ+"ÀAöP'‚èßÙ1f¨ã_kÌù{À|+†~"è×ç_wÖ†9 pßñ°ª™Š®‘ÿŸ‘ÿåTVFúþ‚¢Ò€ ´‘$%Å�Àæ1Ãþôñ±ZG$ ýW»˜}ú»e¯?àù#^àŸ¹ô�æBžý>HÁ\DþÏtÿòÿcù¯,ÿ+Ñÿ»#uO8ü·Ÿç/Àÿã»Áà¾æz¢1*ÐEb´€øo¨9ô/éêB`žnÿíÕBƒ1jPB8a-(r[tû/; ¥ó�:ÀÐç¿Xó—Ýô—Þà0Ô‰‚ýzÂ`¢@ ÿòaDqÅPÑÂ,"îò<¼ã¼N‰É[ðã(ÞÊjWt¢e”8šk³~¶ÆÔe;‡ú‘ ƒùŠˆÉÙ&¾ýó1Ÿû¯rC–Ó5 ÐXjýëʇ‚…Cߎ_9AY�ŒNã’ÑëI†,dvV¸VÜ)æ³—�${Ä6Ÿ}*¾êBmÞ“ÞÜ€ÒSr¶t&tœR~×.öcK6ŽUô°å}òxJ«LO-Óñ+ìǰø3åŽX†o¾ëVñYÃïß¿ÎèÏ;*Òî­•¨‰ b ö»Ë–?’<È@“”{÷ ‹KYüT¥"-‘�¡Ä-‚kÇNrùûtÑ@{Ò ˜g““žJÈ ý‡oš=�â³rù=ËG̶9&ß„Iè[’£�ê28”9k°N‡3jÅླྀ´¬^C×ÒOÝidYù™¥öbs,þÃ01›OôçvqÙI"¢Öirp©ÁO•% à¬î#Žæ‹—wÒ*FN*-=6—UÏ‘[B_Ÿöê,n¦ N¶Z^w ÷D"9öYh¦B-:³wûv’^h‰Ÿ¾¥0ãS“@×kÏ!»myò¦ƒŒ òq Ú»4dï)JÏO°'˜‰‘šPÌ™èlbeêZÊS ÔC;ÜÝž íH’óÓ s½›,FÙj©G¥{Y­ ÓØ'ß¹R×3á7ÕÒÞÒ¡À6ryƪžoÿ¥´f<�?N¢rn ”–,õð„3{9Î ÃøÇésuw÷n6žÁ˜!|ËQìû56AFÕŸ¬+Ý"6ÈßÂʵ+õ‡¦âÙ´nÄ>Ÿ~þ}“þ«Å[ô´¹lV÷›/™ƒžŠ<·*Ñ|oʨ¦o˜>ÉõXÿúÕ0,öQ½Ž“Öu,åƒ[Í„_<…NÖ4W*ï©Y“m`[4[žøA¢Ò6Lf†lÈXòjËÿœ¬ÐÓ�zS65·^nä�¼@øÀzYU×}öªoÍiÙt“F{×½ŒTÒæKps U�‰H§mòiGrÉ:])iãìá›JZç6Ø• YÞ ÙT¥ZCš~®<�3±0Ÿï‰¬1C!Ÿ�‡M ´ýµÇ*FQŒ�ˆ÷G-k; ÷„?{½J·*lý>Ïڢé_¨¸›¥‘BygÙ€;þîÓ‘¥ ¯¤�ŽFvgÓ2]…“†]…Õw¾ÙpI/Ò9:¹%TàºYŠb±^²¸Í¡XZ´ÉÇ)Ƕ€Ñ×°42¬UŸ7¼‘¤$9ýiŠ“ôa¸qñE²‘ßSªãcÇmÿÈ  Uçw'w6Šü³²Ö”ÓFvf/^,ä£D¹UŽ}—×êlŸM?S´†°J¥Ô#%p‡1|º¦uyÛU_ŽnïG•â¬)�\þ.ðÞ©öx™î“+öÛ,>RI‚8V‹lxŸÏ.^ŒÍoMßG¶‡ÚÌq¼àŠýx|dM!OKØx�jå %œ¸¶fÛÍfò±/LrŒ½Z½¿0ѰJÒiÌ^(›°•véiƒeM¤$~”%¡,G±Tä…XÊ2Y'¨ÉJ¨ï`4yVAe-Œ7*è590¤X0�Îÿ˜9FzíªsG -­7N˜ñ¯$Ñ«Å:pæD}«Ü>̰ZçVõŠiC7>V›-nŒ †uƒ+²­O¶fˆ±÷ŽìÑ…ð”Lgr‰¤ŸúQ^=¶exFÛo¤�ƒ=6C÷3ÂW‰Lg­g¯dKî¥oulxͳJ»ûRÄÓ6i&ûºË2ªÍ­). {"¹2‡FáÖÕïsìý4TØ9C ïK¼Ù¶êÓG%âFJŒ ¶8>½h•ùÙù–w¨3^íÖüV‰wuïÇn&ÁÖfâ×¢XÂLýç—øÀÈ…n¦ØùwtÄn#�jï]2öé�J�¿ˆÒ û$w¼~â´m\>TLæ ð¾Þ‚—Š'Ì2ìQß™«žy“åË=õù;[Ê� éÛ® K½ø+F{<‹3ã6¢óœä l¥Ë«ÏnáíX±cdÛð·0äôëÏ· ?¶ÑÔ„úæQ¤$,zݤ<à˜X\ÀÚ—ªÖ‰û|'Yw`wN¸æ”…v=ÿçRš±` Ò¸í¥·¿É®!H\ú™d¿ ߺI¤P‰.ñel*ÀfÏF«ÙÌ—•�òj¸d¨¶#“9µß²G�ížÜw vîÊÛ#º@)O7}oZ}ăŸð»†æ¿)�Þ{á­Ñª×Xn ’}[©í¹7Ç0Þ3¾h9V\�¬&ˆjx½Ê0ߢ´‘Úúª ïªÓ¼*´Â2 ñA�é±<2ˆæk|…V$”:–vay».FÒ³žkŠðJ”'ÀØã&zB9@,ó?B«zÍ`Ý””Ñ~Ç›RýÝ%ò?]|M²ãBz›ÌÜ?e¬2<({ã¤2Ì�tœt0ÿ²-ûš´ßõö�&Q*ËAÂ}è‡mIý™×Ë�,|{Ò±ã3Z� ‘.µ¦{Ú§T>.…mB„x£çüö"u³Ï¿÷jåÀUu ïህœ5"�'G�Üw&,;Wð ‚ŸE„ÏIc $CbùÔÄoe8D~)FƧû[«TÊsüÀQ'ôsb›ˆâ{ŠlÚ¾îóVPï{ÈÞhÉh òH*¡_ÛÛÐé}œ{.Ÿˆ i¨ÐlLTÞXÏn=±ŽYôÓ×?/ÏÝH¨áà1kNêÏBì¥v‰í¶Ï _À˜ƒ7Ü_žödzã㣒±Å}…,Âp˜§FŸñ~ùÄ\dR¸‡Uzê ¢]PäZUõ&Æå}PUäGW©ñŒeõæƒè »à sÃmN¿ðiú»Ï[ç-Š‹zÄÐZ¾ ¾®§B¸Ó·¢û­Rn³„©ÞR{šìî^«ÎWUþµ~9ÓëÀCÚa !‰¸QL1…ã(ÆWËôÙBækצü`G¶ ß貋#öhM¯t28ÙE–ŸÅŸ¦IÈ;±¨”ìÔ[§Í·b¡Ýƒ½dÖÌí·pïø�Ë"/!bÿtüFÃŒIG*EoVâ’ÎØ éÝ݃£mUXù•Ué¡ êN޻Ѷ/Ô˦‘9Xé·ð¾‰›…ï:NšÆì<0 <»œ �û›�ù?Ó#®`Ћ·…Ê–þRƸñ1…�ˆ…ßÉ])X Nà•\€K•¨8…ÊP¨dÎ×âäƒôÚ¦Œyfò ¡maõr&¦¡ÖPQ:Ú(wµ-[ˆ�ÙJìÌÈÐMjüº1ëæ~´7Ù¨XW¿–òÓöpGi*H¬lÍ�f»[™Õìä!Ç¡´ZQm¢‹Ñck j+Ïßûz­-™¸ØY‰ú¾ÓtwÃí<嬭�œÏJåU”«�ž�Ž�Ý\y¹öY`XÍ¢â 1[ÝtfDçžú¹r¸ºrXßÞ­¥Á=„8¶^Ô’·«àš§+�Ë;Íp¿ 7¬}’bø)+×~µœFØýøZÓñf“”]ê“R¸¶?f”(’»»T†oñ¹iÇûsùÉÞ™éÎÇ q;Z·‚I¾§mÜÍ}ú…›�öê�E°É5ÄúÓL¬ë‘0�B…¨oþȸãIkí^ÚêZѹï-žõZ;ÎEÿJ&ò2¶CÖ\ajŧõÄqS¹Š¿zÆãñ�ÚÊ�zrÑI_›9Îð)ÇÇs9jÆ¡s¹ ;Šb^rk±JÆtÒ�æ,N>Ý@Mæ^Ƭí’|Y‡§«™×‡<Ü;êD¨]® Ô)É»£ �P,è´= î³5•ûém5¼§x?rmofSñÖÏð´^ä”4ÝÐÕm#jj'y0àÅÕ\;|¦²òQL«YçªÁÛÄÀÓ?‰ÕÑ6^wn�ÿ˜_0¯¦¢ÐôqF½úWÓsöví±ˆþªŽ)Ë.¨$•¨Š'í”æÀÄ”­Ó(ëäŠ/ýŠ’ÇRK01n÷ìë¾¬Ý Íæ'¥ M™ÆgOV-5YìERšÖÚ5ý[¼Ã�l,'³Hˆžp¨—¿M×T]82cTp?Â÷�Ìh¥6XæT—kíPŽÄ;]8-ÔО7pnx¨×hÕ‚«5l»¬BphBë·<åH¸Ixg:=5ö2äšÝm̯²šÈì]Õ÷v�F„xd¡ø‹A÷˃)ÖôD]‹ÀÇHÏ»’byAä;�G^«;Ý'AÚKæþ¹ºÓËb s qºGÖßdÌd©)¼n&>"ϼn±&{=\ùf2at™U‚�Áª–¬B›Iq tãŠö3Ω©õƳ°d¹I‹˜7®’Å_Æ{ë¢å}åj#øÖCìUpºÚ�t¢û™”<ê áÜÍçý¥i—Ç×Í 1ë„`pI¢Ñdاž~²ÚN·�'ãXe_xò²o7È^¼3NKïñê9¼üªò°A¡ûnX»p²:»„©PH~û„ÿ�¶át8ˆ�}xºjRn7ä j{y/Ìy×zu®’í�÷¥„þ{¡ÀÇùÁèÝ‘ qŠÃ"³µ‘ŠþjŠ’Õ5//Y$cLQ¡ÙÏf+|7?÷¥à›Īˆ_jx8­™âõ‘‹¿áHˆÌˆå ¨KhêŽ!x˜ö^£rc^*?c‡¤°O×ëã � º,l} ù2^„ø²—c=fÝoˆýÆœþ‘þ|c”©PìÓøšCB#«.º‰L¤Þ—[Ÿ~p‡nöuˆÔPÍ“¾” ¼Ivøè¾nPd–GfšP¯pú(b�ê^ÖmVí(§HÜŠþ­âžŠM2*ÅØ\“êT`†|ÊÎ9 `g¨ø¡èõú‘§jDnJ4ià1WðUŸ”´ÐÕlYû¦=£—2„?H­›_�xH¼4Š .}bÑj ?�p:!ÔRß”QèA§Î'â›ê�AH]DUܬJ>TéKʇ¸š_¸–Utb�XÔr‡=ßg)¥Í%£é¹cZö|NoIJé಄š##�”'κÅÄø%}Ím‘æ@#ͯ&Y¨·�G�å+åßo}ëÖš'Épcà y~û\2éµ£öœWN)Ê1y±cý ûñ'²Ê6† ú)bߺù”oˆ5„y"Úq8^¬h �îü,°Õǃþ°{Kt3“ãåŠ]h  4�¡p_ÉGÝhp¾Âü«Á¡�©º¦k¬äŸ�7p¬cJí» ¯¶ÛwªlwDïLž�¦ðã’F3÷TÖY�çÖG1Ü-üQ¡¯XÌ©›¤º¼M‚.mš÷ ‹˜¹ÏØ*l¿>Ù{¤k¦N3 ÿ9ÆïªõQÔ\ZÞ1=°â@>qÞ×|"†Žl®úÙVèRQÚÀ^Öøéd?q–¨`pÈŠfZ'ƹ;Þ’’¦�w).éJ³ò#åg¾fò},�jŸ±€T-Êg¯D3ÿŽº6ÅúFäüõÑ=ç²­÷$&èa¹ ,O: šß£L Å»KÏý¢îlX®|ã�·ÞǼ0¼R&šã\_|Å`#Ü»×v"Z æ½,=1Ânóqò›ÓƒÒ zGµYwv¹ÃŽ�9¡W ÔÞŒÊÈnÈz ¡þ·/»v”ÃeîÉ™þ-+åZt*éÚW*8ÂÞuynÔøUï†�ßr<3üÎ:©¢sRtœÔBë“éMø¡«”å‘zËrÎu.’‡ìáj)ò£Ͳv¸dýÄ^ß9Ïo.ÖšXíAfñ¬B¡Ø1즌.q+Uxá¾1‡h/ŸOÃ$ZÏ{¾¶ÔÏMØS*ŸÚóo¾Ò�°ž‡×ú|à–ð>Z—°x®BÞ­ªÍª�Ïð*Ò1‡ÇIÑÛÚ±Ô,k¤Çj'èán¬ˆú·mV2%1¯jÂÁ5ý¯©ZæfÑk^ÄD~MZ–/F@ ï©ío�æ\³ÊñóOžáÀ…ŠT/¹Îˆg8)}¶ãé¤èŸ(wÝ×\¾û0jCþ"©vÓWñSÿÏVÓÕ ‚߯z5e!þé‡w|•í%+àl\> m‡×+"ߤ:â.uznìÜÇêÅþÄžtÆí¹?@Ã&¿$öÔG×ÛñÔfæY*=ïL– ÿ ý„Ö:ýÙ Qr£òžF2Ÿ×[»7£ û N¼•�&’Ö:®Œ¯ÚósØç*á9ö‡§~²­õ™Z¾3÷Õæ®¿Ù‰v÷(wÕ%~¡ˆ§ØåzùD,-Þ;�6>ûÔÇɲǻ%ìn4x¾¼ð²’�^´É“(S š,~Îß·P‡*»wÄÍH@]ßZö5óæ}”ásÆ“Ã:c8e�Kÿ)�ÈÀè‡ïÅ€E¾¼ö�SˆJÛï¾uaLøæåú­Ú¾À:ÔLtŠBN—IÅK-r2hö¡XfŠÑtAt²E~H$jîu ;Y·¡yÛ“0ý«¯“I·ùôý¾· AZŽ] ©U–\—+ïæçÇ©>ïÈíJR¦ZÒg5žž¿>ÜPG k­¨Ç¤ ç*\¾‰ÉZ%±£„õø6Ÿ›´5“Ò‰?G›äLX§?°o¹­¬ÕNמxTy9¼×óA÷mð8 ¨.çåP÷Ø–÷ly�ú~a¦ZÍ´ãß^0W@â:ÈW=cnæÊÇz]¥”§ÕkçJQ~‚ðõöÉaØëïïî‹+�|; §Â©óÍû‘yA|nLy�áÞ·íäÅA8üEþWzè§:Ê£¼Ói1¹Ê�®ñËÂ=.8ªW{£ß¨¿FÕo‚È|RÙ³*b"+ª6 ç¿'J¸èÌ2Dÿ”D�cÓDÜ& �œ¨Ûé¹^|2^/9kΤ‡\ Hþ¾d:ú2³PJx¦³_¢]k^·l¤v&Ÿ\¶{ø2N<ñ ¿f†»lέ/âÅRsªÅs®ÍOS'—Ùd=µ/¼x²Hp#ý,ðUõ‰hN—4.öjkÌê±€hô µ†ï&Úhk‰+¾Ù9ÑVî§a¢|r˜±£¾G_Cyà °–T©P ´G¢8�uŠ ³A�q×ß ²�"ŠÇ-Í-’S“Yù&¯�n{CÀS°OÛŒVw5*×ã h,¶²éÖüà¾Â1Eµhn½Íÿ ‚p endstream endobj 51 0 obj <> endobj 202 0 obj <>stream xÚ­TgXT[²%J�|ˆ’sF2Hn²ŠÐt7ÐØº›œDP@É’Q‚T@rÎA$ÈE@$H‰M�äk½oæ¾ï¾ù53?Î÷�]U{ÕªZµK€ÇÜJ\ Šv†Ý@£pâÒR*Žtöš¢Q&âÚh å©t000ŽFé‚q0Àta@F�VVV¦tÐ~¸«²±´ûËò+pöû‡‡p wE‚„oí�„¡pˆû¢ àÜ`€ tÌÌí Aú€�>ÈЇ¡`00÷rFÀ!€ Caa€  þ<4 ÿUV‚€¥…ÀÖ�®Á|!0�_.1À†A±XÂ?Ç®0 Gè ÀQ„ô‚Ýý›�Mˆ@|0s4‡…`à8€�Õ\÷ÆŸÉf˜ôiÌ~@«Sõ z˜öc£÷æhܱš'þa¼µœ¾Y} ¾R•UÅ*øœ!X$À©7„Þ÷ʯ-6\¶N�]‹f£r WËr*iEÅŒë#=^Æ!„4Ê4é‹Ö}.�ÕÁ"â^Ð;\PÑíDñ4èWi—“ ¶~ìÛåš§W½Ë,)Þ5¼ËŸhO\UV°uø€ÿ&y}Ü™Ü�±$Ÿàu<–Élü¤,9ÐSâN÷dž<ÁÇ+X²ÝN â™{VT%Í!᳕� ~rQÖ?½—.8ò¦:R¥¾À<”dBñ9æAªª•gtÚXtfØHߣjægUíj“)ÖÀ´o1ëO¾£'#òŽO×Kòu>¿�Í»Z9­Jª$‡f®\V’¦ŸGß·€$-Ã!Ëþ=‹£O ›duc$�oM‚‹ñ~,]ˆ@ûÕŒtL ÂØÑòâ½{ž—HRÕïÂ×É­užáˆT�÷IYd_J²Å!¾pudýÁ K„Ç€>n;Î6}òžV»i>ˆµöú‰æã¿iwõÇw^>Ö‘|Ýb#\+þÎ'—Ó�„å5(W^ÜsiÙ£Ñò¹”„/34ƒßÑC³›¡Ç3Gï”#ÌÎL¡4Å¥óäÔ0æx˜}¦v„µ…R YÙf­�€;y¡úŒ'èâ£Ä½À�ño_ÏtÞU YíÝÏVb88Œnýh†Õl68Yr—Èè’Ž6ä^eé6¿<Û>—¤ã8‚/ÅøU‰"2RZ_’§läqR>‰TŸçÌ16XžUÇú¶ÜvþBä¬ñÌ¡ÉþèN%ã¤NyÛò)=Þàè}mY$öîïLÂ5þµÞAb`pÊ®n¨5‰ö ß¼HÆ%³Gx‹=¸ýXnõÃðæp¾=Ž1v6Q²qt¼©ëÊ}û|g;e¸7k'è+QÌ»¶£òRÐ-ú™¾ÖuåÜ;—šâÄÏí‰k) òK’¿òsv‘ૹ£ˆO*"6C¶Sá-,;°´ùœÚë]ÅŠÒ—Ø‚n!ZÌ ÜŒvƒ÷Z²1%Î¥ïðç!éÃr´×:ôŸ]1:kÖ’þ| õ+¯§'«cú¶8´©O“Æ�³9©ëë·cœ´`àû ÿ”ÎøõÖ¬l.é÷/<<ÙÊâSkNœÈ/˯ vV|öÔï?Á|W”~v°/UQÕèV«ßK$5o÷)  Äáèûëø±û�²&Ã6B¯~&Ú{WXµF:w0tnp+ÑoèÉŽ,[µhÓç-N ’ißóO¨‹¬+UkÀ} i¾è}ür]?M)¥ªóìíNž‚š ã†­\G3ÛÆ£H`@ŸWeâ)A„â¼7ñÔ%*½½ÔÚáy–?ÿß�ôò8T”±TæÝ“Î`òîø'ar�f+ÚcdÚCS*:ëd!�ÖÎ¥s.“r+ŒP%D`ŒéxIû8 ¡SÎj\ÔvµçúãŸþäçè,€²xì¯Þ±ô*CÁ—Ë�¹LU h’�òï¸vlùÏ“eå ó»_$•ÊjTNfSŽ ;MÈðäŠ�âLеû$|¯=?|RÎ!¹mÕª˜­’�ÇáS¾ÈZ�6\S‘«òì¹€¾á¨áÃ…©ÑÃ+yêf0ü4 0YL_LR[°´¹Aqöt8û5â�ƹñ�á"l³pÈÒ«\¤y¡nµ¥g+þÆ!F6?ók¤,KøðPm¹ yDZ:Žp^§LódËRÎÀôM³�ç¹sÒ‰ì[ÍV}Ã¥çKébï’R"+.јiŒ–÷öåù¡ìÏE^ÍùÙaÙp_Œy‚[’×WÜ• [H?¯ö‘ïmËmû#=;Îò°nù¦-þ‚ë«ó#ño7gfe„”ŠGö›îgÀâô‡ ¼ÂßþXþº—Q:Íã4û8†ß¯É[?Øâi’Ž•òQñ]‰†Ù—Vu+2{½s éŸVÐêîÚ ßpM–&­^»n‚Ýz&)|ãÍOâ‡× ¿X *ŒUŸ ¡Tþ,“˜;*‡Oo9ð÷2_Ãg…]cÇ¥õÿáß8ËÔkæÈo›fy´ÍÙQš¶ã`):ìXK¦ÊÏh.Ê}9&„“!5mýÍû7­Ã˜÷¼€Ñ–�oq(ùm|õJ‡M�rL�CIR>Q€™·àíž«Ä*yãј/ œõOn'25•c¶µv‚l*3C÷†¯eVç¼-š,¿|×o¬4è5yr\S³ay’ê0yúúe%yW#Å@ðjó|z×™¦½ àÚ8–ìÅ&JQwž|P4çºûízU…õ¥e~…êÆÞoHc‰gÌþ_¾_/!¯Ñ½•;¤åú˜½UH¼;|¡J—É׋Ⱦlrb|°N9ScŸ4»•ÕUüñ€öÞiÀ×zn Ó$¸9¯Ö'€fD\ÔMîýHê„\÷6ÇÇÖøŸ”w*iøˆÂ�–¶Œ/�î–ÛY!÷ Wl^«Œi]ÐŒ{S[ùÀ“Ï*îûû”’Å,èBaÛqóÍ•G\¹þ®9· Iû`3Dª*‡GDÈv—É£ç®^u“é.F1Rz¨d`‹m½:«ykù¢Óm¾}�úð*#@èä Õ‰¼øøæãs÷ü±cå4Ü4¨è’~ƺ̛™s §éó]>Z9E´ü‡ª© ¢+Ûô½¥M "þ!u·ÎÃÌ¿Î2Oj#Þ2QÏ?´™�?Í%í¡¢^ºYP�Œ˜*od"º òi°ªEªp&ÚõÄåK©Z™©Ö™%%Úº?^ö¹ixÒKó–Yä€dRÜÁLEVHYÔQCņæó;åWÓ‡¯á?†*pÊÇð%¶¥6%­ïŒI‡•”Ñ ¬6¾†2¾žk÷÷ê?ºe,+4T‡W]öØL�6äGÖÝ̹á ÷=}#挲O’í*£“³ãÄ�íÃhÎ ß=½!ϵ@ó` ÒA¿R ¼r)z ú’>­(EîJ¡6Ó•n#wç\òiµ¾©ðeó3E¬)\ªàÒNw±–�΄"T¯Ÿ¢ŽÁá)�4Hiþ˜70}Efеñ¤‘4ÞH˜BtSh°èýh…„¨;²Ö`¦©ÜÉäèþ*‹]ðЀ˜ëª’ÿ¶Å'{þ#Ê¡A~µ’ÅÑ.EÞŽÛ«=ÖQ{X2")®�iOò2CÒ!Z–§Å²‡JjLÆU RL‹Ýøö¢Š)U-¬“ó‹b_¥(Aªé%·¨ÚŸ•%�Ø› •¦.GßNM‹02wòæQzœ)~#:Ks¦|¨µ8¢·l'¯f¢ôûçFŸ3G²·.ÌíÍr¢Ô‘Û#{ÚšúùýS‘ÑáeŸ™R=‘u¤ïÔ<ñà*†™Ü]6Ó^¥yÈ8wIwUÖËFý+¬GQ`Së¥R^%5•á®<[t›Vy8HB»…£Dz*œ´J¢SÉjÅZ7.!ô¸Fi0pM©"ƒÁQDòD”£XðäêQrRã×v÷•uÒ?¿îRvOåºq”øŸ1Üm°c/™¾‡âÓZ�´ÅFÊy~>Ÿª=ýŒôPÞ|£M‡PÅ�Âf&¹ uœ�ð©»íjûKC6w©â2ž‚l&lŸëŸ¢¤°±•‚êý\ÓýŸiDl˜˜éàÊǦþÓÄVÎ?剼NH¢Ÿ¶õõlèi%,ÝqUðг{9!œñ4Ò0Äñ›µWKÐ…!>²¬G‚7#Â×b† r2›>[S¼hËÏÆ®0ÀÊ 'ŽN^×,¹Kæ4Õ=º§0ûÉBMÕÓB…Õ4jd¼ãbòLü¬äð”Yž´xN?ှ]“ õ0‘uîÁÙXìþ¦&Žzï›ágl€-âj¯Ó´3ºýq'êaü@¬Â�õäL®õ†Ïü gÿ¨M8NJÉñco“ù#F7Ãäû…¢Šò™íçP¯Æ·ŒV.¯^U4R>—3�•©7¾µ ç@Ø#âYF”ï•lšÔÝT¨JpÒy°–-~HÓ/pÎé½,@Ûtº=‡g#Ã;n�[ÉÒ,êÞ¢’€Qh5ð¼RVZÆ‘�û,ÙÖ ¬è$ãm«½KÙ®Jôê£V˜�c1¦ pÉûŒ£êæy[,KâÆiŸ °Å~p!3�ÕÛ|àq§Ã\q¤›µeSVÝ¢IhR\ moç;¼ÖËÊOå;…gJ hÕ©PÝ[ÖëîEgF»—™¤‚Úe Q#E}  q«ÄÖŒÎ&‰œg&Ù�í¶™ÍËJSj>fŽý[)xž¦úÆ‚º¯û'Cg Êa;4ôm=¯µ qþ­}’¼÷îÈË?‹LˆÑAº÷Ó|‹–jsñ�©›fÝ|Ÿ^:*z#²ÍŽI¶ÄóE×ëñžÀå·¥a»<3ùr6釃ÆéWîκ¶‹¼7¶¤/ ÃÕˆºª �yÇçkÑÛîÃ`ðÙt!ìÝ×;z{‘Z±¸©‚Ý<Ò« 66G" ¶1mÖžh4Ý{¶ä£ÕÖˆå &Îýÿæêeä endstream endobj 145 0 obj <> endobj 203 0 obj <>stream xÚ­weTœÝ’.î!¸KãÁÝÝÝÝh·à4¸kp·w îÜ=¸·Ë÷�™9³Î�ûgîùÑk½»ªöSOÕS»Öj*2u&Q 3K)°++ó'>€’�½™›‹¢X�IÍÒÚ ðnäD¢¢w¶4uµqK˜ºZò´--–æ66+///@ÜÁÑËÙÆè  ÕTÓ¦c``ü§å¯€™×zÞoºØXƒÔïî– G{K°ë;Äÿú¢º¥%Àh °²YÄ•Ute•¤´ÒJšiK°¥³) âf²1(ؘ[‚],éVÎÐ?s°…Í_¥¹0¿c‰ºL.Ž–æ6ï×,=Í-ÿr1-�ím\\Þ¿6.kgS°ë{\6`s�›Å_ÞíVrtvx�°÷½ƒ©8¸¸º˜;Û8ºÞ³ªHHýƒ§+ÐÔõ¯Ü.6ïn€ƒÕ{¤…ƒ¹Û_%ýí{‡y÷ºšÚ€]®–ž®å2³Xظ8‚L½Þs¿ƒ9:ÛüMÃÍÅlýOŒgKkSg �¥‹Ë;Ì;ö_Ýùg�€ÿV½©£#ÈëïÛGýWK�3+Û{Ns×÷ÜÖ6`$–¿Elå`ýô»…›ãúÜ-�ÿní_3C÷NÂÔ òXXZ!±(9¸¾§ÐþïTfþ÷‰üo�øß"ð¿EÞÿ?qÿU£ÿöˆÿßó¿BK¹�@J¦öïð�xß0À_;dêü…›ÚÛ€¼þ‡ ÿ¨mù’ÿYWÓ÷fˆ‚­ßùÄüéF)OK Ws ÀÊôÞ©¿íš` Kg� Øò]Ñ¿› `býôé_|@s;ð_­çü‡Ëlñ¯äßEú›:‹‚¤¶†Š6ÿîÔ¿£TÞµwÕðr|'ö¥(:Xü×á/ 11O€7Óû dbcçp½'äaeõý²ý Ãúϳ¢©«³�'@ÿ½äO¬þ¿ž ÿFlî`ñ׬¨»š‚-ÞÇë¿ ¹ÍÝœ�ßUýûÅ¿üŸç¿ÝÒÒÓÒiiÞÁœ?Ä6-3ݵ÷ÛÀ˜„~o7+ôÀÇ’:�Âü€j‡.ÿ´ðMÞ “çš/Ìõ|¯-^¿Ž_våè÷†ºq@4])–gyD¾t=ùèkÔmÜ {A,F%Ò�µ¿zŸÏ)lÀèq}ÒÚÛSU3*~†#žhcwF8¿£  pÏÀ¢¼uDõ3Oý‹ÝŽV�Q[ptL�xxwKÓ?<8ð³ë¶g—�!'‘Šß×/ùˆ,ÉÕËÄùO�ù+ì£;·Ç¿j0Z%4óqRóWß!WÒsÝŸ¢ Þ0¢áAÜù�¶xTéÓªþ9ý®eêßp؆‹òHç¥è&zë?]ŽŒÏoë©8é6›êœ± 7Ì`³š¬¹V÷b„]9qts,Uòq÷D« 7Œˆ¡Ê–>>œNÜÈKì]ç�FCèŸX\SkâéiÉvi)oímMþ=�ÖÆ$bÁqXòt\~3”G9ƪ£BÙÓxb ËQ¶Û¸¹€Nç4áùG Æ„ˆ=:MW�‚û†òÅàÿö¼¤ëd˜îç �$=*óSéñ/<§s¢]g‰«¢&bDKçû£l‹1Ä[ýRÇF½ÅC𻩬§‚y}ÇíO–êÝw±‡QGà¬ÂŠ磣x ¡ß7[zU Ž=iÂnÍÆÝ4ÒÏ,(ú¬›¥)0h¿Æ¬ýJ|‘ i� ûu•è\Q$²ÂºJÙÐþÊ…ý~›æª£ÒzRl«„TE ÷üjLAmËMÀ¡jˆÄPïyÒdõpÄ@”[¹M³ú»FÍÚz…s‹ÈÏ¿›‹Láñý=úaÐí²ˆòÛ‡•è\#žÕd¼çP‡›…îCqQ)qÇyizð§¾\¨²¬QŽr5�…=m—w$8sä(Øž©ø{”ÇŽk! Þœ¿�ÅRŸÄ…®AŠÊ SAâÇt[Lß(f¢é6µìú•4UÜMzqüNMø ~9[ÿ+3ØÀ¦»Ç Z9÷<;éUÄ®¼pÌ qË9FËaD_Ÿ‘ Îm‰(ÃPû½A£þ‰�tîg(âÇ’�ÔܳkEQ†.TÊÊw\å³>!Aò-Xɼ¸~‡÷ ÔB*®Y‹ …¬,b`§ø)Ï­™ÌïbÂfè(44È6f +Ÿ0±¹éJ?ŵi·n áÇ!/l¸Ã1æô ‹q&õà•`”ÙLÈÎÒ¶¢*þXáоs�=”˜¤²O;U0@¢n¢Ò+a8[uoQQù@ó\> ÌZ>œ†ßdÊyû'B(ìæ:‹§EDȽ©X›Ñ‚�õr›ø·‰âW#Ú>ºmݺ)UøÝJØ"µ¥f]•±X� )1c²¯òcàð4én[–F¢�mƒöذÞR#q­Ñþ|ÆX«áŸô ðMñ-‚Oœ^åS‹øý‡ºnÀ<³Æusy×Þ¼Žn÷�kš–êgÇî�§C@9Ô^ ÷ן§2qÊ`Ñy~ûXsòé1ª’‹š•Ÿ.?<ÖLTfÝŠ�±rWœüµ‚É(– f[*D‚& ‡'Éà;R Ï™aÔ ­é8 ºìX-ÐøxmÓ‹¡…³Še½ÝËÏt_YÓ’Gë$øq ˆô©wâWîŸf~+H_&V›�ßoé5AUÅ*︈jš71ìç¸Ùè…øN¼X8 Ÿê’z[ÂvåÐSgQ•¬w÷yŠÕätÚÕ§%ĺ<|Œcäó¯ø§À£ž“º¯yùY¥É„™¾÷¦êÒóR½&²BŒË?IÁqa¶Ð¿šx”P7· ÑqÂÌm.%§w” @eÍ•¹¾­“ðG¥è. 8K¹ �?qßêúóØÔ w:ê-Öqˆ7j*(+’9¿îc§îrÉÅáúüÈ+kæÕe¸�ªÁÝ!wçrIæüŽyì«h’ªîßN�‚Å_Ç Âb¬­Æ¢ù-¯r¸[Q—˜ø!lYØ…{ÑO'âkãcÉÏÆ?¹É"Ô· zûÂê…DÕk¥ñsU Ò·ŸÕqî@§p¿ö—yá¶&+øDá`lê¤}Ý„‘N´|Ðç V¹{‘—ÆãÂõ[gÀþ’i˜ßíÏf˜ººÇd÷ZŠÝ4UÃ8ÃH–:Ó7?S}ÛtQH„CŒ÷]®à�ù§¾ÿ)6Y«{ê‡uÅÂïÞÒa Ý`Î[˜»®m£†»”öX~îà'ië¨;hÉ'ß„å{Z±ƒ–Žtˆ¢ÀúÚ®¯KV +.Â�ðÙ($õ}Ó�‚+"&@ù B3ñcÙv© ýàüE™O|G�FªçÔHšÆÐ �Z�%ÖÁÞ ¬ìVÙÜŠ5»vxéò®yÀE~)–î4éªß†v5ø]"ùt eÙ‹Âù¾KO±^κÄWÀ©€‡\×ü_, W;©g¼¢²¿˜4ð°„‚ù&7)÷˜õ?¿…SaÂü~˜,Y/fZ\rÐdAÓ…P"ØEcíÆÕy^b +¸mìĹ)a}°tøCuŤ-¾ÑYŽ=� ~¬|YS¼*n\È´ì/蕃qÍx Ûç¦ ÿI´g–¦l£Ú°lê“IÓœ0Òûª¼ÖJCéÊL*é‘'=/‘Ó°L¥„I:Kfþ¾ïëdÝ®¢DK+2ª¶}È@Õ{·aŒâk…ao”•§áþY®@p§À%yýØÏß>ò唞ph¿Â¡õµºH \šº ç¢äNÞˆ¢!à$ì&C‡3[›Ž}f�{¥Gä‰[Jlª\QKJÈÛ7®(É£Lm-ÿ œâGS‡>|1 ñjKÙHau†O²9÷Ë|_Ò6Ü/¦©³¥L‡–…3�›!H;5Œ¯ò›3Ij]â?£9ÙfÑGb³¬¡±TXtÐ/\Œ…6\:�’Ìøí«–N(-[r\¦…·®1Õ³Jˆ¡ "¼Ú|¨„Ì@´sK‘›Ä´»£PæÒË"`¨Nsºˆ*ÌœªR2DýñE‰¢öç³êô¤k0’ÂÈVßá‹¥…”÷Àq gñÞ�N¦o•¼×ÿmô{JÁÃ|Ö(Y™¸€(ÝÎÕ$ÑI~Vw®a?Y&ÇŸ Š‘´“VMÕÖLtŽÄûá*ùÌ•Ìÿ*½-;•&ô™¼ ‰¤úò± XFÍL¸$ƒŒt: nþÌ�p¹ºŠV,ÛÂîvûLr·Ñr«ÏJÖBpØÒ$µØ¢°¿Ž¢-X€>§8­§Äoõ«øÓæïek¹˜�Ö×H› ŒM¨$žË{ö»é“M,[õ2y‘’•«"ä�˜3”&QªºŸÁ¬Í�B]Éüµ¯„ëÅ´·p÷´¦áüéa/r¶8> Ž�èD:Έ½rÿ”l¾,s,7¡éË®CÓÅ/ÏaïÓI/0C@7µóRkµöûŠº½_‡I·Ép†ž¿]kÑÔíý<$Í9=¨þþÀ ›'8v8õÃ-ß*4HùzРïD R1G õ¯ Ø_ƒãPý“ÇÙŽ)ËîÍy~;pÏ![f¤³)ôõ{=®ÏáÄhì1øç( ä�Õâ°¨ã*Ô½kÐ/{ÃïMŠÂC¾…ªLC*ªD6vòW꘷ó¿Ôú…N1Éø‚"½Cævœëš� zPx©Çõ½ƒ›¦}æ;jçëœ2ª¶‘q´k01ÈÖü{÷+aT3‚4§•"à·&d�ô×éÃ?_zæjÓZãX¢¼ùœZüú)cÓ»õ6ä­© úC"ásBðâ\7¦©Ñ‚üÚ3Pô=óvç|‹æ³vÕ7ü¡`Øm‹¶¦"›ŠÉ,ÁÚ ÇóC(æÑ5ƒ€@œ²ûኘ¬B5€îžuRQvàå蛘 ¯"6†¼×P¶gøCÈѯˆâd¡^kõfÉq8¸O ޳^Ƚ\Ç'­Qƒ‘§^ê‰Ë|‹zÁTç’Îáf�­­F†˜*ÂÌô¿ŒZ޹‘Èw’W¹ü~“ƘêÒ¯-ü�äŠ-ÉØ˜6ÓcG‚2üÒÚ)ßÏMMH¦¯£ÛOw1�Q'4¤;e‡|È]H|²?çÄ(ò;ô(B >Í1©Ïä ð‹ `°gˆté×�O¸ÏÄt1.tr5G�-Öç«ðœó�újÍ«ÊÂÚmQÐ_+ÆüÆÂ–â¾Ð–ñ Üy UB·"ßîW°¢±±\&“”@;]ýèÍ+ß¡C8϶:hô´)˜8™™ÆÆÍ3Ï)^�u2ó}È£|b¡ì| ‡~:•úxÏtÝD�„Gû�òã²E~× âŽCR&[`xÁ  u˜ºsæà渹 Ωzk—æí�ogô|&ûpÇw<¿ú�¸–_ðÊ1Ü¢� ©è¥ñ,ƒ�ä �BáP”¼�—›< ôÆ©áUõ›qÝ̵ÏÒe“«Â²š·”ã¯$ÅÒ4ú¤ßç6]r’fCûQ6vÓ·åÛ~Eñ#}ÊÇ}Ä“û)éÿÄõ#Ô9'C‹—�|¤¬ÅTõGÔ�uvu=OÄà ²ßññmªï£0…a8ƒÀ³ÀÒxÔ>g�j;Ê/Ø?Þ÷]”œ1•¶ºrÏͼ±S FLå�¾(µ“æ�ž)3-ü;Ù©�D¯àæ2¹o6£Ðw2ð«¤`DŽ1rjjÑáu;¼µ®Èà•þ@*׈i_á%ü¾I“â”jfì竵Ù›g¤ŸðèjAl®Åš®>ixÃäMHcÇ‹�I³jv,ªÉ˜¡Ég¿rÚÊÑHý~íž\¶0ÝÃOìgjR0ÝÜ í¾fÀ"T|^òµuõáž=ǧÿ „1é$b~umq¨`Â[›„µnõ/;u 7Å$�+ËeÍÖe:•­clØ•bįôšœ›"õiˆ×üÙNÇ�åæˆî[ìç×…Ã¥=¯ÛbÅ^Ø«àÑ ;ÅîÒbI‡ì¿¥"N¼òö‰ã6XÝ #5°2qö¹ýÎàÐ4X¿ÔùRþR¯2é‚Òp8Õ?$§&q¿1‘4ØÞ–ü NpÏ$êøø±œÝ¸œª±•ŒÞîpÚÅ……ªGÂ÷øëry �n”6V´þ“¡Ô`*ÃòN·ÄfÛÔÛdíQk�'>ñA×÷×K£I¸™ψäÁ¯œÀ›’m7.m›xðe—c·Y¡Ñl8w¿Fê9y—d¡[ÈÔ‚~ÛuNáUÁíø >ÔÑBé·l²@ÇǨY™©lâNß+˜ÈÒBi"õ@:7yºá•Lœ'o¦r³÷ô« !eÛŒîdƒUYH ÐWRnK|‡ôyÎnþ|Çæ•Éo€¼À<»ìÃXÑ"Ðh­þ$(,D“ùü·êòe-k`ÓV�ojœ‹?åz�,t°16«c6›ÃæX¥ÄÁ¯C©8·_·MT¾çŒÜe æ/-^®‚Ey¤¤p_ÞHÛKXj‘¤Çj'Ù9us*¿eQQË”ÂkEÛ¾^{•Ïv9 u¸Q~žùN¤¥ÝD—n©‰6Æ/ÚTc %«(ê=÷vUÿüÙÚB‘mj ›kð‘Y׈dûô®áêüW–_©ã£‘Iv(/Ù{u‡º%œÙ'–­ZFBiJß&œÉh ×þ¼{uÊ[«Š�ªÜÐ{&Á@£}®´¸O%ËÖ¾èGW^0'Ö=Å5M‚)ƒ�ì*v7�¢Ò-ñÍkÞ§bïq\Ò|=yà+¹¡çô÷´‘30‹€¢¶äl YVÌW?€þ*Ã!ÕÞ¸Îb+� qäÏêëŸjˆì²ÊŸ Á¾åÔsÂLˆÀÉþ-³©&¨Ã$:ä\žPwÍæ05¾˜»¶�œúˆ´z7ž¦}We’¶*Îù7´H›·mƒÑ>S¿¡¶Ö˜ÚHÎZR)U?VéIV9¡Çq ’»q8¿ñ|µêíDìå$´ÎäÐB’W¹¯'?\]­ôé£Uû�ýÀÈd!×.~sé]~P•U ì˜_ûé��š$·¯’Øñ  ¤¾È ÑúÒÊê®Rv”³MO%^B#œ?ž+ÐÀ¦À¾ŒXòj‡¡y ½,ßz–µŸù¶ˆÅÀ_aa0!Zßg¿]mee]/ϊ̲úLnŸã­&­ƒëó4qõÂô]~ÿ¡žZçýSäÙÑÐ3ã‹ãTò�,µ?V±]Ô@Ùø ‚âsFçv³"��yöd¶nQÕŠ'0êI�fµ¾fúùÁIÀ—.“dUÁ{ìÉn@ÿFhü ðõ úKß@ùÞk!ïÓ4§²�ÄKFµy$kÖAèô¶\TX/ÃZöKæêµy±g­DÃCZü†Nœ±jް8Û§þ5¿Ky¹tDáõ´Ï®xÕ ø†’fóGe˜bΦe]šaï²oÌ3ôcÐc„¹·ÿ‚Oƒƒ:e*>ÿ»|¶Ê�ÁôÖß7ø>ÑZë~ ò ºSã(J!EÒM7’ɼMöñ¼¢ž‹Mð»ÓȽ9( ®CËéwš@ Õo>øcWڹǨY*ÕàrݺLkŸ£nò…Õ™Ë Ë÷`kïL˜ÜØåg×P%‹¿š8š†i<7þêÅtgRârĨø–¨×a¸^rÍáÓ=·—w‰Ðôûvo“éTùœÁzo,`ÆŸºÔe¡ƒdW�ö§ÚW%¦¯‚Cçø¯Ö`�ƒd ÖwŽÛlr!{×ÓV1°ZŒÁ̬L¢ã–ûÚ€âÊt‹É­œ~{ÝNâ(]ÞÈF“«ó}WÙ‡+ F­:e«¾ÊôÎ ¹iL7Þl[ßꊆSïQR6÷ˆGÆŒúÞXU#ò?;ëá+ðÝÇ7l�_[ŒéŠ˜Æ­,šI¢7¹˜ÜêÏ“]*Ü…ø¿|¶ãHv·§t|~ ô[ †íÿÀ,|�[ ZΡéÒìâÏ©±=‚ îºeÅ�Ö„xë×ÏMZkø«™»0pô¨²ûᑟöB1WüŠ)¢¶þáô)DÃ!{²�ï߆¯¬Ï`tmut쌇µ�­Ó.dßÂyÁmœ�ÞüÞyñÁ$®RÝ‚ŒÉoœg‹Q­¬ê bÿ�ù±Öëà&Ô¤ÖÏæ�ÇøJŒÒ¤Þæ²?n¥DmðŸÃ¶øÔdoï-~ È*ñc="’zÆ€Ô/7––‚ç<Òo ¯jÒ ÃTOºŒ0Ž8@´y-ô$¯Õ ¾·¿ÿµÌê– û u>µ‰ðaú8§Xõ.‡#¡Wa±ô“‚ÄÏóÒ¥Ÿ°9Ý G'_„Üu’¸0x8ú­´/V½›Ü†æ.V¸ZµÄ&D1 Qœû±stdêàèWÀîS‹Yª´ì¢³~Wþ“†T˜ptÒ F\³»-Âɵò}}éŸ]ïaðPöoIJc�{ÛLv*ŸîØÐ©ÊË)2ðï©‹æF-Œf½�u8LI¬>Ä1LÀ@Ë—8»eŽ¥ Ôå�“Ë…õàta#æ/n]?x‰|Üô ®|™T0±éûÅ2Y>a§à$‡ÞÆÐ®XYó›="5WtKÝ+¶Êz_z/‰¾u0Úí¡Ö¥ãŽòPœ:�‡ÎüXðKÜOÕÙ£üq¸š¬nV\ó Ö$YÜÿ|�™Ns2ê”áœbì4Á›“דwó.´Â´éøúöa@ݼfÛz=wÛd T/¨gæ÷ÇÓDSp »ƒŒd¢sWÄŒ‡7„N6Ôàÿ\ ±?Ìßîai8¸°0�'rº2¨]T²ÇÏØÆA䈿ùÞ3Ü›ƒ+cnæÑ9ò“Ô@ñ.gÏ\pÅÆ! O�[Ûšq~˜-¥d/šuSª¥íÄ×ÿðH‹¾G ¢“>\²çºT¼7E8ž=µ°mI;4Ù!Kˆà¨`ãYj÷Ø…öv–‰ƒ(ËÌ}Û‰ÇMÔI¢h[i?-ºüœ4ì"E®ÑNˆ½úkˆóO«&·)š½èÞ(T`“åÀLËÝmc4Ãb¤$[ÁÇ;Àí î<Õ…2;€É%Éý›ÒZJ-¢C ^pJH�\éë�8À™²ÙËv«é;zf”dÑOÍMÝŠ¾Û��~¼´½C”ËqVVÙ)9˜€ CѹѲ}º¬µˆv§�9Kæ–þB꿿ט3|ß’G¥>ùéþ˜,ʼ¼ÛQ¯{š¹ÕŠ09K5êËq´SÀýE÷³ç£C¸×éG²)­téÍÅp�wÊžEŸ|Z7ˆ`{ó ²�„§æ@ɆŸÒc{®!Xò°¹¥h’”>??!8ßüI¯gøc(ÌuÉug4TwNR¿å½H½ú¼‰sâîçÎlsnx$nƒ¸î?½@Y[�L¨Ü5ªÍ8¸1¸½BÂvÅ[ýòªœ¼ÞÉtçaâ�Q}×uTŠ< óKºQn+SœpXóŸHåêž÷ä™û7oçŽ'Â#õFwûáGŒS™ÃŠ>Œ0wn?%â»H²4ŠŸlwá ^±ØÝª’ivÛúÀ}‰êïÈáµ_¨çf4!Žz ‡×¹Ð<åe°›•Óù¢úݺ÷­Zd1Et5Y¤œx¦ø :‹)ã=Cm ) ¬j›8£-€}8~a‡ÓM»³ÝèRÊ]šÇ<­"P›Êª�|ùÛd«kl¯Ù©›g—¯ü¤Wìi?·¶Kä�ÉÔK_zÓf•yЭÑà¹vÓ|ékñýÄëhšêPulÖÄ’œ�=YÊ?õ�9M7–¶)÷Êœ~…þeÕGú& ³%ßâôÚ(}¡£ðæ…‡¡Œ[[‰Ö¬ë±C}�Æœh ^ÜùJÚÆ¨FTÃGäçù3Cåú‘)’À.Sßö›Š²{D ’©PTÅQdºá”RòM…7áþ#¥#{ÊÜÜ8¿ ð‰þU(ŽÓ¡Ð¯Ÿ Üg—x…¹>,ãúPí÷†ò¯|¡Å90šÏ$�ñÞµÕð ÚzY©Uod†wòŸ?ëöÅx´¿èGçÇ"ýD ç,ºFkåèᯀV®‡YÚ46}“¾‡-Ð'ª~%‚ª,×6‡´g9´C(šPçäηɪ¨*S/NRh/gxñŒ¶ ¼Þßy‘`ø�[ÁÉYTVᤎM�ƒÛGéðÆº¾^{ÅujÓ›'A ÆÓ·ãuì>š$Ù b^S#t‘¸Êï;…óñ@‘ÏÏ…Ç�dmCzŸ•¿‰ÕO•êÜ4™»£.àäK@Ë?Ÿz5]©Rø‹9J÷(|šðl.‹ó-,¡©ß¬¡At<ë5¦ †>fÙ>‘O‹µ>¬|0Ô2òÚõ#³¶†èÃëœñãÐÔß�ˆsgfsûõVr¥¸7—ΠHÏqÙ"ªÒ1r—5�¶^kd»àeW�½…öb½í,eˆ«'ÀÕH¿ba£4Ò冲RgÈ!?|£ÓPÞ£ÙŽ\4mÜ'v¸P �¦Ç‹$1#Rn1Ûõhû‚¡ÕYÒ´üÆøºe]Å¡ßÊÛô˜=$ò7ª—¾`ûjZ¢zŠ éEÉ—Úä6œÓåÌK¾ Z×ñ¼¸–µÌ-ªÖC\K£ÐDö Åsé,ãkkQm׉1rÞ?–õÅÍ–¿Ín˜Ù-y0>}¾Í…ÕŸÃ7öiŒZzRZ¨íøi�5îÃó{ 6¼/ŠÏ‡ÀaÉò;öÁÚ;e¶™ ÅWÔñ‰Ëœ}aížœº\Š0k®Ñ²¦ƒÞ]ǘz¡ÀXâëk^“/Ÿ]šWr8åáßN «[*ý<Ö6dUT«„‚û^ݲ{öEbjI/qsëê1Rn±T˜ÁWꆷ_5wjøæý€ÂDÚÖ¥88ö`gëËþ7Ô[w虜N­vtÄG /ý £Ô29 éTÃu_ZnX1r A­ncíá9€�á%²Ey‹§=O¦ þö¦åsªÉ›ªv\ Æl¤–=C"�|1ì�Ì_ÐbMQÒ­Ù _޲l:omZ�ÁŒÈASîeŠÊÖÊ\.Œ*\ï ÀÃK>R�gr¬N„/™i—¢|3Ls{îÁÇ·`A§ßÐ1'®û!²u #«1aP˜Ÿþ"+â­r…ÕîυƑ诲êfú5‚°f•Æ!aÀF“U0=›Ý¨2&½‘HSÁ¼cÈßÄÃ�>\•«ú‘¥ž�¿é µlÒä¹Ú‹éŒ']”góÏfIïÕáã(g$;ÐÕ*øA,è#‰¦ñk°»Ö³D|ôõxf ½åý)7íÒÙ³ÿä¥1T ¬b|ɺÃÃÖi=nø`{ûãBtÿ£Ê9à¤ná9ÿ°Ý(`ÄÔ*‘—?ü›t7“i¯#}È·fJÐõ8O¸RvïÔê<«¦²{Ý~®©À[ì'â>qjàž4’YLÇ] ”èäü]˜aM1 ií2çÓòa¿,�KpNÞ`lç¬Äè§Ms ª:HÒ¶Þ¢¿— >wDõÌï;˜­c8$Š/ü![d Àò˜Bh"Õl=tÖ�{õ-8´³°LåAíèC–¨û¯Ê§þèHxqí~ée#ت…nÜOœvzþK+ËëåÆ×:´emú›si�ÓŠUiˆHÄì(=nÌ5±ÎîþWÔQ§Á¸�/ lø¤t!54¹½¸p£®$ñŸ”óÀ±÷þ­Eî(p!`Z� ·Qrfë%f³ßíÔýš‡ÖžÇb¥€ÇCÎ)�‡¤Ï‹Î°Ñ�jlê_¨¿ŽM¨ï“�"~XqcÖÍݖׄ×N¡ʯp¸‚ßè°xcÜ}’z•|£ò¦Æ @úâµg¾Ãoµbòç£Iê…¹m—lF6º„H‹j+_š°Ä9¡s¾c>;XBºhâc¶h͵›54áibY{ÜUE‰7 SØŽM.oA�–^ØšØSð7 Z9@Ox«âÕ“Bë1T¿J¤ö!#¦gš¦Á8õ�§’¡JH'ƒ[>–8ÇÁîÓ—Eþ˜&¢q¬èØØ­ØâcÀ�‰'5ì§ÝÁä/T>É+-I[á}vü‚ß;oÜäD–b‘ög„É…­G‚ƒ[ƒ”jþÐ e�À$…EªÕ R­•»-�í,Öƒ÷€n+2idíë¹�P¿C[¦x×¥¶.·÷Ú¥wÆúyS‡Ir~soLOa1Nê& ú\¸„°Þ¸³e…Š�-+]ô"„(”ÓG+ÇÉXËàÙ!?ÜÏ–ÐsÕ‚bé¬ýƒ&W—y‘ÍfN‚Éjâ½"#�rü¢<7ßé`d÷Dú’ªê6ŽÐªi!…/ä)k­*®l÷Ë�Lž]À¦Ð‚oÚb{gß“÷D¬=ú)ýXeݪ6zû<¸±(Ó¦}&æ@#ÁõKÌÊa#¸©zFjãVp.ûIå¬ÿH8b´~0:~Šsòù+jž Ë÷³ ÎúuØ@UZuÚˆ†>½©¡oVça±ÏE‹Dêö�¢ì goøë"…ô¾Å{€øÓœ¨ãò‚dè†Û›UŒ7i€UO9X��¹oé´‰ôJr/QÄþ#±§p¨Æ~¡uß5;W7=K¸;× QÙôÇ{=K ^·Æ•zö«ÛÃ`ïÌéc}æNâÀµ_�4vº*Q†–}r¨åÖr¤ "Ôâq÷H±$�G!ab =9"Ðþ±ÜvøŠEÙW‚f\ÑGÇöm›G÷¯O®¤5†=‡šÌÙÖ¾õB5r£•qzîq£LšÀ…¯ŸzÑ©ÙkOºçå™+Y2“ÉCB�¨¸ÿHÅ÷4“×ûsæÿF±3Šë¹Æ{æH¿DhÅS€w.¡I} ¿×ð„…`*•Ü)ú“ÍX–U².µ…¶ô!p�‚¿ÇŒ T#Ö�Ô!Úæ¢ùÀ«‹³¹"ˆdu‹L9ù!ˆí—g޹cù(n\÷:2·â—O‚¸‡a ^üá/œ²_Ÿr ~Ãô=‘Ÿ¿ån„!"PÖðh $ •ðhù¢.WçòµG±R~Í™“Ñ®ÃDƒna‡…M¦Ì §^Õ‰ÁJ¡O& i4fMôó: ’Ö[ðvôñ{D(´òÖz¾~)z²xs6›!í¶ ¯H܆jÇÕqeö>䈫�Eä„ð 7"›Wªø¾©KéGÞšmÀ¾Õ<b(šS†ŒL…ן)a7ÈÓ9…õÉ|X¸ÄW)IyÊÖˆ?bÍûsViæl¶ÓsìÍj�{ö%;Xø~vk¿l aY-k‚•=Öo€Jç[5-6½:WC8±v�ƒ63XE»FžëFAêx�=ÑY)z…ƒWÿ¯A4SÕ Gcô„�Ï€µÔAê¬[Ä…ÆŽiK�{åþ¸¾¯“ÝóöE‹ëÔò­÷Ázœ]øqQ­}°Î€•íGfŽhóOáŽlŒjy8°Ð‰ |W}ÙaÚ-úøžê‰³¨Øð�‰ºp0B<-wý9yêî~]ä©•·;‹¼S(# Ï´™€;yè×|AkÛïËý½™¬�D4œŠô‰Aþ;y�-"ù¶sižÕ¶b6,f0sªy‰ºÚ%¯]žäÈ„³ò¼b{ø—fË ?œ¦¿˜Œf\pz>Ëzìøôrý´5¤ðËÉ’L3b®™Ž5r¨&¤W"¡²QA©N ^ jÐXkI"Ú‘�ÆoÙ��Sb þé-àʾ«ínà/ãÃnŽØœ”†É;=À Ls÷Êa6Å;ë,|nW<Óýá7Î)83¢$c0ê½ÿb„ ŒÚm >a YÔ‰'i« ó|½äng² W?òJ4È WtÚ5fÑöÆMGcüvD–1Æ»eÍC~Ñïi½"cëá¬ÛÖë¡DÚ»u0ci+v7@Yô‚Û!Ö4¿pÞÍîø¦ø¸›ÿ2,Çt¸šž«HÇ’€OBŠçšillÊŸÊb©H£B@Vµ¨Mh‹ ’ äÀVa`Ë2š?Ør±äÏûVn�æ^À’Â⸓T~ÐM£5±&Ùß+€,¶x¾€Fý˜qð4Z$œ‡¿"B¨Y†=åå/`|‰3OÏ»ƒ'ÌÓîtuK‡f–!eM'З@E>ªò!¨î�øîkáºü¬O¦Ø A˜('Õƒ‹žþÕ#5…ç¯ðÑË«¡õÓ29€N¢œé—öa†R�òȈbE¾ej)“NGß|#mÄ<¿yŽ6z]9u= Ô`ˆ+ýyÝ‘3¨Ö§ˆí\ÁלŸ¨ZœìöEp4•Á#ÓbYÎÛ6ùÍ©nçž2Öã‡Ö*ÿÐ[±“ÚfÚìl%™É«-—¼³ÌúÝ9“kˆ¡ó[?L�vMYM×ÌÓµ5¨k\¥!Ù.•·Y>;¥µÐG±õã®7�þå úúZa)g½¾à‡F‚cØP¸ñ Ê€ÎáÕþ–­¹ÂŽ$Q>/É…øízé=?_PÍJ7ž'Ô¤Lj¢w»¯Ô…þX †9VŽrÒ’•G Ó™€LüF•÷aNíŠärv½�\¥¾­¾å5FnÝù“þQÅ܃�äçâ£ä&êù"Ç‹(/ô oNå‰ö?îJŠó\Ø›3ãO(2&2ÈÔ1ž\-UpÛ(…íŽLvb(O;£ ¡Ÿfö‚2Ã*j�úÛ‰}Î|K™pvÊ+Ï]aøÆFßZåÔ÷ã9 (L„Å"÷Oï:?𠨈:äyUÏ8í*—ëê™Ù ¥um¶ú"À,ÑÛÝΩ6-3ܼ0ßšhçÏt%Æá™È1H•ë±™å™jèWnXO@Ê$-”ÝCK Õ­‰U$€oC½Y‚2Iìmѵ;�ÛˆJn öÓ&ûÖÏ�F\5,„yÍ|îlåó®íÚêù”#ìórê�úåÌ·aš¿mZÿ,B¥Ñî[¡Ejš¬šÒõ¤ÄA‡×J!&AŃüÝ2³Ï¥ÄA¥s•¯èzß½Q{N¬Ùí~"v[Ì\ì™Óc|R\Œò›I&ؘ\57LXíWëÅô+ÜôÎÅ%2~� íæ¥.#é¨t\4þ*¶8¦Í]à/|HlÓ&ë‘9©NV,Ú²^F€ÊÝ•¯…>DÚçã©=ò• -ªÔ$� «×(äªÂ(© ¦A­O 0‚,V:©†œ>³ü¦©^PÞÖ}ív©§!w^“F‚zkÌJß&/�—Ø )›:[y©Eþré�:rR<«ÙiéÑd¡7‹»(Ëš„{Eø¢ëþê¾þqt`¾Øhe:}e¸X܉ø>oÚœ^б•Á Ù\ì²ÇIÿó¨gËÍtîÛàÅö˜\…ŧÊ3æ]Mªbå¾³bG¶Ïã0a¹C Ù Õ¸á”½×øÓ=ŽXâÝI=þžNCòÖ›aVPÍà/§¸ýê«5 ä€è€uúŸ� �˜'ªPc‹7e�«®”¢? Gírý‘¥iÂó`M§¸ò„®K§¹ÕócýYSvJá9c²©õü>Dÿ8¥ccèÔÕý’³Ž‚ê»”_(Fœ£j»W</ýÍ9*ö·é$®™ÛC2iîåÆ�aÙå¾»êÕp,–8Å«ùdØ›�Ï[$ËÁíåfsi j‹G‡ü›ós')ض™­2Ø­¹³ 8*1�úâ�ü„þÛÇ£yG÷"\켟Ÿ5ŸƒLÊoq ¥VƨÚ8ñd‘WŸQ›-3 Ò³¿æÁSé _ɹ±ËOÅ Ñh…9,#ö#“ºsOؾˆ~F¥{éí=™0"ÕMB%S·zêK¿óo(üz¶²D;$´¤ŸŽl&­Q�¥™žß› ³��–¡?\­b:9M(ºÑgM,ÛÜÏ™óV´ìÈlÆüo+ØÙë9�*I’@•2d�­ŒøÂëxU-îÅì ÇËá~ìs†:È´p,l 7{ãÔ' ü2—­âµŒ2fe^?þM„e ²¦Ü¶aM ¢ AuÎgõ#æCº]›Á`Ì´vº¢•´V¥ô�$~‡>7èl‹ëIoŒ]´dô¥6òæT‡Ê¸drø¢Q%h´ &‹KÝ~›O"Þ@¦ä¯s<»Ú•ŸMîü9¿*ø¹ÚÉ!»_ê?Ó6ø‡Òæ¨sÃ�Ȳ�š�¸E4Âë}¶<Ù[Ï îtúžá0‘U´Öb­ß“l—ˆMYY—÷ËÀtã¡ÿç¦ÍG°ß¬;8E¤J<ÊÇV¡꣚öšTª%"Þîe…JH B˜yW‚�*riÔ<Vù|D¥C±õaê—%p|S >$M Œÿ˜þ.1Hï …Ùu¤‡6¢šðÆ´“ñð´6…Ö�T­Ž—IÎþ‡óã#}Òÿ%¦ Ú endstream endobj 67 0 obj <> endobj 204 0 obj <>stream xÚ­UeX”í¶FºQé:‡ ¥A¤A醙�º;$¤‘”�–F@:¤é�.é8èwöÞçúÎþuÎþ1s½ÏºŸu¯¸×»^M ŒÌ¤ƒ"�ü<|âu°ƒ…3B Ujƒlœ5, `À= ŒËÂ"ç2G‚aPys$H`²ȃ,~111\€ îî¶±EØõ´ 8¸¸¸ÿeù}`áþäÞ¶�Xï\@ÜEÞSüŸu@ Ò°C@9 Í—ÊêJv%u=€ r2‡4�ïK±¨‚-APˆ` s@þ:,aP+ðïÒ<÷\2€9Y‚ïÝ@n– øoˆ99€ˆûg°q2‡"ï{€„ÀPKˆ³ÕïîíÖ°? Á�`÷7î±{2M‰°tÑ€û¨šòŠ剴5GþŽ�ߨõýM+˜¥óï’þ`÷4÷(Ò E� 7äïX €‡˜»ßǾ'ƒ;�ÿ¤áŒCmþ•7À dcîd!÷4÷Ü¿»ó¯:ÿ£zs8âþÇöçÖ?s# ˆ5.¿À}LKä}l0—÷÷°(C­a~¾¿ìVÎð`. §? bÿ=3÷I˜[Á w€È—W†¼ `ÿ¿©ÌóŸù? ñDàÿˆ¼ÿ?qÿ®Ñÿx‰ÿ¿ïóß©�!us‡ûøkÉî·   ø½g æN€ß»ÆÑô¿ÜÌÀ÷ãø÷‹ ¿’ýo¾¿ÃÊHóû¦È@mî…ò ððýe#Án +M0ÒÒ`m¹ïÙ»Ô äCA÷Úþië½ßß0][°¥=ô·ÂA ¨ÕßÓ¿—ëOò¼F ª jê\ÿnÃþ¹©y? H]w8ðßa Ô`Vÿ<üæ‘•…¹<�"ü € (@TTð„ŸßûßDüCÃÿ¯³š9Ò ì0æãáããÜÿÿã÷¯Óë¿Ñ(@-aV¿'Giµº¶~ÖÎNN÷ÿyÿï‹þÇùÏØƒ@n KÜé ˜¥D�]ÊûwÈròŒ®~yã¶~´®`x~¥îÇl¿RX³oJØ¢X‘ÙuY0OÕ øm½ûøüfõçZO „­9 ´—EãÍÄÑšýhžµA”k-€×$ŸàݶA¤çþ˜êº‘ŸþÚR¿–¶IÞ5&í`ƒ öþ‡“K¶ ó)œÐÇ2¹"†´ñaÊãòœ­mÖøÍ³S¶ŽÞî®ÎæCŒÖUj®ô srŸÄ-†¤»™ÓI¥å-Æ¥‹¨ë’„VàÃb4ží„ºHï$ýþËN™jOt™®°Ñì; –wÃZ¾éÈO:d½¹Y~ôŠÕƒmU|‡Œmç6µ¢ôl¹©ŽQ¸dѵôŠÔ*ˆ¡iit”tE¼4æ0™ïÁ1 �íÖß ØÖ–‹c)oaÔØ¦qE^Ý–‡DR)ÚˆÏ�*r•G{·1CÁBâ×Úm"K8GþUtÕXÇXνe—�+TµÅ&ò1-~[FF€~j@ä Àƒcmîå%‡HÆ+ÝTöhÚ ®Yie•1�,£ÂåÁŠ>É‘ƒS”×Õh—K-í]ëý“Õ=#š(OìGhÆê}ÏŒ~Ðí¡×¶¼•ªD�/?µ­Hüü†^7�½ÙH±ÚѤÐþr©±•í%%=+»”nM2ãµv �9òؿڅú°`‡Zá‘W„�Naö ”b£O/üŒÄêQÚõƒ,r]ÙÚ ’—‡ˆ“s6J=<­yJ¿ÊÇǪ½Ð:,t¹z5ùƒ,5… yöå�¹IZgÕBqjzÁ×?ÝÓðð‹9Ó=I™‡$ú¬m;Ñ‚†ââÛ±î C‘Ê }²Eg¦—œÝv—¼Ðñ€§:_Ã6\o« •�\ ŒÕâÒ¦Õ�7ED°Þ8dòsãÆ£ë„Ü n‡ù=)CS Ùþ‹^ö�-¦‚V G3)m¡%[;G@ç�°-·Ò>‚RÒí*eûˆf5'�=+Áª¯˜î�™ïQAÎ�_¾ÙÔuwù¹–þªOÛD¿L¢`s&"*Xê¡öçŸÛnŸ‹�↠m…Ô¿ÕK5ZüÌ'´é´ŧkªœ¬«²°U–‡D’2Y/=tÈéZDë†VuU†êXá<|”ÑaOÑ1¡0ƒÎewŸ[œ·µ ¡j,-+ È6‘`&žðkíçžc„}z{^Ì5f=Oe6 êxŠ`·i”«ŸhHNhÄö–e ñÉ‹: ÉØÌÝ7Böå+žŒW1ê¦ûZÌø{kÓ/c…oÊø¶ØRÄY¦õ�)Œ_»•†N„Nç­ÊcÝz¦kC^ eJ!~"àCÀª/(ÌmaqxáÓ=AüÐå ËÏ`Á!~ém·ØK½Q~gC—SåÕȧ{ë8«�C8êHóÔ�}žƒœ•„pë|žÇ’| 9í#X¿J㩃9ÆW‡Ú%â§|ÕÓÕñRËé”»‡ú ë:a dðqž?{Ý›<É;Ÿ…l_¼²FYV¿üˆ>·auÅlR|$=`B�YðÁœ±öHRÕžZ¾áǶ°éÀ|ÏæøR ^Oµ1�³DIYÒùóixŒ6nUï²â ÓSçìÅò«Rlœ-ÿ kÿº·ÂŒè^ÜcÖß9B}Ýn¾ k¿ŸsÈ©N~Êd§‚pÄ‹)¬£‚pÔ¢ÕÜGáù(PwÛî@Rð®Ç5ëŒæ×FÏ�°"žhÜ£†d-‹P\Š… xÞŽÎà�]mJ�R2üþ�„9rÇmÁUŸ;þE«�­üÜîú/ï"ÄÏÜ}èrõrrv‰<“¿“,Ÿx?¯Óxü‰TçÁ*0Ò¯û†uúÔÿWk#³?C¶¥L¡QÛÜ2•BØ0žlµSqQ0OÔY©†Ò^FKÀoΕþa�\ÚKiþ~,=�m4¿Nn¹jÿKfQÉá ‹)� »¼^8Ð�z‡)e’¦NúLèÛõM0Á>L0 ¾}ûÒ2—‡è^dµ-c$oëÛYÍÈjO¡—ˆð( ¨µâþp¸„ª¾¤œlM±£2"Û(&9ï4n¬bÓQ‘·mž\Dº*Ðϱ`l ãŒmÅŸ7,® ™_Ë¥Üõ"³3ð{J’§ô}Âæösìž1 ¢—|=Q_¸ j,khKÁ}’sQGº6é�ÀÉ| œhº1pƒz;Úd@¢™“‰ÓÚ…´T¼¢7{¬ë¶/Ê”º´¤�Ë ÊÔ7‰Ýü@,,5Çæ#ó½·¶èèÊ[µ0Í( Å@ˆ¯²w3Äȼ–ɶIàgÉwp ù¸¾vŠ<-Ê¿fê3’(A’í§'ê—ÃÈçM¬^ã1Ç[4S¾«ÙöŸ»ž¯Çpš(ÀÈr¬iph€R‡ÂžòöÄ=a„'MŠó»!aQ3| NÚw{[|q2úÂñx¢Õ‡�O¨Vtßm¥}1ì/öÙôø58”vF>ÍIóÆÄƒsu9Щޯ–Úûë3/Ïy¨{#Wë)µtë À\�£B}{{ç ãXõ�¶,·�ªìcôÇà3Òä¥)ºÛÄÕäA ¡c‘q#òõ‡i�‰þšÛ¼/�àÞ¥Yôí$Ñs¥%»[›7AfÕ ±¼ìþ—Z¢ <¬´‹¡¤ƒ,µÑl—X—󣋠 –ì E¬HÆ“¥É£&â�;{·•¹IsÎ?M¢ß\7/už|z©ðÞÛÉPÑÌ.J»N�tÓ¸Çw4ÄJ_fDG…|ÔbÆK\qB‚‹ë½ài52Í–4Á;E¬„µüõΗZ^æQcf’r–²°k\YþRpn’ùáe‡7py¶é!Â8qéŸˆÌÆ*< ’çÀ8ˆÏSÚ—FuþDïúÎöÔŒ¡t˜™¥±Ùäâs3¢òjí[VŒ¢'ùJò‘ZLìXŽÅ=_ÕÂ3ú\IHW©ÚX,£hK`˜ÕØÿà¨a³�|LGðS/|Í…#ZbóEòнµ£ðæ÷ql”ÏÉᨴoH‰·ó�—úøŒp)_õ–SŠTh¥d~bZáþÚP.6A^E¯?ÇAsÂË9è¼·óp¸i*³Ð­–i…„røD·×Õ�7ë¨øÖXkÅj¯5óɺ킎°O~Ç|v4Ç«!Þâ7=Ò§’ÔïÙôéZ¥¸‡t©ºíØ–ó7á(†ÖB�êdÍ_ºxúTŸ½{žµ³GãÚª±�€gg/dó±Ä”Àrð¸Î{­ç#Ë…KäuŒ›ôD�Ì“à|Â2En(¦±l‘S£è6�¸®‘H•D%ù”·˜—‡žcŸ½ê#¬ôîûW�ˆ–“'%”Ô×ÔÞÓ…j‰”çÆ$Å�É�oPWº#±‰ó»G Õ¶nBë-ˆ}œôÑ£ô&¢Ù¦W/G—MP¢Çàf#¥¢„ç)FÛ²å3p¸æ‡uØ#^åuq²S<›Äïñ�©+YòâUAH¾Ö'k~ö’9š #§_/µöµìÅy�‚ y?Qx LÓ*YDRáåWä_}7ÉŠ¤GvfÉ—L™\Þ'ûÃõ=ÜÉ8ª.úÆòæTÓ׉XЭÞ^¬(¶‡…†:ª¶Œ?‰¡B=Øãß©P¿•üPŒ1/@ÞƒÁ81ªÒ8´0 B©Gr uí¢s¸Ÿ£Ió©\0‡ω/(Åa1Ôã«}3+ €V€GZKTwŽyEéìIð=ß5 º÷bvõ¡iµ7™‹(‹Š»Ù¼¹ºñ©%`YXyæü!R øšá@§F˜Ók=m£±Jôè×(Òð@7wÚëêØ‡Ä:úþñ�ág�¿z8ke!¬NÍ-2úE *£´…Îç9XÎæ…1"Æ/¶È=xñ3)?£[ÍIÔ*×1ÕíÝQ¾D�Úù(uàV˜šõÞéb øC=v@Aè-îðH{J¶áPt‹àépnÍÒTvΖy]3�†¿6Õ¥"ûøÕä—‘ŽbMMë íÔPÓëñò¸ví’v! Ô8iÏgŸŒ$Ýî?ß§+l»õß9† 7°O^SÔ}! ×Q¿G`ÄW2Ù+L�öêñ8Óf¨¢ò_gàÇ~Ó£9ž7-òï[°%×½3H7v¼€ÓrP„P¡X˜(Ú‡$š›?þ*°Àp±Ô»B©¿&¯â  ¿Ò½PHl>Ú@á*ÕÞatûqZ™m2!ýr2mŸ¢Wy¸«Õ•Ð�!u\üÖ²ånlà”êýݬæ$… IÊ+M«ãtÚ^ó^åC+êG"o"dí“ûû4–ÊHÑ`�—­U­œ?`Ì©‚âô�KjWø+ü¯â‚å †¶úûÙ¢‡ÇOüô©÷vóç¤åOñF²HR,äTà¨ëòò"ëÙ¦:ED,×y !„ð¤ -= šu@Y\p1Ó&ê(óœež/Ú[3fnèK%_Z4~+/јm¡x$ö×NS_Ösa3]Ìê»’N²"™ä™\§‡Lã¶}ÉÎ’ˆr¼³ñr UÆa˜¯FˆÃ§o<Œ“è®Ä£zc¿p‡)‚Kñ ÊÝ10qœU™í%áÇOb<3J�dÝQõn}ïjÜŽ8Ó(ãD˜5Û=‰ÓšHzq\"‚ÙîY. ö9¡4·#àyje.'GÃÆ|û®—7›c‚†6ÿ A³E¶šR©N°’ǶÚÄÛox+UÉJBJW±µWÖ«µ=¦øaTÓ ;߆/ÓQÅϲ iî¦#ÕBK[G=,P»çÎRˆ^¹  ð€^ hì7V­¬ÅϲÔ4åf¾ç¢¯¾1Vxô †×Ý-F›÷n»ÚÌâBumV+ÖzÊ$]1¼íѶ¿X.mQ‘•G,àÏñÉ•ÕוÏi ’\ÿêYïÇ(¬ÂnÙKë ´‘w,ežR�ÁÊÕlèy* òõ@gÃñlÑêÉ£&œ*c€úÙF «¾ñl…‡aîyxî©„þ´�_êWÈGM›}ÅÑqTà…òíƒ:aeWE)¡rË‹×øûAçŒ@„oZjem{pï¢ep‹Ž•¬Ä™HyÚþ~ÌN¶Ý’jºÞ×çÄC{~èk_|2>ùOèèlµ.éºSÍõùÙÆÑ™�RÈäc7ó*Où%D¾#©Îzk½ÓßϸÅ0´Á¦«™#ºª7×\¦6AÍ}õDE¸_ð‘œiѫˮÖgÂÇLÛ´¥?pDGFmN¤ ÊÞªõÄs¤3Ýðpq[Â[ÚÛ‰ñ O´øŒ}|º¹ºÁZ€ZñðšÕðM?¶x\¢ðb gâ�(!ͪù -T)̯ɻ (V7$èUŠƒ…Ú²žñ ŽêØjíUzle œKã8WsrÎZ�ï{6ìÈs™þs@Þñ~} »µ?ÃY¯ý oá剶;¸vi¤¦$ºc\š;�w‡¼âX½Éy1ƒM3@‚Ò8s$ÛPá(£s¢ò6D«§GŒæ±cjû¶�‹v¥m ê;y)ϼs\ g‚rËŸËvÄx•Ò5@˙ӉÇžÇèʳHyÅŠ¬#q�gwD 8vëÆú+/ ÅQÃZCU6;„c%�?=ΘG¿ÈL(Ú³PÕ} —õ]_‡‡²õ�nø›Ö1n÷um’;«zruMH°ºH%/Z>É‚Á@Í#�ú+2Á-ó!¥lÔµ¡ágV¹Ü+®Pÿ«@5ê5'âÛÑ)ǰX8‚�YÏO?—8iܘ-ª#玩#Õ"v[ç<%-Aó¹¢7vŘ:r&Gì¢ñ™Á«UÁÊÉil¥g�eÏLTCM‚„øô{nQ°«0ûÛXì¼v²�2¦ —8¯¨çùLõ<¾†™,zd&A¿'�1uýÁpÙ¶F‘Ú<ùG½—SŒÕŠC•§xY㾩|s–\͈‘4ö }ö»€Át/• —€³.…1JǯcþÞtøƒzÚ»ãI0&ÜÈ›BXv—i=HÅ=^b!Öîsnt¦é9¢6]y!êU”¿ÂUëEb†Ó«�:G™„`cõyc>[%Uäd© ç`À«`·è…¹Û+Ù‘nÅOþ nÀTMNܸ±Íˆ3†1rñMÏ ¬â#pZ©“�‘®Nv—ìS^R±ŠAšRÓãÇ$E˜ÄEzïX™˜Èhyæ{VýF‹ÓOê§¿¿¥L% Ó¡ëRÁ?POc�år)™hA1Þü–Æ­Fú_Àd†Å?£šö·SÒiãT§2ν¯:k}† [ö±�Bû.�wã*¡l�X_Ðãmj§"ËI뛺ޟ¥k¾ 57 %ÃΫãu} èxRí¬*¼À•ùñe£ÙƒìÐÛÕGçõ÷Û ¬/ÿ½ÛEKõ«°¬�Ú,œÈá1•RZ)¥ë'R!=S…ª˜íjŒMU$=Ú=ß:%»ž�çIJzæªü»Ï‹O›6¾Ô®ñpHþÞL8ó­B'�ÌNÜ[濾sñÛš-ôÈ=êŒr®n’'øÚ Ò†^íŸWKB%ßŬ�(~8xªª‹É@†š>Wud$0ƒ+Ï'‚ ¶µï†³¿’Iú¥ê®õFŽy~�d1�K7Q ŠÅëòän¦hヘ;Ž�ˆè©Ï:¦ž�&õ “tãôÏ;‡3ø-„Cgn,Žûe6ûí^œCÎ8“zeÊ;º.ØZƒ|Ãr‰›¸bZ¿u^= ùY_€Íê¤5, 'a†´?lµ0øñ“ëú®Q‹³À«"cpÉŒ¬&§r+7–]÷”T•�㵿³– ®PaèÙëp³ho>àôÒ>N|€— &íÊ1燿:üå¯B>o½ •¤EDj<ÎPrÉ¡{;E—â�¬{†S6üÝæATáµöDœêzòfaqžf¿üjH€Ö¸Ø¡ÛÓé*Œaj_M:$†ßpš2­fzåX¥úš*Ö’lŒ¨ôËkSË€ð¬þúKâBo2sN¶²pqsÓ+šH®¢ï@ÍB¸î7ç"ùU±WÈö x‹Äß0zS†Ùöh« Ó£\XLRß9)nmV3ËÕ9|î³Þ�aCî /Z£bo¥9ÅËaãÅ®ù›¼”“+F¡.ãx–.¸[ø–�œ/ÕgJÆ+^�ëw‘(ûÖ‹KÁ�j ðEy‡Gñ8–Aƒv UðÕÐæ—pÊj²‡[ûÎÆë¿pbÃzÍ>C?º}é -‘|ê³+ë³qüí5ðMš£O¦ÈQ¡FÆk!œ-¡‘Ð^ƒa ññ«ÚmCe·A Þó�cüD�î-†ÙnЋÉǪ¶ö ¡´Ÿj8hu|”yÃ$9OäI¿VÐùc‘�YS¶™«•‘~Qkj|p¾íøÔZ¡_ª m©ƒ±œ'­V…yFß}T9¤ˆ•hOã�6'Xä&î—þž´ÿ c s" [€b%b4S¯8½`õi’í 4·%^‹s€;®™ÂPîÙ4‘÷’Õ£.!UpI¥J„ âº«O‹€Ì>Woeu!íêJûS‚Ó"Ý•…î2”µ”«“ùÒí#ÖWC±×Úw1ë[ºíïѰy�\¯Õ2—£VŽ1;Jlž‚íùFd�ÜUz_ÂH,ˆ‰W©?—t«c8�;œç,¨/uk»Ì¶Ð“ŒYw$rA ^“UYÛÉ�G²cš®4Ââ©€}Ò–�={o‹·{Ð~£œ×ðAvzü›M#õS|ˆCÍÉÕðë1¤¿ŸUQ.}ýL8ãØp–ÅvÒž/ðÕ¯ý‚dž-’IG*•E[ÜàEÉ X oÅLòÑÔ‰JÚâÆ-Á;°d¦rÏãZŸèŒÛ÷  a6XéîmÓMr±.{˜Fû&îÍäÞn˜a4]ÁR kkRŒÀqÛ®ª6d–F¼í@�ÈçÁêç\Ë„ÂôuÇ-pø¦×:K$ò’pŠmr§²‹èº¹ÚÑt,ð¼`¿ïAE] ¼¦ƒêW¸ ¶Ìó~Û±¸Š˜>“ñ~e˜$ÖÀK¸u¾ßÐLøi)¯hïÐr{¼19…<²IØWÅIŒ÷¾ `åºÙœcöCyl.wè7“‘ýŸéæwb\ð©E»"‡»h`�Jªå»CGAoéqíÑ‘æßMF¬˜' d¨í%ÑòN¬P_�"GÇiíÑ=žÐ%T¿G;±™¨ªÕàÝç›LÜ’Ûʧ¦i‡)‹q`ëÑ*a¬õà‹2'èÐcEØïærÁac1´^e§âº�&Œêùػޜ烘<…d¨1*¤’8FͳP²6Oýh£UíÊ'7³v­˜nÒ©,�¯ÔÞUÝ…ò5±4'ì�½ÇÆøyí9ÿÁ™üUeÈç#�ô™ú¯>[-ï%7á¹À¬ûŽ6~¹G©WÙÍ&Ib( þ¶ ­ƒ ‡½Jå†<®là©}Ëki9nîy¯GÎ pÞMý2æ`•µ™¬Èjõ&ÐL¨j š¨­y$Aå*Îq`”µ cVK—}ˆ`ÃÍÛH—cåEãg¦ UR™ ¿Sªs£¢â ú^Oȉ^ý‘%³;˜‚¦Ó=UÎ;§b‡�ÅD¼ÜºM:prË$p;$T%zuÇw¦šûØi’æ#·ÿ¸»‘Ω¶¶¯¾íÎÐÕÌsÙm*y%õ^9šÓÃÏ+M˜u¦í|õ¿B^² endstream endobj 108 0 obj <> endobj 205 0 obj <>stream xÚ¬¹ct¥íÖ&ÛNE+¶mÛ¶³bÛ¶*¶Y±mÛIUlV’Š­SïÞÝýõاϟ>ß�5ÆsO^s^óžÏ3Æ"'VR¥6s0J8Ø»Ò330ñ¬ìLÜ\Tì¸åèå�fV€¿rv8rrQg ±«•ƒ½˜±+�  4ˆM,,fnnn8r€¨ƒ£—³•…¥+€J]E“š––î¿$ÿ˜L¼þ§æ¯§‹•…=€âïƒ;ÐÖÁÑhïú7Äÿµ£*pµÌ­l�QE%miI•¤‚:@ht6¶(¹™ØZ™ä¬L�ö.@j€¹ƒ3Àö߀©ƒ½™Õ?¥¹0ü�%ì0¸8M­þº=M�Žÿ¨èŽ@g;+—¿Ï+€…³±½ë߸:¬ìMmÝÌþðWnîð/@ŽÎ-ìþêþSrpqu1u¶rtüͪ$&ñoœ®–Æ®ÿäv±ú«8˜ÿµ4s0uû§¤éþ†ù«u5¶²w¸=]ÿÉe˜Y¹8Ú{ýÍý7˜£³Õ¿`¸¹XÙ[ü:€3ÐÂØÙÌèâò7Ìߨÿtç¿êüoÕ;:ÚzýËÛá_Vÿ ƒ•« ÐÖœŽ™åoNS׿¹-¬ìáÿ™i{s3Ó¿åfnŽÿSçtþWƒ¨þ™ê¿ ŒÍìm½f@s8F׿)Tÿw,3ü÷‘üß@ñ Áÿ-ôþÿ#÷?9úß.ñÿßûüŸ¡%ÜlmŒíþÀ¿w àï’1¶üÝ39À?‹ÆÍîÿåblgeëõÿåôŸÖšÀ£q°5ûO�´«ñß–Û[ü¥…‰�éßB+ +O ™’•«©%ÀÜØöo¿þ%W·7:ÛZÙÿòú¯–è™™˜þC§fiejcÿìÿVíÍþþ_ªþžQLKJYZŠöÿ°\ÿe¨ôw\Õ¼ÿbû¥È;˜ý¯Ã?aDD<>ôÌ\zV6æ¿wï/ n&¿ÿCÊbþ¯³¼±«³•'@÷oÝLÌÿªþüþë¤ÿaÄíMÌþUWc{³¿“ö¿ÿ¨MÝœ�ÿü¯Ëÿ·êÿyþ×Ì�ž@S¸µŸ¦¼¡ÖÙ™®õØù£ÓbºƒýÌà£aŽåMj%E�µ}‘»ÜUFïua ͳ<Ÿ^+¿?ehŽÆû±l)ûÒ€ ñýH©ŠP·(º8i�‚ Ê3Ï5c}®–åv t8˜4Žö¦•U ÊÞ¡f»X�a®ž¨IÝ‹1È‘üMÓ¿cv£4ƒ Õÿ>§H>}z¤žé»�8Ä£ÍûKÎkŒíŸú›8ÅÕËÈù¾ÉôòÕ�ÓD}ÂÍQGfM”!Ѭ¥3KÞ¼f‹& ›qˆ¶F‹ao¥®öñÎN>U#X?VÄî±LLÙ­ît±AÒ ¢mxx…¤)!‹¸òU=¡ÿ)®Å"bâønž“‰�±R†µº¾�*Ê¢=ê „ž⇬'[„7? {ê\IPƒ‰?»Â»€IÖQ °ç~à ”G$œûB;Ë{õ:hÙj½T«’æ†(N¼¹ë—Î e@DF�\÷º7Õõö¸ÉXx”Ð=obõ„V|Í® öxé#Iñûv>}íüéº5¬ö¬ÕúOŒÌ£í4­{‹jú­/~¼¯_!¸ S/ øË¥ r´—DŸÈ¢À*–`æ7q~‚JDeÇ)n‹ v€. Z²�“lÔyEÇKÓ)SœµÀ…ëè/œTY•¦gí¤CT·ÏÕ_$Ñïþˆ91"f� ±õò“0]JÃ0„º…åW qݸëX˜�áS^ûüº^Ö™lܹ9úÊNüÔÍ�KZV7ý�x…É7'åo†€—DîM¡Üiá42¸_Ñ‹—‘ ³ÆwWWÓ°("`˜éL‰èžº¶ð=3ž#áÞ 'J]ľ©V¶É Fbs®|ñ0¨½Vë°n*¥¤™x,½ž0åËí_JÙÞƒ¦&º­÷B¡zûa[½ÓaØÀúl›e)†i92ýÐôu<á×£J¶;2䵟»¹„‡?OÉ6faâzß!Úîq^”-â´8Í�bÊ$z²â0UxuƒÝ¢uN5LHw�nÛJ4Vë›ã1ç ‡}hî#*եݎ etè$ÿðð^€=)÷‚ã¿`$¯¢¡cä±þ²Ü:”¿½>ûÍPXÌyøâ9/µ!Rqìx'–2«î‘œ]øò®EtËžHÎ&¹›q:ÙP1ºXÿù¦èì"6U ÿ ~ñΉBŽf ‹&S³�#o»ù”eøÍCPåÀ;›Ë šêJ­�«Þ‹°²=³øz“¤Ç»7ê»E¶*êæ]Á|ôŠÞ*Öj¦_—¯Ðd"ÚÅØ©ï *Öe±o‹e8Šz)vS@]O¬¢1wkHr¢ÊÍùÔ–-ÝÃ*;Äø‹é–šrª ;vËE帓!½ayAÇÚF&>ÅŸAa©ŽEPfy"ÉõˆÀŸ¹FvÌ —&­ÃgÃqË>�h+äkåX)0´ƒ�m[´…ùY½¾ï¤I¤xnaYÖk»Xfr–ûã(òyÛ–ïh´…*�βáÕò»ÎÑ^€/0û®…O¦&¤ùª è� …®N¯’㈸:1ŒæZÞLÕ¡â¨ç’ýX1ú cPëeK‰ê,¡›Ö¿jj¢e]±ÅØKФWXü´à¾SÑ8j%dí�Žœ§ýÇE“ÕÄáÔ6¨% #ôZeaC¤¦–QÊPlb…`äÇš�¨Bêùô†©óibüÀnõUÖï}†š¥ÕuÃtBÒÉßݺö²r)×°"·MDñ»ÃŒ¯»ù7{ï˽µåNuƒN²if·b¼�M-óÁ[~Tú�­€û]T°±è�ó"-ÔO·7U!ñ#’‘Úºà)ʳÎu„�àÚ·.<É7å¼—Á¶_GÒ‚þb´›H©˜k¸{´¾LÆ5 øTzñêÙ.ΞjÊÎÈêl¯7Ü­—‡ÂᯢßÔHFù“»ýÃíWC†ðjP9¼“æw�ƒkç¦G yûƒ®ù~¶š²}¼òã+(kø|¤Zu@ò"8=q_™«©.÷{’iƨPφD¼1ËܮүàQͬÎ9òÍMKõ¯|G8‹0U¿‚·6�^–ÿ¦UóŽG?aU3ƻÕß6túà´SF>B§ ­¼%ÂF|?@ç¹SL……ô^-4è¥~yÄ$DH 5Æ“Š�ÚeYz±A©ˆx’^¬4*Òz|Ý{¨�*‡mëæ‰5ò£6i,@CJœ º I¥ÑlóFÇÒÒÀì7ÈËð·!?ú=¤ïëIúNü^Ce4›O–Ð+1gP4áYƒØÂuñy|6§ˆ>rÜKĨÕw½}S:2‚A@á©Ör¬›�µy­[kqëe1®j!.TFHCn¢G‹Þ~û´TSJÆÙ"a —I/�}ÞÇã8 ùv;røQ|»—ujl+H™Å T+×Ã@ö5¹æ®º¯ƒ02RKvi%òñY®Z¿ëQçÿ€M�Ó{Ðb¢ïˆÂÙSv3k¬ çÉZŸÁ}é•'ð›¿yæwù¸t­õÐÅFð­sL&çXö¥ØÅYáÊS ò5È\Ÿ×.*ðõ 0& 5�AI à °Æ…’a0÷wݦÏÁÕÀë›E®Õà­ÓíýhèŠÝbÑÝ÷‚=³u6÷éS)–â)RšÓ�*•õN½‹ èýo»·;ßM‚(ï7œ@§Ðäh[B=¤0Æ´'$þ¾Œ6I¯f°¸Å{‹ë=»9z\ )!’{€©TvT# ŸLK‚$*s)„Gß„´2'Ê�B_?³vq­I DÉ'qÕÄ1ô:­ª�Ÿë1]ÒæL§l•† Ž–%O†tžú˜Îþ�rëj]Búf¿¤}™¥ìðå�ùh«Á ùñ¸Hf}n®¹/)µßoO²ZÚÑgÀ߈¿€Ö<×꾜cÿ¶ð~_7`õã.f<¥7yJñg S�ÇùR†·¸±Ñ1¿pFõJx,^J•è“=þj o?½ú±å÷8òòªàØßékw¥K>ÏKF±�xTÎ-‚W¾È–EZèª/#—ðÙ¥»äïkH&QòqA1¦<ëça¢¿®(5&X>@n {TëUœ,C|È—Õ¥ö¯ äog eös"médêÚ¹Ó+wY:K ˜{y÷ ¯¹_Q¨¶Ù6úÅ4ÎX�¢×•H £{*+OM)í‚Ø�ÐWJ‘£àê òÁ4�„j²YÂâ«ñZÆ8.‰ùçê´X›ß$µÛC£ã€¶ä×iª„!ëÄÇ“ßEqÕJ§]ÉP~¯–µÚ�ŠpþÉAU ³ò-¾ÝÒü©úfNùÈ„YËŸÍküK30ØúÕ±X¥Ú¹ü©u*þV:žÜ4Gœ*dH°²/ñÓ¹ngâc¢Ÿ»´3�Žêþ�˜´|6²`<ÑÏuK¢^…·Ôk‚}‹Œ#5c×θeú^ ¢ôÐÕ¹;[ï£[èÏÜ2Àó\Éàúvrü�»OPOâ>1eÐxäús>mÑÀÉöÍMµ3Uó}R¿+ õDdë%,4JeŒ]!)©�‚kÆæ¦çcGÆŠõðŠ?¤Ðxë-"U|ƒÏ�*Uå…0×ë âc/þ&ôýfðGìPÄ®š òÃ`ªA˃¹õ®<¿£÷úFØú�#çÁ}’ÂcÞ€>Þ‡{òu{DæÌ³®: 7DOœ>sEÈÖ¨‰ïxÃ6ÆÞ£Ð“N8 àßêÏÂ!ó äå¹¾¼×õ \bÕ—Ü­hGæ1ZüÍ(š{šç�ßmÎûߺ‚} íÁÄa�ãANè@¿_ãd »Í¾šh ÉêÜd† ¿Å<©ã`‹O!+ö˪gîÙ}DѺ�Û¹¡TÜa&ê&ôI =Ë2.�ÖÇ´Yç úÖ§ÏV-ÁñÔ�7¹ !^ÌU5’‰�~ IÝw!�ÿ42”Ɉ vI{ƒºÅjãA½åÅœØTêu�†Õ–T'å�DƳ¤÷Ò$̉X„;DzòõÜ’ë¢ÇOްè0gj®UK×ÐpV‡Ô�Fe"òÃbƒ {g\iò”¬(�âÊÇ=ªjáS¹;„­©¬ÄéüÁz:Mxmk7‚QwyözÅÂvOû]`°ÄA‡—ëZL—Iø90¥ÍWl‹ "”ùU+ R`7 ­Ç,*ß$¤D6 P6}ír®¡ÙÔvLjX[�£¨ÍÑ­ÿ¹²a¤–&ŽEió±#wÔ‰¶í/m�M¤™fþ.S�/„tŸžZjà§Žnv0>ʰ>‹«M£zên&Ô£íÕ<ÍúéTO×°ù zŠdªÍÌ€óy  •›)B5%T�U£ Ú(Ì9j³Ø(øØÐþ<ðëg2šï29á�Ó«‰à»WRaÅkf[ú¬ #˜SåÛ~¯Ù‰FUí‰Åk§¤² Ql€âTWẗ¶0eÆÀ�€2Ïž-úc§� ä4ê²zä“Ô¦G!€(t#½ôéœJä°*ÈÞ›¢®Ê}žèŽþµxYáòVY÷>tÔ“ü‹Õª—y.ÆûK¨ý• ñ‘xM^«âÅÙÛ”a‹²kͻ㜳A´OûGñ×Lù¦¯¦ñÞÕ( VJaþL¼:˲¬ùoÔ\çÉÉLî‚If::—yÄçøŒ&§1¸\oË›z�å5Ì/â2“¸;}ÜïhùÇKG.£5ïð[g»áf…úVšüþôÈí»ÙÍm7Åà1³=6¯•¾»s¾ËŽÄajg|#a2¨]pÿ¹ì�5-øçBsh¼“\ñ¹ChätÂÞ`_Rjœ"¹u§ÅÔ ;“V ç4°ü�°§*­-ªxóvã«"¨b~bŽæ®¿T¿IàdσѬڙãÍ´Užtêtñ€wqfï,| #YÄ 36…¨¹]ç’1þ y'˜\�ÍO˜*w|l-SßìÙY6=«Úe¿-ÌZ?ŹÇ^{¾¨¶ñ£Œ3Ý�›åtñ Ñ¸:†‰d¥aG�×O�ò4ô"HcŽSlÂÕ—00�olA½jÙÿv:KÝÎ{2^%ªýîŒs6_†àóbl&<øAR#1U!HN«wñ„ޤÄMä$^y;EB8ÖM”«fRF}N±ª03�ºM©fh¿œ‰‹Äa‡þͤkIü–Äîq$^]¡åhEÃñ¸Èµlb3W tmmö¤FVKr ,�¢×ÿ�ò>]±îã‘«Õ ÔÔ:z¤" ·7lABq (ó¨ƒÿ€.edÚvŠÝ ãiÎ�w %xŒŸõ¬pº¯Îgô4ñ‰BÚ4 ‡:r*ýU‘Sâߴ‹T¥{àJ¦þ$h®¾%w«LPê Ìlw‡ÅP»ADnD{ö(@.“n Õÿ¹”ò>o“ËÇêoü«&³/­ž—/â `£²æ ZÛ"zeo ÁË¿tòzÊw…Ú)²K¦›“»ƒ˜X¾ eä�‘,@6‰žîÎ âüc[êΉ[—äÍ}ROÇ3¨x4›á«hB(ënd‚¡ÈiÉϲïãì¿©w+[WˆR"}fÏíEüœ?dšˆí«™Š­ L<©UÕ÷çè&ê\f,›xâ4£K%×ÜÃçâÑ Ã”jÔÙkB·Àær�¾ÃÊ o"Óà|R=3iPE|ÔU™ˆõŠn¶–C˜'WÐ̽qŠH:Ëpƒ~¨ÙIèÊH+DP‰¹ˆØë­iŸ�äH×l’µíÖëªîuôŒ¹÷õºv�m%­ oY]çûF¡%™1Á> ~C6 ]M«|¶s1«Ë唉C�2Œä5üY«ü)"¹Eb™&vVñsŸ”©O“ñÙ%.Í®WPŽa"2FãÌDxI|êÐ髽§Y±ö*AÉLmaUÿFvË®Z«XSŽL'`Á ·ßp)÷³w§ ‹éüý’K™ûÛŒ—ý|~KÉÎ-½(»ØÑmǸÜûvOME&ŸÆ†¤/k’’ꑼãÒt›Öóšý<h“|lÀj³ Ûl÷ú![qètŽ §è±\�1¸½ºÍ’8þè ?aý*GI1 HLdlæsŽp8Œ|§pN2zQÅ PØrÀ󹇘C³—º^Ìg˜¹yÿJ�ÞàóJxG—É¡sôÌ„ðL&�V!HÎ1;þð·HÂu‘sõñ–òýªhÜÕè˃¬?[ˆßb<¼�(ÔX‡×Ônõö”µ_±Ä—?j­Æ©ß7VÎ ÐÔcMãRf[æT‹—S�lkþž¡@Ïñùê±hËvÙq»°œ’‚g6“öyo}èg˜i½ÏU{ºÍqáÇö=ß3ãÊݦ¥æ7‘ Ú/­†ÚHÈ~³Æå‚[?vëÌ-;�ÈìºRÛǤÃYþª4:Ä/ɘÏqâ�Sµÿ ú–Ï] «Fü;?gdø^rRƒX.—“Ôx²ú¦ÃÇ}ì7mm“ßGj�þQÂEÍJÛ°±+]@l"ž›Dk‰‚àÞøãVû"d Èöz1¤å˜Jxûa2¹H¾¢3¤™”P¸šŸà3fÊj§qwì÷r¹i¢ ÷VçLN¤HßåÝÒs׌FŒ÷ž*çn,¦ÒîHQT—í¼"µ1EXP.Ê3Ã>èJÜš£³µÒVÁL¥GÀ*bÒª¬òÌ 9•BÒóË"ǨoµŠ¡¹Ýo+äi"S@Õ:’³>Èk€£Y.Í$ކt¿:%¹,¬‚á€#Àg¾{+ET·/tÅŽ'G½¾ñõñÏ·ýðñÖ9eYe“!𶜈¶ ‹ÈŠõþ0Á˜ZÕÝÆgœÚ%$›<Ð'Í:™¾Ä;ªäbè&°‚{amr©^“µ«q.Çjª,¢w7Yöñ~t›¬ˆhz ÚôãsZÛ«2ŸBÇäÖ°ó7uô#ÉÆµ;óŒÃÖâMâĤ- ;· d9›YÔ?íùbÏçBBmÊÚ¥âk1?“|¤âºËïLªlÞ{Öô3—I÷Ž|õ’F6b‚œU¡¶Ulºœ�ÝÐ +´\÷*—\7K•ä’i©êÇõÂár’¸DwôBׄ ¬Ó‘‹=Ã'¨ó Ð/œ3Rç™Ä´_Ž—%žæ¥iøÏ[¸ˆh;ÄhO�çJÆ~¤Þ'wžQA¸°4ž{†Š½…š‚†îr:ÚYñ—ø=è4Ž'S¬€èÞ§ÉO;%´ ÿm…íú1UôòOg“C_Ósy#¼w?\.'Ù- ©hóª:‘ISi[7ëJ™ãéNIìÆ-î1ÉmM Ú?jb0Ò»&o H×¼óGGâ:‘8õ6Z]úÔ�Ô©ÒG[‚NB$¸xO}A¾¾–¥u³&q\1¡­âð[–Y( q>elpàéO¬¥ÑצÜýÅ’áxÄXq²„< Ðfw¿s—$ÕÉîcÌNlWT‡*T•û°�{Ðb^2;¹XáEßœ€xuv§v(ÄÚh­:C:gWŠœ Ú*œ$¦üZ±ýíÛ; ™³1oDj5Ëf9é²¥¢Eq¨BÏdy˜õkã·¤e|å_]ut>,å`NeŒ¶Žñ€±5ù%½ç¨#ÃŒÍhÜù*BR¶Ã] ½Ôâêéåu¡0q1©çú³ù:õ¡}�ºš”«: ãÈ<ÈUà9“ãÓ�?Îwý«x�' ^A£“X’9–¸ŸyíÌ;í7²bƉÊjPU 'ú@ývm¢»'WøéþpË hqÉfáôX­||(7Õ¸¼ !óýnÜÚ2„jÅO�v\! N¸ŒNE<ïÊ9¯U»ô–›û¥Ot<ød87 £;’b’ø­qðìÅó0U+êCí~q¡C£ÚÁÏyáð¢•c«ÿ ͉çÍ3,¾ž(ðd9•JädO¸Ÿ† IC�†H5!#€¿|3‹}3!ø÷zÜo‚@Ð"iLˆž’DZ—… ‚FÓ*¸!;´døÁØ¢ú>ÙGÅÝɲDÞl`«'ú‘)ì7Ë·'u œ³w_²Ýq*­l–䑨–b#ú²ßÏU'ïÞ\G– ŽYå$JO*‘Õu_þWQ "®N[­KÅ¿kWÁ*$ml!gÔš›£ó˜l8�{TásGoÔè®CÒ‚(‡2 Yøšb×s#kýÝFÚ Á‘làT¹r˜Y+ö³hhøÚ³µö·æ¿?+ÙL'„Û…|[7n 2,_˜Ý“ÿfÑÝ>–ʵt"œ?Ï@f„Y’ µnzŒLè‚ÌõÆÝJO>C¨[?c6 #[e·Bš þÙŠš�4�XÛ½€nD&soQ‡žÊoæÜìøvR6›•ŠÄyøÚýÛ ôâˆK}…p¢Æ0×?Û}¾$NöÒWÕœ;Æ/7ŸTã«—ËtèEõ›ÝȺZè ù�>¥Z ²ít8¬’ñH>øßïcL�Ô ñ û[RîÏÈ\`H»™²||É÷1M#.ÃrPèÛ&zõ* ,ÐmŠª­Iãà‰³MS*š´¥Â]‰m;ëÓN‡�õè„eùÁ-`I·Ÿ „8IUµ ?ÍÌoßÄœ%²Ç%Ž7i;0õsÝ2�Ó§v‹ŽðŸ<§OßõåPáVÐíhL ¹¥•êî’UörTÚ‹ùf¤—$3 V$ ¯ÉŽs.ONyæøÌ¨é €Ž˜ÜÙE! Q�-4Ÿçg8–¼½Äï÷þ k`;·wÆ�)1q ‡•¬Œ½ë°ÙöàB¯r#׎ØÂB(i”Z(ÖH< Ä‘2Íù„aŒ¡`›UúZN…èn‰-hŒð³6H4~Ø\�ñ·©»§öÆ–?Œ!S±(Ë@áPá›*UÑö’ë:èäC'd‚ žx æÂ–EÛf[ÐßwC–~¾(cV üʇt3p‘^bÑ[ý¾J*£ò4ÁøØÃÖâ"}¾KÃ9|pÊ/-»ïj—­Õò`Í%¢™µWý‚&,=ùè˜/m)©|Ù!L&Æ@ÝtO˜µ¯ ›*Ÿÿ<�œø¸šZqqÖD Å€SªZÿ‘Ššâ!p¤ÇB`SZüƒ‰}>Agô›%ÁmQ0½˜XF2ŠHs0ß®4ò ¤kü+lTãû²ö«u=#Ö¾?H'N…¨oâÊMýÌ­úÖ§y§fåZ‘Uh¬»»÷Kñ„±'s}½�d‡RÍÇ[Ô£–,O²bu¤4mÖ0ˆk*¹—ÓÈ•�_]û"ŸÐD¿ARJ –g)t­Iø‘–ÖD'e‰Ï7òpoïÃrÐa Kƒ!^ØÏG8œúD9tÔ¯ur›¸uõ" ØÍÈTgØ’Õ•@ßÖ¯—Ã:·/§q€Ž&wö�{4|8h6ïqÑIcËö Ž¢‡¨çöëèì‹„N«M$CÔÔGõ;ôz ê“ê]ñÇÆ[(b!ê’zÂ{ôãkÜŠ2JânÎ[•¬#³f0…šMÝ“p`QcwŽfïy‡p¯¦Û{ñ&I§iÓÕñ�;}þƒ"‰Û'å~o2t¥¡#žC`×LÄ–·¸dz_¡µ8a úõÜECÞ|(]K”¯ýVlâ~£œ““®¢ PÒ ]°<´ó£>�su~ñÓ“ý£»ëŸ±’Jµhjzó¿Sʸ6z¡(KkÚš¢ºÁU)1d1Ê™™Yw¤ ˜©h_w#VÛè;'´ˆÌU£GUˆÆÆ\±ÊQ·ÓrìêY[F©eÊ:øOnò»¦ÞÆÕ±œ°Þ þT1žXÎ�J6};”ýE¨*v»Ykµûï“rûaÕUÆùÜ�õlÎE…Þõ} éqGÉ·Øñ1ï;ù˜j_Êý¼4ÏRÄv9Ɖ©mÊ!î,Þæ×"@¿IF« è,Àp6ÆúKµ‡{ZžB ï4Â�aÆO�Õ�‰´¬˜¬À·Lñã×êÂõÆ(¯¼j‹!k_DÎü§¢šà–Ak1ŒMWöv1òq@3Y§à_äŠ]¤# ÿ‡ÿß¼ HM"LN!.· ËÁÃUJ:Ïe"-NÛˆä!��±Ý�Ž–÷nFF¥¿Î%3“½ &-¡³Ç˜Ó'ZO|×fœó�ƒVi£yfáÛ†d¾¢Ùß»¬ñ‹}vS˜h¨]P×™Q~¸?í|Gåß¡Nqv¾ØRœœ¼‚GŠJpû~EN,ù”îÞ÷Ý~ÿºoË÷ѪR�Ä™�ßïv…«¾ýœÈõ*­/9�¾…ph‡UûérÈÖóazVáüª+¿\ç~Æœpsº÷W�¤X¬Ûè�K ¦Òh:(z"(œ€®bÆÈî™ ­ƒ º&s·ßŽPóÉ Éþä£`Á�EšGåœ'cdäo ÈÀx`Ñ÷I ƒã½#ïë�UçxìÕ0^¡3¤VÒ°;F¸�·i*WÐÊ�: ŒÝ\2VHº¤ì{, èi´Û“q%x�¹@…¯Ž¯ßÅÞ-uÛ_Ìt`½žVÜI–ÆCN[x–ÇÝë�Šã,b½ü�«ñiªÝ_2°}í°dî…bB«ÖHY0÷£„gÃ-ù,ÞÁ ׉ëë"µ�!œ°1tìåpk0QH‘ýÉÇwhN>óÅòmg£±Ïüdnãû¯®iÅ`[�““6¾¸ùE^^øþÒc‚ѹ§C¾O»ÉvªæFgOöÎÏ1�ÕÀcSÆ©ð³„ühpfexš1F3H'¢y¨"»wx½ÆH…ÍXoÊCÍ„n¢ðE]§aïV‘¦Êwç„/†ÁAR³ ÚàŸà°C"nNÂC8‰}ŽÄ7Ð(3Ñüò¦O­®Eæé#I¹Ÿ6¶þSºþ°x¨WO‚ðÞšRãu-ªN° _Ä $b(bSo#!½Ue¥@¼W™æ[�ßìžPÅó¿ XÃ#¢EÿT)h‹¢1âTM#’MÇœ@ÛÅ9zÝM`ù£%[sð`VÖòËÐhl–³Aüñ‡ï©$µ“m�ÞËp—X0QrM óÀ8 ö“~Œ×–çЃǔ5'.ýý3`½('¾Ð)�dît€#2¦M’�¥6Í…Žº›Ò¡\fÕc˜„ý†´ÂYù47 'WöW¸8yçD�ìZmê8—I‡÷ƒ(ü¢k$~s‹jÌ4Ü}zKÿá^Љ”¡ÊzEqOn�¦ß¡ON‚“ñ%%ÃCâg$DyâRiPÇ÷Õ n|�“˜þî–XHðPW$7 P–Å4ó—QÝç¡kÓeí5ú$æò?à ‰F*H@`¶¸¿{"ä½…l\Qoï,¢³Ë”®y]»ˆØ­¤éDÔ‹?,†Z`N·ˆ�›*v¦LØ=qŒêL:£P z }ÁzÃÿ(0߆¿³.¸ŽÿdÔ€Ãjý8XqÃÍS¯ÅÌ·uBš /4Ù—¡¾$y”ˆvM„:óÂ;þ›†sö@ÔfÅ“›PL‡@¯CY¥êÓò ¦N*Û¨“—Ü9*棩\_GFT†šØ‚bq*ï�{IìÑ듽=<øgoå[{D'ëâ ™|¼[ãz£ e¼ªŸ3ã–õ›L貉—ìýƒyßh<~?˜Ð@©8Í}à+·¶Öv O¿s«ÔCçï¸P:xÁ’ð:ÐŒÖDlá=µ5V#'êDUµ�V¯=Ì É7>Ò+ö—�b÷ù¥/H:Ãt§BÅÌ YiN½3êÚãRøL¹¶Éð„•î1¸£ˆ¹J½°pÍ)]�žû[sw|.ˆZ~J[ËeÚ"Í­l:‚*Aåè!ä´.¬¯˜ÃU—™}©úÊQjä™;líŽq¢‰„ 8f"®ÇÕ.EÄV´\QŠ;…|îÎ'”éóÇ{óÑá—ŽM ð¶£¾°Á‹wßwË�N1%nß] HòërzSvÜ�ÊÊ¢{m”ëä�ƒíó޽Ϫ²A�Ooû§ê•Ê™ xö°ôÐîýùûZWD�Çx§*_¡šó,·55v½-aøeáÃÞgÞq‹³ž’m¾lç ƒn­áiöF¨ð³‚ƒñ�ü"b{$_8�í-Ô?þ´qòɇ °©¡VŠ+�]‘nqŒÈªGŸž±¬JtÉž'h"'ôcý^¢Ðgƒ]—¶¸T¾›+}P'$‰p¢%‡ô�n„C¨-Z˜¨ËàCT΃9 &H� ƒdÈuІÞë‡Qþõí/Ó2 ¸hdÜIÚà†¾qÛTšûm^ ÅÇ#4xªk±¿ÂÚDˆ=æÁU >J~¸~c ~@òrEšé3J léq¤nXKýC>¡Ó¾xË_ˆ¯Kq�¸ñüæ«pIÅÕ‚xµò§{”‹ðÙdã£'û Ù�S:zŠ—œ)7 a3oëH¥Âó»2¡e�Ï|ƒÂÔY|8æ²O1¢‹“5Ìí)‰Ž•�¹އŸ‹QzÃãì×vQ‚)þa�Mä{øÌ=áæfF{bòÁþÌŒR¤»GmÎz‘jÿä„u€ÚÄ(žM"÷1¢ž€NCãöV“²Ùºw¨zÒdÚÄ¿wGãø>w†h“�»—b3Âíhœ€swbh‘q=«¶ÓÙ@§9  ?HzÌõ,A¡i8óÜ-æ„<Ÿ™]ìRŒ½ JÄž•¯Ÿ 3HzFLJiíäI‡ò¦•@\=ùáT;¨i®#áfϰÚYóÅ�ŽÌ°íì–¹8$)¾ÃD 6>åñê„´ª`ošzjÞ6nê&f'qÞÈǪÐöuFc¯ÿà_-�調մKLåoeæPÖ�E§k(ðŠ…%ÚDz`ñ±"ìõó4«$¿Yæ Má„}³I[¥¸•MJb_5¬.Fí3¦aNÉ”´ð¢M´1"ñhÔ&“ìÝaùó¾G2 ·ê-7"³¢ðë'÷³Y÷@æ ³x­®æ!m5jÈn±ºzíüº‰Ã çà|÷‰^ÞQU‡û­§È ©æÑX¡^Õ±Ý@�‚ y=¸_zßK5…W߇ZF“ ì¤'˜ÂV–¬ÇÕi�ÿn„cӪ㟖}veEÿXЂ\5ÿˆÈƒ+’@ŸàªÉ¡&~¾ ã™:÷çeG „ÚˆsäW»ÉúDŒðøô'˜ÿΨsÚ²þ«j ´s�ôð�$£IÅÉ�Fëgeq°�‚”ë’H—k §‘X篗:ÙÉê�û¢Á%”‹ü–ëö˜ž‚Þ†Vã=AÁ^yåMCX¬]©%¶¦eäVêí }rqÑÏ•BFú¥ØC[|˜¸½cL`7‚Þ. ¬ÐÓl‹•W¸“>ÒVb~wÅÉ@ˆEsv“NËOÅ·Éñð),Å�h²Lޜ޴�óç ¤ÎÛ ÄÖÒiËî!ÒªþêV^ä5¿²ø‚�bœžfÖ+Iõ•8åDŠÔБºù¢–_×åã†È´Å¿qS ´\1ŸeªÑ€Ýáò­¶ª´ çû¯dGsvìr¨Žd[Èà6”ædÝ�ŽˆZ�[~¥û�“ :;@Åèãý]�Cµ?|:¥U®Æ‚]ÛgPĈz†ÄÒDá]"�u_hèÜ.gÍÎLÌó¢hF§¤äÉÌ—JÝýÍ{Ôg:"¿¤©Ï”B?§Þ:tZ@;\ñAmT=S“£¾Jô�—χև/�ä[4Q*ü›‡çGåKÜ)Ù¦¯å eü‹W(§‘±ªXq«ßœ0O>rƒtÈBxbgaî'êóË.Ë>e9K¿$L`$jåuãbßÄ/½1êä¾g‘xá8lÇ زu©h>%£??KQ\Í„å­x-¯ ™EÚC–d «SZçGœF¬^+M•I…ŽÍ.C¦˜Ñ™ºî¸@×,Ž_‰ÛBŒ\·ƒ<·4'Ð+¥zŠ)g.gz¿‚gú£—XWßôÞ?º3(‘@«k6ŽT’‹=÷¬ÛúšÞ*•0‚3¹”_ÖmePûUw˜ÌzÓ?št5ºKW3o4š ŸNçfúèWU´ÌI²�)òÓødyÕŸŸ£ÐOŽO BLáæ�ÃÅÿæÿÅú+Aq@ô �ÙoØQWItÃ|H²¦V@ÕƒFZm¤#| Ƚdô¨:èƒÕfÉ/ Š¾]˪v‘7õÒg#Œ;7‹#}uøYš&u-mKDdGΑÍ2Óý@¥âÖlÈ­²¨šW\ÓUá§€6„f~ñ§sn � “'þ Ú+L‚Î~ŽHz¢–™ZdfÝ9 Ó5†;R1ÈA*k–h¿Ðk± ήäîó#ÓQÂL…ÂÆ˜€ê·'pÒœ³ñûÇáÌòº2Ÿ©ÆÈ ¨ï°B�»;ÛÁÙ¾qÂù�ác�h¬’Jö›åäIF†§añèë» ¤åë17xì5ÛŒe˜´5â×THÑLj•Ù¾ _Y;óÎkÙOúÙÉc3¥ÐŸzßõ›“ ï..0¡ØYkµÏ«:æiND›3}׎‹ŽB«í‹Ã-™ô[*ãk;ûZ'5‚X …Ò»þ“IY—ˆøŽúÖ…¶Lé¢a`‹NïL:B<¯'eìžìßÝk`Êô¥4uXÙ>e5~É,e~Šê¾eô€Øà`W4LÍ2®ŠLgd¸{®.5 X–'4ê½Ø�X�Ó;A^€“ë*ÉUµ©ÙHZ8}u-/¾Ê##ƒ·¸VcW—câuÞ|FãH·'Ñ™]¥¾ƒ >´O|I„®Å35èµÙ9¤NZ{f¢¤Ü!þŽÔp�© a¿Í´Ÿ˜Ü•оnh¾õ­lN¬bçµpo]¢Ü�ÍD�hbª$Ì…´Œ Œ;([§©«9A¯2ahJíÁ³[ u6YÆ�§:ŠŒ²ÛI zñ§eܸª[ ÊIÔ»Ë8ÒÖWA_GÝž‡¢Þz"£‚ Y!ð£‹ê×E££æßï4§ ��Eu†Ÿø^gä)QYÎÈÀ8¤C?¤il²yQ»ÍESwEŞPã@ÁXîŸ|W£û�ý#­ߊúÇÁM~¦Sð¤q›­É`èz�«†ìàCPA\ÎÇm±<:K�±§¢a¿-}7JèÎ}ÉÕÕ é²};èóôãb`Ïf×FsŽáJøC—N‰›ÌèòºSóm u‹ G铇µô'– �Y)ˆ3KÒ}Mß ½Fê§:Ø¢¶Ê&iÞbS»zÉk¹_³Ik%$4¾�ïõ2'€*à)nzúmÏY)•’¶E´lxøsÞ úSßáQeâc“ywÐd‹On{%42Ý>pSÛæ^ö*¿"Æð™ÐÂÿ—B²ÆÛ—Ì�º§y×w²ÙÇ£iÞ-ÛL^dh¦߬0.ûùƒÎØ+ÓÿÆŽ™©W’†ÐÁ3‚«ié�î]¸³SÞ+í.—+šQ‹¤ø…<úÊ›?±Œ­M®T;טD­M.YÁFÔ‹Èé�h6Ât¬Àmhµ)ªPئ髗ä*� æÅ?^ò¦y‹a]é@“ØóƒlÄr¸ÀVnx¯¨ ÂJ)Õ•Gw5ç`cy.w`6|"=�÷ã.^� màÓˆëYÏ[ g¢=¾rKVe6Ë)š-!^s¸6þ.œtøR)áRZ“j“Á¬!æÊÞ–m€h�Á¥Î#çH[¦P\ígÈÞkÍŒ¤gT@F›ý8<ÈÃôÀùAªiTµðQ«3PKÙxK"àêl…Jw)KLÊI§um÷lÔh°{:[õÖßêò¥¡z±Ê®˜«œA~ïÚ@=’û4Ê�/Ù#ù\‰iÉå3¡ lŒ�øŠMõ·Ù/pI$%«¾nÚšf[žå]í³»4E4�NØF€ø Gñ‹ÿÛ²‰Ú+óš4G|‹›deÒ7¸µ Fª¾³eTw´\ø6j†ž+ÅU™ÊÔ‡ø¡(*) DÇY Rxú¬<ªÅš|ì[Zç.ÇsŸdî`LTÕRÐD‘ˆštú[�=Q[äJAGù9»7»no¾ËÆÏ«5Z�¡JÅÙ‚ctì3Ö1r-Ôz(²¨íe™Sfrp\å².v½1L­Æ^]eìØ–ôÓ ‰6l³oŒaÇ–<‰’@¤w qø* €ê>£M s@—üâ›fV‰jî¯^{ ¾ë»žoù%��rªgbZ8ŸU�=.UtAÙ2S¾]¸‡÷j,2rëHØòd°"nGýý@Zª3sÄ€›)IzøÖÄŽöeÅY~}|T ¯-ß]= "¼›Š•Ô«¤5z¦?ûüý–Í[�Ú%“ÿ™-B}ƒ1Äk>¹¿$‘°º� "·–ØTºÊÌ‚4ízuH*sƒ=“³"€u¹—¤E–‚¬ó¹³q M0™Ú�dü§ÛÛĸ‡)êCÇ\¢/ •eÇ:ÒÅ& ­eð€G~�¾èÿZ\B™^m›±¡@v©�Hé·CØÔé`äËÈñ-þ$»?ï"qŸvÞµÇbø=à÷@“èe’kƒZT&!³÷ ˜ô£ð0°ªãê}ƒŠqƒöc¡ŽðÜû{ÐožÈf0¹�ì<\Ä�oÏÅi>»‚•7íEUìÇŠ½?¨ødc.±Ä‚ª¾úùez[µh´¿zÍÍì„3¯dúÇ1ç9µ¾ö×üy�l}¯ÞJ™aÜA2Â'£õŒÄ‘ Oƒøɤ—ÕìI\yªX…cyUN„2´Ý:%W|Qn—eãùf"o)ªØ–ãh9Ñž@™9úËþ e%gw/^jâ´Èñ£Æ§4¡M*vz‹ì\Àqå7‰g™‡¾šùŸGÛáÁê–NRåbâמ®Vk$„¥<»8Þ†—ϰ?³ O§ŸÃ1ieuÔWPC?‡´)Š{-ýIˆ½Ö�Ô �â=Q&Xžì2{s›K�yä´2˜ScaÀ¶j‰«PÈ£ ?pà–i,tàÍ(Ž~�Ц‡õÍe~y ¸;Ø./æ~¨ÙJ˜�â­Ó}}ÇJš˜ð+ÚRMŽº­øl¥u¢«© )~IÔ’j\çÑ5²†EX.Ü+‘½ä' Æ]; Äö1‚OK1ç^˜Tþj&Ó®Høió¢¶îðÈ=ãHm‚ˆÈlQ_ ÖêH˜<�HSc(UFÎ[îYy'„WÙYÁ-­&Ÿc’çæ\½­bäÅ͇óg¹Ø` l- a´fcðÅ<’2@Ù‹T·ÇÂYΪ۫;MN6î®Yñ5F_…!mšþ`¾o@Ç›ƒŒˆXLœº»\s¿WÙ;}L°*¦Æ¼øcO±�‚÷ÇĤϧáªTY‘fä�žmÚ¼p§³´ù¶¦'¿Oeã Ÿv¡ê"ïPL9g¨®¡xiœ™Ïï G¬rlzK_µÐ©ýÃM–Ó°ËDƒ} õŸ2p¨ì¸³ZÚá �Ñ Aá ÿOúÿE]ÙȬդ°åÈ‹�£*Èç&Í.ëîš4{ï�k¦óv¼d�La$âÜkbƒÓÌ/c½4ÝbØáä_€�¢ÖÒóµÂs æì;>"�õéÞr7�–¨ýH÷Ïcb•np�ìÍÇŽ˜ ×aÈ­ûQù=òήg*Ž!ªV¤9¹&ðÄ*˜ÕÙ³ï8Ⱥ�ôt‰«3žýéðòî`Ô&ÄwÂS{ÇálõAb~T�ÑΫ\�øHú)>Õ÷çq4ãÆùŽEóÝòg8øeÏ� C’³Ñ� I²VæÀ½™´m9DÄ5|¹‡‹)ÍaÛ×@¶R?í·°>f$O‰§È endstream endobj 42 0 obj <> endobj 206 0 obj <>stream xÚ­veX›k³nq‡-REŠ{‹»§¸%@  Áݽ-nZÜݽ¸SÜ‹)VÜ9´ë|ßÚ×:gÿÙûû‘\ï3÷Ì=3Ï=ï$ôÔªlâ@¨Hjgãd稀mÍœ`êP[¨ ›2–‡›B�/&=½¤#ȆÚI™ÂAB 2pq81é’P{7G°¥À¤¥®ÃÌÂÂú·å· ÀÌí_Èc$ li`x|pA ö¶ ;ø#Åÿ8PÀ­@ 0�|«ª+¯" `’UÑÈ‚ì@Ž�M¨:™AÀæ%°9ÈbX@�¿s¨ü»5û#—8 ` €ÙƒÌÁ�a Ws�ýoˆ`r´Ã`�Ï0 `éhj¼8¶3‡8ðh·€þ)ÈÞúèaûˆ=’©Bap˜¹#Øx̪*%óW�p+SøïÜ0ð# €ZªÃÆÉËÎý— “»‚€ª`¸¹ÀÂòxqìZv@�#lzøÏÝ>qpüÓ´›ÛØýV‚÷/düg�šý)ÿ•œšŒŒœ8˳iÿ8«>N\ÓÍø¿™t”¡À~SIH@]l\�¥°qsñù‚|<^ÿŸ¬x8ÿ>+›ÂÁ®}vNÀã÷¿>Ÿ ÿA#mgþ! ¸©ðqêþmø ›;9:>Šýg<6þ¯óŸù�\Aæ˜sÓPsá@ë¤Ôdx9IFÏ�”~G;'RO�}^•fv¦o)´Í')tE°Èä¶,ˆ½zDè¾Ámj×þnCáåf_;1„±-tð…‹–ùkæ³%†&~–MÿWFy8É?u"='•–‘õø8´7W‡ÔÔ�roQ_Œ4q;¢^0ûÒ:gúÒ�Ûãz›'V~ j~Zý¿”ðBÒK|5¶ºøL”Aí× I2Õ…Úcu*¸¿ZÞØ5Uœz„õÃO A‰aÜW½÷#kkɸÎX9AADbßë½X?(Øê½wV'6h/ÍÕ²Jx1Í·Å‚1ÑT² šzö™S:QÅ›pÇ}6ý–WÑ jð2,2wQÏÞÞ¡Ø^#T§à‹H_ ïÝ";�vü¸’�æVÒÛùôéò�¸K^9¿Å´»¨WdÐ{x]C…äСdkp»Tx=Jî»Pà‘²Q‰ýÞ¹pÒ/'=ªbaW„ m[[ 2ÒU¶á1p àÌn4Û„ÊßMΕZÕpW¥ÐP'3” ¥¯|»¤¬M7ý�Ï|?9F·m£¦c„ò!é9æûI{aq錊ù”“Ì:˜2$&Œ”í-EwÜiWZÜ´¬,W)¦> q`ñë÷lbê!¬ËsÍøfe§Ð1.ŸÝh·Û›Š.­þ0¦ôo®»þû1±@¯µQµcó—ºê£ªaZ ÈÅÉ /ÍQ¯&?+&7ëËh·ŽSŸ®b��ùò JY~FОzq³'ƒç]©Ò‡ä¾)�…ßo¥�ó2ª^zrvMÈ–Ïìµó†`€^¹´\ôP®GvTƒËšiÀTì+îÁofÑT{RáAIÛa#áÖéJwUM }¦ˆ’ú]zŶ±( ¡Ú}"hî°œñ­s„~h��À•0ó\{Ø—Îèaþœ®†!¨‹Eq2ò๪ò;m¤VÊl£—5qbéæ–[žƒ% §<¯‹V²ãOº‹+s×Óç3ÎZÈó�öÁe¢{±B -g2Ӌއ Ëì~ÕðkE¢úh‹vY\CÈ¢åvBÓV‘?ÆEÒs�m}<¡:�Áéæ­Ä[‘�x�’|Ú@‡ÝÎ6`xö ÿ‡®ÈBa\9‡„@X=ãäëª4 šÁ ‘Wv“Tdë¡O8[¡M/Kª¿—™ŠOšŒÝ+빤•ªáyâ_m á07°îå\ƈ$ÙÚ÷|co¤šlcïYô0von¤ ~q�¼æÅM…¢+ëƒýkFÄÝzÜõ%ñà ÌwÐTÝ1yl±„¨H‡—Ã:¥]œ/»ª\¥,!1nСb¹9õ(›\ƒ£]œtúêhÉ¡5ì�Q%0TŒ)ZK}]+’cþˆhK*þRS:Û³:1×xÿ{@JëÖ�ÃåÅwö‰u-yþ÷Ú”€Ìá—oZÄŽœ®BXv÷HŸN\cÈ@Žg*1Ûšd€ƒ9ßÕTX\‡/ ƒ®'ßWU@ÆÔt›ßð2-v�JqÐ$Üaº² ij`¦/�é! Mùï ØŠ{¾¶£Â¶{ˆ•þ¥íY»»€´˜�ø<¦¯‡`¼UC1y#Éݲg·XeM(VÂaµª=ð-±/c¢›Î„‡�)é‚lD/‚¯f“îÓw«×û*šøÛÎ˶Ú^…®¼n¹%4 ¡`#¥ML/&å½L�sÙ¥™Ûœ¤‡ròÔ�d+.LÏÝøò“ ð{Ѩ�bõ ä#_í»,A'jM_‘L#â0.r,{»�GwµŽr~ÀNä&"�oÇÄåÓ @¾  Ê¼ûº+³,…d‹‹/RØwa”ë@ßûR…K†tìð”�ö£§ �œ:ƒƒÖŽ®ãºÜ.ÇWÜ®{-ýuBW¥×h¢ŠÍ,ø§ñ£à{/Ä9Ò+´¸Ù¾8tÈ:9ºøÐq¸p×’×2ìŸùZÜY³S°·Y•´¦>|H##«$àüi‘ý�Ö�Á&Èšo…¯–±Ñçº5¿ãšåd˸`ÎKQQâq—Ä’Ä“ðÐZ1X&¹ÑɘK%�'?¤ýu½ŒÒ¢8V‹-à0ÿL@¾ÔÕÙM-3ó…äÏ1ͪu'˜!‰!S­Ñ⃫¸¸_ºV¯%f¨ œŠFkÙ†ZÅJ׎Ö?s:tEÖCdÔÆô aØ›nâOh£Øéq“NùVÉN×î,¿ž]ÌØÌí‘+ÚË7ÁF*j©’GÀ¦”£xaùú�‘OD=1o¢ð¼+RÌ‹oryóÞôø0teYÅuácÛMÒ�8PC}†iæ·s‡?Bœñ2i³VÅ,Y�ÒNv*’á¹ý<û*ád{OÖ»á@¢Š±S_î®e`éSÍéü’Õ{ìEN• ¦Q~59а½´õ¥OûsJàÏŠ‘)5¾c׉!2ŽèÙ†L{ÕÍŽ:’e)ý±l­•³¨¼ö<ÓÆQ¤Gy1[þn½4ž1ã8㉒ö¯ö7†âZ<Ž5d€<§+ȯï!ñïã]e‘à¼ó&~Ïç9Á1(:!´Cï}T�1û9�}ó“VUUÖ@óÒlÀv2v¼!¹Ò*ÐçSÝEî"ÿ÷i¾ˆÂÅr¯"bK´~�;¼FüÙm:œ7Ák 5ÂÐð"Dd“§å#^™5;k ±dÜM).Eúʉq>ÜbnǾª9QCé{Z}7‘tš˜+¢)K ]•WbØvÕi^ŠË%šzÂmÂkª¦®•¡é|ÇD[tìµJÐlÅ¢±Š·}ü¥õq5¦µ‚¯-mîƒÞ x~D—L /øëñÅ꫇à§JpþVñÚˆw²c @lÇaI‡ ùxu¤þÏË™o¬üÅXD 8éO´P¨Õ OMø ð0Å~ºœëöã$¯>Á1'�ó”£lWóq…š[¹G)%áó¢^‹´ÉȾËWŠ·§÷S–O³@n*ÀYQJ =,4´Ö˜çá žFËüèÄH ÔŠ Á7t×@9šüâVXÆ“ÛË=¼Ûƒq¶€î�N]¥í¸]ùwù[¦gy1a‘´ñQ “‚óe–gñÉdºS–j^H“—K¾P�ûŠiÓ­ÅsdŒd]�«=Èçá—w)Ä,ç§&8«]rËÑÊŒ%nÂß„/5rgbqÉõÏɺäxŸÃ iI½¶æúˆšé¿m¦È�Z”ÆØ‡Vh™å]™ÇLûô½œ'¸•Š=Ã>™óîÛºeÒc™ ïʵå˹r»½TYTRŽ¿"˜ ’ F¬b·+?Ú“ì瑎]—CA±L•ƒ} h�¯ î¯íOE﵂påL\)ºì rÓ¾&å¶NO^4ÈJŒæÿÚU2=S”ûn(6æg¸Ÿ‡ÉÑÇñ=ŠÃkü™¤ˆ¿3³hi³k*•í)ݳÚMá ŽY…Óp¥<�^šk2SÚì¨ò7ùõYU64r¬WÐq°µ\×)…cpß©Œ‘ô“úš¹U'ÝKUrò–nÁB×Î7ø/ &‹ü½Mí`:Zž´-@üú åŸ2]%8Ôm�_QÊC^«$4%˜õj'»þzéÎS€ß̺>^N‹v©&¨ÑÿƒD‡A&*CÅmúz°s�.7{9ÒŽ�³‡Fé6è:­�tgÉJÆX‡›Ps´p_„cdäíÌhîF î7‡çl ïŠënÐî\µžOǯÖßwN¼+ÈF�Ž�#fð¿Šó&ÃðæãóH3' ÀW±'(ﱞ0ÙZV¸›k>¤õw`CÖul»Z�ÕçWIºªûFtLWd5+0ûµ¶ÝßWÑ9š�üìò Ù˜ÅnÏÏ eËió®ÇŒ„7iÛ8Üß÷\åfÚ›=¦Ç ·Û°ßÄ(µ™;lK‹Éy¾;‰F@¯¬ÝxÒzW‚µÉŽTlÅSXîT/”B…#tD©4Ðnkp”,éò d.�ZÒEr¦ ‚Äû˜8ŸÈ½rX´HÕ¼‘ôc# Má²I˜Ñ^4JɸÓPŸü‚Nœ¸•S„0Éøæ¡œ`íš‘yâåÄx~ºKÄ¥òï¥\žs©É‚=EÊ̲74PW€V懫Kh‡e í4©ªèO½gý~qfÄ¡ŒÓ¬‘ȸ¥G|¬ üvqTðlõ}(œ¼.[V*Êåêž@»^?j¡áŠM è¥VGñ'�D})­å·û*ËÍiE:càV 5B�¸Ò\ÜwÝÎSÿ©Fœºœüfˆ´©EôÐiŠ ”$™@èÞKiÌþ,ùš±Ç½•±;¶uÉÄ¢o}Š¡¬DjÇ€ô–ÞE–ò´á�[÷œ–ñ>“._{¥Ž#%ñ¡m©Øáüì.iøÀØJ–«”[2Sõ¼KÑ!Û˸þõºVr©»%]wzÖzòL+œDmã�±5â‚^«lM W•[/¼ŸÁV6ûü£çõ Ÿ Ühé#ÕšAp.�axëùÙ<¢£(ëjo¾ü¼ñ|2 m=âõilúº|*”}; °v:oÅn’2JëO[oãj0ÈÆ#½Ç=(õˆë]®k¯‰ôˆÍáõr0¾æ¸oì%RŸ�½Æã9"K®³Ž¦ƒ¬>A02r ÁOdž9¯Ÿ‰Bx"-„þ+ìÇM|(oÄ`=*ù'uT£¹àˆâ°{Öañ¬ñ»Zˆd}j&=‚¨¡kå¸S|\dÝÐya%óÒÐ:ç%•”gIè  à�jUsZvR“—)VYv1Æ5çûá±÷{+¯Ù_ s]!Cꃣg…ÂÒ�Bg*õ£?ÖL¾Mù$,i„Èù–ÑõGPª¦ã}Ée-·¤B¢îªkÀ„¿õVÈ+å·�ac%Ö R7g~XÍçß5·öLný¡åhñ:`-T&G^#åîµì"µé5w§)ð ”j¼ÖŸ¤ô‡å¨›ôPaC01¹ßV´¿åþ#'šó` �˜¨œ"]%w|KØç½øX‡ßË"T7ÿNÏÔú2=óB' WË;7dŒ/þ“3¸xR<,�ÁOžƒí=U¯¿žŠ¾¡¤K=yS,u °»E�µî»e¾{9ì�µΞ¯ý=êŽuÂ¥=>e)<.Sv¹YòVkËNQò#hž ¼–É´äˆÔió6ýõyZ(gªç¿¬¶:\:~ÙXÄl‹�àIΣåݰú|rIRx4o¿aYèƒz¢—ÚïJk$Ø2�À)²ð¢Bܧgú>3¤iOÝ{�ÎyílËbÖ–ãSëÕ¾…^Þ.¿TfÁ; ¼óþZáïwÌy‰ªïlü#þ £S£ðø�zgü”;–Á†OíCc<2ÆL:Dì™ÝñãîÉqN¹š¶²úi#e㪠£\’¬IK%!œ¥h€-.«le‘ßÌoªË!ÚzÄXÙèÄ̹;•‰·$EOê , b±½s†i2ËôzÄl«ß¦%£xg<ëÂ3ëffÛ',"üˆiå"Û]M†\�órd+�`Éb—Òì‘å‚ÈsC#¹eÇ ”[ä²ü´é³´GPô©ïp¹12È ö.Þ_fÁD}fùƒÈúœü†JLY9߯¥Ökíyª°—|”¨ÂL2ú¥\‹Ÿ‹Å-› »”Ë`tûÈFÛsÍÒû_2Ýd±R"r Ðü{鑉#çÎ)1„wkòMþ–÷ƒïüÌG¬G¯tM¼<]×Ãt7Öt ~¨f…uÝžñŸ˜U†-"…¤7CÓÜMªôš&³èb¤Æ½›#FÆò-t©m}/;åu ¼ôýn䙚VØe}#íí1¹«[–À#3ŸÕÝ·³ôsŒ½VeµÉh+Ln ;ûATͱ2¥‡xÀññŬÑù•˜6ÃQJ~GÔp¾¥ CÙy‹ÕøUÜóÈ–ÕvÓQ¯wÖ“ªÇµ·ü�¿þrE:Š„Fg©}$½:ÂËÅÞk¯ÃzñuK.¹Ø}ÞèvØ�ìÖ�&š�X�– |fê)õãpúÕ>ˆlÈS }t o%Py¯—ª¾×ÊG¬<͸R")*F^ȯõ*}gn½¢ÃmE"Pm‡Ð<< EºŠ‡¥y^ëtý5&Rk¹Äµ]éZ!Wb5{ç®À@Fr†¥ÍæÉe‘Ò¼/F�|MÎJF¹¨Žú ’JJ$K<Íýh½ql‡j®oÅw®¦/ZÄëE¥Æ;aÍbºH†µ^«îËÝ)Ž^˵ AÆ‘ûxë’à"w#ÖH�Œ4�O?™ÈŠŒãj;cÿ¬4 B4)e¦Èg2 Fö xºñ9©ê;g‚- “¯)”BF'æR¾ŽÛ[mŸ} IQØÀ£—1¥ê¬ùÈ*ùæ~‡k¥,%,:ƒÚJšvötxã€C±ËHŠ…]àÃ%RÃNçk>ƒ¾´° 0Ÿ`º‘ˆ ŠÆkÒ‚Š�SÉ÷Wå_z=‹v�ŸÐººµm=kyÞ»º™¿úág)»Ð´FÜ)Šø`Ô¬ 'ö³p:䨶Xw�àúaŒõ£u-¦\ã�¹3‹S›‰á³WùJqÕ ÿ[‰ÓÊë4ly&m–0ñoá~Ù„à†¨pбªP¾ÏàíÒzžA a:††ÞÁü °|¼Ó}�côŒ$=}nflF¹,Ég‘+§7§!Qí8[ôÊýÓ—¢QBRÕ›ÏiÃø“2¯‹¨Ä�’=Ñ|¾½ð³° TiŠþF1+šµ™å½§¿ü&.‹ª·Qÿ‘÷BòíÖs]ÿ :²¾¾®7ùÈ+¢60WÕon¨Z34¼° 0‘á)éñ”»xÓØlå -1=hQb⧃àL‘ž«ðJ“¿ c´ëô×ËI¡�ì ¯tÆä0ËÑM6#»}˜¢xª@ï°ûÜuʧÈÅ/~9O‘ZÐèßý”zz¦¹ú ó¨´Ô‹d‚dârÂÐ�E¤•¡£ù*%áMÆÇÓ|™'�T¬Ù±èx ü|¸[¼Ò×/�ˆ7øƒk{,‚uñõp(ªÐ#Uš]¼T�_‚Ø=ßü„4Å�8ÍÄ È×þ¢åÆ– KvÔ>H©"µcr%*r—Âg;…æ¿ÒÓÏä6¼ãLF:œ+žÇß�áÒó(5#ãºcÉ'‚v%t¢Jñ�)!Ö݉ ­†XN±(XŠKñ43’´ïPµ�°1¯ üš¸«Ë_×…+dädPµÚëØ^›I.îÅŸôfó&,Ãö¬Q¬�ƒ-¶>ûc\U¥4¡o> endobj 207 0 obj <>stream xÚ¬¶ct¥í¶&;[+¶mÛ¶³b۩ضmÛ¬$Ûf¥b§â|õîݧO�óuÿé>?ÖÏÔ5qÍ{ŽEN¬¤J/læ`”p°w¥gf`â(XÙ™¸¹¨8Ø)8pËÑ«-Üõìpää¢Î@cW+{1cW @hšXXÌÜÜÜpäQG/g+ KW•ºŠ&5--Ýjþq˜xý‡åo¤‹•…=€âï‡;ÐÖÁÑhïúâÿ:P¸ZæV¶@€¨¢’¶´‚$€JRA ´:Û”ÜLl­LrV¦@{ 5ÀÜÁ`ûo`ê`ofõOk. ±„]ÆG ©Õß0 §)ÐñÀèlgåâò÷`å°p6¶wý;W€•½©­›Ù?üÕ›;ü« Gg‡¿vmÁ”\\]L�­]³*‰Iü»NWKc×r»Xý5Ìÿzš9˜ºýÓÒ¿laþZ]�­ì]®@O×r™fV.޶Æ^sÿst¶úWn.VöÿYÀhaìlf tqù óûŸéügŸ€ÿ¥{cGG[¯E;üËëÖ`åê´5g€cfù›ÓÔõon +{8ÆvEÚÞÜÀÌôo½™›ãØÜ�ÎÿÕ?;Cý·c3{[/€ÐŽQÁÁõoJÕÿË ÿ}$ÿ7PüßBð ½ÿoäþWŽþ—Güÿúžÿ+´„›­­‚±Ýßø÷�ü=2Æö€¿w øçÐØ;ÿÿbŒí¬l½þOQÿÕ[øïrÿ`Ò®ÆÇ"loñ—&¦+­\$¬<�fJV®¦–scÛ¿3û—^ÝÞ èlkeüËí¿Æ  gfbú/65K+SûH`ÿ· hoö_;øK׿êgT•SÐP¦ýߨ9*ý]W5/Ç¿µý�näÌþ§ðŒˆˆƒ'À‡ž™ƒ @ÏÂÅü÷ýý-ˆ›…Íï“ò_@Ìÿ)Ë»:[ytÿöÍÄü¯îÿÇï?%ýÿ#noê`öÏ꨺Û›ýݶÿ©øÇlêæìü—䀿]ÿ‡ü¯½=�¦pë+¦¼!ÖÙ™® Xù£SbºCÌ࣡ŽåÍj%Eßëú2"ö¸«�ÞëCZfx>;½–Ï?ŽdhŽÇ0m)ûÓ€W…ø~¤ÔƒE(ÛÝœ´ÇAŒ则çš1>×Kr»:LÇûSÊ*eïP3ݬÎ0ר¿“º}G'{rüæošÞ�уÜ‚ÚP|vN‘üûÏåðøÏÑ‘þ[ÈÁ#<Ú¼xXr^c,ÿÔ3âW/#ç‡fÓOÈWwN—šåœvÍ:”duo¼·7"²Ç¸=4æÌKVB‹/aÐC&¡“xY�«ð0ø8–’$:¢ ÑY5ƒÆžéó5Ž�‹&ž ›ì5î8+ø_-Ñ+’¤%ì;Ÿ(TBRÃKÙ:a‰fRL\È™ÊÚÑü³œl�¸‚äâߢ…¾�W¥ì •Æt»úÂð÷�ÔªeühÌ=W¢å·§�eþåõàÄÇ$$¤mFsóýªRÉ'xÀ‡ –¶Ý‚)R5m]³0º -˜Ñ׋Rï!{uHÎúŠŽ"µm×BÄ#�O~ï{ŸjÐÞ¯ÛÛ—!΄¸(h4{2Ô"[¶ãÕ<ª-Õw R! +§PàÏ–ªsþñmɤ~¤¥…N7ú·Þ^5^N—HZvÇA /A6àéš ó€Â]P½0m1Ì3ÊæÛbÜHªÌ8è£!£“í©L�l€·['[×¼é¹0JÜ,Þdm?@î}z Zô L#,¥Úc« Ó1š‚ÜñÖ×Ý={9¡ ¿ƒô°—pù#Äm Õ'K{¾Tϱ9ÓqkÖ*g3-Á²ÄÄfÌ´Ž@3 MmZ W¹U¯Ò3ßÝSÍfçI.GyÒ(G®Ã+ëKÛ_+iFZ­5 ÕT*—+VËn‡lVaêÙè¢�üäîìˆÎüX¤Ä* ¢hã~ÐBCº¾,Ñ|®%AƒŒbµ5SÁ6 É;P‚3+PØð‡è¨¿|JR¤/¨};ºb³gu1´÷´ÂdÛ�öº‹ß´´¦…¸P.1FfúÚ_,·¨…ÄWÐÏ;• Õ»Çë8û~wP™¿¦³¤ÐI-úm1k Ã@F�‹³ŠÞþ/·Ã©3Ù–VÀìâšÅéõŽôPð¶ØkƒlÉÙôe`óÉâŸ�\ 3Ô¦÷¸À¾âJpl%Íl°™Oc½8_ãr—G.­:LÑÒ�÷rÉoe´ {HU�•ÞÎj ‰4ØÞ3Ô5Ö»%9~ìÓÕɵ,êÌœ¼E7[]B¯ñ¯’çÙ­Ó Ôx.¬Ì›[g~MrYà`ã‘Öøts8¸kѬs ì´ì¶ÉþëÆœ€YÚÃF³Ñ’bøü|¬f“7—:eùM uç߃/¬hoó ª`�>}]E'WŸ9ÁË(˜²ª-�=IHB˹´��¢b߉žà—î(�My|ÍçÚ’>}ñÉ£OÔ"î ú—ÇGz!C3ìôÅÝ‚Ng„Ú%}Â_'*(Îo%{7 F¡#vF�3çc§éJ¢$TÓø* "Å å”ðE-U¡–nYÁÎIJñ[ªyg"!ŠQ^„aCVÕŠ•ò•ײþ¾äóN­!VÁ±ííâ¶G:By‘»qÎõò&Õ¤Y5nÝæß„)†T&÷ûÞ™àq¾�}ü(m‡_Íža}‡Ó™�å@ ¤mËüv#1zÿDÉ_êñÞÀÅHÂ#†�×O #ýêg¶ÓŒß8Êu²°õ8?˜KÀܯvZ ÐÐûÊvYÍìÜÝÚÍœM^Œ‚¶õÄ^¹“{ �‡°Î4Úy¹DbÜýÖÛ1˜FnðŒñ_Ìä¨î×Ð�LÙcw|F»>§9}¤LùA¡t$iV€4¸‹ܵ3Vç;<µ�#ïei¯Ù|¦åÃãЇ­“ÞœhJz:Ë|±kNpÓÍžÖ‰ùÍS©“$nB¥wìuxÅ£÷jwP@B­ðψœµDþ�|^М½U²Á'ò^Å5 Ey3¤xx0)Á¬^”ˆºÝ‡°Û"¶�çÚsuZä*MÿÅemP¸3)hØW"3Åãö 6/í,ÇØiÞbz3¤8nir`š¯¯kOŒÔýY–‘Ôoãttë1‹ˆâ1Π?éÓ”qûíB&Xàd6#ƯF;É d—�ýjI=fßmÊšÜç>—x˜ˆ[KÅ™v›�–K 8’S'¯c’¼µ ,2FŠZQBœÈ¶ÕxÒ<ÝD–dM½¨Ã°Æžü¹à†˜�á:½„_ïÇ1½F0 hS²b{õbpánO„Ð#kíA;‘ùZGø·îši^‰ƒ"Oo[òôth�,HCµØØÉ<'QʾCY =wÖ©¹ÐaÃKKßdpw²7þ©»]ê )…–Õb›’¹˜”�Ƶ'�þrTsƒÏ0;‘¸ g!Ô7`Œ)=˜óÁÑôz*X)gFqÀ¥( yCÌdÞ­ú|ä>¶¹gàV¡Àƒ¬ïv yýºòüànÚ‡ !âÞŠ}ñEò°Þx@'mñU'�ª�CËØ˜·xÐFœú�l­#&�bâŒåÅÅÓU÷݇¼us©Ó…8Ÿž‡##rÛùHâ"uŸ4 ?ôJ1ðÎwS1«�,*VHb°UÄÌÿ[¢‘QBuY_!úƒ”;Õ$L§*(ì\”¿Ö’»5�ËRk¥G|Åþ›Q…mZ(NG3är—c­o+ˆ¸¶š(“y ®�ÇVºIW} ân� Y�È éˆëþÖ!‡Ò�bëR­#nǺ Ò:¶E/1u†Å‹ù)ß ñ8Ë+DQYbHKS$ï;|ÆtB8¬ª³îw~˸܈ ’¢žÅ éz J]w¯Omæf§t…´±ß—ˆs€ÔJÇÆymÀÙ*Š?Þm4 ×÷{ Þ]d:̽á¤G–N*xMwúèãúi̪ìA‚u}=ÏòmdÔ—žœK>Î'¯™Àë`ØÈ•˜+ƒòàu,|ó&J´t»G3ÝË›hT´äÔ{5{®7@ ĸL Wž [Àéóû²£ éáŦ�©J[¯š0O¶MWuJ¹jmòW拨€ÀhW³íl ål›œ,F†‹×j¾­/–ñ®¾ß°=lÚ±VPF3u)¤Ýr¾ìu{Òð‘`Aê ÿC¶=ù3qgf«õž6&›…Ç�fÞ4VkE䃥MQÕ"„^ úpú4:é§ ²OF¤ÝÚ'ä¬8QöÇ;.¦§¿i]Àz1b^ü+�Nâøìòœ 6M„v­®Ãb‘uŽbXŒÍeLX’ª;a×ô`ûFg²²ÀÁÕ‰“OD(Ê^�› °‘< ¡‰Ý<ÖMs¿ThôȬc t3•9Ó£�‘ ú›³Ï¬µ(²C¿ö­ïéë /ÌYgpõÞuKzÉé)â¿ç�+{[å]Yàð¼¼g¸8íšž4ÌX:*JÞ=E:¡H�½‹Ž‹n¨5ƒèEîÙ:^ž‘ä8úw¾5bûâaÔB™ƒãëÁšt5Ò“¹?¥%'2�´æŸÀ³|Gî£ÞSD#µíùŸÜ‹2¤8%+.¤ƒVfPâ‹ÖG­aò³e]1²¯­j¶C‘*Æb)âõ2¶ÿ+©/‹¬oIôtS�à¬�çTáâZ´ŽÀR\‹b’GjXcõ´Bº2ˆÎCI@7,ÿÔ2˜°”a`hX“òÍ�¼÷ÙÙfj_& “v½›ÍYµ+Z GøD»| k‰L¾XP|ׂ÷Î%’¨©¢.ÕæS"ðtcpIC¯ ‰ÃÂ]M�òÝg ØöPXM÷ID¸ÅüÓtøS=?üFà‡r‘ÞÀ�T�ë>yÅÖ´„ØïûuÖÅ´Ë •m)ñœiazÉð<1ë"<5>�“°2Ûlúf ʦi’v­¡ä�;OúæçTe31‘‹, ¡/làb_låȹÇ\½™4+ç‚Ë"åbŠR�M=m‰äÙÕW‘®�yÛ·1ÎÜ>4·Óª¾@@í²)GûaH’‘XÙ‹/oqJ¨³²ªó01‰ALâ‹;.­6��îr-Š6U’U³º({¨àñR奠ًþäYz¿ÎŒÌñ~¿˜•ÒÐÄ›A‚.‘of¸é®lâKÅžkŽ–ÅOK[ÙVÀ¤^îY�ÅQf4•Áä ÅœÙ$*­\9öÅ©×�5cëÙ–‰ÛZz½º­Íì„Æ_8)V¯Ýâ,¬4—�ÖÂ]a±´xÁO“0«âV©ÃgRPGVö-Ï xÖë6ýž…> !¸¨PÎóÊ33 v#žn•ß�Ê™[áÖHá}}±›<*BF%MÉõšõûÕªôMìgƼò5?P|’»¬arL¹]âýD³8ó¦øsG?(,Fû[O6^bw�Çia—†Çf·å\æ,£ “Ű˜û2ï ìHä(›BHU@�8½ãù9“Xç´*Ây†BeêmÁ÷t†v�ùtI·ýû¾Ž«Ù¼ƒG‹ GwÎ%OŒœ?†Ð·š¨LeB�ë�™ú¨§™¶ö “³ª*�^°GsïÁ>Ј¹ü£ù÷�†Ev¹xjÑNs2ÒØ&Íâp^޾¬(õ=àÃïűsvâKͪ`ÅˆÎÆU^>î:Ù¾°,²'1÷æÅ´ë'¯ .¸ø¬²š$SñÈpAï%ÿ„ô‡ §®:ä7Õ A{¡kxüÌ,p÷<�(ÞÉŸƒ`Z²mlnû‘T¿¦ºK?sZ ºò9±¦Ý�] V†cùÞ!æ•IÕ²áè3ÿÃöEY)aòI�“§E­ÜjRËQŽÌ,ÆŒ÷€ŒTok-ë‘;žŸ ^Œ\(òW˦¤¤ÑÕ™,˜�º0~›”½”€\‹�…Šg|e2Çú÷ò²_·õ½áw£H<6CdÕ«ÐöÕegxuH™†W¡/\T|Få…»»ªìLÊ�ÑsÌÔ»¿ZœO¸µæÑ-j/gVƒrwí=½¶.9¸q Pø:¼¬$ôÍ:mT�þ¸V†¦¡:×}´+ñ‡ŽÕkEí=µ ;'�}'ö…›ãߟ"é ĺ‚:4M©x5pžhÒýQ}æ¬qò\}òþèÍuûÔ†èɯ‘ £ï‘’ ‡Ði@SÁŽ®d²GÒ¨ýê,Y/¬•€âM—•i!•ØÈæŽx�ñ]¶¶c©NX9Âþ+V%¤A$5lÓù�ЗñQê›�ènÃZìºÂ‡2ä ~{] ËÖÜŽnº«°¸¡bº EE('æ /F?+ѬýlÀ®öÙó:þñÐ¦× ½*l•ŸÅ­‚aùË^¬º˜6>Ñ9¨p%Ÿ ²¡ùVäÌ!§iý\³„ d8ú�æ®ÕùÇ3—w~Âëô¾ŸÃzÐ÷!c Â’õ¸"ÖŽŠ~¤ôâ5?ùÀ•ƒÜHC¥AuÆÉkú·Ã[/yI®h)ˆêðЃ)"|¨ÊìŠvË‹ÛNA�Hº_:¿ÿ;Éøv¿t> ©Ö•wL¦Äæ¯ÓŒ-w^�®²ˆ��!Q$ÆÎ»†º� ™{ÚR¹ÆDJEŸP+CÃ*¾ås Y$¼Wø¬S~mL©E^[Òƒ€,ì½µèÛe­._,¼y4Û9ñÓmÊ£;þþã¦,s+ ª /éiDyŒi(+Ì«íÑÉћҟΠKÓìä!uŽóGµô*ž%Î L™¾¾àó¶­gˆsò7=³?‹< .R1÷AÙ*¿’›Qøì(è†Dï´Û„«�å‰GÑaéývò�Ü€œéPZP�aûö„ί÷˜à�9äÔvÜù }EÆ×™“ŠýB&³›»¼nr˜ {[c�b »ÿa‡•.äÔBý5Åç°0Äi~'ÝXýpÞè"˜ËuëAL5±¤,'õy”Õ/DtvÇ·««èù†Æj©$Ô©ºp¡nû“q×êÌ=i´fèË1mßÏóà ¢U1‡Ê®b)ÚëÛ¦ìò,Œ™iÃr…±gªÍŸ$jT|EÞŸ뉇öØKH�L©#�˜š ³)B¼¤Mí®ZÃK2Š˜W¿}ý”Þä·øXDÖk°à¡%©"�UÇ#P�Ò¶ÙØYNdÕVÌV˜…/ ~}ͯÑÍ…°3¤ßä1@úMG_êDmÁH+èV´ú“¸… M¯*Øñ’ã-ÞÎ<õƒ£R¡ÆÃ÷®$ûĈ+ lÀ~�Z8äD4T§S½"F‘Ý-‡óŒ+>ïYÀ§-�ƒxwäã{ìÝÎ÷I` k3yd;Ž—-k›Yßu°'4ÝÖðâçÅJ ëY½COê?Âòún`}ßy†Bô«wuMl�²÷-¡ õ’X¸Ÿ;`�¹¥…hºøä™êˆ3PÙ>XG‰Â’Lô·Î'Æ' †§Åˆg®­‘h〿ZÔà*ú�¡ÙÒ®¹ò²UT§ŒréIoI«Œ¯îÝ1ŒvjPѶÍc‹z–޹âø)&a’‘0/CôÇvS¡óà‹YaVXª›uÓýè©{¹í½j�Ï܈«Ñ 1Ç~–‘µméâöu9Ê­°äÚ@ 6lÓør:}Üû7Qüê{ƒ£*3A¯ƒ  ´ß6·ô«ÝÊZÆ�Šö Õ&:fŠ.ð1ÁáöÞœ-µ¡7"SÕóíÊÅ$ÝEúHâ,�˜-®ã<á"ߎÏß_ƒEïRç ZTœ¼Ùá"?à´š$yX[¾« ë_]:¥W=ýH²ØÁ¼x¯?Y}rný²éœýý cQúÒ#;$€V›©*¸!«ÏÞò€És²{®X³Ü©{˜rˆ×Z�Lˆ�ùrýÃ1ñwHNçšÀ}Ú–’a|ˆ Â=䤪‡õÝ@DU•ŽÁ;$yÌSR«×dçßâ=·|†Ž:ölò�V¡eZ.h�‰¢FKÙ1ÒŽ Où4\<ß·3{»,¨Y¢´Eyó¡ÏÛg±–„VN l u.öæ™ú¹™ çŽqºöæ4ðn¸(ÌÖøÞ%8�VØô‘‚¾(Õ²Dt^OC(; –¾c‰õmÈ-}<Îvóú*ÇÚÙ†×ú‹Ñ¯Ç¦°i^œJ‰ºoÁÝÃ�îrB¾!)E·=U> ì±2p A/Ü– ˜ë* Ñ¦¾áïÌfùã^žRß7"^­ü¶«2{Ì8qìñóÎy’HرÿUÊE‘àî§s>éo5ÜK�¢IÚWâ4 "ó””aç±8ª8� 5”Ðê|¦•6TYJcäžâüá4+ÂÆQt–YjH5л'p’†{—Ô©,pñ"¢®ž,¦Eêï0Ýr`¼d�©Û:„Lí&ȃÞP°,$½Ü_´>¦æ….•{“*NÎû¤0íßANO_UˆÒ}Ù}å®Ç‚U(Òª5°VžBe'ª>§:HUž‰?˜ž.»:À‘û¿B<22{L\¹R¶óœm­µô[Š"·oç§Ú·‚DFçní@bÕ O÷è¶—Šp©&5ºKà'ª^ô‡1•ÌXÁØL±O®žºËÞì;5^R4ïΟ@�m�GBê Û— Sû•Sþ¿¨hÈX~Ç?èŒ*0thådß® qÃà†Šîôð&×Ì@pÕú¤~XÚþaȵ�UP¤ä¢àqë{ð*µèjv ÚðlŽXð¶»@>$h… 6YÔ²'ÎQ¿P ë}_õIB2(fYHcRO­™ÓB‚Ô˜ŸsÆR#Ï|#ïÖ.OË|z8vø¦õäý K'{Gë“ȋخ�]Ɔ֥[ ð“eå18„lW²)O¹ª>î(˜HÅ™“²'dò'§ª Ô�ò:¹tÇÁ‚ìhó´FxŽìV:•DÏÕ¤dk-é.\Д!çªâ=WÖ¢ª>¢‰ÚÊÚ…8RáažÏ�ez»y™¢bm‘u¹ÇtÕ¥ù4ð=ÌÉ�«·#ÔIN¼ê¥z¿Å˜ï™<8*ƒÃÀ5ómmb ìV=”4×úVMÛ& ¾òúífx�"§Ñ’J‹öæe*¦Pã# Ž£kH}òÙ#xÈá—�I·Šz!bôÆ“íÆlÕ &Ç‘·û¶Y{ ŠI®Îa q1–[ï>÷gÚÏ J,â}^‚Ù{C¨Ö~½n†N'EÅmötS-n)aì†ïJŠx›Ô¬Ä³óM‰‚MX?[œQ7jðå=> Ÿ¤W�Y><À½ábÞ( ÕØï·ñö šps Ì4˜?òðÃñõék¸ c£sGLMù³r�…Èœ³»©È~ð›£^ÿò\i„aÀ~3%Úq¯û(¥ ÁQ˜²ÿɬ#j¥¢ÑøG‰Ÿ…/~jÿÑyF ùrœùÅû“ ÃÔ¢E¬Ì /ðUÓÊú€}»PChFž&ÙŽ §`þ÷+ž¯Ð‹fpP Y£¾´Ì“„$¬"ƒÜ4n§^$ç­"gÌðÙjJ_ù7þ3ÙÜU’åðµI Õ7¯‰@UêðéíÕO¦sãǰ�å¡ú¿ö¨·“kjYÍî#Ìиÿ”Šh¢|!ƒ¢b÷+}ûJà1ŠV½4ŠÕêbÆ]ÉÎÊm¸Û(:ªþœ<ˆï/ÓéC—ß¼J½ÁjëdÇ^0ˆ Q’yú¢_ ÷[`?c_±pt²Ü9o¿_Áˆ¥—¿LÖ·zš+r6%û®âèDœ‡µÉ€ d™æí³FJ@`‘Ñ]P aॡ=Õ”S6i†;þ¶oNíTžèòþHù!F»&ö¥J•E;B‰¼(Ae&â¤PóIÚƒßyÄËGŠ1�,2 ëÈt«¸úËthŽiaÙ«m™3ó8Ñ7=ÃD2¹àY© ÂÞ7#À´5¬B þÌXÊnòw#mqÑö]Ž c©¾ÚwÒ ™Gᶺ¡ I42ñ% в%å˜J#p@.SºŒP8–ý$)'z¤WF­ÿÖ2šqw"f¨! a'?³'T&¿9p¸yÌ© õ5- �bŠQ`U ‡ð¢r†˜#ì¾\ó6%-ªÙØR±Š›ýE¬ç±/Oº—œ|Ž ª£æêH€ b`^Œ[U?ñ«€‰í€ ï"êO a6}u»'ÝxöÏâŠm©SDŽ�¸��Œ�dØ7|%|¸[0xèú¦ÊæaÍI$\sK.çöUQ!9ù€º¦´õ[ üÚćÆÈjb:­½N‡±Þ@rÓ³`¤ü•’…–’šñIÚóá¯èܸH\Ó®¾aÒé¢÷öi•I×f—@˜Â¼sTr PÿLo©¡ü Æþ¼û¦Ý>m{¶ÛÒ7.Hs­">as¥Â�m¬}õ�æ B©…]´†ù0)¬{¦ íP¶¾7‘rÓH �t]8¬öìýQeSXÇÎ\m b^ýÊ%LÄ�nôBògNòÝ+ˆ‘ÛsÛ‡D¹}HÄýýGô„Ç£5úe<ªéµ©ÓÓÃì.0=P†Ð¦ÆAòamQ¯øè䟉 ÙݧÅÕ„H;, f/1 ‰íÊ¥~aó:H¿Q_*vT¡š'Áùòü«ºÔÔêµOW0°LÁÆ«ÖK"äHh„#ãÖ…~6` («§ì, U·8”�˜ø¨¿. ¾Œmßôp¿9y¾<Ž)´­&Cv|¢v…t"ã,ŽÐs|ö&úŽÄˆðêåÁž1÷{Þn˜M˜‡a§¸mn¿¢à“MgŒ1Ðä˹GZM VËc‡zÉܱ?¢ú{°D) ‘î  {œÆ:%ôûØ‹·<[pÝ ˆŸjÝ ]ã|JÄ ­yY·6wVôƒ§@¹ê,ÚÚÆèöÃ!s jƒa¾Xn¸¹µj�”ï¶PàZ¶Þ˜É÷rãvÎs¾õóSå'«¥ ¬Oå>Û£: ì&ι“Ä¢Ê)—ÓÔsö«ë|cˆ+=O&–0UÎqˆHÞ\cDؽïs"ß*¹ BŠœ‘[¦:²�´.l E^Éü.­*šÙ-èçƒÐs›ºáh–W}F*Â9p7@²Á-ÿ¹»rI¹›`(åúKßkИ™¥OŒYÊ/;܇‡Î>*Cè÷±/�ªu‘S £Ø•#§[´ÛãÅôã×ÏÉ”Id¸päBì½éé+ÃÏ,¾/dŒ“Ø2÷}YÏ"•OŰ�†ÞB³%Èh ¾*27³ʼn´–_�b™{áè ÒÚØ�yOÑÜ&UçÇgaOéäÝÚÕƒ?U–´—C·¯F¼hÝóâñÕæçN½LªÜqHÛ‡|dù+˜Îqë¦Ûéu-À•rLˆ]ÜøÈÌ2Ééñc—8H"¹ýN6\$- Á$¢àX¥òäÒ|Eõ3¹N–a˜Nž�Õ<âÅÑJƒñ«ËH«~h[™SÛo�;QÎÆµ@t†utݬ³ðœˆ¼îV„,*—ÈãOZÞˆEv5ba£PV¸Ù €Zúõ­Vü>YjÖB^ݺ¾˜þ¡S ¹OÀÉ›3‹yRÄìu’ú´sîÝÖ“~,åG7uúÜÛ�°ë@›â¾x>œŽDÄþšo½Ô—/k©÷%�@^>ºî1CHb|¦9 Ï-ËŸ_Í®ìëø=÷É“fùÏW야þ”•ýÜ.²ª³ÂpÍ÷EïB”õtá<"ƒ<_.4SÙ¼wa ~ÅTW㺾HðÒÅÎR9ÕJóÀ‚¾=r]U‰žŒ¹ƃw¨´N¿X…: JšY†Æ€Ü,"%Έ®nfÞ7Öû h–ñ�›–~saa™Pê¯Ä©$d�x33­ta‡æfLGŸ?r$ÅLΰ6—ùN?èUŒu“¿V“bâíÈšû’þ¸àEÃø"(�šn–ÓÒXz�>êij¦¹¯vg½(ö¡Ö«E,5?¶R—K*" [Z±±ˆº†R€±eû;:�z'©ãÔ0Á…Ü—„h�¼Ø•!}BWý`ò4õÜȯè¥jz&"ïvQÙ¦ß'ŽOôï¹ö|ÂCzº—9²áè¬ýÐ=®á7F{—²¶’hè½jÓ©•Pr*·¦°Rm-Œ–‘œ/t¡Œ.¬‚·<àt‰ºýDÿEíÚÁ££'š4dWüöíå›6¤]O�ó'ˆï–Ý\vµ“®‡û!%±YÍÚ”úMq‘¥6 XA峋ãTàñ`è&ƒQB[Ó©$œðùÜ”�S‘ÙÍæ9ÌI •áÚ¢¦‡m�¦˜À0íMÉ� eãžY=×&0‰Õ4?ØÛõº]«]Å,Ë«~#õZ)Ñ6=Ù~Цﮫâ÷¯°š²d(iÔü¾Ü¢ Éfù-sÏÌÜþ§Bš|ì@5–ï:ä|ŸM|Ó7z&/¹lU.ë`Îõ°V–Õn÷·çÍðúÛ&¬Æ�CMA‹RLOV Á€[6Q 1»ij«ìªŸÝ—°’„=‘9ÍhI!•è�ñÕ�Ë 8Mlþs  ³«±WAѵƒ@⟠‰M €_™ââŽoÌ¡ˆ5\u¨z›}´H$7;qÏ�”[¶j÷ß õÈÅœàâ�íf©}.Þ¼“[ZH`’@ª^ß’EÙåø¹D½…%ÿÌ›Öóµ�gž%CMà]ŸØ™H·K#ÁöcvÌû‚Ù ÝÄ:Õ½÷ÉŒÑ×_=Û·9W 󺄆�ü\ßR“H90$ÏOÕÚ`ï’°M&²½DŽs× OF?fY‹(ÏÁ£—ƒŽo3ÙJ�Pbñb¿�9Êp¦Iu‰e’Œ‹ù‚,Ãtlß~€C4u€{œÊüâMiv˜Š” òdT¾OŸú¢Áb§0²Tr\YþL1µ·; ëg €âÿÒÂiëPW(ÁÔÞˆn±ý°!€QR6³-›ˆXPùcßÌbM*Ó&b4ñGéáðîS˜à Yéð,±™ ·�7¼(T«]Ø/UN•jQlˆ­…‹˜œ;‘ëŸ�üë?>š°É byº­ƒ "„�¹%öÒg<*-Çé Þ{�ãØ”î‚áx ²wGO{¿¨£¥@n•j¹XËPÍX1'Eàî7©o`º8Š®AŸde7ÛXEXGâ¾Y†[Û¤6¡h�+§Á¾­^Cc�Owr}/R¨«½ujð8Ú ¥l½ÔõW‚üÃÛD™7ë¼áU|ìÇ:»‚þk�þ ë�5DœS+o «|ô�G†¦5Uášù«Û4w­«7Ñ™·¦˜1ʳ‹3\M£öUÂñuÏ–á¼�pé/VÓ"´L$§œCÕN´9«#T Ñ€½Ê±M:Òá/£‡ ¥ß×â(ˆ©^8ª5�…°4Îϳõ«ñãîÖ úØEú÷FïòÏï‹ó{1K‡ü€t2jÄd¡†²ªÐ�ªÞ†Ë=OªšÑ ,²ná—ÈÌÁ¬\ …œëð7ϼ ­K^ö"oŽªKÓùW"ë°“]²—ÏÚtáÖÁ³RGENɵ޽õFŒ–\n[vWšj_Ý‘}x¾ÀîaŽÜÔz•…›sÙ*‚@›�µ�z äe4HþÑ«µ YûábÁš ¾!Áqû0óš? EäžÍœÃµD‚áÞ.›’§J›y‰?G„�ÍfWM/åáSÚ«÷þ½ãfléÁsºCæ‹™øÏÀLø`G— MÝRg:¬ª÷â&™³†¢»áH¯n¬O2É‹C±Chô‹cÞ¬½�üå¥Ä|bhFÇCá�º³×ƒCÓůÑv±,‘3y\³÷ e{A»µw\·?u‘78­.›‚�np¡(˜059ëÛã߇_‰�Ä^5bÂ;Yo;² ¯L¢G 8ì¹Ê…�Ð3º£…¾“¡Øuˆû¿n y®¤ <#‰aĨÍjÜp¡Ëf'Å,�˜ƒ{°kç©ùl´“ÀÏy±Jw¬ˆ€ûÅŠ@˜+“¸ãp˜vÁU½„˜ ¿Z2@¸»Œ 6{ö¢cF”Çñ膩Ðx†VΖ$¸Ò'ô_ pOG !xšž.nŽÛXo�Ù'Ô%Á¼Gs ^*aýUÏPä�ð<Õ«‡QŸ­¯ZüÒžXW•eÕ´µ€u)êCºÃ”Å�ô„PA¤Ü§áTF^‰x´q•)¼$KȃÃ��ÖÉŸ­áCÓô2Kë3�îÎk-˜z& b~oÃÆA 4Œ'ËB˨LIF CîÐ�LJ; ˜r]&\¬2W TºuGy¿V�\·qǹåÿÎAQŪ†_Ïà<6êP9ÿø4» ~M È ØNÌo£T)"cšø�¥L:¤Ï>¨°Z:;¢¹N=—ÿä¥ÃœŒ˜("î\¤ðN¦)Ò"�Éšyããÿ�ùQã`çµKÕ¨3Èß~XL²³º|åù­ˆºÃM.,5#•ÊÊkv±ø¶ÂÓ‹ù ×Ñ�­MÇ«£/P¥32SÖ|Éb<ë®Bl >±jÐNñ@ <›ÃW#Æ*ä«Qk*D°^ ût>�Òâšn6‚²‡¥Šß}ºpWÉfBMJò+8— 9•lPŸÕZ¥Ï£²76qƒ*¡–º½ï¦ow>ö;ßC8zI“ÜfqfpˆûY6þÄž4ºé%‰þQ³â@òÖ :O=fl>�éÏâ«||®ïW÷óKÇ€ÄÖ‘‚¶@CÄÑTpë8‰’¦£±îJÿO$K—™«É®X84š¯ÔB�ÅEq¾­ÆmÇý[‹UÀÐ’5×ЉåµøV—Ùž#hÓÍbïiËœÚ뇋˜`Z_ kŨȪ²—DØvMŒQ3Ù øCˆüC·rµÍ¬¯¼íWæ!ª‚‡ÓA–L<šØzz÷ßÿ�¸ˆi@ -îü=�Õ"â´ÇîN~WÅ�á\œ®7¾¾@Ï8‹S$XgXÎkðúkñwD¡¢Óš'ÐÙá|ådG…ƒV‰`‡‡œB&ySõ”¨@�R5·1Ò�x9ˆ["%“kûŠvù'Óœ(OFü�‰XöŽé4ñR‘ å©y�a8þ•`¤… 9M$�Üþ›?¦…,Å�µ©sÐ4ɦo1�Ö;4ÜyÒ* «ÂY-q°ûÌ¥³9—V}÷*0 ¡±CG¹†îñð”¸GÐeáeÝaÞ0I'Xð]P.\lpà{Ÿ¨N{‹Uè ðºqâO ÜçmÍpê‡ùš¾ïG÷ù.ßãSíwìæiÔð‹ƒ¬Šk+³[5þ°m ——‰^Úmªf$+>–6åá\ îÌ=”öq¢Œu¶ý0´×- ;Je9Xo|AºŽ¨X^7ÉžUî�ü~˜L2’ÙçYE™)u:«F‚SAD¾p8�ÝœsŸ–êåÞ›c?N¬%°L÷Û`ˆIÕ}zš°;ÉÉoEâø�¿nßzú!ús®or’.¨ÐÉ=¼æ2޶íL!6ú|ha­ÞhÔЗlõÜî ˜z£±Ê™§]O²Vß¼(ä¸×ic¦!1­µ\W„~ò‚'m*€ÏCÔhp�©)ßZù¦½¿†öL¹žl§‚R£�£;àŽÔ«5³èà¡¥ü~ »¼f‚S‡CªcþÍ46”ÿG›iw�"'B1¦Á{W,ü�@†KøÞ7AÌ.ž°ÂÅÁ�ÚåÍ# ñbV•îŠ{…ÏV�ªg �ÿžv‘y‹ïÈ¿ë 'MÿòÞ Æ*V§,xëé�ª:�O—Œ�Œºˆþ’ ˜ÌUC³÷æo®Gê&yÈhçNéSÓ»#]XqlãÎùP)½ÿMÃÜÕÉÊÄãm2ò\$[ÃË0ÒÍJ™½©ÂI öËú:wí‘Y`>þÜn™#G2¡Q…e««Ã0'fE¶�[%4î»_ÓJ Ìà2ËHRaß왪aߨd’¡ÈmlØ@”εbr…¹ÒÓÆJiÊQR9t¬»1&;Ÿî‹ñNŒ­qûú,øjCBÛd3–“…L‰e·ì|ñ^MÚ#VS¥ƒ®ö¹| ‚4ÿ„­$"p¶V¢_jK2¹êÉÍÛ<›Ë÷×îXÝ¢1�éµ^C"êš™&Ÿ‘ÄÈï+2$Úw7êS�ÊÄO¦ŒâÕM€ªöÕ1P§øÏDæN=g ¾w¸(…÷o2{Â}êæ@Ëë¡•ÑÆlñ ö\øgøø'î÷jÈó)Bd*%�ÞúѨ›IÚð—¾®Oð¢î4¸ží۪ػIODÒïkû,”,§“�¦ã¡§xYao* ¢I7úÔ]WìÄf¢ìL€I‚üqÛ{P›ÒÂÀ©+�×µ½QÞðÖAÈ$‘"çá\­b–Íl¦üLµÑ0¶?r׳+u“˜jTÓ?“}hCt@€ÈÁdN’†Åò�'+FÖ &Û¥õ õfG ù¼å:Û9z„›Ú¤ËwsËý€, €ˆ—‘A;´µN‡õO„´-¨ÜIšÓ’el³¿œG99\ÓÕA#Æ´H.ΰÑí$ûŸßÈ=• ~Æa7,0Tª!b¾¥{umñnÂÜHÕŽÜ_Ýsõ¯ 2 Ú=Ì´Z!Ú9¿hö御1rŠu4ƒêŸnü�™ç’9OÑ,” žçÜPtv˜×ÿQóö ‘»uK7ÅÆýñMn½Ö2‘U¨„-Vð1Rœç^£(õFš…ÂÖW„jÍq¸¸µñŒq]Oâ2Zr¹~âv“<—°“ú‹Ž4=|„ÅCRêç“Ü{ieŸâèÚWd&ŽÂàe?´þê#˜ ,}¡ÕÕܯG*7\ʯº‹ßëI+\݉VA9bTõÊ1 E·Ö¼s”äê¥!*FcÙ¢>É@©Ý/ë:ìJŸ©Ã�Ä�©aÙÌñ8uÒQRh§/{(¥u`†&6ä1Pn©Ñ$X±…÷VÞƒ¯Üpuf>h1šÒ2|ùÀEËæ.8‚h4²¹ÇÖ¼;÷ŒÚ; *¦ U%1~½þåík¿ÐX©ÕÏÄÞ ýÕ:Jí"‘ü¹«?R¶>×twc�«Æâ ç‰]I¢ÜšíOÅKú·Üò6Ž{Áò´|kŒE££"¿«3�£ùø,Êé¯Ù ñ† BÌŒ""|*CóÌJ]QËôxvû?38ÍXa·‡ˆŒ‡HØ�÷TŸD!•KñM*üŒ`¦µN;‹|£É¸y¹À£ë�sóÄnn.8©¶þç„ñU·9}+^LßÏpù4ig Ý`f–H´ÏÍ•_"Is5íë[ì&ö̶GÍ“Eð•ì™f]Ê:uXÂŽt®ùí¡s?%„È^´¹cæ~bnbàKI颮‹­Ü¦X ¦Ú¢EOø„×PíiéÝMð…~ÜFö'ÞrvÏ£|G%2]ÉÒàfh–êÈãV¥†œPyÒ]„ÑÁ�Ü7È‘‡%%"` Ó¢"©ÀÖˆkë@ Toáeî·²I»MßË'­G{"ëjÑ¢Y¶M¶¬°˜éQÁZ;ß›{¯‡ÃÛ‘Œè9ª Ò=Fmñ—öóݸ¤ªÓ¨O‘URDn3šcãšF”oT4;x÷ŸbÌŠJ×ÎÒ¦Þ³´?f~]pÜ9ÙgMÕ�Ö�Nå‚' Ú{zðŽ¨«‘މº¡0pÆ@�Æ‚K=ZŽ þX%W�™£Ñ8Ïfá¨)I‘b/¢pB÷z% ý+M­–aEð¸T2u·¥Rn2Eo«^½·ùì­4\¸È‹Hqÿ¾.Ù€� ~\º[“Í=4ôI6ÏõÔ'šh§ÈšT<½*ÙþÎþ¢²¬N?Á⩞•Õ•Á-.Ñ"yE¡¼ŠO›«–ųÉ(˜9ª–/Ÿ¨ôªÀ†ÎÂY‰a�o­+q�1Ÿ·kGIQ.ÝlMˆ=&ÚRs±4ì«kø¡ö͘þ¹ÝTH¼O˜s¼œŽ¦âÏþ2ÕQÊò€˜f’°›ØŸ&•®hJºV4~ çDòÕ£wc8m¡ µ´ËôZ ºƒ© a{›î-éýæ„xð†f²º»äž‡Ü�‡Ùt2ƒ¸ŠzP¦Û3JHfõ ¿—i�츩kÓ‹oà,œ¹® „‹ B˜geu3A\®m˜ÙÞs-ihb´Ógè£&ŠHU™/K°Ù¬ø:$l�_‰AQð;IuÓ¦:õÄ�g·}W¢;$‡)7`Óø€æ4ÆÂ”#þ©‚¯&Ðí¿|¤¯Øe~dSÂb�4bÇÆô Õþ¹b˜"áë¢Ì²ë‹« Q·¤�%®/²-¸….oyõmKX¢vØIâtº£õçq9X@¿iïÄŒžFc.ˆJ‰1…#Á7O*«÷[+\¯ÙèèPÁ¢xzlªFÄ ~ŸÃtÁðdI¹æ³ü¾"ó¾­@u…Nøðˆ2¯Oúvû™¨L�D%-ë¾Þ4úƒ¥èL¿qx¯$ÚýtÍQKQôÎW �`pJî‹¢©ØìXÛ«}é¼îbÊtÉŸ7±ƘžîÌõQÈÍ%Vv:r·ìÜ*Ç×ñmŸpÙÂiK*nIqÂ3Kœ�ùs±º½9�ŸçÔ&¿g% !r²_ o^YcÅ8y¨%Ó4ĽŸލCÓâµØnrõD×T-¼o�1hÇ ï›ÿlÉS‡A°V,¼â#ös8_ë8~é™eJ?¬ê5�FåÛZora0 Èˆ;pßX_ç¢]�L d¼qŠ ?gƆhXª©9Þ\ÛùÂÕ‡.ee¡ÊOEx¯ì„ƒÿâç}Ûg'1ÛU·{!ož® uŠ}nfÈúíTÉëÓó:Ñ ý˜o¡²€7ò�^Šß±æêa1‹¸“íl˜«7;-nêÌT’çÇÁÏšn¨4žÕ½eýS‘åhH¨Ôá€É „•Y´9gNÇA<Ú°_®µÉRæ´së¬ëY‚"�8ìdº;ÈÜLö̰¿®¨O96?"¿ŠkoAgÒÎ=§ºp«o:]F é1¡iÅ܉»¹1Íí<˜%ü‡VTб‡éžTÝ´õ8�oç¢sKU�#h>gÎé»ò-¯ïæóÈ�b¸¾ Vûp{î�ˆ‚»ùø%kW²‡€ÑJ…‰ 'ýæ•XU*lE^"šÞ%úc\SÚdÁ[0y="[;ðy/bœærçÏ[‘šµ ãƒò‹JNýX;}äJTà);]ä")!󓎇EÀ—Fä'7¢ˆ¥ùž-*õ|½þÓRų銾i¾�&=òVÊe¶®¨ß¯’.†„=“Ü5BÙµ@Au®Æ¬›ÍéÄÏ—ü¨Jì¬ïÕôyÇõlÁ’ÁN° ÞÙÐðaO~ò¬1¢^Œ�˶5ÈW¾‘l‘éâ\·'ÝÒCãÃËÍ%ídí ßŽ ý¢™ïd¨BšÓµÑ\}(¶qaÉœ…?í­¿Ã:o³ Á£�í½Ë|‹–zûޏ>ˆ¡-|’@^m΋–PZËéO©æ„ÿi™F<Œss:±37LC‘ÈßE}ëæ07•`5¤{ÝæüvððÈ‘ eú¢ÑAÒ±®x¯žk:+C—µLvlM̦L8z´çÚqûÿó óHÔ2äŸÉkñÚ}ówªÎg³Dl'sÈSY&üëe!£³An¹ƒ¤¸�ó"²£–©×âkå¸Á,^E¦Mt•WO�­&µŒ{� rdÞ?û4ý �䯅haD |›qÁ—Y¼ó0h^‘¦¹¶Ý› !bøW¡$ÄOƬSqZ"ˆ^˜²WGOÌ6¿³@&ÅÏ]�ˆ/ð–~Aõ”7»¼BÐ*ó늧‰Ù²Ü«ÓV¶-�eÐÁiKFD™Ž£ÙŒRG$D+”!ÑÓ¿ 'Û¯_ÀØß-Nª©ºY� 7ùÒ@„�:´Pi»àŸÉàèÚgÉÑ¥×e"Ê]±�þZ“…#˜yî ýüˆ”¦‚ð â¯*Kr¦è‡¨{#çõ�çÄ~�`¤U�Ëfwà‚Ö&yª´;s1®¾÷UÛ#íR)rùéP2ßw62Íù­Roªú˸чfÈK…®bCN𡦠zs™õàôcøM:yM†ù¸Gl̺¤f/^p¦0wžìUN+9—“4w‹úÆÇ®à ®Â0˜²¡p¶µèÿDð«\jF›îʨõJÏÖÆí=°¿…èNh¥ó¼Âô¶1/r‹ƒÑ *Ÿ4¼¹}¡2øhÕ(êá©ç…QJ� r©â)Ö�ð“g®³\ºäË:ÌX“O-‡qVJ÷YÕÕžæ¥T½IaÇÕgôvžI\ú]¬ùPsƒ7~šHùG±rÿ2Y†ÎÛ´0Ùµøß} ÿÖªüßFÉ鹆\.Í!ÞY!Ì�™ý5ÐîeÅÕM—Ó¥=³`Š|§œK!ÇâG¸DK—Í-ŒÉðÑ\Ü/¶±GµÿHR1Hº‘ÄòT#ú÷}¸£LÄ|¹i\uÚCw¥ìy»–V¹ÑÂ~î[ -Þ‚‰Irþd]{z-ÊìyB"¼v¡žŠæ‘M¦,Bõ©4Å¡íu;Gæ€"´ŒK`6ÖP…AÖ„¯JÅ%|Éã3ÿ@ÖóŸç�êb¸Ý2"Do8†Šcší}äT!ê¿]#ÊIïkãlÑ…Ýwš†§O~ï´Ä¸ ¨´çwR_Š:ÓAÑôcDéØÙ%íä�ÛÅ0³„SñRM—Ý­Mû¶aŸ¸T[½á;ßïä}ÚЩ¼ûì°¥��¬áÌcõ*ü‘eÄ”A½–£Ÿ ÕÏ4iXk™násWJŶ&Aƒºµ�n/ð�Íçlð4ðÝe¸F¯›ÞåY³*mY ׊'éüØ»¡éË­R‹`aY‡Ü¥. ÉYA®/ÜŒA¬F…£ãLy~Rá¤Í¬�í¦ÂZˆÄ‰{ndÇ=Í’À<Ã7"Ö�†€xì­(ÙE”-’*û8/Xýͺ–µ_¿l•ttô“¬"NT€J¹uø•±k°.^1Œ¾ºÛmå\µó˜ð#lèïærF„`|™¬©¿>�„2<Õ’¶jÓÊa�íê��,X`ùêRî�L !xZ|…‚7±)�»™÷œFµÎÂñœø4G¼[RÝ(¢“ð�ð|Ç–ö[�ÝÀ�C<þuh`\ð+†ºÆWk–—E~o)^9@fۯʵb9å;ßwä%õ.^ò:º`¡„<HaþëFÕ(š»˜·ÊHŸK±K…­b k+ýwÜÌ‚ò»u´Ù*¯N ÛVàÑUÏQÉ#�¨ x¿á=a«Ýîè²M×,œ—ë†}Žs�¼Š›ï.÷R’ ”½Èq?¶ ÊÍ:"§ˆì/L?§„ÓÍi¡œ]¦$4#\ãžò�[£ñ¬ð³· ÷á?ÇüöíÿÂĪÂ*S‘ò&V;Ÿà+oB `ÿýؘîmK'*¡… ®+�8Üåe‡¦pÍiŽè™½Â›uØÐ|Jº€s)]?ôàZ ŽEu‚OÓoŸH{!Lx<²2n±ªtå _mòúÓšqf�[Ëž¢�C@ˆápè2U-?Š�ìqvÉVy;!=!ŽûÀ£Æ�XéÖ�ÝtcBr[I…7ñ+¼J³‘Ÿçïs�\èù‡Æ«!KZŒ ½ð!Åþæœ8Ñiî/íÖJ~-ƒä ÓHØ”àÑM'–‚ˆŒ½�žøßy¨äþI»î:ŽPº|²=y˜³Ip,7V£mÝ5oèÖMw“Ü6}Ö¤$P/“)à@aeÝñeMs¶WÓñtX¬b@¯prôøÿ…³fÑäGHФÞ>¿XÓÓt3:ØIQ5þË(º5âÒ£NϜ߲ ÒCÍ©ýWž•ŠÈ£�Cº:—È.(_Ù›lÉ€/˜;íDGhfB—o+«×¥Oä§bJU¯åã±×Až5²Zô03G/Ôa¾�ÏÕRQ+Ð¥yÄqè}ØhîÜ3 ß ¬Z˜¼q·¹^õ_`@›‡&v27G¥?¿þfî.ª¶+!y„% ñÿ¾ 8^¸H2á6hd)kô£-ñ5xjÝfª÷©9ƒ ¯&ù |0pŽ}ym®TÌìךs¿p>²£¤1ˆ¿ ²bíþçÂòÙ„xìrùn8Ö\�†âÏf40\Ø¿ÛóÚû›¢A ÑjVÊë–�†-Õ5ˆXþ›nKô¦.Ü2 c‘ÇÆú�yaÚNðXŽ•ø™ã®õRôlXyù@_©ðy á“|ηÀ¸I-ï÷”Ë1Z##ôôE’qº¼Ø°ùXüxwH\oñ²M÷ü”ON:s ž0“à»x£ô'«õò&š¿Ó0?máË‚QaêŽ5Ö9 }aT;—i­JÓÌtp}méƒ=~–­>Ù�ædwsÚá¨FA6Úóý¦”†V“ËJÿŸ¶!5í±!q Ï8ûÜÂȨ3·¿~“µñR5 Ž |†ÃVø‹Œ~ã¯C4/lH„Å|ìà«àZ™dj6ëB(ë€n2¥W®ãfúGdêF’^Ú€ÖŽ’£¤:Bi„:Â$[!Œ§úÕ£¯íD%Ë¥Ü}b^ v¨ÝzÑUVbŸ ÇÕÕ'" ~µú²¾Ÿ—¶ËÙM4Ë# ÖФ!¸„ëêlÆÅÊ#—V# endstream endobj 45 0 obj <> endobj 208 0 obj <>stream xÚ­vcx$\·elÛ©Žm«cÛ¶*vÒI:vұ펭ŽmvlÛîxÒï7÷Þy¾™ù3sU�½Î^kŸ]EþEQ…^ÈÔÞØLÜÞÎ…ž™�‰ ´5vuV¶·•·ç–¥W6³p|ÚÙáÈÉEœÌŒ\€öv¢F.f< 3S€¨™ €…ÀÌÍÍ G±wøæ´°tP©)kPÓÒÒý—åï€ñ·ÿ@>=��vŠÏ/nf6ö¶fv.ŸÿÏŽ*ffK3€9ÐÆ ¢ ¨%%/ ’�WH˜Ù™9Ù]�m€&Y ‰™�³5ÀÜÞ `ó¯ÀÄÞÎø·4g†O.!g€ÀÙÁÌøéfæabæð¢8˜9Ù��?¿€Î '#;—ϸ؀v&6®¦ø´›Ûÿ“�ƒ“ýç ÛOì“LÑÞÙÅÙÄ èàøŒª(*þ¯<],�\þÆv~Â{óÏ›¦ö&®Kúû¤ùD]Œ€vÎ3—¿±ŒÍ¦@g£oŸ±?Éœ€ÿ¤áê ´³ø¯ èNfFN¦6fÎΟ4ŸÜ»ó_uþ—ê�l¾ýãmÿÏ­ÿÌèâlfcÎÇÌòÓÄå3¶ÐŽñï¬HÙ™Û˜™þe7uuøÌÍÌéŸQý�êÏ$ŒLííl¾LÍÌáåí]>C¨þßTføïù¿Aâÿ�ÿ[äýÿ÷ß5ú_ñÿï{þwjqWy#ÛÏø×Ž|.#;ÀçžÈþ.#§ÿÍÇÈhóíÿæõï·5Ìþ•îÿ…LÊÅè³-BvŸÒÐs3°q1qÿ :‹=ÌL�.&–s#›Ï¾ýcW³35s²Ú™}êûOkôÌLLÿ†©ZM¬íþ Áþ/ÈÌÎôß«ø”ìŸå´EÄÅhÿ÷%K¯bó9lÌœÿrQü Õof€ÿOCÎÞô? ……í=^ôÌ\z.æÏ×ø™7 Û÷ÿCðˆ˜ÿë,gäâôè01011’þýdúû? ½£³3±7ý;H*.Fv¦Ÿ³÷Ÿ†¿°‰«“Ó§äÿ¬ƒÏúÿãüÏ+03ó03�[^°7á ²JÍHs©ÁÎÕéíf vøY¯Z˜ïWeßå›¶Å]nøZÌÐ0ÉóþëÛü‰ÃÛž4Íþp7– eW²ÙEÁwRêž|ÔuŠ6NÚýFýŸˆi§Q^—s²›ÚLêûÛãJÊúůP„“m¬N0—�Ô~¤nù~dH>&)u1˜í( h5'§ G�”ý#Cƒ]×�={ø´Ù1°ä¼FØ>I'_]¾:ÝÕ›¼C>»q:WÌg6kT¡&¨¹{â¿,¸“ÝGo¡3§�³Y|�î2 .Çȸ_„†ÀG³Æ Ð�ŠL©Jë×¶/H�.q¬œÕ ð¤Zg,qGá"$RI Ù7ÞQÕ©%ûç2´CâL%Õ™¸PÒ”´Ô#ù§8Ùjñ¾’‹ E Öø�”%n ýÐosùNÃß R©šÚW›uªH?ȧÿÁ|àqçÈÇ$(¨eBsõý¬\Êýu‡,y½K¸lªâ÷à2$ô×ÔÆèÔjw™‹]rÖgÜPTÉuÛbž(©ò[ïÛ$ýæ.�ŽÎT1öÄÙ¯†S‡½ 2ÅÛ0ßêµ$;ÏAJd`¢ås}Ø’´Oß�挫èt"�t·Êñ3[…“3º"8vy 3—lX;n_Õò’GC<"¬‘f£jФG@ï -˜lŽ¥«4aë¼mÚ‘8:æuò"ÄlÁbŒ—¶}e_'Ö E^ÀÔ}ÁËÝ×r9DR�;ìÂz»¹eÌÇææTb’îvÍ¿¹v7z%�bkÍé:Ô§9¬M¹Ae®&ÇZ[›Tj$C€¢«Nt(5Jã—zä¸y¨Zo<Èf*�ٛɒkDñÊxÓvUJ˜’–køJÖÉf‰V²Û¢Øú‡”{Ô:«£<¸y:`0ßç+² �(š¸ï4QD‘o…Î 5þT’ CF°AM•q ‚²w”¡ÀLsåW| ZªÏâès+ŸD÷.ØìX� ì<€XlÛQBßnbV-z¬haΔ �P˜>¶çzòÄì*!ñAGäõ²�eƒuoñ[öEBovJs–B´çäQ‹ ͦw§êKër1`•ÑÛõñrÛ›2“­iúnÀÎ.Y_nHõ®‹¾±ÖÈžLœû×Î>vg©k›¢U0½Fûw†})ÇQÔÈ›|7Ò�ö&1úéã|ÏÅ Y…"R´ñúS©˜6v‹¹ì¾ÔÓIµ&ŽÇs’ºÂj³0ó»=ûDyB%‹3'oþÕZë›às̳»ÄiF#á(5~·3+&óêÚÉ÷:Ùtp°‘p+ºi\¼¥HÖévZv›„TŸe#NÀín­é`aüAZÎ/¾ñÔ"¨e3º¨éÛ~ôFh~¤?9]¢¾m˜d7¶l˜�[Ýä~yžz·yÀæû¥¿C¶)ƒu=ÜB©¹G´!¥Xçäð³xOIw÷aud{ý«¿€ŽÀ¢ƒš¥ˆLö]ÎsùC2uÙÁÞ1Gîâ6ófó.›Ï\6)1ø|!T&”.ô—q<Þà$¥1“D!ℇ­5Ê6¦H†K¾ÄÇî7í*é�rjUÐ;Z”àoÄ„ú¬£ßÙÉð®(®‹¤ ò¤<>`‘ ‘è^@Ö,(ªŸgÛÎøHaNsDÀ]Ýð‚»q'ö�Inò_¼�)TÉ›^ð¬>JJFI¾Y'ñÞÝ—©Ð•Fgš ›]âkÇŽ~ñÊKÝ]°#Þ0äü¶ËIBŽ€: 4¶Nðw½Ž„3Ò� :}/3­ðg¤¤"´J†Ž�/ÿ1 éâÎ*´.ªj¼>N¹ŽÀá­… ^’-8ëk¬Wûó»¥rw ÷G¶Þ%‡ãÂ�›¾vî¾Ç怱³g�#Ó<ÕŠL=÷~È4’Mx©Å›>ÐÀ`¢ ëÎ`å(v\=ªêkØO¬Qb=*ǵå(®„í·&RDfR.¸J!1¨5™QûŠ £Të¾j�oéß3{õ³–f‹V‰d[ËÕ¡ît¤ýï`ÊAx›sn>¶}åH§gÂ4ºh?²h¢u–1´lZ ƒ°Õ6~yü°Ž"="(õù3‰†íuÒ„ž+O˜:Þ…/Òõ. »Ÿ(ø+ümf—+<¾ë¾ÅJ¬ƒä�Õ„->¢� ™!õÆ @Ø)Ó}J¥óeÙ¡YGi·±/7æ[nê;Õ-~)Vv‹°ÝÆG£šÜIDtËm{—£ÉR"yŠ7¶\>'s8º>\gÇvï«Í¨Ç*¬Ì0CÿU{| ÏiŸ2YÕHOîŠu‘?îk¾¬é¤à{6Î�Pj‹Ðb€<ø* FBŠþQ¨ëfâÁú½è—n_PâÚËx¼Ñ`À°H@¼+§-xêJÒfDže±Aaœ%Êâ=MöCƒŠÕÕ¾cŒ™»kdb„¶1æ}¬¯'¼‡Jë\j!Ö8@G6 ~·á:i•5¶—ä4X—!Hmωj]\9AŒ*Ôèæþ±ª={´q,rå|û=ß=LˆÙ#¥\ßKUH©T½ �ÎlÝ~0‰œ(¯æî|žmNIŽ\’dêßmñi÷1èOóð 55ò…ñS �ÆÕ]Îu¼ä‘O$A¢VŒ8£sQÜ­È·�Ò[ÔphFÀ–õ³ô?41Jn·»à}Ø7®Ë…�PlPBt›«¼zÜ0S£Š^”t˜wÌ"·TñM=uĶ®9ø4û*¸:];Ðöú”*Áçϵ–*hi\s×5"æ¬{9áz¬›l"@ha¡•þÞ…LÖÎ¥�°¨ª‘‹Ó«ìi‘ÖÐý07,å»KlÇ.}âHxƒÂڴß7MwèÒˆ(§‡K‚ž¾–Á1É5-ÜCèK‚âJ˜‹›¢ŒÑŶg8õ-d Úc±$õY?#Žw¦ø:AFá­ljó*Ä{—ß ¤vj\“ÉZë s%;;…í üô÷D Á©½4,œns¡•…q•ËéyËû(0®d=öŒõB?—ù®Y¨xš¢GŠßƽ¾x�îñ®'øz�¡{ïeÝÖ!¨Ê¢œ²¼ëô{7Z{8¸—AѦÖ�QdJQÁ m|è6µ!£ø‹ÝàG0]pš¥óÈT‘ õšˆÙ}�'½)Äéîë´É¯`%J>¼æ<¼/AÐÙþ‰Ø/ÜÄ8{ró³¥Er$d𚲪A¤Ûbƒuë\»?�ˆ™Â´ñÕ’˜»û†-u/áâ“ú‹£ëcµ¾¦�ÚàXVÀ7ë`„ÍÂç<ÊÁTÁE³áî{w|xÄ1…Öi›Ëó)(Ø?ñì\ðÏWåíðºù8aI“sÆœ|�¬Æßn <©Û³ýÞå”pÖߺC¤ X;’LdÏ›Áš4s§¼(ª:�ëE²×€Û‹Û�‚‘礽4m³)ºÚ�”FOÎŒ’?P•¿À7H¶# vÿž]Ð2„ƒÚéÿÉx­"㢾=“ {H×&<ÙÌ$[[ðð ;;š„Ä5µ«<-êh”P+Ѐe–@.ìôžZ<»|p×hIz¹PZ�DRzÕÛ‡¼çÂMÓz ûvÌžŒõs0 ¿,ئÅÒB¥÷:¼.hWEëq74C¯Ã÷öMúx’²H�çåPDLî|^üîÛáBFa‰kˆ:£OµÏ©k­¸\þîî³V»6;½0ç—ŒAþu·ý†ü¥Ì€%¼3Œ‡`Ô³é>îÆk5jT=®† À÷NVK¥ÐÌzΓ #+ÿºí@©ƒo2IÆtO? l$ ƒkŒqÍ5kFƒHÖP'Ë–Øró~ÑþŠa©¬âçG4LËùƒ7ýtaB¥Ó´R$Š"T+b´g wÈøæá—]éY=’¾;‡S)Gi®s7eŽmgFÍKµ¨ác†¿‘Ýa¡ðSžÍ|^y Hà±#`¿Òaã¯ø"Ú…¢`RòFMí¬ÛJ�^Ú¹^ÜuúAÊÞêÅm‰99žç/>b;õÇøH�Æ�Á¯£7ÅÅjw³aQó-° eÏšTU~øªâÒž¡¾U†!Ûj²ò.%ÿÕfsu –¤ì¦ŸÅÝ_«ÊN*j-@{,ÁÙÔÇë-ƒœ¯Â|)LÑ©ÑÀܵK Æÿýƒm¬êŒwuò�ú%JƒôÖ9Ù/XáC'1QÕ§8ÄR}su”©½¿ÿ'l±Sd»wvÈ*Åž3˜”j½‹Ý‡Ý ΋OuqaàaÂñâpû‹sAè²DÅù“3–À \½Û\‘Ÿ…Ìô+úËL� Øý»CÀf·»­Ÿ&(Ç8ùZÿº ¯`’+‚èD×øèâ»ø2s†{Éݨ±«Œ¸>Z]€tÃ|E%Lԙܽk<õ‚äºxÓlÁIÕèQë¾z,´•È0]Ü/ŸEôNÄ<Ç1 òÒÜæÚéJ·–ê\½r]4\>}å¹V~yé�PP¤PðéùJ 8áÍ"F½†VRµ¹VÕïé]•à nÉ—–(ϲPR±!êgb¢ßa^E¦&8Ûl®\¼lÊ ÂdåÍÐTÇYîsV‡Ç¨¥¤"˜"2š [v,ÈÞX�”±”x—+ðîsK™£`‡­øš�cî%«9îˆ>gw?®ÀQ þüxoóM-ä8�šI k‘4Ÿ§Ezüà -3kŒ�ÆÔú�ÿÑ|G\F�sءܯÉ�¶ä'�oš é•-6É7ìND‚¶½þ/à~Cw”ýReÞXã„QFGè…®½b��K¤%ÛÂÝ®A‘rÉã\.(ù�¡·¨ O5'±7žÂ2(¹œ—èhò¥BÚ+rI]¨6ÂÓ�˜‹T‹K야©K_qØjŸùòH[?*Ä'y-È©ìªM8*‚ç'±Ël¤ÓÑר�ß›ØYºÐdéb¤Ñ¯‰1»-µ ð’Oëa—dDåË +®m·Û  mÂüPÕgÿ�»+ÄÅQý§Ù…ÐSZÒƒ·7˜"¯Ý�sY=súÀâ{ê›=Nb·—5“N|y³Žÿ;À—ï�™…¬ÍJ+‰÷R¶O À¿kÆqkIm ߸‰’¹‚ÜÌ´ˆH«Åù„Úê{-c ‚‡ˆƒçAå|:%T§.§ØŠ^—GÌìR$¦RƒÀe÷åÑäª>xg‡ÏXÂ÷G1h-â`¨cºu'Ù/®ˆÎf)Å a("èùéõú3%“ÊBZ ±ô•^ÑVm±ÆÌð‡îT“ÆSÔW|E•Üœ¯h mG;ì‚h­—¬kÎúNñŽI‹`Üßy3ƒ ^óæÛȈ¹ Æ×»V˜¼Qqþd¯Wiìi—“ À(§z!¤¢]©*ãÓ- /¬—  ññ àby¥ú/ã`ô{ÂñzÂ_e’çWa‡9ÜþtÄ¥îéÉ”Ê|ݰSáÖ/°—M)Í Lmtýe Y€ßЋ¬KL¥ ÏìAR�‡FÙ À Ø×]$¶‰ÂJËjWÜ à¸¨¸¿¼g× æõ�{“Ž6Éõ­~Rc½¼DwqLû¸æ#[ZÆ!u3ž3”hŒÒPɶ»]…èÀU6ÚÈA™þÛÄ?s;T0ü÷Ÿ£8©Èëm…dž¡'oʤq"ÏcèE¡σïÐ]sôaù·t"E� #{ïkjâбãâ( ÈÈ+ê4ÉF´.Vx%ö=XÛST—†5Þè Ipc3ëG€ßyk³0V™R«³ñ.Ÿ9¯ìüPN伃ØQž¦/‘÷ù©èÀ€f¸dûbi—y+»mçL®‰k‰Ñï“ü°bñ‹qœ@ÿˆrÂb:P‘ˆ ÛKDkIÞékû/±,73neŸË²FU')ý±�.‚¯§=Õ´—{pre ¤E„áDK³tv#ÿ(È9ÉW ›³�%Ö&nø‚ô·í¿å- CÐ4Öªú…þv‘ÅÚH–"X|ÓR.Ñcpµ¾|²ÔÛà�|»àgä‚Lë8…Jâܾ�{Dºœ¡åJóŒút\)jÒç4i®ìÑH�ÆŒ«Å7’6?¸ä:'jcí&­Æ´Žª§êÜÛœgáv””o_ íËqNèÁPD—‹¶R(޽"”6ê¶á�§QÂ%ZXU Œ¶1Ê›ÝSâkê=ƒwÂî�9žWéD¾†,ØŠÝáÄû‰G‹¸_cÛê!6å,Ó“d¥°’((t�§Ï~õa}7 )¯'ØeQ5W|ÜtÕö„˜/"¨Ë·*Ñ0‚;Sb âMBö7‰‹örˆ×YMÅ\"Lãqn,4“+5€Î\&�_pùMê—ßËÓžv!çÿHáµË1n�¡úäÿ-÷ºm1úä¼f¥ÉýÞ¤,žaÞn8c"R1ºß¯2Ðçb SÚ¦5Šè¡�­*þ˜¨ÆÍm²ºeBq„å×ìHäP½ï"ÂÞ>I_*¥,¹Q±?‚¸~ÎQoÿtl&(ï¦Í½…ˆLªáœÄ:39¹l–âÍLâB/Ni×{­|B–J¾öä9p I›/?h]^z±N©Ë>mÈ¿« âÕ©¡ó'&ZZn<` ëÛAó¡PÂüÆ/$À3åV´<ÜѨ$2êç_ˆx91!8éÙŸ‚I%UYK¤œKMdh‡*j[2ôjð´~> VZVURã<Æ\SùµÍ[¤_ɲø¾Æ‚+h0‰A”2ðO(­¶ œ|w*@,>û�IyIåÊx˜ÖùøÏ„’ͶbwÞ=°¶ò&c„ØY QÏ«'¿Ìð`³ì U…Ì‹ Ú�‰N—[c§;—C qôñ ÁîGÛVºô_ÔI:…�—öÚ¾úÒB{X"È‘¢ ôÊ{D%òGwËËŽëdÛôÂc©ô2æÜ§Oðí”UʹCkÓ‹""U—¿™ÌŽï@ž'¥¶­–�QX˜ úÙž@ìÃð5¢£Žn §Ñ €Å§c˜8ŒïL ~©|'ÒÃ/ù÷}Iä«gïÚiR¶3ÂIhú&²Ž¤3ŽMp8.E—m7d„¡ú2~6+·7ÝÉ3>yE„Ø×I;ò{¹½èõR öŠ#Ã�Ù|÷ð?9uþ5YžZ´Ïu®I3³‚¸ÙåÖÀEêÀðûv¬¦Ø[;­I2?£³é–*Ö#�JØ«¡I?vCè½U0³;®»s‘©<êÛ. V(­»ƒÇº:Ó\*“Ò(oQ¼ýl×ßËúQ‡Q(Ày^Ôt�‰?/÷w³â�Ú 9‡`t°ÕݺrfOLN«#¡mŠ3½ªÑ˜£©}‡½–ø&n^÷°.�ÇÙô˜)‹¤†¤ UÅG4„×z(P´÷ž×C•ùbç:­mÉe]”fVÁxþ;W(@¬Ò¯©Ínˆâ1×·÷yÆTdäØól!S`®9�“ï+Ty£ÊI)¯¦.¿ò-ÊÙF÷ÒF¤—fða+xhj®ÚdÄŠ˜¤EX¹þY»ÉKL,qLè�ýªrñª—9» d»JʧfÝ·x°îBLIy=’šÅÕ“˜K‡#úp(µ´™ætI<÷$õ;ƒ-eTpÖw‚C–U„Ñ‚¹6ªšœî¹NŽÊ{ƒâþÁËl�PØ\ãMFËÖ*C¼ä�uäôÀŸŸveÁïBéàuOp2IÑð °ŠûSØaŽ6™&ÀÕÀbœ�rn8`¤ 휟5nS�D]Þ 0˜éËC[Þ_è‘Üj†)_û…Á›·†”T³ø¨&E(§+úÁ¯Å>šQ6b&[ÈXoÓª—\t±†û‚¦}§�þ#º§ÐðMÊ”+¹òÃÂ…øÏ�œç÷²ef\B”‹ý cFmpF6n£,ȵu†>ƒZùþV[T6žÙÆß%¦R!J:„W@ZjnDv‚#ììÅšåH(‡¸98ÌÔ0‰öÆ|ˆû¾\|Þß"±Ó/<å?â)¼$Ondùÿ̸¢¤¶dk1‰'  î$ëYa‹mVy¨9NôŒ;µp네¢›æDLÌÝÙv ßxO/¯¸�-õ–}Á­å9‘n{e%ŃF¸eJ™§l)ÔzÉ Û¤ÈÒèÅ3`¹t– Qts 6¢€ç¾$v]ðdU^¥ü&Qö¾Iîqsêûëã!À@²¨Ž?Èr�žÅð(q³½¬¢™®@ëAüè—[]¿�õÖë¢KúŸ¬qÆdÑá®ñ7e{ê!1;Ùõuå,GÁí·âO©ûøå0ÆqÍÿz›ã…‰K äé‘<è¹sf3fƒ]í#‘7ÒÇ3&Ô2'Xç»Ș�ÈñJèÁߪ¢ª{”Ì©O@Ù\Ø…?²+Þ+p¯z¢PÈå@éu“ ¹«°Í¨I¤p�âw…u µZéZ¶3`Uü^ýƒ6:õÕÞ(ø±‡�ë$½HÿéBBº _Ûq@ ”~ÏXY4…–¯tºÓ}�ƒ¯/Åä“M×¥8i™®j4AI¶5ô÷Ù žNÆö5€G²“SM-M]Cà­­šÐá¢ÕòL.¨ò¢Ì1|v{äå A³ºTP¨8[òlRÑ$f�oYíL#¡Çízam‹v¨!x%ÊäËéõ€¦ UŽãá3ÅþÊ@÷üÏ1w�´ëκ 9ojXŠUeòˆ?’Âi•ï©�>Û:lH_¥_ã•Ãø$]Ågí�ìX ^ÖÉC섽Óh±_ÇOÈh]޶…vö]&±Ž3!ÞÑ=}w@zQ5«p�äÔídz•4õxdéV6šÇ,/ÙŠ‡5y‰kÚ�†æ– gg¹îëÖ-Sq|ÞÎ…Í2bñÇl© |²#Í éïÕµ$�Z!ƒÂ†¡+qL»iqOÓïJã¹*ƒˆû6ç}¬âjÙ õ¦F� $1ÐH4Bå¸RФžŠ“m)�ë(£7lÈisE°üHðh=бãÿaµ'Œ›¤ñëé¶š.›Îc6ÉÊÈÃçho«±nÌÁ ÆÞ;â„‹Æ¥›:ÑÊ”›Zië‹×ç;/I9õ¯wýâo­¼@ã·éqùm,·¯‡80—]Æ—GlΣ%¢">�)‘ùë&…«<Ò’'d½[í¤òèäzã•`gdÙD*cöx\n0£¸,eóÑáû¯/ž¦%ÝsÎìû¿ßTkr´O’ ¿~¤‚GÑgO¡´ÍL•"‘¬ˆ·b‹ÂtGî%Ú©z—;L15°$ƒEØÉ4R„QS>o¼w\¡Ãð†e‡]tÀá Ûé60…3¢É§¸U°,§£\Ò&Ï·A+±�ÏÈQ d[2—ÇÚÙ,½A2ˆÓ~‘&,èìÒ÷3(ãØPdpµ~ƒ¯+Ý›¾_FÓ.àævÛlûÙñÖbB’þ-KØ¡àvÏTý§í|B¨ÂTI[»71‰•Ú†ö 4Ù2f� Qê�xDã  ¾oÒØíaBV^WŒFZ0ZBQ°O;yZn� ¹›>" Ø›þ'pƒxþNÍnÓ´—+²ä¸n£ÕFæ>|‚¢³0ÆÇm)¶·¢úTBàxAwiUÔ´LjöÛ ¥˜êV‘¸S[*p©ÿ¢lPÖ]1ëàë¶5ƒusC]UDP}Ëèº$«¶OãÕ¯†éÃfEÖ‰D$Ê+×k8Ö¹w€ìŸ‹Û¬¹M3Ò¢žÓ{²x¦ÁÌ=ºû#x\¨Þ§=Ê÷FóC‹ý4çÜ g7Û„ž_Ú–~p^JôeA›åhP§mÞ¦b|¿ £|`Mþ«ˆ+'ÞM5³ßÊÝWŠuôè¡ÈIøÚH~g UóƒÂÈE*:Ã%zûnÑ`Dbõîö¯eNãZéÝ”ìéœúnFú ïÛ [mv™?r5�LZZ;t¿E‘]x˹²³–¶ìÊÐãYͲ»â�_Š~>d3×¼eÒ“®ä\oUvØá^  v>¦KÑ�FŠ‘¿ÕÛ¨c‘Íék²GýIg¢žNÞGƒ=s+p$?=Ý^±vãÖ:îÓåj"/…³’“£Vg†¤X€€D𧋦á;À¢fíÏâd®IX:Æ‘_Üjɪ�ä®áOȨ‰â! u9¿qc’$`Ùò Gˆ¦!¢Ik×!‡±Ð¢Âß †TÄÛD¶ç©I µŸTƒF6”ÜA¹TkaQï�¼0²ŸQcj£î9�"¬óVþ4îîèÛ1ÊÝ-,”44ÀÏQø,R?jl»�Y×'­ü|¥é01�ªz¾%�_¥œÓ-aé@”°™ø™ªVl{Íõ ì¸`©ûNÝq¼“#¡È‰™hzd½KšBk`ÜWV•×…O¼t•Õè …VüÕÆŒõ·„DmõƒFoç :kÝÝù†">ð^Ì_œÁzRš”*5Œd YØø/LÔ=7™+ê‹<æò'ô€D»ÒNŽèI¯×,NÔ’coSÓ¨©]o ¥‡(DmвNš÷×1y¥fL]“åöhÕfžÄ…kœN�ÂöärGmšõ�¾¤Ø'ôËíYSÕ‚J³&ƒw‹:sZåàújô¥DdÞÛ3×áZ›~!Nòx™u‚È·PɆ-¨Oe?�æfoxÖ+‹]vôÌ´’r ¥ä¢,�H¯™É§BÓ7,RRd|t±Â¸°ÛeÊ=û„úQÆ�§‚Ÿú.£äÐ ¨´€}ù*vÿ¼Î—Ú ¢üj Ç©Ç[·!brÐÙUö…/«PB2´WÃfè©"`;VšY3MѦ#¦ž²muP€ F-øQ®.KS“ù½¥�”SñÔR¢¬—4¬gÔ¢½/j$$’Ø’ŠÏ &ö˜ðXxãW¢VËÖº5|‘<¤rh½ö˜Æ-V²VÏÞá¨øUOx¯õ„p#±€ º' ÷}çOÿÃë”fék@"(ÈŠ¬â½f2 Nœ&®;·õŸ\‹=:m’§ŽÈí`«'«‘ç"æ�‡~¦ö ùcÏ)S’ +ª¾†²k­´dÒÁm³8(,£MÄjlÉeVCqÉ_©¤-Ÿûõ¢3f c~B·i‡s[ô³_%ö0>øÎbõî~L˜r•Y(t=cÜ –j…ÉŒ¯ÒÁ<¤¨Sľ*ø£îèhr×�FEN»ìoS ›§-‹ÿpv�+Ûùª´öùKž0ú~ÍRkõ²"°e¼ÄÇg€QKTc,jÊÓcÓŽC·™øX«÷ Õ\zÙÁšsSJks>¿›<úõf £ˆ õjg�DîòÞ@¦Øèâ ÑLAKè+Ρ™_|hæ5MY-e`ǃz½Ót¦A‚ (Eþ¸ŸCvé÷ñÐ8NuÏwl±d�ðÆÕakÿòé W4µ!k ÅT„+3ú1_ëÙ°ñ"t€›_þ—K”“µøzÁ„±A4ãìH¾ÎxT;KÒéݱ#¤æMG qІ[M¬&ðìX§E~›®/8d5ßç>ŠÆ)û¤`õŸ]oú7w˜#ï-³ 3¨ýaìT%�’€¡ƒ](V‡©±YVÐ~Ÿ^zö»9þÉèWTŽfi/7΄W»ìØ«‚ÇVùt7øínJDúL�¼Q˸ �¹qI¶_÷P�¯”æƒa�R†Ô\»¯NC^‘ir©écTqlµØªÛ¤݈³wK\·A%‘« ¼§h—Í>uV?V{hW\äÈiµÔÐÜ‚t82\a\Ý…�n`âŹ=q׉”ö{…ÈÞ?Þø�(š¨\^‡ØÈlêóqt3Z”&Z‡L›B¦^"6b„Ë{—ÜàݧEÃ[Ýuð”L d]¶ zUÒꚌmEk¬‡öcµ}ÔX„Ú;cåu‡*#³À¦ìÉDiF·àŸÿJÒ¼D=‡k¶Îsä\…^F{5cã‰C*±Q‡Máªèê]G3}C½Î½»°G #­“ëPDSÎeÉ.ò”è|²š?DÓ÷J†¾iÇ*&èÕà P§ÁU³²V³Õrn1T—Èå³ÎtÂÊ$‘›J�ì™›†ðÂd Ðĺ)xj¡jzG](lItÄ~”z±.ð¨îkzŽY6øÜ À,"¿€,gæç_Eâ§©Ìì¥Ì®,œ|© 0MÕÊd ,銹(ÐvmfeÏóß0ú°ÄŠ=µ­Ä*m«æËbjhÃÝÔ…¸¼B�•�I�Ç*#°gˤnEÄP+÷¦/nØ iº fV#‘ ³* �Y«p �¬^…ä�Q ]�piü-ÌìYH¤nïGºƒ�ý®â¢`?¡¿ð¹“HäBe;/�¿æ¸\ÚëAçMÒΜ^²ff!+³‘p�NoÖ”F·¼bÇt|ßz±*2 ¥˜0n¸©rì¤lL…ÕÀJdQ °\ú–Eà \‰_YÅc= —µ‰ß=ÖÌ`™d�í’Y{5T¬94NÂcŒ›p¥�ücñŠ/ë#"ÎTˆÃ`¢,Êç©ÄÅç}Åÿ¾ œOÞgØ×¹·øâœoÌUC¿ŒìQWbia¸ ˆ1 [ܶ+%J)öHY!ö7§­µ˜Av.ñV§)¢ .Yg-6`Ç ê‹¹YWñChê²> endobj 209 0 obj <>stream xÚ¬·ctem·&œTl[;VŶmÛÙ±m«’J*¶mÛFÅvŶ�t=ïÛ§O�ó}ý§ûüØ{¬{⚸æ=×XäÄŠ*tB¦öÆ@q{;:&zFn€¼¥­±«³²½­¼=—,�2ÐÜUÊÅÈðWÇKN.â4r±´·5rr4€¦Q  €™ÀÄÅÅK±wðt²4·pP©)kPÓÒ~ÿOÉ?&cÏÿÐüõt¶4·Pü}pÚØ;Øí\þBü_;ª� ÀÌÒQPÔ’’—PIÈ«$€v@§¿E(ºÛXšd-M€vÎ@j€™½Àæß€‰½�©å?¥9ÓÿÅrœ€&–Ý€&@‡Tß@'[Kgç¿ÏKg€¹“‘�Ë߸Ø,íLl\MÿIà¯ÜÌþ_ 98Ùÿµ°ý«û ¦hïìâlâdéàøUQTüßyºX¹üÛÙò¯`oö×ÒÔÞÄõŸ’þ¥û óWëbdiç pz¸üË0µtv°1òüû/˜ƒ“å¿Òpu¶´3ÿÏ ¾œ€æFN¦6@gç¿0±ÿéÎÖ øßª7rp°ñü—·ý¿¬þW–.Î@3zX&æ¿1M\þÆ6·´ƒeøg^¤ìÌìLŒÿ–›º:ü‡Î èô¯Qý33Ô“02µ·³ñ˜Í`äí]þ†Pýß±LÿßGòÅÿ-ÿ·ÐûÿFîåè»Äÿ¯÷ù¿B‹»ÚØÈÙþ€ïÀßEcdø»k²€–��‘àŸ…ciòÿq5²µ´ñü?9ÿWk ࿳þŸ˜ÿUýïBvæ¢cb£gû·ØÒYÜÒhªhébb03²ùÛ¼ÉÕìL�N6–vÀ¿$ÿ«¿�ÿ‹NÕÂÒÄÚî6Øþ­Ú™þ×þòö¯ TÔ”d´¥iÿÛö_ÆŠ§ÂEÕÓøŸ‘4äìMÿ×á(aa{€7;€Ž™ƒñïeü{¹˜Y}ÿÂþ ˆé?ÏrF.N–FzFF&ÀßÿÿøýçIï¿ÀˆÙ™Ø›þ3G*.Fv¦Gï þQ›¸:9ýeü_Ûàoåÿqþ×%=€&°«Kö&ZÅþí2!›—Fð-Iéþà\#&úººxy ç-V;s/[žÆ_üN�u*ÒÊo\Ñ€…Õ0½<§-[ŽoJ#—‚kñC ÁÏp´N²máɼ(ná(zT‘?¦N 6묖÷$Á˯%Ñ~n˜|¼Zì?cD)ù³^ � GPcô�,>0¸ÈìêÒ’Ë”•ö¯.e:îþ;)ÊdBì xL^vý!�ˆm�9�CÚŦcñ®û>JÐHÕ’¨)ÛÑÁ¾ê^hß{‡ezqüÏ›ã"TO9w.Üo Tï¿Ë§ø¯¦Q›TVÞµ4£âÉ�ù}žõYSSEärËœQmÒ~…76ˆ¹”ѧyD´¶U�µ"=DM¸rdq=ù \Ðô?Ÿru;C¸¸Ë`j-o,À­ú„‘å52Ëî*tÏ*<×åYL:Žo¾k©&úD×�í™ëB'ýñ' ¢¶‚y0�¿áLs<-¿æ†U€pṏj¯8 1²®·a¹ÚÈ(Ó÷û#w*=›SL¡!ž™«le8ûÆÆjÖ’=*Sq‰ˆ áPB×oÝ]´ÃùvZË1^M3Ú÷ÌLýÆ^*0•/¦½o}èB™©[d”ɨkÚÛ´t gPÔ?pOk×\Ȱ¹ã‹qâèìTø_$³Þ@‘ÅUž ™(ßÿx{fÃÃq¡¡Ó¡£»¢c ¤8†¯Í=q,¿‘´ËlRm)ñžNLdÐ"‚=R;Ži4ðr(`OÜù%ܶ—U—Ÿ’í÷€Ÿú¬~éa3®Q£ŸÃs¯©HòN‘½†V~òÝA0$ïÁ#ËÄ…­îy4‰åuç»g'r˜“ÆC/£cZÌ�‰rú¤Ë�õJåÔ¡¤p%ÿÌ�9¾ZIÎ@òxfn]$½²Ÿ ù�´Á˜KÐ Â=NïâÀÃêOÉËgM†u:Û×ê`¤d©6$LfäŒö­çËÇFUYÊÒå�ögK¶ª×åþñ]ÂÄ„ëövÊklŠÔ@þUJyD^ D°ÁÒßË3uº`ÑñÃñ«ç0]pÛjBg­²Õþû÷ ¢ÒÅO¸¡Ä߈×okI–cÑt�D8‹·ª¹sA¶'õ0<õŸb¨%ã>Ø'´:¸'xñ ´èNéŒ!ÍÙZmoCç’$J'ò›Be,R»w�UËIáÐÖ¨N‚ïÚ[ÀŒ…ظ¨�XI³>v°z[Ëþ”œäv¨Æ)ûœ=ÎIQÍ-Ï`‰à­­?ŸŸq?]$tVr'„�MîT9•GÈ20þ¢ºZ–½ö—”ĸÜÁÌL*Biÿ3Cmiè¨:/�>G¿�Â/g–¶B¢zã3; …©‚ Œ£¾Ö-”d¿WÎ>WFMõ)Þì…Ñ7÷äØ ¤ôû`¨ oLŒ�E)Û›>Ô‹�½.”Q(]àƒ’}¸ kº½�ê‚}Ë¡‹8–Uã¿ê˜&õ™Î8m�R)•„:Ø“‰LÐÓæGgåo™úËtùK®ñÝŽ@„%&®wr"ò«ÆbÍy XZ±b@æÀÇÜ…�sÁ1Yé®Ô:zýeYДèɨ³ µ¿Ù„iQšÞ¶�©Ÿýœ›¸Þöš¸ÅÌ'ºÃ_»¹]ÃÇ#Õµ,ÝšÿØ¿˜è­ (þ"ÆaBçÉ%ð…>ÃòîL¶Ìizë®ÜŠòMØÍq�VºÙ¬y«ïñ¢Ë³X$êJ“0ol±ÛV¹ú¼_í—Ø„¨rÙRU›ò[©cÙ‹„Ã[é¢Î„}V«½Ì”¢È x€ZjÆ'E@Ln�iL&–tYWf'3 W‡µ%œNw‰í-}¡´b�TŠåáƒúž·àG~í²eŽùk› ¢)ĈШÝ�fr—°—:ëëÎÚÙùÓYqÇzäšðiH%÷G#x#AÏ çœäD¶$׺nÈ_fŠà6Ò ¤'èÊQ[i=ƒ¢ÜM`Ù 5‹±ß£ÉŠ�rµÄ• Ì4ìqu~ÜHÓÀª8åäK öè{ ½Rë(�°Ö/–FÎâ�º0�c·0š”]¨ø¾ØyËVó ¥A†ÓF Uqs¨fc`ÿÖ=Zm¢Že+õCI[bHÒïé-"·©�^€*Œüs¥W0séìÒò÷�ÒFRúPˆ+%‹¡'L¯ˆ­Úy\"„Ž‹2_d¨•‚€ú¾\åøæ pt Ì´Ãuª´£Êûí7+v©*2«’hŒã=îö’¿…G`ð�Š�;�æ¶kQ Á¯+±‡éS<ý[|ì7ü~·¬æ®•õ€Ãƒn�°„o(:àXóÐMÝø 5 ”óW†BžS6}MÑ[H_Š hÓQ`Yo±ñ .´íîÏ/±í ³�°±âTÑ™,û �ê„íf™ˆ"²ÑD„µ'÷Ô'ëea9¥è¨„´zïîÌ»ïÅpé~ë&ÚßJµÆÑå^õ¤[ÚÐyË×aß:“™Çác¸2m><‡Ûë7ÁëJ`|ãp*Ó»ÁJ¶´Q\1DŽªz¿ßŽp�‰_ X4)ø7K¶žBÊ?Šìޝcï)•û½~•!ôE;*[½\„R›³„Ÿ� �çÉåÍÜ)z,Õ#W±°`iÍ+8@ Áîj‘�¹×'œS¸öÞBz2ÚæGó)¶Ëôîœù¶°·9ì=óßí Xospa4& ?°Ë/ÁPÓÊð•¶Ýý~½Èüé®O¿ø°yÛ&ãj£í¦;il#·„2Ùé²¢w«"·�cá}¥Á-½bv¡b»õ<’>Õqi�à¿>4KC‚lvÌŽZ)ô5g“ºë ÇÛ¡3:Ò³–Μè3%aq€j– Â]t¹Â’L[öÚr¤˜öbNÂÝOw:3©´aè´Nåš®"ù•K' k™,C±éKÿR� j€þm× ÝEÖKÝ’ ¤6:Ý€Ï' ›÷åoë� *ÂsüÓ×¼…K"¼_ÒhÔE�I�§ã^mŽH4é#ØBÃçb†–i!}KµóÎ òc]Ñ xUëA^ œ¨nXŸ†(´�cŒÕûøÈ)}EÌÊ ìå­n»Øˆ�õ&Ç_Í>@•„Ou$øfä6j²&m�¡¦Öº�¤†¶â÷�Ç—7–-¡�5`',ÎÎöÏ&T$F¥†æU~n} 7—€~5òdžb6€ü�gø n5Æñ\—ý&í°Ìä÷’@,VïÌWI¤ûBêZ_N´gÇ^?'½6ÊÁ"˜ y¿ÅjÙÕO! b�t×µ"ÈÃU—ÄtÏž/£ð¥×›LO•$—þÁl•ø#]"+ÚSY^Ñ�E©¯Œ1K²}]¼c’º'Íá³­ �!T£QI47ÜÖ&j»‹²¼Vɸpó��ÝI.Ù´¿ß 4úúUÏ2\Æ¿×>:£ý†í�9ÐWqSu uÙ‘b¹Í¥Ú^‘{À4¦*2LOò-±’r wT{¸øù$öK3<7ˆ\üÅj¯Ý«u./÷ŠJî F�-!33mûñ5t–:Ûgy²Ô6Tƒó½™n «(ÕXˆ�FÊ<·¤±IÒefÙ¹/²³öqTo×d<:ÇHfÔ3¢(ðÑQ 3ùÁe`ƒ»™\g3Fœ Šyèm[Œ,Ø.XéNø‹ä�¯gáUØ…Q�ÜÇÂkaa‘έÏÎ�£È™¼ÌçùjrVê¯Ò2¨ªæ]ÈLFäu¸%­¤›Æ�ï8TM¯ôkáý€ìI�Æ®÷Äý�)à¿€ÿT�ækî»ÛÕß$Ÿ€-Ù[¨‚'Ò}%í£#›.ý “\¢ -ÂK#âhvqä™JXvttOdÎ;D“­´bl±<?ûË:—”È.au¢S�QÝ)ð.Ð;€P#¿®l/k$ù‹e~`t xëÆ>Ïï*eg‘^˜#Ðå_Iv¢ŸO]»Nªð‚©�,UXïOÜô—yŒ•®åwj\”L2[ÌØmd&±£j,¼bÒÈmíÖ⌼!4ǯڦÉ�W½Ch¨‰UxY0G.Ö¸K¥§ì*Qg‡!öÀ×E5Ÿ§þ®iIã)™øá�YDæä½ü8D2�/7Ñ Òá$t!Cd`är…¢ë±ÇÔu=ûkW{ �ö”í-þ¥ÔWÉ?lnö3ƒ©ó:ÌW�·MoÛûÇúScs·%æÚî’Ì…é׿ppfAùÔ8Í›Ow¹RúÞïƒQŠå²÷:ÌÄæDÅÈB3öïƒÓ~Ñ…‘;H8âÂÎç•V6µ, Vùè¶®R¾ž³†ãMºw]bÆò“òÇo"U>gå„‘c`o„ Ùq>ò‰Ê´—~‹Y2 Æ)7ú~vÞÙÂî• ËšÌ[Øf΋y�‡Uî¹9¬šmlH/Éz¥>Ÿ X]B­†MeC¸×ÝÕøWŒ+Ó¿f·}<˜S"x¼áÌm†¯¥E[WŒ@J�pö½óôŠ<s;ÔÙ7ÊÝY,ñ³R¯JU½[ –[Çë©ð„¦áGÎØ#kdkÂÉ%´W¾ì£Œ z6¶†€ÓšUF0×êZ�Í„%"+ù[G¬§t‡Ï“Âäg‰ "–äK-k*´¯G‚WŽYø•ë ³º} ? l¡Á¡G4ÛBÛ½ÚìÒ=±�{Z .¢þ!Ñjî¨ï“íÆÏmäG®Éá;>€ôÙÑcØÀ|T vJVo±©jmëjöèUÚê”Ì®?cf:=£"éÙ1œ5Û „0‰Tsü®„ $²ÅOv3�U.†Ü�w‹“ù ²~íÊs)#ß(¶’‰ë0›ú´Õ¹3�,½ô: “¯†í±#6{mÿÏú£êŽ'>##ÿöí �7�a>Á˜Þ¥ÞW¼�NO*ÓÇ 2Æ Ê 3¼§2âÅ~ìÛô””ߨ‚ÌúiP¡šxªY/²Þb‡"¯�üRŒ6—KÔ©qöž«3õx^ Ò¼v“9a"ÉrWÌ ¶ô½ Sº>¢¾Ž–o•¥+—­”QØäêöõâùú`4¥^`¤~íë¤?S.Ú¹¢@+Yz{ylßx‰;¼®ü0í÷ò'Š’éÃÙuv7K¿¸¼áƒ„ó›nL©žažõoƒ"k˜ÚDä] & kjõž!|1-‚¬éã)1,»õE¼ZLnpgœ™þÉ+×.�XG¸…U6Þbq\tv-W³9b”h+N7 ÿÆ' z†­�xø·âà…ât´kŸ‰äCtÓ:Êšb P‚ETÎb$Ÿhü›xΚAFïlq+yƒ Êæ~°ª(�¥a–Î2ø5+I]?5‰h‹Õöä³Óø–,½Þ÷4mŸ«yG˜ñ¥ô§—^¶A=îÁ�Ù1¹©„»j\ä™(ðÜ·÷�ÇQEmEäxcŸÜÉEÀnŽ{Ýì<ð÷/�Sƒuœ©_äøøC'f¿ˆRRÞZZRùŒ•ÝMKq¯Í›[¥³#¥–4·Ðµg®hý`ÿÈ ÌÃî´‹ã,ÏÐ`Ç•£ÖîÓ]=PŽÕYïÐ^ Ð,ƒu  �@($¥3'ûIXW‡WÝÎ`ݺN Ñ�é)ØE'yoÚ1—«úv¼oYùbÄHHxZ´åbDÑáxí^{(Î+£I… +õ/2u×ô;@m± âרca£�‘­<…±é6zê›Ñf¿ qÃ"&iž8|ñfk%ÌÁh½˜u˜€)àï”Ô � éèf³î­uç\eå…l±€–@š³j08H�…è,ž¯-u…H Žgm·¯A�Ÿ[Πֆ7§Æâÿ–?ûÕÓg`õñ …3J;*{ò½ù¥Ù#MîzÕ,Xθßu ÊŸ1ƒ0åa/}e¶vÈò!3¨;fƒÎ9ËT[G¸!·‘ví¸ÊÃ'Éåû UÊ�ÅúL©¡¬äÔ‰V¹âÑj¦¡RÀò«»Ä�sÉ -8ü sËnù>èñ§Ÿ¦­ºë©\“Éæ…¡ËÁ¢¼fÕŸƒt‹ò'1ë×¼Í25}X¿eÎÑ/Ó€�ÑfjŠ#”Œ�æ6=O0R¾Á±½Úh$9˜*Dš¬’ê�{zK"tañè÷e%=pÃ'–*¨Â=r8ÍÌmÛJIÔh·QA ao¨�ÇòW™•We�rýªp¦ÁÏœÜ�žåmÜK@^/]¥ÿïò¦Œ=,Ýùï"û+Ùi“± ¨MÊ)ï¼e'£Š[æ}‘ó?}&AŠH.Ç\ÈÓŸ¡Qlì{BÔ¿N/ô†eI~ñ^й¼ö± ä·fèþ*f®¹Þ°}ûl/Š4aÀ»ðg~¹¢’ /–rhÀXßeŽâvÈÂ÷.��vuƒ㔃z—é;'ÃcißQ¾Ì*ßíÌZ7ýÑ¿§� ñ¨p‡’K%>ÿ¡´¦†}Šr'E²¨M†øúvžäª\¿€ Û°%ŸI‹£©HŠy CüÜ<Œ:9ùäÔåæþt*›q'šR�™ ÃèS› 3-Š#,ó�f†öæi0h1ŸÙz·où2+ôž�»Ÿ†Ðú¥ªÄIR–@‡‡ŠÓ­¬môuA2gŒ Yp•1U—‡ ßà¨ÕöÄŒg °t±¤A–ILP¸7ÀJÜ bÃk+ĸ ¬€>×´¢Ô}.îz›åÓ•Tåµ6ÿ"eþVeÂæ;GUÇ™tþu¸²)ÈO™ÊI7Œ^žw9)³‘ŸT\_ô«ºµ8ÇŽß�ø âH …RB¾#ôdS¯æiF™Ž‚}Üu¼î¯ëœŒqÄϹ“RW�T§¬`Ïþ q#HòQ�„ž±–RùÍ®ëƒéÄl$¤Ñ¾&©+ƒøé,‚M¼±ü8`È?õ’ÄÐó7uÄ·,Íh.LF¯x2®l¯ÆE؃ƒ›aÊ×Ñ»:ÛåQÊX…ûWWÚCךt{)С~ ‡EùˆV!7œ¬9ÄÿQê[•hF¨__˜zˆhHÜÛæí)Â,sY{ËùT‚àµÅÝËÌWST¹)¾™ªtÓ ­ªYæ2%±¥‰'\Š-ÖeK¶cejq."9²ò¢û\Á|ý)ÇÓq@­²ªýÉc¾Î³äÎi1´ó³u�ÏM??'èw¤Æ§sï´07¾…2±.ŽF’»»y7øs �˜îÍ¡9Êf�™Ëë¼·æ¦n<œì¾jªÍ…ž/œFƒùduæ]”pdN^-™BVvïé`­óÚ\Ыly¦^Ûðlèçg ’¾º†ð�kš!ê95à†~¿Ö ËÝ'á‘Ó/™y’¬5Ï.7¾)]ʇttXÌYHº�Œë�Ž÷F.#$âSZ¬@±ì›ãÇxåäå®,DÊhj±ªHcÈÓ‚s÷—Õ?|&Ù(·�N|ŽBý„^ʇ‰Í[ ‡Zª&·ÏsˆÑfþ¥a|a¬² ¥äfØTtcYq´*.%ñãêc;Ԍʯu ÿ)sm·y.N¨:ã‹�ZÍ9^ w˜ÑÜ^Ô\RªY ]†”'‰^à—»±#/Œña4¤]·´þôÀÞšÇlàë¾=%,A¥x × g5ey¯\óÓyêÑä}¹±ƒ^¨‚Þ|÷îEãã„ ÿe‚‚žsÏPGFW.áá»N�Ù…C:<¹çùÛtË‘!Ô˜"�‚¾ùòwkÐUÌ‚uæµü¨Øv`Å—�’½¶fmV M“ûÇ û‹ýû#e7[Å0»—Ò«¨³É‚^l±�‚HÉ´VÚA‹˜çbÆg™ŽÓÞ/ybzì…ª²¦•;�8ž„å�’¤t¤Ÿc&ÚÁ¤e–ɫޕL?a…rÉ™J/áž?Yõ–Ëñ€®Ï^ªrx÷š½÷Ïì¾çœÁlvI�›XŠ·…±‡ød|Of^o3ŒºC1L´ñªçÇéÞd`Tª _x$ÁÆþìC ÷´V'"9ÎûždùRØ¥çÛ›à›–A™ü@’ø„8PJ~{g>Ä×U‘ìŸlã9:é`˜²µÂ˜ë,..3‡4âòýp _l�¯_‰ì%×ÛË04#ß·ÓóX´"aÍοAëbݺC]Çßâ(ÌHÝFÝ÷/ó M8÷�=Z$àR!«P%yÚÜé|Û‹zknÕ'u™M@q£d€-SæOd)$úM:ÆVASÅH¨}>ÞÉ«®]æÉ�2Ÿ`WG°Q­u~ûî4#ËÅ$�YjÈM�p½VÛ®ÝëDGÎ�1u5˜ÄöJÕ¤ƒ§MÜUÿªJÜüG˜›ð––6x0Èä9üƒ¥%±6!S¸±(‘Uj[œô 7¸Ö^ûÑZ’�ºž3þî+ëÓÆ Â‚-AúÓx½#aek0&ÈÕ?jòv “hœ~oÎQŒü™ãþÚ°)ò–ùÈXY5÷ìë¥rV\vÎ=n›f–M[,=žC:ãn$Z÷ûu%E4Hƒöh²h§êºÖË$(‘’ÁT�£#Ó½|pnHØ‘g^{Ê0³±ƒ%N“ïÂzÀW�– ³ÒY½^–¬šÔ}ƒǫ́pÎ^¬]ܽÂï~–k6g3Xžõ/>7�©W“—e™®•[NÆ(ÙŒgjÔ�'ˆ?4TA…ÚWÒjG‹ÕKÎ+}mÊÙ ” i”쎃{¥振n’vS7íê™�’ä9Y­Ëšœ]‹D^¯×‡é‚Ñ3ÀšÚ0ñuô‰ÔבÔ¼ikâ‚7ÌNꥲ?hü)PÂááNxÃÆUÌWß•JüüPôÔ„¨‡\ÅW¼p˜<*¹["ß]ìA¼Ë¼Ÿ) p kÅx $Ö(m1¥8¢`1%iy½“�[uÅyyÙ_;SS{áHU"LIR㊌G¨U0¯ Z(�$l ùN|Üú€èŸ#Ï5f–hc:hÉô6Y{ý(¥Ù˜tà9èK7AM½“XçŒ%•«:iÇW7i4ã R´F€fˆè)Žéx)²¸ðe#‘³Ø:„åëÞ›„-¥,$Ǫ¦yYÐý1þuîßC�¢y­ôJbžÚm$'óå[š�»¨¥œ¥LrqÓ¼µ+(¤PjÃÉ�Ÿ>À p?cþÛw§Äçªl´Ñ!<áQìö ÞŒGI.µÐÐfv­2Â" eZ¸§ÖÝD¦hÌ®ÙÛBÂi,´�bÓM±>’Ù>*þ~Ä%ƒs§TªËÝÉÕKŸŒ>“àÓº/�*=¹”ì¸tb€ë…¿u‘P€“ËÆ‚zôO ©Ã…ïewü· †dßüôSÑÜ~¯0óW€¹Pƒ“ì’ì·È¤ye%¨7¥ËfáZ’0”w9—Cú!çaó„ÓKFuiü7âE[xùŸnÁ¬�»Ë2Ô‘ªž\‡;u7P§bîö­ÜáÝ‘×Ýf gÀÚ5ÑõÝZK÷SÈ¢€@Ùç;J TO´D˜ûlËm7p*› ÙÖ£›ñ1ÂðQt¥>èí'ÃPúò¤y«ªhKð20l† L]b|°Ñ/ØE†Õö¥’rjN€võ¤r¨ð%Ûõ׃S˜oÆI'õ!Ô6+úú¼ âbÏ;$–b"´6·m�r‚Cl<é ‡•½›’!â…&Rhäm@0Ö1aHÊo¥x› ³¥Tl| 7b–:_œò–Ým_l~Ñ+O±;ÁTöÅðJñ/ù’{4òü›„×U x| Û¦­ÆŒ ¯ãßtí“.‚Ò¶õ731UŸd’ÄêQmÍÑûÏ> >§~~Ïû6OÜ0N?Çú´oŸŸ«Iß´µœ®F×ýHQTèþ�ý\¢ix| *¯}l5²ËVÀß`×nÅQ¾òÛO�ðÌ\/ŠgOÍÍ:pЛ[�3+!E«n—U°>9晆¹µÁ¿ë’`núÅÀžä:ífßc2cc~ªXÏûq„ø£kO:üÇu•ÆŸé�Z(gØs¨Òß|Ôìñµ+Iˆ^ãI"£ %2‡r'šÎ;�" Wì"ã #:Õ-¥¡]÷ކv³póоµ!êtªÍn�T?Ô¥9-WÂ,GIø_èßÑä|#·½Òº¡¼‘ƒ«¼&æÙû-4_4êM{˜ÉÇ)¬AF]Fœr¸oǤð´Ã»æ©üAƒ�,ÿÂ�!^Š’™$çÉfÓ6B¨;…õ'”ÈÌ-+ž"ÞnýjÞ’–pÌãåÜ�x¿0•íTãQ÷q(ØÛx�i(™øNZñжÄ|'fJøZö�vÆ«éýÌ„¨?]{ϸ"¶|³£LQØf1ðä¬I i–ˆ–&<ºò`¡á×j*³88}×zcEdŠæ 0²IëŸ&ÐúaͪôÙ(¸ž·Ê_úv ˜1$êKЇïX¼zP:Qíh‹£q”}ðý<ÉÂÌèvØrªÛÖ Zþ)¨Ý«Ü:W`Ñ:A åiø1¨|É3VÚ�ã­š*Y:�v0âðfã6ÕÏðý§™2Q‰+±ŒG ÝTT›ö^_ܧ©¥O¡›pá{ò‚¢¶yŽõàKèœ�4¹Ú¹íúÛóË Kã°Ýâ­g¤ù¸ŽÆZÎÖBغ“XN‰dçÛ›Kj—ž;’x+à ·žâ~£7³SÍ"6ƒñ#ãÓ/—Ò/ËÞÆvó=&˜½ë•~be?&2”ȺLŸ¯Þþ2\“<.tx ­hâá…ãƒþ°–— ðÐQ0U1mÅœyÝ„øDè.ÿêƒ5f–:õ¿° +P nüá'°ÔPañ±ãwKM‹�6á�@õZ®£Ù B醪y¦«s¹…ÈYVæêŽ&"OpmeW.±š£}†è¥zp ,ý.‹k&(+ŸNó¸�p6’(â·ca•ãtI ÓczÌ¡ê¢Ê-ï5:bf§Ó›w¼JLº„æh³òžò˹+·�ÍÍ̶Á~4Ko[³vëïË|�Õ ÝF.JØÞM‘²‹M® ¡<þÊ*ø‚ŸÞâŽp�£æTò�ë2Á²ë÷<ÂxrŠ‹žÃ¦M…3ßÇ1ò*•ßÜSËaró3‹öf”tï^DD²ð†þ˜OM™c¦²€Ön05²f’Ÿ|p`¡6ùÆÂï%g”í™–I©vä`»µtèYû æ­J )VRfjز0—›@9ªáq 0±gÑ>~¥ÍgžòQ5“DžýàBÈj ‘ÑϽu)hv Œo6Zœ�¸ãÙ°síº^SnnÚã®H¿XÞ�×U<ư˜eí–_ù{¹«¸§ôD<ÍŽ}·þH%¢’‰‰�bhAXK+f};öÛ�Ýí™âSËí%Ö»ßk «c·jöšp¦�(ôkòÕiÓß·Ð}{Å~†8äé1~úò3I;w3µB™(­X©…ÊDĽ¡›ÍV8û£›ÛM±‰ñø4ñ>Õ$&°h’RœJÁ2B$¥&f‡&ãÛkbgÒ–òpF]ïÃ&6Û½wëN»xؼ^+\ûý3V$ÌÝ¥ä]G&Ò-[ZØ“C.R*¦mÌ‚Œ,­êDqrn`*ãÃ�ˆÄ¼Å1æUY:cý+S„n7ož™a©|äãúBäþÛMЏw¥#®ëno\¡RWð]Ä©Ùc7Ú´‰ä¦Š…?&êPÈÔ;“Qh\Z�Ï#3{”„S˜GÂâÁ)ÒÌÔùí;źIùÖ§&3ûOAŠù"ßÛZN½€óZßàEr! éÅQª8wG;k�øÜD@®ºA†ï("#˜îJš0Û¿?Rì;k�•IdV–?y9¬XLhÙ9{ÝEnȨn3¢ÿöÛ¥‹4m‡õU1–°™N‰èwö*³î%9Ǧ@OæU˜/±>i°óõ…;Ë‚°¦1ˆž'V÷ò{U�¾Ã”óERÓVó´IÊÅÜ?°Å—ó´tû‰»~ýâ©’è84x×�tÇ¡4;«¤eÚ8Ë=©¨Ä”|¸¾¾Ù;Rô"Ú,cˆŸ­©\,»ŽQg8°[�ŒDæìÇ+r*¦Á—Oô›U§ ¢/Göú¦âöâB«ùc¯¼²‹ðÏ/TÎo W°¡?¶�SKz›õrBxsjÅD�úàÓMªãÒžïГ"ÜØrgR>ÇTV¥7üÈN2‚5-Ô°¿Oµ´¤ Ç¥½ß‘K´ÐÉ0fëÙg0æ� óiÖÄùêh´jìÒªoÍÏ¡ÊVUžÿL´Öd‡-bÂ1Ô €ö9Þ|"|'“ª)$nÞd3®]šfç„Mñ´ ’0µÛ˜$¹ >uÎÍ�­%!î`)4àåôƒµŸ°¥뱎ßÔ3>le.ìY zî§ŽŸw”“{e†º —Ê%4g]3$ /W ÙÂpAúRÛáy T9Ôl\mÊ=cçed`5ÁQ~Ûþ臾/ë º×d”t¥ïTM 'eFÊÃSá½BxÝ11L¶I]Çâ<³Š#/4ÕlNs’öåì#ÔlNŒïRbh�£Á o„•úQ—Gè!HžU¼äÍe˜”¨yEt��`E°îO$p�O¬“•Q òÕÍv`æe °Ï¬ÿ�߯ç3cwrg ©lÉnÂ]æñh?&lBk¤�ø[~o È•Ößo‘îïõð8šW„�K‰¬ãeýšþ«¤c˜¡ñú»Få¾}ëk‘ø˜~”+šLe¶TgFR¶!ºFZóÜÀ„Õ÷j¶oN ®aÌwy?;£h'üõÞðrCc’½‘-F‚_hn²õãÑy—8æ%÷º•2⩲=7LgïnÍR{DT_ÊìF;Ýs9¯MîIÄÏ õN: bsbü¢ºáÆ¢” Îl¿Ñ‹:€Á8V0[žù¨‰0÷V¥°cì+&ºË›–b¿ä!¡í°Ú Ø‘•®7q•LÇp“Zþ\Ù«>c 4ùƒÉ¿�:Ö@MÆÕ3‚×åðïçÊènùY±žs¾Ã™µ=ú•®ÔJà⊼Òç�GÄD.C–òsè¢ï§ÃØ”ãRB¬•R®" „…Í;Y”F‡ ˆ¨½ K_ÁÂæJß~ÛI~ã,ìV Íôb£–¼øËY5kŸøç÷Í}};¬‘_¦—¿_0Íi7t›û˜²ä õu�'A1whC;±¯Ö¥aÉ`… ÚEF>²ÝŸh»Eùˆ"}ª•{gžÜLpG[ýx˜±:K%üà›Óq.šT¤´ýÓâ�”˽~œH%õ’úIÜhíLvxŸ.ßü Pïo>wß�´ŽB<�ïF Pªù#FEòþô é9 ;Óâäš6b4ÍŸÈ!3dšpLcât¢ É(‰ãSÛ#èl'9oÄ,¨Ë–�8H9!NC!>$û@¤{h³Á½OpéHòàÆ;nf-±ôÝPícŽ“ò¨6 �@ØQÈ‚vÉ@,¯ºØ~ÅZî¾b— ÝþŸ¡ÉbxþȸÞ!í,Ö$úºÈ,gF‰”j‡2slFðšúJ”²¬~?økNª¥6rá³²{ÓúõT!8C®"4—Ñþ@?)âùÖ|ÅOœ‚ÕƒkxK¶*¡²t†Öæz÷git…:6áG€êb�&X¤0ñ'>KO÷yMÎ|·õƒ¼^#æârŒú’¥ˆÕûÚâÔz˰=°GËs¤©çÞ3uU%Fó�%ÛkóïÛQ$^X,„°BYºgN›N�˧t~Q¼UÁšzÃ\TÙa"jæßAèEù½ý>TäЉ,ÊU¢0ýíËz¢ó ª; éL»…%nضk 3 Á—dIIhžÇ·=u×0.ç�ñ~¯÷FáuP� ÐOØ1Îã^ËÞFœhQÁÊ:¦Ž•^)ºƒ¯ž§U ÌR×T±è(†é;~¤Ñód^ ¬bò2A‰…ž9㎅xʤ¾ªn\Zðô4·…t$Ûà4ËÁM׳FU÷h.üôˆ‡~¬^¬XqMîiã�ðǥù²Ó<èÆø‡sa�uyfå…ü'²¤’Þw˜"ucX0ýfn«Ñ»½ûnãßnðÀϱPü„¦æ–®´Ó`MÙ?«"Œˆí:ªcÛ©�%d…ÅsÕ÷Qèj颶02 Ä ß.ôÑ=Ðm3†O¦éÄèÿÜЀÄÐŽG`ÜMH}/8æJIèeŽ�Õ,ÇL-Ò¬©Õô€a}£ÊCaöˆ±ÙMg¬³<~3ýŽ ª�$ÃiË!yëlã¨vÉûÐB{÷V°a0�!œÍ˜~%ÆaóÜâÊo¥Ñù™9õ,é–&§óQ¾ÿÄ}¤_G˜)e%P{T€“@T3�3ÞÝÂOErH5†›:gÀ›ŠrcÕ룊‚ÙMÉàüs’�rC˜rÔ…ÍÛ6ü÷exƒÇ|%0Çä*ðÌž¢æ�*üaª�) ´‰œÓ~®ËïDJTrAxãO\Tƒ"=Ÿ˜ßÝÖPÛ¨5½¢Ôˆæžq¯Âº,Ö1ˆ&¹nOp›™6ëyCÝòÕþ {¨æl嬠<îË7¬~IÚÁ­]]ª›Ïàd 5ˆL<—c§fÑ;ëá­œjBÜM»œ8‰Õé’÷-š<¡ ìÀl)ìdšÒð‘*õÈ•;mk"Mûµˆd ç/TLA$IwGWûŸhRç�‚�·“hxØä(‘KÎ.F²1{Íf·ôsªGy–Æí˜Œ>nšÊ­©É¥_€ –©™”çɇÌ;=\{ãrlÉMÏ5®Gù�|$¢ÒkišüÖ«©ºL�AÉFŽ<&Ñ1ž)jþ¦ºø%#õ:Wa>Á†·YÔnßS\·t�Na½fJþ�×ûA‹ �,½]ñ‹:°¹?‡6 h¤ìKÆÒpÄêÆdÝJô¤)^‚(ó·T�UFÀ.s†¹7äI‡ú‘ð œ&oéÂŒgm™µòË4LhX‚F:Éaͦ.¡8®«²/nÐGRH�|.²‚P%Ï}âÇ@ûåÙ½§Öö ¿-žÞ¥dÆ&óš\Õ U1£¦|áÙ�~•8+e‰Æ—K ±ä?yË¿SÐ�ëFÆÿã™p åÊ— V¡Äª’íyR5iË8J%ÊF[|ͺklêúÚÓýå$‡è¼Í*+g$l j'ÈÈ×l¾¤çwÀÀι ¸‹óK?pA ¥‘°Dì9cº­Êç7QR�ùÇR?žõ¬4u6ÅAVÖ±õ|Žü]´I©<¤«]�`äø-®PA”dAv®ŸÉü¯mj4� è9 7§åvŸ“’‚•Íip�z‘ÑCû/DïœkžEÏ`}\2øT®Ù1ãås¿\»bBç�ëd|˜kîÏ]’·ŽÂªo2œ½›îea×ØÏ»X,¯|$£Ï‘5H!©ï«#šî¾�%l$XTC¸pQÌ.¤û>'͈§NZeΚ€TT~k8Lâ–—†Þ õ愺’V’¢¬¨_cš<ÝRk„eg†-!eé)%^K};tô²DáìÁÇÖÔ$µ”âk~rÍåÃi¸0›cB*‚à åûéëe=yêÞ‰c+ƒAsÈ™þö9‹ZìqÑi¥l»#ÈlÜM®¨HÞ¸°Ý_ÐöÔ ëæ(Gñ·97ÚxP®K½•Œ}™q±ü *‰WQz¾1 ­ŸBK„L$G”W±[¦Jm¯ /²ÉÕ§ßez™F`K™2œ±#$+X%¢­I³ŠÝÜN—ŸûÜöH›¼²L‹Þ³…è9&àÒùh‘ùÝ(jx7uÚ*aÊ(Ô\vˆ¸�s¸jY{ó]ïÀZ• .=ôe£ `.Z›Uýê/À{ב‹©µ§6(¿-<ÈFx·!ËçØ®NŽîèéáö¡,ò¿fb$âKOxy±ºBü¼÷(Éú3ÈB2ÙŽr×£r—‘! :V;ŠÑž¨ n4â‰1ÊÅW¹åÝ‹&ùÁm¹�æñ�ðü[«7µåI©{,‰ O ˉ[ö%±zˆÎ¥Ã\â� KðQ½2çÁ‰ö¢bÖ0ö~çC¾1 çbò–ÁÂvÀI"w^&IŠñýîꃊåXà ?”F(gµ„½++|>G¶E2r“ìñpÅäšó`§ˆAR欞�°KxAÆrºÚAHŸôå×øÔ®½Š9Ù® |#ŸJëÉt‡Yœ z&C¦û(?-Œ¥R~Ñ@cßS±ãkŽ©3>ëÄwUù¥Èenõ¢($$šC7Éòdß³¬øø0‰ˆ>/b]I —ìezS±³¸ƒ[käø‰Ãæ0v«oU8òÔ� ½ž@í¨1a™‘Ú™ª\yüa#ªÇ\ÉLKWRñƒoÚÓ—…Óš(ÛÀ³{`%Ù÷»‹ã‹Åd��Á �³&YÔ©²\�GHy*xGïœ~ +ØâR3Qï›úêšh½í_ióöƒNº5<˜Ê2ótˆþG¡^ú-9äD˜g=ò¨d�³³l­íjØô õà„ÿ¸þ—�²zÝX“GNÔº'#¡—´Y�/xH¿ïDBô;ûA± µLà�èßéµÝ« yµÃtþíŠÆ‡¬ôЊ46^ñ m/r½�´*G\ n·Ñå×G‚½U|)òjú@Mì3†² vbg}|«0è–föÔŠnÎi¯"Ðfëd›èý¹ŽûÁ¢e†&�°çýM—”%Cýé $ÉUfFõEÏôé'jÕÎЊ7'ÿÏŠÓà˜âŸÛˆ;c>©_pDØ$±k 0ôå+Œ‚(¬×¹ÖŒE 6ÆJ}AW×°;ý’5Ukr…‚cç³¥0Wíb{W]¬z$.�ÌTs¿ܸ)ÕóèÖH¹ÔÓ�µ=�¨E�E¯ýc/ iM[»}àœ‘á¾’otÞzG�L]ûkU¯ækWÌžÚSW),@L!_DìÈ“3²½“äIJl’Ç|¼nýpà!Ì~W”¬á­ao…î6�=&üÂÞöoX’M`Û8å]éùn-È?Xyñ O‘Ê70(¥—$ 1�6ÚäÀW@XݦýÎm·`m¨µc˜Aƒ1"�øÎð5Íiu“Ô/éªD²Œá ËúÛi-ö�©�ƒÇ«ŸÜl6v­±ûPæP;~ά�ÏEÇ Œ¢óÅ“Kv¸É½­ß?1"±¥Žþ�\]‡ËÕa.dt~ª e]ÇV Ge*D=œ�Ô—¿Û‡,‘Ù�Üj]=‡ÉëH˜ŸÌ£­ag�IÆ­ÆØN„ªÈ‹Ëø0‡#.èNóP˜ŸÉ´ÉŒK¯ Ö½1nò–åÍ;,ê8*¥O½¯Þ¯ÙµüDïRwpc¤Ž¹#þ†[¶£ãÀ’pÕÝ]…Ìê¡XŽºíOÕr¾qtq^‰a­ù#èB‡ÍSÙÔ‹‰ƒ�ÿu¢¾‡Ñ’¹%ÔÁ›�hàøË¡9ÛjlUB©¢†(Û\RqtŒõªtíY»'E´Êáaøf‹Ž±•cš‰Äº¾N5åÈœD8N‰¦£G;›0£ëÆ€KyÈWÉoG¼Fv¶öñ”i7¥,|2³@ÏK”‚·('ùQ:k2¯oJ,%1, çøþOÐ ¡úlÕ‹:…„ânSí#ülW9•Ñ›·ÿ�Tž‰»µ —ާÉoÑÓëN .Û%•m“÷¥ ¦¸+¾R)~ôl^@'5ŽX"Ù¾Â•Š§¥#þ‡C oÈHlôÏÖ.'^Öd <.‹4…|È(`jí©~§I›ñ!cõöA¡/ SôèÊTË ¼P1'Óà ÄüË,Iè±,Ø}ªTºß«“œÚs¤!qr¾ µCcCH•u [¾ ™ðêÊ¥..6W9Ð5­.ŒœLÈC¸7·e¹ÉØ’¾�Ž�s[u Ï ~ÕT‡ðU¥�-÷ D-ÚWõ çá»à¸»Ù„:Û‘Ý€ê‘y¶£-!)_® $ê$N¡‘á«Ù‹Ž¼ÑkV`²âg”Ø(µî÷‰^ïª�Ò¼Ž°­�Ñ7¾ µþÎ-|]-üN^ð¢æºQÚóÖ™,uÅ^�ß‘ßä›7M9þœTÓû8‹ÅzÚ²/Ç`�ŒßQbj÷ø—w‡@¢ x¦V¯˜ìH"|‰‰�c‚:ì^ˆGwF­ïz?ÜÔïØ–a¢šŽO¥nr”cçÌhâHöÄÕí§UaÚ°ùà¨{ÿ�`· ‡›qoi®ÃúZŒœ‚-Žˆî?Y óÄBvq€G{ ²6ã"Û³wÎîÂÉ”{¼6• P¯¹+uzT:á)¤oˆbI'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 H‰d“iTYÇ«µà…XŽ]¥U±]Ðv_hAÛpAt$â‚Ø h {€PÑ€¨ " qA�ìÒ¶‚Š{‹Ú.�£¶Ž¶Ž­ã­ÌãÄsz¦?Ìyç¼óî{÷þî½ÿ÷ŽÙÛa8Žð Ó(£')´š ˆ>{„Èá&aýdõ F`Þ‡%aÉ ˆr¬>ÌË©ÏAï®Õ%D……ªbäãÖ(Ö�Ÿ0aâŸ;ÓÜÜÜäÁ ÿ=‘{(£ÃB#äcm‹8¥Z«Ó(#bæÈÝmÞjuØfy¨:A§Š–mÙ¢ÜÒ¶6H­ —/S‡étÚ8ù8÷ñòéS§N›d›\0 · ÌÇàØ stÀ¾Æ°Ñ$6‘ÀfH0W;l‰ya˜w?l†Í¶5‡Ùaæ�åauØ¿ðÁx^kç`g²k•¸IÊ%wìWØ× ‘Aô’)äKJG=¡‡Ð‡éß|Zú}ÛïxÿIýÛ8Hh70_JJ�Hÿ=hÕ öÁ΃·9*O;ÍsÒËÙ.Ù½!+†´0_1•CÕý,í�&EO­£Kð¦ 4Y]™…þšÈ�ïi�™*gäÀ"Yõø¿�á-þå±?„ç6çºöŒî}{k×ösÁ“ŠvÞÜ~¢ª£�þþ=’äÉt6�(¯n ï=?óXònÆG>¸)òȺS)IÃ~ö®P™ÐG—˜ïÌŽJvÕ­äµÞšPwZ:ÎToá�uKYp–AÚe Eº[ í-¤Ý2ÒVôö’¤ON0õ¬lÓS4’¹]Yí*{Au6@ÆËJÃËôU9¹™™9¼lSV®É”ÉåålO ׆¬ lÑ[mu:~`4Q‘êˆcQÇO–;~2²\#H�åV§rüè[(x+�\›¾A‰ªÁgµQ}jà•È¡q5XÝÝÆµÔ�©Ú.Õ Yš #Ñ_øŒHæY="�)å..�_` ¨êAÒ#HM…âŃ÷l¹ÃlZ×ÙèhéTÂHåï=���Eç.ÊÞÏ•î3„ ½~ÔßÒb’RyCª1#h7m€ã…Ôw™Iû›Xñ%5u‰e�8¼ê‘ˆZÁ$ï%!É©J#á;ð ^¼>Ûõ�ý0»{”ïºØÍ!|x˜!<Ñ£tǰßÎU�ºË=kUÌšûýäYÓ´ù)"KI�Uâ««NÐñHÙ!» “à)s¥lWêQ¡=ö¬b1;KáµPŸ{4„?¬IÌMäb Æ8UmìOÝ�Ê-�B£¥¼í6Û’Ôq’�?¢Ï,¦e¿Üm’hé ¥“�o ©±Zl}„ƒõ' ,f`=y(;+w�Pó"5—ˆ3lÛÇ!%‰p´�ؽ˴{»#;#ïÔ¹ôd TÈÅãØ +Ì�OÌ=¢áËÂcöÇqÆ”(ecôƒg-„†úÒÖ.¶Cßàw�¬S”¡~¥´ÔhíðÓ¯!û¥DTX0ˆÜæ£_´žFؼUˆD,;³bF­Xóct;ƒ{þ< YôQ�qéJo¡&€=`0­œFÁè,ÓsÁ9"»-+=g¬ySZòÌ%…¡ғûÎpÒ´ñ~'.®±~Ãô’ä*ä\”FÜ©=\p‰ ‰6ô¾&n’ ²~m“Âl•š�.wyv‚ö®o—¬jEŠyñÌù;ì÷«ÎŸ½tªWqÄç)¼ìÂÜbÕKØo-tßú�—uw‡5£�/ù„ÑÌýuGCW³^^ó×·=¿qä|[#ßÜÍLo m¸Ì¶Õ[®ß© \¬Ð(”üŽ “ig-…mµ¢½?ñ«äJ,ö—Šï4ÓŸº®Á`àXp›ˆAý§�E’vÌìÒùC–‹|0š…$r41’†+`eâw¦nM壵!É¡Ü|ÿпõÐÕÒr¡¤èØ�ãÜózô� ½b{+ë-âÈܺ¶˜ سm¿ªe‰7‡Å“hKoÊr46%É×WzØPLùǘó÷Ü[ 4€…¤e‘¯Ë�4²Q‰ikwózÈ£z“a?˜�FfBšm¬?‡Û,‰×2©GÄ‘qÛ“Râ¹TÞƒphƒ_ÞFÎÍUí»Bð\¡œŒìØÉ'\Z¼×Õ_•ï9 Þ7<¾&$&<.Ó¸rÞ«Kj6 ¾Íê— aaÙkp€1­?Äm>ÇŸ /Ô{Ñ¶ŽŠõÕâ/Õúb§OEpYæ'À÷”äù;x™ZÕП+/· 7¯T¿xǾÔ<ô½Äß]‚ð*4‚Ce¤l¸žz”¾/u!+S¬dNȳôÜL kâ®±¸ ŒEý‚gÍÞÈG¬÷I™ÉmNÙwJ�®ëË µØWcKûþ£,F|s-‰0¿MÑh§#7íÍMvìÙu ˆL¦ž&»e`ˆ!Óƒw¶éÄdmÚFM†(Òœ“SÁGqÄ0­H8FfÀ(¢×LÊ2õTçö£'Û»Šò4ÙZòЋՔTn*†k £mÞ§æ¤$æphLuouøÿS»ÿGõ¤\·ö ¥‡Êbj^¶ñ` 0†z\d˜�o{.Æsâ—sø) Eù;‰Õ¾0(/�¬ÍÈÏÈO£ Ssb6±è[*|¥ÎÍrV¾1¿ªkæ›ëÚ+îp—›ÿCv•Eq¦áŒ0óM­²qv6Ømuc-n\âbÄòf5I-HP‘嚆™a8d8†k.Žîs@„¢D��¨e¶¶’5qk÷mö#[û5úc«üÛÕo?ïó}Ïû¼O+âO±�Éu)-R»Dñât‰¢@©Ê µÙåUJ¶ö@T5ñÞHüöÀÑhÛ>È~ðõßã` ý^ïëdá š2[&+ážá¬ú9Ñ¿ç`bÎâË!]7™nW1îR Ûù&ÍŸN´ê-§.m¯Ìµ\£ &pÈËÏùÀ—ëq0" ¹„›wåD€"rÚž«Þp’TžãÐÆòlë ¡ò†ÕòÀ@*Ï)ÐÃB³f%ô¸Xõ›9þ½ù7äz³±Ä@w›u™TzÚ± PïÂëŃn˜L÷*Im¿Í˜sw¾¸‰ÍBw}ÚR¡6ß àcÔÚø¯Uâ[ÛÇw¦R*U~²ž)Ô”èÕ¬&9Rª2z=Á*(w‡½xe¦®úJÅr×¢E�žâŸ.J#…ÿ|åYqª´œ,é§ AJú#‰oneËC׬Ö;¤�¾ÿÓ™¬â…Ò|ú |Ån�ñ‚™ÈÉ7̹̿Ï#'›ÖGý¼c¢ß •uñ<¯Y,ß Ì">¾P†³ù21WHîZÔ¾ÔÂÛhµJáS@jÔ‚Þ²ìO)Þ�aaTl•¸MilyÎ2çONÙž×Èy;ºdìç,ŒÕh5 ¤V+ÐÀIkQmžÔ¦ª‰ßMá¿¢9¯ãm ɰU9È.ìF²Ð—‘V ™… XDØþ¿Q/öV�¸À/B¤Ø‡WàÕ8ʳÛk|ë?ùý§�iƒ°¢þ‘ô0è{Õƒã:ÞudDyÔÁއwyâ¥T`î™!LÞ‰¬iiÒ„„Ê`:ê@CW2rä)q­¹ö'C£Ìð©³Mèűm„s‚]ý<ÙÄ®á8åÅ­õúVzvÜØ<Ì^êvLE ©R:ç'Þíž4®—ÈêÉéŒÚç×i·å??øÍå9D޲D>õ­ªª èË‘«ß Ã(SUZ–ƸJ8þ™77¹îö¼'�+Ï4&õâX¨tÿÚÒiîi“v·rC£ÔpnÿñætœO+Áì�ÈÎ(ÐM�Qó\žZõvá8;ÉqVäZˆQ„¡‰2ÈÃÓbX/‘….Dð�äí¦êAx}2Ú3,#&^ÁDO(x§Xê¶RåH·ñøôaÛ²k�@õT¶‚ßGN˜•t„MHTÆ„P›œûÀ5�¹7Û'­É­ÈH¥> ‹ò]çܘ4I'N7Idþ\©ÙZK›ê‹ò9ò¡œ�AÝ èû;ÏîÍ`÷kìªÉç8uahàò™!E|ÓuÔz¼.PÚ"f…ÿiHUsBn}E¾p½¯Ñøº>C¦Ý ²�i¯G iRâ%v¶YR[Å Ó’¼UÜLN³�WšHÊÉÏs¢ÎÁ/Nx³|Î\wßHF!Gòºt ÛчùqÙǘˆ¿ÄíôÎðæÑVÙ�ßÿ7'º+8‘ƒì£“Æ—Â3︷¶‚èfß•SLóPÍÈmÊ z5¶ùWm¢ÿø�X#ÌÖùÂM •Qp\›Ì�(ô7ì?Wä5éË—ç5p&ªÙn/%_¶)ÐE½1¯wSÏF÷•¸¯æ-Îo(ª7QMÖªóåä�b:_X«ì÷„ý ½îµXËoï…MâZÉC°ÛA£Ü˜©æs£°ymóKH�ðÚÈSHÆ‹ëòÓ¨�2)ž!)ž‰™vÏù-ò²˜œ]dîò$�8•VJªèÁš¼v¡%>5UóÃé’ô-h¼›J— *a>ÿ Ð3þ€žÖ±pW×p7ùÌ�ʽŠTË Ý?0`p8ËT�&½žÐEÍÒS�u©Îõ÷”ïÜ›^X£.Ì&²ˆ�“ üÂG°z_Oh”Hæò© å <~rð\Ì3B¾{‘OÍÒ¹4Ÿ_%2Î 6K!û�Ûs_:VÈæL­U¯6#칪̥‰@la•†ßâ×Óù¥Ùiƒz”k‹655�mMGNúˆ’ná"U�óù$|â;Ù½ïž/Èÿ+…S8z¶c@Ћù¢1oˆœ •4b@¥…;T¤Åƒ7†maÑ� � P‡wõõi4ã}éÌÄx&Ý7ÑIKEà ¾ä«BiàûRÜ yÃd.l:AoéÀ1·»Ò,˜x ÷bïø˜xž€ ŽŽø]>·Ïíw—-~‡“°ZfªŸ��¼Déï8wú2ú5¬ß‘Iݾ±±” –ñq_‚ òè+™÷D\,a³²¬™B;‘*€Ë×bî´UËÕ6ì‡YKþU(Å ‘x#Qo�̆ٓôV7¨cM §ØÇÅ�9|…ˆ—�Z,‡ åRÄav®•Ü/@Eñ+='ü÷Ç‚Þ92ž ÑˆÀÔxD€Ôû˜È<óÀ ÔÄÔb"O^o{�FjPÃqÕEûxPíe‹3¹±%r}¬«‚F­ Úf«²‹'4<èöajŸiL{ÀmͽRÕÐ]UG­´§êH¥†UTÐw€Ý×ÐßÎÕ2åEƉ+%_àÁBéh±Ã‘°Øa:Ä4ÒÈ ª9¶¡X¹� CLtŽ€çÁ{Ëãѹ2Ùñ�Z€Âd8^<Ñ̃F1 ¯p3yQGkÖŒ·nß߸-êš:a€jQ8¥Éî ö¾ÜvâÞPà�!ò|À">O8ÆqG”|—:�ü­1°ßkŠˆþý ÊOZH¸íøüüñëÿØ]£ì©SÒw�ÃW§k3ÕÊáîýøÌÕ¹¥ÏW^Ee¨´qåÉê¹™bé8›€Õ ²´lò>4ä Ü^ÆSMêP3‰~²=&&SÙ�}®]™^¾D££ f€9(fôäâ 6j .ÂC¼†þŽ÷ºLÕ¯U™;ÈŽ®pROŸÍè>½AÀm|¾¹1«ú=õYz9Yò7q%÷ÇCÞ(9õÃfùÁq»ýÍâJØypØoà× ¨ÙÅÕÔHÈi‰PìhÄ#'ùD:§K¶Ÿîì;ØH# s½¶Õt´_´Ä”eÜœžIšÆe—7à‹·äOÿÀ›¸ þ ã$ƒƒ˜Ýêñ¸H‡Å7ÌÑòDP«ê&_ªn¨¬É¾³y‚¾¦ÂòúDo¡<«ihïˆ�÷Sº)ë„i½ÌˆöÆ$áÀ�/JÊ¡ø cB¼îH§\cäÝO®ÝZíÍ™£Ñ�>Á4£ÌTЏ8›^ZŸiß7QTËš°=+‹A'úCA¾ ƒ¢ Ë?Û%êpØãwPv«Ãj·´Ôž:at•É79»Ãî$ÜÞAÿ %ÿìô¡ä…™S×W.L®å(SëÑ,Zò “ú3 ç�|óß©åZuRøm‚�Ënà¡‚°è£xô6 ¦] .h€äÙá·ñj,}|´•!˜>…AMu³Ú~–tX}Ã:Ðo2�}z}¯*Û³psù*ü凴˜ŸŽe#áI¹TŸê“°6)™Ù¶ùøLpûöͱíOî'¿ßƒÿO€ ú°® endstream endobj 219 0 obj <>stream H‰d”yPI‡«hêÀ£ÚÚq«´ªt¼@eñ<]A<¥mŽmšnîºAE9U…�áD.GDE]/Dð\utuu _õ&±»MÄîΑ‘/óå÷ÞïÅËÄ1K Çñ>ajeôLo�:0bÈ/rxŠ0•˜Üˆñ˜çQÉHX1 4ÖÕã¾)°rйj´ Qa!¡1ò©¼7M›>}Æo;öÎÎÎò „ÿžÈÝ”Ña!ò)æEœ2\£U+#b\ä®fïðð°íò�ðmh´ÇÎÎ~¦yrÀ0Ü<0+‰aÖVØ·6‰ÄfØ\ æ„cËHÌÃ<‡a[0ÌѬ ³ÀÌ+Àîâ³ñxüº…§Å.‹H‚%¹–RËxËÄ*⹄¬¦ì©2ª—ö§k¬«+6ìÃð}Ãï�pÑ9róÈÏROiå(nT¨žÑ'FÿË:×úºM¤ÍcÙ$Yù˜ÑcTcþÉ(˜ë¿[.´—¢g¦IåxÛ€ÚLNÌR?udð6Úm^¨-²b‘¬nÚ_&ó�~U±?ª Kƺ\×ÔhÐÑ·vö}d¿=­îæ�Ý'k{ºèÿ`Ào@R�ܙ޶“Uu-ô½5ÁŠ…1Áïç~âƒÚ"�m:�’4ö±gu¨q }|åáŶìÄd'íZ^ã©qõ¢Í í*OúlvgeÏÐæÖ™ækWÙ ¡gýC£cÂxY…ªRW›—¿/ 8�Ÿ•µŸ+ÈÛ•®Òo¤†*“M~ü½“@¾YŽO`bh°àµ^‰¨!9ødÕºžWÔuDwqM¥5µB×¥z a$ �v0}ÃgF2Ï›�”H©�;8(¾ÂmÉ€ Í*/¹gf.Öy3­´# Taî᜜tþÑÒœC\ÅA½Jô¥þ”“”ÆëÓ ™�ûh=|_L-ØŸt¨�ßSÒ¬>±²‡×Qã™ä\Â;89ÍŸCé$,7â図}Ù�óû'úlŠÝÌ«ÂôªD·ŠÝcÿÖP{ú÷ü²·ãÂm³çh9ò"RD–’jÅ×Wm ç‘²GvfÂ3æJåÞ´ãBwìYï嬣·ÇRm|þñ`þ¨:1?‘‹ÑâB›bïö?ªjlZ«ºn±I­§øøcºBE-ûùN뉺ŸØ'«;gû*U!¼Z«�Œýcñž±÷›Ï\çn6+f`3Y’s ?[¨™–OÄéSwÇqHI"¥ûöfíÛËîÎÉ,8Ý�‘ÜÈ|qÍTvúÚ% ãó�©ùJUÌ¡8.Â�¥l�~𼧺ã‚ÐÒ\q¹�íѵø^àç½+Ѱ Zj0Š–-øo ç•Dô6-a™ê¥[¶™FØ¢uˆD,;¯zn“/¯¨ÿ)º›ƒÑÆ,{‚(E\†ÒS¨†é` ØWÑ(�e.¸"kd±c­ûÜ oavG�±¼X(©8u°†“¦—‹÷{qqƒé;f�$×!ÛÒtâvÓÑ¢K¨I´eð q“„PÓ·æRMR£MgŸ{/hîøôÉú¡I¤˜kÎÝfŸº^µEøü•ve_fó²—sŽ _Á~÷h0¢ÿÏ¿ò²þþ°v4òŸ0‰¹¿éxÈzÖÃßßcñæ®7Ž�ëjåÛû™9]!-�lWsãõÛMŠåÞo%¿;3+kO&-…Ô&ÑÒˆŸüEr%–Ë¢Ke·ÛéÏ}×`4p,8Ï+Ä ás¦ I{ævé\IãE>9"‰͈¤á ˜˜ø=i;ÓøhMpr·Øï ¿\rµ¢J(/=qø{îE³Z H¯˜{es£8¡7m,cü³S…ö¢âͱñ$Ú1˜²MIIòÛû{l)£ü⋌…ÙGr‹„°" ˜lœNjó# lTbúÆ}¼ ¨Ád8ÄF ‘‘�æ΋¿6àfKbÂÄ�LÄqdÜ®¤”x.MŸ�§J¶ølåœ�Â}Öîk”³�;ë¤C‡7ïqõåˆ-O® G ·¥«ÔNœçúòúÁ§=üHXXõ¬`òåã¶7ð§UÅš2Ú¬¨LW'þ\§+³ùüI$—íÿ 8ãš’¼x7/ ×Aô—3�ÝÂÍ+u/ß³¯Ô}.ñwV ¼�çP%)§£eL[ÊÊÂ?�aN.h¸™ÖÆ?ÜÐè€0 rœ¿•�Øì•2�Ûžrð´ Ý4šá`½9ì‡O²ñ-,d4$Â|¢ÑDNKn ÌÍÏvgï=\ÊBÌ¢ž'; • �!3‚öèwèÄdMúVÍ‚(Ò˜—WÍGqLo_*œ 3a"1h$eûuTï®"ƒ;;¸Žr7è—™%¹éÄ:J*Ï*ƒk¿%*F›ß¼N¹¤$è]84yˆš;D÷ÿÔþÿQÝ)§�C…ÒÁ™2jQŽáH 0™zRªŸ_hnCƒøµ? ¤(/1ùÂW$�M™…™…étqZ^L‹þ@©Öj]‘£-�°ö­ñõùv¾ý|wõm®³]rV8©)ÑžXKW’éBÄ’º] †8.5);?A(ößV`þ{·¢‰ÈL«^Ò¹NX~ë�,¸°®©i@Aý›Ìj jêLÃ��|™uKwÍf‹ç8縮³tÚâÒV+ŒwÔmgA‹ŠÜ‘K‹ br!! � á’@È�Ë $�[¸GX•"‚Øâ -/U§ÝÙ©cw�;»ßa?º³ç ?vÆ¿™¼çyŸ÷{Þç}¦-Ö)Á¾3¼à�}çß^8éõ�i a¸c6/Ôꔀ…³j/Ëi«Z¹ƒåÔI�Ý5EÖ9 ¦ÂIýúïtÄëõ( 0µ‚Zò¥80@€‘Óî"åÖ³LåE „TÚwmÖGz¦ò¢<ÖZT{0¶Ç•ª_y}è–Þê,¦ =~®Ü¢cùy§"c´máÂp×l~PÃÔöIÀb©¥hß«—ØÎv×K�¥å.?mÍÿÚÀýv÷ľ3˜BQ’­#´ª �’”À) DW*LAÏ�VûÃÃ0âælƒñ¦a-…êÁŠ@èç+ÒÈ¡oÃP¡,M‘'—ñ¿Èˆ”ãŸòB‹jzIú˜³Ùî˜>zÿOgÃ+¥EHè^ðÊõƒ¯˜q4¤-B¯¥á¡‰Y9»ä ùr€OJÒ Oñ9aY»ñ}qαRÚUÒ÷ï²NtŸu"7s�JͪP Í´çAÜ 9ó½7çpÝèæ{Tö¥7íœÿ3±†Ý­KÚ&UVPš«Î&˜(ô7ä,7·èª×7—RfÌé0MT2_¶KÀ�©¸g[wˆÿzÔ‹6Ò¿ä–4•5š±[í¥jæåpI[/í „G—{üëyp½ n^ÞÆ­ç=†6S;äÀ1jÜ\÷¥‰½¼ö¥UL�gÛ(–ð&ÊJò0¹J*J'˜O¤Ls>>3Ò‚Ùë�Ý•D{%—B—%`öl“ü'DBÚì�>@G?ü�¶,¦Œ‰ ÒK�¬¾¾µo”€«á;OÑznw\Ó 9&-TŸÐe*ÝŠû16U#7%O¡Hèò‡€ž]´[¾Ö¯õCÙê+‡§hçšÉïà; 9x]¨�)µr<¯Äæ!a4×vÈ�„;?™ŠÀ÷Ä…çÙÅg³½E¯3èjÉò:�±suµ ^p‰ŽÚt@¦INãç‹'21AL¸'iÆ3Ô<>C¬Ñ†¦‚!¼§ÙÒßK bпfi‹ ”„âLvqž‘Ý3BêÁô�¾é!üÔ]ôê¯8·Añ÷>0pi‡P[•"ÏÑ$­i¸… ²F_Q‹Ö§�Ë ëqæ}èï…«àïá[»~ 8x(=NLDùŒ¹Ç/î@~È'>,$ú˜£•`9ß¡¹œÖz î�O?s »Á‹ËsÜVÕqY“ÏÍ66I›ñ¶Ê1¹lk\Œ8=•ŒMÊþd;†~{oô9?ØÐé&\NÊunšï§¯h ÑÎq=�âG>ð™Zƹ @'-¯8‹§kÌ£$ý5ÐVÅË2Ôa²µ cM…ï«S§’(t¥å˜?ÇØÄHaúÍüf¸j²ß>ÖC†1÷Ô·¤D©Vbéiµ޼ß‚Ü ß|ûå…„(’¥s Šº psè÷a°pW|²( ?œÜqEDJûKºËgøp†§™Uwœîâ»O%6Gã± ÒidBjξ w¶@ðt~¾1L Eø¾pÑÜÓ7ƒÏ8³7[Iö´×Ó]0¥�ó‚¡u�I©è-ÈçMQ�ýÍ6µ¨‰Èm°¨qÕäp'µ}v *'1—ÌMÒ¤ë¶ñCN>D7x¡*åÞ2B­õLP™ç1xú1¡At~d‡o·ÂÌC;§ý6,\pµûЙ´¿p`'Ë«kÅd¾‘kÊÉ1äâ›öì w¥]Ï$%R©¬TËωÅX�E9$&öEçdÇ¢“žÎ/¶ �ý��]ýص„á=ÕÖp£ªN×5`öî^—‘ÐÕý�Äj�mª ã.£=Æ¢½Tݽr¯1Ê€¢˜è4*èxH¨�=ƒ9›{°®Œ­{´÷¶½}¯¶ÝÖwïZš=h;V6„l8·1„�NE�ˆÏhG"òЉ$šsÉÙžbrþ<ç÷}ßï;ßï÷ynªëXÈÑK�:#ÄO0©„0:C&­Ü�Ì‹¤ÜœúÕ2Mý™ÒÕn¬F’W “g<¡ñ¦Þ‘_NŒNž8®QöÑѺ`e5YÜTW¹óÀ7÷éÜE9¦j¹0ƒ+È~~ðZšøˆûåh}‰„^§Ä 9}Ô O[Å ð†­Zxlï1ù±A@@ˆå°M~¤µU¥êoM$ú“‰Ö�&&ç Y¿¥³=³åÎ�Ïé§R~Ý^f± ì¶Û ôF'€v§ä�‹ �’Pà³h§Ûæ²»ìn{ž—w[¬¤ÑhÑÓ,l¤UîÆcΡaÙÓÉøõ+ó“Io^·vE(¯€ösÒÓŽ€�#MFŽÓÓhÊ•ˆùÀæªÑ7™ µyJ“äQ­Y¥³�á|z¥Î@Ðé¥FüÜ>f±”r:…gd€¢[ï¿@ŠwñãÝš~«&/\̪٬›i¨ÈœìcâsrwÈë PÇ}Ú½ êÅl±@™‹ œ&á(pyý=04¥Îö×ma� E[Päd#ó$ìéè$5=’Ï ZPd2šñ •š]¥KÅ`\VýÅ;…åÍ…¥ô\g}¼”ªRqŠ|æ`v•wÔJؼ ãä…¬_Óps:»/“a¯g˜ð± r‚"Wž‰\'€òn68F“àÓ©þ`ŠšlÜΠ ÐiödnT  o§Ó$ìw«.¾[٨ٱ�þGªèÄ‘´y¹|BÜ�ÈJÞ‚á[ÙÐ�ù/O¾¼шº³Ê ìþ¿�†O­¿‡V2:•<}y-î‡äÃm›ª?<ÓÆ¨fµ×®“÷>›¿ŽuMÑD;¡ gî²ÒP}“°úÄUr§Ïó±�:éáq{êÀnƒa—…&Vk FÁ&§.€ õÐ0:È�SpÙm¸¾ßòǚ⪣¥UÌOÀâ*m«Ó•hòàšMòá‹c“7¦7¢¥(»bSÁ¾¢±áLè0�E_в„lð&Ô¦ .ŠoËã•J_5…žX‹–àUQveÃÝKŽO�eÐ.PÜÉnÆKó´ $hòŽ“â=xý.o±éxÝ¡nÐ7R�Gü±væp²í›+$\vþÆÂü‰†÷éÿeéíXÖ�x$DRîûœAjèÑd¹Á³yGf$ÌØæÖs$Tƒ‘‰™x¯ÏÊh®/` QƒB$‘j‹ÕhjÝ\ÁÜÆÂ\¦®ÕíêÀ–çûõ1ñ¥˜®_vn¾q�X¿ƒßÊmð‰AÚÕ%1eá]=†ˆxÕêîfê­¢ò‚â‘C {™K ’ÑöHK#YuXU^ßêï Û†Œº¹¥ZôrHê÷t»‚¡ð…»,ø¹%·E©Ÿ¾¾tm¦%µsŒA�}-Qõ±Cqò̉ÄäÜpý†�Œ²ð³bΈ,­èƒ4±½X†‰««±ûn m6ZŒf¾¦dÿ^­m)±`0[ÌVÒîìrwÑÄÕóèséëÃû/O28›¢uÉÑ6 ¯¦>bã_1ð4 þ–æò—Šbâ›.,»ž†[ÓDDl™‘[¥•ìZð>Úˆ”ÌÛƒüé�ÊÊqZ}¤Q¯¤ªŸÇeÀ_ÐjLÙÃl%‰zÀ[Såߟ:Ý�Ó’|@(º»fbc�saLoSZü2–%ª2NB±Ò‘>£Öæ°ØÍÌ”DöJ,a[(@FÏ„‹ÐA·E ^ ”"ÇÓn“ ”$öôÕ²$ÛªÐ(éfNÝÁQ£«‡g<š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 H‰¬TÛNA}Ÿ¯èǪ„™�îžéž�'Q0j4ê>HŒ!ËrvWv¿Þsz. ½S]}êÔ©ËE6z=.Íñ*íÎJój‘}Ê.îÛloÛî²ÑK'+S¦?³šÌég“_g¿—Æšî(sUºÆÑ6…+­7µ ¦›eûÒi¬‹ ³«ÎVöÔVøk#;f¡µ,͵ôкð²6k}Ò_«ÂɦùÈ'Ó¥æÖÃåöF–6E+3õr ¶yœh„uŠh¶#cô[÷6ËË¢,Arbn~\_Temr¤tæ{xfe5Õ¼Æó¥º¢’\mDè1�¼üT`D„âÍI ˆæA@=y�žƒ`o$‚«kŠZ®A­–ÕúÆ<ƒ“¬%*j{E»v`×’�íEÆÑ¶…¥7Uhz‘· åå„„Z9XÄÈr +‚¿£Ž­\’Rà$MOÜ}¦1’g‹ã`ü�Âuºÿ¢.wÎW­ó à9ŠÍá@K­(×Fzp›�ë³)S"LbÚ¡hQÖjŽ…òñœ‚E¹6Û¬ ­åíÝ™ÙKÁZ6ršzà—:Kºa-‹¤¶¤àP–È9Ðp·9n™gh»/CŽˆdÅÒU·ùw<>îtM>ô I„ö`ôdÊ®-\ãøû0“ t_÷£§à žn9âÇ6 ýàú|ÃÂx”—aßkîY+&5å9°ü©¤¿Ùï‘ÍÀ*嬒ç³Dúà�]G½9 [ ñQyâÀ-öòì-ÊrÚ3ú£yó• Ó´×%u‚•3e*ž­ÿO+„g·‚{¬Z”q`áïåøpø­ëÇ Â·HëéR©ÎŠBÖ`^¬G Æ9q~Ãná™z CæÍãÝÆ5SË‚pï±z„%,·hÎzRÅË舻£®‘1딀oÅjã%j$—QBÒaûp£ôÄ|Z¢¹O¥®5jœsÐ'œ#|Ã.Ïþ(IÈÅaelÿ‘¡—™I`á¯5Ü!¥Õ¦¨xjw:Í�‰—VQ Z¬òN—ý`y�_ endstream endobj 222 0 obj <>/ExtGState<>/ProcSet[/PDF/ImageC]/XObject<>>>/Subtype/Form>>stream H‰„ŒÍ Â@ „ïyŠy�nóÓÝnî‚^Š‚ ⩊öýÁì¢g3¹$3ó1ÎGz…G6A1†ÎŒ÷�.xÄÜŸ÷�Šzòs0ZF“ªŠ×ŒV ·ÖÂÓ<áºÒxX»'-¡ŽŽíäRÿ“‹'61‘Ö„û¥Ù¾`ù�ú0²O'j endstream endobj 223 0 obj <>/ExtGState<>/Font<>/ProcSet[/PDF/Text]/Properties<>/Shading<>>>/Subtype/Form>>stream H‰ìW]o%Å}¿¿bg$îlW÷cXØÈFk”H€"síe›Ø‹üúœsjæ®xÊcdY¾Ó5]Ý]§Nõ„éâo‡ÿ>¾8<{þ*L§‡)èoz8Ýžý¯¾8<»°‡É¦‹×‡0]œ0}ñ & xüÆñýd]+ñ°4ÖjžRÊk™.~<|=_,iíó›ÅÂÚæ·‹Ùç‡é'¼ó%ßÚüÓbP¹^òZçûé¬óv˜¼]~OK_Ó|Cý:ÿ¼ü^é÷új×›ÞáÙpRÃêëéåbGÜ/{ßé„ÓbuÍ8(ð¸+lióãC¾ÇoÇÁwXSæ×ÓòíÅç‡cXChòÞ¿Lq-棭)¥éâ N¾["�¾^Žmžl©´²,1ÀæmJ3_Áþùl©ó§Ë1Ö/—cÂã³…¶þKJÏclîn—<¿ÆŽó÷n² ·'ØL7¨ 5Zù>=Xœ2‡W‡yZ.~ø3ŽMìõ^ðØ‚xD~ã›_"KΕØ�áMÃÑw÷ Aúêïl³›s±ÔÎð/ÇŠÇió=a|{Gëã|ƒgÑ2Sø ×ø-óƒvøfF–`MnÞ_\÷—6@I 1Æ%6XiKc ™ço–ÅvY�ìèÌ“„m`ë�/¸(ÁúþÝ’7¼ü,].ÄÏ1"Jó¯S\AÔ–B$Ê Ç#Þ|¡ä¸r“× ~ƒÇÍ�0°8zT`sçQ�nÄ4bïË ƒF'ß]:ˆö¢á¾]j úG˜>ÒFÄÆˆÓ�«‚HP×{€¥k^º@³  (у§˜ÇêÄ=(Ÿ!ê<a/éÇ8°ÂB€µÙ< `¶Ã²cÍÜá' :bÅš!¼#SD˜ =Ó5扄NŒu.HE2Û¥ÓrÏïg± szë”ZÈ:ƨZV-,9Mç eìM�j”=¡'×ìÙhPOØ´®Á*¥‚A²Ü(!JÔEÂQmmܹ‚G�R«”4»bNZ_i¤")¶q–ŠtÝR98ÑÕkÏCh�<Ém­ P^È2“!lN iÏå<ÖÑ$1²Á­§�o¯ÿðËÚóWûeíÕó/‘¡{í0}�w?àÿóéëoÃt5=ááÿAç¼9¼*¥yp³Œ47¤9ÃÿR|8ç™ùÓ}}�U»‡¢_Í¡P¸5¢·‰��*™k3!)öêŠ( -¾cMá•ÏTè$D¥Š©}CDW«è‹Æ�b†u�_0ÃBÕÉ–“«¹X8W‡+6žÜMgÅàŠ#j.bY‹ábs¡A)ÊfŠ5aÎ|ŒF)@H±H/ukÁ\®ò#õAA§¤áz l@+ÊzÔe&8šªðȳtb›­¥�gý##¸Ô£cD«rÕ¾=i®”ÎÇð�“JÏ€-£kh"4þô,ú¸¹Ck£ëf¡1"í¼2æÐIzYº¤\ÌU«©ÞKÕF5:ŽQ½ï¥Öú¦K·bÇA×î:„PÀå`t÷j¸f#òáP§Ðå•9g‹'Õ0îɦÏYA †%+Tˆ(-Ç·e%RŒ½ÅX2!ÅX$¿8Rš*–…·£È¦$ 5Hè)îü]üA´À+BLÑmð-©ÏbŽ„ ©— \±Þð “Í7T…ÛÀ· º<Ǿ#ºQ-UG_a2HZç˜hFr›¸3—èET5WådpFî¤w'T°²èe|Ä�†\Š(šwŸ¬ðó e•ÇH Ûçõ�ɽ‚Q²Ú@‚ NœFäß�ú3¿’`Ø™Z\®LxÉQœÝ¬m(r»G¡»4ç÷&È[i»DˆÇM„ÁpBªiÀîÙc²‰f$kâó<„–wJ£Tš¨/;ý“2Q,JtJ;#t‚èÌ£=,ˆDÜ ~äSXíÞÆÔè62ÀçDó¢�Â`m[]÷æ¸kÞNÍ`V•Ú·ríMk͋Ț:ËÈj½¬‹ÌË®oÛ’Ä’N^ý¬/©¦c$Ï�ŸÓtîÑHu*g àÍÅU7¹\lÊm®ÒµQ܃µÑ§6úÔFŸÚèSýŸÚèï¿GcBµÇkޤ›’¸ÍÞHy$)võ¤›ŠGT)wÛ°ì}ª 7Ï!mC¼›-:Sïœä¡9OV_R�†%¥Í,Ý…`E%²ëÙ#i‚AÈ2û~�›€0h§kÌjÉÎl!P2#%1ƨ$ÀR9n}ã?^*ŒÃ�XF]ˆ¢¾4cäÈ’”P€%ªi©K­E%Šç‚éÕá"µúÖµ¤4‚ð$Îdì7ÅÛ�oF[‰�†ÚÅrjÙ›�Ÿáõ ߈‹?Ê­gÏ€Êټ桢ËcKšJÅ�=wAŒaUnuÏäêX(N­8’“аiïûME,Î0ˆôÅC"ß6q]ðûLÛ1ïAia ±‚E‰ÑTãoHH•Ï™æ÷3fRÝÈRrÎÌ`²² ²„‘Þdf*‹pkqöZÈ›ÐvÙǪæ^ƒtCtÒ�C[Ý21’sP“×Ý¥ùîä…†¾I—ÜĨz'WÏ�g�(RL)×#(…)û]Àu%a»ž7]—cù/ûÕ’#Ù�÷>E^  ýE�§0€ãÍÜ1Œê¥òSír70€1 .±SO¢È`0H®+CB‡Ì™$Ù–4 0È*«¢¯1HB6È••%ÒÈkBšQÅ< D’ª,6áµ¹~á7›]Z’7ãš j³deÍIÏ”]Èg…?ÿ|þúãƒýb°_ öÄ`/,O‹ Än4”Šº…išKЋÒ�Ù‰HQåÔ¦¡ÐcZk¬?~ó #,ëüÁ�w…_Xëœ>~¿KQ—ÅS“Êá9IBÀ½fŽƒÁ�@‰Oy•ÓJ0¦äì lžîK>Uü¶& ��ãŒÄ IÄ-àÕ“¡Ÿ¥{sU}«Um„¹üšæ¯÷bmíÅô0ÔÃtœû{�)Ü7 ­Ymãú©¨JPþä[VC*Cå sß–îË?ž;Ò¯lþƒ³™˜Uh©LIäyïüÏ¿<íGÒ±µ¯…‰ñ}Òñ­’~œò¤'Zhèüf)�Oδ¹xfSâÀ|ïjzÕrcqÝw�qÚ‹Õz¹÷hy·Á�ùÉp<»ö=Zô±¸jøÉz‡ñdî‰ãÂ9×Eº+®±ÌÅú9ƒd”¿s4‰Ø‹²¼1ÁÔ�«·�pÞ‘òp=瘓H™ Xû g®Ÿ–ÙþÈ»Kš÷3EWÜ…JlÛ‹L)¸�ž¥lü+¦I3ãöEãF%Ju¼¿dÊ7CÔJ¦ìµúƒ»æ«^åÇÈkÛBÇûFb¨7{°9•ä�f¥«gõ±›—BœA—£ñQǪ-£1™¾¹÷�„ئ¬×X5çÕΙ,FÁR¡ÕЀNLXÔ³±ì&¸+Y£…ùo˜ˆëµ5¯µqßfÛçÓQ]ì›f�ôœíl‣w$*n~æX÷—cP¬;,ð­EÀ�«+�o ¢]JòcQo£­éq›U¢4w/+Ϥì¨!~4ýœIz2SµkݳvÉò¸é 3q”ÏUÂ%>t$$Ǩ5byþe¢z¦ –2çFÙi�&SÐ9x¦BUÕ+FÍ”chƒé1ÍS©ÃV˜¢lVIÊû|_§ø wÃäÝð*ñ¿�J­ñò?/+{y¸æ@úÌ B€z' ´>æØÿ}’2aÒ ]K‹{ªFÜ0E€'jʨƒQ42 ¼„aYÓÍeé ©¿rºT›A°˜ŽêA�{–BÞ¤¸’ñF@”UÛÙ7G1`3ȘL(Úfe_!EÈp¿·ßÄàZÉobšmñ­~Âl„Ê>€`!>nårSન*° ±.$ fÀ�Ø[¤Æ‹95f3¡Ðsd•Jëãv&ù㥪–á] Bç]¦²W‹ÌŠ0E-‹e{ €²š{ñ r‘5}@%›ûÔÎèÖˆë_j\ôšE¤¶¨Í(±ªNç�N•§÷ziƒ0pêý¡Ëg îöBNë:É/¯ù¸ÇùEÿL/<Àóî¡G^œþ{å×¼‡òõndï ŠßVÚ2hý+šîËÇ…lÄõK¥ïXƒOqØ�ÿ‹!øæ)tšÉMkÑñilJüSù£ØM1^jséKEÜŠÎ êZÆ>–¯>¹ò?èšï¤¼JJ˜ëþ¾ž c‚âÒå_Ô‡@�žè§ž¨§žø9Ñå„�rbýŒœ˜Orbœr¢}YNä’ö¹œ¨§œ˜ß•vÊ ûTNäCOŒCOÔÿ‘ž(Ë;D©(þ·úÝcØ3»WYS$8Ba«¬Jt5õoø¼�¢I»/1ÂYg˜ATTS† !>—‚¯¾9g_­.h° d¶OÔtGbª: ¿5c,Q­´@ÞÂ>Kd´(gQnîÔ.#èfðаu.N-½œfb“›• Öl°ãUy„ÎXF`½j¦èYhS³G[&ˆ,šñk¤�5é"MôÀÎT#ð ¡iMII€TÈù47̹æ55:"ìÉz; Uß3ûJ) $;N³_u"„ÊJŽId†G¥�¤„ è” TÒI'EWŽQ½îø,#ø çPà¹3K˜EC4>µ•è¯=´Xh‚±�V�¼y.ch¾¥±JÀÜ^‰ñ± N”¦£�\¦Ô�•ˆÏ««‘HäÊe3ø­¹$p¯5|D¯Ö¨Ý|ÿ±ðuT×CüÚÏb»ð»|I=e”M˶'&;ƒf™ùeí5¬í’Z´é¡Ñû–CÛûº îJ O©³kV†ƒj h�8oM:v®q‰»É=ê7ø²—к k'6Ú„·]X ÎDŸg34‡&Ãç#SX[�µF‹²"Ü]¬é´À�‚¶F‡âK¢{QgÎ�Áy �íAð¦Q£ÜÛG©¨Z _õZ/Óu_oàéTñ’ZÉH꠬ؼÑ4X²Ñå˜/AfU&2‡Þ6öï)a? xSu‡}}… P=‰òÀ6 Ñ64Kì£@T‰ïI|H“º Ç)/x¸195Ò;µ§*4A´¹ŽYŽD ÛHP)éþ*‹(e+|sÌ8UÌ*‰\2930ù ÿ×”¤¡�è÷¤2öD÷LaÓ£ëz½¾mréâAiËg«uq$'ÙÃ(l�Ø—×£áY/¶·=j˜ØÖë‹õŽšT·äÉ�ó£-Ÿ÷òá¼gŸ›½øK6[”2Z²1E�ñL^§æH]µÖH´­µæM_€3ã¨Â.†ÁSCÞIƒ �¿*KÆ)©ÀÊl4Šô­q˜Û¢©µ˜í¨* ÉþÊJÌÑ;`&–'ÕU't“$I#DSÞçû:Åg…Ìâ¹¾…W%¢„—ÿyYy¢â+¬Ä\ ùRPhÍFhiÿ/,ÝddvU�¸R)Ý�JF�ÄáGv°SÍœ2h´™Š:dRY%rõ¦H/)|.-D4‹8•˜Ó1L/¯º4ÇLuÉQL˜ÚŸcýYÈÔý“¨õû_³¾´ËÅ´ý�‰x Jê7ÁX5cè´`ؼäêº÷ÛÐËWïÄØrô žµBâ-ÿ\h}Q Oµ”ØD[cÆÊSiVØ‚ÆÀ¥‹¼ÎMŠàJ¡�ë¿pÞÉù|öz2¶ÏH)Îw˜üû9•åuêRL‰n1Ï—Eγgý_·Ð¯·îгu†hát»í‹Í+˜�²…`Ð72—à}Ws°=øJ|H°s(Žs wµH £JJ>s:æ:FNWX‹´ ÖÒÀ–vβHš®*/øûŒ”ÖÁpÉ(,c“NB`¡¶]GºOº³J„Th$\²9Qn6/*ÿK0Ô%âïÒRø5æ"irùÑ÷;)cX~2úa2»—ÿÌÌ{Úž¨“2žTïçRoÞ˃ºµ¬Ö®[R¡”ª}rZ)_œÌ\ÓxÜÞ9ýT¾¦5ökZ >fÌL;͘]èš“&»úwB"ã‰&û=¾ë¯�ùˆË~·´~:Áádž‘üÞÿ³×¼�»m=g`T1E>v…wg}jB]åðT¶T[Ä­Æq7?fo±CLRŠMš}ï¨uÉiŸÔÍuÍ£Ì*!ãu8yH›U‚xª ©W@˜F©Q0öT¶ƒ"®Ë)yP‡ �þÏ�°]XEðgp‘‹èW73ì4 �"ŸûÑc½?Þ¢4öÕ[X6zõ-{8÷Ÿ£vÈ º¼�¹—ý]ô æ‰ðIÑÃ9ejpö&"q�å [ºJ‰§¡5Y�m‘ˆñhÓr°®Ìç»p#~‹žzë�kMtÔ܃äuk–·Öf{~„�¥j ‹²aÄ!©É^p!ó”ì+�° ;�%ƹÀÕb1ËÞ)²ž™‡*ã´w ÛëØKKî*i/Ål’°E×®�~çWÌ£¾+Ú4ù’8†ËCœ+&€ŸÃG6•^!¿£It¦^øùÞù 6Ùu–3é¹’¾¬ÈT4v4Ž�èH•vç…s=Šo’Ò—nÕ¸- 7‡2©Ô*¸Ú¢ 5 _£Po<¼74M䤱�–ÍÉIÅÞ¥[ÝkôC« ”üUŸßzç[² uÑÁØéÉ1Ó@¡þÍ @,Ñ0·’ÿ •fåõ€6X3AÚqÌ0¢o�LHoULÔéAûèìÎFe”meÑ]A®Ä ?ÊžK •p/~ÂÕSnù¬y=уd’m5øñ• ¡nÛ$²q Ê®ó‚jd›‘C‹± r‹l8Z+�8�ÆáZ9 @ç9îs9²$[ÃÔ®—@ÿ²ï¼$–bv_2=8‰j9_ôÎsŠ×éBÓ"­º$Œ¸y“õNsiÑ Ù⤆Æ}tuŽ^A¤ÖÑ|å¯]?¤OQ3 áÐZÝÁdŠöœ4K˜ÛïìVŸ;cÁ’xu$Øšõ8Û¨Rè+èèõvj? ¨ÞŒ€Èv™—)9•b½q�ùÍ-3Š—Fd£:m„› ÝðÛ¬bãŠcÆ!–Å…!kˆºJ(wL{-©e ‰µ©§+(­Ë7òy´CèˆÐ¿/º¾UEM;Ô‰i:@¥]^ªïÀ›j±ò™™ë~q’±”jÉ÷ˆ<µÛ:³µŸ¥¥'žûŒ4ž¸Ïê�"„¹£ –RP7NÑËTyÑ �ês¥8/3ï!«©¼ÈŒ"Ô«àbUê�³ƒš—®” %XØæ Æ8èÙ¯z ï³ÉóÚ–.Qî¸ÓÛãÉâ–.Z�þce;(4Uyt]p�¹ÚAóÜz`ë&jêü­.Ö¯×ùè1M)À_$=DU#ª&R �n"w,ÃspÚ'$†ÊÌEScDhŸ´0¨ºXybì�Þ)ÔCkrÌä:ËÜ*Vu¶u#äW®ê‚=Ná\GÈy vÿïÒä²��±¸ltÿ=úîð¾/¾M,F”·é¯Tpï9#º jà :d†L” \,*îVùVeìéIËÏ/:f¯e5Ç6¨5ö´ÅÉüž¼N%n§Õâ2�º¼¯ âšqÿ¼a™øÚÛeA„P¾ X˜-þ›±bi$ÇÄ�ò3TàâòŒ8¹ì¨B¦F¸ÁÁíŠDxxD�n÷&Fƒ¥r¶?·!ïÿyŒªó÷r¥‰ßlEþà’5+G5SÎ J•Žþ?¥)ÎS®F*FfÃÀ]¨—1%ˆœ‘ŸH [Z)QªA^!G(|……⣬9É×4²÷»$€ü�ãŒoÆ×O1¾?>Ãøü ÆÛ<8þUŒoÆ—Æ3~ãû‰ñë;ŸOŽÏw�Ï/’ü8I¾$?o$ß’Ï/‘|ùa’ÿ”ãÇÁñýàøyãørr¼�?î?NŽ'Ç·Ç—Ÿâø~r|¿s|ÿrŽ/'Ç·“ãÛ�ãíàx;8~|Ç——8¾œÏÌÞ ?�7�Èç¯ùù]�Ÿ?òóòýòëòõs�OòóFò–?#ù|Cùö Ê{H¹GYn_KŽò.ýèlNìÌLyÔÙ‡ºFß«énì*Vo{O )íh¬EÑ øxkRžã $NŸ |Ùs5Ÿ,}ï”iÓ8T7j�»'óqs�¢– iˆƒ=$ž¦†ý�×ìƒçE®b)(™F2ŠK÷àEÓCŒÉ‹kØÞÐÇžØmÜÆuñ9dð�ô ×F�/òV¬½X:“b`Ò¯uò>ƒ:6Qs 2‰­fe�âå*AÝr˜¬6¦µ‚*¡Nd‘Ü2n³Íý  „]¯W3û€¹ŽªgªIé§Ú@Æ‘t¡}Z¤ÊŠ‹({tC7Âz^‘[·e¢ç•Ñà¯Ë¥yÂÙÈÏ”*nG0ïÒ¸ãD{'úK8Ñ^Á‰òN¬'ò«xb<1o<1ž(_ËãOá‰yç‰ò:OŒ;O'ÚGœøšXî8ÈÚ¯–çöKžÉóy®ŸÊ³ý’ç_òü·‘çúŠ<—„üLiy,[†Æy‹„°ºä™ßW U¥…Qq¸£!w'=Yªú�„�j£„å&Æo�×EÀÁµjä(ä£ãkÅ%䧬&5PÝF„Q ç3Ï�fmÏõÐX•½º®±OáùU�zöÉ!8½'©¤c2¿¸Õ¾³çs·mH¶a( ’Þ™ôõ»³¯Ñë�>´6ùVSUk�õÚvFéd8Xã[84ÎŒç‹Å«²HLvx­KXaX ÿS¶�ižÙ×mËïÉÒúBNØkÉ?Û=pœv—O÷¹än�Xq ›(Dö<;aEãC‘¶ÿºþJ VËNJˆNDw¥-r3å �Áÿ©Ä]• n-Å™µ,`ÂzAS§ÄK@˜=Péü‡½(ûz0Ö~ßK½VrwÑ,Ø¢P=´µW�ËÀxkÐi•u¤Ä%*+ྊԊ«Wâˆlÿõ†�$¦3z?i ¥¸ÇC›hkä@_q*å C°q4XìŠrV7Á¸¤"×VVšåqìñ´˜?�‘LßÐø×rrËcû%k€CÈ•û|áä8{øÿq@(ö]ãÕãUcü– ºôu¯ˆÉ锚JwHíODnû8)0‘¼I{�ΓïJ¼˜ %ŽGD®º1öG¹/ÒôFÚ‰êe„Ýp°€æ°73™>˜¬ÀCEƒmîkX7$3*™q°JÕ‹Hj™ÁC1öª6öRáÇ’ìX�ªiîUYsОÆ6wYÐLó]š»[ÕÌ«[#Ü©öè?sÑÕ`?©®’þŸÚˆ¢ëÿ­…âð{–‘Á2¥1qË©—Vâ-Ö¡5qÌU$ϼ�ÏÌVÚ^©âþŸ¨7‹Ð#qå:PZá=2*ÅyØ©‘v'>iQëï¯ög b§ÎÕ`hÞÃp”ÎØhƒ¨¬X x‹�xˤœß[f¡�=þ+ôË~„0Nt“(§ ¼ØwÍ·&Üæ‹ƒ ‚eá@¸|y¤Lò5)…l.¬AFŠP)€ž*Å( ëùÿŠ= 3Û~e0eofµjéjHð �©†µ]t»Ô¾åU:1P—�bC¹×.&dÛ…të™d•YÎÐ}©qÓªŒªŸtÂl§ÑM"ŸÍF?f„;Zœ/Q’T ï€ÙжhCÖ€Ì8)éùIŽvr©­ÅwDµÂÞU²QÆíˆKª€¾Æ4H%”2Qu„îó†s%{¦ú¦–Áýؼb*óöÿöwN¥›�‡™ÜÕ––_¾7ðï©tºL-âÕ¦2.”¥½‘z™D yI¥WÄ=H`Û™VŸOÐÒêÅÞµšO–¾wÊDè8e wýÏ?¨Òº8e‹„O'>­‹ƒœ%2Šü®®¦ˆÌ%ÏQ/©º9ð¾GЛbü†ñ¶7ô±§C·q€B|…�NgeDæ>~\{‰’s­ûªùj_5¿®¯G_•´±jƒÆªý\c•ÏÎj|yg5 ³š·ÎjþVgU‡'hn€wtV9§A4:x#Mž‘Ê�ª d=Ù †¢sÕ mlÇ<ØU…©š²Þ ļâ샹&é,Œã±y”Y9†ú’Éê*ïðPtu™ ï "ÇÚ¤fÉå“ájmx„%Z6z‚ä¤ è™ÈÍj˜„6×ù÷*M@‰rYTu‚ìz®:H¿Øî,ÙU¤`„Ãq{jt›ÑW̉³—’ÕÕQþB!jä˜ÌÎôCû—à§PaC _ÃpŸ7Qêî£ge|ôÉvÀ{ ÿ}f1Ь�?\f èïŶ�}+sù_¬ú{�ÉðnÆ™Ü@ˆ˜™ß L†®€#°:öœž7Vm¯ðnæ�3^ó¸­¾’£Ç7/R¢ïÌÝ<Û—¬ôúû,ÑÝ™‹¢zöæÙ9,€¹» glßL‡¸M¼q"O,ÐÝg8·{-ŽÍïãáãÝÖäŠð3–¸Ï`�æùBÓ°Âø™–Ç Œ9ArïÌÿ¯yãÍÐ'yt;çT®�,n8.¯…htÄñï¸ÀmB×(~¬8Gá5¦§:ÆÞtðÖåð*|7ƒ5<ò#(r\Ã;Ýòè{8Yqìkž3oZ5eÚ"q 0m¥ÇÐãu5pqÎÆ%î3¾D[.UQŸú¸Ä×ÎmòŠ  õ»¬a®.tbE ¬Ñ´•þm ÐÜlˆÄŒx‘ûÄ[Lô˜ÉñE¼Ñ5î)ž·Kœ3Zƒ ™±gZãL�VbìþåØéc³³Ðð>¡‹•†]šûÛhŒ…!J=¢µpÜò¸¢õ9#Í3E¡±FÖÆBô=Ö÷­1&îYRŸëò‰Y#õϳ)ï5Ž™7z~xob%1�0¬aŒn•WÃÅ…¯öðó9£X�±½½dô0v�ŠÞÉ ®aÍ‚»ºãWmoÿg¼Ú•ã†a`_¡¸1I‘ Ù&ãI•ÊEÜ{’¸Ð¥ˆÿ&» J¦..<.,àHð…ÝfϦ¨c GWr€Ï¥„KÆb®ª ,5¨Š¶qrlrXÈr4ÀšÂJ\© +‘ '™=~ã;afföw]Q¨p¶¨þ®³Çß$�—°ïšk¦SU‘é'n¢°lv˜$œG`¶&;4¬E— øŸ΄‘@ª*òa7Ý ˜]ïVÕ ÐÃê„|öìlêžÆÚ6ÁA»¯iÐ’®®×ƒµìÂsQÞ>ÔG–ž&*(Xá¦7NÉDµ9I•e« eÒˆySãI'‡§•Q$“Í mÁ>(Ÿ|â’ØSsöxbéþó¾8 b—]¢«�‘Jˆœò®²“ÇASU0Kàæ8üåòcùƒ îáÛS\~¿]"f€@ãÜÉŒEöû×uú�J�T ‰@ =6£Ø3š�/ÏËÃÓkXÞ^—ÇçeÔˆÆGp6Xqa7åÁŠ_kuÙUcQψ·#¹¡H‚îé¾î<®w±ºL4—rFQ6ú*»›IÍŠ6wÆÀ\ °@: ´óŠbòž‚tMøGoMœ\gÏ� ÀÖ(D´„J›`…sÔ3�ðØ4•¼Ëæì…" 7¸šËÆdï4Åê)˜hËSpö ZáÎàÉz~SÅO;�@"I6ê”5 Z™=#n†ð ¸[�U¬¼—¦ÓR5+žÉº2(W=Ë�!*àÇZ:Ú‘´ƒxlDz„3ˆ�Ä>*í1&Ïæžµ¹Qcÿ™k�±'¬Q½ ™ßŠÇ8{6y¢;éŠz »~‘,h«$6#œ=¼ ¡ð3æ ‹;u•Zž—û¤þ?GoòT•Pðð ´YnÂ6æmƈÒ6bÌžÍ=¬¥9gm>GÕ#c~•ÿP]�$ nCÑ ;>®Ço̦p·Àu(õˆõ�çxÆ3ø]b€=&ê„FšxùûS{Øw€ñè¶°…M5Œf¤¦œ“i¸±ûL(„ÙaŽOüË�é¦OÈeÜM ”ÙÝ"O#é23`W>+è�?_W5%_8FÅ,R¶÷Õ϶�—�óÞ*P¸Ùã ë´aq Òñ9mt˜Ù•«–ÖhèÈ08Ys¬úÊuYŒÀ=NQJv ß}Õ|¨Ë0¸€XìÝîaœšé ¾a„–ïm·¢÷i‡á1Ýôõ4g߯±A­Û¸. ‰hذ·‰Š`(ö ¸,L`qˆ8ÞÈ¡ÀS,ön¸4HÅ51K—sÄ—Ë/$èã÷¯Ë…™ú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‰À?ÿý¾\ý¼\üº[û·ZûµYú²Yú°Xù®Wø«Vø©V÷§U÷¥Tö¢Tö SõžRõœRô™Qô—Pó•Pó“Oó‘Oò�Nò�Mñ‹Mñ‰Lð‡Kð„Kð‚Jï€Iï~Iî|HîzHîxGívGísFíqFìoEìmDëjDëhCëeBêcBê`Aê^Aé[@éY@éV?èT?èQ>èN>çK=çH<çD<æA;æ?;æ<;å8:å5:å19ä,9ä(8ä#8ã7ã7 é>jò endstream endobj 230 0 obj <>stream H‰œ–yTSwÇoÉž�•°Ãc [€°�5la‘QIBHØADED„ª•2ÖmtFOE�.®c­Ö}êÒõ0êè8´׎�8G�Ng¦Óïï÷9÷wïïÝß½÷�ó '¥ªµÕ0 �Ö ÏJŒÅb¤  2y­.-;!à’ÆK°ZÜ ü‹ž^�i½"LÊÀ0ðÿ‰-×é @8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ �V�³)g�B£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚óÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= €x¯Íú·¶Ò-Œ¯Àòæ[›Ëû0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±Z�L®Ä„?â_øóyxg)Ë”z¥�ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.òò· åÒR´ ß�Þô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ�;ÂA4ˆÉ 䀰ÈA9Ð=¨- t�°lÃ`;»Á~pŒƒ�Á ðGp| ®�[`Lƒ‡`<¯ "A ˆ YA�+äùCb(ЇR¡,¨*�T�2B-Ð ¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°Ž�Sàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4z�BgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p�0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"E�ÒI2’�ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷�?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@� æP+¨íÔ!ê~êêmê�æD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒ�Ó¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™�˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 N'çÎ)Î].ÂuæJ¸rî î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…�EŒ…Òb�Å~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X�[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„�Æfm“�Ž;'_9 œr�:œ8Ýq¦:‹�ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=GTB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%�—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† �ž�kï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»Îå�wW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO¤[þ˜¸™$™�™üšhšÕ›B›¯œœ‰œ÷�d�Òž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª�««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½�¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ ÷„óû 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|~€�ƒ…‡‰ŠŒŽ�’”• — ™!›"�"Ÿ#¡#£$¥%§%©&«&­'¯(±(³)µ*·*¹+»+½,¿-Á-Ã.Å/Ç/É0Ë1Í1Ð2Ò3Ô3Ö4Ù4Û5Þ6à6ã7 ÏÔ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‰\‘ËjÃ0E÷úŠY6‹ ¿šCIRð¢êöiœ jYÈÊÂß‘&¤P�4GÝat%í±µ&€|÷“ê0À`¬ö8OW¯Îx1Väh£Âm—V5öNHwËplí0‰ºùAÉ9øžôtÆ•�o^£7ö_‡n²»:÷ƒ#Ú4 h¨ÐKï^ûA&ÙºÕ”7aY“æïÆç⊴Ϲ5iœ]¯Ð÷ö‚¢Îh4P?ÓhZý/Ÿ—,;ê»÷¢.âå,£@|d>—yb Äs¹d.#o˜7‘·ÌÛÈ;æ]ä=óž¸â:U¬Sñy•ÎOÌ'âG®O!6ë2>ƒÜ†»Gêê=Ù“¾$ù1ï¿æ&¤ŠSü 0‹Q endstream endobj 239 0 obj <>stream H‰|TiTÙ®¢»ªAMOìšbÆ.§ª#ê@@7dqAZF%n@·¬v³)A3*Kƒ� ˆ²ŒÈ*ƒ((¢ Ê.  ‚qcÆIb¼…sR­?sNÎ;ç�wï{ï»ßûÞ½ÇÄ&ŽãÓ<×lðvõž³nŸ&ØO奉˜ë­ŒóÓ7gò Î)æ§O¡·£ô÷ïßÄWVvÿw�þÔL½9}²� 3ÁñsE+#"€À (…e€•ÂÎÖÖV±\á¯V(÷i£Ô{´ ÷ð€Md„Æ/J­²V, Sx�kÞj­ZctúX+­^Â�ð(Å*µÖZ©W‡Zâ¦Ö*üu`°€¨Q«Q?•z�Ÿ&T±ûÿE³qUnÚ©V,V¨Ô»1 &5Ád&ØbÌÃþˆa6f�a+0l†¹Š±u¶ÁS’˜… ‘`ya*ì;ìì&Nà!øcÌ$Éä?¢Å¢Q£˜G‰G‰¯‰x¢Žt#ÓȲGÂH¶IšM'›î2=o:f6Ûì¯f£I©õüX=.Ì3ëE©b>iÜk"‰„tÔD£¥p‚€$R ŒÆÄqɹãã–"Á&ù´q…Œ–]•¢-p¨¿©¢‹ÐH{Bj«DŠêt ÃoÀdˆttyÞ�å—´AAšÈÀÀ¼ÈRNŠìÇ—Çâ)ðFÔ@CÉx0áJ¢¢Á„4'†oJ�•�n˜º:óáqÖ…¤ºÐŒeYn@Ü!ÒHij/ºÞ âw™÷¢«i’ëµ|_>ƒ)ò^¯çâ¾{'{a‘±îâÏÌXÑzw«e‹�#²ã\݉T× kU· žŽ¸�R/ªJè˜âÖ¨^l†Fÿ5êÑì”É¥I¨ß /ßî”lìCŸ¯v×h‚ØA’•›‚ýÂØd2°ž7À�Ï?–›v.Å}3q�¶Ùúè] wöØéïO²µyõÅ Ì`ƒÒÚzËZΨßý^œŸü\t{œ¥W@w²•NôÏH(çGˆ&áé­|U‹ìÒ3÷' v¡z©~È·¢i¿z¦²HÙÌ%I¨‘%Á¾^òo†œ`:ü~ì�·69³éªÿÑ¥ Í�ò!χHÆR#ßM¼¥¶6µ¥sw/_ï;Ï4�*g¹Ûß%,ÕŸÆWÑ‹|6{í PÆq.Ù[Ëôm¦·*k{Yib8t@]^i€ŒÑëD:;¥0­øØ½]Eõµ¦­wk߀…œÞ¡ihÚ<„!)?˜fí7 ®–³éäÁ¥aÊ]»ƒþ³åðž£Ñ)qzS°ç éçU‹�8…KHJ<úV¥ÝîÅ,ó½=ø¼¡ý>÷13§BLÅ`’ÄðŠ.Ïý±ìRTA`°fïî czêÑ¿ÿ×)ýép'd´AT‡¬ï)D�¸=§Þö¥ÑG kŽ63`Ò—}¥†++ɽÚ$ãÒà™iŠ¿—õv»¼!º2¨€-õWfÚ3Ö>¤æžn¤Ó3rÓ+ÃÏ¡Î>¾¶ÜÒCÜCRo_ ¨l­‡Ì ÓêÓ÷ l³rbÆÆâ ¢ã é ã %R°IÒ:†o}'Jß¼¢¶��9\–Pa N<2̦ëKVT/½æ2 BÐ+B¸å€ÊI*Ë"ÍáÄ<6)%¬+ Ûw` …—Äœ Iibb/_Ó+»e€=ª¿ª”Ö–wǶ10¿oôŸ¿zßDd5g]î_tW^SÖøüNuÜ�–ªÎë!¨þ³á[ήaÐöÎ3ævn57\¾{­|Íæív”?ä©XiŒ®-$RMVf€�ªŽ·ƒzz,ð7dµÞk¿&€Íö"rK¯�©a~ÕŸZ O”  z Od&_]ïúKWCiE�ðåÔŸO¬'È#%É—«ä ®ÑTÝ¡”ĤC¬‚€'³S]Ðôð¬×ÉœtSb7�ÝÃ+„²ûú ­Ó„ÜÊÌYÙâ7Í�AT[rP—Ãewg´ÛÏlf�Ý,„#+dùÊf·]Ï:•ËI“»À©,ZðŠa89,âý!†N;©?sN>â²C°G4Ízf –ý7³2ŠØø"!T¥[ËÌw©ƒIÉœ¾…¾s¼bèóKž½2EøÎ@¡<t€c7>h�³9¿L;�Y�ä~vûý‚¬#‡3ØS�Äñý{�‡2;„†pþªøukäQnn $Ò[HÝ3:à}§.VV1ùjŒ�‡·45ؤ¯L/e�Ij,i‘L^ŽÞqeƒÄ ´1ŸS4”Wpiß’è3÷mó6l=—ÊF¯!öþÔšÐÄÜé̼RËÕ\Éí±|>L§ã“÷I`½÷ùobæú>z Ds÷“¶*¿Íg¹cõäÒÂ[{!4ï5€Î ê57@5™¥?óýi¶6ëjåmæq¡‡3‡Š Bb‚“E¥GHØ¡ø½ldBtT‚Æ4ç“Rt^@‰‹ý಻€[¨°Àœ�›?'4ß+| ]š“_X�­ ÏÑ "f 5ákŒj 9î+ ©8õ’|dBõ¢’‘vöØ)¶îlõe#÷OTª$àhQ鿤ܱC+´WªúÈáL¦è¶È¥5ºv~R;^ñ jž‰ OGƒ¦þ—¤j i* ìq¾™Ùùái17Øñ‡$¤¦d˜Â,‹щ¶²ËÄiÛŸ¢ònêŽ[SCçÜV+ÝfÛ̘©E^jŠ£¼†e:´¬à ”’n’ß‘O¨3ûûÂsƒ÷}Þ9˜ C#~"‡£ñ+ î%�Sܘôù?+îo¿×ûBâбè0‰O¡Äk0}šfÏü7Óý…X›ER®Ú «óe>sPØÆ2<C£¿#ÿø“—Ò/’Œ‹Ïµ ˜³õçÓø^×l´ÌBbÍcë¬ÅîGìÌ£Ò2û_W’Z³Îjáãè:ja[‡˜ö%¶€f}³Á*œ´ <{#°4êt�äG_sC_-ÈÈ”§”’Z@ôÖ}ÅŽ£L/•ðñà*&ï$kt -±]NnY× j”qè_~ŸÓûˆ·å;\üžŽ‡#în¥¦EØ:�Ù s­RAHjj¼¤/Ë{™|[ÜVz�/¿zEœ“í°q”P5 7<¬Õeö*=Ã=˜�üÙ8’¦\g�°¤õ±ªOÐÕn2ÙÉ:V§VÕ ¤Ê®qZa B?þ\3+÷-EàŒVz 7]D—s£Ñ Pj©ÚëB%—gDy+$¼�z8ÌûÌý´<2üô¾Ðˆò["lhŸè†ùxiƒ7y›ÊJˈ+ÃÅ[åØ"€º‹ȉ½”L¥Ð(ü´ Ê¥vQîpèäáPÕ°ÇW™‚ulž"z>è>:æ #¦í#w‡-¯ü À"iβŸþ€(Þ<€Q ë!�„ê(‰ú\�4H 4ƒª‘бXË;DHG�¡Îj|óê!õ°úE ¬çáŠV¦Ë`Së�ζù”bQJ@ ؘ�,G§ý�­3Èìy¶‚–üwˆÅûP<4Â8¨ÆÂ@rˆ²�*¢òVª£ÒYÑž´ÎÃ5æÍ ’™a¤yмUrÐ)&$6må›Ý¦NGØš›XÝü7`§Çß»Ë{3`7Ý´‡nàþ`Lb‡æ endstream endobj 240 0 obj <> endobj 241 0 obj <>stream H‰\“ÍjÃ0„ï~ ›CñŸ´jÀJÒBý¡iÀ±•ÔÐÈFqyûj4¥…l¶vG3f�¯·›­f•¿†±Û¹Yßw/¡sjÏÊJõC7ÿ<¥kwj§,�Í»ëyv§­?ŒYÓ¨ü-.žçpU7÷ý¸w‹, ½ ƒ?ª›�õn¡òÝeš¾ÜÉùYjµR½;D¡§vznONå©ívÛÇõa¾ÞÆž¿Š÷ëäT•žKšéÆÞ�§¶s¡õG—5E>stream H‰|”yPYÇ» ý®FÉv &­ƒâpÄ *Ã"$ ˆÐaftäŠ×ººƒаÈ!ˆº ЏZxÀÖŠ8ãÍ.º*0*×õ×Ù‡UÛkþ�ꪮwýŽú~?ï‘„µA’¤låÒ5K"ÜWåéSâ5ázÝ—jíÖ”]šÆ²;�““œÌšs±gB±ÑÅúÌÿ¨Éqæ¡ìw„¾‰/]&Ìu"¬H²¢~‘.ƒO‘¼9›�™èÆúxyy±Á]‚–Uçeek·f±ËÓuú �>>[«ñ`ƒÓÒØËñ,6B›¥Õ,‹ë<Ôl8 =› Õfy°ÚtMJz²ÇçîØ”,6žÕk“SøŒz­†ÍÖÇk´[ãõ[X]ÒoUó\¢ŽÌËвþ¬F›D$ÿ"+Â�  b¢!!)ALµ"¦“Ä,‚˜MÂך ˆy""Â(BmMD“„Ž ² BÅKG¬"‰ âq�#Ér'yÝÊÅj¡•Q€ëù‚*A»à½u”uEPë©NÄ¢ d@­B;¡�°V$%ŠîÛ̲Iµùh»Ð6Ïö¢í»5våvö«ì+ìÁ!Àa¯C7ÍÒ‘t2]–tro:IþïÚ)(±æöšÃÇ÷"0ânχC #Ìâ« X&ã…ã(ö—1ÌÇüq]Œe„-3zÜ•æb PœCÖA˜`ļ€Ù˜133øÁ!iËí¶±Ú!�oÌ2�·Gf^ά Ã’b%Âëzñ¤îyŠ(ìu4L‚Å2Xv ¤½?+>ËGØ`[¦{ ˜RØ ‚¨• YûXáƒzÜ/ãIx‰ /‰ÆÎa³ô y¢C˜bZ{Û€¨ÁL¡4ß?cjÆ]>ä˜-qsñtS{GZClÜ–Ô�±õ)mJ:´`„Ë!›Àôà(€Š¼žò%�:Xì�gÏÁr§ÄÑ¥O° ¸É�#ÌÒ¸gàS¦�¶gw~jöÁîØ+É7XA‡VÌŠ ÀN°3+¦!ìTåv7©2D‡–˜¸MïHåKq9>^&¼~™ôa`„²ÿ.~…]BÓµ1Šf?êT㥺nù`}T¸²x΢ ü%ž2‘4XÈ÷üö ƒxŒ„ÿ€“€ÛhV0ø%ŠÇO)ã©Zc‹˜kÑ ç/IX®>þƒN©÷ r›zrÈÁ÷½ &Š»ïŒCà…§|R!úMÁ(·g”l g˜ø»“�Db¸á(Á?3xW¾{<ÔÊý£ ¶] È@Ö 6¼¾Ž=Ø‹ñ”eØ Û)éßó_Ã7?[¤ͯrBß«,>)þ úr§²¥¹²«WÖ“y5±QѼiÅqoyÀêÝ߯ò€ùñ€U›äƒ]‰ÁAê�žúÜÒýëé— þ%kâgoi8}Ý-ª×UúVÌ=y8GN(¿&ïѶíø{zGt…È(ì=qãÆsY·¡#©^qvãŠòYòÐ¥»¿‰á+ÍeŒGN[åO®lYç¯ A´o¡‰+0¥æ8uÁDX ÅÏ70ÛZ~ʹ'‡à�a _«o`›v¥w“¦ºKv®ñü£žŽÜüS q{Ý;JüðØæõå!r<ÃÓ Üû×€µF9˜Ö´5J—¶ºò¤FAð>ÞyOBŒå5ŒáåîÀú÷ã\!Ñ7xGþ™CÞåemä÷ïò|ŽK„x³É¼@õq4 ŽÁŽã“…Xº~µ�ä-�*¸ÉBzw ÐÓ-;äߌ ÎJ;- NBnø%nÉ ÐäÍ¡íO³gzÂM)–!Hç9¤óymÏ8ï²’»"àú%üå{ _Ã� Z„•†„�[óâ-ŸÝѸíB(¥x*‚uøŽÁ#LAÿYmWEsy+Ïq¥æxr݆{X&¥JƸÔ1²†; ¨‘pÆð[#ú?ÑUÕu†;�Ü; 8<åf,™kïµ´F„qM¢«‘%1jªì"UÙf 3̈£0 ‚"²(«ì2ƒâŠU—Ú6’(‹ˆ€¦iü®Ï™>íHžþ¸νç;ßû~ß÷¾çÂ$—G<´Ä/ƒ{4cQBgÅØn)¨žLŽ:\À5õ;ÊÄ}]¢7¡³ÈÝÓ_šv€9»‘8]o>ÙC�%±ì—´]‹xþH(Þ|uëÌ�Þê–Zæ(IeÀ'óêÔ�bÊ„ìúDªBU�Š9(?»‡Þw¦çoß•�jXašbÚWʽÿ¢Ó0Û \kÓ,QÙ{Õêæß$eÒ?ž²£ñZÊ_iø%ðG᜵ëgÑBz‹$.ø«†NdO‚½åQ©Î +fúŒÝMfúÛ6¯uÎÁŸyJ›Ì9¬ºXSR"¢ÕÊi¸÷²Ð*‰X])SâTô‡¾×_±ãškC/èÎZ•² â™I,ˆ¥ !%¡4Ú´è}ä:»>èï5–žc…IŠÙíRnù”5ùFܨÙ`�[ò6H„jÕ‚¦´ êí4²]æ‚>Ô²ÈeÂlïßlè«et˜!½'ýè{1²'‘L“yD΄Ê"…ОƒßÍöÞºÜjd�*µ ¹XxCqz… ³vS †3`õž.Ò¨5˜æ²† =ô½s^,ª¶z’Ü×^ý(.þKY2“œ#ÍÈNµQCn&!ú‡ÊJï9Üýcš„�‹¹,\ª,õú6×'j¯®kb[4Iµô¾„ø¨Õ‡ÚX«õá}P0—vZÛÁþ?Aø´ d› _µb ÀöµÚÀ‚äL¢…h•Ø@#b«Ïº�§bÙ[iY1âØ”Ô€0É×_%⿊båk¸>Á�Eüî±È}ÛÊ!”!ð+ ­N`’+›³»é–zýñrV=I‘É5itpVÝ-K‰í²…_ „QŠWÞÖv¸ƒ~�±vq. ÷0ºDÊÔ²|%+�Åúä›ty˜…r¼~Q€Ö KÆÆzÌ §­òŸ¡ßB¼!Õ­êžb¡s!,p™‹g಩D>–,‘ð—E é� ±5æ„)¢T‘6¤ªUyQÖñG(t.u•r¯Óy'¸,þ ëFoËnâ˜\››/Î+È=¢b2câS³“'+¤ù5¿w¬+2Ÿ2µ_7w ‚/¶°gŽØx7!£2Nõ—ÜD윹ՊfeÝZ(s¢U…3Ð9ƒ½Ö�_±˜s›AÅ:²ê\eÍÙZ؇[¯…Z�œ MI>„üPNbÿÉ«ãüùuÐ-òàüñoºN âµ€Š«°B \¹<8(¹ìã ñѲÞWþ|—* o×—¢ Rp5˜K,)z’óÑ#?½%ÁÐ¥¯Ò æ_‡`¥Ád°¤·á|õÈþu­Þ–9î¥*û¯�íİ_öÇíií„ x—ûAô?�Âð endstream endobj 243 0 obj <> endobj 244 0 obj <> endobj 245 0 obj [/ICCBased 246 0 R] endobj 246 0 obj <>stream H‰œ–yTSwÇoÉž�•°Ãc [€°�5la‘QIBHØADED„ª•2ÖmtFOE�.®c­Ö}êÒõ0êè8´׎�8G�Ng¦Óïï÷9÷wïïÝß½÷�ó '¥ªµÕ0 �Ö ÏJŒÅb¤  2y­.-;!à’ÆK°ZÜ ü‹ž^�i½"LÊÀ0ðÿ‰-×é @8(”µrœ;q®ª7èLöœy¥•&†Qëñq¶4±jž½ç|æ9ÚÄ �V�³)g�B£0ñiœWו8#©8wÕ©•õ8_Å٥ʨQãüÜ«QÊj@é&»A)/ÇÙgº>'K‚óÈtÕ;\ú” Ó¥$ÕºF½ZUnÀÜå˜(4TŒ%)ë«”ƒ0C&¯”阤Z£“i˜¿óœ8¦Úbx‘ƒE¡ÁÁBÑ;…ú¯›¿P¦ÞÎӓ̹žAü om?çW= €x¯Íú·¶Ò-Œ¯Àòæ[›Ëû0ñ¾¾øÎ}ø¦y)7ta¾¾õõõ>j¥ÜÇTÐ7úŸ¿@ï¼ÏÇtÜ›ò`qÊ2™±Ê€™ê&¯®ª6ê±Z�L®Ä„?â_øóyxg)Ë”z¥�ÈçL­UáíÖ*ÔuµSkÿSeØO4?׸¸c¯¯Ø°.òò· åÒR´ ß�Þô-•’2ð5ßáÞüÜÏ ú÷Sá>Ó£V­š‹“då`r£¾n~ÏôY &à+`œ�;ÂA4ˆÉ 䀰ÈA9Ð=¨- t�°lÃ`;»Á~pŒƒ�Á ðGp| ®�[`Lƒ‡`<¯ "A ˆ YA�+äùCb(ЇR¡,¨*�T�2B-Ð ¨ꇆ¡Ðnè÷ÐQètº}MA ï —0Óal»Á¾°Ž�Sàx ¬‚kà&¸^Á£ð>ø0|>_ƒ'á‡ð,ÂG!"F$H:Rˆ”!z¤éF‘Qd?r 9‹\A&‘GÈ ”ˆrQ ¢áhš‹ÊÑ´íE‡Ñ]èaô4z�BgÐ×Á–àE#H ‹*B=¡‹0HØIøˆp†p�0MxJ$ùD1„˜D, V›‰½Ä­ÄÄãÄKÄ»ÄY‰dEò"E�ÒI2’�ÔEÚBÚGúŒt™4MzN¦‘Èþär!YKî ’÷�?%_&ß#¿¢°(®”0J:EAi¤ôQÆ(Ç()Ó”WT6U@� æP+¨íÔ!ê~êêmê�æD ¥eÒÔ´å´!ÚïhŸÓ¦h/èº']B/¢éëèÒ�Ó¿¢?a0nŒhF!ÃÀXÇØÍ8ÅøšñÜŒkæc&5S˜µ™�˜6»lö˜Iaº2c˜K™MÌAæ!æEæ#…寒°d¬VÖë(ëk–Íe‹Øél »—½‡}Ž}ŸCâ¸qâ9 N'çÎ)Î].ÂuæJ¸rî î÷ wšGä xR^¯‡÷[ÞoÆœchžgÞ`>bþ‰ù$á»ñ¥ü*~ÿ ÿ:ÿ¥…�EŒ…Òb�Å~‹ËÏ,m,£-•–Ý–,¯Y¾´Â¬â­*­6X�[ݱF­=­3­ë­·YŸ±~dó ·‘ÛtÛ´¹i ÛzÚfÙ6Û~`{ÁvÖÎÞ.ÑNg·Åî”Ý#{¾}´}…ý€ý§ö¸‘j‡‡ÏþŠ™c1X6„�Æfm“�Ž;'_9 œr�:œ8Ýq¦:‹�ËœœO:ϸ8¸¤¹´¸ìu¹éJq»–»nv=ëúÌMà–ï¶ÊmÜí¾ÀR 4 ö n»3Ü£ÜkÜGݯz=Ä•[=¾ô„=ƒ<Ë=GTB(É/ÙSòƒ,]6*›-•–¾W:#—È7Ë*¢ŠÊe¿ò^YDYÙ}U„j£êAyTù`ù#µD=¬þ¶"©b{ųÊôÊ+¬Ê¯: !kJ4Gµm¥ötµ}uCõ%�—®K7YV³©fFŸ¢ßY Õ.©=bàá?SŒîƕƩºÈº‘ºçõyõ‡Ø Ú† �ž�kï5%4ý¦m–7Ÿlqlio™Z³lG+ÔZÚz²Í¹­³mzyâò]íÔöÊö?uøuôw|¿"űN»Îå�wW&®ÜÛe֥ﺱ*|ÕöÕèjõê‰5k¶¬yÝ­èþ¢Ç¯g°ç‡^yïkEk‡Öþ¸®lÝD_pß¶õÄõÚõ×7DmØÕÏîoê¿»1mãál {àûMśΠnßLÝlÜ<9”úO¤[þ˜¸™$™�™üšhšÕ›B›¯œœ‰œ÷�d�Òž@ž®ŸŸ‹Ÿú i Ø¡G¡¶¢&¢–££v£æ¤V¤Ç¥8¥©¦¦‹¦ý§n§à¨R¨Ä©7©©ªª�««u«é¬\¬Ð­D­¸®-®¡¯¯‹°°u°ê±`±Ö²K²Â³8³®´%´œµµŠ¶¶y¶ð·h·à¸Y¸Ñ¹J¹Âº;ºµ».»§¼!¼›½½�¾ ¾„¾ÿ¿z¿õÀpÀìÁgÁãÂ_ÂÛÃXÃÔÄQÄÎÅKÅÈÆFÆÃÇAÇ¿È=ȼÉ:ɹÊ8Ê·Ë6˶Ì5̵Í5͵Î6ζÏ7ϸÐ9кÑ<ѾÒ?ÒÁÓDÓÆÔIÔËÕNÕÑÖUÖØ×\×àØdØèÙlÙñÚvÚûÛ€ÜÜŠÝÝ–ÞÞ¢ß)߯à6à½áDáÌâSâÛãcãëäsäü儿 æ–çç©è2è¼éFéÐê[êåëpëûì†ííœî(î´ï@ïÌðXðåñrñÿòŒóó§ô4ôÂõPõÞömöû÷Šøø¨ù8ùÇúWúçûwüü˜ý)ýºþKþÜÿmÿÿ ÷„óû endstream endobj 247 0 obj <>stream ÿØÿàJFIFIkÿîAdobedÿÛÅ!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDDÿÝ5ÿÀkI"ÿÄ¢   )Q!1AQa"2Rq�‘¡±3rÁÑ#4BSb’Ccs²áð $%&'()*56789:DEFGHIJTUVWXYZde‚¢fghijtuvwxyzƒ„…†‡ˆ‰Š“”•–—˜™š£¤¥¦§¨©ª³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêñòóôõö÷øùú‹!1AQ"aq¡Bb�‘ð±Á #$%&'()*23456789:CDEFGHIJRSTUVWXYZcdefghijrstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÑÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÚ ?¨¨H¨øá»¬¦Úw¬Z�±ýÛºÊjTô*áÖ�ë”9Þ° ‰ÈÖ�¬Pãëš”.húÀ%´}`S— húÀ%´}`S�Ú>° mXÔ¨8:Ñõ€K'Ö5*áÁÒ}`Éõ€MJƒ‡`NÂ{±Ô¹Éõ‚éLZ¦ö npäÅsAÅŒY>°K%"T²}`–JD à²}`–O¬D¨8,ŸX¶�¬D¨mX¶�¬D àëGÖ-£ëš•t´ïX¶�ë‘8u¯Û>ªHbR×ßýT'°CBî23�GF_C(ÏRLËx‚êÁg&q8×x�æ[y+›îo2W½2Mq9>L|Éê +ð…6°÷ “÷=à¡>÷Bí_ål^â+7�4‰w*ë8‚kò¸Jobºà‘ƒ:só­Nbüa< "]Êžì6‰*ocüqõGw”VŒê_cüsõGw—i½Í8–­"$^xÏZiWR ž2˜네€‘¡8„rF�€.N‹ÐBFEéHN! &8�ðZ`Œ]a Ù™²o&ô�R£CÉ2@’o]+Ðe*Œ $ƒ‰‘§RuQCfhdlwZÆ1½&P(6ˆ¾'¾»‘›UêÌ�–S ³/™ÄÌ.T†â§r˜BëLn*w+—°º˜8 C`LÌçE‰k� Flåu)4È�鈿�sy/qtc£ÂIœÀHB|$‹ÐHl\˜ë¡HŒr@.Np½@\™¼ §z{ ïpÍd†™�` ìœa!SróDå60ë[#­àZx :‡K”�Â$ΜR¤ä¥ ‡F%)ÁNÉ’ŠUƒÚû[ µhvÛ€#¥‹Gc6n2cYºÕˆâª[QqÌŽOäÓy\$\™‰O8$Dv ¹ÇbšœR �Ô‰ÉtjD䈨J‘tèÔ‰Å"�HœR èÔ‰Å5tèÔ%)N‚„!)©Å5�ÿЧ©ÛÝ»¬¦§Tí�îÝÖSR§¡W ¡*áÁBT�* ¡ ‡ P„*D«€*T%AÀJ„ àæ’Ò.!u²Ê·´†;;N…qO°í"Çízº'”%Úõx=!s²áˆJ$àƒ–åGM¯[ƒÒíjÜ‘áL²í‚1] r£¦Ö­Áéí«_ƒÒ<+ŠsX÷˜h.:�rÜ«du-~Hð¥Ú•ø=#›°Wà9.ׯÀr6 Œè­­ˆí©”pzG….ÔÊ8=#›µòŽ’í|£€äFƒ Ñ[[ÛO(àô� ]§”p:G…7ke%ÚÙG•¹v4Éѧkb;iå<‘áK´²žHð®n¥V�ïkš4�a4L¢Í·*Ù}r]\’»Ÿ!·@Î<)ÁŒ¥~PæŸI°Ë�̹ԧiÓ9‚ABp= »«^ÉJΨûd†´`„ÒK±]Näl$bz-;+.ŒeY0¢i`p¸í<¨:v2oÒ<)�¢ìZMÙÅ˸9XôcùÔ¯¾JíMÃVår\¨ˆØÏG… É2¡è³ÑáK²å#Ñ®çOÊÏ£ΈZ!5kº£G•;èð§m\«ÊÏG…=®Ê„—=ðâ�”eàóÓá]…¢rj×uNc#ʇ¢ÏG…8ä™QôYè𮢦W¤óŸ l©·—ÏáD-˜Uk§!’eBíŒôxTšT¶“^´lŽÆâ¹ õܶà@$NeÅÖžeĸé7®Ø­Rê¬qàa$¤'ÙE•r7'YE”‘°…ÔQ¨á!¦hTD¢a,§$�Ÿ„‘‰Ž…Ö/ €˜æ×:ð%tÊ*Sªæšb Aº:“KˆhĘ ΤúNhx‚L�Ê»ˆå’ž3‰c›¾qˆ])o*w+¾Vꎳ²2ÄL_+•!¸©Ü¢!„Í2rËZÃ6-c M–6£ˆ˜€F>àe�cI¶ fA¦H¨ê�Åí‹î�ƃ³µ±#”ÕÒB‰#™HŸ !F$)ð’ÊÉÏÓzèZ�µp쌔Õе6Ê�)%:ÊHAѨ”°ˆAѸ$)Ð’Êà ”‰ÖQeF(˜N²’ÊŒ8Ê ”ë), $],¤²ƒ²sHºYIedæ‘t±­%�h 9¤],kE�h;'4ÕÖÆ´–5®�“šjëcZM�ZÉȤ]v=i6=h“²ŽI«¶Ç­&Å­vNÊ9!tØõ£cÖ‰;(æ„ûÒXÖ»!(iM] nL„Lÿѧ©ÛÝ»¬¤ jvÇ÷në)Tô8…J”.(H•pà©BDä© à©RåÀ• Pp¡*¦7K°\©ï—Tb¦Ó4äÚxÓ˜˜ô8nJT�Þ”9�$œÂ²{Ù’S¢IÃ^’U}=û{¡Ö¦eØ3Œ÷�®g*¶ªV!»}üÎS¶ûøœ¨iQ,0)ÈLöPs”£²à7œ¨IWeœÀ§!7ÙEüó”áÙœó•'Œ&sœ…®M• ¤šOhŒ1(9E!F³˜ÜãˆÞºd8Ë“²Ñî$ñ5uÛLè�YÚÚWAÊ©!×ÁH �W8Þè�qåÌ¢‰·l‘!bbá�8…!¯¢(9¥—ÚmÖÍð ë‰n4Hp�„òap�êTvI$À ¦Ö§¯�?'ƒÝ.…I+:œ�êÐ šdg””è6ÓŽ8¤VíNâ異ZÒæÚ3ÂäZw àœLÁq�Tz´ö3¤g”9ލâÁäŽêfT,§ñ”T í7B�§šJ�hÒ�¥%$ è€0 �'PH¦dÕ²vRª×Ó—PM²-n…Ñ™D{š\K[e¤ÜÙ˜å(jàM¶Ô\5”’‚@‘’W%´’Ò‚DZIi i%¤"KA% ƒ¢¤E ’Ø@[[vH’ØÐ’ØÐƒ°*D–Æ„–Æ„�P›lhI² ¡ rDÝ�hI² ƒ°Ç$MÙ„lƒBì†ŧ—ˆ7.r‚IÿÓ©©ÛÝ»¬¤]�L[tðÝÖQ±µ)&þ9©Å°ë:WAM«‡9§Ó ó§lmÌšÖË£BJgiRlmA¦"Bá™t�¹1–¯+¥† ã€y9®Ç2/ Í`‰( |„×8HŒÉl54¶ iAÄuédiL ÒØjX pµ9—PB亄ðÆ $‘„ Š dŒm¬PrÈ:‚÷ 1œ¤Ú‡0!tå‡J.‘œÖ¥å,ε�0K\t޵/)`plæ•Õq]Q„ˆ• _®í{\$ì²D_*C2RD�z‚¸„:Z1#�r¶6[Y°]ÆKK9<—§Ðc¬†‚uË�6 °FV‹»­íüW®‚›±7q˜@q76x…ÝK¦ÕÊ$Íf×zêDËL–‘eBâàfnÖ»UØíî�ð3Âm ’¥'ì•*"È“Ž²ºT£’¹öë\s@©%aÖËvb8º¥ŒÇV>S¯N CcPÖÎJÁ,£1¤êNNeQÖqXï5¢rT\ö,APœ/õµ&½õn c�®òí³;Içw„.o¬æß.3¬÷É]ØœWÜ=†«€6{œ�/‚9Ò5ï€o]Zƒ ]"ô‘å$>"Bî*±Ù�åH즥 Ç1®HõIKh?}L m¹x¬�&-ªYÍžTÖÑpyx!Ív„»R“»[¹ Mm Ôßdi·&È%[fv¦"£fëÓ*½­.¾ù7.ìq´†|W:™;K›Œœ¢Ë¦¦Ó…4 $Åë¼·Hç\™“É6³fÀ§ìôuÅ'\HÚÎim�d’ŸIí,`� �J!‚ÓpN§A¥¡ÎÏ™ÈYYn‘θUx/m›ì®»^ž¾uÎ¥CŒ (s)‰$Ós\ Ȧ—4bG:)Qk³’Ø)§'§šB•°FÉdZ„9åà É�º9–\Zs$…Yrv „–KœÑ$àá–<8b5Ìs 8AMtÙÎug‰‰0Wdïl‚EÍ.æDd ,·�¯[f‹¢'<â™LnÄ’é�Ëø‘{ ”#�–Ù5 ¢3Bi5)‡S2ÙßÐY-kXËk}7jC€m¶ÕÕ‘p\;'SuBCqž@¹�§dï§h�ŒH¦éu£}×ó¨ÕÇE†XŒ`“<èjÉ:ªrÔHM!t!4…c©T �ì èkRÓÐRQ¦×Kœ&.u4ÙÁ˪`‹jHµªµÍ²Üø””ë5­ uÑ�t¯I¡–š � )Re€â$›ï\¶IJÁÖ¥§ ¨õ³=¬fr›¯&³Mœ̆lªSˆ{�PC­ŒÁ šV¤Û+ª1ÔÞênß4�xÅÉ„)ÙuJ.«U�¢ñQÒûD“ÍÆëÔ"¢Ô2Ê\¤Ýƒ iO)¥p˜Ô‰ÉtjDä…F§º‹ÙE•ÌX¨\}òÜRÒsP:£V‰–[<¡YUÊ2Q�äî9+KKêÙfÈðI�k©&�¤j©§JI¹z‰N‘=ÄH 01�Iª$ƤNHƒ£P•"ˆ‘*D‘9"�)ŠjDŠCX؉(²Ý„FHWW°3§Øh̺vHÉ¥J-iÌw‹.! �NF$)RÒb!]:58¦ ÿÔ�žüR¦º ¶éá»­#RpnÃÛè¸K­h]F :&·~ä›#s$k Î•ÑyÙÐö¤/`u=êzäÇEÅ>ÛP ýêxÀ.NtÜšñPr,:$vù©-µ!t™Ð€:¥ �á-°‚0~x—EÄ;u+ {WA�IOÆ›lfKL™€&t æ#¨C·¥>ÀhšŽ Õ‰J* (²O È#"Ñcˆi‹®Rª†˜µ'q¤*Ô8„[s)€¤–µ÷p7Ù ò)"º�¤wÔâ!—è´åÙ¬«WxÒF“‡x.�¬iÜ1¢0s·né¸t§Ú¨ýû jݘ °EÕ“TA“šµý74dm« cª¾5‘Ñu  /-5¥æWVÔ^†€Ð¥ Cq+u=Àh}p!Œm!®æ�‡)~/Ž-Ï�t@Þ65›ÊvÈÓ¾´zB–ÄŒ¼ˆäÌ•” }»O+³i1×–’tÌ…À‹-»°Yh ©"5Tïwœ¶­7-ë'¾›’Qhˆ»�u”«°²«+°Ò:zÓ_@¸Cj9œ@z¥Ñ,®Â9,ã°¾.y= ¥µ�¾yR¢ �\ó²4[pÕëÒIÎRÆ:÷HÏ�0ÑDó®C%„™Î5s%§TÛsmcxMy4ñ�7:äÚ„:Ó„Î:W&Ä¢sl’¸êÁ#�i&#X\©Ôcž�e9Õ¬8ƒ8ã™JT‡#©¸Tl’±rRØÆñ¥ 7·rM÷`Q²ë¸�8 æ‘ΰñ3ÈžÁ¹A%kL· 缆=¥³F #ÜCÂmGX v|É6jzù—*�¶àEÀ`†Á'$¡Ÿ‰$&²«\b”†³5žEÙG!‘ë<�Kœ.Ž%Î.Ò‹Ðy”bp‘ÎÖ[{[„çN-# ¤_ráÙVžÂð“+«+–­†ÜÃË…Ë›i¸¸Z$JZôØÇÍß+·[ˆåŽ¿(e4ƒ H�3p¹0n_Ĉs´ž”ö5Á¯�D…ËÙÛ”I4—.$Âs¢�ºoÎ1œ¶0Z  %ÑÆ´)‡Óé�×�p”œHO!! $Žd$!t°ã˜ó&–‘ˆ!S:ÐÞ5Шì{˜n9“öWp êviÈ•»[�ÎÖÞ%Ê­G8Y"ÈHÊŽh² ¹6�Ápv*6SƒxÊèj¿€Tz�sÍ÷FeÆÉRœœJiO)¥D´aM)å4®C D⑆¤NH€ƒ8fJR.‘8¤AÑ©’ èÒ‘9"�Hœ‘5"rBƒ£R© �Ɖ �¨@ŒQ²êAÈaS|Þ4õÅÎ.2S…GÒƒ±põ¦ü®†£‡‘\I“%u¥ HR”‹¤Æ¡*,»Aæ]:!MN ŒSPuÿÕ€æ¶Ûˆ¾\Lò¥�¡A â !$nËE°3Ô3&ø]@9“ZÑhƒ™=5»ç æQà -%Fd�%>k7©è5ÀD§5 ŽÞ§ s°\ÛÄgN ¾883'@Б=¬s°i+§Ì4ZŒË«ZMÍ€)5×›NÐ0]ZÚµ.h²5\ƒ��ØØ7æN�áN¦^ë©¶ÀÕ�:xm[ómÚþ©v¤2šÃÄÛ±7N~r»V|1ƒ'kwUˆo<Ø®€6»„Ž`²B%sÆäëMÒ»' |¡6BT—#B™2j̺!›Cl�`\žX%±~ ¡"…:VoÓšd.° ΂¸ÑØÐWQzê8ï$A¼&¶“Y†:s§‹ðJºpK Ð9—'Ñ—K`Šì¹Ôß0ë\hr=¬kD‚Æœ@æJ…Ó‡l ¨íXr®Ð˜ÞØî ž¸Ž±�l´ƒ¡D�éÓáS\a§ˆ¨‡Èêð®TJ‚Q �f‹ œÄ.ë•{ÙH]w¦ô8†, …<u$‹×�Z›I`“}Ù´¦–X¦ø;—E“øwSsï½"ó¥¥TÒk@C—"òj«”•ä'Ñd¸º.oYO¬ÂË-16oŽ2º±í²Ã"ìn½E+Iº¬°B˜à ç]ˆñO«wÓDZ3 õØ"™ƒDža<£&‚ÇñORx‡r(«‰7k#×°� )¶Û±]+F×:Ý ÔÝ©â/�r-ØœîÄäæ–’Óqõ)h¹ÙðVp~Q"ދψè.߸¨~²PÑÚ= M+½0 *Îf]ç‚h`yÏm—ò9B ¤àS �à6»L_²:ÿª„Ú  TˆµÓçŠäOq8†9áÅ¢CiÚ„Ç}s‰ÁXŒ¡´XXYLÚÉÛ²I$ƒèQêÆÜ¸6FÜ ÈhM·f‘ ÷aŽ¬ÉªOÌŸ[Ñ�smw¿dmüŽ\‚IœR.Îk°Ååï¿‘©*€J3°Ïž(:žâqH»W=°#ÄÙê!9àmË0#e3bgp#$]érˆ"é}Ü…2�T›â‘ë;'(19†)#ø.Ìí5~©Ö’¶ö—¦‡©96ÁÅ"íXP#rÏQ Ð6嘳Dfß.�ÀŒ‘v¤¨A¿rÿQ)´À-©9©÷ÂÉÉ!]ZÂóœ9�ô„ €û!¿ê¡gq8¢É� ÉÁux3¤:yÓÇn£Ü3¾ºvw=B0@Ö»¦Ð‹fs1ÝEuhÜ¿¹apåNÓšŽñ )`x›�šo}p«ÏmÂyºŽÒí8ÕÚ )ëiŸ´JäÃ+�¨Øó1¬ÜœiUp‘ Àq™]ìQÏà†ôÏ�9Í€ÓÂø\‚xWêSªDºør̾ ~ùÒ2°s@·EÀr£±�·�%Þqä4uUaÊÅOÃÅq¿ Õ¥ÉͨÆÙ;ÒARƒƒ€'�b耒+;ĂƋÞâPDVì`@Ý'‚ó½0ö‹©¶P^ó¾pn¡ê�´Ç¹¢7nŽ’œÒØÜ‰ãKK%«Vû$îØ©ô²*l½æÙуy‚êM�ª´±É”êÕ0ÙäÁK¥�4A¨dè( †€œ¤©)«4në�k4Bzâê¬f³ ./®]vmáω]˜!‚Ù)ÕZ.¢4`8Êâê¥þkV ð”ÆR©R-n[˜‡2’Êmf�%°±h±�¤÷Á~ º‚�Ö†áÏ�"cë±—L�vâ.YÙ5ÕXÌMú*#«½÷ ÈЄuQ”�ì¡î¹»‘Ò¹É7›ÊhJ$”$8'МpPœSÚ×<ÃA'@½tã% E<†£¯y åJfIE™­&õ5Ceo4¥h�Ç¿z â »rJ§oð)àp¹ J„VóGˆŒÜŒy'sñ“RO*ê^щ•&ÈÜÒx�R„G ¦ £Hy—b§ÁÈ´s4ôú%Ü”Xrܺ¡±Óà„›= ÒîJ- èð¢À´fÂÌÒl: ékH#“À‹mÓw"K9lnÓ`ŒT„"á“Ëu&–…è€� n8¦¥@l:BPHqiĨ8:A¼!4Lƒ˜®œ) é@è§&Â[!AÆ\€’O,Λ®3¨ê™Tˆ ÒRìcI\ÜË7âÎ(“¬]r  @`•tᣅ±æWAº2+2ûC?ZFÓ²A›ÂŽ2vB:nˆ¹qs]N¥·D:å,šö �-9×Z8ª‚6hNÞð‹—F n]2tMÎÓ¥A_i7t fOTZ&̸œç:æð[,9Šž£etÆÈ$ã]0¬9MRí#j<5¤Zº10º ’­€ÓffqõJ#ši�ö›Á•mF «MµqxÖ¹JNd•mÒ“WjÑ©Jè�íJZ‘pÏ�8=åyR›j±Ô݃„*�’VÏ`²ñsŒfŒë•ÓÌëNfôt¥AùE0êe¥ œ÷õ.›K(µj[¡Íx# ãÌ€¸` àœ±Ôͦà†Õ:ík’v1£²&é J` Rºpp2`š ÌpNÅ*fɃ‚réÀLŒÊj¡É¯Ôé �ž$ Á*m°S�@" äD\º’“™p/i¾WÔ=ŽƒWEʘ3˜.¨@ï8Öo’«�]ëÔ &óŠŠç´ ¯QªòtÌòz»%9;áq]H›Šã“SØéÉÅ×®ÊJå$*‰pVå,Øí76!?#©`†:W<ª¸ªâx¹6W_ƒ/=å^µasYËK% /¤MŠíÓpµÅ*j�•ÔÞÐTÞt4^T깕Q*¥H®{­¸¸ù"O:²Èël´ì�ó.ÖO…dæ‘t³O‡õ“áIeœ?¬”“šBºYgë%!k8_Y(;#Ɖ"©ÄZè(.§ÂèA›÷ÍãOLqa ‡a©:Õ>B dÌvÃÄž]O…йË-ZµŽ¤‘©ðºÓK¡NtðÖÐÞ!:zºFðB€!B€!HæµÂ éP€8œ²ú,ó8·™5Õ`†å,²sP:¸®ÉßLÛÉÌiaÁ#*µîƒâU³ÎŒ.N&v&Ôw—2çî›ÂþP¸T¦¶ËÚt.í©&ÃÅ—èÌxŠ ÚeÄâ<‰ä]jN' àë1n#RêLJ¶yÂâáaÖ€Ž5jÒï0ñës(̉$ ä)Zìǣ셆ÅKÆ•Öd è=åÙ8ÑÐÞš iŒÈž4¦]"8Q •í)áÈ��ð\ HNŽÁtkF9Ó’J%U3 ñL°0„®ß ÁœTIb:5¡¢R@s.{.¥ÍõK͘€e†Æ:ââ/(§I¯uâáyHSÙT1±gŒÊ�“ie±a%qÊe–F.êLTù•Æ£ËÜ\W]VXFš\ÚG{nEú–OHQ¦Ÿq¨m¨)›dZŒ °ËdMŽŸT£L+IׄÒJâ[ˆh.7$ª’ãS+mC䤢㠵l¤Õe€,‰¾ù\)öú|g¨¢ª¥£´S‚›wÃ&É›V iî*ã ‚¬¡•6ƒ,†I&I˜ï.žÊ>“úתE.šQÌÒšêwX޹u}†•†˜}IPÎU[ÑB¨ŽZ2ŠÎ¯”Û7n` a9€ì5nàu¨UVÙ–SN)cmNÌŠêl#\Àâg2’A\Y‹¸Ô “±�c4Ê¥6Ù$!w+›÷§‰p’gl¶�ò¥ÖhÚt[ZuÊ==àRjøÒ�—UÏH*½iîD Œð»äl»4ßÔ¹UÞò®ù'ŽËÔ¸¯%Sν&q¬Ñ³<ÅöÏZL°NQÆÖõ'Ví¯îÏZL¯Ç¹K™A^´Ž6[¡4µºÒ ™È6I2u–è@ß9*áÑŽh‹®MkA¼®‡ÆoPwYn„Ç´!tL©½@!ÁoAkt' D8½°@Óì4fC÷ÍãNAÙ¸act.V7vsÝs°ñ êw…†èMsFº$@IÁŒ’s'Øn€’ž�9t“vœª1¡¤‹¡pRªoˆº‰ÑqÿÒx¦ÜuœÁ8Sn´䙫,¯œ¥ f€„«¤G ISRŒn'¾ƒ‡Dª3²Žå+›ª=ûãÉ™w’ÝY�Ï'@\]”=×7r:W«’IR�²Mæô!:(NMJppN ©B Á4)tòXùI4Úw¬j;ˆfã+©IÒ¼åJ•JϱI¥Î:ŽO’1®€QTfôSxÎu"†H÷¶Én×£åc~î詎u –˜˜cp9:Ä•m4cbÙ¦jÞul�”òpÓ²T6êf9† 3&ÕÊšÒYH½»ëá�ÖçfâÅDÊrÇHcí0¿yB�õßÇÑÓ­-‚­`Wé‹Û“S¹£º9ÊœâEx:ÕoKkkLcjUÊjMx=µÂ)³¹ižs%K£‘1†ÝS²¼ÞIÂyqåä…ÜšT0cEÀÐ\â­}ôÒ§ÁxÈÃ’ýk©F‹8ênìêêû£NˆÙ1ÌÖñžö)BÑ®vG Àˆ`âo|Þºµ�cCXZ0䫱”„Åß\„.œ!B€!B€!B€!B€έVáxÀŒBè„qi¹Ô|O(铹~�]…SN-›TÎö¦Žë»9­p-p�qBsjdd¹¾)@ïšo-Qvi(ªÌ{‰5ÍkÄôôÝNC¯¦pwëJÇìm)tayg­Y”�ZöÈ‚Ò8ÁEúg-§H…{…ƒ¿nƄƽÌ7r…Þµ7·†­Kƒ·r|�ßú‹°ši¢K*5âëˆÌºJ¯-2.*M:Á׊ê¨åTÅÇ|S/,èKq] tê)Ö´®d"ÔcΉ;[HãÄ™:ƒÅò»' æL¢Ö¤§ã µ.rfWR¹Åê,’Ö¤Ç?RèSMáQÈ:Ê õæŒè*$Ž/tÝ‚h|‰]$q$h€¸KÂýE%Wg( §•Æ ¼q”VØ7d8xHjêRvz¼.�àHrŠÜ.�à\Øê�³!›EÙà®Ì¨NOUÐbX9d§mŠû%›WAºàIR¥Z�I: ;q,XÈæ©‡8gã ƒ\ZgRȸȺ;ê;’t.2j-Õó%r}BDD)s¨iÔ¸uAŵ DD…*³ã#¢`Þç.À œåImJ/¤)V%¶ -"üP±…W§2Ü]©wÈœNPÀußÈŸQ™%ïó¾©tÉÛ“¶«v'8ºø@Á Zvª– ±Üñëº+>ï&zÑ•ŸŸ2Þ¥"¨ÉöG9ÓhÈ�j-gŠ•­` ]ĸÎÓliíêH_©tH‚gH2�oQ@£©9péÉϺ"C¬®®.”ÄõÍΛ°]“* ¥†Àˆ”¥úŠsD‚ƒ§8“)¦¤¯¡­9Nf¤f\ímg]×0ÑlŒÁT ²j)®¨bá ²i  âÝr�²y’ŠcžºIÄœP¸DBä¤ÕÂt(˨�7ÿÓ]•­0ø˜8Œz¶V ê-¦¹Îƒ0â:K$oyŽ 3c¶væ¤5Üpt¨áÀ˜790Pò÷»R$J¸tT$Jƒ‚¥H…Ð*D¨8*TÔ¡9u¥Iõw·4bãsG*ë“duk:æÆs+ºŒcaÙA¶F 0rgS¦‡QNišÓF;H&JçÉ›'=w�Èî[ë%mC#¥@Û3R©Æ£¯>©+òŠtÎÅL•º›‘ǘ5µWÕy¤ñ³Tù�HÅ6úr§{ «RTè±gUUè-XÚÒDŠ™`!Û’¿ªã›ó�C”…žÏ•:ÞJLŽYU·ÆqI™†¾µ&žAlµùiKw”š,Ðfˆn~3Ð¥¾£)6ÓÍ‘€×¨Øn×a%M”©{[=ÃLã“dtrPKsÝ¿¨ãiî:ÉOub\iÐÞ.$ïÆtê ±V¾þiSàÎíÜdaÄ/Ö»5­cCX@À ‚’ȬD¶]¬çNˆk¶G�’§æÔaëÕ]"Ü‚„!@„!@„!@„!@„!@„ €D„¥:™Íj"Õ"wlÑĺ1À Ÿ'ÝRuî`Ää :B”DÜpUõi¿"©³Q¾“Žíž·BƒX6âÜ ±߸“ÚæÔhsHs\JôK ¶] ÷�…=Žlù6é®ßÓÏ9È�Zî×2£$nšà»z9m/@­;© C†ù©“œ)ELÚÜÎÎ5K‰�÷; ñ*Ú-NQÒ�b.>¨© xp¹W�=µ O}uT‰¸Ÿ:R¹2¨uÙýl@yB”É\@˜aÌ–AA½4úÅ:Q)³¥€�JfuÑ­.7ÌA\È! êšRSI*$’à�¦É$.+‡`½)5ÄœSE¬Ë„¢ÁÅs¨pãN6õ&¶›Þö‚ ÀµÃªË@¦”ê´êS{š²× ¦ë×#²!’V�ŸUÔ\ÆR†Ëœ`I'YHrªü3Ì< –RM¦iؘ¸Ž\m�T¦“„J9U~æɹ^PI—œtà縮rA�¹„ò’T,‹dNeGÖ&�]Ð-q‚ÈQ€is÷­l˜ÄæŽT¹5G·ðê%qs©T� õ$IÕL6´‡¶±²,†´h ®J Wêó­ð(ÁŸ Ôrä“Á:Tªð3cÁo�wÉ^çWh1s›R‚I8© ;eƒ5ýHNÔS�zL+=«Å×8æx—QÖ†ÃÀ�]Çf¨<ۺ׊ã%J±i‹Ý«˜$´sÁäLݤ6ÐvëDŒ TËá±�èÝê\:)Á5›Ô޵àš-fAذè˜ýê]Þ¥ÍÖ³ êCƉ1¶âìvMHçtÔåÉÓ7â‹n;EÌ'¶SÂuñõ©cj4±âZEáU¿"¬L0ï�!Æ‘Êm`½ À¹<5¯-TZ5̪˯i¸ƒÔT ôM¦MÚ”†¸¹Å̆Õ2w/ˆ=G�®Á̬ÂÔæœF¢¤ÖÑ ›¥èc*ä8_xü�ã ®qeÓ(ÉÝAÒÙ³ä]œj\ÛPŒ4Ÿ8| §‘—«T«P�Ä`»Ó¯™ÜùùW3EÇ‚{Ç:æd7KA –!ÀÞ�,ƒŠ€Ê¥‡Vu)•„Že%T�tÁÐÜ‘¢âºD{*o& ¦‰”‰%v€S JzI\:†oÌÓÌšiÔàžeÔ9ÍÀÂCR®gtB;/@âiTàžd¢�HÞžd®­\bzA^©î¥Ë4Nç´4êpO2r†9¶m†Ú�1zS^¯  .oÊk Ð,Ñ; ä:V5ê9ÃvX\Hc®\ *œÌŸ¶*ðºiÊ+pº<§RjËyE*®sKXLSh¸.…+w1R+e5šE—@,‰\NY”pú�EÄã'N+Žg'¯ånæ)§'¯ånæ+©Ë2ž@ð&œ·)áôåš$óú¡B�fÔ—1ÀXx¼í+“rzâ›Á¦é!±qÒ¦ ©û)¤K��ëÉÀœ!sfWR¬€\Ó ƒõTB95_  keVï:Rml£ÊÝçJë·²¯,<ÃÀ›·²¯,<ÃÀ¹f‰f]Õ9íl£ÊÝçJï‘Ь̥Ž{Ð&ò `¹íÜ«Ë0ð#oe@ïç�xfˆ5[MgmÓ8×íõ;·u®c®qs‹�‹ŒžTƒjáé¤+ 7Õõ¡ôʈpLn ÄÀMaºwäÇïS“n„`•€¸ "SÅg1Ò€˜#T̹Á7 Ôý†žqÐs� '=×®Y>øòu¤5œq 'Ih%«¬¼€Ð`^tIØq‰R."T‹‡DAOB#�\MÀžDÝ�M%uتsORsrJÏ05ýK¡)c8*l•9½�¨IkÈe˜›D3è©ûLÞIxó-s‡9²‚ÙšÒ±•§ UƒHã¹]ŒŸ#£¾-[­jc¾œÒÓÚ)=úÃE&óî�Jî ›d[2¡¹R%Ä�ÑÎaunFögY¼s৸�wu)R:5_ϺëHin�:•|ÕW Lõ¹WpNmãd"ÐÛ‰Bþ¤»H›$ .ÜŽ˜R‹Ã=JˆÑI¥îóÞ­psòi’*V:\àÁÑhô®@&òˆkq ñIð%i¨ã›'̶OQ]6ÍžÕJ›5Ù¶yÞJcòšïêŽ�ÙÂ,;kų[•�ü·»}‘ÌHL%ã­ÌÉ<à. �'Uë Éò‡aIþtŽ´%|çNú£�Ïß+žç4ô.§&¬7Á­îžÁÖRl oªÓD»ÔA\†I5”å1…É­Vï^áÄâ;éÅ”F5'‰‡¾Boˆ¼ë|( ê¶²‘èב¬Úë”›r¿ ó7Àš]L ™®ç¿¾M·PoM�Í6õ�S[’å57”žî&”ý£\vÒÊ#Ò�kO4“ЋNg1µ±r0åyK±ªà4dtBâç¹Ûçq’zÔÁ’ä�¾®VÓª›\î“ ûKú§Í8�ÌÐÞ´CÆÖÌê©b¥ì®O§Bµ[©Ssû–’¤ÈÒgh¦Ökm6Ï;ËÊãW²ªÜ÷TpÐj9š )ÜûÅlèr;±§@zR£Zy�'¡0·!glÊ C¢•2~´û=J)ª1 `ÖAqúÑ)6z¹�g¹½@.JÈK¬oegÃ%ì´ñ ‘Õ<ÕW8ŽfŽ”Ý�ÿ0èó;øõ îs·Ä»ŒÊår$êÌÖÓ ÿ×Ü!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@çZ…<¢™§TKO8ÖD ‹QN”ö)ö]5rgŽqà=Y±ô2ºV›ï[�®Žk^Ò׿‘ª«‘å ÎQ�’æbêFû»ýjéѧ&BÙY¥ùÚòâdº´\<ÔÅàŽÚÍ`çëãUõòW�³Q;5,å£t8Ú=mJÇ#Ëèåbæ Å‡M+«èí’™Øêp†ŒgëC¥T¥UÕC‡až�o ³Ê²fÔ2ð(V8*Å™ÿ îÝS“TŽõY§5l©GÿÐÜ!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@2ÎÆ²¹Ù¨а¼8\ ×k�ÉUÉßµû"Ò×f©f:µ\ëÐ¥”3c¬ÐáÒ5‚¢é¶i±ê2ÅšJÁ­JÅ••"×0B‡”d ¨Ë4̃{GÄujPÝ“e½Œ&¦HMjšfò9;ã™MÉ;#“å{�lTÎÇcÉ¥rS²¥ î Tç¨sN†-4R×ÉêäΊ�,qŇ”\¸Ú#Ë™jÜÖ¸¸qðªr¾Ä‘52CÍ3‡$ªêÌÚµZ]Fnª²«\E\Î \×ö–¸c§™ : õªËÇ!$é¹$ è©).@ˆ¼âG*H(«rš�Çuƺ ©‡|â¿À¢Ùv‚’Ë´dK ɵ'`áË#­8í鈂«ì<àÒº7'q½Ä•Ù"éK0‡ Bl ˆm xºN³=+²šC9w@Dœ‡ŠÓ°aÎc¥­KÎHÖ�4ª†ô ·™ä�Š/§6Xã`þ¨SÏb2ÙÜÓ»[›=k�NÆå”¯u7¥¢×Q*5de‹4¡ëKfCBsšaÁÀè":ÒKsr¸LjÚ9®âH€JD è$B!+Zç˜`.:'©"E2—bòúÛÚ.hÒè`éSèúU7×ªÖ �9…%EO ³\Λê[‰HŸJ…jî³Eލ|È•©¡Ø\‚�冫´¼Èæ¸)ícX,°�˜ Ř¼l¦­µ¥Ä©½; ÞOè?”Ôƒ”8RéÞo“v'"É µ–Þ<“÷GÀä+)Ìé§µy¾i]îE`!S*!B€!B€!B€!ÿÓÜ!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@æ1âÐá¬Ö£?±Ù Mõr =P¥!q¤ï:ªjæÖ‘\îÂäÁ®o�~W3Ø �àúƒ”òµBæ95›f‹Ze?³'ò×ýgÀ�föOå¯úÏ�\!snéÈwoóNjeHìH7Ϩy@ï.­ì'cÛ‹î7žô+.àS‘y¶hõ¦Egc²{Ú åºåIkÁ hhÐIPº’Wu7{oL„.œ!B€!B€!B€!B€!B€?ÿÔÜ!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@ÿÕÜ!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@„!@ÿÙ endstream endobj 248 0 obj <>stream ÿØÿàJFIFIgÿîAdobedÿÛÅ!!##!,##!.333.!>BBBB>DDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDD  &.###&3')))'3>344443>;DDDDD;DDDDDDDDDDDDDDDDDDDDDÿÝ5ÿÀgI"ÿÄ¢   w!1AQ"2Raq�‘±Á3r¡#bÑBC’¢ðDS‚²áñ $%&'()*456789:EFGHIJTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š“”•–—˜™š£¤¥¦§¨©ª³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùú8W!1AQ"aq�‘B± #$%&'()*23456789:CDEFGHIJRSTUVWXYZbcdefgh¡Ñijrstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÁÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêðñòóôõö÷øùúÿÚ ?ÜÿÐÜÿÑÜåm Éò &«ÏD•5ȳ¥çÃÌÆ<Ž”üs•_.M¯mV^c“gd®¼ŠE©–d”|ehEìrWê8KÃÑ7/&}ĘdÙ=>(Gš)wRK@`°² N Ñ) »n‰¬uS’^ËÞDý–‡\þgÅÃ[UûsõŠQNeȯ�Ñ=‹„ô¬¹ø¸k{ón~°åï!—³P]øB�PË‘_ ±cá=+/ãï ¤øtd¹š~±ÞÈeÂs‡<}k™¥ = �Tž²JË”ö<5ŽjéøC"«À­ ìo5ùìHÎ�³®³vß㥅ðÍO šŽ«3ºˆ<¥W"xèÔÕð–EK UM­Qß?5ÈÒðîM{S§Ro™.ó? F2¼£®+º^f‹ G‚Þò\ÎXÊS]©†\nê@òžnE$‹øS(Ÿ‹Èæþ—põá ¯Ù²*½ 1”rOå>&1ob””º¯s¯°ºñS«KÉ©.û“V÷ç‰.˜©»¢Õ¬Túq=ŠB>:…j\®›k­\íKÂghU�ø­æ¾§cŸ¡rÚ~+*rä«/:³9Ô�f­–d�¯5+Iûl¬üçgý]1ËX]#õÍzòÄ ªPÉ\³r:óÉj{õ;ÛÛ*wwl²‡ËÅ%VþQÓÓ�SgT_¢¤ƒ‚óÆt2aUáSÊ/[&µ*ÚpÂ2})cG(£”,êSR¶•¡®tñGC­(•ð†(¬qMPÊ“ÂÕ²Zž„ðšiÇQé\ûW){FqR‹R‹WMb™Ã,Ȩe´ó+,Wk„¹™I徫™SÓri<6tl|„&க~ñm¬6jaÀÇv�Ñ�Ë'ÊhåTÕZ2΋ëOcGRÊÊiÉÐÀàÿÔÜεz9ÜûŒÞQ•å9SίQÏbÑа8ت+3¹@ÜH•19á*‹,£Ãym{¨IQŽÈiöç‰])Jo:Mɽ-»¿8åNoU¹ÇªRZ-}¯Ö*mºÆ!†(I!Š8]ïV×Ü…ÏQà+z§ÂøAû‹nò�åB:Ûš8%P‡/XåFžÀ�["(*|TtŽLž9©.T8ãH€>ªO‚°ÚðE‚¡J>Ê›æðÓ�ÛR.Éx†²hÅ^¤»‡¨F*ñV[^kF÷K£eJá]ô°‘ËiÖp•X­çæ99Ê\œÄ¯CRå]"<’:¤×S 3ª(QRCÉ'ì­?1ÍЫ1o›’%l�Ó˜¡kiÝdº>Ë(pj9.,÷ËωS©µQÆ”T4ž)wCÃ�vYD;åÕ§´³¥^�xçQššä}ÆD|%:rϧ' -qve�ÙZ®‘xòž±hÍÊ´iVŽmXFk•\�èZÔqÉ*´½û©yá𗜮ɼ1VŽSÒUá¼¢­ã“­Æ¨Ü‘Žœc�Vm.U›Û‰Ô™D3½<ž¤±{Õ˧¨|§“à QÎ{[Àäç9k·6AÉ·U¤… T´µ}¯HÙVŽ¤ß˜à(Lå­úG9Éò.AP:€à8 ¢Štà‚Ø[ ¸FXI'ÎŽRÉi¾ âúÑ [‚Ù¢²Z‘Ѿ\šNViÙ«2ÒÁ(FjÒIœµ$¬—ÊÁISÉšnÜ�×#Êœàí%c’‘5cGÓœéMNœœ$µ¬Š\džRµ<ªÑzª. çZ» TÓWX¦dÉY&][%y«K\®g«°¶%Ç’/d°'L4aõhÓ­ÚŠöÅ= =©¬S#TÎ¥O+[¾Ný©kÊ>R]«§iÞ†QK)†}'u­hk‘£©l“¥ ÍÃC¹rñ3žL“ru²w¢§ Q\¶Ò¹tíÚKMI)EÝ5tÖ(‰*2vêdŠñnó ð‹Úã±ù˜ÚRI:Ùå úe„¢õÙ=“CÔq9PI¥šý1H~ðdã?Fä;Ú±yÒŒp¿*åäÖIðo„¡–Gs©h׊Æ:Ÿ*õ‰ÔêB¬黧֞Ƶ2§Â^ ’—£r+Ƭ^t£~©rö‘jÕÛCUÔN”k-ÇC[+ØL¸ƒ|#¶³´kAo£·•ɦšš*Š pºÐÒ ÿÖÜËt¯.<Õ¶r·š7r­/U®H%;Îg&vWÚ;6¢®Ý–×�ÅåT/hË=ì‚sø-Î5¥‘døÕYò[oR^å‚ VðÔ’Í¡t–ÙÍIûl.EÆ•rÍ–CbqT›é ]Ú«àQ•¶Í¨.öC¯á(Ѻ©Zœ_šueÚ‘U/Geü*•jÅê…7yÜž�É©|¼UŒ=Nz”½¶š}¤mÕ’Ë¡°Â¶3¦òS}/L>¿†+Nꓚå“KÍ»Jú•«V~™9O‘»“]oRV§BUå¶mÂ=Wläü!V8dð§“­°‚Îöé]•·:ÞA|)-‹°Ý8ÚYWUgF›ŒxÓÞG­Øì²C’�GÅ¥oo�‘YVUS‡Vrç“9·)p›|îç&¯”n¶–!7}OÄѧKÕTœg?rv]G)ÆUujð“å”§Øš# �µ—éOK3¶çAiªß“Þп ËUI{l’8�©dõë;R„§Ì°ë cŽŠß®>ŠÑJþTÛì°»µ¸0„~ƒ\ïèOª´)z”óçÔ…Ýr:>&“«.5G‡¶£²wdˆ['RqfºQ”ÞY[ YÍz•šºÕ�÷Fœ1ÊjÞ\H<ùuè9ÔÊ«ÕV”­,w±ón––�Mb℞Ä$ú%C ž Ÿª{éu³Œ¥)»Í¹=¯¹ÑÚºÅÎŽÕÖ;) 8ntv®±T£µuœˆœv®±o«¬éÁEÖÔ8 )Ó€-€P8€§N (XPÇN*JÍ]rŽ Â5L‘/&‹å©9O̳PK µäóY²1ÚžK”Õñt§.\×n¶uö!^>)S£äSŠ}m6ržS”Õñ•g.G'n £ äâ¼–<ÎëÁÕc�z”¨ùsMõFã•/SáÖ�g²œ3W\ˆB„Õì“–­×EÕ•äôþ]òh'ƨÝGÕ eL·*¬­:�G‹êêV#¡P[3–�ªe7‡NlQF·ã&—>ª'ÀRŸ2vëC�íe¥» ¢–„ru&ÚYª.ø&îú‘">S%�(Ê1ÚÔiG®m¤ã¢¶�‰-‚Ù#N„1©R¦u_¸¨¯8õ•dðv§Ÿ7ê#v*’ó�•òwcaF¤øræ‹cý QpÔaåJ1ía,¦´´dòkmG6½ÎIyŽ2ʲˆht©s8'îí ù̼HTöx¿%J‹èx­._†Úø6i ÑM]5¯ÍŸ.æ.çQé�GäÒk¶Á5x-]×,bnãG[kŸ1~ÜÂ0¢¤â炳Në«Yqã*ÏŸ6=¬7*z&ùH'Ö ^\N¶OÇóÿjÉøëÛ¾†¨Ò÷æ_‡`9Q¥ïÅN‰Å„ð‘ËU}ô�91F“Ñ/?Âd8Ý„EJ’ö�hô_±ŽNœ}ž¤|¨¿…;3–·›%nkT½Þ°ÜÞÓ„jCßȾ{®äuNú1æiö0"ÓC³Y Mò®{®Ñɳ§ØQ× °¶ÀtàX° XçV„*c¢[N¶Á#‰È­�)Óv’æz†–’Œd³d®™®Lᾆ1ó¢.Ãèd{òL¶y3Ì�åGf—nNB0M§4v$¢RfŽ…H©Á©E¬ZŒ+C6z�ÓXI5¡§´¤É²š™,¯ô ë”»¥V�h*”ÝÓ.†%�¬p8ÕW©¹ªU^exßr¬–ZÓ]«¥á8׌¨ÕŠSJÓƒÅ4õ­©�«Ja™5†”Ö 5¡§´Žã'%J«Í¯ ºURÂKZkµt£µš‰^—HUµSÀÙ^to,š«Ñɳ�yÑ} Ƥàó£%tÖÆFœiå´g“×Y³\%±ê’äøb¿ ¯S!ÊA”ð[ÞKRoGCí"°.Y‹« –D²ä3Ìᯠ_.€° U²œŸ'W­R0çxõi Ž¤Ý “¨¼?’à 0•W·‚¼øùˆ5=ä\¼\!Ëy>âÉ º[SÙ"¹,SJB~ðŒý­›äÆ+¸äü#—¿}=ºÄrò¼ËQÇ}@1^Ärõ·6t�…ü# ›ò”_peåy†ˆã¾ºSb^Ÿ¼ƒ-‹Jq…EÌâüÌïñp×÷æÜÎåØH<¥²+‰ãŸÿÐY: O{)bôÉ%§b]âîÉpiÁs§/ƒ6s— ó¾ÑækÈíèšëƒ,ß%(|!’©R|9J\í¾Ñ 9$® �¢ @QcN¤øræM�–KUpói¯W8ÇÍ{„ˆ¶•Ó€¨ìéäÐñ•ïÉN^yfŠ�hÐ�_URy‘ó%ÚvG-°žk6q:Æ�Y+Ækm¬ºÞ»¸¼kR¡êhCuŸ·cÚ.7Ê•JÏ�”TÍ�RõÂ@Ûý?D&bXJ¤#É}ÑõBëÎuY:¶tÕIGlœrhuÊïÎ,UT±«ÙF ?o—®1ÏÁôÞtÞí>4å*¯ª8{‘Ù"3n©¼Eú…O&ƒÞ8'õj¯?o©eÔuPœÖr¡)®5yµ¨æGÎq~§j4ßFm%î*Ró‘çáówJåÍÏ—\Ü‚h»’Ão¦'5W{RYë{B8¬;ÅûpÙÓ£z®R–Ú•!OÍyÈ®•zõSÝ*JJÚvêÐr9lIXÝùbn¶M�ù!:Ï®£HkË#k)U’Ø¥ Kª)�†([3¹mbâ’%]7…5ð)NoÎíæe6L"»ŽOH™ÛTuuëËMI?�1·oKo�ÜjH[·¥¯)ö!‡}Í*QÎ’�ÛzÒ–À8ÝG4‡$9B ÙTXú–Ím=)ØLTÚÐÚ:ªµ‰K­œ�õc¤YÙV¨Ö-K�'Ú…S‹áB/šñìg%aÈìÈÉã8­pæ•מÇXÔ–©©yJϬŒ‡#³"Ò%)½pÃl]ÐøÊ2ÐñØðdXᣢœµï¹ÕÉLƒ„‘`±Î3Kjó£¬Z|§H°°b:ÀtŒÄM -‚Íh íÕre-ô0–ÍLˆââìÕšÔZ �(Tá,vë8á' r¡•§J5ªdóϧŠ|(êcçAÅÚ.ûÁü)ÎÍ`ðdiE“M_EÝð¯8>u­©N5c›.tÖ 5¡§´¤¥Rt'ºSøÔËšá^ðéZÑl1[P뎚¨âÔç% <Ü¢š¼'l$¹¶mZ´‘òÜ�eÔ[ŠÍÊ(鎾ng©“êSU#kÚIÞ2ZSÚqjsyÑ´rŠJÍ{,—¬õl`ÕËá Riªý2> ËQOrªý6š³¾–´_×'”¹\*‘ð†L³wÖ©,µ¦¹Kj¡”R�Xh’ѱëAÌ]k¥Gl�­Žªw/3 *�jôrxgÖš„v·§‘-l)ÐŽ€BôFY”|ºÒÜ ý«^몚ǮÁì:qË*O)|Y<Ê~Ù.»œ�âv©lg,%KSÂY%™îµ8”“«.¨'n‘žŠËjøŒ‘Åj•yÆŸ¸Ç=’²\Ž�že- .¢o ä´•à¥Sc¶j|×ÇÌq¹VäJg±`o ýItü1=5¨Rä�9Ô}r”{9^S•d·Œ¼ ¥Q{$2x7Òܰ!e~Ër•™M*Þ”�äùÞmªm÷zŠ¢²^ž,Ƭv\V« BŸK&K©á_ N9¾ˆŠOZ¦¢úÑRÊ[rš�Fô¼æŸœvløÞïPZ¦ÛõzÅM·]#à 5(V"‘ÏwKÆFPåjë­Œã5x´ùƒ:kJóz×9¸R›½³_8v9#¨½:¦ªÇª_ :a<³Öž áÉQi\èêrZW::�8ÏÿÑz¡)ãÓ“xáR+O•aÞƒÊ^ˆgy2Œ»9¼¢¤¢”³^HzÇ78½6èIv ÐkJ,,ÙßЙRÓF~ÚØ«&Ê=ù©í’õˆÛ­´7×aU%ìöøõ€”XD½Æ²ÓK7ÊVø3C¡ï€â¼”Ÿ�'ÚVË*\ï›×òš�Fw-ÄﳎQìòoÊšK©Èá(æé”WKîEvé7¦O¬M:@’±µuc"vz�µòb¯Öî6S¦ñ’�Wê�ל�OOAØÖCýR yÌ5åäøO A)è|çJð�NNò»|®áf´�Z&1&ôÍ–ÁÑЇ61kæ›Ô=®ÁÈLbRZ…¿"2Z@àiÄQ.ÄçàÚÚ¥¶»Ž¤Ùdž·"¤ÏaµøÐë~°¾Ãkñ¡Öýc¶®ñ¹ ôC$Õñpèø*:{ ¯Æ‡[õ‰‚”¡Î׎ÉYhKZ{¨Y3T‘b÷%ME+Í)6Òokb:uª*’JØIû*ÛÌJyó=BK‡müS›È+ÊNMÃÞ—¯ ì™h]g^§'¶ÇÖ«TäöÕëWƒëq£ÖýaË ­Æ�[õ‚Q¶ƒe9:²ÌšM4ìÒI¬/¨j‹ØJ£‘Ô„Ô›�•ô>Aë$©¶=gmYxS¡‘3^ÁÈ”²Z›cÖÉ*'{Ǭ-YËu|à¢ÇY¢BɧµuŽô4ö®³¶¬�º¾GC‘Õdµ6ǬrÉgµu�“8âWÆFR\§E$ôà*ɧµuŽY<ö®³²d[B 9PšÖ…t¦–¦vLŒÐËnÁ}Û FÝë-®&kZà’Œd­%tp©K7ÕGUô¯�zä„ö޲jÏÂS:›Es§ÅÇÔ¼$%:“¡<øt¢MJN8ÅgEjÖ¹™ÎÊJï_f\ëY H±9«è³£Z¡�:ÖÁjSr´ í8ð_säeM9O'šœõëÕÌ[R«ÐÎ�JÖ‹!ŠÚ‡YLpÚ¹ªŽŠ«TŒnÚÍ­Ië[9Ö¦@Éjú(Ü›½ ¸Æ^dû™iR2Œ·jjòJÒ�zëQ -ÉãV“­K½óäzßN¾³‘'Z­‚$ð.§Ò@AðnUºÓÜj=ý5‡*øBq4æ¦W.Ó:Dµå&’Jí¼9Ö¯ )^òœ°„#Œ¤ù~„qY<ëµ<²Í'xÑXÁsñŸ›bÖrd’ºèB<¢¶S½ÈÒP×^iæü89sà¹ÇÑÈéRžë+Õ­ïíMôº5%ÍbF lH†òš¹KpÈ­™{K(’¼’½™ù¹ÎbÒΦÜÒ¡]};ý1ÙFUC%Šu¥g,#œ§'±EbÈ®^ʱ�²8¶˜Õ�9Æ­ ¼úxKaÙÇ`'m=~¸50NT¢wº{ס§Á|ã©ÊT§�OJÓ³¼‘VŒjb°–Ò3M<Ê—VÐõ¢-H±4×®,©T�XçG¥l/I“Ÿ´æ÷ëc~ÍÌõõ‘)NPŸª÷¯\ŸF¤n´<}ŒšsÅ*‰Z¼&UeY<²JË)¡Á½í©=œÌ´£V5éª�ÐõlzÑÍ%èz˜Óš´ø+î!Órð~PéËÄÔÐûú5‘Ø®wxL›Á©fJ§}`XRµ¥�¸ÐJuu߃õÉ÷i~q'RudéPv³´êiQä[eæZö)Ò…(æAY^íém½-½låd¥*^@Ú4#I¹É¹Õ— £ÒùÅÈ-zô²zn¥ifÇBÖÛÔ’ÒÙË*Ë!“µN)Õ¯>(ðŸ+عH2–ãQÖÊeùZZ/j4ï÷'Ìq´¨D¡�ÅK»U÷õÕ«Gu˯Fƒ{Ì�c9½YÖÅù+¦äL³ÂS¶åOÒ’VP‹YÉz©-ËU ‰_+�I77&¬ê<%m‘^ʹ/[dB˜£¸²F ±*¹R¸¿L‘»¾Ñ£˜Ò²ñ@:  ¢: *§9h]:1™®< W££a)Pã>¡Êœ…׉Ù²"Eç`“ºÒµ„¨9êiêz.pŒ¹ÐÖ Rqyµ5è–§ë0 kÄSœf·G™+ïj{+ägOL÷ú¹ÅJ2WM;¦Eô="êJ)ך?ÿÓ¬¥Áér¥$•ž[­¢lÞu‰SƒÒ=h\Ç*’V²Ä|$šXâCÆË…×[FJK9[QÈê(Õ$ô1×[@àÕÃ|ÇC’’Ͼ¦tMmc†ÓÐùÅrHlX09pê$¸,.„“V°pÈ5kºŒ³Lée©Ûœã&°±Ñ4ΜcóWyý`ÌYü8èåõ†Ý I*•£MØ_:Æ ë<¾±+,Š•dÜ”w«~äÎ;­(Ï5S‹³µÞ’FUVª%8Fo5;½$®2·;eˆÈ�§½ütòúÇUñãçõ„†UJøÐ‚;ÅÒ¯J£PP•8ç'qMªçÒ�8f»Ô�­©6û)EÆ1‚´c{_KÚÙÊrJ-_-),Û7f€%A1(Ö„-8ÆPŽkRv¾7M>‘'“ÝxÚksøCŠkhÚ’M$±;2)9ÐɱɛXT§íß=dÒãÓöï„#FQqŽ;N´é¹§+Æ1X9IÙ]ê:¥xƒš»ÒcN4**“œ[Qy±‹»m¦ºŽh$åªÓ²õOo1ÕR‹ÑVŸ·|!Ó“‚)78¯jSöï„9ÙÓ¨ã<ç3¢¨jkh®I#¤E†ƒ¢9ÓjÖgUc¨ã zÐs“V°øµc¤]CÐk@¬ âtˆô9 MV:pU¤{IÁ&1cˆLÿÔ©§,^ƒ¦ç)pzG‰¶o6æsœUÐèÓV»Ö-Nõ¡sÆèsˆ×;-gQ²áDáÄÅTã¯w8Ž96sQßfì:*qxÇÌ=65Á[!í'A)è|àrt ™%•Ðð—�ɉ&®ÇfD#Á\Àãg9FÃÔ±%«œèØ™‘“«e\½ÂÉþ^aÎt‹©â ·Wå¾ÒN_*Ënbï8KÆ?)ö’rß¼…Þvã Þ FB„sž:‰Ù,"©×å¤C§¦\äì—Å×û6ÖGFATÒ�Ö¡iÓRWcåÁ|ÂÒà Ð*¥' ÜVƒªSƒÒgHøÒN*ø¼I’ô2Vö«z}J9#¿¾eöuüD"nŒR4¡g{¸³ª§Ô(ºùL ´Zò{iì>ŽÙu¯X”07IìŠ&UîqÔt«Î ê¥ õ2Œš� yÉÉÉáuëªxÅöj€Ô¨"¢¶¥ Tâ+‚µÑ+'É•X¹Îéj±ßÐt¶Ë¯á (D]‘'"¾ÎÅ�"t© tå™M·m7Ú-8¹ÉEk9+€âºsq¶(t`­vKy56­v$éS§ãÈJÔ…ºg³çް¦§‹Ð‚@܆(¡Ù¨ë¹G”I$�‘)œÎicc­·© \3µ°±ÔqŒÍ*ã¬$@à8©+3›N/™Ô4àÎiÜ[ (¸â´ ~p: i<ÌS³Ó©÷êÒRŽ÷JÑë §Q­òÅ®ÛËÎwNüëJ:{ìøéÖ¶œjê:�Æ,•í^Ž2¶+Œ¶s‘êÁ¦²¼ŸO³G·Ó¢“¥,èã j:5g»RÅ>vòóœ¬êrý:F:�hÖ†tzVÆt!NŒ½“ãÂ�»î¢U*°«èô­h’wdb†ê«4<‘�Zñ¥hÙΤ¸0\'ë.P§@ê•!J.svKݱÅS�v§]fÁ;Æ“ó9ròjçNŒœ•jíJ¢à¥Á‡7//`µòŠtûZê+O;¾…ÊÎaº‰+Ê—|}J�¥:�F+Ke6W–z%<ù:Y*zŒ©È¹=Ü^ŽVUS(•åŒW+Ñ}\¯Ȱ8f¶ó猵l\ˆª(çB¨fÇaµ¥×šR¬ëEC5R£è\¯k9±ÌFVË•XÖ9ˆÎ#ˆÀèÖ5�QrvŠ»;C&×Qô �6‘FRvŠ»;Ã&×Qô"JŒb­ddEÆî QQVвÂÁ¢çpš]§WâÅó½êóœ:“gAÁμø8s.ö7q­.ë%k}£»”V–†:‘å} bÉ¥®}_/¡á­·ÔpíÅuÎÅÞ5Õ[<ã·-O­Œ›ÉéðÜW>,©a�•egÍËë7eîÜZ™fOÔ#�†Ä‘ÑÑ÷ïν`,†xÿÕ©„Ôpz›¬§f®ã£¥×=BlÞr�G)ÍIYhŠÖz…›I]F=Cãk-ìom€qÊBn‘)]Ýj:ÝqcÔ6M)$£yâT޼Ý"9YhŒz…ºâǨáÊJ[ì㢩YífÆË�èšâǨŒu°ÍÒuº~Ë£ž©�PŸ%4Õ�™þ¦=B=@¤¬ÇgÄféêcÔ.éêcÔ$•ôSZÄÝ=Lz…Ý=D=´ψüž_!o ñÏtõöÑÑ©wlÈ{iÓ�PÎóŒÕW½— czÎùnvê³bå¼ZkXÈåU••×Qß*«Va'š´¢L©ÎÙUS Âbñ„±õ,�“ÞkÎqqŽçkÉ[’=<«)mÞ¤°æ:Õj+T“’ØôRAn‡#„ª&¬µ‹N¢Š³pN-Û-,Üæ®Ø¢CÕX{¨IÔS²Z‰-ˆeX¤”–EJcáUZÒÒIÝ#èTþ®¿‚£Œ!–üŠ­-ÊqN1yë�aç% �Êãi)Þ&d7:[¤•§RÍíKR%�+«tóe}þ�»Æ(…b ÓX¥~S•Æ­VãŒc„}pQ•Jôཚ”/È­¤3rgì³÷X�‘Á4ëY&÷±Zmà—9RN&_PÃB©c¨­ Y ¯UQ¦ç¯B\§B¿,–é7PÑÎY’(�[EN9,Þv7w¹c“BÐÏze£˜…’ÒU$³½Û„`WIÙ]À!Õ¬¥6µGwÊj:t›Z^"Â)E‰Ü#¢lt$¤ÔV–MIEYj8Ђ¶v½c°£‘:D””cvpÝ‘õݶ¢ž*…¤®ÜßAÔIYjHãs)%†±"í§Xë'¤]G3�\QºÎœ2Q¶1€jw«XÝ ±8tbÇO ¤%ƒå^qpIÉkÒÇ #!½ßSÑ®,ê2QÇ:8?3©‹koé⟠;~�*n›Ýòmãð‡xË¡ëB½9ÐÂZÖ§ð§™ÔäkƲà -(èF�7ºQy••£Ô²Œw:Ë6~f Üg7VAÜ 9UÊ)Òy®ò›Ñã'Ðsܪåå2ýEéò¥¯™aÎrgT7]YW�Véä¶vÂU_<ÜgæÚt¥FS•ܧ.匟ÂrhW(¡“EGZXB:zµYFW[)¼x0â®KרEÄ•t²È`qP¨Wï“2¯ BžòŽúZ3´®…¯°«�IÔ“Ïwmß6÷é“ÖüÛÔ¯Áé›î¢¢¬Š¢‰Ä1 ÁUcm¯X1XŒ‰1¬kÄ`tk:×Ðu†M'Œ÷«f³’ ¤G³nËv†LÞ3Ñi%F‚´U»E%".;Ç8Â0Vа9N­8`ÝÞÅ‹ŠlQ²qмšK”á<¢O"ßKÖBF•Y»Û7ÕK}#“%k~�ò¬­x¬6Ëz½sžtêh¼—&ò=o¬hB.ï}-²ÄxšU#FÚm%cÖñ©Â8¥Ž×‹ó�N¤)«ÎIv€M°�S-ŽŠq¿+ÃÌB­^­K)IÙêX/1É“†ÆÞaS(£O…+½‹æ"TËß´áÓ/Y,%ŽL±A Ã<¦½N�¶,˜ãfõs7úVó}߆É¥QI¤ï°äNqVwzŽY�÷WÂÉ(�ÿÖ¬¥Áép„¤°Jü‡LùñDÚ7š¤uNøè\Ç JO­È:�¬•Â@Õq’áDLéñF6Û»Ò$�ÍN|[‹�>-Ž�«Æ>c¢#¦ï}gU)ñ@:G9JÚ,4!EPEP8*D(|8C+§p8ÉÒ¹ÉYgŽ^Jï!FSºÞë%eò’¬­ÄXõ’¸ÊšÁ,Fp§¦\çdE„œ^e9ñNhé. æ—'9µf¬…§9Ç«ò9* hm^ çªTâ œå'¾ÂÚ€ŠT“ƒ­*’¥R5#¦/ÝD:u*ZÉgXéºTâLƒ†á¦„ãR qÅI] ­IV¦àú)Yଭ缞£ác}h·…¨�œp¸"–AKšÔ³^ ;2VK=Ç)©“·x·ƒå–º´-V–“Jx'ŽÒ%|®¤ªÉS•éçol—­r½Šñ ”ãW$ÑrEÊéậJÒõΙ5mÚ’“V–‰.S´¢¤œ^)«2ׂE pňUP“ŠRZS-!%8©-eLã:eMbµr­L•’V–vç(ÙKCå!“‘e’«dK©RZ"YÇzô¬ ¤|¦2VœUõ2Q+¥p»�JY²³ÐÉ ùñItjn�Ç„°a ¸v(n‹R7Ç`Äv#ÍÎi,53¬â¦ƒ¼d¤¹V‘H´æã;½zI@œÎ5 MàùǼÎ*MIæëÔ Ó°ËâÃ:\Q­ãˆL:­22z#®ö #ZÐ�±wÀÒ’³ÞbǬè„jçDÓI­"ŽlyRyÙ²è`(ß�hcnÖèzŽƒZ¾ �iÞéÙ­a-Ϊͪ¬õ?Y…šÑŠØI[ÌpèÔ«Qàúd6kGHV§Sìö<Äå ºØ$·:œ8ÝíX0¨%:òQ ÉN.w\Yúâú&Q¤åX£³9jîRH’Ê(¿f·>E8=O¤ìÑÉ4(À²©ð¤—;HæòªZ!y½‘Mœš:“wÀpÝ2‰ð)¨-³}Èç8ÃßMg/SêêX„ÿJލEIÚyM(<ÔóçĂΗ˜e²šÜ'¸Cb´ª>�ãèªT–nONËozç •ëTÂR²âÇEÅú"jzXo¦%î™.HšŽ2zm¾›ç~¹¶[ZxCÒ×&2ëÔpvKb‹Ñ‡)ª¢Å­Òï±’·³c}Z[šß ÅõΖK×�,˜Ö5Žb0:5�Ç„ç‹Þ­¬ÎG¤2yËoWœ“ P†…wµ�;jEÇxåp‡c·XáÇÕ„9_›¬*#Kp©^ÁožÅëœç:•9#Ô½v,2vôà¹tõzç'xš…*ÎS«R¦—dõG×<Þ�âØ´’£N0бÚñb„ŽÛÜG(R…> Çn±Ì'(Á^m%ÊD­—F8SWå– «HP�'%‘ªå”)àž|¶G9¥z•�¤Ü¹81êC7:œ‘\„\EªÄ•lëW,¯<#jQóõœo|[r{~iC7!TÛñqÀ‰jI*™¯gX’‹ÖíÍ€­VzZŠ%N/~ÜßR¨sÍ\¾pÇÙWpÜù[yË‹'Uë�÷u-óŠó°n<²ó"3½ùGÚ¦Ó¤­NŽv[Ô‘Ïu–Ñ“SÍ|Ç =Œá% ?ÿ׃ ¢RWiÝ¥±©=ïIÐM›®3¤ò‰Æ7IU¥e‚#Ô{Þv>.ñO�Z©÷ilBJ¼”’²Äæ6oC‡D�Ú[nÒØŽB�É!ê¼³œl°:*ÒØˆÑ~˜Îˆ4ŽÛ¼¶#Ÿ¢êqcÔ!ÀB¯–WS‹¡VYS‹¢* Ux’²ÊœXõYeN,zˆ¢„ÂÖÄ¥–ÔâǨ_FÔâÇ©‘E;3–�Þ%¬º§=LtrÚ�Û6=D1ðáÙÇ7‰Ë+©Å�PŽo(«ûbÔ]¶\à‡Ó’Œã'¡4úŽÌ…ªU FÝ×±ÚÖŠ–ÛùŽ4glõÇõîuμTv_Îæ>tîÝ;ê½ú.6„})Ï•yïë *–n¥µhè°”%éY»Zó_× §)–AÛ6Ù¾©wØJÔŒ3±æ:ù¾¥wÜmj–»¶3ÎVç:ENghE*iú¤¼ÃóV|¢½—;Ì2N r§æŸ¾”—³_Ît‹˜Ìב«gžºÒ½ÉË)Ê3£Ñï­©k J¥§jR½ú,HSßF\[yާ"1)ÊhìëÖœeNêØ«,q±ÂI¹r´—5½qÊV¿ª]÷N¥äá±¶Ÿ=½c­ÌâRœ‰tå:sÍ„­}=W»ÖÌ“ÎwV¶ƒŠ–û;ÝÑ`ÎJ\�‡fA©Ü¼tR�IZnïSvØž¡c¢û,r¥Q7œµjèHêžÛo1Ô J�õ+UŒRÓȶØè§QÞ.W²wÁªËx—»¦çXÏ9gm]§gI¨¨zX_”Få ‘Ívβ}`žå¸ÉÎÓ‡©·hU’TåŽ:»v¸Äôò޾ŽBDd2)n¯‘\î›±2ô×ʬwLD91´ñroMޱFYÙÛos·ˆÜgS”�äù§ a7}}à´8(Q°wŠtãZW8£fì×8ëÜ€‘–uùÀà£e iC�´•ØÆwRºÖ {G´¦»n-i"IR>éèÒcG]�Ù �8�&8F€Y®^q/Ð:ÂbpèܸÇ\bú=kv‡FæÇŠºä»Ä´x‹Û¥ë‹Ò#ç8tU% 8.‹öƒ¯[B•¹•†» a3²A)J\)7Ò2Ûçq­$†±ù‡ÎmzÄc˜ŒáѬk:(J\s¤rwìï¡‚i‡Æ„å§z¹Iq§pWN±NÚœqÞ8ÆŒ!ªïk8kiiêÖtäæ ÉN1Ó§`ÙMÉæÇO'{ÐŽj.Z7Þh/\ãd’¾6sœôanö�^±±¤åŽŸU%‡DI šNòß5¢ú2rGm¯ãN1wÒö¼X§*ÙU <)]ìX²$òºÕ|RÍŽß…8ÚGT:zVL©V�5y»rk ÕËÛy´•¹t³„”V5%œö#šªÛµ8ÙmZH¸‹¡±¬\Ðé:“yÓvåožñz¡Î/LÝ»F¹B+~s…ˆle&·±²äÇŒÆ*’–—nláÙ '¬w8™òkg0ɼ-´"î€ì¨ç=\ãÎuŽ@$« ^ø¡?Ð8c’Ͼ­€è�@Ë“I6öwHí¨ÿЧ‚“ààv”*FÖ–˜§Ö%.IÚz¼„&Ù¼Ý' Ó¨¦£'vÚWÕˆAO?s‹³»\˜ªÉgç_(»õ¡(ªùíïs›¿YÐMµŒ,\å{= ¾¡\”¥Åµú]‚””\¯…á%ÒÐêM%$ôË6ÝLà:&>0©›�{$Ò°ç ™ªWÁ¶º‡¦·6µç'æb¶·8­i¿=Ž›88¸¨·ìÊ뭮㪋Ý3�œS¿Às†Öiæ%ª6}m�"Öï³kôÙÐnŒfrŽ|ï�.O Uã)j�¯Ò줢§|/M¥Ï€°’Tç¦Y¶ègôÀ¢ó3õgfù®+‹QRÕ+Û –㛯t½¹3l,¤�8EiNWéhtá(¸¨·ìÑÎ^ï@²ƒŒ³^œ<êýáRJJ cji>{±õ%URNêÐó%p9NlEN[®å†vvo%ïaiÃ>N-ÚÑ“êM÷S�¢·Kïw[ß’áAúcò'ðVtãnOLÕ¹*šÜómÑpqqŒdôJöèvï�}�A)'NœSÆ*WéwéÅ–|-wŠ’æbÉMOs“Æérco\J²R̳½©Å>t>¤ã,£=;ÆñÇ™+�Ι‰ruw$í,çêºRm¤ôEˉ\XN+*ÝÞî�ß‘¶6Œ”e''kÓšéjÈ?\*Sœe+á›évï*j¤]’’O¦ï¸JrJxÊ)/nLXÉn…÷Îqir$ýp9{”Õ(ÔÎwr”m†¤Ÿxµ ÷wJ÷yÊ)¾Q²ùw‡ÙÉöDéRIenMàª&ßQߨGê…5StÜ¢ìî×& :«;Ú\¹>dJqÉau•UŒë;æIgrt\‰FJ9ùÎ×§$¹ÙÙHŒç7.�XÅÊ2ŸÍô»#*ŠêX)(ù¯Ü2œ’§R-ã%tJã”–àã|wDíÉšÐõãܪf)9a&×U½qÊN6Ó%œ­Î×pÇ$éB)â¥;®{X‘JJY¶ÅÆ�Ÿ>sgHºHýδ]œ–„öé:SNjRº‚mt;–dê+ÊÊÑÔÝðX¨¢¥VÎ÷Œ®­kbNEVÎk¦!҄䜠í›kô�Ô+fçg-6“4¨ÉkmyŽé¬Ëkο˜âTMÍâ‘ç ‘JSwNöè:BM;)+ެӢ–´ûΉ¬Ø[T;*H·F8ÜÊÉÛ9 pžé™.v¹!´åuÈ,÷5i¹ZÓÓgË�)¶8BUÍ‹Ôðæ$ÑUm)JöÍim¹”ó%�{Y;>‚] Ô”e9Jë5Ùk¾Ð„#Æ9ns²i;¾M�­S5+Ùëc)Ôœ³o+Þ.ýgkãÐuH‹lj§9a9aÈ21’›Pz0¹ÚøŒÉígÎvU� r�^28ɼçœîÑ(ŠüdúA„7N�SxÇtͩƟs:‘é8II;=,è©ma><¡á n¡Ž—(ÚwSk¬ês�÷Yl°J �gD­ŽÑ•!�ŠÒ<œ™Æ�ÚqzÜ’ÖΖØNHìÎMX,ÌjÁ¨«ì8Jà…86Â8±àfriìÎâXäŽÌŽ#$8Eé]XÝôJK©œ‘ÔÑÈkòyê©î(OCT×Uûj9'x”Õó›�ÖN’´¥'æ¨ÓZ¯ÏˆI…²"éÁb;q›ÕnrU’Á`jäu“ñŸPåJÕ׉ÔC²G-› á­€#ia¯`ŽWÂ;îlXDzNï‰öp’BJm»G±bú^„1«»<_=ìê¡&¬÷±âÇ×çJšµÒ¶¤pê©ÝZz8«ð£�¢¶%ÐE©–¶óhÅÉòbE«•òŠ™«Š±~±epš�ºè%UË©SÂ;÷É ‰R¦S]o¥¹Cf‡ëŒÝiÓÂŒqÚñg9gË’ÍD[™l0%s$kt)<é-¬$êÔÒócÔ6S„Ì�ÞÖ$¥)iw"Y/щ™J:[›ó u&ÞlmÈ(Ïg|Ç qÚØ× 0:1ìÎJ9Âæ-¬Xh|â�Ùœ¥b"…ÕÙÒ|"й€ì蘶³œ£švSW8Lj§µƒ¦¶±âMœ\^vh»šÚÇ?Ð)ÒS9JžÏQÇs‘)è€LêlÿѪ¥%kk:‘@RG pÌïVJÖÖr8R‹³Oc‡,pŒ”šz·KIÉRZØ»”v²%t “¼›UåštÜãÊtìÒ9ŠŽŽš¶4p'1Â�hà8*A@à¢�h pp£G …8éÁECE‡LæÒM»- R¸¨b€àô9 C‘Ò#ÑÞ„ÔeŽDtu¥ ÒVе�Db¨œžÆšQm¼_YÅP†Ö ”[‹Ñ©’¤ªJu�2y¬ÜÖìîHMéRÏÅ»$vT!µõ�S‘È’˜êÓY¹©âÙÖ”Ô¢±Å,HÕ)f,äî†&“ TÑatq­;µî–�—#¦*a9œPÈè™Þ3ͤšjùú=›áˆÉ�cš¢¥¿ÎàØê8ÑÚ�mûm$¥É �š!ºµ/%,í�……oÒ£ÎÉ&AÂMS„q“9Òœs¤– »¢,c)»E]�)ÍÑ�䞆¬Õµ”ï“.E”­R\·):µŠÅêÔ£+IYƒsa‘2ŒÓ‚WÅ.WÜ[�QpjÔYѶ9®ãÕjo]ˆ‘Å¥µ’Õ:kUùÎ¦ÙÆ’’êB)I¼ƒŠ®ó®ø;²„Rk �^£‹Ð�ÌRd�ÚžÑ'UE]c}̇Œs\m‡!ÚNQ†>3SŽtAN2y©ÚKQÆŠÍnIÝ3£„g¾¶;A0i&%J’Ž‹½»W(ØUºÅç-xcÔ:SQ^˜°ZÐÝÆo¬å3:¥*D©(ÂM7až‰ŠvjëiÒ¬båyFú1"Ô„SY®×ÔÎ9¢P¤ë&FQš¼]Å"ªj¥ŠÖtU¤´â¾EÃxì9ƽ7,ÛÙìg]:1:rM ° @h `8Da²Â-òѲœcƒºÃ”lT^2}Çf'¢=-Ø�$¤„uaÊ7v‡/PfA<^sÙ“Ü£„œiùR¼º‘ÊI$°ÂU•ð]/0×Rž™^ocÁu Ý(ÛyTåà®¶5¤±v§w\ŽL’KéºÅð›K‹eÖ6yM:qÞG]ê]¬ŒêÑ‹ÍsÏqÒ »dû�*™ÒvŽe´+Ý‘¶'iŠ-Jµçø1Û/K‡òL��F1ßÉÔZ°Üéô-,*ÂS“–™/g›¿iÃ2— rueÉ ‹e�Â¥ÓR弤¬¶EYªE{ZVäX±]GkE(­ˆ�8­',…c7h¥h,ÞW‹9¹§‹wlAÅl8JHç)]ÝjŸ²�šKXìØì8J�£´ç�¾¹ÑÆ;y»ë)ÎŽÑÖ¬EÍŽÁSä´ Œ’Á‹�¢F)âÅÍŽÀ:6rMY «Y‹8«] «]ãp;D…sŽÓ”å}Ž®1ØrœRjÚÀ‡gÇ^ç¡™ªàã€vƒ“–ÿ8~|vŒqßæê›‡N¹ •H¤õàrÝyÒ„Zxj8îKhPIHÿÒ¥SѨAP>%Îs�šg2X§5V/�]ÒH•I„|kæ:í<í§]Ò@p::‘¶³�C… EA@࢈*‚¡D (‚€ >0œÔ¥Ú‚¼šÔ´\am’{ÜrœÇZÛ†þê3–Ž[�…L„qZ©ÊeX£ëz9z?2Øî–½ú`v±Âˆpr†@pz†!É�Æ=¨FPœá5›%k§¤å“úÚΦvr¶fmºnMʪdÔòš¯Ó7G+>f®’iQ2¨�6²u …z1ÅW¥·ÌÄ�xfµ[;2®ñ×'ñ},ìˆt+(,ÙhÓsº¯Ko™‚tP¹±õ¼[çDdÇÕ­¬Øô³’`Ý'aRGDÇ&sLéMÓ¿¦gZÞËkùÀë4“j×W\§Hææ¬Ûî¹Ølä:Uô>e;çø½î�zN1qqQŠ{®v¾‡j!9¡ÓsÏ{§ ]Î�úTyØÉZ.q¬›©…�ôsŠß¤Ç��¾rðúw96Ý“V½®Hp�eKNsXrã¬�s¤jÎ6Ívͽºt�Nã94ÍVtNTjjn=BN£©<çƒä Ö©iFs”œ°Ð’´Å;akƒŸ#²\$9œ¥&ÝÇgò;!Ã=�óŸ!Ï9Þà DŸÈÄsä°�CCç楚;?‘�Ùø,HðW0ÉM¼4fÒµ®eAÐçSW8®|Œç)90ެA›¦Ô#ª¶Ù0~3 qÇ9çgkº­‡dvC˜Û¡²«ƒ²ÔpÝ&$¡gÿÓ¥ê)¡s")3ÐÌæ)Ó2"îq œ¶G1QÓ2"æD&rcCó".dN˜ÁPüÈ‹›91‚�͈fÄáÉ�vj5Lh£³P¹¨Lh£³P¹¨Lh¨[!l€à‚‹d-�ƒãRpRPm)¬Ù%­i°–AdP²È¡d*Qº½í|m¦ÇN¤Ú¾„ô-,ÕSM\Û¸Þ÷Zp!ÙjDTS¹ C“$9$pè©’)Þ½W:­Éémë#¤‰97 \ÇQªl’¡*êt âì¬ÒÔu¤áœ³ï¥ZÖÛÊ:»†tóo¦W½­Ñbr ¦nr¤�“ÓŒ£�%|l‰ ⮣ŽLý/¥�Ð*‚*Ùʵ8¨çEZÏŠdŠïÒŸ:"¦qÖJ‡¦93�Éqy?¡Þñ‘¾1½ó_&€Tƒ æç)$›¾j²äCó$©ª·V½´âp¹ÝYЊ¼SsÓìß utKXÎ*2RŽt¥¢Mè'é1çg ¬É8¦¥mkAÒOÒ!ÎûΜj¬S®Os“U’Xca“´g%RnÁ“Ê’“Ý­kau|n2rŽ|³87væ ‡%‚uúáéµ LæåŽ#. âdu¸\çqn$u†úimdí"¾œ­R/•®N¸ëGIpbE„Ví%ª8¢L¸é"Â^Ÿ>nî´r™"ãd”“L.#v@på“¥g-w±Úç zùη8ª%letœÖ‚’J Ú^,*Ûsw×° ã™_B9t3s­où‘¥YÓ”s^—fž(‘ZÛ£½ô"-W Æ÷ÁßQØ®„îq|%Ô'¥½m {V†1³“;!®�-ÒêKnmÑÑ×°á†í}v°æp“NŠG:i«=¹Ê�ŶñêõÇ3Œ,³­­Üã‘Õ9:Nî1ÛçG:‘¤âóšÃo²Â1“Æ-=€u,1ÐÜTo§]½{�„ÓšIigÙE%¨}/s‰�j°ËjJžk…®õÚìäç&±m‹álÑ—Àã­’…`PŒ�8­Ù-Owg ¿N�7iÆN£ñÒ9�gá¬ùz�ª'ÌEƒôÉ’r~æv*™Æº¼¦ŽÖöçzï>“„÷¤ã¬’Ø£™Î¦‹�c'ÁH²Z0æ·Ë”pÙ½òp•àg$–{[‡4÷ìÕÕ˜¢0�ZXá°ÐùÇ'XÊŠñæ«Er„ø,#Á@åQhgS�]ªÎCX¢,ˆ+tè’ÐÎGYh|Ç $�ÿÔ©Ž„8椒= ò: sÝ»¢å9 “:Ït�(»¤yBG$΂œ÷D.z’: sÏB磇$tçž…Ï@(Ìô.z’(Ìô.z’s�g fr9Áà79 œ€àáFg!s�ðœ…Î@pp£n‚ç@p¨mŸ…C..p‘Ñ1𛃺8©!ÊH4KYO©ó„²‡%š•®FRB©™Tw¥UÓÁbž£²Ê½Oœ‡qÉ�™Ç gz•�L-e°eÆ\[„ÎJGK‹q—àîv…IfÆ"¦�í|H÷;Ƨ¥F“ÎSº�°ç:ˆÄ…¬ïVN÷ÇM­æ;S�9ÒŠ©=Í+ÙÚ÷ä#MÍͺœ-wÀé'éç}çS¥‘j„‰™<(BM®èÚÑšöôŽ„hªòš©�'{Ã5àA£YÑ“’IÝ[¥•%]Î 9I7fì±$¢TPAÀés¹„v«N„ª9J®kz³^xÆ›ªâçh+ÚV«'4”µ¥ŠÐrO|qºj% 4Wp—¹dþÿ{ˆ»�½Ä‹qn W}ô„�·¿¾c¼c4°©uË܃¯ê}¸�7‰`o®�ls`ï–èºúµÔ' ëúŸnÐuýO·�㳆ú µ%éêÙÊš’àJêûy%v—Æ[YÞ�­Ñ¤–œnu'3Ž$•s)ÏÝ]žZ¹“Xï¥�1&¤óæå·A³W�+±È®„埘¬ï§P�tÛæ:7‚éØ8ëÓˆëÏÝCn·kr\{g ;ƒ%ŸlF-;׉ÔãM§�mNǪ˜ëÌd³µ�7h·±Ô2öÐÄ£Vo(Œp¶qÎ5¤’¾"PwÊãåúägJ'*!×Â/Ó!äw�ÕYÅY< ^ñ°ò;È-„U²V5€GG^§'QɶÝÞ‘„I¤tݦµß k«7¬`Ù M§u¤•‘ÎRœ“â÷‘ 9^Ox*ÎF°,å”Éî³Z®rŽw²�ÊB9Éà €v@›Zt�Œh�²“zDRk@t认†¶Þ,@©ÄÓ¢1Àè�C9�†s:IÿÕ¦Íl3XøèRg ˜ÌÉdŽ‚„Î[3–d…Ì‘ÔS“ fsÌ�ª(LäÆfH\ÙLfl…Í�ñN˜ÌÙ šÇ€˜ÜÖ.k(Ææ±sXà“šÅ³(˜Û1lÅbY‹f( rbY…˜äY‹f( pK1lÀS§°¶`8K1É0B 8 1É0¸á:pQ@P8(¢ tà§XF[ÙÛ{œ–‘&&gQÔF'!*8gÔÎRÎÃ6îýbÉúD9ßxÊþ:\ýÃ¥â!ÎûÂù�þ—¡IÖ“Šy¶WÚt£ Ƽ¡ %(Ý^×Ð.Aã%ä÷�£òù?�v’J¬R178•äp­œªÉMçK[µµSßòŸ>uØp\".²pÔ±Ü[�|%›8½�îW-+œ±' ]’à\ƒVYÕ$ÖÒq\'ÎÂ#�VÄÄLE‚b&#„W´y»Ù&“½8ò+å¢<ÝìïGÅô²J²1UŽ>ä|¡ãjw$«ð—0:ŽCY!»Å>q·Ù"4/ò}V·˜êqö¯IÙœDÝÌA#Ѻr¾·s¼´>c�=/˜gULèÎux -jÃÙΧãY’šlb›§W=iŒ¯ç$-$Zœ9s‘-T¶ZN�¶œgv¶5§•ƒ©ñåÔŽùË´z{NÌœ“¤¦ÙÂÜ)ЙØu><º�×àøqåÔ‰ìk Tw.E|ƒì>wÔ†¼‚wÔ‰Ìk9$vÞ+ä'�CŽú�èžK Kµëæ$²6Wâ%ÎŽJD”N&“etäç''¥»ŽƒÞÛc9�§¡�/uQà<çSB: ±ÉÝ <+8*�Žcêp†4 ‚ˆDQè‚ F(Œè#FDÇ gNˆ#C¤†½ `÷¡Œ¨ÿÙ endstream endobj 249 0 obj [/ICCBased 246 0 R] endobj 250 0 obj <>stream H‰\’ÍŠƒ0€ïyŠ9¶‡¢µmÒ‚ŶàaXwÀƱ+¬1D{ðíwÆ)]XAç ™?2‰òâT¸v„è=ô¶ÄšÖÕ‡þ,Âo­SëêÖŽ�Õüµ]åUDÅå4ŒØ®éUšBôA›Ã&XëþŠK½…Cën°øÊË%DåÝûìÐ�C–A� 5z©ükÕ!DsÙª¨i¿§Õüe|N!™×k‘±}�ƒ¯,†ÊÝP¥1=¤z2…®þ·Ÿì¤ìÚØï*¨49QrS > Ÿ™/ÂÔ$ݬg¦@l„ óQøH¬%GsŽÞo˜wÂ;f-¬™¥�æ>z/¼g>˜sáœYÜ4»iqÓìfâ™)' ³8v0[á-³øö1âcØÇˆ�a#>†}èäø8çÆKó‡çÔì=Ø|IæIñŒZ‡Ï{ä{Tůú`—•¨\ endstream endobj 251 0 obj <> endobj 252 0 obj <>stream H‰\’Ïnƒ0 ÆïyŠÛC¥�´BÚh+qØ�íhb:¤¢@¼ýl\uÒ"�Q>'_ìDeu¬\7Éè= ¦†I¶�³Æá È \;'¶‰´�™î³åoúÆ‹“ëyœ ¯\;ˆ<—Ñ.ŽS˜åêÉX‹è-X�»ÊÕWY¯eTß¼ÿ�Ü$cYÒB‹½4þµéAFKÚ¦²¸ÞMósþŸ³™,ó-›1ƒ…Ñ7Bã® òG!ó3ŽB€³ÿÖÍi—Ö|7Aä ‰ãrÉ\™�È»ç…1ˆ<Ý.Œ9aNˆÌbÎM)7cMFšlǼ#Θ3dÅ{*ÚS±F‘F¥Ì)1ëÕ¢ß3ï‰ù\Eç*ö©È§â»(º‹b?Šü¨ó‰øÌŒ…Ê5ûÔäS³M4{ÐäA+fEÌçb "ß«IåÆW!½4·°�ËÓYúG�ë<^—¼Ä,úį¤¬Ä endstream endobj 253 0 obj <>stream H‰|T{TéŸI˜!l!*ã f0“u­îú*V¥ˆ»ŠnApy.,*˜H”— $ XAˆE±,O‘‡ "Êè ¨XP|¬V{”5"uW¤Ûz‡~xì÷ôœþÓ3çÌùîܹ¿û»¿{¿‹c Çq‡uîßø¹ùÍóNVEÉÃ}Tq ü•1QЏèp�³ÿsŽÁ9‰…ÎZÀ9XÓ³�ÑÁ"çß$1Æl eÔNyæ`Un‹ p<-ïë¸xgkd‚ìó-_È~ïèè([§PÊü“Õ ÊµÌ#vKœ*>N%OP†/”­ŠŽ–ù™WËü”j¥JÃüHD¥–Ée*åÖ(>N¥ —%¨äáʹj»,.âÿaþÎÍ? 9^)s–…+#0 çÌÇ0l&ŽÍŰ…¶Çœ0l5†ýQ€yà˜—æ/À‚0,ÃxM0oÌ‹Å2°K8‰ïÄ ¶‚$A¿p®ð°ð±…«E…Å?‰yD,±ŸœN¦��–Ö–[-;,ß‹¾9¿ÿ"÷ÓEœϺ(ÜoÁÆ|Æ $Ñ5­€|^‘H†:h0ã-ÇÉЉ3¬@¼Mr—ió ™-1:&ž£ÁƒA/l@ÝÖs°æad§·W;‡ÎT®‰ ÏðZ(ž‡›tŠF²èÁGqþ°ÿæ Oò‘í=Ý‘ô#AÉùÓNµµÄÖ)6D…oRÔD7³b˜Y®�´¿Æã¹^!7 è2@€ é4æD Ù$2½ç³L&‡ €h4ÑOà˲¦â %ÍÓsHã–ܠ܈R´Ü^ü&cŸƒßK[n*LZ ÖÔÛªôÞW3ú˜Ñ'Eg®°í'OwÜ—< ½ìU*5ZR¯”ݺö\riGSø1éqEpÁf½ÿÞ=¡ìˆ mÛר׉2ɬžô;Ý[¡Ï- ©xäjÂÈÇp·¨¯|´ø_lîòKòWЍÆt‹xIÂ2¸×x¿i°áoÓ�äNç]óun"*> Ý%Ä£¼¤u?ÂŽ!œ[6ÂJ;žRÔ]dw]ôÒì—ƒërSD`Mêk2¥ ìíÑ^Ø\,2Z>¯º{{DreGsDµ´NîuÄ“ññÚ«ß̾YFç–æÔ2·Úã¼V{û-b=Hñ)ý·g$Jkk1à0‰z”×H×&ÜNxš%‚¹ èæiHç²VÖ«AYs^r®¥õ�ôJö¹¤£»EÔ¹Ó¯ êQQü†W9 ‹åˆv¹þíc9Ûy<&LâéééXR.ƒ·îgn@‹÷�è£Æ«Ç§Ñ™Q±ôé³µ`›-—a„�ar²"]Ç¥’îð pfÜ­wjŒ5yU¼o!~®öÖpóM«4×ÚÖ€ l|CUSë¹»}×ò‡ ï_„ƒöTõ‘¿Ãß2H‹Dh rù¢Ë}ðfOÝ‹6ÖHR CxV¬è(ÔÐT5šœàáÈ'µ\a?‡±TAYÑ>C+Vë‡aX3¬Åë@,„ïh�:jw(ã)oþaôÞ/`Q_‘žVÂÖšˆCIÊÛ´Ñè3þ Z=ü Ä7Û �³b“nع› Rk{œ‡÷¥Ú¹ ±z3Ò‡41yj¹£)hrE‚î5ƒ¹Qwë,›CR©ú¥Ä;2§ãPOA×(Wo�äãQ4Õ>[ëíÄ$œ¿øŽÔT¦é Yq¥~>„Ƀ:ö�ë»Û÷߿ؔ·”„ÕgÕç“xûšÖõMR¿×Ið5Lûi6ýwô´ï:ÓöLû“?‰í‡ò¤ß“ÿäOÛ9yÑDvˆtÜ´ïúiŽ*@éI@é]“–Oà”[�àÚ4ó?çS®ïüÜ=<|ß›D~D‰!í¥n endstream endobj 254 0 obj <>stream H‰\’ÍŠƒ0ÇïyŠÛCÑÚš´ Bk[𰬻`“±+¬1D{ðíwÆ)]Ø€Î/dføÏGT”§Òµ£ŒÞCo*eÓ:`èïÁ€¼Â­ub�HÛšñq›ÿ¦«½ˆ0¸š†ºÒ5½È2}àã0†I.¶¿ÂRDoÁBhÝM.¾Šj)£êîýtàFË<—LôRû׺Ía«Òâ{;N+Œùóøœ<Èd¾¯YŒé- ¾6jw‘Åxr™]ðäœý÷žh»6æ»"KÈ9ŽÑ Ìò6™ rÊœ™�È)û¤ä“n™·ÄŠY˜Èj=3döWä¯8¿¢üJ3kâóŽxϼ'f Š4(Ö¬H³:1ŸˆÏÌgâ 36$Ó¬Y“f½aÞ³Mz4ëѤGs-šjѬA“Íu¡¡&?ºIíÆ­�ÏYš{8ÆyuæùÑäZÏíò½—EŸø`ê¬Ø endstream endobj 255 0 obj <> endobj 256 0 obj <>stream H‰\’ÍŠƒ0ÇïyŠ9¶‡bk5R¡Ø<ìëîØ8v…5†h¾ýÎdJ6 ó óõg&QY�*ÛϽûÑÔ8C×ÛÖã4Þ½A¸â­·jCÛ›ùq 34NE”\/ÓŒCe»Qå9Däœf¿ÀêØŽW\«èÍ·è{{ƒÕWY¯!ªïÎýà€v†-´ØQ¡—ƽ6BÒ6UKþ~^6”óñ¹8„8Üw"ÆŒ-N®1è{C•oé�_è mûÏ'’víÌwãUsðvK†ø$|"Þ“Qy’&C¬…5óYøLœJ�”ë¤{á=s"œ0K�”ëè]`2į9^KŒ1ÒKs/}>0—Â%³hÖ¬Y‹ÍzôE˜†�g¢-cmY,3Kߌûf¢3c�™ô"Ã|LŠGI‡çžÌÝ{ZQxa7¼•Þâóå¸Ñeñ§~×n¥� endstream endobj 257 0 obj <>stream H‰|TkPWîffz B+4MpZ»{} Èð q³‹QA„F@�ò¨\Áð†ÅÈðPEä©"*Añ-É 1îÙ¨›Ýf)cY®f=MîX»Mj÷×Ö­ºuß=çÔwÎ=$!·!H’t YáºSŸž¨ ×ëMA¸‘„7A,%ˆå6Ä*‚$ˆ ’&ˆP9iCÄÄlÌJl$’ˆÓÄcRFF�Ý6³l|l2lþ&ó’•Ⱦ‘¿'åírPø+ú)j+ÕF½i¯–ž “ø^0,«–K•SáÖJ jÑM­„Ï0I!]aaZ±îWZ©ø·2¬DX§¤vZBÓM#5¤½ » YÖc¬4¿PÒh{„ ?<€�j£Óeb¢™4á{õTÿˆpÍ”Ö÷)·9E»iói͈`FÞÙ™Æÿz&mÚÉÓ·«Á–Ã,üÜ‘µLJ•¢©…µ>|ù**ó�æûä{H„jWôÆ�¢_ã¤%`°Åñ< ·Ð`Ìßa[E]6Äö†p+¶f„JŠ*W –ªI¨‰Þ¨¢Aþ?E¨ñßV3ƒÓ%R˜©SÊ&sÓÞz¾Ãr¼ówÙcé/¬÷ô”¢8ePS\G6¯?~îCÜù¾ºý-‚ ”ŠÊÂb“�‹/8qK€5˜29"a¶’ÂãLÖIY�TÈÂ:k”bßgæ²rUyeiE)_˜»CŸ÷YÞîÜ’ü==ÈÙµïõC#® ]œø6ߺ¢ñ)+Ë.M-Ë™]I•·÷•v¬‚rWºÈ2å×€b,°Ä2\oÍ­£¤à}(¤Îª³ ÖÙ¯|玷€·eÈbÍÛo+ס ïÜ�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-3.18.3/doc/html/cuse_8c_source.html0000644000175000017500000016232715250106404017036 0ustar berndbernd libfuse: example/cuse.c Source File
    libfuse
    cuse.c
    Go to the documentation of this file.
    1/*
    2 CUSE example: Character device in Userspace
    3 Copyright (C) 2008-2009 SUSE Linux Products GmbH
    4 Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8
    9*/
    10
    32
    33
    34#define FUSE_USE_VERSION 31
    35
    36#include <cuse_lowlevel.h>
    37#include <fuse_opt.h>
    38#include <stddef.h>
    39#include <stdio.h>
    40#include <stdlib.h>
    41#include <string.h>
    42#include <unistd.h>
    43#include <errno.h>
    44
    45#include "ioctl.h"
    46
    47static void *cusexmp_buf;
    48static size_t cusexmp_size;
    49
    50static const char *usage =
    51"usage: cusexmp [options]\n"
    52"\n"
    53"options:\n"
    54" --help|-h print this help message\n"
    55" --maj=MAJ|-M MAJ device major number\n"
    56" --min=MIN|-m MIN device minor number\n"
    57" --name=NAME|-n NAME device name (mandatory)\n"
    58" -d -o debug enable debug output (implies -f)\n"
    59" -f foreground operation\n"
    60" -s disable multi-threaded operation\n"
    61"\n";
    62
    63static int cusexmp_resize(size_t new_size)
    64{
    65 void *new_buf;
    66
    67 if (new_size == cusexmp_size)
    68 return 0;
    69
    70 new_buf = realloc(cusexmp_buf, new_size);
    71 if (!new_buf && new_size)
    72 return -ENOMEM;
    73
    74 if (new_size > cusexmp_size)
    75 memset(new_buf + cusexmp_size, 0, new_size - cusexmp_size);
    76
    77 cusexmp_buf = new_buf;
    78 cusexmp_size = new_size;
    79
    80 return 0;
    81}
    82
    83static int cusexmp_expand(size_t new_size)
    84{
    85 if (new_size > cusexmp_size)
    86 return cusexmp_resize(new_size);
    87 return 0;
    88}
    89
    90static void cusexmp_init(void *userdata, struct fuse_conn_info *conn)
    91{
    92 (void)userdata;
    93
    94 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    95 conn->no_interrupt = 1;
    96}
    97
    98static void cusexmp_open(fuse_req_t req, struct fuse_file_info *fi)
    99{
    100 fuse_reply_open(req, fi);
    101}
    102
    103static void cusexmp_read(fuse_req_t req, size_t size, off_t off,
    104 struct fuse_file_info *fi)
    105{
    106 (void)fi;
    107
    108 if (off >= cusexmp_size)
    109 off = cusexmp_size;
    110 if (size > cusexmp_size - off)
    111 size = cusexmp_size - off;
    112
    113 fuse_reply_buf(req, cusexmp_buf + off, size);
    114}
    115
    116static void cusexmp_write(fuse_req_t req, const char *buf, size_t size,
    117 off_t off, struct fuse_file_info *fi)
    118{
    119 (void)fi;
    120
    121 if (cusexmp_expand(off + size)) {
    122 fuse_reply_err(req, ENOMEM);
    123 return;
    124 }
    125
    126 memcpy(cusexmp_buf + off, buf, size);
    127 fuse_reply_write(req, size);
    128}
    129
    130static void fioc_do_rw(fuse_req_t req, void *addr, const void *in_buf,
    131 size_t in_bufsz, size_t out_bufsz, int is_read)
    132{
    133 const struct fioc_rw_arg *arg;
    134 struct iovec in_iov[2], out_iov[3], iov[3];
    135 size_t cur_size;
    136
    137 /* read in arg */
    138 in_iov[0].iov_base = addr;
    139 in_iov[0].iov_len = sizeof(*arg);
    140 if (!in_bufsz) {
    141 fuse_reply_ioctl_retry(req, in_iov, 1, NULL, 0);
    142 return;
    143 }
    144 arg = in_buf;
    145 in_buf += sizeof(*arg);
    146 in_bufsz -= sizeof(*arg);
    147
    148 /* prepare size outputs */
    149 out_iov[0].iov_base =
    150 addr + offsetof(struct fioc_rw_arg, prev_size);
    151 out_iov[0].iov_len = sizeof(arg->prev_size);
    152
    153 out_iov[1].iov_base =
    154 addr + offsetof(struct fioc_rw_arg, new_size);
    155 out_iov[1].iov_len = sizeof(arg->new_size);
    156
    157 /* prepare client buf */
    158 if (is_read) {
    159 out_iov[2].iov_base = arg->buf;
    160 out_iov[2].iov_len = arg->size;
    161 if (!out_bufsz) {
    162 fuse_reply_ioctl_retry(req, in_iov, 1, out_iov, 3);
    163 return;
    164 }
    165 } else {
    166 in_iov[1].iov_base = arg->buf;
    167 in_iov[1].iov_len = arg->size;
    168 if (arg->size && !in_bufsz) {
    169 fuse_reply_ioctl_retry(req, in_iov, 2, out_iov, 2);
    170 return;
    171 }
    172 }
    173
    174 /* we're all set */
    175 cur_size = cusexmp_size;
    176 iov[0].iov_base = &cur_size;
    177 iov[0].iov_len = sizeof(cur_size);
    178
    179 iov[1].iov_base = &cusexmp_size;
    180 iov[1].iov_len = sizeof(cusexmp_size);
    181
    182 if (is_read) {
    183 size_t off = arg->offset;
    184 size_t size = arg->size;
    185
    186 if (off >= cusexmp_size)
    187 off = cusexmp_size;
    188 if (size > cusexmp_size - off)
    189 size = cusexmp_size - off;
    190
    191 iov[2].iov_base = cusexmp_buf + off;
    192 iov[2].iov_len = size;
    193 fuse_reply_ioctl_iov(req, size, iov, 3);
    194 } else {
    195 if (cusexmp_expand(arg->offset + in_bufsz)) {
    196 fuse_reply_err(req, ENOMEM);
    197 return;
    198 }
    199
    200 memcpy(cusexmp_buf + arg->offset, in_buf, in_bufsz);
    201 fuse_reply_ioctl_iov(req, in_bufsz, iov, 2);
    202 }
    203}
    204
    205static void cusexmp_ioctl(fuse_req_t req, int cmd, void *arg,
    206 struct fuse_file_info *fi, unsigned flags,
    207 const void *in_buf, size_t in_bufsz, size_t out_bufsz)
    208{
    209 int is_read = 0;
    210
    211 (void)fi;
    212
    213 if (flags & FUSE_IOCTL_COMPAT) {
    214 fuse_reply_err(req, ENOSYS);
    215 return;
    216 }
    217
    218 switch (cmd) {
    219 case FIOC_GET_SIZE:
    220 if (!out_bufsz) {
    221 struct iovec iov = { arg, sizeof(size_t) };
    222
    223 fuse_reply_ioctl_retry(req, NULL, 0, &iov, 1);
    224 } else
    225 fuse_reply_ioctl(req, 0, &cusexmp_size,
    226 sizeof(cusexmp_size));
    227 break;
    228
    229 case FIOC_SET_SIZE:
    230 if (!in_bufsz) {
    231 struct iovec iov = { arg, sizeof(size_t) };
    232
    233 fuse_reply_ioctl_retry(req, &iov, 1, NULL, 0);
    234 } else {
    235 cusexmp_resize(*(size_t *)in_buf);
    236 fuse_reply_ioctl(req, 0, NULL, 0);
    237 }
    238 break;
    239
    240 case FIOC_READ:
    241 is_read = 1;
    242 /* fall through */
    243 case FIOC_WRITE:
    244 fioc_do_rw(req, arg, in_buf, in_bufsz, out_bufsz, is_read);
    245 break;
    246
    247 default:
    248 fuse_reply_err(req, EINVAL);
    249 }
    250}
    251
    252struct cusexmp_param {
    253 unsigned major;
    254 unsigned minor;
    255 char *dev_name;
    256 int is_help;
    257};
    258
    259#define CUSEXMP_OPT(t, p) { t, offsetof(struct cusexmp_param, p), 1 }
    260
    261static const struct fuse_opt cusexmp_opts[] = {
    262 CUSEXMP_OPT("-M %u", major),
    263 CUSEXMP_OPT("--maj=%u", major),
    264 CUSEXMP_OPT("-m %u", minor),
    265 CUSEXMP_OPT("--min=%u", minor),
    266 CUSEXMP_OPT("-n %s", dev_name),
    267 CUSEXMP_OPT("--name=%s", dev_name),
    268 FUSE_OPT_KEY("-h", 0),
    269 FUSE_OPT_KEY("--help", 0),
    271};
    272
    273static int cusexmp_process_arg(void *data, const char *arg, int key,
    274 struct fuse_args *outargs)
    275{
    276 struct cusexmp_param *param = data;
    277
    278 (void)outargs;
    279 (void)arg;
    280
    281 switch (key) {
    282 case 0:
    283 param->is_help = 1;
    284 fprintf(stderr, "%s", usage);
    285 return fuse_opt_add_arg(outargs, "-ho");
    286 default:
    287 return 1;
    288 }
    289}
    290
    291static const struct cuse_lowlevel_ops cusexmp_clop = {
    292 .init = cusexmp_init,
    293 .open = cusexmp_open,
    294 .read = cusexmp_read,
    295 .write = cusexmp_write,
    296 .ioctl = cusexmp_ioctl,
    297};
    298
    299int main(int argc, char **argv)
    300{
    301 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    302 struct cusexmp_param param = { 0, 0, NULL, 0 };
    303 char dev_name[128] = "DEVNAME=";
    304 const char *dev_info_argv[] = { dev_name };
    305 struct cuse_info ci;
    306 int ret = 1;
    307
    308 if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
    309 printf("failed to parse option\n");
    310 free(param.dev_name);
    311 goto out;
    312 }
    313
    314 if (!param.is_help) {
    315 if (!param.dev_name) {
    316 fprintf(stderr, "Error: device name missing\n");
    317 goto out;
    318 }
    319 strncat(dev_name, param.dev_name, sizeof(dev_name) - sizeof("DEVNAME="));
    320 free(param.dev_name);
    321 }
    322
    323 memset(&ci, 0, sizeof(ci));
    324 ci.dev_major = param.major;
    325 ci.dev_minor = param.minor;
    326 ci.dev_info_argc = 1;
    327 ci.dev_info_argv = dev_info_argv;
    328 ci.flags = CUSE_UNRESTRICTED_IOCTL;
    329
    330 ret = cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop, NULL);
    331
    332out:
    333 fuse_opt_free_args(&args);
    334 return ret;
    335}
    #define FUSE_IOCTL_COMPAT
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
    int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse-3.18.3/doc/html/cuse__client_8c_source.html0000644000175000017500000005266415250106404020535 0ustar berndbernd libfuse: example/cuse_client.c Source File
    libfuse
    cuse_client.c
    Go to the documentation of this file.
    1/*
    2 FUSE fioclient: FUSE ioctl example client
    3 Copyright (C) 2008 SUSE Linux Products GmbH
    4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    38
    39
    40#include <sys/types.h>
    41#include <fcntl.h>
    42#include <sys/stat.h>
    43#include <sys/ioctl.h>
    44#include <stdio.h>
    45#include <stdlib.h>
    46#include <ctype.h>
    47#include <errno.h>
    48#include <unistd.h>
    49#include "ioctl.h"
    50
    51/* keeps a mistyped SIZE from asking for the machine's memory */
    52#define MAX_XFER_SIZE (16 * 1024 * 1024)
    53
    54const char *usage =
    55"Usage: cuse_client FIOC_FILE COMMAND\n"
    56"\n"
    57"COMMANDS\n"
    58" s [SIZE] : get size if SIZE is omitted, set size otherwise\n"
    59" r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
    60" w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
    61"\n";
    62
    63static int do_rw(int fd, int is_read, size_t size, off_t offset,
    64 size_t *prev_size, size_t *new_size)
    65{
    66 struct fioc_rw_arg arg = { .offset = offset };
    67 ssize_t ret;
    68
    69 if (size > MAX_XFER_SIZE) {
    70 fprintf(stderr, "size %zu exceeds limit of %d bytes\n",
    71 size, MAX_XFER_SIZE);
    72 return -1;
    73 }
    74
    75 arg.buf = calloc(1, size);
    76 if (!arg.buf) {
    77 fprintf(stderr, "failed to allocated %zu bytes\n", size);
    78 return -1;
    79 }
    80
    81 if (is_read) {
    82 arg.size = size;
    83 ret = ioctl(fd, FIOC_READ, &arg);
    84 if (ret >= 0)
    85 fwrite(arg.buf, 1, ret, stdout);
    86 } else {
    87 arg.size = fread(arg.buf, 1, size, stdin);
    88 fprintf(stderr, "Writing %zu bytes\n", arg.size);
    89 ret = ioctl(fd, FIOC_WRITE, &arg);
    90 }
    91
    92 if (ret >= 0) {
    93 *prev_size = arg.prev_size;
    94 *new_size = arg.new_size;
    95 } else
    96 perror("ioctl");
    97
    98 free(arg.buf);
    99 return ret;
    100}
    101
    102int main(int argc, char **argv)
    103{
    104 size_t param[2] = { };
    105 size_t size, prev_size = 0, new_size = 0;
    106 char cmd;
    107 int fd, i, rc;
    108
    109 if (argc < 3)
    110 goto usage;
    111
    112 fd = open(argv[1], O_RDWR);
    113 if (fd < 0) {
    114 perror("open");
    115 return 1;
    116 }
    117
    118 cmd = tolower(argv[2][0]);
    119 argc -= 3;
    120 argv += 3;
    121
    122 for (i = 0; i < argc; i++) {
    123 char *endp;
    124 param[i] = strtoul(argv[i], &endp, 0);
    125 if (endp == argv[i] || *endp != '\0')
    126 goto usage;
    127 }
    128
    129 switch (cmd) {
    130 case 's':
    131 if (!argc) {
    132 if (ioctl(fd, FIOC_GET_SIZE, &size)) {
    133 perror("ioctl");
    134 goto error;
    135 }
    136 printf("%zu\n", size);
    137 } else {
    138 size = param[0];
    139 if (ioctl(fd, FIOC_SET_SIZE, &size)) {
    140 perror("ioctl");
    141 goto error;
    142 }
    143 }
    144 close(fd);
    145 return 0;
    146
    147 case 'r':
    148 case 'w':
    149 rc = do_rw(fd, cmd == 'r', param[0], param[1],
    150 &prev_size, &new_size);
    151 if (rc < 0)
    152 goto error;
    153 fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
    154 rc, prev_size, new_size);
    155 close(fd);
    156 return 0;
    157 }
    158
    159usage:
    160 fprintf(stderr, "%s", usage);
    161 return 1;
    162
    163error:
    164 close(fd);
    165 return 1;
    166}
    fuse-3.18.3/doc/html/example_2hello_8c_source.html0000644000175000017500000011244015250106404020766 0ustar berndbernd libfuse: example/hello.c Source File
    libfuse
    hello.c
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    20
    21
    22#define FUSE_USE_VERSION 31
    23
    24#include <fuse.h>
    25#include <stdio.h>
    26#include <string.h>
    27#include <errno.h>
    28#include <fcntl.h>
    29#include <stddef.h>
    30#include <assert.h>
    31
    32/*
    33 * Command line options
    34 *
    35 * We can't set default values for the char* fields here because
    36 * fuse_opt_parse would attempt to free() them when the user specifies
    37 * different values on the command line.
    38 */
    39static struct options {
    40 const char *filename;
    41 const char *contents;
    42 int show_help;
    43} options;
    44
    45#define OPTION(t, p) \
    46 { t, offsetof(struct options, p), 1 }
    47static const struct fuse_opt option_spec[] = {
    48 OPTION("--name=%s", filename),
    49 OPTION("--contents=%s", contents),
    50 OPTION("-h", show_help),
    51 OPTION("--help", show_help),
    53};
    54
    55static void *hello_init(struct fuse_conn_info *conn,
    56 struct fuse_config *cfg)
    57{
    58 (void) conn;
    59 cfg->kernel_cache = 1;
    60
    61 /* Test setting flags the old way */
    64
    65 return NULL;
    66}
    67
    68static int hello_getattr(const char *path, struct stat *stbuf,
    69 struct fuse_file_info *fi)
    70{
    71 (void) fi;
    72 int res = 0;
    73
    74 memset(stbuf, 0, sizeof(struct stat));
    75 if (strcmp(path, "/") == 0) {
    76 stbuf->st_mode = S_IFDIR | 0755;
    77 stbuf->st_nlink = 2;
    78 } else if (strcmp(path+1, options.filename) == 0) {
    79 stbuf->st_mode = S_IFREG | 0444;
    80 stbuf->st_nlink = 1;
    81 stbuf->st_size = strlen(options.contents);
    82 } else
    83 res = -ENOENT;
    84
    85 return res;
    86}
    87
    88static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    89 off_t offset, struct fuse_file_info *fi,
    90 enum fuse_readdir_flags flags)
    91{
    92 (void) offset;
    93 (void) fi;
    94 (void) flags;
    95
    96 if (strcmp(path, "/") != 0)
    97 return -ENOENT;
    98
    99 filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    100 filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    101 filler(buf, options.filename, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    102
    103 return 0;
    104}
    105
    106static int hello_open(const char *path, struct fuse_file_info *fi)
    107{
    108 if (strcmp(path+1, options.filename) != 0)
    109 return -ENOENT;
    110
    111 if ((fi->flags & O_ACCMODE) != O_RDONLY)
    112 return -EACCES;
    113
    114 return 0;
    115}
    116
    117static int hello_read(const char *path, char *buf, size_t size, off_t offset,
    118 struct fuse_file_info *fi)
    119{
    120 size_t len;
    121 (void) fi;
    122 if(strcmp(path+1, options.filename) != 0)
    123 return -ENOENT;
    124
    125 len = strlen(options.contents);
    126 if (offset < len) {
    127 if (offset + size > len)
    128 size = len - offset;
    129 memcpy(buf, options.contents + offset, size);
    130 } else
    131 size = 0;
    132
    133 return size;
    134}
    135
    136static const struct fuse_operations hello_oper = {
    137 .init = hello_init,
    138 .getattr = hello_getattr,
    139 .readdir = hello_readdir,
    140 .open = hello_open,
    141 .read = hello_read,
    142};
    143
    144static void show_help(const char *progname)
    145{
    146 printf("usage: %s [options] <mountpoint>\n\n", progname);
    147 printf("File-system specific options:\n"
    148 " --name=<s> Name of the \"hello\" file\n"
    149 " (default: \"hello\")\n"
    150 " --contents=<s> Contents \"hello\" file\n"
    151 " (default \"Hello, World!\\n\")\n"
    152 "\n");
    153}
    154
    155int main(int argc, char *argv[])
    156{
    157 int ret;
    158 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    159
    160 /* Set defaults -- we have to use strdup so that
    161 fuse_opt_parse can free the defaults if other
    162 values are specified */
    163 options.filename = strdup("hello");
    164 options.contents = strdup("Hello World!\n");
    165
    166 /* Parse options */
    167 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    168 return 1;
    169
    170 /* When --help is specified, first print our own file-system
    171 specific help text, then signal fuse_main to show
    172 additional help (by adding `--help` to the options again)
    173 without usage: line (by setting argv[0] to the empty
    174 string) */
    175 if (options.show_help) {
    176 show_help(argv[0]);
    177 assert(fuse_opt_add_arg(&args, "--help") == 0);
    178 args.argv[0][0] = '\0';
    179 }
    180
    181 ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
    182 fuse_opt_free_args(&args);
    183 return ret;
    184}
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_ASYNC_READ
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    int32_t kernel_cache
    Definition fuse.h:251
    unsigned long offset
    Definition fuse_opt.h:85
    fuse-3.18.3/doc/html/test_2hello_8c_source.html0000644000175000017500000011061415250106404020313 0ustar berndbernd libfuse: test/hello.c Source File
    libfuse
    hello.c
    Go to the documentation of this file.
    1/*
    2 * FUSE: Filesystem in Userspace
    3 * Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4 *
    5 * This program can be distributed under the terms of the GNU GPLv2.
    6 * See the file GPL2.txt.
    7 */
    8
    20
    21#define FUSE_USE_VERSION 31
    22
    23#include <fuse.h>
    24#include <stdio.h>
    25#include <string.h>
    26#include <errno.h>
    27#include <fcntl.h>
    28#include <stddef.h>
    29#include <assert.h>
    30
    31/*
    32 * Command line options
    33 *
    34 * We can't set default values for the char* fields here because
    35 * fuse_opt_parse would attempt to free() them when the user specifies
    36 * different values on the command line.
    37 */
    38static struct options {
    39 const char *filename;
    40 const char *contents;
    41 int show_help;
    42} options;
    43
    44#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    45static const struct fuse_opt option_spec[] = {
    46 OPTION("--name=%s", filename), OPTION("--contents=%s", contents),
    47 OPTION("-h", show_help), OPTION("--help", show_help), FUSE_OPT_END
    48};
    49
    50static void *hello_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
    51{
    52 (void)conn;
    53 cfg->kernel_cache = 1;
    54
    55 /* Test setting flags the old way */
    58
    59 return NULL;
    60}
    61
    62static int hello_getattr(const char *path, struct stat *stbuf,
    63 struct fuse_file_info *fi)
    64{
    65 (void)fi;
    66 int res = 0;
    67
    68 memset(stbuf, 0, sizeof(struct stat));
    69 if (strcmp(path, "/") == 0) {
    70 stbuf->st_mode = S_IFDIR | 0755;
    71 stbuf->st_nlink = 2;
    72 } else if (strcmp(path + 1, options.filename) == 0) {
    73 stbuf->st_mode = S_IFREG | 0444;
    74 stbuf->st_nlink = 1;
    75 stbuf->st_size = strlen(options.contents);
    76 } else
    77 res = -ENOENT;
    78
    79 return res;
    80}
    81
    82static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    83 off_t offset, struct fuse_file_info *fi,
    84 enum fuse_readdir_flags flags)
    85{
    86 (void)offset;
    87 (void)fi;
    88 (void)flags;
    89
    90 if (strcmp(path, "/") != 0)
    91 return -ENOENT;
    92
    93 filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    94 filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    95 filler(buf, options.filename, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    96
    97 return 0;
    98}
    99
    100static int hello_open(const char *path, struct fuse_file_info *fi)
    101{
    102 if (strcmp(path + 1, options.filename) != 0)
    103 return -ENOENT;
    104
    105 if ((fi->flags & O_ACCMODE) != O_RDONLY)
    106 return -EACCES;
    107
    108 return 0;
    109}
    110
    111static int hello_read(const char *path, char *buf, size_t size, off_t offset,
    112 struct fuse_file_info *fi)
    113{
    114 size_t len;
    115 (void)fi;
    116 if (strcmp(path + 1, options.filename) != 0)
    117 return -ENOENT;
    118
    119 len = strlen(options.contents);
    120 if (offset < len) {
    121 if (offset + size > len)
    122 size = len - offset;
    123 memcpy(buf, options.contents + offset, size);
    124 } else
    125 size = 0;
    126
    127 return size;
    128}
    129
    130static const struct fuse_operations hello_oper = {
    131 .init = hello_init,
    132 .getattr = hello_getattr,
    133 .readdir = hello_readdir,
    134 .open = hello_open,
    135 .read = hello_read,
    136};
    137
    138static void show_help(const char *progname)
    139{
    140 printf("usage: %s [options] <mountpoint>\n\n", progname);
    141 printf("File-system specific options:\n"
    142 " --name=<s> Name of the \"hello\" file\n"
    143 " (default: \"hello\")\n"
    144 " --contents=<s> Contents \"hello\" file\n"
    145 " (default \"Hello, World!\\n\")\n"
    146 "\n");
    147}
    148
    149int main(int argc, char *argv[])
    150{
    151 int ret;
    152 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    153
    154 /* Set defaults -- we have to use strdup so that
    155 * fuse_opt_parse can free the defaults if other
    156 * values are specified
    157 */
    158 options.filename = strdup("hello");
    159 options.contents = strdup("Hello World!\n");
    160
    161 /* Parse options */
    162 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    163 return 1;
    164
    165 /* When --help is specified, first print our own file-system
    166 * specific help text, then signal fuse_main to show
    167 * additional help (by adding `--help` to the options again)
    168 * without usage: line (by setting argv[0] to the empty
    169 * string)
    170 */
    171 if (options.show_help) {
    172 show_help(argv[0]);
    173 assert(fuse_opt_add_arg(&args, "--help") == 0);
    174 args.argv[0][0] = '\0';
    175 }
    176
    177 ret = fuse_main(args.argc, args.argv, &hello_oper, NULL);
    178 fuse_opt_free_args(&args);
    179 return ret;
    180}
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    #define FUSE_CAP_ASYNC_READ
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    int32_t kernel_cache
    Definition fuse.h:251
    unsigned long offset
    Definition fuse_opt.h:85
    fuse-3.18.3/doc/html/hello__ll_8c_source.html0000644000175000017500000016472015250106404020027 0ustar berndbernd libfuse: example/hello_ll.c Source File
    libfuse
    hello_ll.c
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    24
    25#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    26
    27#include <fuse_lowlevel.h>
    28#include <stdio.h>
    29#include <stdlib.h>
    30#include <string.h>
    31#include <errno.h>
    32#include <fcntl.h>
    33#include <unistd.h>
    34#include <assert.h>
    35
    36static const char *hello_str = "Hello World!\n";
    37static const char *hello_name = "hello";
    38
    39static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
    40{
    41 stbuf->st_ino = ino;
    42 switch (ino) {
    43 case 1:
    44 stbuf->st_mode = S_IFDIR | 0755;
    45 stbuf->st_nlink = 2;
    46 break;
    47
    48 case 2:
    49 stbuf->st_mode = S_IFREG | 0444;
    50 stbuf->st_nlink = 1;
    51 stbuf->st_size = strlen(hello_str);
    52 break;
    53
    54 default:
    55 return -1;
    56 }
    57 return 0;
    58}
    59
    60static void hello_ll_init(void *userdata, struct fuse_conn_info *conn)
    61{
    62 (void)userdata;
    63
    64 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    65 conn->no_interrupt = 1;
    66
    67 /* Test setting flags the old way */
    70}
    71
    72static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
    73 struct fuse_file_info *fi)
    74{
    75 struct stat stbuf;
    76
    77 (void) fi;
    78
    79 memset(&stbuf, 0, sizeof(stbuf));
    80 if (hello_stat(ino, &stbuf) == -1)
    81 fuse_reply_err(req, ENOENT);
    82 else
    83 fuse_reply_attr(req, &stbuf, 1.0);
    84}
    85
    86static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    87{
    88 struct fuse_entry_param e;
    89
    90 if (parent != 1 || strcmp(name, hello_name) != 0)
    91 fuse_reply_err(req, ENOENT);
    92 else {
    93 memset(&e, 0, sizeof(e));
    94 e.ino = 2;
    95 e.attr_timeout = 1.0;
    96 e.entry_timeout = 1.0;
    97 hello_stat(e.ino, &e.attr);
    98
    99 fuse_reply_entry(req, &e);
    100 }
    101}
    102
    103struct dirbuf {
    104 char *p;
    105 size_t size;
    106};
    107
    108static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    109 fuse_ino_t ino)
    110{
    111 struct stat stbuf;
    112 size_t oldsize = b->size;
    113 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    114 b->p = (char *) realloc(b->p, b->size);
    115 memset(&stbuf, 0, sizeof(stbuf));
    116 stbuf.st_ino = ino;
    117 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    118 b->size);
    119}
    120
    121#define min(x, y) ((x) < (y) ? (x) : (y))
    122
    123static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    124 off_t off, size_t maxsize)
    125{
    126 if (off < bufsize)
    127 return fuse_reply_buf(req, buf + off,
    128 min(bufsize - off, maxsize));
    129 else
    130 return fuse_reply_buf(req, NULL, 0);
    131}
    132
    133static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    134 off_t off, struct fuse_file_info *fi)
    135{
    136 (void) fi;
    137
    138 if (ino != 1)
    139 fuse_reply_err(req, ENOTDIR);
    140 else {
    141 struct dirbuf b;
    142
    143 memset(&b, 0, sizeof(b));
    144 dirbuf_add(req, &b, ".", 1);
    145 dirbuf_add(req, &b, "..", 1);
    146 dirbuf_add(req, &b, hello_name, 2);
    147 reply_buf_limited(req, b.p, b.size, off, size);
    148 free(b.p);
    149 }
    150}
    151
    152static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
    153 struct fuse_file_info *fi)
    154{
    155 if (ino != 2)
    156 fuse_reply_err(req, EISDIR);
    157 else if ((fi->flags & O_ACCMODE) != O_RDONLY)
    158 fuse_reply_err(req, EACCES);
    159 else
    160 fuse_reply_open(req, fi);
    161}
    162
    163static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
    164 off_t off, struct fuse_file_info *fi)
    165{
    166 (void) fi;
    167
    168 assert(ino == 2);
    169 reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
    170}
    171
    172static void hello_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    173 size_t size)
    174{
    175 (void)size;
    176 assert(ino == 1 || ino == 2);
    177 if (strcmp(name, "hello_ll_getxattr_name") == 0)
    178 {
    179 const char *buf = "hello_ll_getxattr_value";
    180 fuse_reply_buf(req, buf, strlen(buf));
    181 }
    182 else
    183 {
    184 fuse_reply_err(req, ENOTSUP);
    185 }
    186}
    187
    188static void hello_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    189 const char *value, size_t size, int flags)
    190{
    191 (void)flags;
    192 (void)size;
    193 assert(ino == 1 || ino == 2);
    194 const char* exp_val = "hello_ll_setxattr_value";
    195 if (strcmp(name, "hello_ll_setxattr_name") == 0 &&
    196 strlen(exp_val) == size &&
    197 strncmp(value, exp_val, size) == 0)
    198 {
    199 fuse_reply_err(req, 0);
    200 }
    201 else
    202 {
    203 fuse_reply_err(req, ENOTSUP);
    204 }
    205}
    206
    207static void hello_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
    208{
    209 assert(ino == 1 || ino == 2);
    210 if (strcmp(name, "hello_ll_removexattr_name") == 0)
    211 {
    212 fuse_reply_err(req, 0);
    213 }
    214 else
    215 {
    216 fuse_reply_err(req, ENOTSUP);
    217 }
    218}
    219
    220static const struct fuse_lowlevel_ops hello_ll_oper = {
    221 .init = hello_ll_init,
    222 .lookup = hello_ll_lookup,
    223 .getattr = hello_ll_getattr,
    224 .readdir = hello_ll_readdir,
    225 .open = hello_ll_open,
    226 .read = hello_ll_read,
    227 .setxattr = hello_ll_setxattr,
    228 .getxattr = hello_ll_getxattr,
    229 .removexattr = hello_ll_removexattr,
    230};
    231
    232int main(int argc, char *argv[])
    233{
    234 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    235 struct fuse_session *se;
    236 struct fuse_cmdline_opts opts;
    237 struct fuse_loop_config *config;
    238 int ret = -1;
    239
    240 if (fuse_parse_cmdline(&args, &opts) != 0)
    241 return 1;
    242 if (opts.show_help) {
    243 printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
    246 ret = 0;
    247 goto err_out1;
    248 } else if (opts.show_version) {
    249 printf("FUSE library version %s\n", fuse_pkgversion());
    251 ret = 0;
    252 goto err_out1;
    253 }
    254
    255 if(opts.mountpoint == NULL) {
    256 printf("usage: %s [options] <mountpoint>\n", argv[0]);
    257 printf(" %s --help\n", argv[0]);
    258 ret = 1;
    259 goto err_out1;
    260 }
    261
    262 se = fuse_session_new(&args, &hello_ll_oper,
    263 sizeof(hello_ll_oper), NULL);
    264 if (se == NULL)
    265 goto err_out1;
    266
    267 if (fuse_set_signal_handlers(se) != 0)
    268 goto err_out2;
    269
    270 if (fuse_session_mount(se, opts.mountpoint) != 0)
    271 goto err_out3;
    272
    273 fuse_daemonize(opts.foreground);
    274
    275 /* Block until ctrl+c or fusermount -u */
    276 if (opts.singlethread)
    277 ret = fuse_session_loop(se);
    278 else {
    279 config = fuse_loop_cfg_create();
    280 fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    281 fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    282 ret = fuse_session_loop_mt(se, config);
    283 fuse_loop_cfg_destroy(config);
    284 config = NULL;
    285 }
    286
    288err_out3:
    290err_out2:
    292err_out1:
    293 free(opts.mountpoint);
    294 fuse_opt_free_args(&args);
    295
    296 return ret ? 1 : 0;
    297}
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_ASYNC_READ
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse-3.18.3/doc/html/hello__ll__uds_8c_source.html0000644000175000017500000021302315250106404021030 0ustar berndbernd libfuse: example/hello_ll_uds.c Source File
    libfuse
    hello_ll_uds.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 Copyright (C) 2022 Tofik Sonono <tofik.sonono@intel.com>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    22
    23#define FUSE_USE_VERSION 34
    24
    25
    26#ifndef _GNU_SOURCE
    27#define _GNU_SOURCE
    28#endif
    29
    30#include <fuse_lowlevel.h>
    31#include <fuse_kernel.h>
    32#include <stdio.h>
    33#include <stdlib.h>
    34#include <string.h>
    35#include <errno.h>
    36#include <fcntl.h>
    37#include <unistd.h>
    38#include <assert.h>
    39#include <sys/socket.h>
    40#include <sys/un.h>
    41
    42static const char *hello_str = "Hello World!\n";
    43static const char *hello_name = "hello";
    44
    45#define DEFAULT_SOCKET_PATH "/tmp/libfuse-hello-ll.sock"
    46
    47static struct options {
    48 const char *socket_path;
    49} options;
    50
    51#define OPTION(t, p) \
    52 { t, offsetof(struct options, p), 1 }
    53static const struct fuse_opt option_spec[] = {
    54 OPTION("--socket=%s", socket_path),
    56};
    57
    58static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
    59{
    60 stbuf->st_ino = ino;
    61 switch (ino) {
    62 case 1:
    63 stbuf->st_mode = S_IFDIR | 0755;
    64 stbuf->st_nlink = 2;
    65 break;
    66
    67 case 2:
    68 stbuf->st_mode = S_IFREG | 0444;
    69 stbuf->st_nlink = 1;
    70 stbuf->st_size = strlen(hello_str);
    71 break;
    72
    73 default:
    74 return -1;
    75 }
    76 return 0;
    77}
    78
    79static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
    80 struct fuse_file_info *fi)
    81{
    82 struct stat stbuf;
    83
    84 (void) fi;
    85
    86 memset(&stbuf, 0, sizeof(stbuf));
    87 if (hello_stat(ino, &stbuf) == -1)
    88 fuse_reply_err(req, ENOENT);
    89 else
    90 fuse_reply_attr(req, &stbuf, 1.0);
    91}
    92
    93static void hello_ll_init(void *userdata, struct fuse_conn_info *conn)
    94{
    95 (void)userdata;
    96
    97 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    98 conn->no_interrupt = 1;
    99}
    100
    101static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    102{
    103 struct fuse_entry_param e;
    104
    105 if (parent != 1 || strcmp(name, hello_name) != 0)
    106 fuse_reply_err(req, ENOENT);
    107 else {
    108 memset(&e, 0, sizeof(e));
    109 e.ino = 2;
    110 e.attr_timeout = 1.0;
    111 e.entry_timeout = 1.0;
    112 hello_stat(e.ino, &e.attr);
    113
    114 fuse_reply_entry(req, &e);
    115 }
    116}
    117
    118struct dirbuf {
    119 char *p;
    120 size_t size;
    121};
    122
    123static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    124 fuse_ino_t ino)
    125{
    126 struct stat stbuf;
    127 size_t oldsize = b->size;
    128 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    129 b->p = (char *) realloc(b->p, b->size);
    130 memset(&stbuf, 0, sizeof(stbuf));
    131 stbuf.st_ino = ino;
    132 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    133 b->size);
    134}
    135
    136#define min(x, y) ((x) < (y) ? (x) : (y))
    137
    138static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    139 off_t off, size_t maxsize)
    140{
    141 if (off < bufsize)
    142 return fuse_reply_buf(req, buf + off,
    143 min(bufsize - off, maxsize));
    144 else
    145 return fuse_reply_buf(req, NULL, 0);
    146}
    147
    148static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    149 off_t off, struct fuse_file_info *fi)
    150{
    151 (void) fi;
    152
    153 if (ino != 1)
    154 fuse_reply_err(req, ENOTDIR);
    155 else {
    156 struct dirbuf b;
    157
    158 memset(&b, 0, sizeof(b));
    159 dirbuf_add(req, &b, ".", 1);
    160 dirbuf_add(req, &b, "..", 1);
    161 dirbuf_add(req, &b, hello_name, 2);
    162 reply_buf_limited(req, b.p, b.size, off, size);
    163 free(b.p);
    164 }
    165}
    166
    167static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
    168 struct fuse_file_info *fi)
    169{
    170 if (ino != 2)
    171 fuse_reply_err(req, EISDIR);
    172 else if ((fi->flags & O_ACCMODE) != O_RDONLY)
    173 fuse_reply_err(req, EACCES);
    174 else
    175 fuse_reply_open(req, fi);
    176}
    177
    178static void hello_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
    179 off_t off, struct fuse_file_info *fi)
    180{
    181 (void) fi;
    182
    183 assert(ino == 2);
    184 reply_buf_limited(req, hello_str, strlen(hello_str), off, size);
    185}
    186
    187static const struct fuse_lowlevel_ops hello_ll_oper = {
    188 .init = hello_ll_init,
    189 .lookup = hello_ll_lookup,
    190 .getattr = hello_ll_getattr,
    191 .readdir = hello_ll_readdir,
    192 .open = hello_ll_open,
    193 .read = hello_ll_read,
    194};
    195
    196static int create_socket(const char *socket_path) {
    197 struct sockaddr_un addr;
    198
    199 if (strnlen(socket_path, sizeof(addr.sun_path)) >=
    200 sizeof(addr.sun_path)) {
    201 printf("Socket path may not be longer than %zu characters\n",
    202 sizeof(addr.sun_path) - 1);
    203 return -1;
    204 }
    205
    206 if (remove(socket_path) == -1 && errno != ENOENT) {
    207 printf("Could not delete previous socket file entry at %s. Error: "
    208 "%s\n", socket_path, strerror(errno));
    209 return -1;
    210 }
    211
    212 memset(&addr, 0, sizeof(struct sockaddr_un));
    213 strcpy(addr.sun_path, socket_path);
    214
    215 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
    216 if (sfd == -1) {
    217 printf("Could not create socket. Error: %s\n", strerror(errno));
    218 return -1;
    219 }
    220
    221 addr.sun_family = AF_UNIX;
    222 if (bind(sfd, (struct sockaddr *) &addr,
    223 sizeof(struct sockaddr_un)) == -1) {
    224 printf("Could not bind socket. Error: %s\n", strerror(errno));
    225 return -1;
    226 }
    227
    228 if (listen(sfd, 1) == -1)
    229 return -1;
    230
    231 printf("Awaiting connection on socket at %s...\n", socket_path);
    232 int cfd = accept(sfd, NULL, NULL);
    233 if (cfd == -1) {
    234 printf("Could not accept connection. Error: %s\n",
    235 strerror(errno));
    236 return -1;
    237 } else {
    238 printf("Accepted connection!\n");
    239 }
    240 return cfd;
    241}
    242
    243static ssize_t stream_writev(int fd, struct iovec *iov, int count,
    244 void *userdata) {
    245 (void)userdata;
    246
    247 ssize_t written = 0;
    248 int cur = 0;
    249 for (;;) {
    250 written = writev(fd, iov+cur, count-cur);
    251 if (written < 0)
    252 return written;
    253
    254 while (cur < count && written >= iov[cur].iov_len)
    255 written -= iov[cur++].iov_len;
    256 if (cur == count)
    257 break;
    258
    259 iov[cur].iov_base = (char *)iov[cur].iov_base + written;
    260 iov[cur].iov_len -= written;
    261 }
    262 return written;
    263}
    264
    265
    266static ssize_t readall(int fd, void *buf, size_t len) {
    267 size_t count = 0;
    268
    269 while (count < len) {
    270 int i = read(fd, (char *)buf + count, len - count);
    271 if (!i)
    272 break;
    273
    274 if (i < 0)
    275 return i;
    276
    277 count += i;
    278 }
    279 return count;
    280}
    281
    282static ssize_t stream_read(int fd, void *buf, size_t buf_len, void *userdata) {
    283 (void)userdata;
    284
    285 int res = readall(fd, buf, sizeof(struct fuse_in_header));
    286 if (res == -1)
    287 return res;
    288
    289
    290 uint32_t packet_len = ((struct fuse_in_header *)buf)->len;
    291 if (packet_len > buf_len)
    292 return -1;
    293
    294 int prev_res = res;
    295
    296 res = readall(fd, (char *)buf + sizeof(struct fuse_in_header),
    297 packet_len - sizeof(struct fuse_in_header));
    298
    299 return (res == -1) ? res : (res + prev_res);
    300}
    301
    302static ssize_t stream_splice_send(int fdin, off_t *offin, int fdout,
    303 off_t *offout, size_t len,
    304 unsigned int flags, void *userdata) {
    305 (void)userdata;
    306
    307 size_t count = 0;
    308 while (count < len) {
    309 int i = splice(fdin, offin, fdout, offout, len - count, flags);
    310 if (i < 1)
    311 return i;
    312
    313 count += i;
    314 }
    315 return count;
    316}
    317
    318static void fuse_cmdline_help_uds(void)
    319{
    320 printf(" -h --help print help\n"
    321 " -V --version print version\n"
    322 " -d -o debug enable debug output (implies -f)\n"
    323 " --socket=PATH serve on PATH\n"
    324 " (default: " DEFAULT_SOCKET_PATH ")\n");
    325}
    326
    327int main(int argc, char *argv[])
    328{
    329 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    330 struct fuse_session *se;
    331 struct fuse_cmdline_opts opts;
    332 const struct fuse_custom_io io = {
    333 .writev = stream_writev,
    334 .read = stream_read,
    335 .splice_receive = NULL,
    336 .splice_send = stream_splice_send,
    337 };
    338 int cfd = -1;
    339 int ret = -1;
    340
    341 /* strdup: fuse_opt_parse frees the old value if --socket is given */
    342 options.socket_path = strdup(DEFAULT_SOCKET_PATH);
    343 if (options.socket_path == NULL)
    344 return 1;
    345
    346 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    347 return 1;
    348 if (fuse_parse_cmdline(&args, &opts) != 0)
    349 return 1;
    350 if (opts.show_help) {
    351 printf("usage: %s [options]\n\n", argv[0]);
    352 fuse_cmdline_help_uds();
    354 ret = 0;
    355 goto err_out1;
    356 } else if (opts.show_version) {
    357 printf("FUSE library version %s\n", fuse_pkgversion());
    359 ret = 0;
    360 goto err_out1;
    361 }
    362
    363 se = fuse_session_new(&args, &hello_ll_oper,
    364 sizeof(hello_ll_oper), NULL);
    365 if (se == NULL)
    366 goto err_out1;
    367
    368 if (fuse_set_signal_handlers(se) != 0)
    369 goto err_out2;
    370
    371 cfd = create_socket(options.socket_path);
    372 if (cfd == -1)
    373 goto err_out3;
    374
    375 if (fuse_session_custom_io(se, &io, cfd) != 0)
    376 goto err_out3;
    377
    378 /* Block until ctrl+c */
    379 ret = fuse_session_loop(se);
    380err_out3:
    382err_out2:
    384err_out1:
    385 free(opts.mountpoint);
    386 fuse_opt_free_args(&args);
    387
    388 return ret ? 1 : 0;
    389}
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_lowlevel_help(void)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse-3.18.3/doc/html/invalidate__path_8c_source.html0000644000175000017500000016010315250106404021360 0ustar berndbernd libfuse: example/invalidate_path.c Source File
    libfuse
    invalidate_path.c
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
    4 (C) 2017 EditShare LLC <slawek.rudnicki@editshare.com>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8 */
    9
    27
    28#define FUSE_USE_VERSION 34
    29
    30#include <fuse.h>
    31#include <fuse_lowlevel.h> /* for fuse_cmdline_opts */
    32
    33#include <stdio.h>
    34#include <stdlib.h>
    35#include <string.h>
    36#include <errno.h>
    37#include <fcntl.h>
    38#include <assert.h>
    39#include <stddef.h>
    40#include <unistd.h>
    41#include <pthread.h>
    42
    43/* We can't actually tell the kernel that there is no
    44 timeout, so we just send a big value */
    45#define NO_TIMEOUT 500000
    46
    47#define MAX_STR_LEN 128
    48#define TIME_FILE_NAME "current_time"
    49#define TIME_FILE_INO 2
    50#define GROW_FILE_NAME "growing"
    51#define GROW_FILE_INO 3
    52
    53static char time_file_contents[MAX_STR_LEN];
    54static size_t grow_file_size;
    55
    56/* Command line parsing */
    57struct options {
    58 int no_notify;
    59 int update_interval;
    60};
    61static struct options options = {
    62 .no_notify = 0,
    63 .update_interval = 1,
    64};
    65
    66#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    67static const struct fuse_opt option_spec[] = {
    68 OPTION("--no-notify", no_notify),
    69 OPTION("--update-interval=%d", update_interval),
    71};
    72
    73static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
    74{
    75 (void) conn;
    76 cfg->entry_timeout = NO_TIMEOUT;
    77 cfg->attr_timeout = NO_TIMEOUT;
    78 cfg->negative_timeout = 0;
    79
    80 return NULL;
    81}
    82
    83static int xmp_getattr(const char *path,
    84 struct stat *stbuf, struct fuse_file_info* fi) {
    85 (void) fi;
    86 if (strcmp(path, "/") == 0) {
    87 stbuf->st_ino = 1;
    88 stbuf->st_mode = S_IFDIR | 0755;
    89 stbuf->st_nlink = 1;
    90 } else if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
    91 stbuf->st_ino = TIME_FILE_INO;
    92 stbuf->st_mode = S_IFREG | 0444;
    93 stbuf->st_nlink = 1;
    94 stbuf->st_size = strlen(time_file_contents);
    95 } else if (strcmp(path, "/" GROW_FILE_NAME) == 0) {
    96 stbuf->st_ino = GROW_FILE_INO;
    97 stbuf->st_mode = S_IFREG | 0444;
    98 stbuf->st_nlink = 1;
    99 stbuf->st_size = grow_file_size;
    100 } else {
    101 return -ENOENT;
    102 }
    103
    104 return 0;
    105}
    106
    107static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    108 off_t offset, struct fuse_file_info *fi,
    109 enum fuse_readdir_flags flags) {
    110 (void) fi;
    111 (void) offset;
    112 (void) flags;
    113 if (strcmp(path, "/") != 0) {
    114 return -ENOTDIR;
    115 } else {
    116 (void) filler;
    117 (void) buf;
    118 struct stat file_stat;
    119 xmp_getattr("/" TIME_FILE_NAME, &file_stat, NULL);
    120 filler(buf, TIME_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS);
    121 xmp_getattr("/" GROW_FILE_NAME, &file_stat, NULL);
    122 filler(buf, GROW_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS);
    123 return 0;
    124 }
    125}
    126
    127static int xmp_open(const char *path, struct fuse_file_info *fi) {
    128 (void) path;
    129 /* Make cache persistent even if file is closed,
    130 this makes it easier to see the effects */
    131 fi->keep_cache = 1;
    132 return 0;
    133}
    134
    135static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
    136 struct fuse_file_info *fi) {
    137 (void) fi;
    138 (void) offset;
    139 if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
    140 int file_length = strlen(time_file_contents);
    141 int to_copy = offset + size <= file_length
    142 ? size
    143 : file_length - offset;
    144 memcpy(buf, time_file_contents, to_copy);
    145 return to_copy;
    146 } else {
    147 assert(strcmp(path, "/" GROW_FILE_NAME) == 0);
    148 int to_copy = offset + size <= grow_file_size
    149 ? size
    150 : grow_file_size - offset;
    151 memset(buf, 'x', to_copy);
    152 return to_copy;
    153 }
    154}
    155
    156static const struct fuse_operations xmp_oper = {
    157 .init = xmp_init,
    158 .getattr = xmp_getattr,
    159 .readdir = xmp_readdir,
    160 .open = xmp_open,
    161 .read = xmp_read,
    162};
    163
    164static void update_fs(void) {
    165 static int count = 0;
    166 struct tm tmbuf;
    167 struct tm *now;
    168 time_t t;
    169 t = time(NULL);
    170 now = localtime_r(&t, &tmbuf);
    171 assert(now != NULL);
    172
    173 int time_file_size = strftime(time_file_contents, MAX_STR_LEN,
    174 "The current time is %H:%M:%S\n", now);
    175 assert(time_file_size != 0);
    176
    177 grow_file_size = count++;
    178}
    179
    180static int invalidate(struct fuse *fuse, const char *path) {
    181 int status = fuse_invalidate_path(fuse, path);
    182 if (status == -ENOENT) {
    183 return 0;
    184 } else {
    185 return status;
    186 }
    187}
    188
    189static void* update_fs_loop(void *data) {
    190 struct fuse *fuse = (struct fuse*) data;
    191
    192 while (1) {
    193 update_fs();
    194 if (!options.no_notify) {
    195 assert(invalidate(fuse, "/" TIME_FILE_NAME) == 0);
    196 assert(invalidate(fuse, "/" GROW_FILE_NAME) == 0);
    197 }
    198 sleep(options.update_interval);
    199 }
    200 return NULL;
    201}
    202
    203static void show_help(const char *progname)
    204{
    205 printf("usage: %s [options] <mountpoint>\n\n", progname);
    206 printf("File-system specific options:\n"
    207 " --update-interval=<secs> Update-rate of file system contents\n"
    208 " --no-notify Disable kernel notifications\n"
    209 "\n");
    210}
    211
    212int main(int argc, char *argv[]) {
    213 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    214 struct fuse *fuse;
    215 struct fuse_cmdline_opts opts;
    216 struct fuse_loop_config config;
    217 int res;
    218
    219 /* Initialize the files */
    220 update_fs();
    221
    222 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    223 return 1;
    224
    225 if (fuse_parse_cmdline(&args, &opts) != 0)
    226 return 1;
    227
    228 if (opts.show_version) {
    229 printf("FUSE library version %s\n", fuse_pkgversion());
    231 res = 0;
    232 goto out1;
    233 } else if (opts.show_help) {
    234 show_help(argv[0]);
    236 fuse_lib_help(&args);
    237 res = 0;
    238 goto out1;
    239 } else if (!opts.mountpoint) {
    240 fprintf(stderr, "error: no mountpoint specified\n");
    241 res = 1;
    242 goto out1;
    243 }
    244
    245 fuse = fuse_new(&args, &xmp_oper, sizeof(xmp_oper), NULL);
    246 if (fuse == NULL) {
    247 res = 1;
    248 goto out1;
    249 }
    250
    251 if (fuse_mount(fuse,opts.mountpoint) != 0) {
    252 res = 1;
    253 goto out2;
    254 }
    255
    256 if (fuse_daemonize(opts.foreground) != 0) {
    257 res = 1;
    258 goto out3;
    259 }
    260
    261 pthread_t updater; /* Start thread to update file contents */
    262 int ret = pthread_create(&updater, NULL, update_fs_loop, (void *) fuse);
    263 if (ret != 0) {
    264 fprintf(stderr, "pthread_create failed with %s\n", strerror(ret));
    265 return 1;
    266 };
    267
    268 struct fuse_session *se = fuse_get_session(fuse);
    269 if (fuse_set_signal_handlers(se) != 0) {
    270 res = 1;
    271 goto out3;
    272 }
    273
    274 if (opts.singlethread)
    275 res = fuse_loop(fuse);
    276 else {
    277 config.clone_fd = opts.clone_fd;
    278 config.max_idle_threads = opts.max_idle_threads;
    279 res = fuse_loop_mt(fuse, &config);
    280 }
    281 if (res)
    282 res = 1;
    283
    285out3:
    286 fuse_unmount(fuse);
    287out2:
    288 fuse_destroy(fuse);
    289out1:
    290 free(opts.mountpoint);
    291 fuse_opt_free_args(&args);
    292 return res;
    293}
    int fuse_mount(struct fuse *f, const char *mountpoint)
    Definition fuse.c:5260
    void fuse_destroy(struct fuse *f)
    Definition fuse.c:5209
    int fuse_invalidate_path(struct fuse *f, const char *path)
    Definition fuse.c:4740
    int fuse_loop(struct fuse *f)
    Definition fuse.c:4644
    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:93
    void fuse_lib_help(struct fuse_args *args)
    Definition fuse.c:4813
    struct fuse_session * fuse_get_session(struct fuse *f)
    Definition fuse.c:4588
    void fuse_unmount(struct fuse *f)
    Definition fuse.c:5265
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_lowlevel_version(void)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint32_t keep_cache
    Definition fuse_common.h:69
    unsigned long offset
    Definition fuse_opt.h:85
    fuse-3.18.3/doc/html/ioctl_8c_source.html0000644000175000017500000010517215250106404017204 0ustar berndbernd 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 GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    24
    25#define FUSE_USE_VERSION 35
    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
    39enum {
    40 FIOC_NONE,
    41 FIOC_ROOT,
    42 FIOC_FILE,
    43};
    44
    45static void *fioc_buf;
    46static size_t fioc_size;
    47
    48static 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
    68static 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
    75static 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
    84static 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
    109static 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
    118static 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
    131static 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
    142static 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
    152static 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
    163static 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
    173static 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, FUSE_FILL_DIR_DEFAULTS);
    185 filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    186 filler(buf, FIOC_NAME, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    187
    188 return 0;
    189}
    190
    191static int fioc_ioctl(const char *path, unsigned 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
    217static const 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
    227int main(int argc, char *argv[])
    228{
    229 return fuse_main(argc, argv, &fioc_oper, NULL);
    230}
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    #define FUSE_IOCTL_COMPAT
    fuse-3.18.3/doc/html/ioctl_8h_source.html0000644000175000017500000001566515250106404017220 0ustar berndbernd libfuse: example/ioctl.h Source File
    libfuse
    ioctl.h
    Go to the documentation of this file.
    1/*
    2 FUSE-ioctl: ioctl support for FUSE
    3 Copyright (C) 2008 SUSE Linux Products GmbH
    4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    18
    19
    20#include <sys/types.h>
    21#include <sys/uio.h>
    22#include <sys/ioctl.h>
    23
    24enum {
    25 FIOC_GET_SIZE = _IOR('E', 0, size_t),
    26 FIOC_SET_SIZE = _IOW('E', 1, size_t),
    27
    28 /*
    29 * The following two ioctls don't follow usual encoding rules
    30 * and transfer variable amount of data.
    31 */
    32 FIOC_READ = _IO('E', 2),
    33 FIOC_WRITE = _IO('E', 3),
    34};
    35
    36struct fioc_rw_arg {
    37 off_t offset;
    38 void *buf;
    39 size_t size;
    40 size_t prev_size; /* out param for previous total size */
    41 size_t new_size; /* out param for new total size */
    42};
    fuse-3.18.3/doc/html/ioctl__client_8c_source.html0000644000175000017500000002561515250106404020704 0ustar berndbernd 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 can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    21
    22#include <sys/types.h>
    23#include <fcntl.h>
    24#include <sys/stat.h>
    25#include <sys/ioctl.h>
    26#include <stdio.h>
    27#include <stdlib.h>
    28#include <ctype.h>
    29#include <errno.h>
    30#include <unistd.h>
    31#include "ioctl.h"
    32
    33const char *usage =
    34"Usage: fioclient FIOC_FILE [size]\n"
    35"\n"
    36"Get size if <size> is omitted, set size otherwise\n"
    37"\n";
    38
    39int main(int argc, char **argv)
    40{
    41 size_t size;
    42 int fd;
    43 int ret = 0;
    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 ret = 1;
    60 goto out;
    61 }
    62 printf("%zu\n", size);
    63 } else {
    64 size = strtoul(argv[2], NULL, 0);
    65 if (ioctl(fd, FIOC_SET_SIZE, &size)) {
    66 perror("ioctl");
    67 ret = 1;
    68 goto out;
    69 }
    70 }
    71out:
    72 close(fd);
    73 return ret;
    74}
    fuse-3.18.3/doc/html/notify__inval__entry_8c_source.html0000644000175000017500000021456215250106404022316 0ustar berndbernd libfuse: example/notify_inval_entry.c Source File
    libfuse
    notify_inval_entry.c
    Go to the documentation of this file.
    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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    83
    84#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    85
    86#include <fuse_lowlevel.h>
    87#include <stdio.h>
    88#include <stdlib.h>
    89#include <string.h>
    90#include <errno.h>
    91#include <fcntl.h>
    92#include <assert.h>
    93#include <signal.h>
    94#include <stddef.h>
    95#include <sys/stat.h>
    96#include <unistd.h>
    97#include <pthread.h>
    98
    99#define MAX_STR_LEN 128
    100static char file_name[MAX_STR_LEN];
    101static fuse_ino_t file_ino = 2;
    102static int lookup_cnt = 0;
    103static pthread_t main_thread;
    104
    105/* Command line parsing */
    106struct options {
    107 int no_notify;
    108 float timeout;
    109 int update_interval;
    110 int only_expire;
    111 int inc_epoch;
    112};
    113static struct options options = {
    114 .timeout = 5,
    115 .no_notify = 0,
    116 .update_interval = 1,
    117 .only_expire = 0,
    118 .inc_epoch = 0,
    119};
    120
    121#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    122static const struct fuse_opt option_spec[] = {
    123 OPTION("--no-notify", no_notify),
    124 OPTION("--update-interval=%d", update_interval),
    125 OPTION("--timeout=%f", timeout),
    126 OPTION("--only-expire", only_expire),
    127 OPTION("--inc-epoch", inc_epoch),
    129};
    130
    131static int tfs_stat(fuse_ino_t ino, struct stat *stbuf)
    132{
    133 stbuf->st_ino = ino;
    134 if (ino == FUSE_ROOT_ID) {
    135 stbuf->st_mode = S_IFDIR | 0755;
    136 stbuf->st_nlink = 1;
    137 }
    138
    139 else if (ino == file_ino) {
    140 stbuf->st_mode = S_IFREG | 0000;
    141 stbuf->st_nlink = 1;
    142 stbuf->st_size = 0;
    143 }
    144
    145 else
    146 return -1;
    147
    148 return 0;
    149}
    150
    151static void tfs_init(void *userdata, struct fuse_conn_info *conn)
    152{
    153 (void)userdata;
    154
    155 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    156 conn->no_interrupt = 1;
    157}
    158
    159static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    160{
    161 struct fuse_entry_param e;
    162 memset(&e, 0, sizeof(e));
    163
    164 if (parent != FUSE_ROOT_ID)
    165 goto err_out;
    166 else if (strcmp(name, file_name) == 0) {
    167 e.ino = file_ino;
    168 lookup_cnt++;
    169 } else
    170 goto err_out;
    171
    172 e.attr_timeout = options.timeout;
    173 e.entry_timeout = options.timeout;
    174 if (tfs_stat(e.ino, &e.attr) != 0)
    175 goto err_out;
    176 fuse_reply_entry(req, &e);
    177 return;
    178
    179err_out:
    180 fuse_reply_err(req, ENOENT);
    181}
    182
    183static void tfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    184{
    185 (void)req;
    186 if (ino == file_ino)
    187 lookup_cnt -= nlookup;
    188 else
    189 assert(ino == FUSE_ROOT_ID);
    190 fuse_reply_none(req);
    191}
    192
    193static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    194 struct fuse_file_info *fi)
    195{
    196 struct stat stbuf;
    197
    198 (void)fi;
    199
    200 memset(&stbuf, 0, sizeof(stbuf));
    201 if (tfs_stat(ino, &stbuf) != 0)
    202 fuse_reply_err(req, ENOENT);
    203 else
    204 fuse_reply_attr(req, &stbuf, options.timeout);
    205}
    206
    207struct dirbuf {
    208 char *p;
    209 size_t size;
    210};
    211
    212static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    213 fuse_ino_t ino)
    214{
    215 struct stat stbuf;
    216 size_t oldsize = b->size;
    217 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    218 b->p = (char *)realloc(b->p, b->size);
    219 memset(&stbuf, 0, sizeof(stbuf));
    220 stbuf.st_ino = ino;
    221 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    222 b->size);
    223}
    224
    225#define min(x, y) ((x) < (y) ? (x) : (y))
    226
    227static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    228 off_t off, size_t maxsize)
    229{
    230 if (off < bufsize)
    231 return fuse_reply_buf(req, buf + off,
    232 min(bufsize - off, maxsize));
    233 else
    234 return fuse_reply_buf(req, NULL, 0);
    235}
    236
    237static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    238 struct fuse_file_info *fi)
    239{
    240 (void)fi;
    241
    242 if (ino != FUSE_ROOT_ID)
    243 fuse_reply_err(req, ENOTDIR);
    244 else {
    245 struct dirbuf b;
    246
    247 memset(&b, 0, sizeof(b));
    248 dirbuf_add(req, &b, file_name, file_ino);
    249 reply_buf_limited(req, b.p, b.size, off, size);
    250 free(b.p);
    251 }
    252}
    253
    254static const struct fuse_lowlevel_ops tfs_oper = {
    255 .init = tfs_init,
    256 .lookup = tfs_lookup,
    257 .getattr = tfs_getattr,
    258 .readdir = tfs_readdir,
    259 .forget = tfs_forget,
    260};
    261
    262static void update_fs(void)
    263{
    264 time_t t;
    265 struct tm tmbuf;
    266 struct tm *now;
    267 ssize_t ret;
    268
    269 t = time(NULL);
    270 now = localtime_r(&t, &tmbuf);
    271 assert(now != NULL);
    272
    273 ret = strftime(file_name, MAX_STR_LEN, "Time_is_%Hh_%Mm_%Ss", now);
    274 assert(ret != 0);
    275}
    276
    277static void *update_fs_loop(void *data)
    278{
    279 struct fuse_session *se = (struct fuse_session *)data;
    280 char *old_name;
    281 int ret = 0;
    282
    283 while (!fuse_session_exited(se)) {
    284 old_name = strdup(file_name);
    285 update_fs();
    286
    287 if (!options.no_notify && lookup_cnt) {
    288 if (options.only_expire) { // expire entry
    290 se, FUSE_ROOT_ID, old_name,
    291 strlen(old_name));
    292
    293 // no kernel support
    294 if (ret == -ENOSYS) {
    295 printf("%s not supported by kernel\n",
    296 "fuse_lowlevel_notify_expire_entry");
    297 break;
    298 }
    299
    300 // 1) ret == 0: successful expire of an existing entry
    301 // 2) ret == -ENOENT: kernel has already expired the entry /
    302 // entry does not exist anymore in the kernel
    303 assert(ret == 0 || ret == -ENOENT);
    304 } else if (options.inc_epoch) { // increment epoch
    306
    307 if (ret == -ENOSYS) {
    308 printf("%s not supported by kernel\n",
    309 "fuse_lowlevel_notify_increment_epoch");
    310 break;
    311 }
    312 assert(ret == 0);
    313 } else { // invalidate entry
    315 se, FUSE_ROOT_ID, old_name,
    316 strlen(old_name)) == 0);
    317 }
    318 }
    319 free(old_name);
    320 sleep(options.update_interval);
    321 }
    322
    323 if (ret == -ENOSYS) {
    324 printf("Exiting...\n");
    325
    327 // Make sure to exit now, rather than on next request from userspace
    328 pthread_kill(main_thread, SIGPIPE);
    329 }
    330
    331 return NULL;
    332}
    333
    334static void show_help(const char *progname)
    335{
    336 printf("usage: %s [options] <mountpoint>\n\n", progname);
    337 printf("File-system specific options:\n"
    338 " --timeout=<secs> Timeout for kernel caches\n"
    339 " --update-interval=<secs> Update-rate of file system contents\n"
    340 " --no-notify Disable kernel notifications\n"
    341 " --only-expire Expire entries instead of invalidating them\n"
    342 " --inc-epoch Increment epoch, invalidating all dentries\n"
    343 "\n");
    344}
    345
    346int main(int argc, char *argv[])
    347{
    348 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    349 struct fuse_session *se;
    350 struct fuse_cmdline_opts opts;
    351 struct fuse_loop_config *config;
    352 pthread_t updater;
    353 int ret = -1;
    354
    355 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    356 return 1;
    357
    358 if (fuse_parse_cmdline(&args, &opts) != 0)
    359 return 1;
    360 if (opts.show_help) {
    361 show_help(argv[0]);
    364 ret = 0;
    365 goto err_out1;
    366 } else if (opts.show_version) {
    367 printf("FUSE library version %s\n", fuse_pkgversion());
    369 ret = 0;
    370 goto err_out1;
    371 }
    372 if (options.only_expire && options.inc_epoch) {
    373 printf("'only-expire' and 'inc-epoch' options are exclusive\n");
    374 ret = 0;
    375 goto err_out1;
    376 }
    377
    378 /* Initial contents */
    379 update_fs();
    380
    381 se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), &se);
    382 if (se == NULL)
    383 goto err_out1;
    384
    385 if (fuse_set_signal_handlers(se) != 0)
    386 goto err_out2;
    387
    388 if (fuse_session_mount(se, opts.mountpoint) != 0)
    389 goto err_out3;
    390
    391 fuse_daemonize(opts.foreground);
    392
    393 // Needed to ensure that the main thread continues/restarts processing as soon
    394 // as the fuse session ends (immediately after calling fuse_session_exit() )
    395 // and not only on the next request from userspace
    396 main_thread = pthread_self();
    397
    398 /* Start thread to update file contents */
    399 ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
    400 if (ret != 0) {
    401 fprintf(stderr, "pthread_create failed with %s\n",
    402 strerror(ret));
    403 goto err_out3;
    404 }
    405
    406 /* Block until ctrl+c or fusermount -u */
    407 if (opts.singlethread) {
    408 ret = fuse_session_loop(se);
    409 } else {
    410 config = fuse_loop_cfg_create();
    411 fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    412 fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    413 ret = fuse_session_loop_mt(se, config);
    414 fuse_loop_cfg_destroy(config);
    415 config = NULL;
    416 }
    417
    419err_out3:
    421err_out2:
    423err_out1:
    424 free(opts.mountpoint);
    425 fuse_opt_free_args(&args);
    426
    427 return ret ? 1 : 0;
    428}
    429
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_exited(struct fuse_session *se)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
    int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse_ino_t ino
    fuse-3.18.3/doc/html/notify__inval__inode_8c_source.html0000644000175000017500000021203415250106404022243 0ustar berndbernd libfuse: example/notify_inval_inode.c Source File
    libfuse
    notify_inval_inode.c
    Go to the documentation of this file.
    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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    60
    61#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    62
    63#include <fuse_lowlevel.h>
    64#include <stdio.h>
    65#include <stdlib.h>
    66#include <string.h>
    67#include <errno.h>
    68#include <fcntl.h>
    69#include <assert.h>
    70#include <stddef.h>
    71#include <unistd.h>
    72#include <pthread.h>
    73#include <stdbool.h>
    74#include <stdatomic.h>
    75
    76/* We can't actually tell the kernel that there is no
    77 timeout, so we just send a big value */
    78#define NO_TIMEOUT 500000
    79
    80#define MAX_STR_LEN 128
    81#define FILE_INO 2
    82#define FILE_NAME "current_time"
    83static char file_contents[MAX_STR_LEN];
    84static int lookup_cnt = 0;
    85static size_t file_size;
    86static _Atomic bool is_stop = false;
    87
    88/* Command line parsing */
    89struct options {
    90 int no_notify;
    91 int update_interval;
    92};
    93static struct options options = {
    94 .no_notify = 0,
    95 .update_interval = 1,
    96};
    97
    98#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    99static const struct fuse_opt option_spec[] = {
    100 OPTION("--no-notify", no_notify),
    101 OPTION("--update-interval=%d", update_interval), FUSE_OPT_END
    102};
    103
    104static int tfs_stat(fuse_ino_t ino, struct stat *stbuf)
    105{
    106 stbuf->st_ino = ino;
    107 if (ino == FUSE_ROOT_ID) {
    108 stbuf->st_mode = S_IFDIR | 0755;
    109 stbuf->st_nlink = 1;
    110 }
    111
    112 else if (ino == FILE_INO) {
    113 stbuf->st_mode = S_IFREG | 0444;
    114 stbuf->st_nlink = 1;
    115 stbuf->st_size = file_size;
    116 }
    117
    118 else
    119 return -1;
    120
    121 return 0;
    122}
    123
    124static void tfs_init(void *userdata, struct fuse_conn_info *conn)
    125{
    126 (void)userdata;
    127
    128 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    129 conn->no_interrupt = 1;
    130}
    131
    132static void tfs_destroy(void *userarg)
    133{
    134 (void)userarg;
    135
    136 is_stop = true;
    137}
    138
    139static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    140{
    141 struct fuse_entry_param e;
    142 memset(&e, 0, sizeof(e));
    143
    144 if (parent != FUSE_ROOT_ID)
    145 goto err_out;
    146 else if (strcmp(name, FILE_NAME) == 0) {
    147 e.ino = FILE_INO;
    148 lookup_cnt++;
    149 } else
    150 goto err_out;
    151
    152 e.attr_timeout = NO_TIMEOUT;
    153 e.entry_timeout = NO_TIMEOUT;
    154 if (tfs_stat(e.ino, &e.attr) != 0)
    155 goto err_out;
    156 fuse_reply_entry(req, &e);
    157 return;
    158
    159err_out:
    160 fuse_reply_err(req, ENOENT);
    161}
    162
    163static void tfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    164{
    165 (void)req;
    166 if (ino == FILE_INO)
    167 lookup_cnt -= nlookup;
    168 else
    169 assert(ino == FUSE_ROOT_ID);
    170 fuse_reply_none(req);
    171}
    172
    173static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    174 struct fuse_file_info *fi)
    175{
    176 struct stat stbuf;
    177
    178 (void)fi;
    179
    180 memset(&stbuf, 0, sizeof(stbuf));
    181 if (tfs_stat(ino, &stbuf) != 0)
    182 fuse_reply_err(req, ENOENT);
    183 else
    184 fuse_reply_attr(req, &stbuf, NO_TIMEOUT);
    185}
    186
    187struct dirbuf {
    188 char *p;
    189 size_t size;
    190};
    191
    192static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    193 fuse_ino_t ino)
    194{
    195 struct stat stbuf;
    196 size_t oldsize = b->size;
    197 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    198 b->p = (char *)realloc(b->p, b->size);
    199 memset(&stbuf, 0, sizeof(stbuf));
    200 stbuf.st_ino = ino;
    201 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    202 b->size);
    203}
    204
    205#define min(x, y) ((x) < (y) ? (x) : (y))
    206
    207static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    208 off_t off, size_t maxsize)
    209{
    210 if (off < bufsize)
    211 return fuse_reply_buf(req, buf + off,
    212 min(bufsize - off, maxsize));
    213 else
    214 return fuse_reply_buf(req, NULL, 0);
    215}
    216
    217static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    218 struct fuse_file_info *fi)
    219{
    220 (void)fi;
    221
    222 if (ino != FUSE_ROOT_ID)
    223 fuse_reply_err(req, ENOTDIR);
    224 else {
    225 struct dirbuf b;
    226
    227 memset(&b, 0, sizeof(b));
    228 dirbuf_add(req, &b, FILE_NAME, FILE_INO);
    229 reply_buf_limited(req, b.p, b.size, off, size);
    230 free(b.p);
    231 }
    232}
    233
    234static void tfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    235{
    236 /* Make cache persistent even if file is closed,
    237 this makes it easier to see the effects */
    238 fi->keep_cache = 1;
    239
    240 if (ino == FUSE_ROOT_ID)
    241 fuse_reply_err(req, EISDIR);
    242 else if ((fi->flags & O_ACCMODE) != O_RDONLY)
    243 fuse_reply_err(req, EACCES);
    244 else if (ino == FILE_INO)
    245 fuse_reply_open(req, fi);
    246 else {
    247 // This should not happen
    248 fprintf(stderr, "Got open for non-existing inode!\n");
    249 fuse_reply_err(req, ENOENT);
    250 }
    251}
    252
    253static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    254 struct fuse_file_info *fi)
    255{
    256 (void)fi;
    257
    258 assert(ino == FILE_INO);
    259 reply_buf_limited(req, file_contents, file_size, off, size);
    260}
    261
    262static const struct fuse_lowlevel_ops tfs_oper = {
    263 .init = tfs_init,
    264 .destroy = tfs_destroy,
    265 .lookup = tfs_lookup,
    266 .getattr = tfs_getattr,
    267 .readdir = tfs_readdir,
    268 .open = tfs_open,
    269 .read = tfs_read,
    270 .forget = tfs_forget,
    271};
    272
    273static void update_fs(void)
    274{
    275 struct tm tmbuf;
    276 struct tm *now;
    277 time_t t;
    278 t = time(NULL);
    279 now = localtime_r(&t, &tmbuf);
    280 assert(now != NULL);
    281
    282 file_size = strftime(file_contents, MAX_STR_LEN,
    283 "The current time is %H:%M:%S\n", now);
    284 assert(file_size != 0);
    285}
    286
    287static void *update_fs_loop(void *data)
    288{
    289 struct fuse_session *se = (struct fuse_session *)data;
    290
    291 while (!is_stop) {
    292 update_fs();
    293 if (!options.no_notify && lookup_cnt) {
    294 /* Only send notification if the kernel is aware of the inode */
    295
    296 /* Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they
    297 * might come up during umount, when kernel side already releases
    298 * all inodes, but does not send FUSE_DESTROY yet.
    299 */
    300 int ret = fuse_lowlevel_notify_inval_inode(se, FILE_INO,
    301 0, 0);
    302 if ((ret != 0 && !is_stop) && ret != -ENOENT &&
    303 ret != -EBADF && ret != -ENODEV) {
    304 fprintf(stderr,
    305 "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n",
    306 strerror(-ret), -ret);
    307 abort();
    308 }
    309 }
    310 sleep(options.update_interval);
    311 }
    312 return NULL;
    313}
    314
    315static void show_help(const char *progname)
    316{
    317 printf("usage: %s [options] <mountpoint>\n\n", progname);
    318 printf("File-system specific options:\n"
    319 " --update-interval=<secs> Update-rate of file system contents\n"
    320 " --no-notify Disable kernel notifications\n"
    321 "\n");
    322}
    323
    324int main(int argc, char *argv[])
    325{
    326 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    327 struct fuse_session *se;
    328 struct fuse_cmdline_opts opts;
    329 struct fuse_loop_config *config;
    330 pthread_t updater;
    331 int ret = -1;
    332
    333 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    334 return 1;
    335
    336 if (fuse_parse_cmdline(&args, &opts) != 0) {
    337 ret = 1;
    338 goto err_out1;
    339 }
    340
    341 if (opts.show_help) {
    342 show_help(argv[0]);
    345 ret = 0;
    346 goto err_out1;
    347 } else if (opts.show_version) {
    348 printf("FUSE library version %s\n", fuse_pkgversion());
    350 ret = 0;
    351 goto err_out1;
    352 }
    353
    354 /* Initial contents */
    355 update_fs();
    356
    357 se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL);
    358 if (se == NULL)
    359 goto err_out1;
    360
    361 if (fuse_set_signal_handlers(se) != 0)
    362 goto err_out2;
    363
    364 if (fuse_session_mount(se, opts.mountpoint) != 0)
    365 goto err_out3;
    366
    367 fuse_daemonize(opts.foreground);
    368
    369 /* Start thread to update file contents */
    370 ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
    371 if (ret != 0) {
    372 fprintf(stderr, "pthread_create failed with %s\n",
    373 strerror(ret));
    374 goto err_out3;
    375 }
    376
    377 /* Block until ctrl+c or fusermount -u */
    378 if (opts.singlethread)
    379 ret = fuse_session_loop(se);
    380 else {
    381 config = fuse_loop_cfg_create();
    382 fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    383 fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    384 ret = fuse_session_loop_mt(se, config);
    385 fuse_loop_cfg_destroy(config);
    386 config = NULL;
    387 }
    388
    390err_out3:
    392err_out2:
    394err_out1:
    395 fuse_opt_free_args(&args);
    396 free(opts.mountpoint);
    397
    398 return ret ? 1 : 0;
    399}
    400
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse_ino_t ino
    uint32_t keep_cache
    Definition fuse_common.h:69
    fuse-3.18.3/doc/html/notify__store__retrieve_8c_source.html0000644000175000017500000024362715250106404023031 0ustar berndbernd libfuse: example/notify_store_retrieve.c Source File
    libfuse
    notify_store_retrieve.c
    Go to the documentation of this file.
    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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    59
    60#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    61
    62#include <fuse_lowlevel.h>
    63#include <stdio.h>
    64#include <stdlib.h>
    65#include <string.h>
    66#include <errno.h>
    67#include <fcntl.h>
    68#include <assert.h>
    69#include <stddef.h>
    70#include <unistd.h>
    71#include <pthread.h>
    72#include <stdbool.h>
    73
    74/* We can't actually tell the kernel that there is no
    75 timeout, so we just send a big value */
    76#define NO_TIMEOUT 500000
    77
    78#define MAX_STR_LEN 128
    79#define FILE_INO 2
    80#define FILE_NAME "current_time"
    81static char file_contents[MAX_STR_LEN];
    82static int lookup_cnt = 0;
    83static int open_cnt = 0;
    84static size_t file_size;
    85static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    86
    87/* Keep track if we ever stored data (==1), and
    88 received it back correctly (==2) */
    89static int retrieve_status = 0;
    90
    91static bool is_umount = false;
    92
    93/* updater thread tid */
    94static pthread_t updater;
    95
    96/* Command line parsing */
    97struct options {
    98 int no_notify;
    99 int update_interval;
    100};
    101static struct options options = {
    102 .no_notify = 0,
    103 .update_interval = 1,
    104};
    105
    106#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    107static const struct fuse_opt option_spec[] = {
    108 OPTION("--no-notify", no_notify),
    109 OPTION("--update-interval=%d", update_interval), FUSE_OPT_END
    110};
    111
    112static int tfs_stat(fuse_ino_t ino, struct stat *stbuf)
    113{
    114 stbuf->st_ino = ino;
    115 if (ino == FUSE_ROOT_ID) {
    116 stbuf->st_mode = S_IFDIR | 0755;
    117 stbuf->st_nlink = 1;
    118 }
    119
    120 else if (ino == FILE_INO) {
    121 stbuf->st_mode = S_IFREG | 0444;
    122 stbuf->st_nlink = 1;
    123 stbuf->st_size = file_size;
    124 }
    125
    126 else
    127 return -1;
    128
    129 return 0;
    130}
    131
    132static void tfs_init(void *userdata, struct fuse_conn_info *conn)
    133{
    134 (void)userdata;
    135
    136 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    137 conn->no_interrupt = 1;
    138}
    139
    140static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    141{
    142 struct fuse_entry_param e;
    143 memset(&e, 0, sizeof(e));
    144
    145 if (parent != FUSE_ROOT_ID)
    146 goto err_out;
    147 else if (strcmp(name, FILE_NAME) == 0)
    148 e.ino = FILE_INO;
    149 else
    150 goto err_out;
    151
    152 e.attr_timeout = NO_TIMEOUT;
    153 e.entry_timeout = NO_TIMEOUT;
    154 if (tfs_stat(e.ino, &e.attr) != 0)
    155 goto err_out;
    156 fuse_reply_entry(req, &e);
    157
    158 /*
    159 * must only be set when the kernel knows about the entry,
    160 * otherwise update_fs_loop() might see a positive count, but kernel
    161 * would not have the entry yet
    162 */
    163 if (e.ino == FILE_INO) {
    164 pthread_mutex_lock(&lock);
    165 lookup_cnt++;
    166 pthread_mutex_unlock(&lock);
    167 }
    168
    169 return;
    170
    171err_out:
    172 fuse_reply_err(req, ENOENT);
    173}
    174
    175static void tfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    176{
    177 (void)req;
    178 if (ino == FILE_INO) {
    179 pthread_mutex_lock(&lock);
    180 lookup_cnt -= nlookup;
    181 pthread_mutex_unlock(&lock);
    182 } else
    183 assert(ino == FUSE_ROOT_ID);
    184 fuse_reply_none(req);
    185}
    186
    187static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    188 struct fuse_file_info *fi)
    189{
    190 struct stat stbuf;
    191
    192 (void)fi;
    193
    194 memset(&stbuf, 0, sizeof(stbuf));
    195 if (tfs_stat(ino, &stbuf) != 0)
    196 fuse_reply_err(req, ENOENT);
    197 else
    198 fuse_reply_attr(req, &stbuf, NO_TIMEOUT);
    199}
    200
    201struct dirbuf {
    202 char *p;
    203 size_t size;
    204};
    205
    206static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    207 fuse_ino_t ino)
    208{
    209 struct stat stbuf;
    210 size_t oldsize = b->size;
    211 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    212 b->p = (char *)realloc(b->p, b->size);
    213 memset(&stbuf, 0, sizeof(stbuf));
    214 stbuf.st_ino = ino;
    215 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    216 b->size);
    217}
    218
    219#define min(x, y) ((x) < (y) ? (x) : (y))
    220
    221static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    222 off_t off, size_t maxsize)
    223{
    224 if (off < bufsize)
    225 return fuse_reply_buf(req, buf + off,
    226 min(bufsize - off, maxsize));
    227 else
    228 return fuse_reply_buf(req, NULL, 0);
    229}
    230
    231static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    232 struct fuse_file_info *fi)
    233{
    234 (void)fi;
    235
    236 if (ino != FUSE_ROOT_ID)
    237 fuse_reply_err(req, ENOTDIR);
    238 else {
    239 struct dirbuf b;
    240
    241 memset(&b, 0, sizeof(b));
    242 dirbuf_add(req, &b, FILE_NAME, FILE_INO);
    243 reply_buf_limited(req, b.p, b.size, off, size);
    244 free(b.p);
    245 }
    246}
    247
    248static void tfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    249{
    250 /* Make cache persistent even if file is closed,
    251 this makes it easier to see the effects */
    252 fi->keep_cache = 1;
    253
    254 if (ino == FUSE_ROOT_ID)
    255 fuse_reply_err(req, EISDIR);
    256 else if ((fi->flags & O_ACCMODE) != O_RDONLY)
    257 fuse_reply_err(req, EACCES);
    258 else if (ino == FILE_INO) {
    259 fuse_reply_open(req, fi);
    260 pthread_mutex_lock(&lock);
    261 open_cnt++;
    262 pthread_mutex_unlock(&lock);
    263 } else {
    264 // This should not happen
    265 fprintf(stderr, "Got open for non-existing inode!\n");
    266 fuse_reply_err(req, ENOENT);
    267 }
    268}
    269
    270static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    271 struct fuse_file_info *fi)
    272{
    273 (void)fi;
    274
    275 assert(ino == FILE_INO);
    276 reply_buf_limited(req, file_contents, file_size, off, size);
    277}
    278
    279static void tfs_retrieve_reply(fuse_req_t req, void *cookie, fuse_ino_t ino,
    280 off_t offset, struct fuse_bufvec *data)
    281{
    282 struct fuse_bufvec bufv;
    283 char buf[MAX_STR_LEN];
    284 char *expected;
    285 ssize_t ret;
    286
    287 assert(ino == FILE_INO);
    288 assert(offset == 0);
    289 expected = (char *)cookie;
    290
    291 bufv.count = 1;
    292 bufv.idx = 0;
    293 bufv.off = 0;
    294 bufv.buf[0].size = MAX_STR_LEN;
    295 bufv.buf[0].mem = buf;
    296 bufv.buf[0].flags = 0;
    297
    298 ret = fuse_buf_copy(&bufv, data, 0);
    299 assert(ret > 0);
    300 assert(strncmp(buf, expected, ret) == 0);
    301 free(expected);
    302 retrieve_status = 2;
    303 fuse_reply_none(req);
    304}
    305
    306static void tfs_destroy(void *userdata)
    307{
    308 (void)userdata;
    309
    310 is_umount = true;
    311
    312 pthread_join(updater, NULL);
    313}
    314
    315static const struct fuse_lowlevel_ops tfs_oper = {
    316 .init = tfs_init,
    317 .lookup = tfs_lookup,
    318 .getattr = tfs_getattr,
    319 .readdir = tfs_readdir,
    320 .open = tfs_open,
    321 .read = tfs_read,
    322 .forget = tfs_forget,
    323 .retrieve_reply = tfs_retrieve_reply,
    324 .destroy = tfs_destroy,
    325};
    326
    327static void update_fs(void)
    328{
    329 struct tm tmbuf;
    330 struct tm *now;
    331 time_t t;
    332 t = time(NULL);
    333 now = localtime_r(&t, &tmbuf);
    334 assert(now != NULL);
    335
    336 file_size = strftime(file_contents, MAX_STR_LEN,
    337 "The current time is %H:%M:%S\n", now);
    338 assert(file_size != 0);
    339}
    340
    341static void *update_fs_loop(void *data)
    342{
    343 struct fuse_session *se = (struct fuse_session *)data;
    344 struct fuse_bufvec bufv;
    345 int ret;
    346
    347 while (!is_umount) {
    348 update_fs();
    349 pthread_mutex_lock(&lock);
    350 if (!options.no_notify && open_cnt && lookup_cnt) {
    351 /* Only send notification if the kernel
    352 is aware of the inode */
    353 bufv.count = 1;
    354 bufv.idx = 0;
    355 bufv.off = 0;
    356 bufv.buf[0].size = file_size;
    357 bufv.buf[0].mem = file_contents;
    358 bufv.buf[0].flags = 0;
    359
    360 /*
    361 * Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they
    362 * might come up during umount, when kernel side already releases
    363 * all inodes, but does not send FUSE_DESTROY yet.
    364 */
    365
    366 ret = fuse_lowlevel_notify_store(se, FILE_INO, 0, &bufv,
    367 0);
    368 if ((ret != 0 && !is_umount) && ret != -ENOENT &&
    369 ret != -EBADF && ret != -ENODEV) {
    370 fprintf(stderr,
    371 "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n",
    372 strerror(-ret), -ret);
    373 abort();
    374 }
    375
    376 /* To make sure that everything worked correctly, ask the
    377 kernel to send us back the stored data */
    379 se, FILE_INO, MAX_STR_LEN, 0,
    380 (void *)strdup(file_contents));
    381 assert((ret == 0 || is_umount) || ret == -ENOENT ||
    382 ret == -EBADF || ret != -ENODEV);
    383 if (retrieve_status == 0)
    384 retrieve_status = 1;
    385 }
    386 pthread_mutex_unlock(&lock);
    387 sleep(options.update_interval);
    388 }
    389 return NULL;
    390}
    391
    392static void show_help(const char *progname)
    393{
    394 printf("usage: %s [options] <mountpoint>\n\n", progname);
    395 printf("File-system specific options:\n"
    396 " --update-interval=<secs> Update-rate of file system contents\n"
    397 " --no-notify Disable kernel notifications\n"
    398 "\n");
    399}
    400
    401int main(int argc, char *argv[])
    402{
    403 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    404 struct fuse_session *se;
    405 struct fuse_cmdline_opts opts;
    406 struct fuse_loop_config *config;
    407 int ret = -1;
    408
    409 if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    410 return 1;
    411
    412 if (fuse_parse_cmdline(&args, &opts) != 0)
    413 return 1;
    414 if (opts.show_help) {
    415 show_help(argv[0]);
    418 ret = 0;
    419 goto err_out1;
    420 } else if (opts.show_version) {
    421 printf("FUSE library version %s\n", fuse_pkgversion());
    423 ret = 0;
    424 goto err_out1;
    425 }
    426
    427 /* Initial contents */
    428 update_fs();
    429
    430 se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL);
    431 if (se == NULL)
    432 goto err_out1;
    433
    434 if (fuse_set_signal_handlers(se) != 0)
    435 goto err_out2;
    436
    437 if (fuse_session_mount(se, opts.mountpoint) != 0)
    438 goto err_out3;
    439
    440 fuse_daemonize(opts.foreground);
    441
    442 /* Start thread to update file contents */
    443 ret = pthread_create(&updater, NULL, update_fs_loop, (void *)se);
    444 if (ret != 0) {
    445 fprintf(stderr, "pthread_create failed with %s\n",
    446 strerror(ret));
    447 goto err_out3;
    448 }
    449
    450 /* Block until ctrl+c or fusermount -u */
    451 if (opts.singlethread)
    452 ret = fuse_session_loop(se);
    453 else {
    454 config = fuse_loop_cfg_create();
    455 fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    456 fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    457 ret = fuse_session_loop_mt(se, config);
    458 fuse_loop_cfg_destroy(config);
    459 config = NULL;
    460 }
    461
    462 assert(retrieve_status != 1);
    464err_out3:
    466err_out2:
    468err_out1:
    469 free(opts.mountpoint);
    470 fuse_opt_free_args(&args);
    471
    472 return ret ? 1 : 0;
    473}
    474
    int fuse_set_signal_handlers(struct fuse_session *se)
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    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)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    enum fuse_buf_flags flags
    struct fuse_buf buf[1]
    uint32_t no_interrupt
    fuse_ino_t ino
    uint32_t keep_cache
    Definition fuse_common.h:69
    fuse-3.18.3/doc/html/null_8c_source.html0000644000175000017500000005606015250106404017045 0ustar berndbernd 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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    23
    24
    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
    36static 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
    55static 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
    67static 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
    77static 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
    94static 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
    107static const 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
    115int 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}
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    fuse-3.18.3/doc/html/passthrough_8c_source.html0000644000175000017500000026510215250106404020441 0ustar berndbernd libfuse: example/passthrough.c Source File
    libfuse
    passthrough.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 Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    24
    25
    26#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    27
    28#define _GNU_SOURCE
    29
    30#ifdef linux
    31/* For pread()/pwrite()/utimensat() */
    32#define _XOPEN_SOURCE 700
    33#endif
    34
    35#include <fuse.h>
    36#include <stdio.h>
    37#include <string.h>
    38#include <unistd.h>
    39#include <fcntl.h>
    40#include <sys/stat.h>
    41#include <dirent.h>
    42#include <errno.h>
    43#include <sys/time.h>
    44#ifdef HAVE_SETXATTR
    45#include <sys/xattr.h>
    46#endif
    47
    48#include "passthrough_helpers.h"
    49
    50static int fill_dir_plus = 0;
    51static int readdir_zero_ino;
    52
    53static void *xmp_init(struct fuse_conn_info *conn,
    54 struct fuse_config *cfg)
    55{
    56 (void) conn;
    57 cfg->use_ino = !readdir_zero_ino;
    58
    59 /* parallel_direct_writes feature depends on direct_io features.
    60 To make parallel_direct_writes valid, need either set cfg->direct_io
    61 in current function (recommended in high level API) or set fi->direct_io
    62 in xmp_create() or xmp_open(). */
    63 // cfg->direct_io = 1;
    65
    66 /* Pick up changes from lower filesystem right away. This is
    67 also necessary for better hardlink support. When the kernel
    68 calls the unlink() handler, it does not know the inode of
    69 the to-be-removed entry and can therefore not invalidate
    70 the cache of the associated inode - resulting in an
    71 incorrect st_nlink value being reported for any remaining
    72 hardlinks to this inode. */
    73 if (!cfg->auto_cache) {
    74 cfg->entry_timeout = 0;
    75 cfg->attr_timeout = 0;
    76 cfg->negative_timeout = 0;
    77 }
    78
    79 return NULL;
    80}
    81
    82static int xmp_getattr(const char *path, struct stat *stbuf,
    83 struct fuse_file_info *fi)
    84{
    85 (void) fi;
    86 int res;
    87
    88 res = lstat(path, stbuf);
    89 if (res == -1)
    90 return -errno;
    91
    92 return 0;
    93}
    94
    95static int xmp_access(const char *path, int mask)
    96{
    97 int res;
    98
    99 res = access(path, mask);
    100 if (res == -1)
    101 return -errno;
    102
    103 return 0;
    104}
    105
    106static int xmp_readlink(const char *path, char *buf, size_t size)
    107{
    108 int res;
    109
    110 res = readlink(path, buf, size - 1);
    111 if (res == -1)
    112 return -errno;
    113
    114 buf[res] = '\0';
    115 return 0;
    116}
    117
    118
    119static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    120 off_t offset, struct fuse_file_info *fi,
    121 enum fuse_readdir_flags flags)
    122{
    123 DIR *dp;
    124 struct dirent *de;
    125
    126 (void) offset;
    127 (void) fi;
    128 (void) flags;
    129
    130 dp = opendir(path);
    131 if (dp == NULL)
    132 return -errno;
    133
    134 while ((de = readdir(dp)) != NULL) {
    135 struct stat st;
    136 if (fill_dir_plus) {
    137 fstatat(dirfd(dp), de->d_name, &st,
    138 AT_SYMLINK_NOFOLLOW);
    139 } else {
    140 memset(&st, 0, sizeof(st));
    141 st.st_ino = de->d_ino;
    142 st.st_mode = de->d_type << 12;
    143 }
    144 if (readdir_zero_ino)
    145 st.st_ino = 0;
    146 if (filler(buf, de->d_name, &st, 0, fill_dir_plus))
    147 break;
    148 }
    149
    150 closedir(dp);
    151 return 0;
    152}
    153
    154static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
    155{
    156 int res;
    157
    158 res = mknod_wrapper(AT_FDCWD, path, NULL, mode, rdev);
    159 if (res == -1)
    160 return -errno;
    161
    162 return 0;
    163}
    164
    165static int xmp_mkdir(const char *path, mode_t mode)
    166{
    167 int res;
    168
    169 res = mkdir(path, mode);
    170 if (res == -1)
    171 return -errno;
    172
    173 return 0;
    174}
    175
    176static int xmp_unlink(const char *path)
    177{
    178 int res;
    179
    180 res = unlink(path);
    181 if (res == -1)
    182 return -errno;
    183
    184 return 0;
    185}
    186
    187static int xmp_rmdir(const char *path)
    188{
    189 int res;
    190
    191 res = rmdir(path);
    192 if (res == -1)
    193 return -errno;
    194
    195 return 0;
    196}
    197
    198static int xmp_symlink(const char *from, const char *to)
    199{
    200 int res;
    201
    202 res = symlink(from, to);
    203 if (res == -1)
    204 return -errno;
    205
    206 return 0;
    207}
    208
    209static int xmp_rename(const char *from, const char *to, unsigned int flags)
    210{
    211 int res;
    212
    213 if (flags)
    214 return -EINVAL;
    215
    216 res = rename(from, to);
    217 if (res == -1)
    218 return -errno;
    219
    220 return 0;
    221}
    222
    223static int xmp_link(const char *from, const char *to)
    224{
    225 int res;
    226
    227 res = link(from, to);
    228 if (res == -1)
    229 return -errno;
    230
    231 return 0;
    232}
    233
    234static int xmp_chmod(const char *path, mode_t mode,
    235 struct fuse_file_info *fi)
    236{
    237 (void) fi;
    238 int res;
    239
    240 res = chmod(path, mode);
    241 if (res == -1)
    242 return -errno;
    243
    244 return 0;
    245}
    246
    247static int xmp_chown(const char *path, uid_t uid, gid_t gid,
    248 struct fuse_file_info *fi)
    249{
    250 (void) fi;
    251 int res;
    252
    253 res = lchown(path, uid, gid);
    254 if (res == -1)
    255 return -errno;
    256
    257 return 0;
    258}
    259
    260static int xmp_truncate(const char *path, off_t size,
    261 struct fuse_file_info *fi)
    262{
    263 int res;
    264
    265 if (fi != NULL)
    266 res = ftruncate(fi->fh, size);
    267 else
    268 res = truncate(path, size);
    269 if (res == -1)
    270 return -errno;
    271
    272 return 0;
    273}
    274
    275#ifdef HAVE_UTIMENSAT
    276static int xmp_utimens(const char *path, const struct timespec ts[2],
    277 struct fuse_file_info *fi)
    278{
    279 (void) fi;
    280 int res;
    281
    282 /* don't use utime/utimes since they follow symlinks */
    283 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
    284 if (res == -1)
    285 return -errno;
    286
    287 return 0;
    288}
    289#endif
    290
    291static int xmp_create(const char *path, mode_t mode,
    292 struct fuse_file_info *fi)
    293{
    294 int res;
    295
    296 res = open(path, fi->flags, mode);
    297 if (res == -1)
    298 return -errno;
    299
    300 fi->fh = res;
    301 return 0;
    302}
    303
    304static int xmp_open(const char *path, struct fuse_file_info *fi)
    305{
    306 int res;
    307
    308 res = open(path, fi->flags);
    309 if (res == -1)
    310 return -errno;
    311
    312 /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    313 parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    314 for writes to the same file). */
    315 if (fi->flags & O_DIRECT) {
    316 fi->direct_io = 1;
    318 }
    319
    320 fi->fh = res;
    321 return 0;
    322}
    323
    324static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
    325 struct fuse_file_info *fi)
    326{
    327 int fd;
    328 int res;
    329
    330 if(fi == NULL)
    331 fd = open(path, O_RDONLY);
    332 else
    333 fd = fi->fh;
    334
    335 if (fd == -1)
    336 return -errno;
    337
    338 res = pread(fd, buf, size, offset);
    339 if (res == -1)
    340 res = -errno;
    341
    342 if(fi == NULL)
    343 close(fd);
    344 return res;
    345}
    346
    347static int xmp_write(const char *path, const char *buf, size_t size,
    348 off_t offset, struct fuse_file_info *fi)
    349{
    350 int fd;
    351 int res;
    352
    353 (void) fi;
    354 if(fi == NULL)
    355 fd = open(path, O_WRONLY);
    356 else
    357 fd = fi->fh;
    358
    359 if (fd == -1)
    360 return -errno;
    361
    362 res = pwrite(fd, buf, size, offset);
    363 if (res == -1)
    364 res = -errno;
    365
    366 if(fi == NULL)
    367 close(fd);
    368 return res;
    369}
    370
    371static int xmp_statfs(const char *path, struct statvfs *stbuf)
    372{
    373 int res;
    374
    375 res = statvfs(path, stbuf);
    376 if (res == -1)
    377 return -errno;
    378
    379 return 0;
    380}
    381
    382static int xmp_release(const char *path, struct fuse_file_info *fi)
    383{
    384 (void) path;
    385 close(fi->fh);
    386 return 0;
    387}
    388
    389static int xmp_fsync(const char *path, int isdatasync,
    390 struct fuse_file_info *fi)
    391{
    392 /* Just a stub. This method is optional and can safely be left
    393 unimplemented */
    394
    395 (void) path;
    396 (void) isdatasync;
    397 (void) fi;
    398 return 0;
    399}
    400
    401static int xmp_fallocate(const char *path, int mode,
    402 off_t offset, off_t length, struct fuse_file_info *fi)
    403{
    404 int fd;
    405 int res;
    406
    407 (void) fi;
    408
    409 if(fi == NULL)
    410 fd = open(path, O_WRONLY);
    411 else
    412 fd = fi->fh;
    413
    414 if (fd == -1)
    415 return -errno;
    416
    417 res = do_fallocate(fd, mode, offset, length);
    418
    419 if(fi == NULL)
    420 close(fd);
    421 return res;
    422}
    423
    424#ifdef HAVE_SETXATTR
    425/* xattr operations are optional and can safely be left unimplemented */
    426static int xmp_setxattr(const char *path, const char *name, const char *value,
    427 size_t size, int flags)
    428{
    429 int res = lsetxattr(path, name, value, size, flags);
    430 if (res == -1)
    431 return -errno;
    432 return 0;
    433}
    434
    435static int xmp_getxattr(const char *path, const char *name, char *value,
    436 size_t size)
    437{
    438 int res = lgetxattr(path, name, value, size);
    439 if (res == -1)
    440 return -errno;
    441 return res;
    442}
    443
    444static int xmp_listxattr(const char *path, char *list, size_t size)
    445{
    446 int res = llistxattr(path, list, size);
    447 if (res == -1)
    448 return -errno;
    449 return res;
    450}
    451
    452static int xmp_removexattr(const char *path, const char *name)
    453{
    454 int res = lremovexattr(path, name);
    455 if (res == -1)
    456 return -errno;
    457 return 0;
    458}
    459#endif /* HAVE_SETXATTR */
    460
    461#ifdef HAVE_COPY_FILE_RANGE
    462static ssize_t xmp_copy_file_range(const char *path_in,
    463 struct fuse_file_info *fi_in,
    464 off_t offset_in, const char *path_out,
    465 struct fuse_file_info *fi_out,
    466 off_t offset_out, size_t len, int flags)
    467{
    468 int fd_in, fd_out;
    469 ssize_t res;
    470
    471 if(fi_in == NULL)
    472 fd_in = open(path_in, O_RDONLY);
    473 else
    474 fd_in = fi_in->fh;
    475
    476 if (fd_in == -1)
    477 return -errno;
    478
    479 if(fi_out == NULL)
    480 fd_out = open(path_out, O_WRONLY);
    481 else
    482 fd_out = fi_out->fh;
    483
    484 if (fd_out == -1) {
    485 close(fd_in);
    486 return -errno;
    487 }
    488
    489 res = copy_file_range(fd_in, &offset_in, fd_out, &offset_out, len,
    490 flags);
    491 if (res == -1)
    492 res = -errno;
    493
    494 if (fi_out == NULL)
    495 close(fd_out);
    496 if (fi_in == NULL)
    497 close(fd_in);
    498
    499 return res;
    500}
    501#endif
    502
    503static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
    504{
    505 int fd;
    506 off_t res;
    507
    508 if (fi == NULL)
    509 fd = open(path, O_RDONLY);
    510 else
    511 fd = fi->fh;
    512
    513 if (fd == -1)
    514 return -errno;
    515
    516 res = lseek(fd, off, whence);
    517 if (res == -1)
    518 res = -errno;
    519
    520 if (fi == NULL)
    521 close(fd);
    522 return res;
    523}
    524
    525#ifdef HAVE_STATX
    526static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    527 struct fuse_file_info *fi)
    528{
    529 int fd = -1;
    530 int res;
    531
    532 if (fi)
    533 fd = fi->fh;
    534
    535 res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf);
    536 if (res == -1)
    537 return -errno;
    538
    539 return 0;
    540}
    541#endif
    542
    543static const struct fuse_operations xmp_oper = {
    544 .init = xmp_init,
    545 .getattr = xmp_getattr,
    546 .access = xmp_access,
    547 .readlink = xmp_readlink,
    548 .readdir = xmp_readdir,
    549 .mknod = xmp_mknod,
    550 .mkdir = xmp_mkdir,
    551 .symlink = xmp_symlink,
    552 .unlink = xmp_unlink,
    553 .rmdir = xmp_rmdir,
    554 .rename = xmp_rename,
    555 .link = xmp_link,
    556 .chmod = xmp_chmod,
    557 .chown = xmp_chown,
    558 .truncate = xmp_truncate,
    559#ifdef HAVE_UTIMENSAT
    560 .utimens = xmp_utimens,
    561#endif
    562 .open = xmp_open,
    563 .create = xmp_create,
    564 .read = xmp_read,
    565 .write = xmp_write,
    566 .statfs = xmp_statfs,
    567 .release = xmp_release,
    568 .fsync = xmp_fsync,
    569 .fallocate = xmp_fallocate,
    570#ifdef HAVE_SETXATTR
    571 .setxattr = xmp_setxattr,
    572 .getxattr = xmp_getxattr,
    573 .listxattr = xmp_listxattr,
    574 .removexattr = xmp_removexattr,
    575#endif
    576#ifdef HAVE_COPY_FILE_RANGE
    577 .copy_file_range = xmp_copy_file_range,
    578#endif
    579 .lseek = xmp_lseek,
    580#ifdef HAVE_STATX
    581 .statx = xmp_statx,
    582#endif
    583};
    584
    585int main(int argc, char *argv[])
    586{
    587 enum { MAX_ARGS = 10 };
    588 int i,new_argc;
    589 char *new_argv[MAX_ARGS];
    590
    591 umask(0);
    592 /* Process the "--plus" option apart */
    593 for (i=0, new_argc=0; (i<argc) && (new_argc<MAX_ARGS); i++) {
    594 if (!strcmp(argv[i], "--plus")) {
    595 fill_dir_plus = FUSE_FILL_DIR_PLUS;
    596 } else if (!strcmp(argv[i], "--readdir-zero-inodes")) {
    597 // Return zero inodes from readdir
    598 readdir_zero_ino = 1;
    599 } else {
    600 new_argv[new_argc++] = argv[i];
    601 }
    602 }
    603 return fuse_main(new_argc, new_argv, &xmp_oper, NULL);
    604}
    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:93
    fuse_readdir_flags
    Definition fuse.h:45
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    int32_t auto_cache
    Definition fuse.h:259
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63
    fuse-3.18.3/doc/html/passthrough__fh_8c_source.html0000644000175000017500000034225015250106404021255 0ustar berndbernd libfuse: example/passthrough_fh.c Source File
    libfuse
    passthrough_fh.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 Copyright (C) 2011 Sebastian Pipping <sebastian@pipping.org>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    25
    26#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    27
    28#define _GNU_SOURCE
    29
    30#include <fuse.h>
    31
    32#ifdef HAVE_LIBULOCKMGR
    33#include <ulockmgr.h>
    34#endif
    35
    36#include <stdio.h>
    37#include <stdlib.h>
    38#include <string.h>
    39#include <unistd.h>
    40#include <fcntl.h>
    41#include <sys/stat.h>
    42#include <dirent.h>
    43#include <errno.h>
    44#include <sys/time.h>
    45#ifdef HAVE_SETXATTR
    46#include <sys/xattr.h>
    47#endif
    48#include <sys/file.h> /* flock(2) */
    49
    50#include "passthrough_helpers.h"
    51
    52static void *xmp_init(struct fuse_conn_info *conn,
    53 struct fuse_config *cfg)
    54{
    55 (void) conn;
    56 cfg->use_ino = 1;
    57 cfg->nullpath_ok = 1;
    58
    59 /* parallel_direct_writes feature depends on direct_io features.
    60 To make parallel_direct_writes valid, need either set cfg->direct_io
    61 in current function (recommended in high level API) or set fi->direct_io
    62 in xmp_create() or xmp_open(). */
    63 // cfg->direct_io = 1;
    65
    66 /* Pick up changes from lower filesystem right away. This is
    67 also necessary for better hardlink support. When the kernel
    68 calls the unlink() handler, it does not know the inode of
    69 the to-be-removed entry and can therefore not invalidate
    70 the cache of the associated inode - resulting in an
    71 incorrect st_nlink value being reported for any remaining
    72 hardlinks to this inode. */
    73 cfg->entry_timeout = 0;
    74 cfg->attr_timeout = 0;
    75 cfg->negative_timeout = 0;
    76
    77 return NULL;
    78}
    79
    80static int xmp_getattr(const char *path, struct stat *stbuf,
    81 struct fuse_file_info *fi)
    82{
    83 int res;
    84
    85 (void) path;
    86
    87 if(fi)
    88 res = fstat(fi->fh, stbuf);
    89 else
    90 res = lstat(path, stbuf);
    91 if (res == -1)
    92 return -errno;
    93
    94 return 0;
    95}
    96
    97static int xmp_access(const char *path, int mask)
    98{
    99 int res;
    100
    101 res = access(path, mask);
    102 if (res == -1)
    103 return -errno;
    104
    105 return 0;
    106}
    107
    108static int xmp_readlink(const char *path, char *buf, size_t size)
    109{
    110 int res;
    111
    112 res = readlink(path, buf, size - 1);
    113 if (res == -1)
    114 return -errno;
    115
    116 buf[res] = '\0';
    117 return 0;
    118}
    119
    120struct xmp_dirp {
    121 DIR *dp;
    122 struct dirent *entry;
    123 off_t offset;
    124};
    125
    126static int xmp_opendir(const char *path, struct fuse_file_info *fi)
    127{
    128 int res;
    129 struct xmp_dirp *d = malloc(sizeof(struct xmp_dirp));
    130 if (d == NULL)
    131 return -ENOMEM;
    132
    133 d->dp = opendir(path);
    134 if (d->dp == NULL) {
    135 res = -errno;
    136 free(d);
    137 return res;
    138 }
    139 d->offset = 0;
    140 d->entry = NULL;
    141
    142 fi->fh = (unsigned long) d;
    143 return 0;
    144}
    145
    146static inline struct xmp_dirp *get_dirp(struct fuse_file_info *fi)
    147{
    148 return (struct xmp_dirp *) (uintptr_t) fi->fh;
    149}
    150
    151static int xmp_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    152 off_t offset, struct fuse_file_info *fi,
    153 enum fuse_readdir_flags flags)
    154{
    155 struct xmp_dirp *d = get_dirp(fi);
    156
    157 (void) path;
    158 if (offset != d->offset) {
    159#ifndef __FreeBSD__
    160 seekdir(d->dp, offset);
    161#else
    162 /* Subtract the one that we add when calling
    163 telldir() below */
    164 seekdir(d->dp, offset-1);
    165#endif
    166 d->entry = NULL;
    167 d->offset = offset;
    168 }
    169 while (1) {
    170 struct stat st;
    171 off_t nextoff;
    173
    174 if (!d->entry) {
    175 d->entry = readdir(d->dp);
    176 if (!d->entry)
    177 break;
    178 }
    179#ifdef HAVE_FSTATAT
    180 if (flags & FUSE_READDIR_PLUS) {
    181 int res;
    182
    183 res = fstatat(dirfd(d->dp), d->entry->d_name, &st,
    184 AT_SYMLINK_NOFOLLOW);
    185 if (res != -1)
    186 fill_flags |= FUSE_FILL_DIR_PLUS;
    187 }
    188#endif
    189 if (!(fill_flags & FUSE_FILL_DIR_PLUS)) {
    190 memset(&st, 0, sizeof(st));
    191 st.st_ino = d->entry->d_ino;
    192 st.st_mode = d->entry->d_type << 12;
    193 }
    194 nextoff = telldir(d->dp);
    195#ifdef __FreeBSD__
    196 /* Under FreeBSD, telldir() may return 0 the first time
    197 it is called. But for libfuse, an offset of zero
    198 means that offsets are not supported, so we shift
    199 everything by one. */
    200 nextoff++;
    201#endif
    202 if (filler(buf, d->entry->d_name, &st, nextoff, fill_flags))
    203 break;
    204
    205 d->entry = NULL;
    206 d->offset = nextoff;
    207 }
    208
    209 return 0;
    210}
    211
    212static int xmp_releasedir(const char *path, struct fuse_file_info *fi)
    213{
    214 struct xmp_dirp *d = get_dirp(fi);
    215 (void) path;
    216 closedir(d->dp);
    217 free(d);
    218 return 0;
    219}
    220
    221static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
    222{
    223 int res;
    224
    225 if (S_ISFIFO(mode))
    226 res = mkfifo(path, mode);
    227 else
    228 res = mknod(path, mode, rdev);
    229 if (res == -1)
    230 return -errno;
    231
    232 return 0;
    233}
    234
    235static int xmp_mkdir(const char *path, mode_t mode)
    236{
    237 int res;
    238
    239 res = mkdir(path, mode);
    240 if (res == -1)
    241 return -errno;
    242
    243 return 0;
    244}
    245
    246static int xmp_unlink(const char *path)
    247{
    248 int res;
    249
    250 res = unlink(path);
    251 if (res == -1)
    252 return -errno;
    253
    254 return 0;
    255}
    256
    257static int xmp_rmdir(const char *path)
    258{
    259 int res;
    260
    261 res = rmdir(path);
    262 if (res == -1)
    263 return -errno;
    264
    265 return 0;
    266}
    267
    268static int xmp_symlink(const char *from, const char *to)
    269{
    270 int res;
    271
    272 res = symlink(from, to);
    273 if (res == -1)
    274 return -errno;
    275
    276 return 0;
    277}
    278
    279static int xmp_rename(const char *from, const char *to, unsigned int flags)
    280{
    281 int res;
    282
    283 /* When we have renameat2() in libc, then we can implement flags */
    284 if (flags)
    285 return -EINVAL;
    286
    287 res = rename(from, to);
    288 if (res == -1)
    289 return -errno;
    290
    291 return 0;
    292}
    293
    294static int xmp_link(const char *from, const char *to)
    295{
    296 int res;
    297
    298 res = link(from, to);
    299 if (res == -1)
    300 return -errno;
    301
    302 return 0;
    303}
    304
    305static int xmp_chmod(const char *path, mode_t mode,
    306 struct fuse_file_info *fi)
    307{
    308 int res;
    309
    310 if(fi)
    311 res = fchmod(fi->fh, mode);
    312 else
    313 res = chmod(path, mode);
    314 if (res == -1)
    315 return -errno;
    316
    317 return 0;
    318}
    319
    320static int xmp_chown(const char *path, uid_t uid, gid_t gid,
    321 struct fuse_file_info *fi)
    322{
    323 int res;
    324
    325 if (fi)
    326 res = fchown(fi->fh, uid, gid);
    327 else
    328 res = lchown(path, uid, gid);
    329 if (res == -1)
    330 return -errno;
    331
    332 return 0;
    333}
    334
    335static int xmp_truncate(const char *path, off_t size,
    336 struct fuse_file_info *fi)
    337{
    338 int res;
    339
    340 if(fi)
    341 res = ftruncate(fi->fh, size);
    342 else
    343 res = truncate(path, size);
    344
    345 if (res == -1)
    346 return -errno;
    347
    348 return 0;
    349}
    350
    351#ifdef HAVE_UTIMENSAT
    352static int xmp_utimens(const char *path, const struct timespec ts[2],
    353 struct fuse_file_info *fi)
    354{
    355 int res;
    356
    357 /* don't use utime/utimes since they follow symlinks */
    358 if (fi)
    359 res = futimens(fi->fh, ts);
    360 else
    361 res = utimensat(0, path, ts, AT_SYMLINK_NOFOLLOW);
    362 if (res == -1)
    363 return -errno;
    364
    365 return 0;
    366}
    367#endif
    368
    369static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
    370{
    371 int fd;
    372
    373 fd = open(path, fi->flags, mode);
    374 if (fd == -1)
    375 return -errno;
    376
    377 fi->fh = fd;
    378 return 0;
    379}
    380
    381static int xmp_open(const char *path, struct fuse_file_info *fi)
    382{
    383 int fd;
    384
    385 fd = open(path, fi->flags);
    386 if (fd == -1)
    387 return -errno;
    388
    389 /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    390 parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    391 for writes to the same file). */
    392 if (fi->flags & O_DIRECT) {
    393 fi->direct_io = 1;
    395 }
    396
    397 fi->fh = fd;
    398 return 0;
    399}
    400
    401static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
    402 struct fuse_file_info *fi)
    403{
    404 int res;
    405
    406 (void) path;
    407 res = pread(fi->fh, buf, size, offset);
    408 if (res == -1)
    409 res = -errno;
    410
    411 return res;
    412}
    413
    414static int xmp_read_buf(const char *path, struct fuse_bufvec **bufp,
    415 size_t size, off_t offset, struct fuse_file_info *fi)
    416{
    417 struct fuse_bufvec *src;
    418
    419 (void) path;
    420
    421 src = malloc(sizeof(struct fuse_bufvec));
    422 if (src == NULL)
    423 return -ENOMEM;
    424
    425 *src = FUSE_BUFVEC_INIT(size);
    426
    428 src->buf[0].fd = fi->fh;
    429 src->buf[0].pos = offset;
    430
    431 *bufp = src;
    432
    433 return 0;
    434}
    435
    436static int xmp_write(const char *path, const char *buf, size_t size,
    437 off_t offset, struct fuse_file_info *fi)
    438{
    439 int res;
    440
    441 (void) path;
    442 res = pwrite(fi->fh, buf, size, offset);
    443 if (res == -1)
    444 res = -errno;
    445
    446 return res;
    447}
    448
    449static int xmp_write_buf(const char *path, struct fuse_bufvec *buf,
    450 off_t offset, struct fuse_file_info *fi)
    451{
    452 struct fuse_bufvec dst = FUSE_BUFVEC_INIT(fuse_buf_size(buf));
    453
    454 (void) path;
    455
    457 dst.buf[0].fd = fi->fh;
    458 dst.buf[0].pos = offset;
    459
    461}
    462
    463static int xmp_statfs(const char *path, struct statvfs *stbuf)
    464{
    465 int res;
    466
    467 res = statvfs(path, stbuf);
    468 if (res == -1)
    469 return -errno;
    470
    471 return 0;
    472}
    473
    474static int xmp_flush(const char *path, struct fuse_file_info *fi)
    475{
    476 int res;
    477
    478 (void) path;
    479 /* This is called from every close on an open file, so call the
    480 close on the underlying filesystem. But since flush may be
    481 called multiple times for an open file, this must not really
    482 close the file. This is important if used on a network
    483 filesystem like NFS which flush the data/metadata on close() */
    484 res = close(dup(fi->fh));
    485 if (res == -1)
    486 return -errno;
    487
    488 return 0;
    489}
    490
    491static int xmp_release(const char *path, struct fuse_file_info *fi)
    492{
    493 (void) path;
    494 close(fi->fh);
    495
    496 return 0;
    497}
    498
    499static int xmp_fsync(const char *path, int isdatasync,
    500 struct fuse_file_info *fi)
    501{
    502 int res;
    503 (void) path;
    504
    505#ifndef HAVE_FDATASYNC
    506 (void) isdatasync;
    507#else
    508 if (isdatasync)
    509 res = fdatasync(fi->fh);
    510 else
    511#endif
    512 res = fsync(fi->fh);
    513 if (res == -1)
    514 return -errno;
    515
    516 return 0;
    517}
    518
    519static int xmp_fallocate(const char *path, int mode,
    520 off_t offset, off_t length, struct fuse_file_info *fi)
    521{
    522 (void) path;
    523
    524 return do_fallocate(fi->fh, mode, offset, length);
    525}
    526
    527#ifdef HAVE_SETXATTR
    528/* xattr operations are optional and can safely be left unimplemented */
    529static int xmp_setxattr(const char *path, const char *name, const char *value,
    530 size_t size, int flags)
    531{
    532 int res = lsetxattr(path, name, value, size, flags);
    533 if (res == -1)
    534 return -errno;
    535 return 0;
    536}
    537
    538static int xmp_getxattr(const char *path, const char *name, char *value,
    539 size_t size)
    540{
    541 int res = lgetxattr(path, name, value, size);
    542 if (res == -1)
    543 return -errno;
    544 return res;
    545}
    546
    547static int xmp_listxattr(const char *path, char *list, size_t size)
    548{
    549 int res = llistxattr(path, list, size);
    550 if (res == -1)
    551 return -errno;
    552 return res;
    553}
    554
    555static int xmp_removexattr(const char *path, const char *name)
    556{
    557 int res = lremovexattr(path, name);
    558 if (res == -1)
    559 return -errno;
    560 return 0;
    561}
    562#endif /* HAVE_SETXATTR */
    563
    564#ifdef HAVE_LIBULOCKMGR
    565static int xmp_lock(const char *path, struct fuse_file_info *fi, int cmd,
    566 struct flock *lock)
    567{
    568 (void) path;
    569
    570 return ulockmgr_op(fi->fh, cmd, lock, &fi->lock_owner,
    571 sizeof(fi->lock_owner));
    572}
    573#endif
    574
    575static int xmp_flock(const char *path, struct fuse_file_info *fi, int op)
    576{
    577 int res;
    578 (void) path;
    579
    580 res = flock(fi->fh, op);
    581 if (res == -1)
    582 return -errno;
    583
    584 return 0;
    585}
    586
    587#ifdef HAVE_COPY_FILE_RANGE
    588static ssize_t xmp_copy_file_range(const char *path_in,
    589 struct fuse_file_info *fi_in,
    590 off_t off_in, const char *path_out,
    591 struct fuse_file_info *fi_out,
    592 off_t off_out, size_t len, int flags)
    593{
    594 ssize_t res;
    595 (void) path_in;
    596 (void) path_out;
    597
    598 res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
    599 flags);
    600 if (res == -1)
    601 return -errno;
    602
    603 return res;
    604}
    605#endif
    606
    607static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
    608{
    609 off_t res;
    610 (void) path;
    611
    612 res = lseek(fi->fh, off, whence);
    613 if (res == -1)
    614 return -errno;
    615
    616 return res;
    617}
    618
    619#ifdef HAVE_STATX
    620static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    621 struct fuse_file_info *fi)
    622{
    623 int fd = -1;
    624 int res;
    625
    626 if (fi)
    627 fd = fi->fh;
    628
    629 res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf);
    630 if (res == -1)
    631 return -errno;
    632
    633 return 0;
    634}
    635#endif
    636
    637static const struct fuse_operations xmp_oper = {
    638 .init = xmp_init,
    639 .getattr = xmp_getattr,
    640 .access = xmp_access,
    641 .readlink = xmp_readlink,
    642 .opendir = xmp_opendir,
    643 .readdir = xmp_readdir,
    644 .releasedir = xmp_releasedir,
    645 .mknod = xmp_mknod,
    646 .mkdir = xmp_mkdir,
    647 .symlink = xmp_symlink,
    648 .unlink = xmp_unlink,
    649 .rmdir = xmp_rmdir,
    650 .rename = xmp_rename,
    651 .link = xmp_link,
    652 .chmod = xmp_chmod,
    653 .chown = xmp_chown,
    654 .truncate = xmp_truncate,
    655#ifdef HAVE_UTIMENSAT
    656 .utimens = xmp_utimens,
    657#endif
    658 .create = xmp_create,
    659 .open = xmp_open,
    660 .read = xmp_read,
    661 .read_buf = xmp_read_buf,
    662 .write = xmp_write,
    663 .write_buf = xmp_write_buf,
    664 .statfs = xmp_statfs,
    665 .flush = xmp_flush,
    666 .release = xmp_release,
    667 .fsync = xmp_fsync,
    668 .fallocate = xmp_fallocate,
    669#ifdef HAVE_SETXATTR
    670 .setxattr = xmp_setxattr,
    671 .getxattr = xmp_getxattr,
    672 .listxattr = xmp_listxattr,
    673 .removexattr = xmp_removexattr,
    674#endif
    675#ifdef HAVE_LIBULOCKMGR
    676 .lock = xmp_lock,
    677#endif
    678 .flock = xmp_flock,
    679#ifdef HAVE_COPY_FILE_RANGE
    680 .copy_file_range = xmp_copy_file_range,
    681#endif
    682 .lseek = xmp_lseek,
    683#ifdef HAVE_STATX
    684 .statx = xmp_statx,
    685#endif
    686};
    687
    688int main(int argc, char *argv[])
    689{
    690 umask(0);
    691 return fuse_main(argc, argv, &xmp_oper, NULL);
    692}
    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:93
    fuse_fill_dir_flags
    Definition fuse.h:61
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    @ FUSE_BUF_SPLICE_NONBLOCK
    enum fuse_buf_flags flags
    off_t pos
    struct fuse_buf buf[1]
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint64_t lock_owner
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63
    fuse-3.18.3/doc/html/passthrough__helpers_8h_source.html0000644000175000017500000005046015250106404022326 0ustar berndbernd libfuse: example/passthrough_helpers.h Source File
    libfuse
    passthrough_helpers.h
    1/*
    2 * FUSE: Filesystem in Userspace
    3 *
    4 * Redistribution and use in source and binary forms, with or without
    5 * modification, are permitted provided that the following conditions
    6 * are met:
    7 * 1. Redistributions of source code must retain the above copyright
    8 * notice, this list of conditions and the following disclaimer.
    9 * 2. Redistributions in binary form must reproduce the above copyright
    10 * notice, this list of conditions and the following disclaimer in the
    11 * documentation and/or other materials provided with the distribution.
    12 *
    13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
    17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    23 * SUCH DAMAGE
    24 */
    25
    26#ifndef FUSE_EXAMPLE_PASSTHROUGH_HELPERS_H_
    27#define FUSE_EXAMPLE_PASSTHROUGH_HELPERS_H_
    28
    29#include <errno.h>
    30#include <fcntl.h>
    31#include <string.h>
    32#include <sys/stat.h>
    33#include <unistd.h>
    34
    35#ifdef __FreeBSD__
    36#include <sys/socket.h>
    37#include <sys/un.h>
    38#endif
    39
    40static inline int do_fallocate(int fd, int mode, off_t offset, off_t length)
    41{
    42#ifdef HAVE_FALLOCATE
    43 if (fallocate(fd, mode, offset, length) == -1)
    44 return -errno;
    45 return 0;
    46#else // HAVE_FALLOCATE
    47
    48#ifdef HAVE_POSIX_FALLOCATE
    49 if (mode == 0)
    50 return -posix_fallocate(fd, offset, length);
    51#endif
    52
    53#ifdef HAVE_FSPACECTL
    54 // 0x3 == FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE
    55 if (mode == 0x3) {
    56 struct spacectl_range sr;
    57
    58 sr.r_offset = offset;
    59 sr.r_len = length;
    60 if (fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, NULL) == -1)
    61 return -errno;
    62 return 0;
    63 }
    64#endif
    65
    66 return -EOPNOTSUPP;
    67#endif // HAVE_FALLOCATE
    68}
    69
    70/*
    71 * Creates files on the underlying file system in response to a FUSE_MKNOD
    72 * operation
    73 */
    74static inline int mknod_wrapper(int dirfd, const char *path, const char *link,
    75 int mode, dev_t rdev)
    76{
    77 int res;
    78
    79 if (S_ISREG(mode)) {
    80 res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode);
    81 if (res >= 0)
    82 res = close(res);
    83 } else if (S_ISDIR(mode)) {
    84 res = mkdirat(dirfd, path, mode);
    85 } else if (S_ISLNK(mode) && link != NULL) {
    86 res = symlinkat(link, dirfd, path);
    87 } else if (S_ISFIFO(mode)) {
    88 res = mkfifoat(dirfd, path, mode);
    89#ifdef __FreeBSD__
    90 } else if (S_ISSOCK(mode)) {
    91 struct sockaddr_un su;
    92 int fd;
    93
    94 if (strlen(path) >= sizeof(su.sun_path)) {
    95 errno = ENAMETOOLONG;
    96 return -1;
    97 }
    98 fd = socket(AF_UNIX, SOCK_STREAM, 0);
    99 if (fd >= 0) {
    100 /*
    101 * We must bind the socket to the underlying file
    102 * system to create the socket file, even though
    103 * we'll never listen on this socket.
    104 */
    105 su.sun_family = AF_UNIX;
    106 strncpy(su.sun_path, path, sizeof(su.sun_path));
    107 res = bindat(dirfd, fd, (struct sockaddr*)&su,
    108 sizeof(su));
    109 if (res == 0)
    110 close(fd);
    111 } else {
    112 res = -1;
    113 }
    114#endif
    115 } else {
    116 res = mknodat(dirfd, path, mode, rdev);
    117 }
    118
    119 return res;
    120}
    121
    122#endif // FUSE_PASSTHROUGH_HELPERS_H_
    fuse-3.18.3/doc/html/passthrough__ll_8c_source.html0000644000175000017500000076450015250106404021275 0ustar berndbernd libfuse: example/passthrough_ll.c Source File
    libfuse
    passthrough_ll.c
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    32
    33#define _GNU_SOURCE
    34#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    35
    36#include <fuse_lowlevel.h>
    37#include <unistd.h>
    38#include <stdlib.h>
    39#include <stdio.h>
    40#include <stddef.h>
    41#include <stdbool.h>
    42#include <string.h>
    43#include <limits.h>
    44#include <dirent.h>
    45#include <assert.h>
    46#include <errno.h>
    47#include <inttypes.h>
    48#include <pthread.h>
    49#include <sys/file.h>
    50#include <sys/xattr.h>
    51
    52#include "passthrough_helpers.h"
    53
    54/* We are re-using pointers to our `struct lo_inode` and `struct
    55 lo_dirp` elements as inodes. This means that we must be able to
    56 store uintptr_t values in a fuse_ino_t variable. The following
    57 incantation checks this condition at compile time. */
    58#if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 6) && !defined __cplusplus
    59_Static_assert(sizeof(fuse_ino_t) >= sizeof(uintptr_t),
    60 "fuse_ino_t too small to hold uintptr_t values!");
    61#else
    62struct _uintptr_to_must_hold_fuse_ino_t_dummy_struct \
    63 { unsigned _uintptr_to_must_hold_fuse_ino_t:
    64 ((sizeof(fuse_ino_t) >= sizeof(uintptr_t)) ? 1 : -1); };
    65#endif
    66
    67struct lo_inode {
    68 struct lo_inode *next; /* protected by lo->mutex */
    69 struct lo_inode *prev; /* protected by lo->mutex */
    70 int fd;
    71 ino_t ino;
    72 dev_t dev;
    73 uint64_t refcount; /* protected by lo->mutex */
    74};
    75
    76enum {
    77 CACHE_NEVER,
    78 CACHE_NORMAL,
    79 CACHE_ALWAYS,
    80};
    81
    82struct lo_data {
    83 pthread_mutex_t mutex;
    84 int debug;
    85 int writeback;
    86 int flock;
    87 int xattr;
    88 char *source;
    89 double timeout;
    90 int cache;
    91 int timeout_set;
    92 struct lo_inode root; /* protected by lo->mutex */
    93};
    94
    95static const struct fuse_opt lo_opts[] = {
    96 { "writeback",
    97 offsetof(struct lo_data, writeback), 1 },
    98 { "no_writeback",
    99 offsetof(struct lo_data, writeback), 0 },
    100 { "source=%s",
    101 offsetof(struct lo_data, source), 0 },
    102 { "flock",
    103 offsetof(struct lo_data, flock), 1 },
    104 { "no_flock",
    105 offsetof(struct lo_data, flock), 0 },
    106 { "xattr",
    107 offsetof(struct lo_data, xattr), 1 },
    108 { "no_xattr",
    109 offsetof(struct lo_data, xattr), 0 },
    110 { "timeout=%lf",
    111 offsetof(struct lo_data, timeout), 0 },
    112 { "timeout=",
    113 offsetof(struct lo_data, timeout_set), 1 },
    114 { "cache=never",
    115 offsetof(struct lo_data, cache), CACHE_NEVER },
    116 { "cache=auto",
    117 offsetof(struct lo_data, cache), CACHE_NORMAL },
    118 { "cache=always",
    119 offsetof(struct lo_data, cache), CACHE_ALWAYS },
    120
    122};
    123
    124static void passthrough_ll_help(void)
    125{
    126 printf(
    127" -o writeback Enable writeback\n"
    128" -o no_writeback Disable write back\n"
    129" -o source=/home/dir Source directory to be mounted\n"
    130" -o flock Enable flock\n"
    131" -o no_flock Disable flock\n"
    132" -o xattr Enable xattr\n"
    133" -o no_xattr Disable xattr\n"
    134" -o timeout=1.0 Caching timeout\n"
    135" -o timeout=0/1 Timeout is set\n"
    136" -o cache=never Disable cache\n"
    137" -o cache=auto Auto enable cache\n"
    138" -o cache=always Cache always\n");
    139}
    140
    141static struct lo_data *lo_data(fuse_req_t req)
    142{
    143 return (struct lo_data *) fuse_req_userdata(req);
    144}
    145
    146static struct lo_inode *lo_inode(fuse_req_t req, fuse_ino_t ino)
    147{
    148 if (ino == FUSE_ROOT_ID)
    149 return &lo_data(req)->root;
    150 else
    151 return (struct lo_inode *) (uintptr_t) ino;
    152}
    153
    154static int lo_fd(fuse_req_t req, fuse_ino_t ino)
    155{
    156 return lo_inode(req, ino)->fd;
    157}
    158
    159static bool lo_debug(fuse_req_t req)
    160{
    161 return lo_data(req)->debug != 0;
    162}
    163
    164static void lo_init(void *userdata,
    165 struct fuse_conn_info *conn)
    166{
    167 struct lo_data *lo = (struct lo_data *)userdata;
    168 bool has_flag;
    169
    170 if (lo->writeback) {
    172 if (lo->debug && has_flag)
    173 fuse_log(FUSE_LOG_DEBUG,
    174 "lo_init: activating writeback\n");
    175 }
    176 if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
    178 if (lo->debug && has_flag)
    179 fuse_log(FUSE_LOG_DEBUG,
    180 "lo_init: activating flock locks\n");
    181 }
    182
    183 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    184 conn->no_interrupt = 1;
    185}
    186
    187static void lo_destroy(void *userdata)
    188{
    189 struct lo_data *lo = (struct lo_data*) userdata;
    190
    191 while (lo->root.next != &lo->root) {
    192 struct lo_inode* next = lo->root.next;
    193 lo->root.next = next->next;
    194 close(next->fd);
    195 free(next);
    196 }
    197}
    198
    199static void lo_getattr(fuse_req_t req, fuse_ino_t ino,
    200 struct fuse_file_info *fi)
    201{
    202 int res;
    203 struct stat buf;
    204 struct lo_data *lo = lo_data(req);
    205 int fd = fi ? fi->fh : lo_fd(req, ino);
    206
    207 (void) fi;
    208
    209 res = fstatat(fd, "", &buf, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    210 if (res == -1)
    211 return (void) fuse_reply_err(req, errno);
    212
    213 fuse_reply_attr(req, &buf, lo->timeout);
    214}
    215
    216static void lo_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
    217 int valid, struct fuse_file_info *fi)
    218{
    219 int saverr;
    220 char procname[64];
    221 struct lo_inode *inode = lo_inode(req, ino);
    222 int ifd = inode->fd;
    223 int res;
    224
    225 if (valid & FUSE_SET_ATTR_MODE) {
    226 if (fi) {
    227 res = fchmod(fi->fh, attr->st_mode);
    228 } else {
    229 sprintf(procname, "/proc/self/fd/%i", ifd);
    230 res = chmod(procname, attr->st_mode);
    231 }
    232 if (res == -1)
    233 goto out_err;
    234 }
    235 if (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
    236 uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
    237 attr->st_uid : (uid_t) -1;
    238 gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
    239 attr->st_gid : (gid_t) -1;
    240
    241 res = fchownat(ifd, "", uid, gid,
    242 AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    243 if (res == -1)
    244 goto out_err;
    245 }
    246 if (valid & FUSE_SET_ATTR_SIZE) {
    247 if (fi) {
    248 res = ftruncate(fi->fh, attr->st_size);
    249 } else {
    250 sprintf(procname, "/proc/self/fd/%i", ifd);
    251 res = truncate(procname, attr->st_size);
    252 }
    253 if (res == -1)
    254 goto out_err;
    255 }
    256 if (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
    257 struct timespec tv[2];
    258
    259 tv[0].tv_sec = 0;
    260 tv[1].tv_sec = 0;
    261 tv[0].tv_nsec = UTIME_OMIT;
    262 tv[1].tv_nsec = UTIME_OMIT;
    263
    264 if (valid & FUSE_SET_ATTR_ATIME_NOW)
    265 tv[0].tv_nsec = UTIME_NOW;
    266 else if (valid & FUSE_SET_ATTR_ATIME)
    267 tv[0] = attr->st_atim;
    268
    269 if (valid & FUSE_SET_ATTR_MTIME_NOW)
    270 tv[1].tv_nsec = UTIME_NOW;
    271 else if (valid & FUSE_SET_ATTR_MTIME)
    272 tv[1] = attr->st_mtim;
    273
    274 if (fi)
    275 res = futimens(fi->fh, tv);
    276 else {
    277 sprintf(procname, "/proc/self/fd/%i", ifd);
    278 res = utimensat(AT_FDCWD, procname, tv, 0);
    279 }
    280 if (res == -1)
    281 goto out_err;
    282 }
    283
    284 return lo_getattr(req, ino, fi);
    285
    286out_err:
    287 saverr = errno;
    288 fuse_reply_err(req, saverr);
    289}
    290
    291static struct lo_inode *lo_find(struct lo_data *lo, struct stat *st)
    292{
    293 struct lo_inode *p;
    294 struct lo_inode *ret = NULL;
    295
    296 pthread_mutex_lock(&lo->mutex);
    297 for (p = lo->root.next; p != &lo->root; p = p->next) {
    298 if (p->ino == st->st_ino && p->dev == st->st_dev) {
    299 assert(p->refcount > 0);
    300 ret = p;
    301 ret->refcount++;
    302 break;
    303 }
    304 }
    305 pthread_mutex_unlock(&lo->mutex);
    306 return ret;
    307}
    308
    309
    310static struct lo_inode *create_new_inode(int fd, struct fuse_entry_param *e, struct lo_data* lo)
    311{
    312 struct lo_inode *inode = NULL;
    313 struct lo_inode *prev, *next;
    314
    315 inode = calloc(1, sizeof(struct lo_inode));
    316 if (!inode)
    317 return NULL;
    318
    319 inode->refcount = 1;
    320 inode->fd = fd;
    321 inode->ino = e->attr.st_ino;
    322 inode->dev = e->attr.st_dev;
    323
    324 pthread_mutex_lock(&lo->mutex);
    325 prev = &lo->root;
    326 next = prev->next;
    327 next->prev = inode;
    328 inode->next = next;
    329 inode->prev = prev;
    330 prev->next = inode;
    331 pthread_mutex_unlock(&lo->mutex);
    332 return inode;
    333}
    334
    335static int fill_entry_param_new_inode(fuse_req_t req, fuse_ino_t parent, int fd, struct fuse_entry_param *e)
    336{
    337 int res;
    338 struct lo_data *lo = lo_data(req);
    339
    340 memset(e, 0, sizeof(*e));
    341 e->attr_timeout = lo->timeout;
    342 e->entry_timeout = lo->timeout;
    343
    344 res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    345 if (res == -1)
    346 return errno;
    347
    348 e->ino = (uintptr_t) create_new_inode(dup(fd), e, lo);
    349
    350 if (lo_debug(req))
    351 fuse_log(FUSE_LOG_DEBUG, " %lli/%d -> %lli\n",
    352 (unsigned long long) parent, fd, (unsigned long long) e->ino);
    353
    354 return 0;
    355
    356}
    357
    358static int lo_do_lookup(fuse_req_t req, fuse_ino_t parent, const char *name,
    359 struct fuse_entry_param *e)
    360{
    361 int newfd;
    362 int res;
    363 int saverr;
    364 struct lo_data *lo = lo_data(req);
    365 struct lo_inode *inode;
    366
    367 memset(e, 0, sizeof(*e));
    368 e->attr_timeout = lo->timeout;
    369 e->entry_timeout = lo->timeout;
    370
    371 newfd = openat(lo_fd(req, parent), name, O_PATH | O_NOFOLLOW);
    372 if (newfd == -1)
    373 goto out_err;
    374
    375 res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    376 if (res == -1)
    377 goto out_err;
    378
    379 inode = lo_find(lo_data(req), &e->attr);
    380 if (inode) {
    381 close(newfd);
    382 newfd = -1;
    383 } else {
    384 inode = create_new_inode(newfd, e, lo);
    385 if (!inode)
    386 goto out_err;
    387 }
    388 e->ino = (uintptr_t) inode;
    389
    390 if (lo_debug(req))
    391 fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
    392 (unsigned long long) parent, name, (unsigned long long) e->ino);
    393
    394 return 0;
    395
    396out_err:
    397 saverr = errno;
    398 if (newfd != -1)
    399 close(newfd);
    400 return saverr;
    401}
    402
    403static void lo_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    404{
    405 struct fuse_entry_param e;
    406 int err;
    407
    408 if (lo_debug(req))
    409 fuse_log(FUSE_LOG_DEBUG, "lo_lookup(parent=%" PRIu64 ", name=%s)\n",
    410 parent, name);
    411
    412 err = lo_do_lookup(req, parent, name, &e);
    413 if (err)
    414 fuse_reply_err(req, err);
    415 else
    416 fuse_reply_entry(req, &e);
    417}
    418
    419static void lo_mknod_symlink(fuse_req_t req, fuse_ino_t parent,
    420 const char *name, mode_t mode, dev_t rdev,
    421 const char *link)
    422{
    423 int res;
    424 int saverr;
    425 struct lo_inode *dir = lo_inode(req, parent);
    426 struct fuse_entry_param e;
    427
    428 res = mknod_wrapper(dir->fd, name, link, mode, rdev);
    429
    430 saverr = errno;
    431 if (res == -1)
    432 goto out;
    433
    434 saverr = lo_do_lookup(req, parent, name, &e);
    435 if (saverr)
    436 goto out;
    437
    438 if (lo_debug(req))
    439 fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
    440 (unsigned long long) parent, name, (unsigned long long) e.ino);
    441
    442 fuse_reply_entry(req, &e);
    443 return;
    444
    445out:
    446 fuse_reply_err(req, saverr);
    447}
    448
    449static void lo_mknod(fuse_req_t req, fuse_ino_t parent,
    450 const char *name, mode_t mode, dev_t rdev)
    451{
    452 lo_mknod_symlink(req, parent, name, mode, rdev, NULL);
    453}
    454
    455static void lo_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
    456 mode_t mode)
    457{
    458 lo_mknod_symlink(req, parent, name, S_IFDIR | mode, 0, NULL);
    459}
    460
    461static void lo_symlink(fuse_req_t req, const char *link,
    462 fuse_ino_t parent, const char *name)
    463{
    464 lo_mknod_symlink(req, parent, name, S_IFLNK, 0, link);
    465}
    466
    467static void lo_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent,
    468 const char *name)
    469{
    470 int res;
    471 struct lo_data *lo = lo_data(req);
    472 struct lo_inode *inode = lo_inode(req, ino);
    473 struct fuse_entry_param e;
    474 char procname[64];
    475 int saverr;
    476
    477 memset(&e, 0, sizeof(struct fuse_entry_param));
    478 e.attr_timeout = lo->timeout;
    479 e.entry_timeout = lo->timeout;
    480
    481 sprintf(procname, "/proc/self/fd/%i", inode->fd);
    482 res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
    483 AT_SYMLINK_FOLLOW);
    484 if (res == -1)
    485 goto out_err;
    486
    487 res = fstatat(inode->fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    488 if (res == -1)
    489 goto out_err;
    490
    491 pthread_mutex_lock(&lo->mutex);
    492 inode->refcount++;
    493 pthread_mutex_unlock(&lo->mutex);
    494 e.ino = (uintptr_t) inode;
    495
    496 if (lo_debug(req))
    497 fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
    498 (unsigned long long) parent, name,
    499 (unsigned long long) e.ino);
    500
    501 fuse_reply_entry(req, &e);
    502 return;
    503
    504out_err:
    505 saverr = errno;
    506 fuse_reply_err(req, saverr);
    507}
    508
    509static void lo_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
    510{
    511 int res;
    512
    513 res = unlinkat(lo_fd(req, parent), name, AT_REMOVEDIR);
    514
    515 fuse_reply_err(req, res == -1 ? errno : 0);
    516}
    517
    518static void lo_rename(fuse_req_t req, fuse_ino_t parent, const char *name,
    519 fuse_ino_t newparent, const char *newname,
    520 unsigned int flags)
    521{
    522 int res;
    523
    524 if (flags) {
    525 fuse_reply_err(req, EINVAL);
    526 return;
    527 }
    528
    529 res = renameat(lo_fd(req, parent), name,
    530 lo_fd(req, newparent), newname);
    531
    532 fuse_reply_err(req, res == -1 ? errno : 0);
    533}
    534
    535static void lo_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
    536{
    537 int res;
    538
    539 res = unlinkat(lo_fd(req, parent), name, 0);
    540
    541 fuse_reply_err(req, res == -1 ? errno : 0);
    542}
    543
    544static void unref_inode(struct lo_data *lo, struct lo_inode *inode, uint64_t n)
    545{
    546 if (!inode)
    547 return;
    548
    549 pthread_mutex_lock(&lo->mutex);
    550 assert(inode->refcount >= n);
    551 inode->refcount -= n;
    552 if (!inode->refcount) {
    553 struct lo_inode *prev, *next;
    554
    555 prev = inode->prev;
    556 next = inode->next;
    557 next->prev = prev;
    558 prev->next = next;
    559
    560 pthread_mutex_unlock(&lo->mutex);
    561 close(inode->fd);
    562 free(inode);
    563
    564 } else {
    565 pthread_mutex_unlock(&lo->mutex);
    566 }
    567}
    568
    569static void lo_forget_one(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    570{
    571 struct lo_data *lo = lo_data(req);
    572 struct lo_inode *inode = lo_inode(req, ino);
    573
    574 if (lo_debug(req)) {
    575 fuse_log(FUSE_LOG_DEBUG, " forget %lli %lli -%lli\n",
    576 (unsigned long long) ino,
    577 (unsigned long long) inode->refcount,
    578 (unsigned long long) nlookup);
    579 }
    580
    581 unref_inode(lo, inode, nlookup);
    582}
    583
    584static void lo_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    585{
    586 lo_forget_one(req, ino, nlookup);
    587 fuse_reply_none(req);
    588}
    589
    590static void lo_forget_multi(fuse_req_t req, size_t count,
    591 struct fuse_forget_data *forgets)
    592{
    593 int i;
    594
    595 for (i = 0; i < count; i++)
    596 lo_forget_one(req, forgets[i].ino, forgets[i].nlookup);
    597 fuse_reply_none(req);
    598}
    599
    600static void lo_readlink(fuse_req_t req, fuse_ino_t ino)
    601{
    602 char buf[PATH_MAX + 1];
    603 int res;
    604
    605 res = readlinkat(lo_fd(req, ino), "", buf, sizeof(buf));
    606 if (res == -1)
    607 return (void) fuse_reply_err(req, errno);
    608
    609 if (res == sizeof(buf))
    610 return (void) fuse_reply_err(req, ENAMETOOLONG);
    611
    612 buf[res] = '\0';
    613
    614 fuse_reply_readlink(req, buf);
    615}
    616
    617struct lo_dirp {
    618 DIR *dp;
    619 struct dirent *entry;
    620 off_t offset;
    621};
    622
    623static struct lo_dirp *lo_dirp(struct fuse_file_info *fi)
    624{
    625 return (struct lo_dirp *) (uintptr_t) fi->fh;
    626}
    627
    628static void lo_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    629{
    630 int error = ENOMEM;
    631 struct lo_data *lo = lo_data(req);
    632 struct lo_dirp *d;
    633 int fd = -1;
    634
    635 d = calloc(1, sizeof(struct lo_dirp));
    636 if (d == NULL)
    637 goto out_err;
    638
    639 fd = openat(lo_fd(req, ino), ".", O_RDONLY);
    640 if (fd == -1)
    641 goto out_errno;
    642
    643 d->dp = fdopendir(fd);
    644 if (d->dp == NULL)
    645 goto out_errno;
    646
    647 d->offset = 0;
    648 d->entry = NULL;
    649
    650 fi->fh = (uintptr_t) d;
    651 if (lo->cache != CACHE_NEVER)
    652 fi->cache_readdir = 1;
    653 if (lo->cache == CACHE_ALWAYS)
    654 fi->keep_cache = 1;
    655 fuse_reply_open(req, fi);
    656 return;
    657
    658out_errno:
    659 error = errno;
    660out_err:
    661 if (d) {
    662 if (fd != -1)
    663 close(fd);
    664 free(d);
    665 }
    666 fuse_reply_err(req, error);
    667}
    668
    669static int is_dot_or_dotdot(const char *name)
    670{
    671 return name[0] == '.' && (name[1] == '\0' ||
    672 (name[1] == '.' && name[2] == '\0'));
    673}
    674
    675static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    676 off_t offset, struct fuse_file_info *fi, int plus)
    677{
    678 struct lo_dirp *d = lo_dirp(fi);
    679 char *buf;
    680 char *p;
    681 size_t rem = size;
    682 int err;
    683
    684 (void) ino;
    685
    686 buf = calloc(1, size);
    687 if (!buf) {
    688 err = ENOMEM;
    689 goto error;
    690 }
    691 p = buf;
    692
    693 if (offset != d->offset) {
    694 seekdir(d->dp, offset);
    695 d->entry = NULL;
    696 d->offset = offset;
    697 }
    698 while (1) {
    699 size_t entsize;
    700 off_t nextoff;
    701 const char *name;
    702
    703 if (!d->entry) {
    704 errno = 0;
    705 d->entry = readdir(d->dp);
    706 if (!d->entry) {
    707 if (errno) { // Error
    708 err = errno;
    709 goto error;
    710 } else { // End of stream
    711 break;
    712 }
    713 }
    714 }
    715 nextoff = d->entry->d_off;
    716 name = d->entry->d_name;
    717 fuse_ino_t entry_ino = 0;
    718 if (plus) {
    719 struct fuse_entry_param e;
    720 if (is_dot_or_dotdot(name)) {
    721 e = (struct fuse_entry_param) {
    722 .attr.st_ino = d->entry->d_ino,
    723 .attr.st_mode = d->entry->d_type << 12,
    724 };
    725 } else {
    726 err = lo_do_lookup(req, ino, name, &e);
    727 if (err)
    728 goto error;
    729 entry_ino = e.ino;
    730 }
    731
    732 entsize = fuse_add_direntry_plus(req, p, rem, name,
    733 &e, nextoff);
    734 } else {
    735 struct stat st = {
    736 .st_ino = d->entry->d_ino,
    737 .st_mode = d->entry->d_type << 12,
    738 };
    739 entsize = fuse_add_direntry(req, p, rem, name,
    740 &st, nextoff);
    741 }
    742 if (entsize > rem) {
    743 if (entry_ino != 0)
    744 lo_forget_one(req, entry_ino, 1);
    745 break;
    746 }
    747
    748 p += entsize;
    749 rem -= entsize;
    750
    751 d->entry = NULL;
    752 d->offset = nextoff;
    753 }
    754
    755 err = 0;
    756error:
    757 // If there's an error, we can only signal it if we haven't stored
    758 // any entries yet - otherwise we'd end up with wrong lookup
    759 // counts for the entries that are already in the buffer. So we
    760 // return what we've collected until that point.
    761 if (err && rem == size)
    762 fuse_reply_err(req, err);
    763 else
    764 fuse_reply_buf(req, buf, size - rem);
    765 free(buf);
    766}
    767
    768static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    769 off_t offset, struct fuse_file_info *fi)
    770{
    771 lo_do_readdir(req, ino, size, offset, fi, 0);
    772}
    773
    774static void lo_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
    775 off_t offset, struct fuse_file_info *fi)
    776{
    777 lo_do_readdir(req, ino, size, offset, fi, 1);
    778}
    779
    780static void lo_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    781{
    782 struct lo_dirp *d = lo_dirp(fi);
    783 (void) ino;
    784 closedir(d->dp);
    785 free(d);
    786 fuse_reply_err(req, 0);
    787}
    788
    789static void lo_tmpfile(fuse_req_t req, fuse_ino_t parent,
    790 mode_t mode, struct fuse_file_info *fi)
    791{
    792 int fd;
    793 struct lo_data *lo = lo_data(req);
    794 struct fuse_entry_param e;
    795 int err;
    796
    797 if (lo_debug(req))
    798 fuse_log(FUSE_LOG_DEBUG, "lo_tmpfile(parent=%" PRIu64 ")\n",
    799 parent);
    800
    801 fd = openat(lo_fd(req, parent), ".",
    802 (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode);
    803 if (fd == -1)
    804 return (void) fuse_reply_err(req, errno);
    805
    806 fi->fh = fd;
    807 if (lo->cache == CACHE_NEVER)
    808 fi->direct_io = 1;
    809 else if (lo->cache == CACHE_ALWAYS)
    810 fi->keep_cache = 1;
    811
    812 /* parallel_direct_writes feature depends on direct_io features.
    813 To make parallel_direct_writes valid, need set fi->direct_io
    814 in current function. */
    816
    817 err = fill_entry_param_new_inode(req, parent, fd, &e);
    818 if (err)
    819 fuse_reply_err(req, err);
    820 else
    821 fuse_reply_create(req, &e, fi);
    822}
    823
    824static void lo_create(fuse_req_t req, fuse_ino_t parent, const char *name,
    825 mode_t mode, struct fuse_file_info *fi)
    826{
    827 int fd;
    828 struct lo_data *lo = lo_data(req);
    829 struct fuse_entry_param e;
    830 int err;
    831
    832 if (lo_debug(req))
    833 fuse_log(FUSE_LOG_DEBUG, "lo_create(parent=%" PRIu64 ", name=%s)\n",
    834 parent, name);
    835
    836 fd = openat(lo_fd(req, parent), name,
    837 (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode);
    838 if (fd == -1)
    839 return (void) fuse_reply_err(req, errno);
    840
    841 fi->fh = fd;
    842 if (lo->cache == CACHE_NEVER)
    843 fi->direct_io = 1;
    844 else if (lo->cache == CACHE_ALWAYS)
    845 fi->keep_cache = 1;
    846
    847 /* parallel_direct_writes feature depends on direct_io features.
    848 To make parallel_direct_writes valid, need set fi->direct_io
    849 in current function. */
    851
    852 err = lo_do_lookup(req, parent, name, &e);
    853 if (err)
    854 fuse_reply_err(req, err);
    855 else
    856 fuse_reply_create(req, &e, fi);
    857}
    858
    859static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
    860 struct fuse_file_info *fi)
    861{
    862 int res;
    863 int fd = dirfd(lo_dirp(fi)->dp);
    864 (void) ino;
    865 if (datasync)
    866 res = fdatasync(fd);
    867 else
    868 res = fsync(fd);
    869 fuse_reply_err(req, res == -1 ? errno : 0);
    870}
    871
    872static void lo_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    873{
    874 int fd;
    875 char buf[64];
    876 struct lo_data *lo = lo_data(req);
    877
    878 if (lo_debug(req))
    879 fuse_log(FUSE_LOG_DEBUG, "lo_open(ino=%" PRIu64 ", flags=%d)\n",
    880 ino, fi->flags);
    881
    882 /* With writeback cache, kernel may send read requests even
    883 when userspace opened write-only */
    884 if (lo->writeback && (fi->flags & O_ACCMODE) == O_WRONLY) {
    885 fi->flags &= ~O_ACCMODE;
    886 fi->flags |= O_RDWR;
    887 }
    888
    889 /* With writeback cache, O_APPEND is handled by the kernel.
    890 This breaks atomicity (since the file may change in the
    891 underlying filesystem, so that the kernel's idea of the
    892 end of the file isn't accurate anymore). In this example,
    893 we just accept that. A more rigorous filesystem may want
    894 to return an error here */
    895 if (lo->writeback && (fi->flags & O_APPEND))
    896 fi->flags &= ~O_APPEND;
    897
    898 sprintf(buf, "/proc/self/fd/%i", lo_fd(req, ino));
    899 fd = open(buf, fi->flags & ~O_NOFOLLOW);
    900 if (fd == -1)
    901 return (void) fuse_reply_err(req, errno);
    902
    903 fi->fh = fd;
    904 if (lo->cache == CACHE_NEVER)
    905 fi->direct_io = 1;
    906 else if (lo->cache == CACHE_ALWAYS)
    907 fi->keep_cache = 1;
    908
    909 /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    910 parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    911 for writes to the same file in the kernel). */
    912 if (fi->flags & O_DIRECT)
    913 fi->direct_io = 1;
    914
    915 /* parallel_direct_writes feature depends on direct_io features.
    916 To make parallel_direct_writes valid, need set fi->direct_io
    917 in current function. */
    919
    920 fuse_reply_open(req, fi);
    921}
    922
    923static void lo_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    924{
    925 (void) ino;
    926
    927 close(fi->fh);
    928 fuse_reply_err(req, 0);
    929}
    930
    931static void lo_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    932{
    933 int res;
    934 (void) ino;
    935 res = close(dup(fi->fh));
    936 fuse_reply_err(req, res == -1 ? errno : 0);
    937}
    938
    939static void lo_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
    940 struct fuse_file_info *fi)
    941{
    942 int res;
    943 (void) ino;
    944 if (datasync)
    945 res = fdatasync(fi->fh);
    946 else
    947 res = fsync(fi->fh);
    948 fuse_reply_err(req, res == -1 ? errno : 0);
    949}
    950
    951static void lo_read(fuse_req_t req, fuse_ino_t ino, size_t size,
    952 off_t offset, struct fuse_file_info *fi)
    953{
    954 struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
    955
    956 if (lo_debug(req))
    957 fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, "
    958 "off=%lu)\n", ino, size, (unsigned long) offset);
    959
    961 buf.buf[0].fd = fi->fh;
    962 buf.buf[0].pos = offset;
    963
    965}
    966
    967static void lo_write_buf(fuse_req_t req, fuse_ino_t ino,
    968 struct fuse_bufvec *in_buf, off_t off,
    969 struct fuse_file_info *fi)
    970{
    971 (void) ino;
    972 ssize_t res;
    973 struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(in_buf));
    974
    976 out_buf.buf[0].fd = fi->fh;
    977 out_buf.buf[0].pos = off;
    978
    979 if (lo_debug(req))
    980 fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%jd)\n",
    981 ino, out_buf.buf[0].size, (intmax_t) off);
    982
    983 res = fuse_buf_copy(&out_buf, in_buf, 0);
    984 if(res < 0)
    985 fuse_reply_err(req, -res);
    986 else
    987 fuse_reply_write(req, (size_t) res);
    988}
    989
    990static void lo_statfs(fuse_req_t req, fuse_ino_t ino)
    991{
    992 int res;
    993 struct statvfs stbuf;
    994
    995 res = fstatvfs(lo_fd(req, ino), &stbuf);
    996 if (res == -1)
    997 fuse_reply_err(req, errno);
    998 else
    999 fuse_reply_statfs(req, &stbuf);
    1000}
    1001
    1002static void lo_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
    1003 off_t offset, off_t length, struct fuse_file_info *fi)
    1004{
    1005 int err;
    1006 (void) ino;
    1007
    1008 err = -do_fallocate(fi->fh, mode, offset, length);
    1009
    1010 fuse_reply_err(req, err);
    1011}
    1012
    1013static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
    1014 int op)
    1015{
    1016 int res;
    1017 (void) ino;
    1018
    1019 res = flock(fi->fh, op);
    1020
    1021 fuse_reply_err(req, res == -1 ? errno : 0);
    1022}
    1023
    1024static void lo_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    1025 size_t size)
    1026{
    1027 char *value = NULL;
    1028 char procname[64];
    1029 struct lo_inode *inode = lo_inode(req, ino);
    1030 ssize_t ret;
    1031 int saverr;
    1032
    1033 saverr = ENOSYS;
    1034 if (!lo_data(req)->xattr)
    1035 goto out;
    1036
    1037 if (lo_debug(req)) {
    1038 fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
    1039 ino, name, size);
    1040 }
    1041
    1042 sprintf(procname, "/proc/self/fd/%i", inode->fd);
    1043
    1044 if (size) {
    1045 value = malloc(size);
    1046 if (!value)
    1047 goto out_err;
    1048
    1049 ret = getxattr(procname, name, value, size);
    1050 if (ret == -1)
    1051 goto out_err;
    1052 saverr = 0;
    1053 if (ret == 0)
    1054 goto out;
    1055
    1056 fuse_reply_buf(req, value, ret);
    1057 } else {
    1058 ret = getxattr(procname, name, NULL, 0);
    1059 if (ret == -1)
    1060 goto out_err;
    1061
    1062 fuse_reply_xattr(req, ret);
    1063 }
    1064out_free:
    1065 free(value);
    1066 return;
    1067
    1068out_err:
    1069 saverr = errno;
    1070out:
    1071 fuse_reply_err(req, saverr);
    1072 goto out_free;
    1073}
    1074
    1075static void lo_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
    1076{
    1077 char *value = NULL;
    1078 char procname[64];
    1079 struct lo_inode *inode = lo_inode(req, ino);
    1080 ssize_t ret;
    1081 int saverr;
    1082
    1083 saverr = ENOSYS;
    1084 if (!lo_data(req)->xattr)
    1085 goto out;
    1086
    1087 if (lo_debug(req)) {
    1088 fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
    1089 ino, size);
    1090 }
    1091
    1092 sprintf(procname, "/proc/self/fd/%i", inode->fd);
    1093
    1094 if (size) {
    1095 value = malloc(size);
    1096 if (!value)
    1097 goto out_err;
    1098
    1099 ret = listxattr(procname, value, size);
    1100 if (ret == -1)
    1101 goto out_err;
    1102 saverr = 0;
    1103 if (ret == 0)
    1104 goto out;
    1105
    1106 fuse_reply_buf(req, value, ret);
    1107 } else {
    1108 ret = listxattr(procname, NULL, 0);
    1109 if (ret == -1)
    1110 goto out_err;
    1111
    1112 fuse_reply_xattr(req, ret);
    1113 }
    1114out_free:
    1115 free(value);
    1116 return;
    1117
    1118out_err:
    1119 saverr = errno;
    1120out:
    1121 fuse_reply_err(req, saverr);
    1122 goto out_free;
    1123}
    1124
    1125static void lo_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    1126 const char *value, size_t size, int flags)
    1127{
    1128 char procname[64];
    1129 struct lo_inode *inode = lo_inode(req, ino);
    1130 ssize_t ret;
    1131 int saverr;
    1132
    1133 saverr = ENOSYS;
    1134 if (!lo_data(req)->xattr)
    1135 goto out;
    1136
    1137 if (lo_debug(req)) {
    1138 fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
    1139 ino, name, value, size);
    1140 }
    1141
    1142 sprintf(procname, "/proc/self/fd/%i", inode->fd);
    1143
    1144 ret = setxattr(procname, name, value, size, flags);
    1145 saverr = ret == -1 ? errno : 0;
    1146
    1147out:
    1148 fuse_reply_err(req, saverr);
    1149}
    1150
    1151static void lo_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
    1152{
    1153 char procname[64];
    1154 struct lo_inode *inode = lo_inode(req, ino);
    1155 ssize_t ret;
    1156 int saverr;
    1157
    1158 saverr = ENOSYS;
    1159 if (!lo_data(req)->xattr)
    1160 goto out;
    1161
    1162 if (lo_debug(req)) {
    1163 fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
    1164 ino, name);
    1165 }
    1166
    1167 sprintf(procname, "/proc/self/fd/%i", inode->fd);
    1168
    1169 ret = removexattr(procname, name);
    1170 saverr = ret == -1 ? errno : 0;
    1171
    1172out:
    1173 fuse_reply_err(req, saverr);
    1174}
    1175
    1176#ifdef HAVE_COPY_FILE_RANGE
    1177static void lo_copy_file_range(fuse_req_t req, fuse_ino_t ino_in, off_t off_in,
    1178 struct fuse_file_info *fi_in,
    1179 fuse_ino_t ino_out, off_t off_out,
    1180 struct fuse_file_info *fi_out, size_t len,
    1181 int flags)
    1182{
    1183 ssize_t res;
    1184
    1185 if (lo_debug(req))
    1186 fuse_log(FUSE_LOG_DEBUG,
    1187 "%s(ino=%lld fd=%lld off=%jd ino=%lld fd=%lld off=%jd, size=%zd, flags=0x%x)\n",
    1188 __func__, (unsigned long long)ino_in,
    1189 (unsigned long long)fi_in->fh,
    1190 (intmax_t) off_in, (unsigned long long)ino_out,
    1191 (unsigned long long)fi_out->fh, (intmax_t) off_out,
    1192 len, flags);
    1193
    1194 res = copy_file_range(fi_in->fh, &off_in, fi_out->fh, &off_out, len,
    1195 flags);
    1196 if (res < 0)
    1197 fuse_reply_err(req, errno);
    1198 else
    1199 fuse_reply_write(req, res);
    1200}
    1201#endif
    1202
    1203static void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
    1204 struct fuse_file_info *fi)
    1205{
    1206 off_t res;
    1207
    1208 (void)ino;
    1209 res = lseek(fi->fh, off, whence);
    1210 if (res != -1)
    1211 fuse_reply_lseek(req, res);
    1212 else
    1213 fuse_reply_err(req, errno);
    1214}
    1215
    1216#ifdef HAVE_STATX
    1217static void lo_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask,
    1218 struct fuse_file_info *fi)
    1219{
    1220 struct lo_data *lo = lo_data(req);
    1221 struct statx buf;
    1222 int res;
    1223 int fd;
    1224
    1225 if (fi)
    1226 fd = fi->fh;
    1227 else
    1228 fd = lo_fd(req, ino);
    1229
    1230 res = statx(fd, "", flags | AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, mask, &buf);
    1231 if (res == -1)
    1232 fuse_reply_err(req, errno);
    1233 else
    1234 fuse_reply_statx(req, 0, &buf, lo->timeout);
    1235}
    1236#endif
    1237
    1238static const struct fuse_lowlevel_ops lo_oper = {
    1239 .init = lo_init,
    1240 .destroy = lo_destroy,
    1241 .lookup = lo_lookup,
    1242 .mkdir = lo_mkdir,
    1243 .mknod = lo_mknod,
    1244 .symlink = lo_symlink,
    1245 .link = lo_link,
    1246 .unlink = lo_unlink,
    1247 .rmdir = lo_rmdir,
    1248 .rename = lo_rename,
    1249 .forget = lo_forget,
    1250 .forget_multi = lo_forget_multi,
    1251 .getattr = lo_getattr,
    1252 .setattr = lo_setattr,
    1253 .readlink = lo_readlink,
    1254 .opendir = lo_opendir,
    1255 .readdir = lo_readdir,
    1256 .readdirplus = lo_readdirplus,
    1257 .releasedir = lo_releasedir,
    1258 .fsyncdir = lo_fsyncdir,
    1259 .create = lo_create,
    1260 .tmpfile = lo_tmpfile,
    1261 .open = lo_open,
    1262 .release = lo_release,
    1263 .flush = lo_flush,
    1264 .fsync = lo_fsync,
    1265 .read = lo_read,
    1266 .write_buf = lo_write_buf,
    1267 .statfs = lo_statfs,
    1268 .fallocate = lo_fallocate,
    1269 .flock = lo_flock,
    1270 .getxattr = lo_getxattr,
    1271 .listxattr = lo_listxattr,
    1272 .setxattr = lo_setxattr,
    1273 .removexattr = lo_removexattr,
    1274#ifdef HAVE_COPY_FILE_RANGE
    1275 .copy_file_range = lo_copy_file_range,
    1276#endif
    1277 .lseek = lo_lseek,
    1278#ifdef HAVE_STATX
    1279 .statx = lo_statx,
    1280#endif
    1281};
    1282
    1283int main(int argc, char *argv[])
    1284{
    1285 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    1286 struct fuse_session *se;
    1287 struct fuse_cmdline_opts opts;
    1288 struct fuse_loop_config *config;
    1289 struct lo_data lo = { .debug = 0,
    1290 .writeback = 0 };
    1291 int ret = -1;
    1292
    1293 /* Don't mask creation mode, kernel already did that */
    1294 umask(0);
    1295
    1296 pthread_mutex_init(&lo.mutex, NULL);
    1297 lo.root.next = lo.root.prev = &lo.root;
    1298 lo.root.fd = -1;
    1299 lo.cache = CACHE_NORMAL;
    1300
    1301 if (fuse_parse_cmdline(&args, &opts) != 0)
    1302 return 1;
    1303 if (opts.show_help) {
    1304 printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
    1307 passthrough_ll_help();
    1308 ret = 0;
    1309 goto err_out1;
    1310 } else if (opts.show_version) {
    1311 printf("FUSE library version %s\n", fuse_pkgversion());
    1313 ret = 0;
    1314 goto err_out1;
    1315 }
    1316
    1317 if(opts.mountpoint == NULL) {
    1318 printf("usage: %s [options] <mountpoint>\n", argv[0]);
    1319 printf(" %s --help\n", argv[0]);
    1320 ret = 1;
    1321 goto err_out1;
    1322 }
    1323
    1324 if (fuse_opt_parse(&args, &lo, lo_opts, NULL)== -1)
    1325 return 1;
    1326
    1327 lo.debug = opts.debug;
    1328 lo.root.refcount = 2;
    1329 if (lo.source) {
    1330 struct stat stat;
    1331 int res;
    1332
    1333 res = lstat(lo.source, &stat);
    1334 if (res == -1) {
    1335 fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
    1336 lo.source);
    1337 exit(1);
    1338 }
    1339 if (!S_ISDIR(stat.st_mode)) {
    1340 fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
    1341 exit(1);
    1342 }
    1343
    1344 } else {
    1345 lo.source = strdup("/");
    1346 if(!lo.source) {
    1347 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    1348 exit(1);
    1349 }
    1350 }
    1351 if (!lo.timeout_set) {
    1352 switch (lo.cache) {
    1353 case CACHE_NEVER:
    1354 lo.timeout = 0.0;
    1355 break;
    1356
    1357 case CACHE_NORMAL:
    1358 lo.timeout = 1.0;
    1359 break;
    1360
    1361 case CACHE_ALWAYS:
    1362 lo.timeout = 86400.0;
    1363 break;
    1364 }
    1365 } else if (lo.timeout < 0) {
    1366 fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
    1367 lo.timeout);
    1368 exit(1);
    1369 }
    1370
    1371 lo.root.fd = open(lo.source, O_PATH);
    1372 if (lo.root.fd == -1) {
    1373 fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
    1374 lo.source);
    1375 exit(1);
    1376 }
    1377
    1378 se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo);
    1379 if (se == NULL)
    1380 goto err_out1;
    1381
    1382 if (fuse_set_signal_handlers(se) != 0)
    1383 goto err_out2;
    1384
    1385 if (fuse_session_mount(se, opts.mountpoint) != 0)
    1386 goto err_out3;
    1387
    1388 fuse_daemonize(opts.foreground);
    1389
    1390 /* Block until ctrl+c or fusermount -u */
    1391 if (opts.singlethread)
    1392 ret = fuse_session_loop(se);
    1393 else {
    1394 config = fuse_loop_cfg_create();
    1395 fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    1396 fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    1397 ret = fuse_session_loop_mt(se, config);
    1398 fuse_loop_cfg_destroy(config);
    1399 config = NULL;
    1400 }
    1401
    1403err_out3:
    1405err_out2:
    1407err_out1:
    1408 free(opts.mountpoint);
    1409 fuse_opt_free_args(&args);
    1410
    1411 if (lo.root.fd >= 0)
    1412 close(lo.root.fd);
    1413
    1414 free(lo.source);
    1415 return ret ? 1 : 0;
    1416}
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_set_signal_handlers(struct fuse_session *se)
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    #define FUSE_CAP_WRITEBACK_CACHE
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    @ FUSE_BUF_SPLICE_MOVE
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    void * fuse_req_userdata(fuse_req_t req)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    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_readlink(fuse_req_t req, const char *link)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_lseek(fuse_req_t req, off_t off)
    void fuse_lowlevel_version(void)
    int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_xattr(fuse_req_t req, size_t count)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    enum fuse_buf_flags flags
    off_t pos
    size_t size
    struct fuse_buf buf[1]
    uint32_t no_interrupt
    uint32_t capable
    double entry_timeout
    fuse_ino_t ino
    double attr_timeout
    struct stat attr
    uint32_t cache_readdir
    Definition fuse_common.h:89
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63
    uint32_t keep_cache
    Definition fuse_common.h:69
    fuse-3.18.3/doc/html/poll_8c_source.html0000644000175000017500000014103415250106404017035 0ustar berndbernd libfuse: example/poll.c Source File
    libfuse
    poll.c
    Go to the documentation of this file.
    1/*
    2 FUSE fsel: FUSE select 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 GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    23
    24#define FUSE_USE_VERSION 31
    25
    26#include <fuse.h>
    27#include <unistd.h>
    28#include <ctype.h>
    29#include <string.h>
    30#include <stdio.h>
    31#include <stdlib.h>
    32#include <errno.h>
    33#include <time.h>
    34#include <pthread.h>
    35#include <poll.h>
    36#include <stdbool.h>
    37
    38/*
    39 * fsel_open_mask is used to limit the number of opens to 1 per file.
    40 * This is to use file index (0-F) as fh as poll support requires
    41 * unique fh per open file. Lifting this would require proper open
    42 * file management.
    43 */
    44static unsigned fsel_open_mask;
    45static const char fsel_hex_map[] = "0123456789ABCDEF";
    46static struct fuse *fsel_fuse; /* needed for poll notification */
    47
    48#define FSEL_CNT_MAX 10 /* each file can store up to 10 chars */
    49#define FSEL_FILES 16
    50
    51static pthread_mutex_t fsel_mutex; /* protects notify_mask and cnt array */
    52static unsigned fsel_poll_notify_mask; /* poll notification scheduled? */
    53static struct fuse_pollhandle *fsel_poll_handle[FSEL_FILES]; /* poll notify handles */
    54static unsigned fsel_cnt[FSEL_FILES]; /* nbytes stored in each file */
    55static _Atomic bool fsel_stop = false;
    56static pthread_t fsel_producer_thread;
    57
    58
    59static int fsel_path_index(const char *path)
    60{
    61 char ch = path[1];
    62
    63 if (strlen(path) != 2 || path[0] != '/' || !isxdigit(ch) || islower(ch))
    64 return -1;
    65 return ch <= '9' ? ch - '0' : ch - 'A' + 10;
    66}
    67
    68static void fsel_destroy(void *private_data)
    69{
    70 (void)private_data;
    71
    72 fsel_stop = true;
    73
    74 pthread_join(fsel_producer_thread, NULL);
    75}
    76
    77static int fsel_getattr(const char *path, struct stat *stbuf,
    78 struct fuse_file_info *fi)
    79{
    80 (void) fi;
    81 int idx;
    82
    83 memset(stbuf, 0, sizeof(struct stat));
    84
    85 if (strcmp(path, "/") == 0) {
    86 stbuf->st_mode = S_IFDIR | 0555;
    87 stbuf->st_nlink = 2;
    88 return 0;
    89 }
    90
    91 idx = fsel_path_index(path);
    92 if (idx < 0)
    93 return -ENOENT;
    94
    95 stbuf->st_mode = S_IFREG | 0444;
    96 stbuf->st_nlink = 1;
    97 stbuf->st_size = fsel_cnt[idx];
    98 return 0;
    99}
    100
    101static int fsel_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    102 off_t offset, struct fuse_file_info *fi,
    103 enum fuse_readdir_flags flags)
    104{
    105 char name[2] = { };
    106 int i;
    107
    108 (void) offset;
    109 (void) fi;
    110 (void) flags;
    111
    112 if (strcmp(path, "/") != 0)
    113 return -ENOENT;
    114
    115 for (i = 0; i < FSEL_FILES; i++) {
    116 name[0] = fsel_hex_map[i];
    117 filler(buf, name, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    118 }
    119
    120 return 0;
    121}
    122
    123static int fsel_open(const char *path, struct fuse_file_info *fi)
    124{
    125 int idx = fsel_path_index(path);
    126
    127 if (idx < 0)
    128 return -ENOENT;
    129 if ((fi->flags & O_ACCMODE) != O_RDONLY)
    130 return -EACCES;
    131 if (fsel_open_mask & (1 << idx))
    132 return -EBUSY;
    133 fsel_open_mask |= (1 << idx);
    134
    135 /*
    136 * fsel files are nonseekable somewhat pipe-like files which
    137 * gets filled up periodically by producer thread and consumed
    138 * on read. Tell FUSE as such.
    139 */
    140 fi->fh = idx;
    141 fi->direct_io = 1;
    142 fi->nonseekable = 1;
    143
    144 return 0;
    145}
    146
    147static int fsel_release(const char *path, struct fuse_file_info *fi)
    148{
    149 int idx = fi->fh;
    150
    151 (void) path;
    152
    153 fsel_open_mask &= ~(1 << idx);
    154 return 0;
    155}
    156
    157static int fsel_read(const char *path, char *buf, size_t size, off_t offset,
    158 struct fuse_file_info *fi)
    159{
    160 int idx = fi->fh;
    161
    162 (void) path;
    163 (void) offset;
    164
    165 pthread_mutex_lock(&fsel_mutex);
    166 if (fsel_cnt[idx] < size)
    167 size = fsel_cnt[idx];
    168 printf("READ %X transferred=%zu cnt=%u\n", idx, size, fsel_cnt[idx]);
    169 fsel_cnt[idx] -= size;
    170 pthread_mutex_unlock(&fsel_mutex);
    171
    172 memset(buf, fsel_hex_map[idx], size);
    173 return size;
    174}
    175
    176static int fsel_poll(const char *path, struct fuse_file_info *fi,
    177 struct fuse_pollhandle *ph, unsigned *reventsp)
    178{
    179 static unsigned polled_zero;
    180 int idx = fi->fh;
    181
    182 (void) path;
    183
    184 /*
    185 * Poll notification requires pointer to struct fuse which
    186 * can't be obtained when using fuse_main(). As notification
    187 * happens only after poll is called, fill it here from
    188 * fuse_context.
    189 */
    190 if (!fsel_fuse) {
    191 struct fuse_context *cxt = fuse_get_context();
    192 if (cxt)
    193 fsel_fuse = cxt->fuse;
    194 }
    195
    196 pthread_mutex_lock(&fsel_mutex);
    197
    198 if (ph != NULL) {
    199 struct fuse_pollhandle *oldph = fsel_poll_handle[idx];
    200
    201 if (oldph)
    203
    204 fsel_poll_notify_mask |= (1 << idx);
    205 fsel_poll_handle[idx] = ph;
    206 }
    207
    208 if (fsel_cnt[idx]) {
    209 *reventsp |= POLLIN;
    210 printf("POLL %X cnt=%u polled_zero=%u\n",
    211 idx, fsel_cnt[idx], polled_zero);
    212 polled_zero = 0;
    213 } else
    214 polled_zero++;
    215
    216 pthread_mutex_unlock(&fsel_mutex);
    217 return 0;
    218}
    219
    220static const struct fuse_operations fsel_oper = {
    221 .destroy = fsel_destroy,
    222 .getattr = fsel_getattr,
    223 .readdir = fsel_readdir,
    224 .open = fsel_open,
    225 .release = fsel_release,
    226 .read = fsel_read,
    227 .poll = fsel_poll,
    228};
    229
    230static void *fsel_producer(void *data)
    231{
    232 const struct timespec interval = { 0, 250000000 };
    233 unsigned idx = 0, nr = 1;
    234
    235 (void) data;
    236
    237 while (!fsel_stop) {
    238 int i, t;
    239
    240 pthread_mutex_lock(&fsel_mutex);
    241
    242 /*
    243 * This is the main producer loop which is executed
    244 * ever 500ms. On each iteration, it fills one byte
    245 * to 1, 2 or 4 files and sends poll notification if
    246 * requested.
    247 */
    248 for (i = 0, t = idx; i < nr;
    249 i++, t = (t + FSEL_FILES / nr) % FSEL_FILES) {
    250 if (fsel_cnt[t] == FSEL_CNT_MAX)
    251 continue;
    252
    253 fsel_cnt[t]++;
    254 if (fsel_fuse && (fsel_poll_notify_mask & (1 << t))) {
    255 struct fuse_pollhandle *ph;
    256
    257 printf("NOTIFY %X\n", t);
    258 ph = fsel_poll_handle[t];
    259 fuse_notify_poll(ph);
    261 fsel_poll_notify_mask &= ~(1 << t);
    262 fsel_poll_handle[t] = NULL;
    263 }
    264 }
    265
    266 idx = (idx + 1) % FSEL_FILES;
    267 if (idx == 0)
    268 nr = (nr * 2) % 7; /* cycle through 1, 2 and 4 */
    269
    270 pthread_mutex_unlock(&fsel_mutex);
    271
    272 nanosleep(&interval, NULL);
    273 }
    274
    275 return NULL;
    276}
    277
    278int main(int argc, char *argv[])
    279{
    280 pthread_attr_t attr;
    281 int ret;
    282
    283 errno = pthread_mutex_init(&fsel_mutex, NULL);
    284 if (errno) {
    285 perror("pthread_mutex_init");
    286 return 1;
    287 }
    288
    289 errno = pthread_attr_init(&attr);
    290 if (errno) {
    291 perror("pthread_attr_init");
    292 return 1;
    293 }
    294
    295 errno = pthread_create(&fsel_producer_thread, &attr, fsel_producer, NULL);
    296 if (errno) {
    297 perror("pthread_create");
    298 return 1;
    299 }
    300
    301 ret = fuse_main(argc, argv, &fsel_oper, NULL);
    302
    303 return ret;
    304}
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    struct fuse * fuse
    Definition fuse.h:879
    uint32_t nonseekable
    Definition fuse_common.h:78
    uint32_t direct_io
    Definition fuse_common.h:63
    fuse-3.18.3/doc/html/poll__client_8c_source.html0000644000175000017500000003107115250106404020531 0ustar berndbernd libfuse: example/poll_client.c Source File
    libfuse
    poll_client.c
    Go to the documentation of this file.
    1/*
    2 FUSE fselclient: FUSE select example client
    3 Copyright (C) 2008 SUSE Linux Products GmbH
    4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    5
    6 This program can be distributed under the terms of the GNU GPLv2.
    7 See the file GPL2.txt.
    8*/
    9
    21
    22
    23#include <sys/select.h>
    24#include <sys/time.h>
    25#include <sys/types.h>
    26#include <sys/stat.h>
    27#include <fcntl.h>
    28#include <unistd.h>
    29#include <ctype.h>
    30#include <stdio.h>
    31#include <stdlib.h>
    32#include <errno.h>
    33
    34int main(void)
    35{
    36 static const char hex_map[] = "0123456789ABCDEF";
    37 const size_t fsel_files = sizeof(hex_map) - 1;
    38 int fds[sizeof(hex_map) - 1];
    39 size_t i, tries;
    40 int nfds;
    41
    42 for (i = 0; i < fsel_files; i++) {
    43 char name[] = { hex_map[i], '\0' };
    44 fds[i] = open(name, O_RDONLY);
    45 if (fds[i] < 0) {
    46 perror("open");
    47 return 1;
    48 }
    49 }
    50 nfds = fds[fsel_files - 1] + 1;
    51
    52 for (tries = 0; tries < fsel_files; tries++) {
    53 static char buf[4096];
    54 fd_set rfds;
    55 int rc;
    56
    57 FD_ZERO(&rfds);
    58 for (i = 0; i < fsel_files; i++)
    59 FD_SET(fds[i], &rfds);
    60
    61 rc = select(nfds, &rfds, NULL, NULL, NULL);
    62
    63 if (rc < 0) {
    64 perror("select");
    65 return 1;
    66 }
    67
    68 for (i = 0; i < fsel_files; i++) {
    69 if (!FD_ISSET(fds[i], &rfds)) {
    70 printf("_: ");
    71 continue;
    72 }
    73 printf("%zX:", i);
    74 rc = read(fds[i], buf, sizeof(buf));
    75 if (rc < 0) {
    76 perror("read");
    77 return 1;
    78 }
    79 printf("%02d ", rc);
    80 }
    81 printf("\n");
    82 }
    83 return 0;
    84}
    fuse-3.18.3/doc/html/printcap_8c_source.html0000644000175000017500000012255315250106404017714 0ustar berndbernd libfuse: example/printcap.c Source File
    libfuse
    printcap.c
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2017 Nikolaus Rath <Nikolaus@rath.org>
    4
    5 This program can be distributed under the terms of the GNU GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    21
    22#define FUSE_USE_VERSION 31
    23
    24#include <fuse_lowlevel.h>
    25#include <stdio.h>
    26#include <unistd.h>
    27#include <string.h>
    28#include <stdlib.h>
    29
    30struct fuse_session *se;
    31
    32// Define a structure to hold capability information
    33struct cap_info {
    34 uint64_t flag;
    35 const char *name;
    36};
    37
    38// Define an array of all capabilities
    39static const struct cap_info capabilities[] = {
    40 {FUSE_CAP_ASYNC_READ, "FUSE_CAP_ASYNC_READ"},
    41 {FUSE_CAP_POSIX_LOCKS, "FUSE_CAP_POSIX_LOCKS"},
    42 {FUSE_CAP_ATOMIC_O_TRUNC, "FUSE_CAP_ATOMIC_O_TRUNC"},
    43 {FUSE_CAP_EXPORT_SUPPORT, "FUSE_CAP_EXPORT_SUPPORT"},
    44 {FUSE_CAP_DONT_MASK, "FUSE_CAP_DONT_MASK"},
    45 {FUSE_CAP_SPLICE_MOVE, "FUSE_CAP_SPLICE_MOVE"},
    46 {FUSE_CAP_SPLICE_READ, "FUSE_CAP_SPLICE_READ"},
    47 {FUSE_CAP_SPLICE_WRITE, "FUSE_CAP_SPLICE_WRITE"},
    48 {FUSE_CAP_FLOCK_LOCKS, "FUSE_CAP_FLOCK_LOCKS"},
    49 {FUSE_CAP_IOCTL_DIR, "FUSE_CAP_IOCTL_DIR"},
    50 {FUSE_CAP_AUTO_INVAL_DATA, "FUSE_CAP_AUTO_INVAL_DATA"},
    51 {FUSE_CAP_READDIRPLUS, "FUSE_CAP_READDIRPLUS"},
    52 {FUSE_CAP_READDIRPLUS_AUTO, "FUSE_CAP_READDIRPLUS_AUTO"},
    53 {FUSE_CAP_ASYNC_DIO, "FUSE_CAP_ASYNC_DIO"},
    54 {FUSE_CAP_WRITEBACK_CACHE, "FUSE_CAP_WRITEBACK_CACHE"},
    55 {FUSE_CAP_NO_OPEN_SUPPORT, "FUSE_CAP_NO_OPEN_SUPPORT"},
    56 {FUSE_CAP_PARALLEL_DIROPS, "FUSE_CAP_PARALLEL_DIROPS"},
    57 {FUSE_CAP_POSIX_ACL, "FUSE_CAP_POSIX_ACL"},
    58 {FUSE_CAP_CACHE_SYMLINKS, "FUSE_CAP_CACHE_SYMLINKS"},
    59 {FUSE_CAP_NO_OPENDIR_SUPPORT, "FUSE_CAP_NO_OPENDIR_SUPPORT"},
    60 {FUSE_CAP_EXPLICIT_INVAL_DATA, "FUSE_CAP_EXPLICIT_INVAL_DATA"},
    61 {FUSE_CAP_EXPIRE_ONLY, "FUSE_CAP_EXPIRE_ONLY"},
    62 {FUSE_CAP_SETXATTR_EXT, "FUSE_CAP_SETXATTR_EXT"},
    63 {FUSE_CAP_HANDLE_KILLPRIV, "FUSE_CAP_HANDLE_KILLPRIV"},
    64 {FUSE_CAP_HANDLE_KILLPRIV_V2, "FUSE_CAP_HANDLE_KILLPRIV_V2"},
    65 {FUSE_CAP_DIRECT_IO_ALLOW_MMAP, "FUSE_CAP_DIRECT_IO_ALLOW_MMAP"},
    66 {FUSE_CAP_NO_EXPORT_SUPPORT, "FUSE_CAP_NO_EXPORT_SUPPORT"},
    67 {FUSE_CAP_PASSTHROUGH, "FUSE_CAP_PASSTHROUGH"},
    68 // Add any new capabilities here
    69 {0, NULL} // Sentinel to mark the end of the array
    70};
    71
    72static void print_capabilities(struct fuse_conn_info *conn)
    73{
    74 printf("Capabilities:\n");
    75 for (const struct cap_info *cap = capabilities; cap->name != NULL; cap++) {
    76 if (fuse_get_feature_flag(conn, cap->flag)) {
    77 printf("\t%s\n", cap->name);
    78 }
    79 }
    80}
    81
    82static void pc_init(void *userdata, struct fuse_conn_info *conn)
    83{
    84 (void) userdata;
    85
    86 printf("Protocol version: %d.%d\n", conn->proto_major,
    87 conn->proto_minor);
    88 print_capabilities(conn);
    90}
    91
    92
    93static const struct fuse_lowlevel_ops pc_oper = {
    94 .init = pc_init,
    95};
    96
    97int main(int argc, char **argv)
    98{
    99 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    100 char *mountpoint;
    101 int ret = -1;
    102
    103 mountpoint = strdup("/tmp/fuse_printcap_XXXXXX");
    104 if(mkdtemp(mountpoint) == NULL) {
    105 perror("mkdtemp");
    106 return 1;
    107 }
    108
    109 printf("FUSE library version %s\n", fuse_pkgversion());
    111
    112 se = fuse_session_new(&args, &pc_oper,
    113 sizeof(pc_oper), NULL);
    114 if (se == NULL)
    115 goto err_out1;
    116
    117 if (fuse_set_signal_handlers(se) != 0)
    118 goto err_out2;
    119
    120 if (fuse_session_mount(se, mountpoint) != 0)
    121 goto err_out3;
    122
    123 ret = fuse_session_loop(se);
    124
    126err_out3:
    128err_out2:
    130err_out1:
    131 rmdir(mountpoint);
    132 free(mountpoint);
    133 fuse_opt_free_args(&args);
    134
    135 return ret ? 1 : 0;
    136}
    #define FUSE_CAP_IOCTL_DIR
    #define FUSE_CAP_DONT_MASK
    #define FUSE_CAP_HANDLE_KILLPRIV
    #define FUSE_CAP_AUTO_INVAL_DATA
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_HANDLE_KILLPRIV_V2
    #define FUSE_CAP_SPLICE_READ
    #define FUSE_CAP_PARALLEL_DIROPS
    #define FUSE_CAP_WRITEBACK_CACHE
    #define FUSE_CAP_EXPIRE_ONLY
    #define FUSE_CAP_ATOMIC_O_TRUNC
    #define FUSE_CAP_ASYNC_READ
    #define FUSE_CAP_SPLICE_WRITE
    #define FUSE_CAP_CACHE_SYMLINKS
    #define FUSE_CAP_POSIX_ACL
    #define FUSE_CAP_EXPORT_SUPPORT
    #define FUSE_CAP_POSIX_LOCKS
    #define FUSE_CAP_EXPLICIT_INVAL_DATA
    #define FUSE_CAP_READDIRPLUS_AUTO
    #define FUSE_CAP_NO_OPENDIR_SUPPORT
    #define FUSE_CAP_ASYNC_DIO
    bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_PASSTHROUGH
    #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP
    #define FUSE_CAP_NO_OPEN_SUPPORT
    #define FUSE_CAP_READDIRPLUS
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_SETXATTR_EXT
    #define FUSE_CAP_SPLICE_MOVE
    #define FUSE_CAP_NO_EXPORT_SUPPORT
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_session_destroy(struct fuse_session *se)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    uint32_t proto_major
    uint32_t proto_minor
    fuse-3.18.3/doc/html/cuse__lowlevel_8h_source.html0000644000175000017500000004246315250106404021111 0ustar berndbernd libfuse: include/cuse_lowlevel.h Source File
    libfuse
    cuse_lowlevel.h
    1/*
    2 CUSE: Character device in Userspace
    3 Copyright (C) 2008-2009 SUSE Linux Products GmbH
    4 Copyright (C) 2008-2009 Tejun Heo <tj@kernel.org>
    5
    6 This program can be distributed under the terms of the GNU LGPLv2.
    7 See the file LGPL2.txt.
    8
    9 Read example/cusexmp.c for usages.
    10*/
    11
    12#ifndef CUSE_LOWLEVEL_H_
    13#define CUSE_LOWLEVEL_H_
    14
    15#ifndef FUSE_USE_VERSION
    16#define FUSE_USE_VERSION 29
    17#endif
    18
    19#include "fuse_lowlevel.h"
    20
    21#include <fcntl.h>
    22#include <sys/types.h>
    23#include <sys/uio.h>
    24
    25#ifdef __cplusplus
    26extern "C" {
    27#endif
    28
    29#define CUSE_UNRESTRICTED_IOCTL (1 << 0) /* use unrestricted ioctl */
    30
    31struct fuse_session;
    32
    33struct cuse_info {
    34 unsigned dev_major;
    35 unsigned dev_minor;
    36 unsigned dev_info_argc;
    37 const char **dev_info_argv;
    38 unsigned flags;
    39};
    40
    41/*
    42 * Most ops behave almost identically to the matching fuse_lowlevel
    43 * ops except that they don't take @ino.
    44 *
    45 * init_done : called after initialization is complete
    46 * read/write : always direct IO, simultaneous operations allowed
    47 * ioctl : might be in unrestricted mode depending on ci->flags
    48 */
    49struct cuse_lowlevel_ops {
    50 void (*init) (void *userdata, struct fuse_conn_info *conn);
    51 void (*init_done) (void *userdata);
    52 void (*destroy) (void *userdata);
    53 void (*open) (fuse_req_t req, struct fuse_file_info *fi);
    54 void (*read) (fuse_req_t req, size_t size, off_t off,
    55 struct fuse_file_info *fi);
    56 void (*write) (fuse_req_t req, const char *buf, size_t size, off_t off,
    57 struct fuse_file_info *fi);
    58 void (*flush) (fuse_req_t req, struct fuse_file_info *fi);
    59 void (*release) (fuse_req_t req, struct fuse_file_info *fi);
    60 void (*fsync) (fuse_req_t req, int datasync, struct fuse_file_info *fi);
    61 void (*ioctl) (fuse_req_t req, int cmd, void *arg,
    62 struct fuse_file_info *fi, unsigned int flags,
    63 const void *in_buf, size_t in_bufsz, size_t out_bufsz);
    64 void (*poll) (fuse_req_t req, struct fuse_file_info *fi,
    65 struct fuse_pollhandle *ph);
    66};
    67
    68struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
    69 const struct cuse_info *ci,
    70 const struct cuse_lowlevel_ops *clop,
    71 void *userdata);
    72
    73struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
    74 const struct cuse_info *ci,
    75 const struct cuse_lowlevel_ops *clop,
    76 int *multithreaded, void *userdata);
    77
    78void cuse_lowlevel_teardown(struct fuse_session *se);
    79
    80int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
    81 const struct cuse_lowlevel_ops *clop, void *userdata);
    82
    83#ifdef __cplusplus
    84}
    85#endif
    86
    87#endif /* CUSE_LOWLEVEL_H_ */
    struct fuse_req * fuse_req_t
    fuse-3.18.3/doc/html/fuse_8h_source.html0000644000175000017500000042601115250106404017037 0ustar berndbernd 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 LGPL2.txt.
    7*/
    8
    9#ifndef FUSE_H_
    10#define FUSE_H_
    11
    18
    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
    29extern "C" {
    30#endif
    31
    32/* ----------------------------------------------------------- *
    33 * Basic FUSE API *
    34 * ----------------------------------------------------------- */
    35
    36/* Forward declaration */
    37struct statx;
    38
    40struct fuse;
    41
    55 FUSE_READDIR_PLUS = (1 << 0)
    56};
    57
    75 FUSE_FILL_DIR_PLUS = (1 << 1)
    76};
    77
    93typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
    94 const struct stat *stbuf, off_t off,
    95 enum fuse_fill_dir_flags flags);
    112 int32_t set_gid;
    113 uint32_t gid;
    114
    119 int32_t set_uid;
    120 uint32_t uid;
    121
    126 int32_t set_mode;
    127 uint32_t umask;
    128
    134
    144
    150
    154 int32_t intr;
    155
    161 int32_t intr_signal;
    162
    173 int32_t remember;
    174
    191 int32_t hard_remove;
    192
    204 int32_t use_ino;
    205
    213 int32_t readdir_ino;
    214
    232 int32_t direct_io;
    233
    252
    259 int32_t auto_cache;
    260
    261 /*
    262 * The timeout in seconds for which file attributes are cached
    263 * for the purpose of checking if auto_cache should flush the
    264 * file data on open.
    265 */
    266 int32_t ac_attr_timeout_set;
    267 double ac_attr_timeout;
    268
    279 int32_t nullpath_ok;
    280
    285 int32_t show_help;
    286 char *modules;
    287 int32_t debug;
    288
    294 uint32_t fmask;
    295 uint32_t dmask;
    296
    304
    319
    320
    324 uint32_t flags;
    325
    329 uint64_t reserved[48];
    330};
    331
    332
    367 int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi);
    368
    377 int (*readlink) (const char *, char *, size_t);
    378
    385 int (*mknod) (const char *, mode_t, dev_t);
    386
    393 int (*mkdir) (const char *, mode_t);
    394
    396 int (*unlink) (const char *);
    397
    399 int (*rmdir) (const char *);
    400
    402 int (*symlink) (const char *, const char *);
    403
    413 int (*rename) (const char *, const char *, unsigned int flags);
    414
    416 int (*link) (const char *, const char *);
    417
    423 int (*chmod) (const char *, mode_t, struct fuse_file_info *fi);
    424
    433 int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi);
    434
    443 int (*truncate) (const char *, off_t, struct fuse_file_info *fi);
    444
    492 int (*open) (const char *, struct fuse_file_info *);
    493
    503 int (*read) (const char *, char *, size_t, off_t,
    504 struct fuse_file_info *);
    505
    515 int (*write) (const char *, const char *, size_t, off_t,
    516 struct fuse_file_info *);
    517
    522 int (*statfs) (const char *, struct statvfs *);
    523
    552 int (*flush) (const char *, struct fuse_file_info *);
    553
    566 int (*release) (const char *, struct fuse_file_info *);
    567
    573 int (*fsync) (const char *, int, struct fuse_file_info *);
    574
    576 int (*setxattr) (const char *, const char *, const char *, size_t, int);
    577
    579 int (*getxattr) (const char *, const char *, char *, size_t);
    580
    582 int (*listxattr) (const char *, char *, size_t);
    583
    585 int (*removexattr) (const char *, const char *);
    586
    595 int (*opendir) (const char *, struct fuse_file_info *);
    596
    619 int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
    620 struct fuse_file_info *, enum fuse_readdir_flags);
    621
    627 int (*releasedir) (const char *, struct fuse_file_info *);
    628
    637 int (*fsyncdir) (const char *, int, struct fuse_file_info *);
    638
    647 void *(*init) (struct fuse_conn_info *conn,
    648 struct fuse_config *cfg);
    649
    655 void (*destroy) (void *private_data);
    656
    666 int (*access) (const char *, int);
    667
    678 int (*create) (const char *, mode_t, struct fuse_file_info *);
    679
    710 int (*lock) (const char *, struct fuse_file_info *, int cmd,
    711 struct flock *);
    712
    725 int (*utimens) (const char *, const struct timespec tv[2],
    726 struct fuse_file_info *fi);
    727
    734 int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
    735
    736#if FUSE_USE_VERSION < 35
    737 int (*ioctl) (const char *, int cmd, void *arg,
    738 struct fuse_file_info *, unsigned int flags, void *data);
    739#else
    756 int (*ioctl) (const char *, unsigned int cmd, void *arg,
    757 struct fuse_file_info *, unsigned int flags, void *data);
    758#endif
    759
    775 int (*poll) (const char *, struct fuse_file_info *,
    776 struct fuse_pollhandle *ph, unsigned *reventsp);
    777
    787 int (*write_buf) (const char *, struct fuse_bufvec *buf, off_t off,
    788 struct fuse_file_info *);
    789
    804 int (*read_buf) (const char *, struct fuse_bufvec **bufp,
    805 size_t size, off_t off, struct fuse_file_info *);
    824 int (*flock) (const char *, struct fuse_file_info *, int op);
    825
    834 int (*fallocate) (const char *, int, off_t, off_t,
    835 struct fuse_file_info *);
    836
    849 ssize_t (*copy_file_range) (const char *path_in,
    850 struct fuse_file_info *fi_in,
    851 off_t offset_in, const char *path_out,
    852 struct fuse_file_info *fi_out,
    853 off_t offset_out, size_t size, int flags);
    854
    858 off_t (*lseek) (const char *, off_t off, int whence, struct fuse_file_info *);
    859
    868 int (*statx)(const char *path, int flags, int mask, struct statx *stxbuf,
    869 struct fuse_file_info *fi);
    870};
    871
    879 struct fuse *fuse;
    880
    882 uid_t uid;
    883
    885 gid_t gid;
    886
    888 pid_t pid;
    889
    892
    894 mode_t umask;
    895};
    896
    902int fuse_main_real_versioned(int argc, char *argv[],
    903 const struct fuse_operations *op, size_t op_size,
    904 struct libfuse_version *version, void *user_data);
    905static inline int fuse_main_real(int argc, char *argv[],
    906 const struct fuse_operations *op,
    907 size_t op_size, void *user_data)
    908{
    909 struct libfuse_version version = { .major = FUSE_MAJOR_VERSION,
    910 .minor = FUSE_MINOR_VERSION,
    911 .hotfix = FUSE_HOTFIX_VERSION,
    912 .padding = 0 };
    913
    914 fuse_log(FUSE_LOG_ERR,
    915 "%s is a libfuse internal function, please use fuse_main()\n",
    916 __func__);
    917
    918 return fuse_main_real_versioned(argc, argv, op, op_size, &version,
    919 user_data);
    920}
    921
    976static inline int fuse_main_fn(int argc, char *argv[],
    977 const struct fuse_operations *op,
    978 void *user_data)
    979{
    980 struct libfuse_version version = {
    981 .major = FUSE_MAJOR_VERSION,
    982 .minor = FUSE_MINOR_VERSION,
    983 .hotfix = FUSE_HOTFIX_VERSION,
    984 .padding = 0
    985 };
    986
    987 return fuse_main_real_versioned(argc, argv, op, sizeof(*(op)), &version,
    988 user_data);
    989}
    990#define fuse_main(argc, argv, op, user_data) \
    991 fuse_main_fn(argc, argv, op, user_data)
    992
    993/* ----------------------------------------------------------- *
    994 * More detailed API *
    995 * ----------------------------------------------------------- */
    996
    1008void fuse_lib_help(struct fuse_args *args);
    1009
    1010/* Do not call this directly, use fuse_new() instead */
    1011struct fuse *_fuse_new_30(struct fuse_args *args,
    1012 const struct fuse_operations *op, size_t op_size,
    1013 struct libfuse_version *version, void *user_data);
    1014struct fuse *_fuse_new_31(struct fuse_args *args,
    1015 const struct fuse_operations *op, size_t op_size,
    1016 struct libfuse_version *version, void *user_data);
    1017
    1045#if FUSE_USE_VERSION == 30
    1046static inline struct fuse *fuse_new_fn(struct fuse_args *args,
    1047 const struct fuse_operations *op,
    1048 size_t op_size, void *user_data)
    1049{
    1050 struct libfuse_version version = {
    1051 .major = FUSE_MAJOR_VERSION,
    1052 .minor = FUSE_MINOR_VERSION,
    1053 .hotfix = FUSE_HOTFIX_VERSION,
    1054 .padding = 0
    1055 };
    1056
    1057 return _fuse_new_30(args, op, op_size, &version, user_data);
    1058}
    1059#else /* FUSE_USE_VERSION */
    1060static inline struct fuse *fuse_new_fn(struct fuse_args *args,
    1061 const struct fuse_operations *op,
    1062 size_t op_size, void *user_data)
    1063{
    1064 struct libfuse_version version = {
    1065 .major = FUSE_MAJOR_VERSION,
    1066 .minor = FUSE_MINOR_VERSION,
    1067 .hotfix = FUSE_HOTFIX_VERSION,
    1068 .padding = 0
    1069 };
    1070
    1071 return _fuse_new_31(args, op, op_size, &version, user_data);
    1072}
    1073#endif
    1074#define fuse_new(args, op, size, data) fuse_new_fn(args, op, size, data)
    1075
    1084int fuse_mount(struct fuse *f, const char *mountpoint);
    1085
    1093void fuse_unmount(struct fuse *f);
    1094
    1103void fuse_destroy(struct fuse *f);
    1104
    1120int fuse_loop(struct fuse *f);
    1121
    1130void fuse_exit(struct fuse *f);
    1131
    1132#if FUSE_USE_VERSION < 32
    1133int fuse_loop_mt_31(struct fuse *f, int clone_fd);
    1134#define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd)
    1135#elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12)
    1136int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config);
    1137#define fuse_loop_mt(f, config) fuse_loop_mt_32(f, config)
    1138#else
    1170#if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS))
    1171int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config);
    1172#else
    1173int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config);
    1174#define fuse_loop_mt(f, config) fuse_loop_mt_312(f, config)
    1175#endif /* LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS */
    1176#endif
    1177
    1178
    1187struct fuse_context *fuse_get_context(void);
    1188
    1207int fuse_getgroups(int size, gid_t list[]);
    1208
    1214int fuse_interrupted(void);
    1215
    1227int fuse_invalidate_path(struct fuse *f, const char *path);
    1228
    1236int fuse_start_cleanup_thread(struct fuse *fuse);
    1237
    1244void fuse_stop_cleanup_thread(struct fuse *fuse);
    1245
    1255int fuse_clean_cache(struct fuse *fuse);
    1256
    1257/*
    1258 * Stacking API
    1259 */
    1260
    1266struct fuse_fs;
    1267
    1268/*
    1269 * These functions call the relevant filesystem operation, and return
    1270 * the result.
    1271 *
    1272 * If the operation is not defined, they return -ENOSYS, with the
    1273 * exception of fuse_fs_open, fuse_fs_release, fuse_fs_opendir,
    1274 * fuse_fs_releasedir and fuse_fs_statfs, which return 0.
    1275 */
    1276
    1277int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
    1278 struct fuse_file_info *fi);
    1279int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
    1280 const char *newpath, unsigned int flags);
    1281int fuse_fs_unlink(struct fuse_fs *fs, const char *path);
    1282int fuse_fs_rmdir(struct fuse_fs *fs, const char *path);
    1283int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname,
    1284 const char *path);
    1285int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath);
    1286int fuse_fs_release(struct fuse_fs *fs, const char *path,
    1287 struct fuse_file_info *fi);
    1288int fuse_fs_open(struct fuse_fs *fs, const char *path,
    1289 struct fuse_file_info *fi);
    1290int fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
    1291 off_t off, struct fuse_file_info *fi);
    1292int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
    1293 struct fuse_bufvec **bufp, size_t size, off_t off,
    1294 struct fuse_file_info *fi);
    1295int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
    1296 size_t size, off_t off, struct fuse_file_info *fi);
    1297int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
    1298 struct fuse_bufvec *buf, off_t off,
    1299 struct fuse_file_info *fi);
    1300int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
    1301 struct fuse_file_info *fi);
    1302int fuse_fs_flush(struct fuse_fs *fs, const char *path,
    1303 struct fuse_file_info *fi);
    1304int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
    1305int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
    1306 struct fuse_file_info *fi);
    1307int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
    1308 fuse_fill_dir_t filler, off_t off,
    1309 struct fuse_file_info *fi, enum fuse_readdir_flags flags);
    1310int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
    1311 struct fuse_file_info *fi);
    1312int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
    1313 struct fuse_file_info *fi);
    1314int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
    1315 struct fuse_file_info *fi);
    1316int fuse_fs_lock(struct fuse_fs *fs, const char *path,
    1317 struct fuse_file_info *fi, int cmd, struct flock *lock);
    1318int fuse_fs_flock(struct fuse_fs *fs, const char *path,
    1319 struct fuse_file_info *fi, int op);
    1320int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
    1321 struct fuse_file_info *fi);
    1322int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid,
    1323 struct fuse_file_info *fi);
    1324int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
    1325 struct fuse_file_info *fi);
    1326int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
    1327 const struct timespec tv[2], struct fuse_file_info *fi);
    1328int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask);
    1329int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
    1330 size_t len);
    1331int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
    1332 dev_t rdev);
    1333int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode);
    1334int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
    1335 const char *value, size_t size, int flags);
    1336int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
    1337 char *value, size_t size);
    1338int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
    1339 size_t size);
    1340int fuse_fs_removexattr(struct fuse_fs *fs, const char *path,
    1341 const char *name);
    1342int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
    1343 uint64_t *idx);
    1344#if FUSE_USE_VERSION < 35
    1345int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd,
    1346 void *arg, struct fuse_file_info *fi, unsigned int flags,
    1347 void *data);
    1348#else
    1349int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
    1350 void *arg, struct fuse_file_info *fi, unsigned int flags,
    1351 void *data);
    1352#endif
    1353int fuse_fs_poll(struct fuse_fs *fs, const char *path,
    1354 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
    1355 unsigned *reventsp);
    1356int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
    1357 off_t offset, off_t length, struct fuse_file_info *fi);
    1358ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
    1359 struct fuse_file_info *fi_in, off_t off_in,
    1360 const char *path_out,
    1361 struct fuse_file_info *fi_out, off_t off_out,
    1362 size_t len, int flags);
    1363off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
    1364 struct fuse_file_info *fi);
    1365int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask,
    1366 struct statx *stxbuf, struct fuse_file_info *fi);
    1367void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
    1368 struct fuse_config *cfg);
    1369void fuse_fs_destroy(struct fuse_fs *fs);
    1370
    1371int fuse_notify_poll(struct fuse_pollhandle *ph);
    1372
    1386struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
    1387 void *private_data);
    1388
    1403typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args,
    1404 struct fuse_fs *fs[]);
    1415#define FUSE_REGISTER_MODULE(name_, factory_) \
    1416 fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
    1417
    1419struct fuse_session *fuse_get_session(struct fuse *f);
    1420
    1429int fuse_open_channel(const char *mountpoint, const char *options);
    1430
    1431#ifdef __cplusplus
    1432}
    1433#endif
    1434
    1435#endif /* FUSE_H_ */
    int fuse_getgroups(int size, gid_t list[])
    Definition fuse.c:4721
    int fuse_mount(struct fuse *f, const char *mountpoint)
    Definition fuse.c:5260
    int fuse_interrupted(void)
    Definition fuse.c:4730
    void fuse_destroy(struct fuse *f)
    Definition fuse.c:5209
    int fuse_main_real_versioned(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data)
    Definition helper.c:317
    int fuse_start_cleanup_thread(struct fuse *fuse)
    Definition fuse.c:4973
    int fuse_invalidate_path(struct fuse *f, const char *path)
    Definition fuse.c:4740
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    int fuse_loop(struct fuse *f)
    Definition fuse.c:4644
    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:93
    void fuse_exit(struct fuse *f)
    Definition fuse.c:4706
    int fuse_clean_cache(struct fuse *fuse)
    Definition fuse.c:4498
    void fuse_lib_help(struct fuse_args *args)
    Definition fuse.c:4813
    int fuse_open_channel(const char *mountpoint, const char *options)
    Definition helper.c:492
    struct fuse_session * fuse_get_session(struct fuse *f)
    Definition fuse.c:4588
    void fuse_unmount(struct fuse *f)
    Definition fuse.c:5265
    struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
    Definition fuse.c:4923
    void fuse_stop_cleanup_thread(struct fuse *fuse)
    Definition fuse.c:4981
    fuse_fill_dir_flags
    Definition fuse.h:61
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    @ FUSE_READDIR_DEFAULTS
    Definition fuse.h:54
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    uint32_t fmask
    Definition fuse.h:294
    int32_t show_help
    Definition fuse.h:285
    uint32_t flags
    Definition fuse.h:324
    int32_t direct_io
    Definition fuse.h:232
    int32_t no_rofd_flush
    Definition fuse.h:303
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t intr_signal
    Definition fuse.h:161
    int32_t remember
    Definition fuse.h:173
    int32_t kernel_cache
    Definition fuse.h:251
    int32_t readdir_ino
    Definition fuse.h:213
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    int32_t set_mode
    Definition fuse.h:126
    int32_t auto_cache
    Definition fuse.h:259
    uint64_t reserved[48]
    Definition fuse.h:329
    int32_t intr
    Definition fuse.h:154
    double negative_timeout
    Definition fuse.h:143
    int32_t set_gid
    Definition fuse.h:112
    int32_t set_uid
    Definition fuse.h:119
    int32_t hard_remove
    Definition fuse.h:191
    double attr_timeout
    Definition fuse.h:149
    void * private_data
    Definition fuse.h:891
    uid_t uid
    Definition fuse.h:882
    pid_t pid
    Definition fuse.h:888
    struct fuse * fuse
    Definition fuse.h:879
    gid_t gid
    Definition fuse.h:885
    mode_t umask
    Definition fuse.h:894
    int(* mknod)(const char *, mode_t, dev_t)
    Definition fuse.h:385
    int(* open)(const char *, struct fuse_file_info *)
    Definition fuse.h:492
    int(* readlink)(const char *, char *, size_t)
    Definition fuse.h:377
    int(* write)(const char *, const char *, size_t, off_t, struct fuse_file_info *)
    Definition fuse.h:515
    int(* fallocate)(const char *, int, off_t, off_t, struct fuse_file_info *)
    Definition fuse.h:834
    int(* read)(const char *, char *, size_t, off_t, struct fuse_file_info *)
    Definition fuse.h:503
    int(* symlink)(const char *, const char *)
    Definition fuse.h:402
    int(* write_buf)(const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *)
    Definition fuse.h:787
    int(* release)(const char *, struct fuse_file_info *)
    Definition fuse.h:566
    int(* access)(const char *, int)
    Definition fuse.h:666
    int(* lock)(const char *, struct fuse_file_info *, int cmd, struct flock *)
    Definition fuse.h:710
    int(* fsyncdir)(const char *, int, struct fuse_file_info *)
    Definition fuse.h:637
    int(* mkdir)(const char *, mode_t)
    Definition fuse.h:393
    int(* chown)(const char *, uid_t, gid_t, struct fuse_file_info *fi)
    Definition fuse.h:433
    int(* unlink)(const char *)
    Definition fuse.h:396
    int(* flush)(const char *, struct fuse_file_info *)
    Definition fuse.h:552
    int(* listxattr)(const char *, char *, size_t)
    Definition fuse.h:582
    int(* truncate)(const char *, off_t, struct fuse_file_info *fi)
    Definition fuse.h:443
    int(* statfs)(const char *, struct statvfs *)
    Definition fuse.h:522
    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)
    Definition fuse.h:849
    int(* create)(const char *, mode_t, struct fuse_file_info *)
    Definition fuse.h:678
    int(* utimens)(const char *, const struct timespec tv[2], struct fuse_file_info *fi)
    Definition fuse.h:725
    off_t(* lseek)(const char *, off_t off, int whence, struct fuse_file_info *)
    Definition fuse.h:858
    int(* getxattr)(const char *, const char *, char *, size_t)
    Definition fuse.h:579
    int(* setxattr)(const char *, const char *, const char *, size_t, int)
    Definition fuse.h:576
    int(* poll)(const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)
    Definition fuse.h:775
    int(* fsync)(const char *, int, struct fuse_file_info *)
    Definition fuse.h:573
    int(* chmod)(const char *, mode_t, struct fuse_file_info *fi)
    Definition fuse.h:423
    int(* opendir)(const char *, struct fuse_file_info *)
    Definition fuse.h:595
    int(* rmdir)(const char *)
    Definition fuse.h:399
    int(* statx)(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi)
    Definition fuse.h:868
    int(* releasedir)(const char *, struct fuse_file_info *)
    Definition fuse.h:627
    int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
    Definition fuse.h:367
    int(* read_buf)(const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *)
    Definition fuse.h:804
    int(* link)(const char *, const char *)
    Definition fuse.h:416
    int(* flock)(const char *, struct fuse_file_info *, int op)
    Definition fuse.h:824
    int(* removexattr)(const char *, const char *)
    Definition fuse.h:585
    int(* ioctl)(const char *, unsigned int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)
    Definition fuse.h:756
    int(* rename)(const char *, const char *, unsigned int flags)
    Definition fuse.h:413
    int(* readdir)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags)
    Definition fuse.h:619
    void(* destroy)(void *private_data)
    Definition fuse.h:655
    int(* bmap)(const char *, size_t blocksize, uint64_t *idx)
    Definition fuse.h:734
    fuse-3.18.3/doc/html/fuse__common_8h_source.html0000644000175000017500000026724715250106404020564 0ustar berndbernd 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 LGPL2.txt.
    6*/
    7
    9
    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#ifdef HAVE_LIBFUSE_PRIVATE_CONFIG_H
    18#include "fuse_config.h"
    19#endif
    20
    21#include "libfuse_config.h"
    22
    23#include "fuse_opt.h"
    24#include "fuse_log.h"
    25#include <stdint.h>
    26#include <stdbool.h>
    27#include <sys/types.h>
    28#include <assert.h>
    29
    30#define FUSE_MAKE_VERSION(maj, min) ((maj) * 100 + (min))
    31#define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION)
    32
    33#ifdef __cplusplus
    34extern "C" {
    35#endif
    36
    52 int32_t flags;
    53
    60 uint32_t writepage : 1;
    61
    63 uint32_t direct_io : 1;
    64
    69 uint32_t keep_cache : 1;
    70
    74 uint32_t flush : 1;
    75
    78 uint32_t nonseekable : 1;
    79
    80 /* Indicates that flock locks for this file should be
    81 released. If set, lock_owner shall contain a valid value.
    82 May only be set in ->release(). */
    83 uint32_t flock_release : 1;
    84
    89 uint32_t cache_readdir : 1;
    90
    93 uint32_t noflush : 1;
    94
    98
    105 uint32_t kill_suidgid : 1;
    106
    108 uint32_t padding : 22;
    109 uint32_t padding2 : 32;
    110 uint32_t padding3 : 32;
    111
    115 uint64_t fh;
    116
    118 uint64_t lock_owner;
    119
    122 uint32_t poll_events;
    123
    127 int32_t backing_id;
    128
    130 uint64_t compat_flags;
    131
    132 uint64_t reserved[2];
    133};
    134
    145#if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12)
    146struct fuse_loop_config_v1; /* forward declaration */
    148#else
    149struct fuse_loop_config_v1 {
    150#endif
    156
    167 unsigned int max_idle_threads;
    168};
    169
    170
    171/**************************************************************************
    172 * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' *
    173 **************************************************************************/
    174
    185#define FUSE_CAP_ASYNC_READ (1UL << 0)
    186
    193#define FUSE_CAP_POSIX_LOCKS (1UL << 1)
    194
    202#define FUSE_CAP_ATOMIC_O_TRUNC (1UL << 3)
    203
    214#define FUSE_CAP_EXPORT_SUPPORT (1UL << 4)
    215
    222#define FUSE_CAP_DONT_MASK (1UL << 6)
    223
    230#define FUSE_CAP_SPLICE_WRITE (1UL << 7)
    231
    238#define FUSE_CAP_SPLICE_MOVE (1UL << 8)
    239
    247#define FUSE_CAP_SPLICE_READ (1UL << 9)
    248
    260#define FUSE_CAP_FLOCK_LOCKS (1UL << 10)
    261
    267#define FUSE_CAP_IOCTL_DIR (1UL << 11)
    268
    289#define FUSE_CAP_AUTO_INVAL_DATA (1UL << 12)
    290
    297#define FUSE_CAP_READDIRPLUS (1UL << 13)
    298
    325#define FUSE_CAP_READDIRPLUS_AUTO (1UL << 14)
    326
    336#define FUSE_CAP_ASYNC_DIO (1UL << 15)
    337
    345#define FUSE_CAP_WRITEBACK_CACHE (1UL << 16)
    346
    360#define FUSE_CAP_NO_OPEN_SUPPORT (1UL << 17)
    361
    368#define FUSE_CAP_PARALLEL_DIROPS (1UL << 18)
    369
    387#define FUSE_CAP_POSIX_ACL (1UL << 19)
    388
    396#define FUSE_CAP_HANDLE_KILLPRIV (1UL << 20)
    397
    413#define FUSE_CAP_HANDLE_KILLPRIV_V2 (1UL << 21)
    414
    426#define FUSE_CAP_CACHE_SYMLINKS (1UL << 23)
    427
    441#define FUSE_CAP_NO_OPENDIR_SUPPORT (1UL << 24)
    442
    464#define FUSE_CAP_EXPLICIT_INVAL_DATA (1UL << 25)
    465
    480#define FUSE_CAP_EXPIRE_ONLY (1UL << 26)
    481
    487#define FUSE_CAP_SETXATTR_EXT (1UL << 27)
    488
    496#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP (1UL << 28)
    497
    508#define FUSE_CAP_PASSTHROUGH (1UL << 29)
    509
    516#define FUSE_CAP_NO_EXPORT_SUPPORT (1UL << 30)
    517
    521#define FUSE_CAP_OVER_IO_URING (1UL << 31)
    522
    533#define FUSE_IOCTL_COMPAT (1 << 0)
    534#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
    535#define FUSE_IOCTL_RETRY (1 << 2)
    536#define FUSE_IOCTL_DIR (1 << 4)
    537
    538#define FUSE_IOCTL_MAX_IOV 256
    539
    555 uint32_t proto_major;
    556
    560 uint32_t proto_minor;
    561
    565 uint32_t max_write;
    566
    579 uint32_t max_read;
    580
    585
    591 uint32_t capable;
    592
    603 uint32_t want;
    604
    634
    644
    660 uint32_t time_gran;
    661
    678#define FUSE_BACKING_STACKED_UNDER (0)
    679#define FUSE_BACKING_STACKED_OVER (1)
    680 uint32_t max_backing_stack_depth;
    681
    690 uint32_t no_interrupt : 1;
    691
    692 /* reserved bits for future use */
    693 uint32_t padding : 31;
    694
    699 uint64_t capable_ext;
    700
    709 uint64_t want_ext;
    710
    716
    720 uint16_t reserved[31];
    721};
    722
    723struct fuse_session;
    724struct fuse_pollhandle;
    725struct fuse_conn_info_opts;
    726
    769struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args);
    770
    778void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
    779 struct fuse_conn_info *conn);
    780
    787int fuse_daemonize(int foreground);
    788
    794int fuse_version(void);
    795
    801const char *fuse_pkgversion(void);
    802
    808void fuse_pollhandle_destroy(struct fuse_pollhandle *ph);
    809
    810/* ----------------------------------------------------------- *
    811 * Data buffer *
    812 * ----------------------------------------------------------- */
    813
    824 FUSE_BUF_IS_FD = (1 << 1),
    825
    834
    843};
    844
    886
    893struct fuse_buf {
    897 size_t size;
    898
    903
    909 void *mem;
    910
    916 int fd;
    917
    923 off_t pos;
    924
    931 size_t mem_size;
    932};
    933
    946 size_t count;
    947
    951 size_t idx;
    952
    956 size_t off;
    957
    961 struct fuse_buf buf[1];
    962};
    963
    969{
    970 uint32_t major;
    971 uint32_t minor;
    972 uint32_t hotfix;
    973 uint32_t padding;
    974};
    975
    976/* Initialize bufvec with a single buffer of given size */
    977#define FUSE_BUFVEC_INIT(size__) \
    978 ((struct fuse_bufvec) { \
    979 /* .count= */ 1, \
    980 /* .idx = */ 0, \
    981 /* .off = */ 0, \
    982 /* .buf = */ { /* [0] = */ { \
    983 /* .size = */ (size__), \
    984 /* .flags = */ (enum fuse_buf_flags) 0, \
    985 /* .mem = */ NULL, \
    986 /* .fd = */ -1, \
    987 /* .pos = */ 0, \
    988 /* .mem_size = */ 0, \
    989 } } \
    990 } )
    991
    998size_t fuse_buf_size(const struct fuse_bufvec *bufv);
    999
    1008ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src,
    1009 enum fuse_buf_copy_flags flags);
    1010
    1011/* ----------------------------------------------------------- *
    1012 * Signal handling *
    1013 * ----------------------------------------------------------- */
    1014
    1030int fuse_set_signal_handlers(struct fuse_session *se);
    1031
    1047int fuse_set_fail_signal_handlers(struct fuse_session *se);
    1048
    1060void fuse_remove_signal_handlers(struct fuse_session *se);
    1061
    1067#if FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 12)
    1073struct fuse_loop_config *fuse_loop_cfg_create(void);
    1074
    1078void fuse_loop_cfg_destroy(struct fuse_loop_config *config);
    1079
    1083void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config,
    1084 unsigned int value);
    1085
    1089void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config,
    1090 unsigned int value);
    1091
    1095void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config,
    1096 unsigned int value);
    1097
    1104void fuse_loop_cfg_convert(struct fuse_loop_config *config,
    1105 struct fuse_loop_config_v1 *v1_conf);
    1106#endif
    1107
    1115bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag);
    1116
    1123void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag);
    1124
    1132bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag);
    1133
    1134/*
    1135 * DO NOT USE: Not part of public API, for internal test use only.
    1136 * The function signature or any use of it is not guaranteeed to
    1137 * remain stable. And neither are results of what this function does.
    1138 */
    1140
    1141
    1142
    1143/* ----------------------------------------------------------- *
    1144 * Compatibility stuff *
    1145 * ----------------------------------------------------------- */
    1146
    1147#if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30
    1148# error only API version 30 or greater is supported
    1149#endif
    1150
    1151#ifdef __cplusplus
    1152}
    1153#endif
    1154
    1155
    1156/*
    1157 * This interface uses 64 bit off_t.
    1158 *
    1159 * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags!
    1160 */
    1161
    1162#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
    1163_Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit");
    1164#else
    1165struct _fuse_off_t_must_be_64bit_dummy_struct \
    1166 { unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); };
    1167#endif
    1168
    1169#endif /* FUSE_COMMON_H_ */
    void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
    int fuse_set_fail_signal_handlers(struct fuse_session *se)
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_set_signal_handlers(struct fuse_session *se)
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
    Definition helper.c:422
    fuse_buf_flags
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_FD_RETRY
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    struct fuse_conn_info_opts * fuse_parse_conn_info_opts(struct fuse_args *args)
    Definition helper.c:476
    bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    int fuse_version(void)
    Definition fuse.c:5269
    void fuse_remove_signal_handlers(struct fuse_session *se)
    fuse_buf_copy_flags
    @ FUSE_BUF_SPLICE_NONBLOCK
    @ FUSE_BUF_FORCE_SPLICE
    @ FUSE_BUF_NO_SPLICE
    @ FUSE_BUF_SPLICE_MOVE
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    enum fuse_buf_flags flags
    size_t mem_size
    void * mem
    off_t pos
    size_t size
    struct fuse_buf buf[1]
    uint32_t time_gran
    uint16_t request_timeout
    uint32_t proto_major
    uint32_t congestion_threshold
    uint32_t proto_minor
    uint32_t max_write
    uint64_t capable_ext
    uint32_t max_readahead
    uint32_t no_interrupt
    uint32_t max_read
    uint32_t max_background
    uint32_t capable
    uint64_t want_ext
    uint16_t reserved[31]
    uint64_t lock_owner
    uint32_t kill_suidgid
    uint32_t writepage
    Definition fuse_common.h:60
    uint32_t poll_events
    uint32_t cache_readdir
    Definition fuse_common.h:89
    uint32_t nonseekable
    Definition fuse_common.h:78
    int32_t backing_id
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t padding
    uint32_t noflush
    Definition fuse_common.h:93
    uint64_t compat_flags
    uint32_t flush
    Definition fuse_common.h:74
    uint32_t direct_io
    Definition fuse_common.h:63
    uint32_t keep_cache
    Definition fuse_common.h:69
    unsigned int max_idle_threads
    fuse-3.18.3/doc/html/fuse__kernel_8h_source.html0000644000175000017500000045250115250106404020541 0ustar berndbernd libfuse: include/fuse_kernel.h Source File
    libfuse
    fuse_kernel.h
    1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
    2/*
    3 This file defines the kernel interface of FUSE
    4 Copyright (C) 2001-2008 Miklos Szeredi <miklos@szeredi.hu>
    5
    6 This program can be distributed under the terms of the GNU GPL.
    7 See the file COPYING.
    8
    9 This -- and only this -- header file may also be distributed under
    10 the terms of the BSD Licence as follows:
    11
    12 Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved.
    13
    14 Redistribution and use in source and binary forms, with or without
    15 modification, are permitted provided that the following conditions
    16 are met:
    17 1. Redistributions of source code must retain the above copyright
    18 notice, this list of conditions and the following disclaimer.
    19 2. Redistributions in binary form must reproduce the above copyright
    20 notice, this list of conditions and the following disclaimer in the
    21 documentation and/or other materials provided with the distribution.
    22
    23 THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
    24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    26 ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
    27 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    28 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
    29 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    32 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    33 SUCH DAMAGE.
    34*/
    35
    36/*
    37 * This file defines the kernel interface of FUSE
    38 *
    39 * Protocol changelog:
    40 *
    41 * 7.1:
    42 * - add the following messages:
    43 * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK,
    44 * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE,
    45 * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR,
    46 * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR,
    47 * FUSE_RELEASEDIR
    48 * - add padding to messages to accommodate 32-bit servers on 64-bit kernels
    49 *
    50 * 7.2:
    51 * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags
    52 * - add FUSE_FSYNCDIR message
    53 *
    54 * 7.3:
    55 * - add FUSE_ACCESS message
    56 * - add FUSE_CREATE message
    57 * - add filehandle to fuse_setattr_in
    58 *
    59 * 7.4:
    60 * - add frsize to fuse_kstatfs
    61 * - clean up request size limit checking
    62 *
    63 * 7.5:
    64 * - add flags and max_write to fuse_init_out
    65 *
    66 * 7.6:
    67 * - add max_readahead to fuse_init_in and fuse_init_out
    68 *
    69 * 7.7:
    70 * - add FUSE_INTERRUPT message
    71 * - add POSIX file lock support
    72 *
    73 * 7.8:
    74 * - add lock_owner and flags fields to fuse_release_in
    75 * - add FUSE_BMAP message
    76 * - add FUSE_DESTROY message
    77 *
    78 * 7.9:
    79 * - new fuse_getattr_in input argument of GETATTR
    80 * - add lk_flags in fuse_lk_in
    81 * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in
    82 * - add blksize field to fuse_attr
    83 * - add file flags field to fuse_read_in and fuse_write_in
    84 * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in
    85 *
    86 * 7.10
    87 * - add nonseekable open flag
    88 *
    89 * 7.11
    90 * - add IOCTL message
    91 * - add unsolicited notification support
    92 * - add POLL message and NOTIFY_POLL notification
    93 *
    94 * 7.12
    95 * - add umask flag to input argument of create, mknod and mkdir
    96 * - add notification messages for invalidation of inodes and
    97 * directory entries
    98 *
    99 * 7.13
    100 * - make max number of background requests and congestion threshold
    101 * tunables
    102 *
    103 * 7.14
    104 * - add splice support to fuse device
    105 *
    106 * 7.15
    107 * - add store notify
    108 * - add retrieve notify
    109 *
    110 * 7.16
    111 * - add BATCH_FORGET request
    112 * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
    113 * fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
    114 * - add FUSE_IOCTL_32BIT flag
    115 *
    116 * 7.17
    117 * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
    118 *
    119 * 7.18
    120 * - add FUSE_IOCTL_DIR flag
    121 * - add FUSE_NOTIFY_DELETE
    122 *
    123 * 7.19
    124 * - add FUSE_FALLOCATE
    125 *
    126 * 7.20
    127 * - add FUSE_AUTO_INVAL_DATA
    128 *
    129 * 7.21
    130 * - add FUSE_READDIRPLUS
    131 * - send the requested events in POLL request
    132 *
    133 * 7.22
    134 * - add FUSE_ASYNC_DIO
    135 *
    136 * 7.23
    137 * - add FUSE_WRITEBACK_CACHE
    138 * - add time_gran to fuse_init_out
    139 * - add reserved space to fuse_init_out
    140 * - add FATTR_CTIME
    141 * - add ctime and ctimensec to fuse_setattr_in
    142 * - add FUSE_RENAME2 request
    143 * - add FUSE_NO_OPEN_SUPPORT flag
    144 *
    145 * 7.24
    146 * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support
    147 *
    148 * 7.25
    149 * - add FUSE_PARALLEL_DIROPS
    150 *
    151 * 7.26
    152 * - add FUSE_HANDLE_KILLPRIV
    153 * - add FUSE_POSIX_ACL
    154 *
    155 * 7.27
    156 * - add FUSE_ABORT_ERROR
    157 *
    158 * 7.28
    159 * - add FUSE_COPY_FILE_RANGE
    160 * - add FOPEN_CACHE_DIR
    161 * - add FUSE_MAX_PAGES, add max_pages to init_out
    162 * - add FUSE_CACHE_SYMLINKS
    163 *
    164 * 7.29
    165 * - add FUSE_NO_OPENDIR_SUPPORT flag
    166 *
    167 * 7.30
    168 * - add FUSE_EXPLICIT_INVAL_DATA
    169 * - add FUSE_IOCTL_COMPAT_X32
    170 *
    171 * 7.31
    172 * - add FUSE_WRITE_KILL_PRIV flag
    173 * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING
    174 * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag
    175 *
    176 * 7.32
    177 * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS
    178 *
    179 * 7.33
    180 * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID
    181 * - add FUSE_OPEN_KILL_SUIDGID
    182 * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT
    183 * - add FUSE_SETXATTR_ACL_KILL_SGID
    184 *
    185 * 7.34
    186 * - add FUSE_SYNCFS
    187 *
    188 * 7.35
    189 * - add FOPEN_NOFLUSH
    190 *
    191 * 7.36
    192 * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag
    193 * - add flags2 to fuse_init_in and fuse_init_out
    194 * - add FUSE_SECURITY_CTX init flag
    195 * - add security context to create, mkdir, symlink, and mknod requests
    196 * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX
    197 *
    198 * 7.37
    199 * - add FUSE_TMPFILE
    200 *
    201 * 7.38
    202 * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry
    203 * - add FOPEN_PARALLEL_DIRECT_WRITES
    204 * - add total_extlen to fuse_in_header
    205 * - add FUSE_MAX_NR_SECCTX
    206 * - add extension header
    207 * - add FUSE_EXT_GROUPS
    208 * - add FUSE_CREATE_SUPP_GROUP
    209 * - add FUSE_HAS_EXPIRE_ONLY
    210 *
    211 * 7.39
    212 * - add FUSE_DIRECT_IO_ALLOW_MMAP
    213 * - add FUSE_STATX and related structures
    214 *
    215 * 7.40
    216 * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag
    217 * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag
    218 * - add FUSE_NO_EXPORT_SUPPORT init flag
    219 * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag
    220 *
    221 * 7.41
    222 * - add FUSE_ALLOW_IDMAP
    223 * 7.42
    224 * - Add FUSE_OVER_IO_URING and all other io-uring related flags and data
    225 * structures:
    226 * - struct fuse_uring_ent_in_out
    227 * - struct fuse_uring_req_header
    228 * - struct fuse_uring_cmd_req
    229 * - FUSE_URING_IN_OUT_HEADER_SZ
    230 * - FUSE_URING_OP_IN_OUT_SZ
    231 * - enum fuse_uring_cmd
    232 *
    233 * 7.43
    234 * - add FUSE_REQUEST_TIMEOUT
    235 *
    236 * 7.44
    237 * - add FUSE_NOTIFY_INC_EPOCH
    238 *
    239 * 7.45
    240 * - add FUSE_COPY_FILE_RANGE_64
    241 * - add struct fuse_copy_file_range_out
    242 */
    243
    244#ifndef _LINUX_FUSE_H
    245#define _LINUX_FUSE_H
    246
    247#ifdef __KERNEL__
    248#include <linux/types.h>
    249#else
    250#include <stdint.h>
    251#endif
    252
    253/*
    254 * Version negotiation:
    255 *
    256 * Both the kernel and userspace send the version they support in the
    257 * INIT request and reply respectively.
    258 *
    259 * If the major versions match then both shall use the smallest
    260 * of the two minor versions for communication.
    261 *
    262 * If the kernel supports a larger major version, then userspace shall
    263 * reply with the major version it supports, ignore the rest of the
    264 * INIT message and expect a new INIT message from the kernel with a
    265 * matching major version.
    266 *
    267 * If the library supports a larger major version, then it shall fall
    268 * back to the major protocol version sent by the kernel for
    269 * communication and reply with that major version (and an arbitrary
    270 * supported minor version).
    271 */
    272
    274#define FUSE_KERNEL_VERSION 7
    275
    277#define FUSE_KERNEL_MINOR_VERSION 45
    278
    280#define FUSE_ROOT_ID 1
    281
    282/* Make sure all structures are padded to 64bit boundary, so 32bit
    283 userspace works under 64bit kernels */
    284
    285struct fuse_attr {
    286 uint64_t ino;
    287 uint64_t size;
    288 uint64_t blocks;
    289 uint64_t atime;
    290 uint64_t mtime;
    291 uint64_t ctime;
    292 uint32_t atimensec;
    293 uint32_t mtimensec;
    294 uint32_t ctimensec;
    295 uint32_t mode;
    296 uint32_t nlink;
    297 uint32_t uid;
    298 uint32_t gid;
    299 uint32_t rdev;
    300 uint32_t blksize;
    301 uint32_t flags;
    302};
    303
    304/*
    305 * The following structures are bit-for-bit compatible with the statx(2) ABI in
    306 * Linux.
    307 */
    308struct fuse_sx_time {
    309 int64_t tv_sec;
    310 uint32_t tv_nsec;
    311 int32_t __reserved;
    312};
    313
    314struct fuse_statx {
    315 uint32_t mask;
    316 uint32_t blksize;
    317 uint64_t attributes;
    318 uint32_t nlink;
    319 uint32_t uid;
    320 uint32_t gid;
    321 uint16_t mode;
    322 uint16_t __spare0[1];
    323 uint64_t ino;
    324 uint64_t size;
    325 uint64_t blocks;
    326 uint64_t attributes_mask;
    327 struct fuse_sx_time atime;
    328 struct fuse_sx_time btime;
    329 struct fuse_sx_time ctime;
    330 struct fuse_sx_time mtime;
    331 uint32_t rdev_major;
    332 uint32_t rdev_minor;
    333 uint32_t dev_major;
    334 uint32_t dev_minor;
    335 uint64_t __spare2[14];
    336};
    337
    338struct fuse_kstatfs {
    339 uint64_t blocks;
    340 uint64_t bfree;
    341 uint64_t bavail;
    342 uint64_t files;
    343 uint64_t ffree;
    344 uint32_t bsize;
    345 uint32_t namelen;
    346 uint32_t frsize;
    347 uint32_t padding;
    348 uint32_t spare[6];
    349};
    350
    351struct fuse_file_lock {
    352 uint64_t start;
    353 uint64_t end;
    354 uint32_t type;
    355 uint32_t pid; /* tgid */
    356};
    357
    361#define FATTR_MODE (1 << 0)
    362#define FATTR_UID (1 << 1)
    363#define FATTR_GID (1 << 2)
    364#define FATTR_SIZE (1 << 3)
    365#define FATTR_ATIME (1 << 4)
    366#define FATTR_MTIME (1 << 5)
    367#define FATTR_FH (1 << 6)
    368#define FATTR_ATIME_NOW (1 << 7)
    369#define FATTR_MTIME_NOW (1 << 8)
    370#define FATTR_LOCKOWNER (1 << 9)
    371#define FATTR_CTIME (1 << 10)
    372#define FATTR_KILL_SUIDGID (1 << 11)
    373
    386#define FOPEN_DIRECT_IO (1 << 0)
    387#define FOPEN_KEEP_CACHE (1 << 1)
    388#define FOPEN_NONSEEKABLE (1 << 2)
    389#define FOPEN_CACHE_DIR (1 << 3)
    390#define FOPEN_STREAM (1 << 4)
    391#define FOPEN_NOFLUSH (1 << 5)
    392#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6)
    393#define FOPEN_PASSTHROUGH (1 << 7)
    394
    451#define FUSE_ASYNC_READ (1 << 0)
    452#define FUSE_POSIX_LOCKS (1 << 1)
    453#define FUSE_FILE_OPS (1 << 2)
    454#define FUSE_ATOMIC_O_TRUNC (1 << 3)
    455#define FUSE_EXPORT_SUPPORT (1 << 4)
    456#define FUSE_BIG_WRITES (1 << 5)
    457#define FUSE_DONT_MASK (1 << 6)
    458#define FUSE_SPLICE_WRITE (1 << 7)
    459#define FUSE_SPLICE_MOVE (1 << 8)
    460#define FUSE_SPLICE_READ (1 << 9)
    461#define FUSE_FLOCK_LOCKS (1 << 10)
    462#define FUSE_HAS_IOCTL_DIR (1 << 11)
    463#define FUSE_AUTO_INVAL_DATA (1 << 12)
    464#define FUSE_DO_READDIRPLUS (1 << 13)
    465#define FUSE_READDIRPLUS_AUTO (1 << 14)
    466#define FUSE_ASYNC_DIO (1 << 15)
    467#define FUSE_WRITEBACK_CACHE (1 << 16)
    468#define FUSE_NO_OPEN_SUPPORT (1 << 17)
    469#define FUSE_PARALLEL_DIROPS (1 << 18)
    470#define FUSE_HANDLE_KILLPRIV (1 << 19)
    471#define FUSE_POSIX_ACL (1 << 20)
    472#define FUSE_ABORT_ERROR (1 << 21)
    473#define FUSE_MAX_PAGES (1 << 22)
    474#define FUSE_CACHE_SYMLINKS (1 << 23)
    475#define FUSE_NO_OPENDIR_SUPPORT (1 << 24)
    476#define FUSE_EXPLICIT_INVAL_DATA (1 << 25)
    477#define FUSE_MAP_ALIGNMENT (1 << 26)
    478#define FUSE_SUBMOUNTS (1 << 27)
    479#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28)
    480#define FUSE_SETXATTR_EXT (1 << 29)
    481#define FUSE_INIT_EXT (1 << 30)
    482#define FUSE_INIT_RESERVED (1 << 31)
    483/* bits 32..63 get shifted down 32 bits into the flags2 field */
    484#define FUSE_SECURITY_CTX (1ULL << 32)
    485#define FUSE_HAS_INODE_DAX (1ULL << 33)
    486#define FUSE_CREATE_SUPP_GROUP (1ULL << 34)
    487#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35)
    488#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36)
    489#define FUSE_PASSTHROUGH (1ULL << 37)
    490#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38)
    491#define FUSE_HAS_RESEND (1ULL << 39)
    492/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */
    493#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP
    494#define FUSE_ALLOW_IDMAP (1ULL << 40)
    495#define FUSE_OVER_IO_URING (1ULL << 41)
    496#define FUSE_REQUEST_TIMEOUT (1ULL << 42)
    497
    503#define CUSE_UNRESTRICTED_IOCTL (1 << 0)
    504
    508#define FUSE_RELEASE_FLUSH (1 << 0)
    509#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
    510
    514#define FUSE_GETATTR_FH (1 << 0)
    515
    519#define FUSE_LK_FLOCK (1 << 0)
    520
    528#define FUSE_WRITE_CACHE (1 << 0)
    529#define FUSE_WRITE_LOCKOWNER (1 << 1)
    530#define FUSE_WRITE_KILL_SUIDGID (1 << 2)
    531
    532/* Obsolete alias; this flag implies killing suid/sgid only. */
    533#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID
    534
    538#define FUSE_READ_LOCKOWNER (1 << 1)
    539
    552#define FUSE_IOCTL_COMPAT (1 << 0)
    553#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
    554#define FUSE_IOCTL_RETRY (1 << 2)
    555#define FUSE_IOCTL_32BIT (1 << 3)
    556#define FUSE_IOCTL_DIR (1 << 4)
    557#define FUSE_IOCTL_COMPAT_X32 (1 << 5)
    558
    559#define FUSE_IOCTL_MAX_IOV 256
    560
    566#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0)
    567
    573#define FUSE_FSYNC_FDATASYNC (1 << 0)
    574
    581#define FUSE_ATTR_SUBMOUNT (1 << 0)
    582#define FUSE_ATTR_DAX (1 << 1)
    583
    588#define FUSE_OPEN_KILL_SUIDGID (1 << 0)
    589
    594#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0)
    595
    600#define FUSE_EXPIRE_ONLY (1 << 0)
    601
    607enum fuse_ext_type {
    608 /* Types 0..31 are reserved for fuse_secctx_header */
    609 FUSE_MAX_NR_SECCTX = 31,
    610 FUSE_EXT_GROUPS = 32,
    611};
    612
    613enum fuse_opcode {
    614 FUSE_LOOKUP = 1,
    615 FUSE_FORGET = 2, /* no reply */
    616 FUSE_GETATTR = 3,
    617 FUSE_SETATTR = 4,
    618 FUSE_READLINK = 5,
    619 FUSE_SYMLINK = 6,
    620 FUSE_MKNOD = 8,
    621 FUSE_MKDIR = 9,
    622 FUSE_UNLINK = 10,
    623 FUSE_RMDIR = 11,
    624 FUSE_RENAME = 12,
    625 FUSE_LINK = 13,
    626 FUSE_OPEN = 14,
    627 FUSE_READ = 15,
    628 FUSE_WRITE = 16,
    629 FUSE_STATFS = 17,
    630 FUSE_RELEASE = 18,
    631 FUSE_FSYNC = 20,
    632 FUSE_SETXATTR = 21,
    633 FUSE_GETXATTR = 22,
    634 FUSE_LISTXATTR = 23,
    635 FUSE_REMOVEXATTR = 24,
    636 FUSE_FLUSH = 25,
    637 FUSE_INIT = 26,
    638 FUSE_OPENDIR = 27,
    639 FUSE_READDIR = 28,
    640 FUSE_RELEASEDIR = 29,
    641 FUSE_FSYNCDIR = 30,
    642 FUSE_GETLK = 31,
    643 FUSE_SETLK = 32,
    644 FUSE_SETLKW = 33,
    645 FUSE_ACCESS = 34,
    646 FUSE_CREATE = 35,
    647 FUSE_INTERRUPT = 36,
    648 FUSE_BMAP = 37,
    649 FUSE_DESTROY = 38,
    650 FUSE_IOCTL = 39,
    651 FUSE_POLL = 40,
    652 FUSE_NOTIFY_REPLY = 41,
    653 FUSE_BATCH_FORGET = 42,
    654 FUSE_FALLOCATE = 43,
    655 FUSE_READDIRPLUS = 44,
    656 FUSE_RENAME2 = 45,
    657 FUSE_LSEEK = 46,
    658 FUSE_COPY_FILE_RANGE = 47,
    659 FUSE_SETUPMAPPING = 48,
    660 FUSE_REMOVEMAPPING = 49,
    661 FUSE_SYNCFS = 50,
    662 FUSE_TMPFILE = 51,
    663 FUSE_STATX = 52,
    664 FUSE_COPY_FILE_RANGE_64 = 53,
    665
    666 /* CUSE specific operations */
    667 CUSE_INIT = 4096,
    668
    669 /* Reserved opcodes: helpful to detect structure endian-ness */
    670 CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */
    671 FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */
    672};
    673
    674enum fuse_notify_code {
    675 FUSE_NOTIFY_POLL = 1,
    676 FUSE_NOTIFY_INVAL_INODE = 2,
    677 FUSE_NOTIFY_INVAL_ENTRY = 3,
    678 FUSE_NOTIFY_STORE = 4,
    679 FUSE_NOTIFY_RETRIEVE = 5,
    680 FUSE_NOTIFY_DELETE = 6,
    681 FUSE_NOTIFY_RESEND = 7,
    682 FUSE_NOTIFY_INC_EPOCH = 8,
    683 FUSE_NOTIFY_CODE_MAX,
    684};
    685
    686/* The read buffer is required to be at least 8k, but may be much larger */
    687#define FUSE_MIN_READ_BUFFER 8192
    688
    689#define FUSE_COMPAT_ENTRY_OUT_SIZE 120
    690
    691struct fuse_entry_out {
    692 uint64_t nodeid; /* Inode ID */
    693 uint64_t generation; /* Inode generation: nodeid:gen must
    694 be unique for the fs's lifetime */
    695 uint64_t entry_valid; /* Cache timeout for the name */
    696 uint64_t attr_valid; /* Cache timeout for the attributes */
    697 uint32_t entry_valid_nsec;
    698 uint32_t attr_valid_nsec;
    699 struct fuse_attr attr;
    700};
    701
    702struct fuse_forget_in {
    703 uint64_t nlookup;
    704};
    705
    706struct fuse_forget_one {
    707 uint64_t nodeid;
    708 uint64_t nlookup;
    709};
    710
    711struct fuse_batch_forget_in {
    712 uint32_t count;
    713 uint32_t dummy;
    714};
    715
    716struct fuse_getattr_in {
    717 uint32_t getattr_flags;
    718 uint32_t dummy;
    719 uint64_t fh;
    720};
    721
    722#define FUSE_COMPAT_ATTR_OUT_SIZE 96
    723
    724struct fuse_attr_out {
    725 uint64_t attr_valid; /* Cache timeout for the attributes */
    726 uint32_t attr_valid_nsec;
    727 uint32_t dummy;
    728 struct fuse_attr attr;
    729};
    730
    731struct fuse_statx_in {
    732 uint32_t getattr_flags;
    733 uint32_t reserved;
    734 uint64_t fh;
    735 uint32_t sx_flags;
    736 uint32_t sx_mask;
    737};
    738
    739struct fuse_statx_out {
    740 uint64_t attr_valid; /* Cache timeout for the attributes */
    741 uint32_t attr_valid_nsec;
    742 uint32_t flags;
    743 uint64_t spare[2];
    744 struct fuse_statx stat;
    745};
    746
    747#define FUSE_COMPAT_MKNOD_IN_SIZE 8
    748
    749struct fuse_mknod_in {
    750 uint32_t mode;
    751 uint32_t rdev;
    752 uint32_t umask;
    753 uint32_t padding;
    754};
    755
    756struct fuse_mkdir_in {
    757 uint32_t mode;
    758 uint32_t umask;
    759};
    760
    761struct fuse_rename_in {
    762 uint64_t newdir;
    763};
    764
    765struct fuse_rename2_in {
    766 uint64_t newdir;
    767 uint32_t flags;
    768 uint32_t padding;
    769};
    770
    771struct fuse_link_in {
    772 uint64_t oldnodeid;
    773};
    774
    775struct fuse_setattr_in {
    776 uint32_t valid;
    777 uint32_t padding;
    778 uint64_t fh;
    779 uint64_t size;
    780 uint64_t lock_owner;
    781 uint64_t atime;
    782 uint64_t mtime;
    783 uint64_t ctime;
    784 uint32_t atimensec;
    785 uint32_t mtimensec;
    786 uint32_t ctimensec;
    787 uint32_t mode;
    788 uint32_t unused4;
    789 uint32_t uid;
    790 uint32_t gid;
    791 uint32_t unused5;
    792};
    793
    794struct fuse_open_in {
    795 uint32_t flags;
    796 uint32_t open_flags; /* FUSE_OPEN_... */
    797};
    798
    799struct fuse_create_in {
    800 uint32_t flags;
    801 uint32_t mode;
    802 uint32_t umask;
    803 uint32_t open_flags; /* FUSE_OPEN_... */
    804};
    805
    806struct fuse_open_out {
    807 uint64_t fh;
    808 uint32_t open_flags;
    809 int32_t backing_id;
    810};
    811
    812struct fuse_release_in {
    813 uint64_t fh;
    814 uint32_t flags;
    815 uint32_t release_flags;
    816 uint64_t lock_owner;
    817};
    818
    819struct fuse_flush_in {
    820 uint64_t fh;
    821 uint32_t unused;
    822 uint32_t padding;
    823 uint64_t lock_owner;
    824};
    825
    826struct fuse_read_in {
    827 uint64_t fh;
    828 uint64_t offset;
    829 uint32_t size;
    830 uint32_t read_flags;
    831 uint64_t lock_owner;
    832 uint32_t flags;
    833 uint32_t padding;
    834};
    835
    836#define FUSE_COMPAT_WRITE_IN_SIZE 24
    837
    838struct fuse_write_in {
    839 uint64_t fh;
    840 uint64_t offset;
    841 uint32_t size;
    842 uint32_t write_flags;
    843 uint64_t lock_owner;
    844 uint32_t flags;
    845 uint32_t padding;
    846};
    847
    848struct fuse_write_out {
    849 uint32_t size;
    850 uint32_t padding;
    851};
    852
    853#define FUSE_COMPAT_STATFS_SIZE 48
    854
    855struct fuse_statfs_out {
    856 struct fuse_kstatfs st;
    857};
    858
    859struct fuse_fsync_in {
    860 uint64_t fh;
    861 uint32_t fsync_flags;
    862 uint32_t padding;
    863};
    864
    865#define FUSE_COMPAT_SETXATTR_IN_SIZE 8
    866
    867struct fuse_setxattr_in {
    868 uint32_t size;
    869 uint32_t flags;
    870 uint32_t setxattr_flags;
    871 uint32_t padding;
    872};
    873
    874struct fuse_getxattr_in {
    875 uint32_t size;
    876 uint32_t padding;
    877};
    878
    879struct fuse_getxattr_out {
    880 uint32_t size;
    881 uint32_t padding;
    882};
    883
    884struct fuse_lk_in {
    885 uint64_t fh;
    886 uint64_t owner;
    887 struct fuse_file_lock lk;
    888 uint32_t lk_flags;
    889 uint32_t padding;
    890};
    891
    892struct fuse_lk_out {
    893 struct fuse_file_lock lk;
    894};
    895
    896struct fuse_access_in {
    897 uint32_t mask;
    898 uint32_t padding;
    899};
    900
    901struct fuse_init_in {
    902 uint32_t major;
    903 uint32_t minor;
    904 uint32_t max_readahead;
    905 uint32_t flags;
    906 uint32_t flags2;
    907 uint32_t unused[11];
    908};
    909
    910#define FUSE_COMPAT_INIT_OUT_SIZE 8
    911#define FUSE_COMPAT_22_INIT_OUT_SIZE 24
    912
    913struct fuse_init_out {
    914 uint32_t major;
    915 uint32_t minor;
    916 uint32_t max_readahead;
    917 uint32_t flags;
    918 uint16_t max_background;
    919 uint16_t congestion_threshold;
    920 uint32_t max_write;
    921 uint32_t time_gran;
    922 uint16_t max_pages;
    923 uint16_t map_alignment;
    924 uint32_t flags2;
    925 uint32_t max_stack_depth;
    926 uint16_t request_timeout;
    927 uint16_t unused[11];
    928};
    929
    930#define CUSE_INIT_INFO_MAX 4096
    931
    932struct cuse_init_in {
    933 uint32_t major;
    934 uint32_t minor;
    935 uint32_t unused;
    936 uint32_t flags;
    937};
    938
    939struct cuse_init_out {
    940 uint32_t major;
    941 uint32_t minor;
    942 uint32_t unused;
    943 uint32_t flags;
    944 uint32_t max_read;
    945 uint32_t max_write;
    946 uint32_t dev_major; /* chardev major */
    947 uint32_t dev_minor; /* chardev minor */
    948 uint32_t spare[10];
    949};
    950
    951struct fuse_interrupt_in {
    952 uint64_t unique;
    953};
    954
    955struct fuse_bmap_in {
    956 uint64_t block;
    957 uint32_t blocksize;
    958 uint32_t padding;
    959};
    960
    961struct fuse_bmap_out {
    962 uint64_t block;
    963};
    964
    965struct fuse_ioctl_in {
    966 uint64_t fh;
    967 uint32_t flags;
    968 uint32_t cmd;
    969 uint64_t arg;
    970 uint32_t in_size;
    971 uint32_t out_size;
    972};
    973
    974struct fuse_ioctl_iovec {
    975 uint64_t base;
    976 uint64_t len;
    977};
    978
    979struct fuse_ioctl_out {
    980 int32_t result;
    981 uint32_t flags;
    982 uint32_t in_iovs;
    983 uint32_t out_iovs;
    984};
    985
    986struct fuse_poll_in {
    987 uint64_t fh;
    988 uint64_t kh;
    989 uint32_t flags;
    990 uint32_t events;
    991};
    992
    993struct fuse_poll_out {
    994 uint32_t revents;
    995 uint32_t padding;
    996};
    997
    998struct fuse_notify_poll_wakeup_out {
    999 uint64_t kh;
    1000};
    1001
    1002struct fuse_fallocate_in {
    1003 uint64_t fh;
    1004 uint64_t offset;
    1005 uint64_t length;
    1006 uint32_t mode;
    1007 uint32_t padding;
    1008};
    1009
    1016#define FUSE_UNIQUE_RESEND (1ULL << 63)
    1017
    1031#define FUSE_INVALID_UIDGID ((uint32_t)(-1))
    1032
    1033struct fuse_in_header {
    1034 uint32_t len;
    1035 uint32_t opcode;
    1036 uint64_t unique;
    1037 uint64_t nodeid;
    1038 uint32_t uid;
    1039 uint32_t gid;
    1040 uint32_t pid;
    1041 uint16_t total_extlen; /* length of extensions in 8byte units */
    1042 uint16_t padding;
    1043};
    1044
    1045struct fuse_out_header {
    1046 uint32_t len;
    1047 int32_t error;
    1048 uint64_t unique;
    1049};
    1050
    1051struct fuse_dirent {
    1052 uint64_t ino;
    1053 uint64_t off;
    1054 uint32_t namelen;
    1055 uint32_t type;
    1056 char name[];
    1057};
    1058
    1059/* Align variable length records to 64bit boundary */
    1060#define FUSE_REC_ALIGN(x) \
    1061 (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1))
    1062
    1063#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name)
    1064#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x)
    1065#define FUSE_DIRENT_SIZE(d) \
    1066 FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen)
    1067
    1068struct fuse_direntplus {
    1069 struct fuse_entry_out entry_out;
    1070 struct fuse_dirent dirent;
    1071};
    1072
    1073#define FUSE_NAME_OFFSET_DIRENTPLUS \
    1074 offsetof(struct fuse_direntplus, dirent.name)
    1075#define FUSE_DIRENTPLUS_SIZE(d) \
    1076 FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen)
    1077
    1078struct fuse_notify_inval_inode_out {
    1079 uint64_t ino;
    1080 int64_t off;
    1081 int64_t len;
    1082};
    1083
    1084struct fuse_notify_inval_entry_out {
    1085 uint64_t parent;
    1086 uint32_t namelen;
    1087 uint32_t flags;
    1088};
    1089
    1090struct fuse_notify_delete_out {
    1091 uint64_t parent;
    1092 uint64_t child;
    1093 uint32_t namelen;
    1094 uint32_t padding;
    1095};
    1096
    1097struct fuse_notify_store_out {
    1098 uint64_t nodeid;
    1099 uint64_t offset;
    1100 uint32_t size;
    1101 uint32_t padding;
    1102};
    1103
    1104struct fuse_notify_retrieve_out {
    1105 uint64_t notify_unique;
    1106 uint64_t nodeid;
    1107 uint64_t offset;
    1108 uint32_t size;
    1109 uint32_t padding;
    1110};
    1111
    1112/* Matches the size of fuse_write_in */
    1113struct fuse_notify_retrieve_in {
    1114 uint64_t dummy1;
    1115 uint64_t offset;
    1116 uint32_t size;
    1117 uint32_t dummy2;
    1118 uint64_t dummy3;
    1119 uint64_t dummy4;
    1120};
    1121
    1122struct fuse_backing_map {
    1123 int32_t fd;
    1124 uint32_t flags;
    1125 uint64_t padding;
    1126};
    1127
    1128/* Device ioctls: */
    1129#define FUSE_DEV_IOC_MAGIC 229
    1130#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
    1131#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \
    1132 struct fuse_backing_map)
    1133#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t)
    1134
    1135struct fuse_lseek_in {
    1136 uint64_t fh;
    1137 uint64_t offset;
    1138 uint32_t whence;
    1139 uint32_t padding;
    1140};
    1141
    1142struct fuse_lseek_out {
    1143 uint64_t offset;
    1144};
    1145
    1146struct fuse_copy_file_range_in {
    1147 uint64_t fh_in;
    1148 uint64_t off_in;
    1149 uint64_t nodeid_out;
    1150 uint64_t fh_out;
    1151 uint64_t off_out;
    1152 uint64_t len;
    1153 uint64_t flags;
    1154};
    1155
    1156/* For FUSE_COPY_FILE_RANGE_64 */
    1157struct fuse_copy_file_range_out {
    1158 uint64_t bytes_copied;
    1159};
    1160
    1161#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0)
    1162#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1)
    1163struct fuse_setupmapping_in {
    1164 /* An already open handle */
    1165 uint64_t fh;
    1166 /* Offset into the file to start the mapping */
    1167 uint64_t foffset;
    1168 /* Length of mapping required */
    1169 uint64_t len;
    1170 /* Flags, FUSE_SETUPMAPPING_FLAG_* */
    1171 uint64_t flags;
    1172 /* Offset in Memory Window */
    1173 uint64_t moffset;
    1174};
    1175
    1176struct fuse_removemapping_in {
    1177 /* number of fuse_removemapping_one follows */
    1178 uint32_t count;
    1179};
    1180
    1181struct fuse_removemapping_one {
    1182 /* Offset into the dax window start the unmapping */
    1183 uint64_t moffset;
    1184 /* Length of mapping required */
    1185 uint64_t len;
    1186};
    1187
    1188#define FUSE_REMOVEMAPPING_MAX_ENTRY \
    1189 (PAGE_SIZE / sizeof(struct fuse_removemapping_one))
    1190
    1191struct fuse_syncfs_in {
    1192 uint64_t padding;
    1193};
    1194
    1195/*
    1196 * For each security context, send fuse_secctx with size of security context
    1197 * fuse_secctx will be followed by security context name and this in turn
    1198 * will be followed by actual context label.
    1199 * fuse_secctx, name, context
    1200 */
    1201struct fuse_secctx {
    1202 uint32_t size;
    1203 uint32_t padding;
    1204};
    1205
    1206/*
    1207 * Contains the information about how many fuse_secctx structures are being
    1208 * sent and what's the total size of all security contexts (including
    1209 * size of fuse_secctx_header).
    1210 *
    1211 */
    1212struct fuse_secctx_header {
    1213 uint32_t size;
    1214 uint32_t nr_secctx;
    1215};
    1216
    1226 uint32_t size;
    1227 uint32_t type;
    1228};
    1229
    1236 uint32_t nr_groups;
    1237 uint32_t groups[];
    1238};
    1239
    1243#define FUSE_URING_IN_OUT_HEADER_SZ 128
    1244#define FUSE_URING_OP_IN_OUT_SZ 128
    1245
    1246/* Used as part of the fuse_uring_req_header */
    1247struct fuse_uring_ent_in_out {
    1248 uint64_t flags;
    1249
    1250 /*
    1251 * commit ID to be used in a reply to a ring request (see also
    1252 * struct fuse_uring_cmd_req)
    1253 */
    1254 uint64_t commit_id;
    1255
    1256 /* size of user payload buffer */
    1257 uint32_t payload_sz;
    1258 uint32_t padding;
    1259
    1260 uint64_t reserved;
    1261};
    1262
    1267 /* struct fuse_in_header / struct fuse_out_header */
    1268 char in_out[FUSE_URING_IN_OUT_HEADER_SZ];
    1269
    1270 /* per op code header */
    1271 char op_in[FUSE_URING_OP_IN_OUT_SZ];
    1272
    1273 struct fuse_uring_ent_in_out ring_ent_in_out;
    1274};
    1275
    1279enum fuse_uring_cmd {
    1280 FUSE_IO_URING_CMD_INVALID = 0,
    1281
    1282 /* register the request buffer and fetch a fuse request */
    1283 FUSE_IO_URING_CMD_REGISTER = 1,
    1284
    1285 /* commit fuse request result and fetch next request */
    1286 FUSE_IO_URING_CMD_COMMIT_AND_FETCH = 2,
    1287};
    1288
    1293 uint64_t flags;
    1294
    1295 /* entry identifier for commits */
    1296 uint64_t commit_id;
    1297
    1298 /* queue the command is for (queue index) */
    1299 uint16_t qid;
    1300 uint8_t padding[6];
    1301};
    1302
    1303#endif /* _LINUX_FUSE_H */
    fuse-3.18.3/doc/html/fuse__log_8h_source.html0000644000175000017500000002652715250106404020047 0ustar berndbernd libfuse: include/fuse_log.h Source File
    libfuse
    fuse_log.h
    Go to the documentation of this file.
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2019 Red Hat, Inc.
    4
    5 This program can be distributed under the terms of the GNU LGPLv2.
    6 See the file LGPL2.txt.
    7*/
    8
    9#ifndef FUSE_LOG_H_
    10#define FUSE_LOG_H_
    11
    16
    17#include <stdarg.h>
    18
    19#ifdef __cplusplus
    20extern "C" {
    21#endif
    22
    29 FUSE_LOG_EMERG,
    30 FUSE_LOG_ALERT,
    31 FUSE_LOG_CRIT,
    32 FUSE_LOG_ERR,
    33 FUSE_LOG_WARNING,
    34 FUSE_LOG_NOTICE,
    35 FUSE_LOG_INFO,
    36 FUSE_LOG_DEBUG
    37};
    38
    52typedef void (*fuse_log_func_t)(enum fuse_log_level level,
    53 const char *fmt, va_list ap);
    54
    69
    76void fuse_log(enum fuse_log_level level, const char *fmt, ...)
    77 __attribute__((format(printf, 2, 3)));
    78
    84void fuse_log_enable_syslog(const char *ident, int option, int facility);
    85
    89void fuse_log_close_syslog(void);
    90
    91#ifdef __cplusplus
    92}
    93#endif
    94
    95#endif /* FUSE_LOG_H_ */
    void fuse_log_close_syslog(void)
    Definition fuse_log.c:56
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void(* fuse_log_func_t)(enum fuse_log_level level, const char *fmt, va_list ap)
    Definition fuse_log.h:52
    void void fuse_log_enable_syslog(const char *ident, int option, int facility)
    Definition fuse_log.c:49
    fuse_log_level
    Definition fuse_log.h:28
    void fuse_set_log_func(fuse_log_func_t func)
    Definition fuse_log.c:32
    fuse-3.18.3/doc/html/fuse__lowlevel_8h_source.html0000644000175000017500000050334515250106404021115 0ustar berndbernd 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 LGPL2.txt.
    7*/
    8
    9#ifndef FUSE_LOWLEVEL_H_
    10#define FUSE_LOWLEVEL_H_
    11
    20
    21#ifndef FUSE_USE_VERSION
    22#error FUSE_USE_VERSION not defined
    23#endif
    24
    25#include "fuse_common.h"
    26
    27#include <stddef.h>
    28#include <utime.h>
    29#include <fcntl.h>
    30#include <sys/types.h>
    31#include <sys/stat.h>
    32#include <sys/statvfs.h>
    33#include <sys/uio.h>
    34
    35#ifdef __cplusplus
    36extern "C" {
    37#endif
    38
    39/* ----------------------------------------------------------- *
    40 * Miscellaneous definitions *
    41 * ----------------------------------------------------------- */
    42
    44#define FUSE_ROOT_ID 1
    45
    47typedef uint64_t fuse_ino_t;
    48
    50typedef struct fuse_req *fuse_req_t;
    51
    52/* Forward declaration */
    53struct statx;
    54
    60struct fuse_session;
    61
    72
    83 uint64_t generation;
    84
    92 struct stat attr;
    93
    99
    105};
    106
    115struct fuse_ctx {
    117 uid_t uid;
    118
    120 gid_t gid;
    121
    123 pid_t pid;
    124
    126 mode_t umask;
    127};
    128
    129struct fuse_forget_data {
    130 fuse_ino_t ino;
    131 uint64_t nlookup;
    132};
    133
    134struct fuse_custom_io {
    135 ssize_t (*writev)(int fd, struct iovec *iov, int count, void *userdata);
    136 ssize_t (*read)(int fd, void *buf, size_t buf_len, void *userdata);
    137 ssize_t (*splice_receive)(int fdin, off_t *offin, int fdout,
    138 off_t *offout, size_t len,
    139 unsigned int flags, void *userdata);
    140 ssize_t (*splice_send)(int fdin, off_t *offin, int fdout,
    141 off_t *offout, size_t len,
    142 unsigned int flags, void *userdata);
    143 int (*clone_fd)(int master_fd);
    144};
    145
    152 FUSE_LL_INVALIDATE = 0,
    153 FUSE_LL_EXPIRE_ONLY = (1 << 0),
    154};
    155
    156/* 'to_set' flags in setattr */
    157#define FUSE_SET_ATTR_MODE (1 << 0)
    158#define FUSE_SET_ATTR_UID (1 << 1)
    159#define FUSE_SET_ATTR_GID (1 << 2)
    160#define FUSE_SET_ATTR_SIZE (1 << 3)
    161#define FUSE_SET_ATTR_ATIME (1 << 4)
    162#define FUSE_SET_ATTR_MTIME (1 << 5)
    163#define FUSE_SET_ATTR_ATIME_NOW (1 << 7)
    164#define FUSE_SET_ATTR_MTIME_NOW (1 << 8)
    165#define FUSE_SET_ATTR_FORCE (1 << 9)
    166#define FUSE_SET_ATTR_CTIME (1 << 10)
    167#define FUSE_SET_ATTR_KILL_SUID (1 << 11)
    168#define FUSE_SET_ATTR_KILL_SGID (1 << 12)
    169#define FUSE_SET_ATTR_FILE (1 << 13)
    170#define FUSE_SET_ATTR_KILL_PRIV (1 << 14)
    171#define FUSE_SET_ATTR_OPEN (1 << 15)
    172#define FUSE_SET_ATTR_TIMES_SET (1 << 16)
    173#define FUSE_SET_ATTR_TOUCH (1 << 17)
    174
    175/* ----------------------------------------------------------- *
    176 * Request methods and replies *
    177 * ----------------------------------------------------------- */
    178
    225 void (*init) (void *userdata, struct fuse_conn_info *conn);
    226
    238 void (*destroy) (void *userdata);
    239
    251 void (*lookup) (fuse_req_t req, fuse_ino_t parent, const char *name);
    252
    289 void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup);
    290
    310 void (*getattr) (fuse_req_t req, fuse_ino_t ino,
    311 struct fuse_file_info *fi);
    312
    347 void (*setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
    348 int to_set, struct fuse_file_info *fi);
    349
    360 void (*readlink) (fuse_req_t req, fuse_ino_t ino);
    361
    378 void (*mknod) (fuse_req_t req, fuse_ino_t parent, const char *name,
    379 mode_t mode, dev_t rdev);
    380
    393 void (*mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name,
    394 mode_t mode);
    395
    411 void (*unlink) (fuse_req_t req, fuse_ino_t parent, const char *name);
    412
    428 void (*rmdir) (fuse_req_t req, fuse_ino_t parent, const char *name);
    429
    442 void (*symlink) (fuse_req_t req, const char *link, fuse_ino_t parent,
    443 const char *name);
    444
    474 void (*rename) (fuse_req_t req, fuse_ino_t parent, const char *name,
    475 fuse_ino_t newparent, const char *newname,
    476 unsigned int flags);
    477
    490 void (*link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
    491 const char *newname);
    492
    556 void (*open) (fuse_req_t req, fuse_ino_t ino,
    557 struct fuse_file_info *fi);
    558
    584 void (*read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    585 struct fuse_file_info *fi);
    586
    613 void (*write) (fuse_req_t req, fuse_ino_t ino, const char *buf,
    614 size_t size, off_t off, struct fuse_file_info *fi);
    615
    654 void (*flush) (fuse_req_t req, fuse_ino_t ino,
    655 struct fuse_file_info *fi);
    656
    682 void (*release) (fuse_req_t req, fuse_ino_t ino,
    683 struct fuse_file_info *fi);
    684
    704 void (*fsync) (fuse_req_t req, fuse_ino_t ino, int datasync,
    705 struct fuse_file_info *fi);
    706
    736 void (*opendir) (fuse_req_t req, fuse_ino_t ino,
    737 struct fuse_file_info *fi);
    738
    782 void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    783 struct fuse_file_info *fi);
    784
    802 struct fuse_file_info *fi);
    803
    826 void (*fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync,
    827 struct fuse_file_info *fi);
    828
    839 void (*statfs) (fuse_req_t req, fuse_ino_t ino);
    840
    852 void (*setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
    853 const char *value, size_t size, int flags);
    854
    883 void (*getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name,
    884 size_t size);
    885
    914 void (*listxattr) (fuse_req_t req, fuse_ino_t ino, size_t size);
    915
    931 void (*removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name);
    932
    953 void (*access) (fuse_req_t req, fuse_ino_t ino, int mask);
    954
    982 void (*create) (fuse_req_t req, fuse_ino_t parent, const char *name,
    983 mode_t mode, struct fuse_file_info *fi);
    984
    997 void (*getlk) (fuse_req_t req, fuse_ino_t ino,
    998 struct fuse_file_info *fi, struct flock *lock);
    999
    1022 void (*setlk) (fuse_req_t req, fuse_ino_t ino,
    1023 struct fuse_file_info *fi,
    1024 struct flock *lock, int sleep);
    1025
    1046 void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
    1047 uint64_t idx);
    1048
    1049#if FUSE_USE_VERSION < 35
    1050 void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd,
    1051 void *arg, struct fuse_file_info *fi, unsigned flags,
    1052 const void *in_buf, size_t in_bufsz, size_t out_bufsz);
    1053#else
    1082 void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
    1083 void *arg, struct fuse_file_info *fi, unsigned flags,
    1084 const void *in_buf, size_t in_bufsz, size_t out_bufsz);
    1085#endif
    1086
    1119 void (*poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi,
    1120 struct fuse_pollhandle *ph);
    1121
    1150 struct fuse_bufvec *bufv, off_t off,
    1151 struct fuse_file_info *fi);
    1152
    1165 void (*retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino,
    1166 off_t offset, struct fuse_bufvec *bufv);
    1167
    1179 void (*forget_multi) (fuse_req_t req, size_t count,
    1180 struct fuse_forget_data *forgets);
    1181
    1197 void (*flock) (fuse_req_t req, fuse_ino_t ino,
    1198 struct fuse_file_info *fi, int op);
    1199
    1220 void (*fallocate) (fuse_req_t req, fuse_ino_t ino, int mode,
    1221 off_t offset, off_t length, struct fuse_file_info *fi);
    1222
    1248 void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    1249 struct fuse_file_info *fi);
    1250
    1282 off_t off_in, struct fuse_file_info *fi_in,
    1283 fuse_ino_t ino_out, off_t off_out,
    1284 struct fuse_file_info *fi_out, size_t len,
    1285 int flags);
    1286
    1305 void (*lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
    1306 struct fuse_file_info *fi);
    1307
    1326 void (*tmpfile) (fuse_req_t req, fuse_ino_t parent,
    1327 mode_t mode, struct fuse_file_info *fi);
    1328
    1342 void (*statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask,
    1343 struct fuse_file_info *fi);
    1344};
    1345
    1367int fuse_reply_err(fuse_req_t req, int err);
    1368
    1379void fuse_reply_none(fuse_req_t req);
    1380
    1394int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e);
    1395
    1414int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
    1415 const struct fuse_file_info *fi);
    1416
    1428int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
    1429 double attr_timeout);
    1430
    1441int fuse_reply_readlink(fuse_req_t req, const char *link);
    1442
    1455int fuse_passthrough_open(fuse_req_t req, int fd);
    1456int fuse_passthrough_close(fuse_req_t req, int backing_id);
    1457
    1472int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi);
    1473
    1484int fuse_reply_write(fuse_req_t req, size_t count);
    1485
    1497int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size);
    1498
    1542int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
    1544
    1556int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count);
    1557
    1568int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf);
    1569
    1580int fuse_reply_xattr(fuse_req_t req, size_t count);
    1581
    1592int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
    1593
    1604int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
    1605
    1606/* ----------------------------------------------------------- *
    1607 * Filling a buffer in readdir *
    1608 * ----------------------------------------------------------- */
    1609
    1637size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
    1638 const char *name, const struct stat *stbuf,
    1639 off_t off);
    1640
    1654size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
    1655 const char *name,
    1656 const struct fuse_entry_param *e, off_t off);
    1657
    1674 const struct iovec *in_iov, size_t in_count,
    1675 const struct iovec *out_iov, size_t out_count);
    1676
    1688int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
    1689
    1701int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
    1702 int count);
    1703
    1710int fuse_reply_poll(fuse_req_t req, unsigned revents);
    1711
    1722int fuse_reply_lseek(fuse_req_t req, off_t off);
    1723
    1736int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout);
    1737
    1738/* ----------------------------------------------------------- *
    1739 * Notification *
    1740 * ----------------------------------------------------------- */
    1741
    1749int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph);
    1750
    1774int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
    1775 off_t off, off_t len);
    1776
    1789int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se);
    1790
    1815int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
    1816 const char *name, size_t namelen);
    1817
    1846int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
    1847 const char *name, size_t namelen);
    1848
    1877int fuse_lowlevel_notify_delete(struct fuse_session *se,
    1878 fuse_ino_t parent, fuse_ino_t child,
    1879 const char *name, size_t namelen);
    1880
    1906int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
    1907 off_t offset, struct fuse_bufvec *bufv,
    1938int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
    1939 size_t size, off_t offset, void *cookie);
    1940
    1941
    1942/* ----------------------------------------------------------- *
    1943 * Utility functions *
    1944 * ----------------------------------------------------------- */
    1945
    1952void *fuse_req_userdata(fuse_req_t req);
    1953
    1963const struct fuse_ctx *fuse_req_ctx(fuse_req_t req);
    1964
    1984int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]);
    1985
    1992typedef void (*fuse_interrupt_func_t)(fuse_req_t req, void *data);
    1993
    2006 void *data);
    2007
    2015
    2016
    2017/* ----------------------------------------------------------- *
    2018 * Inquiry functions *
    2019 * ----------------------------------------------------------- */
    2020
    2024void fuse_lowlevel_version(void);
    2025
    2031void fuse_lowlevel_help(void);
    2032
    2036void fuse_cmdline_help(void);
    2037
    2038/* ----------------------------------------------------------- *
    2039 * Filesystem setup & teardown *
    2040 * ----------------------------------------------------------- */
    2041
    2048 int singlethread;
    2049 int foreground;
    2050 int debug;
    2051 int nodefault_subtype;
    2052 char *mountpoint;
    2053 int show_version;
    2054 int show_help;
    2055 int clone_fd;
    2056 unsigned int max_idle_threads; /* discouraged, due to thread
    2057 * destruct overhead */
    2058
    2059 /* Added in libfuse-3.12 */
    2060 unsigned int max_threads;
    2061};
    2062
    2081#if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS))
    2082int fuse_parse_cmdline(struct fuse_args *args,
    2083 struct fuse_cmdline_opts *opts);
    2084#else
    2085#if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12)
    2086int fuse_parse_cmdline_30(struct fuse_args *args,
    2087 struct fuse_cmdline_opts *opts);
    2088#define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_30(args, opts)
    2089#else
    2090int fuse_parse_cmdline_312(struct fuse_args *args,
    2091 struct fuse_cmdline_opts *opts);
    2092#define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_312(args, opts)
    2093#endif
    2094#endif
    2095
    2096/* Do not call this directly, use fuse_session_new() instead */
    2097struct fuse_session *
    2098fuse_session_new_versioned(struct fuse_args *args,
    2099 const struct fuse_lowlevel_ops *op, size_t op_size,
    2100 struct libfuse_version *version, void *userdata);
    2101
    2132static inline struct fuse_session *
    2133fuse_session_new_fn(struct fuse_args *args, const struct fuse_lowlevel_ops *op,
    2134 size_t op_size, void *userdata)
    2135{
    2136 struct libfuse_version version = {
    2137 .major = FUSE_MAJOR_VERSION,
    2138 .minor = FUSE_MINOR_VERSION,
    2139 .hotfix = FUSE_HOTFIX_VERSION,
    2140 .padding = 0
    2141 };
    2142
    2143 return fuse_session_new_versioned(args, op, op_size, &version,
    2144 userdata);
    2145}
    2146#define fuse_session_new(args, op, op_size, userdata) \
    2147 fuse_session_new_fn(args, op, op_size, userdata)
    2148
    2149/*
    2150 * This should mostly not be called directly, but instead the
    2151 * fuse_session_custom_io() should be used.
    2152 */
    2153int fuse_session_custom_io_317(struct fuse_session *se,
    2154 const struct fuse_custom_io *io, size_t op_size, int fd);
    2155
    2191#if FUSE_MAKE_VERSION(3, 17) <= FUSE_USE_VERSION
    2192static inline int fuse_session_custom_io(struct fuse_session *se,
    2193 const struct fuse_custom_io *io, size_t op_size, int fd)
    2194{
    2195 return fuse_session_custom_io_317(se, io, op_size, fd);
    2196}
    2197#else
    2198static inline int fuse_session_custom_io(struct fuse_session *se,
    2199 const struct fuse_custom_io *io, int fd)
    2200{
    2201 return fuse_session_custom_io_317(se, io,
    2202 offsetof(struct fuse_custom_io, clone_fd), fd);
    2203}
    2204#endif
    2205
    2214int fuse_session_mount(struct fuse_session *se, const char *mountpoint);
    2215
    2238int fuse_session_loop(struct fuse_session *se);
    2239
    2240#if FUSE_USE_VERSION < 32
    2241 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
    2242 #define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd)
    2243#elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12)
    2244 int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config);
    2245 #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_32(se, config)
    2246#else
    2247 #if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS))
    2259 int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config);
    2260 #else
    2261 int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config);
    2262 #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_312(se, config)
    2263 #endif
    2264#endif
    2265
    2283void fuse_session_exit(struct fuse_session *se);
    2284
    2290void fuse_session_reset(struct fuse_session *se);
    2291
    2298int fuse_session_exited(struct fuse_session *se);
    2299
    2324void fuse_session_unmount(struct fuse_session *se);
    2325
    2331void fuse_session_destroy(struct fuse_session *se);
    2332
    2333/* ----------------------------------------------------------- *
    2334 * Custom event loop support *
    2335 * ----------------------------------------------------------- */
    2336
    2351int fuse_session_fd(struct fuse_session *se);
    2352
    2361void fuse_session_process_buf(struct fuse_session *se,
    2362 const struct fuse_buf *buf);
    2363
    2375int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf);
    2376
    2381
    2397int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz,
    2398 void **mr);
    2399
    2400#ifdef __cplusplus
    2401}
    2402#endif
    2403
    2404#endif /* FUSE_LOWLEVEL_H_ */
    fuse_buf_copy_flags
    void fuse_session_destroy(struct fuse_session *se)
    fuse_notify_entry_flags
    int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    void fuse_session_exit(struct fuse_session *se)
    void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
    int fuse_reply_poll(fuse_req_t req, unsigned revents)
    int fuse_reply_err(fuse_req_t req, int err)
    bool fuse_req_is_uring(fuse_req_t req)
    const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
    void * fuse_req_userdata(fuse_req_t req)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
    int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
    int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
    void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
    int fuse_session_exited(struct fuse_session *se)
    int fuse_session_fd(struct fuse_session *se)
    int fuse_req_interrupted(fuse_req_t req)
    int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
    int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
    int fuse_reply_readlink(fuse_req_t req, const char *link)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
    int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr)
    int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
    void fuse_lowlevel_help(void)
    int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts)
    Definition helper.c:237
    int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
    int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
    int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
    void fuse_session_reset(struct fuse_session *se)
    int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_lseek(fuse_req_t req, off_t off)
    void fuse_lowlevel_version(void)
    int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_passthrough_open(fuse_req_t req, int fd)
    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_xattr(fuse_req_t req, size_t count)
    mode_t umask
    double entry_timeout
    fuse_ino_t ino
    uint64_t generation
    double attr_timeout
    struct stat attr
    int32_t backing_id
    void(* fsync)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
    void(* bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
    void(* unlink)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
    void(* rename)(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags)
    void(* releasedir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
    void(* write_buf)(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, off_t off, struct fuse_file_info *fi)
    void(* symlink)(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
    void(* statfs)(fuse_req_t req, fuse_ino_t ino)
    void(* tmpfile)(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)
    void(* release)(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(* fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
    void(* create)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)
    void(* link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
    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(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
    void(* flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)
    void(* getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
    void(* setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
    void(* open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name)
    void(* forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    void(* poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)
    void(* ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)
    void(* rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* init)(void *userdata, struct fuse_conn_info *conn)
    void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
    void(* retrieve_reply)(fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv)
    void(* fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
    void(* destroy)(void *userdata)
    void(* mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
    void(* statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)
    void(* access)(fuse_req_t req, fuse_ino_t ino, int mask)
    void(* mknod)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
    void(* lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)
    void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
    void(* readlink)(fuse_req_t req, fuse_ino_t ino)
    void(* read)(fuse_req_t req, fuse_ino_t ino, 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(* listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size)
    void(* opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* forget_multi)(fuse_req_t req, size_t count, struct fuse_forget_data *forgets)
    fuse-3.18.3/doc/html/fuse__mount__compat_8h_source.html0000644000175000017500000002201215250106404022113 0ustar berndbernd libfuse: include/fuse_mount_compat.h Source File
    libfuse
    fuse_mount_compat.h
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2023 Giulio Benetti <giulio.benetti@benettiengineering.com>
    4
    5 Logging API.
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LICENSE
    9*/
    10
    11#ifndef FUSE_MOUNT_COMPAT_H_
    12#define FUSE_MOUNT_COMPAT_H_
    13
    14#include <sys/mount.h>
    15
    16/* Some libc don't define MS_*, so define them manually
    17 * (values taken from https://elixir.bootlin.com/linux/v6.10/source/include/uapi/linux/mount.h#L13 on)
    18 */
    19#ifndef MS_DIRSYNC
    20#define MS_DIRSYNC 128
    21#endif
    22
    23#ifndef MS_NOSYMFOLLOW
    24#define MS_NOSYMFOLLOW 256
    25#endif
    26
    27#ifndef MS_REC
    28#define MS_REC 16384
    29#endif
    30
    31#ifndef MS_PRIVATE
    32#define MS_PRIVATE (1<<18)
    33#endif
    34
    35#ifndef MS_LAZYTIME
    36#define MS_LAZYTIME (1<<25)
    37#endif
    38
    39#ifndef UMOUNT_DETACH
    40#define UMOUNT_DETACH 0x00000002 /* Just detach from the tree */
    41#endif
    42#ifndef UMOUNT_NOFOLLOW
    43#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
    44#endif
    45#ifndef UMOUNT_UNUSED
    46#define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
    47#endif
    48
    49#endif /* FUSE_MOUNT_COMPAT_H_ */
    fuse-3.18.3/doc/html/fuse__opt_8h_source.html0000644000175000017500000005043715250106404020065 0ustar berndbernd 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 LGPL2.txt.
    7*/
    8
    9#ifndef FUSE_OPT_H_
    10#define FUSE_OPT_H_
    11
    16
    17#ifdef __cplusplus
    18extern "C" {
    19#endif
    20
    77struct 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
    109struct 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
    180typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
    181 struct fuse_args *outargs);
    182
    203int fuse_opt_parse(struct fuse_args *args, void *data,
    204 const struct fuse_opt opts[], fuse_opt_proc_t proc);
    205
    213int fuse_opt_add_opt(char **opts, const char *opt);
    214
    222int fuse_opt_add_opt_escaped(char **opts, const char *opt);
    223
    231int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
    232
    246int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg);
    247
    255void fuse_opt_free_args(struct fuse_args *args);
    256
    257
    265int 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_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)
    Definition fuse_opt.h:180
    int fuse_opt_add_opt_escaped(char **opts, const char *opt)
    Definition fuse_opt.c:144
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    int fuse_opt_add_opt(char **opts, const char *opt)
    Definition fuse_opt.c:139
    int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
    Definition fuse_opt.c:95
    int fuse_opt_match(const struct fuse_opt opts[], const char *opt)
    int allocated
    Definition fuse_opt.h:117
    char ** argv
    Definition fuse_opt.h:114
    const char * templ
    Definition fuse_opt.h:79
    unsigned long offset
    Definition fuse_opt.h:85
    int value
    Definition fuse_opt.h:91
    fuse-3.18.3/doc/html/buffer_8c_source.html0000644000175000017500000020215315250106404017340 0ustar berndbernd libfuse: lib/buffer.c Source File
    libfuse
    buffer.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2010 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Functions for dealing with `struct fuse_buf` and `struct
    6 fuse_bufvec`.
    7
    8 This program can be distributed under the terms of the GNU LGPLv2.
    9 See the file LGPL2.txt
    10*/
    11
    12#define _GNU_SOURCE
    13
    14#include "fuse_config.h"
    15#include "fuse_i.h"
    16#include "fuse_lowlevel.h"
    17#include <string.h>
    18#include <unistd.h>
    19#include <errno.h>
    20#include <assert.h>
    21
    22size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    23{
    24 size_t i;
    25 size_t size = 0;
    26
    27 for (i = 0; i < bufv->count; i++) {
    28 if (bufv->buf[i].size >= SIZE_MAX - size)
    29 return SIZE_MAX;
    30
    31 size += bufv->buf[i].size;
    32 }
    33
    34 return size;
    35}
    36
    37static size_t min_size(size_t s1, size_t s2)
    38{
    39 return s1 < s2 ? s1 : s2;
    40}
    41
    42static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off,
    43 const struct fuse_buf *src, size_t src_off,
    44 size_t len)
    45{
    46 ssize_t res = 0;
    47 size_t copied = 0;
    48
    49 while (len) {
    50 if (dst->flags & FUSE_BUF_FD_SEEK) {
    51 res = pwrite(dst->fd, (char *)src->mem + src_off, len,
    52 dst->pos + dst_off);
    53 } else {
    54 res = write(dst->fd, (char *)src->mem + src_off, len);
    55 }
    56 if (res == -1) {
    57 if (!copied)
    58 return -errno;
    59 break;
    60 }
    61 if (res == 0)
    62 break;
    63
    64 copied += res;
    65 if (!(dst->flags & FUSE_BUF_FD_RETRY))
    66 break;
    67
    68 src_off += res;
    69 dst_off += res;
    70 len -= res;
    71 }
    72
    73 return copied;
    74}
    75
    76static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off,
    77 const struct fuse_buf *src, size_t src_off,
    78 size_t len)
    79{
    80 ssize_t res = 0;
    81 size_t copied = 0;
    82
    83 while (len) {
    84 if (src->flags & FUSE_BUF_FD_SEEK) {
    85 res = pread(src->fd, (char *)dst->mem + dst_off, len,
    86 src->pos + src_off);
    87 } else {
    88 res = read(src->fd, (char *)dst->mem + dst_off, len);
    89 }
    90 if (res == -1) {
    91 if (!copied)
    92 return -errno;
    93 break;
    94 }
    95 if (res == 0)
    96 break;
    97
    98 copied += res;
    99 if (!(src->flags & FUSE_BUF_FD_RETRY))
    100 break;
    101
    102 dst_off += res;
    103 src_off += res;
    104 len -= res;
    105 }
    106
    107 return copied;
    108}
    109
    110static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off,
    111 const struct fuse_buf *src, size_t src_off,
    112 size_t len)
    113{
    114 char buf[4096];
    115 struct fuse_buf tmp = {
    116 .size = sizeof(buf),
    117 .flags = 0,
    118 };
    119 ssize_t res;
    120 size_t copied = 0;
    121
    122 tmp.mem = buf;
    123
    124 while (len) {
    125 size_t this_len = min_size(tmp.size, len);
    126 size_t read_len;
    127
    128 res = fuse_buf_read(&tmp, 0, src, src_off, this_len);
    129 if (res < 0) {
    130 if (!copied)
    131 return res;
    132 break;
    133 }
    134 if (res == 0)
    135 break;
    136
    137 read_len = res;
    138 res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len);
    139 if (res < 0) {
    140 if (!copied)
    141 return res;
    142 break;
    143 }
    144 if (res == 0)
    145 break;
    146
    147 copied += res;
    148
    149 if (res < this_len)
    150 break;
    151
    152 dst_off += res;
    153 src_off += res;
    154 len -= res;
    155 }
    156
    157 return copied;
    158}
    159
    160#ifdef HAVE_SPLICE
    161static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
    162 const struct fuse_buf *src, size_t src_off,
    163 size_t len, enum fuse_buf_copy_flags flags)
    164{
    165 int splice_flags = 0;
    166 off_t *srcpos = NULL;
    167 off_t *dstpos = NULL;
    168 off_t srcpos_val;
    169 off_t dstpos_val;
    170 ssize_t res;
    171 size_t copied = 0;
    172
    174 splice_flags |= SPLICE_F_MOVE;
    176 splice_flags |= SPLICE_F_NONBLOCK;
    177
    178 if (src->flags & FUSE_BUF_FD_SEEK) {
    179 srcpos_val = src->pos + src_off;
    180 srcpos = &srcpos_val;
    181 }
    182 if (dst->flags & FUSE_BUF_FD_SEEK) {
    183 dstpos_val = dst->pos + dst_off;
    184 dstpos = &dstpos_val;
    185 }
    186
    187 while (len) {
    188 res = splice(src->fd, srcpos, dst->fd, dstpos, len,
    189 splice_flags);
    190 if (res == -1) {
    191 if (copied)
    192 break;
    193
    194 if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE))
    195 return -errno;
    196
    197 /* Maybe splice is not supported for this combination */
    198 return fuse_buf_fd_to_fd(dst, dst_off, src, src_off,
    199 len);
    200 }
    201 if (res == 0)
    202 break;
    203
    204 copied += res;
    205 if (!(src->flags & FUSE_BUF_FD_RETRY) &&
    206 !(dst->flags & FUSE_BUF_FD_RETRY)) {
    207 break;
    208 }
    209
    210 len -= res;
    211 }
    212
    213 return copied;
    214}
    215#else
    216static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off,
    217 const struct fuse_buf *src, size_t src_off,
    218 size_t len, enum fuse_buf_copy_flags flags)
    219{
    220 (void) flags;
    221
    222 return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
    223}
    224#endif
    225
    226
    227static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off,
    228 const struct fuse_buf *src, size_t src_off,
    229 size_t len, enum fuse_buf_copy_flags flags)
    230{
    231 int src_is_fd = src->flags & FUSE_BUF_IS_FD;
    232 int dst_is_fd = dst->flags & FUSE_BUF_IS_FD;
    233
    234 if (!src_is_fd && !dst_is_fd) {
    235 char *dstmem = (char *)dst->mem + dst_off;
    236 char *srcmem = (char *)src->mem + src_off;
    237
    238 if (dstmem != srcmem) {
    239 if (dstmem + len <= srcmem || srcmem + len <= dstmem)
    240 memcpy(dstmem, srcmem, len);
    241 else
    242 memmove(dstmem, srcmem, len);
    243 }
    244
    245 return len;
    246 } else if (!src_is_fd) {
    247 return fuse_buf_write(dst, dst_off, src, src_off, len);
    248 } else if (!dst_is_fd) {
    249 return fuse_buf_read(dst, dst_off, src, src_off, len);
    250 } else if (flags & FUSE_BUF_NO_SPLICE) {
    251 return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len);
    252 } else {
    253 return fuse_buf_splice(dst, dst_off, src, src_off, len, flags);
    254 }
    255}
    256
    257static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv)
    258{
    259 if (bufv->idx < bufv->count)
    260 return &bufv->buf[bufv->idx];
    261 else
    262 return NULL;
    263}
    264
    265static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len)
    266{
    267 const struct fuse_buf *buf = fuse_bufvec_current(bufv);
    268
    269 if (!buf)
    270 return 0;
    271
    272 bufv->off += len;
    273 assert(bufv->off <= buf->size);
    274 if (bufv->off == buf->size) {
    275 assert(bufv->idx < bufv->count);
    276 bufv->idx++;
    277 if (bufv->idx == bufv->count)
    278 return 0;
    279 bufv->off = 0;
    280 }
    281 return 1;
    282}
    283
    284ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv,
    286{
    287 size_t copied = 0;
    288
    289 if (dstv == srcv)
    290 return fuse_buf_size(dstv);
    291
    292 for (;;) {
    293 const struct fuse_buf *src = fuse_bufvec_current(srcv);
    294 const struct fuse_buf *dst = fuse_bufvec_current(dstv);
    295 size_t src_len;
    296 size_t dst_len;
    297 size_t len;
    298 ssize_t res;
    299
    300 if (src == NULL || dst == NULL)
    301 break;
    302
    303 src_len = src->size - srcv->off;
    304 dst_len = dst->size - dstv->off;
    305 len = min_size(src_len, dst_len);
    306
    307 res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags);
    308 if (res < 0) {
    309 if (!copied)
    310 return res;
    311 break;
    312 }
    313 copied += res;
    314
    315 if (!fuse_bufvec_advance(srcv, res) ||
    316 !fuse_bufvec_advance(dstv, res))
    317 break;
    318
    319 if (res < len)
    320 break;
    321 }
    322
    323 return copied;
    324}
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_FD_RETRY
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    fuse_buf_copy_flags
    @ FUSE_BUF_SPLICE_NONBLOCK
    @ FUSE_BUF_FORCE_SPLICE
    @ FUSE_BUF_NO_SPLICE
    @ FUSE_BUF_SPLICE_MOVE
    enum fuse_buf_flags flags
    void * mem
    off_t pos
    size_t size
    struct fuse_buf buf[1]
    fuse-3.18.3/doc/html/compat_8c_source.html0000644000175000017500000004443015250106404017354 0ustar berndbernd libfuse: lib/compat.c Source File
    libfuse
    compat.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Helper functions to create (simple) standalone programs. With the
    6 aid of these functions it should be possible to create full FUSE
    7 file system by implementing nothing but the request handlers.
    8
    9 This program can be distributed under the terms of the GNU LGPLv2.
    10 See the file LGPL2.txt.
    11*/
    12
    13/* Description:
    14 This file has compatibility symbols for platforms that do not
    15 support version symboling
    16*/
    17
    18#include "libfuse_config.h"
    19
    20#include <stddef.h>
    21#include <stdint.h>
    22
    23struct fuse_args;
    26struct fuse_session;
    27struct fuse_custom_io;
    28struct fuse_operations;
    30
    34#if (!defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS))
    35/* With current libfuse fuse_parse_cmdline is a macro pointing to the
    36 * versioned function. Here in this file we need to provide the ABI symbol
    37 * and the redirecting macro is conflicting.
    38 */
    39#ifdef fuse_parse_cmdline
    40#undef fuse_parse_cmdline
    41#endif
    42int fuse_parse_cmdline_30(struct fuse_args *args,
    43 struct fuse_cmdline_opts *opts);
    44int fuse_parse_cmdline(struct fuse_args *args,
    45 struct fuse_cmdline_opts *opts);
    46int fuse_parse_cmdline(struct fuse_args *args,
    47 struct fuse_cmdline_opts *opts)
    48{
    49 return fuse_parse_cmdline_30(args, opts);
    50}
    51
    52int fuse_session_custom_io_30(struct fuse_session *se,
    53 const struct fuse_custom_io *io, int fd);
    54int fuse_session_custom_io(struct fuse_session *se,
    55 const struct fuse_custom_io *io, int fd);
    56int fuse_session_custom_io(struct fuse_session *se,
    57 const struct fuse_custom_io *io, int fd)
    58
    59{
    60 return fuse_session_custom_io_30(se, io, fd);
    61}
    62
    63#endif /* LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS */
    64
    65int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op,
    66 size_t op_size, void *user_data);
    67int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
    68 size_t op_size, void *user_data);
    69int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op,
    70 size_t op_size, void *user_data)
    71{
    72 return fuse_main_real_30(argc, argv, op, op_size, user_data);
    73}
    74
    75struct fuse_session *fuse_session_new_30(struct fuse_args *args,
    76 const struct fuse_lowlevel_ops *op,
    77 size_t op_size, void *userdata);
    78struct fuse_session *fuse_session_new(struct fuse_args *args,
    79 const struct fuse_lowlevel_ops *op,
    80 size_t op_size, void *userdata);
    81struct fuse_session *fuse_session_new(struct fuse_args *args,
    82 const struct fuse_lowlevel_ops *op,
    83 size_t op_size, void *userdata)
    84{
    85 return fuse_session_new_30(args, op, op_size, userdata);
    86}
    int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts)
    Definition helper.c:237
    fuse-3.18.3/doc/html/cuse__lowlevel_8c_source.html0000644000175000017500000020762715250106404021111 0ustar berndbernd libfuse: lib/cuse_lowlevel.c Source File
    libfuse
    cuse_lowlevel.c
    1/*
    2 CUSE: Character device in Userspace
    3 Copyright (C) 2008 SUSE Linux Products GmbH
    4 Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    5
    6 This program can be distributed under the terms of the GNU LGPLv2.
    7 See the file LGPL2.txt.
    8*/
    9
    10#include "fuse_config.h"
    11#include "cuse_lowlevel.h"
    12#include "fuse_kernel.h"
    13#include "fuse_i.h"
    14#include "fuse_opt.h"
    15
    16#include <stdio.h>
    17#include <string.h>
    18#include <stdlib.h>
    19#include <stddef.h>
    20#include <errno.h>
    21#include <unistd.h>
    22
    23struct cuse_data {
    24 struct cuse_lowlevel_ops clop;
    25 unsigned max_read;
    26 unsigned dev_major;
    27 unsigned dev_minor;
    28 unsigned flags;
    29 unsigned dev_info_len;
    30 char dev_info[];
    31};
    32
    33static struct cuse_lowlevel_ops *req_clop(fuse_req_t req)
    34{
    35 return &req->se->cuse_data->clop;
    36}
    37
    38static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino,
    39 struct fuse_file_info *fi)
    40{
    41 (void)ino;
    42 req_clop(req)->open(req, fi);
    43}
    44
    45static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size,
    46 off_t off, struct fuse_file_info *fi)
    47{
    48 (void)ino;
    49 req_clop(req)->read(req, size, off, fi);
    50}
    51
    52static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
    53 size_t size, off_t off, struct fuse_file_info *fi)
    54{
    55 (void)ino;
    56 req_clop(req)->write(req, buf, size, off, fi);
    57}
    58
    59static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino,
    60 struct fuse_file_info *fi)
    61{
    62 (void)ino;
    63 req_clop(req)->flush(req, fi);
    64}
    65
    66static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino,
    67 struct fuse_file_info *fi)
    68{
    69 (void)ino;
    70 req_clop(req)->release(req, fi);
    71}
    72
    73static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
    74 struct fuse_file_info *fi)
    75{
    76 (void)ino;
    77 req_clop(req)->fsync(req, datasync, fi);
    78}
    79
    80static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg,
    81 struct fuse_file_info *fi, unsigned int flags,
    82 const void *in_buf, size_t in_bufsz, size_t out_bufsz)
    83{
    84 (void)ino;
    85 req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz,
    86 out_bufsz);
    87}
    88
    89static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino,
    90 struct fuse_file_info *fi, struct fuse_pollhandle *ph)
    91{
    92 (void)ino;
    93 req_clop(req)->poll(req, fi, ph);
    94}
    95
    96static size_t cuse_pack_info(int argc, const char **argv, char *buf)
    97{
    98 size_t size = 0;
    99 int i;
    100
    101 for (i = 0; i < argc; i++) {
    102 size_t len;
    103
    104 len = strlen(argv[i]) + 1;
    105 size += len;
    106 if (buf) {
    107 memcpy(buf, argv[i], len);
    108 buf += len;
    109 }
    110 }
    111
    112 return size;
    113}
    114
    115static struct cuse_data *cuse_prep_data(const struct cuse_info *ci,
    116 const struct cuse_lowlevel_ops *clop)
    117{
    118 struct cuse_data *cd;
    119 size_t dev_info_len;
    120
    121 dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv,
    122 NULL);
    123
    124 if (dev_info_len > CUSE_INIT_INFO_MAX) {
    125 fuse_log(FUSE_LOG_ERR, "cuse: dev_info (%zu) too large, limit=%u\n",
    126 dev_info_len, CUSE_INIT_INFO_MAX);
    127 return NULL;
    128 }
    129
    130 cd = calloc(1, sizeof(*cd) + dev_info_len);
    131 if (!cd) {
    132 fuse_log(FUSE_LOG_ERR, "cuse: failed to allocate cuse_data\n");
    133 return NULL;
    134 }
    135
    136 memcpy(&cd->clop, clop, sizeof(cd->clop));
    137 cd->max_read = 131072;
    138 cd->dev_major = ci->dev_major;
    139 cd->dev_minor = ci->dev_minor;
    140 cd->dev_info_len = dev_info_len;
    141 cd->flags = ci->flags;
    142 cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info);
    143
    144 return cd;
    145}
    146
    147struct fuse_session *cuse_lowlevel_new(struct fuse_args *args,
    148 const struct cuse_info *ci,
    149 const struct cuse_lowlevel_ops *clop,
    150 void *userdata)
    151{
    152 struct fuse_lowlevel_ops lop;
    153 struct cuse_data *cd;
    154 struct fuse_session *se;
    155
    156 cd = cuse_prep_data(ci, clop);
    157 if (!cd)
    158 return NULL;
    159
    160 memset(&lop, 0, sizeof(lop));
    161 lop.init = clop->init;
    162 lop.destroy = clop->destroy;
    163 lop.open = clop->open ? cuse_fll_open : NULL;
    164 lop.read = clop->read ? cuse_fll_read : NULL;
    165 lop.write = clop->write ? cuse_fll_write : NULL;
    166 lop.flush = clop->flush ? cuse_fll_flush : NULL;
    167 lop.release = clop->release ? cuse_fll_release : NULL;
    168 lop.fsync = clop->fsync ? cuse_fll_fsync : NULL;
    169 lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL;
    170 lop.poll = clop->poll ? cuse_fll_poll : NULL;
    171
    172 se = fuse_session_new(args, &lop, sizeof(lop), userdata);
    173 if (!se) {
    174 free(cd);
    175 return NULL;
    176 }
    177 se->cuse_data = cd;
    178
    179 return se;
    180}
    181
    182static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg,
    183 char *dev_info, unsigned dev_info_len)
    184{
    185 struct iovec iov[3];
    186
    187 iov[1].iov_base = arg;
    188 iov[1].iov_len = sizeof(struct cuse_init_out);
    189 iov[2].iov_base = dev_info;
    190 iov[2].iov_len = dev_info_len;
    191
    192 return fuse_send_reply_iov_nofree(req, 0, iov, 3);
    193}
    194
    195void _cuse_lowlevel_init(fuse_req_t req, const fuse_ino_t nodeid,
    196 const void *op_in, const void *req_payload)
    197{
    198 const struct fuse_init_in *arg = op_in;
    199 (void)req_payload;
    200 struct cuse_init_out outarg;
    201 struct fuse_session *se = req->se;
    202 struct cuse_data *cd = se->cuse_data;
    203 size_t bufsize = se->bufsize;
    204 struct cuse_lowlevel_ops *clop = req_clop(req);
    205
    206 (void) nodeid;
    207 if (se->debug) {
    208 fuse_log(FUSE_LOG_DEBUG, "CUSE_INIT: %u.%u\n", arg->major, arg->minor);
    209 fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
    210 }
    211 se->conn.proto_major = arg->major;
    212 se->conn.proto_minor = arg->minor;
    213
    214 /* XXX This is not right.*/
    215 se->conn.capable_ext = 0;
    216 se->conn.want_ext = 0;
    217
    218 if (arg->major < 7) {
    219 fuse_log(FUSE_LOG_ERR, "cuse: unsupported protocol version: %u.%u\n",
    220 arg->major, arg->minor);
    221 fuse_reply_err(req, EPROTO);
    222 return;
    223 }
    224
    225 if (bufsize < FUSE_MIN_READ_BUFFER) {
    226 fuse_log(FUSE_LOG_ERR, "cuse: warning: buffer size too small: %zu\n",
    227 bufsize);
    228 bufsize = FUSE_MIN_READ_BUFFER;
    229 }
    230
    231 bufsize -= 4096;
    232 if (bufsize < se->conn.max_write)
    233 se->conn.max_write = bufsize;
    234
    235 se->got_init = 1;
    236 if (se->op.init)
    237 se->op.init(se->userdata, &se->conn);
    238
    239 memset(&outarg, 0, sizeof(outarg));
    240 outarg.major = FUSE_KERNEL_VERSION;
    241 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
    242 outarg.flags = cd->flags;
    243 outarg.max_read = cd->max_read;
    244 outarg.max_write = se->conn.max_write;
    245 outarg.dev_major = cd->dev_major;
    246 outarg.dev_minor = cd->dev_minor;
    247
    248 if (se->debug) {
    249 fuse_log(FUSE_LOG_DEBUG, " CUSE_INIT: %u.%u\n",
    250 outarg.major, outarg.minor);
    251 fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
    252 fuse_log(FUSE_LOG_DEBUG, " max_read=0x%08x\n", outarg.max_read);
    253 fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
    254 fuse_log(FUSE_LOG_DEBUG, " dev_major=%u\n", outarg.dev_major);
    255 fuse_log(FUSE_LOG_DEBUG, " dev_minor=%u\n", outarg.dev_minor);
    256 fuse_log(FUSE_LOG_DEBUG, " dev_info: %.*s\n", cd->dev_info_len,
    257 cd->dev_info);
    258 }
    259
    260 cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len);
    261
    262 if (clop->init_done)
    263 clop->init_done(se->userdata);
    264
    265 fuse_free_req(req);
    266}
    267
    268void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    269{
    270 _cuse_lowlevel_init(req, nodeid, inarg, NULL);
    271}
    272
    273struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[],
    274 const struct cuse_info *ci,
    275 const struct cuse_lowlevel_ops *clop,
    276 int *multithreaded, void *userdata)
    277{
    278 const char *devname = "/dev/cuse";
    279 static const struct fuse_opt kill_subtype_opts[] = {
    282 };
    283 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    284 struct fuse_session *se;
    285 struct fuse_cmdline_opts opts;
    286 int fd;
    287 int res;
    288
    289 if (fuse_parse_cmdline(&args, &opts) == -1)
    290 return NULL;
    291 *multithreaded = !opts.singlethread;
    292
    293 /* Remove subtype= option */
    294 res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL);
    295 if (res == -1)
    296 goto out1;
    297
    298 /*
    299 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
    300 * would ensue.
    301 */
    302 do {
    303 fd = open("/dev/null", O_RDWR);
    304 if (fd > 2)
    305 close(fd);
    306 } while (fd >= 0 && fd <= 2);
    307
    308 se = cuse_lowlevel_new(&args, ci, clop, userdata);
    309 if (se == NULL)
    310 goto out1;
    311
    312 fd = open(devname, O_RDWR);
    313 if (fd == -1) {
    314 if (errno == ENODEV || errno == ENOENT)
    315 fuse_log(FUSE_LOG_ERR, "cuse: device not found, try 'modprobe cuse' first\n");
    316 else
    317 fuse_log(FUSE_LOG_ERR, "cuse: failed to open %s: %s\n",
    318 devname, strerror(errno));
    319 goto err_se;
    320 }
    321 se->fd = fd;
    322
    323 res = fuse_set_signal_handlers(se);
    324 if (res == -1)
    325 goto err_se;
    326
    327 res = fuse_daemonize(opts.foreground);
    328 if (res == -1)
    329 goto err_sig;
    330
    331 fuse_opt_free_args(&args);
    332 return se;
    333
    334err_sig:
    336err_se:
    338out1:
    339 free(opts.mountpoint);
    340 fuse_opt_free_args(&args);
    341 return NULL;
    342}
    343
    344void cuse_lowlevel_teardown(struct fuse_session *se)
    345{
    348}
    349
    350int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci,
    351 const struct cuse_lowlevel_ops *clop, void *userdata)
    352{
    353 struct fuse_session *se;
    354 int multithreaded;
    355 int res;
    356
    357 se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded,
    358 userdata);
    359 if (se == NULL)
    360 return 1;
    361
    362 if (multithreaded) {
    363 struct fuse_loop_config *config = fuse_loop_cfg_create();
    364 res = fuse_session_loop_mt(se, config);
    365 fuse_loop_cfg_destroy(config);
    366 }
    367 else
    368 res = fuse_session_loop(se);
    369
    370 cuse_lowlevel_teardown(se);
    371 if (res == -1)
    372 return 1;
    373
    374 return 0;
    375}
    int fuse_set_signal_handlers(struct fuse_session *se)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    uint64_t fuse_ino_t
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_KEY_DISCARD
    Definition fuse_opt.h:153
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    fuse-3.18.3/doc/html/fuse_8c_source.html0000644000175000017500000340021615250106404017034 0ustar berndbernd 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 LGPL2.txt
    10*/
    11
    12#define _GNU_SOURCE
    13#include "fuse.h"
    14#include <pthread.h>
    15
    16#include "fuse_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#include "util.h"
    23
    24#include <stdint.h>
    25#include <stdio.h>
    26#include <string.h>
    27#include <stdlib.h>
    28#include <stddef.h>
    29#include <stdbool.h>
    30#include <unistd.h>
    31#include <time.h>
    32#include <fcntl.h>
    33#include <limits.h>
    34#include <errno.h>
    35#include <signal.h>
    36#include <dlfcn.h>
    37#include <assert.h>
    38#include <poll.h>
    39#include <sys/param.h>
    40#include <sys/uio.h>
    41#include <sys/time.h>
    42#include <sys/mman.h>
    43#include <sys/file.h>
    44
    45#define FUSE_NODE_SLAB 1
    46
    47#ifndef MAP_ANONYMOUS
    48#undef FUSE_NODE_SLAB
    49#endif
    50
    51#ifndef RENAME_EXCHANGE
    52#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
    53#endif
    54
    55#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
    56
    57#define FUSE_UNKNOWN_INO 0xffffffff
    58#define OFFSET_MAX 0x7fffffffffffffffLL
    59
    60#define NODE_TABLE_MIN_SIZE 8192
    61
    62struct fuse_fs {
    63 struct fuse_operations op;
    64 void *user_data;
    65 int debug;
    66};
    67
    68struct fusemod_so {
    69 void *handle;
    70 int ctr;
    71};
    72
    73struct lock_queue_element {
    74 struct lock_queue_element *next;
    75 pthread_cond_t cond;
    76 fuse_ino_t nodeid1;
    77 const char *name1;
    78 char **path1;
    79 struct node **wnode1;
    80 fuse_ino_t nodeid2;
    81 const char *name2;
    82 char **path2;
    83 struct node **wnode2;
    84 int err;
    85 bool done : 1;
    86};
    87
    88struct node_table {
    89 struct node **array;
    90 size_t use;
    91 size_t size;
    92 size_t split;
    93};
    94
    95#define list_entry(ptr, type, member) \
    96 container_of(ptr, type, member)
    97
    98struct list_head {
    99 struct list_head *next;
    100 struct list_head *prev;
    101};
    102
    103struct node_slab {
    104 struct list_head list; /* must be the first member */
    105 struct list_head freelist;
    106 int used;
    107};
    108
    109struct fuse {
    110 struct fuse_session *se;
    111 struct node_table name_table;
    112 struct node_table id_table;
    113 struct list_head lru_table;
    114 fuse_ino_t ctr;
    115 unsigned int generation;
    116 unsigned int hidectr;
    117 pthread_mutex_t lock;
    118 struct fuse_config conf;
    119 int intr_installed;
    120 struct fuse_fs *fs;
    121 struct lock_queue_element *lockq;
    122 int pagesize;
    123 struct list_head partial_slabs;
    124 struct list_head full_slabs;
    125 pthread_t prune_thread;
    126};
    127
    128struct lock {
    129 int type;
    130 off_t start;
    131 off_t end;
    132 pid_t pid;
    133 uint64_t owner;
    134 struct lock *next;
    135};
    136
    137struct node {
    138 struct node *name_next;
    139 struct node *id_next;
    140 fuse_ino_t nodeid;
    141 unsigned int generation;
    142 int refctr;
    143 struct node *parent;
    144 char *name;
    145 uint64_t nlookup;
    146 int open_count;
    147 struct timespec stat_updated;
    148 struct timespec mtime;
    149 off_t size;
    150 struct lock *locks;
    151 unsigned int is_hidden : 1;
    152 unsigned int cache_valid : 1;
    153 int treelock;
    154 char inline_name[32];
    155};
    156
    157#define TREELOCK_WRITE -1
    158#define TREELOCK_WAIT_OFFSET INT_MIN
    159
    160struct node_lru {
    161 struct node node;
    162 struct list_head lru;
    163 struct timespec forget_time;
    164};
    165
    166struct fuse_direntry {
    167 struct stat stat;
    168 enum fuse_fill_dir_flags flags;
    169 char *name;
    170 struct fuse_direntry *next;
    171};
    172
    173struct fuse_dh {
    174 pthread_mutex_t lock;
    175 struct fuse *fuse;
    176 fuse_req_t req;
    177 char *contents;
    178 struct fuse_direntry *first;
    179 struct fuse_direntry **last;
    180 unsigned len;
    181 unsigned size;
    182 unsigned needlen;
    183 int filled;
    184 uint64_t fh;
    185 int error;
    186 fuse_ino_t nodeid;
    187};
    188
    189struct fuse_context_i {
    190 struct fuse_context ctx;
    191 fuse_req_t req;
    192};
    193
    194/* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */
    195extern fuse_module_factory_t fuse_module_subdir_factory;
    196#ifdef HAVE_ICONV
    197extern fuse_module_factory_t fuse_module_iconv_factory;
    198#endif
    199
    200static pthread_key_t fuse_context_key;
    201static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
    202static int fuse_context_ref;
    203static struct fuse_module *fuse_modules = NULL;
    204
    205static int fuse_register_module(const char *name,
    206 fuse_module_factory_t factory,
    207 struct fusemod_so *so)
    208{
    209 struct fuse_module *mod;
    210
    211 mod = calloc(1, sizeof(struct fuse_module));
    212 if (!mod) {
    213 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module\n");
    214 return -1;
    215 }
    216 mod->name = strdup(name);
    217 if (!mod->name) {
    218 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module name\n");
    219 free(mod);
    220 return -1;
    221 }
    222 mod->factory = factory;
    223 mod->ctr = 0;
    224 mod->so = so;
    225 if (mod->so)
    226 mod->so->ctr++;
    227 mod->next = fuse_modules;
    228 fuse_modules = mod;
    229
    230 return 0;
    231}
    232
    233static void fuse_unregister_module(struct fuse_module *m)
    234{
    235 struct fuse_module **mp;
    236 for (mp = &fuse_modules; *mp; mp = &(*mp)->next) {
    237 if (*mp == m) {
    238 *mp = (*mp)->next;
    239 break;
    240 }
    241 }
    242 free(m->name);
    243 free(m);
    244}
    245
    246static int fuse_load_so_module(const char *module)
    247{
    248 int ret = -1;
    249 char *tmp;
    250 struct fusemod_so *so;
    251 fuse_module_factory_t *factory;
    252
    253 tmp = malloc(strlen(module) + 64);
    254 if (!tmp) {
    255 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    256 return -1;
    257 }
    258 sprintf(tmp, "libfusemod_%s.so", module);
    259 so = calloc(1, sizeof(struct fusemod_so));
    260 if (!so) {
    261 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module so\n");
    262 goto out;
    263 }
    264
    265 so->handle = dlopen(tmp, RTLD_NOW);
    266 if (so->handle == NULL) {
    267 fuse_log(FUSE_LOG_ERR, "fuse: dlopen(%s) failed: %s\n",
    268 tmp, dlerror());
    269 goto out_free_so;
    270 }
    271
    272 sprintf(tmp, "fuse_module_%s_factory", module);
    273 factory = (fuse_module_factory_t*)dlsym(so->handle, tmp);
    274 if (factory == NULL) {
    275 fuse_log(FUSE_LOG_ERR, "fuse: symbol <%s> not found in module: %s\n",
    276 tmp, dlerror());
    277 goto out_dlclose;
    278 }
    279 ret = fuse_register_module(module, *factory, so);
    280 if (ret)
    281 goto out_dlclose;
    282
    283out:
    284 free(tmp);
    285 return ret;
    286
    287out_dlclose:
    288 dlclose(so->handle);
    289out_free_so:
    290 free(so);
    291 goto out;
    292}
    293
    294static struct fuse_module *fuse_find_module(const char *module)
    295{
    296 struct fuse_module *m;
    297 for (m = fuse_modules; m; m = m->next) {
    298 if (strcmp(module, m->name) == 0) {
    299 m->ctr++;
    300 break;
    301 }
    302 }
    303 return m;
    304}
    305
    306static struct fuse_module *fuse_get_module(const char *module)
    307{
    308 struct fuse_module *m;
    309
    310 pthread_mutex_lock(&fuse_context_lock);
    311 m = fuse_find_module(module);
    312 if (!m) {
    313 int err = fuse_load_so_module(module);
    314 if (!err)
    315 m = fuse_find_module(module);
    316 }
    317 pthread_mutex_unlock(&fuse_context_lock);
    318 return m;
    319}
    320
    321static void fuse_put_module(struct fuse_module *m)
    322{
    323 pthread_mutex_lock(&fuse_context_lock);
    324 if (m->so)
    325 assert(m->ctr > 0);
    326 /* Builtin modules may already have m->ctr == 0 */
    327 if (m->ctr > 0)
    328 m->ctr--;
    329 if (!m->ctr && m->so) {
    330 struct fusemod_so *so = m->so;
    331 assert(so->ctr > 0);
    332 so->ctr--;
    333 if (!so->ctr) {
    334 struct fuse_module **mp;
    335 for (mp = &fuse_modules; *mp;) {
    336 if ((*mp)->so == so)
    337 fuse_unregister_module(*mp);
    338 else
    339 mp = &(*mp)->next;
    340 }
    341 dlclose(so->handle);
    342 free(so);
    343 }
    344 } else if (!m->ctr) {
    345 fuse_unregister_module(m);
    346 }
    347 pthread_mutex_unlock(&fuse_context_lock);
    348}
    349
    350static void init_list_head(struct list_head *list)
    351{
    352 list->next = list;
    353 list->prev = list;
    354}
    355
    356static int list_empty(const struct list_head *head)
    357{
    358 return head->next == head;
    359}
    360
    361static void list_add(struct list_head *new, struct list_head *prev,
    362 struct list_head *next)
    363{
    364 next->prev = new;
    365 new->next = next;
    366 new->prev = prev;
    367 prev->next = new;
    368}
    369
    370static inline void list_add_head(struct list_head *new, struct list_head *head)
    371{
    372 list_add(new, head, head->next);
    373}
    374
    375static inline void list_add_tail(struct list_head *new, struct list_head *head)
    376{
    377 list_add(new, head->prev, head);
    378}
    379
    380static inline void list_del(struct list_head *entry)
    381{
    382 struct list_head *prev = entry->prev;
    383 struct list_head *next = entry->next;
    384
    385 next->prev = prev;
    386 prev->next = next;
    387}
    388
    389static inline int lru_enabled(struct fuse *f)
    390{
    391 return f->conf.remember > 0;
    392}
    393
    394static struct node_lru *node_lru(struct node *node)
    395{
    396 return (struct node_lru *) node;
    397}
    398
    399static size_t get_node_size(struct fuse *f)
    400{
    401 if (lru_enabled(f))
    402 return sizeof(struct node_lru);
    403 else
    404 return sizeof(struct node);
    405}
    406
    407#ifdef FUSE_NODE_SLAB
    408static struct node_slab *list_to_slab(struct list_head *head)
    409{
    410 return (struct node_slab *) head;
    411}
    412
    413static struct node_slab *node_to_slab(struct fuse *f, struct node *node)
    414{
    415 return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1));
    416}
    417
    418static int alloc_slab(struct fuse *f)
    419{
    420 void *mem;
    421 struct node_slab *slab;
    422 char *start;
    423 size_t num;
    424 size_t i;
    425 size_t node_size = get_node_size(f);
    426
    427 mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE,
    428 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    429
    430 if (mem == MAP_FAILED)
    431 return -1;
    432
    433 slab = mem;
    434 init_list_head(&slab->freelist);
    435 slab->used = 0;
    436 num = (f->pagesize - sizeof(struct node_slab)) / node_size;
    437
    438 start = (char *) mem + f->pagesize - num * node_size;
    439 for (i = 0; i < num; i++) {
    440 struct list_head *n;
    441
    442 n = (struct list_head *) (start + i * node_size);
    443 list_add_tail(n, &slab->freelist);
    444 }
    445 list_add_tail(&slab->list, &f->partial_slabs);
    446
    447 return 0;
    448}
    449
    450static struct node *alloc_node(struct fuse *f)
    451{
    452 struct node_slab *slab;
    453 struct list_head *node;
    454
    455 if (list_empty(&f->partial_slabs)) {
    456 int res = alloc_slab(f);
    457 if (res != 0)
    458 return NULL;
    459 }
    460 slab = list_to_slab(f->partial_slabs.next);
    461 slab->used++;
    462 node = slab->freelist.next;
    463 list_del(node);
    464 if (list_empty(&slab->freelist)) {
    465 list_del(&slab->list);
    466 list_add_tail(&slab->list, &f->full_slabs);
    467 }
    468 memset(node, 0, sizeof(struct node));
    469
    470 return (struct node *) node;
    471}
    472
    473static void free_slab(struct fuse *f, struct node_slab *slab)
    474{
    475 int res;
    476
    477 list_del(&slab->list);
    478 res = munmap(slab, f->pagesize);
    479 if (res == -1)
    480 fuse_log(FUSE_LOG_WARNING, "fuse warning: munmap(%p) failed\n",
    481 slab);
    482}
    483
    484static void free_node_mem(struct fuse *f, struct node *node)
    485{
    486 struct node_slab *slab = node_to_slab(f, node);
    487 struct list_head *n = (struct list_head *) node;
    488
    489 slab->used--;
    490 if (slab->used) {
    491 if (list_empty(&slab->freelist)) {
    492 list_del(&slab->list);
    493 list_add_tail(&slab->list, &f->partial_slabs);
    494 }
    495 list_add_head(n, &slab->freelist);
    496 } else {
    497 free_slab(f, slab);
    498 }
    499}
    500#else
    501static struct node *alloc_node(struct fuse *f)
    502{
    503 return (struct node *) calloc(1, get_node_size(f));
    504}
    505
    506static void free_node_mem(struct fuse *f, struct node *node)
    507{
    508 (void) f;
    509 free(node);
    510}
    511#endif
    512
    513static size_t id_hash(struct fuse *f, fuse_ino_t ino)
    514{
    515 uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size;
    516 uint64_t oldhash = hash % (f->id_table.size / 2);
    517
    518 if (oldhash >= f->id_table.split)
    519 return oldhash;
    520 else
    521 return hash;
    522}
    523
    524static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
    525{
    526 size_t hash = id_hash(f, nodeid);
    527 struct node *node;
    528
    529 for (node = f->id_table.array[hash]; node != NULL; node = node->id_next)
    530 if (node->nodeid == nodeid)
    531 return node;
    532
    533 return NULL;
    534}
    535
    536static struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
    537{
    538 struct node *node = get_node_nocheck(f, nodeid);
    539 if (!node) {
    540 fuse_log(FUSE_LOG_ERR, "fuse internal error: node %llu not found\n",
    541 (unsigned long long) nodeid);
    542 abort();
    543 }
    544 return node;
    545}
    546
    547static void curr_time(struct timespec *now);
    548static double diff_timespec(const struct timespec *t1,
    549 const struct timespec *t2);
    550
    551static void remove_node_lru(struct node *node)
    552{
    553 struct node_lru *lnode = node_lru(node);
    554 list_del(&lnode->lru);
    555 init_list_head(&lnode->lru);
    556}
    557
    558static void set_forget_time(struct fuse *f, struct node *node)
    559{
    560 struct node_lru *lnode = node_lru(node);
    561
    562 list_del(&lnode->lru);
    563 list_add_tail(&lnode->lru, &f->lru_table);
    564 curr_time(&lnode->forget_time);
    565}
    566
    567static void free_node(struct fuse *f, struct node *node)
    568{
    569 if (node->name != node->inline_name)
    570 free(node->name);
    571 free_node_mem(f, node);
    572}
    573
    574static void node_table_reduce(struct node_table *t)
    575{
    576 size_t newsize = t->size / 2;
    577 void *newarray;
    578
    579 if (newsize < NODE_TABLE_MIN_SIZE)
    580 return;
    581
    582 newarray = realloc(t->array, sizeof(struct node *) * newsize);
    583 if (newarray != NULL)
    584 t->array = newarray;
    585
    586 t->size = newsize;
    587 t->split = t->size / 2;
    588}
    589
    590static void remerge_id(struct fuse *f)
    591{
    592 struct node_table *t = &f->id_table;
    593 int iter;
    594
    595 if (t->split == 0)
    596 node_table_reduce(t);
    597
    598 for (iter = 8; t->split > 0 && iter; iter--) {
    599 struct node **upper;
    600
    601 t->split--;
    602 upper = &t->array[t->split + t->size / 2];
    603 if (*upper) {
    604 struct node **nodep;
    605
    606 for (nodep = &t->array[t->split]; *nodep;
    607 nodep = &(*nodep)->id_next);
    608
    609 *nodep = *upper;
    610 *upper = NULL;
    611 break;
    612 }
    613 }
    614}
    615
    616static void unhash_id(struct fuse *f, struct node *node)
    617{
    618 struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)];
    619
    620 for (; *nodep != NULL; nodep = &(*nodep)->id_next)
    621 if (*nodep == node) {
    622 *nodep = node->id_next;
    623 f->id_table.use--;
    624
    625 if(f->id_table.use < f->id_table.size / 4)
    626 remerge_id(f);
    627 return;
    628 }
    629}
    630
    631static int node_table_resize(struct node_table *t)
    632{
    633 size_t newsize = t->size * 2;
    634 void *newarray;
    635
    636 newarray = realloc(t->array, sizeof(struct node *) * newsize);
    637 if (newarray == NULL)
    638 return -1;
    639
    640 t->array = newarray;
    641 memset(t->array + t->size, 0, t->size * sizeof(struct node *));
    642 t->size = newsize;
    643 t->split = 0;
    644
    645 return 0;
    646}
    647
    648static void rehash_id(struct fuse *f)
    649{
    650 struct node_table *t = &f->id_table;
    651 struct node **nodep;
    652 struct node **next;
    653 size_t hash;
    654
    655 if (t->split == t->size / 2)
    656 return;
    657
    658 hash = t->split;
    659 t->split++;
    660 for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
    661 struct node *node = *nodep;
    662 size_t newhash = id_hash(f, node->nodeid);
    663
    664 if (newhash != hash) {
    665 next = nodep;
    666 *nodep = node->id_next;
    667 node->id_next = t->array[newhash];
    668 t->array[newhash] = node;
    669 } else {
    670 next = &node->id_next;
    671 }
    672 }
    673 if (t->split == t->size / 2)
    674 node_table_resize(t);
    675}
    676
    677static void hash_id(struct fuse *f, struct node *node)
    678{
    679 size_t hash = id_hash(f, node->nodeid);
    680 node->id_next = f->id_table.array[hash];
    681 f->id_table.array[hash] = node;
    682 f->id_table.use++;
    683
    684 if (f->id_table.use >= f->id_table.size / 2)
    685 rehash_id(f);
    686}
    687
    688static size_t name_hash(struct fuse *f, fuse_ino_t parent,
    689 const char *name)
    690{
    691 uint64_t hash = parent;
    692 uint64_t oldhash;
    693
    694 for (; *name; name++)
    695 hash = hash * 31 + (unsigned char) *name;
    696
    697 hash %= f->name_table.size;
    698 oldhash = hash % (f->name_table.size / 2);
    699 if (oldhash >= f->name_table.split)
    700 return oldhash;
    701 else
    702 return hash;
    703}
    704
    705static void unref_node(struct fuse *f, struct node *node);
    706
    707static void remerge_name(struct fuse *f)
    708{
    709 struct node_table *t = &f->name_table;
    710 int iter;
    711
    712 if (t->split == 0)
    713 node_table_reduce(t);
    714
    715 for (iter = 8; t->split > 0 && iter; iter--) {
    716 struct node **upper;
    717
    718 t->split--;
    719 upper = &t->array[t->split + t->size / 2];
    720 if (*upper) {
    721 struct node **nodep;
    722
    723 for (nodep = &t->array[t->split]; *nodep;
    724 nodep = &(*nodep)->name_next);
    725
    726 *nodep = *upper;
    727 *upper = NULL;
    728 break;
    729 }
    730 }
    731}
    732
    733static void unhash_name(struct fuse *f, struct node *node)
    734{
    735 if (node->name) {
    736 size_t hash = name_hash(f, node->parent->nodeid, node->name);
    737 struct node **nodep = &f->name_table.array[hash];
    738
    739 for (; *nodep != NULL; nodep = &(*nodep)->name_next)
    740 if (*nodep == node) {
    741 *nodep = node->name_next;
    742 node->name_next = NULL;
    743 unref_node(f, node->parent);
    744 if (node->name != node->inline_name)
    745 free(node->name);
    746 node->name = NULL;
    747 node->parent = NULL;
    748 f->name_table.use--;
    749
    750 if (f->name_table.use < f->name_table.size / 4)
    751 remerge_name(f);
    752 return;
    753 }
    754 fuse_log(FUSE_LOG_ERR,
    755 "fuse internal error: unable to unhash node: %llu\n",
    756 (unsigned long long) node->nodeid);
    757 abort();
    758 }
    759}
    760
    761static void rehash_name(struct fuse *f)
    762{
    763 struct node_table *t = &f->name_table;
    764 struct node **nodep;
    765 struct node **next;
    766 size_t hash;
    767
    768 if (t->split == t->size / 2)
    769 return;
    770
    771 hash = t->split;
    772 t->split++;
    773 for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
    774 struct node *node = *nodep;
    775 size_t newhash = name_hash(f, node->parent->nodeid, node->name);
    776
    777 if (newhash != hash) {
    778 next = nodep;
    779 *nodep = node->name_next;
    780 node->name_next = t->array[newhash];
    781 t->array[newhash] = node;
    782 } else {
    783 next = &node->name_next;
    784 }
    785 }
    786 if (t->split == t->size / 2)
    787 node_table_resize(t);
    788}
    789
    790static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
    791 const char *name)
    792{
    793 size_t hash = name_hash(f, parentid, name);
    794 struct node *parent = get_node(f, parentid);
    795 if (strlen(name) < sizeof(node->inline_name)) {
    796 strcpy(node->inline_name, name);
    797 node->name = node->inline_name;
    798 } else {
    799 node->name = strdup(name);
    800 if (node->name == NULL)
    801 return -1;
    802 }
    803
    804 parent->refctr ++;
    805 node->parent = parent;
    806 node->name_next = f->name_table.array[hash];
    807 f->name_table.array[hash] = node;
    808 f->name_table.use++;
    809
    810 if (f->name_table.use >= f->name_table.size / 2)
    811 rehash_name(f);
    812
    813 return 0;
    814}
    815
    816static void delete_node(struct fuse *f, struct node *node)
    817{
    818 if (f->conf.debug)
    819 fuse_log(FUSE_LOG_DEBUG, "DELETE: %llu\n",
    820 (unsigned long long) node->nodeid);
    821
    822 assert(node->treelock == 0);
    823 unhash_name(f, node);
    824 if (lru_enabled(f))
    825 remove_node_lru(node);
    826 unhash_id(f, node);
    827 free_node(f, node);
    828}
    829
    830static void unref_node(struct fuse *f, struct node *node)
    831{
    832 assert(node->refctr > 0);
    833 node->refctr --;
    834 if (!node->refctr)
    835 delete_node(f, node);
    836}
    837
    838static fuse_ino_t next_id(struct fuse *f)
    839{
    840 do {
    841 f->ctr = (f->ctr + 1) & 0xffffffff;
    842 if (!f->ctr)
    843 f->generation ++;
    844 } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
    845 get_node_nocheck(f, f->ctr) != NULL);
    846 return f->ctr;
    847}
    848
    849static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
    850 const char *name)
    851{
    852 size_t hash = name_hash(f, parent, name);
    853 struct node *node;
    854
    855 for (node = f->name_table.array[hash]; node != NULL; node = node->name_next)
    856 if (node->parent->nodeid == parent &&
    857 strcmp(node->name, name) == 0)
    858 return node;
    859
    860 return NULL;
    861}
    862
    863static void inc_nlookup(struct node *node)
    864{
    865 if (!node->nlookup)
    866 node->refctr++;
    867 node->nlookup++;
    868}
    869
    870static struct node *find_node(struct fuse *f, fuse_ino_t parent,
    871 const char *name)
    872{
    873 struct node *node;
    874
    875 pthread_mutex_lock(&f->lock);
    876 if (!name)
    877 node = get_node(f, parent);
    878 else
    879 node = lookup_node(f, parent, name);
    880 if (node == NULL) {
    881 node = alloc_node(f);
    882 if (node == NULL)
    883 goto out_err;
    884
    885 node->nodeid = next_id(f);
    886 node->generation = f->generation;
    887 if (f->conf.remember)
    888 inc_nlookup(node);
    889
    890 if (hash_name(f, node, parent, name) == -1) {
    891 free_node(f, node);
    892 node = NULL;
    893 goto out_err;
    894 }
    895 hash_id(f, node);
    896 if (lru_enabled(f)) {
    897 struct node_lru *lnode = node_lru(node);
    898 init_list_head(&lnode->lru);
    899 }
    900 } else if (lru_enabled(f) && node->nlookup == 1) {
    901 remove_node_lru(node);
    902 }
    903 inc_nlookup(node);
    904out_err:
    905 pthread_mutex_unlock(&f->lock);
    906 return node;
    907}
    908
    909static int lookup_path_in_cache(struct fuse *f,
    910 const char *path, fuse_ino_t *inop)
    911{
    912 char *tmp = strdup(path);
    913 if (!tmp)
    914 return -ENOMEM;
    915
    916 pthread_mutex_lock(&f->lock);
    917 fuse_ino_t ino = FUSE_ROOT_ID;
    918
    919 int err = 0;
    920 char *save_ptr;
    921 char *path_element = strtok_r(tmp, "/", &save_ptr);
    922 while (path_element != NULL) {
    923 struct node *node = lookup_node(f, ino, path_element);
    924 if (node == NULL) {
    925 err = -ENOENT;
    926 break;
    927 }
    928 ino = node->nodeid;
    929 path_element = strtok_r(NULL, "/", &save_ptr);
    930 }
    931 pthread_mutex_unlock(&f->lock);
    932 free(tmp);
    933
    934 if (!err)
    935 *inop = ino;
    936 return err;
    937}
    938
    939static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
    940{
    941 size_t len = strlen(name);
    942
    943 if (s - len <= *buf) {
    944 unsigned pathlen = *bufsize - (s - *buf);
    945 unsigned newbufsize = *bufsize;
    946 char *newbuf;
    947
    948 while (newbufsize < pathlen + len + 1) {
    949 if (newbufsize >= 0x80000000)
    950 newbufsize = 0xffffffff;
    951 else
    952 newbufsize *= 2;
    953 }
    954
    955 newbuf = realloc(*buf, newbufsize);
    956 if (newbuf == NULL)
    957 return NULL;
    958
    959 *buf = newbuf;
    960 s = newbuf + newbufsize - pathlen;
    961 memmove(s, newbuf + *bufsize - pathlen, pathlen);
    962 *bufsize = newbufsize;
    963 }
    964 s -= len;
    965 memcpy(s, name, len);
    966 s--;
    967 *s = '/';
    968
    969 return s;
    970}
    971
    972static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode,
    973 struct node *end)
    974{
    975 struct node *node;
    976
    977 if (wnode) {
    978 assert(wnode->treelock == TREELOCK_WRITE);
    979 wnode->treelock = 0;
    980 }
    981
    982 for (node = get_node(f, nodeid);
    983 node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) {
    984 assert(node->treelock != 0);
    985 assert(node->treelock != TREELOCK_WAIT_OFFSET);
    986 assert(node->treelock != TREELOCK_WRITE);
    987 node->treelock--;
    988 if (node->treelock == TREELOCK_WAIT_OFFSET)
    989 node->treelock = 0;
    990 }
    991}
    992
    993static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
    994 char **path, struct node **wnodep, bool need_lock)
    995{
    996 unsigned bufsize = 256;
    997 char *buf;
    998 char *s;
    999 struct node *node;
    1000 struct node *wnode = NULL;
    1001 int err;
    1002
    1003 *path = NULL;
    1004
    1005 err = -ENOMEM;
    1006 buf = malloc(bufsize);
    1007 if (buf == NULL)
    1008 goto out_err;
    1009
    1010 s = buf + bufsize - 1;
    1011 *s = '\0';
    1012
    1013 if (name != NULL) {
    1014 s = add_name(&buf, &bufsize, s, name);
    1015 err = -ENOMEM;
    1016 if (s == NULL)
    1017 goto out_free;
    1018 }
    1019
    1020 if (wnodep) {
    1021 assert(need_lock);
    1022 assert(name != NULL);
    1023 wnode = lookup_node(f, nodeid, name);
    1024 if (wnode) {
    1025 if (wnode->treelock != 0) {
    1026 if (wnode->treelock > 0)
    1027 wnode->treelock += TREELOCK_WAIT_OFFSET;
    1028 err = -EAGAIN;
    1029 goto out_free;
    1030 }
    1031 wnode->treelock = TREELOCK_WRITE;
    1032 }
    1033 }
    1034
    1035 for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID;
    1036 node = node->parent) {
    1037 err = -ESTALE;
    1038 if (node->name == NULL || node->parent == NULL)
    1039 goto out_unlock;
    1040
    1041 err = -ENOMEM;
    1042 s = add_name(&buf, &bufsize, s, node->name);
    1043 if (s == NULL)
    1044 goto out_unlock;
    1045
    1046 if (need_lock) {
    1047 err = -EAGAIN;
    1048 if (node->treelock < 0)
    1049 goto out_unlock;
    1050
    1051 node->treelock++;
    1052 }
    1053 }
    1054
    1055 if (s[0])
    1056 memmove(buf, s, bufsize - (s - buf));
    1057 else
    1058 strcpy(buf, "/");
    1059
    1060 *path = buf;
    1061 if (wnodep)
    1062 *wnodep = wnode;
    1063
    1064 return 0;
    1065
    1066 out_unlock:
    1067 if (need_lock)
    1068 unlock_path(f, nodeid, wnode, node);
    1069 out_free:
    1070 free(buf);
    1071
    1072 out_err:
    1073 return err;
    1074}
    1075
    1076static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
    1077 fuse_ino_t nodeid2, const char *name2,
    1078 char **path1, char **path2,
    1079 struct node **wnode1, struct node **wnode2)
    1080{
    1081 int err;
    1082
    1083 /* FIXME: locking two paths needs deadlock checking */
    1084 err = try_get_path(f, nodeid1, name1, path1, wnode1, true);
    1085 if (!err) {
    1086 err = try_get_path(f, nodeid2, name2, path2, wnode2, true);
    1087 if (err) {
    1088 struct node *wn1 = wnode1 ? *wnode1 : NULL;
    1089
    1090 unlock_path(f, nodeid1, wn1, NULL);
    1091 free(*path1);
    1092 }
    1093 }
    1094 return err;
    1095}
    1096
    1097static void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe)
    1098{
    1099 int err;
    1100
    1101 if (!qe->path1) {
    1102 /* Just waiting for it to be unlocked */
    1103 if (get_node(f, qe->nodeid1)->treelock == 0)
    1104 pthread_cond_signal(&qe->cond);
    1105
    1106 return;
    1107 }
    1108
    1109 if (qe->done)
    1110 return; // Don't try to double-lock the element
    1111
    1112 if (!qe->path2) {
    1113 err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1,
    1114 qe->wnode1, true);
    1115 } else {
    1116 err = try_get_path2(f, qe->nodeid1, qe->name1, qe->nodeid2,
    1117 qe->name2, qe->path1, qe->path2, qe->wnode1,
    1118 qe->wnode2);
    1119 }
    1120
    1121 if (err == -EAGAIN)
    1122 return; /* keep trying */
    1123
    1124 qe->err = err;
    1125 qe->done = true;
    1126 pthread_cond_signal(&qe->cond);
    1127}
    1128
    1129static void wake_up_queued(struct fuse *f)
    1130{
    1131 struct lock_queue_element *qe;
    1132
    1133 for (qe = f->lockq; qe != NULL; qe = qe->next)
    1134 queue_element_wakeup(f, qe);
    1135}
    1136
    1137static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid,
    1138 const char *name, bool wr)
    1139{
    1140 if (f->conf.debug) {
    1141 struct node *wnode = NULL;
    1142
    1143 if (wr)
    1144 wnode = lookup_node(f, nodeid, name);
    1145
    1146 if (wnode) {
    1147 fuse_log(FUSE_LOG_DEBUG, "%s %llu (w)\n",
    1148 msg, (unsigned long long) wnode->nodeid);
    1149 } else {
    1150 fuse_log(FUSE_LOG_DEBUG, "%s %llu\n",
    1151 msg, (unsigned long long) nodeid);
    1152 }
    1153 }
    1154}
    1155
    1156static void queue_path(struct fuse *f, struct lock_queue_element *qe)
    1157{
    1158 struct lock_queue_element **qp;
    1159
    1160 qe->done = false;
    1161 pthread_cond_init(&qe->cond, NULL);
    1162 qe->next = NULL;
    1163 for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next);
    1164 *qp = qe;
    1165}
    1166
    1167static void dequeue_path(struct fuse *f, struct lock_queue_element *qe)
    1168{
    1169 struct lock_queue_element **qp;
    1170
    1171 pthread_cond_destroy(&qe->cond);
    1172 for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next);
    1173 *qp = qe->next;
    1174}
    1175
    1176static int wait_path(struct fuse *f, struct lock_queue_element *qe)
    1177{
    1178 queue_path(f, qe);
    1179
    1180 do {
    1181 pthread_cond_wait(&qe->cond, &f->lock);
    1182 } while (!qe->done);
    1183
    1184 dequeue_path(f, qe);
    1185
    1186 return qe->err;
    1187}
    1188
    1189static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name,
    1190 char **path, struct node **wnode)
    1191{
    1192 int err;
    1193
    1194 pthread_mutex_lock(&f->lock);
    1195 err = try_get_path(f, nodeid, name, path, wnode, true);
    1196 if (err == -EAGAIN) {
    1197 struct lock_queue_element qe = {
    1198 .nodeid1 = nodeid,
    1199 .name1 = name,
    1200 .path1 = path,
    1201 .wnode1 = wnode,
    1202 };
    1203 debug_path(f, "QUEUE PATH", nodeid, name, !!wnode);
    1204 err = wait_path(f, &qe);
    1205 debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode);
    1206 }
    1207 pthread_mutex_unlock(&f->lock);
    1208
    1209 return err;
    1210}
    1211
    1212static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path)
    1213{
    1214 return get_path_common(f, nodeid, NULL, path, NULL);
    1215}
    1216
    1217static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path)
    1218{
    1219 int err = 0;
    1220
    1221 if (f->conf.nullpath_ok) {
    1222 *path = NULL;
    1223 } else {
    1224 err = get_path_common(f, nodeid, NULL, path, NULL);
    1225 if (err == -ESTALE)
    1226 err = 0;
    1227 }
    1228
    1229 return err;
    1230}
    1231
    1232static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name,
    1233 char **path)
    1234{
    1235 return get_path_common(f, nodeid, name, path, NULL);
    1236}
    1237
    1238static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name,
    1239 char **path, struct node **wnode)
    1240{
    1241 return get_path_common(f, nodeid, name, path, wnode);
    1242}
    1243
    1244#if defined(__FreeBSD__)
    1245#define CHECK_DIR_LOOP
    1246#endif
    1247
    1248#if defined(CHECK_DIR_LOOP)
    1249static int check_dir_loop(struct fuse *f,
    1250 fuse_ino_t nodeid1, const char *name1,
    1251 fuse_ino_t nodeid2, const char *name2)
    1252{
    1253 struct node *node, *node1, *node2;
    1254 fuse_ino_t id1, id2;
    1255
    1256 node1 = lookup_node(f, nodeid1, name1);
    1257 id1 = node1 ? node1->nodeid : nodeid1;
    1258
    1259 node2 = lookup_node(f, nodeid2, name2);
    1260 id2 = node2 ? node2->nodeid : nodeid2;
    1261
    1262 for (node = get_node(f, id2); node->nodeid != FUSE_ROOT_ID;
    1263 node = node->parent) {
    1264 if (node->name == NULL || node->parent == NULL)
    1265 break;
    1266
    1267 if (node->nodeid != id2 && node->nodeid == id1)
    1268 return -EINVAL;
    1269 }
    1270
    1271 if (node2)
    1272 {
    1273 for (node = get_node(f, id1); node->nodeid != FUSE_ROOT_ID;
    1274 node = node->parent) {
    1275 if (node->name == NULL || node->parent == NULL)
    1276 break;
    1277
    1278 if (node->nodeid != id1 && node->nodeid == id2)
    1279 return -ENOTEMPTY;
    1280 }
    1281 }
    1282
    1283 return 0;
    1284}
    1285#endif
    1286
    1287static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1,
    1288 fuse_ino_t nodeid2, const char *name2,
    1289 char **path1, char **path2,
    1290 struct node **wnode1, struct node **wnode2)
    1291{
    1292 int err;
    1293
    1294 pthread_mutex_lock(&f->lock);
    1295
    1296#if defined(CHECK_DIR_LOOP)
    1297 if (name1)
    1298 {
    1299 // called during rename; perform dir loop check
    1300 err = check_dir_loop(f, nodeid1, name1, nodeid2, name2);
    1301 if (err)
    1302 goto out_unlock;
    1303 }
    1304#endif
    1305
    1306 err = try_get_path2(f, nodeid1, name1, nodeid2, name2,
    1307 path1, path2, wnode1, wnode2);
    1308 if (err == -EAGAIN) {
    1309 struct lock_queue_element qe = {
    1310 .nodeid1 = nodeid1,
    1311 .name1 = name1,
    1312 .path1 = path1,
    1313 .wnode1 = wnode1,
    1314 .nodeid2 = nodeid2,
    1315 .name2 = name2,
    1316 .path2 = path2,
    1317 .wnode2 = wnode2,
    1318 };
    1319
    1320 debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1);
    1321 debug_path(f, " PATH2", nodeid2, name2, !!wnode2);
    1322 err = wait_path(f, &qe);
    1323 debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1);
    1324 debug_path(f, " PATH2", nodeid2, name2, !!wnode2);
    1325 }
    1326
    1327#if defined(CHECK_DIR_LOOP)
    1328out_unlock:
    1329#endif
    1330 pthread_mutex_unlock(&f->lock);
    1331
    1332 return err;
    1333}
    1334
    1335static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid,
    1336 struct node *wnode, char *path)
    1337{
    1338 pthread_mutex_lock(&f->lock);
    1339 unlock_path(f, nodeid, wnode, NULL);
    1340 if (f->lockq)
    1341 wake_up_queued(f);
    1342 pthread_mutex_unlock(&f->lock);
    1343 free(path);
    1344}
    1345
    1346static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path)
    1347{
    1348 if (path)
    1349 free_path_wrlock(f, nodeid, NULL, path);
    1350}
    1351
    1352static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2,
    1353 struct node *wnode1, struct node *wnode2,
    1354 char *path1, char *path2)
    1355{
    1356 pthread_mutex_lock(&f->lock);
    1357 unlock_path(f, nodeid1, wnode1, NULL);
    1358 unlock_path(f, nodeid2, wnode2, NULL);
    1359 wake_up_queued(f);
    1360 pthread_mutex_unlock(&f->lock);
    1361 free(path1);
    1362 free(path2);
    1363}
    1364
    1365static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
    1366{
    1367 struct node *node;
    1368 if (nodeid == FUSE_ROOT_ID)
    1369 return;
    1370 pthread_mutex_lock(&f->lock);
    1371 node = get_node(f, nodeid);
    1372
    1373 /*
    1374 * Node may still be locked due to interrupt idiocy in open,
    1375 * create and opendir
    1376 */
    1377 while (node->nlookup == nlookup && node->treelock) {
    1378 struct lock_queue_element qe = {
    1379 .nodeid1 = nodeid,
    1380 };
    1381
    1382 debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false);
    1383 queue_path(f, &qe);
    1384
    1385 do {
    1386 pthread_cond_wait(&qe.cond, &f->lock);
    1387 } while (node->nlookup == nlookup && node->treelock);
    1388
    1389 dequeue_path(f, &qe);
    1390 debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false);
    1391 }
    1392
    1393 assert(node->nlookup >= nlookup);
    1394 node->nlookup -= nlookup;
    1395 if (!node->nlookup) {
    1396 unref_node(f, node);
    1397 } else if (lru_enabled(f) && node->nlookup == 1) {
    1398 set_forget_time(f, node);
    1399 }
    1400 pthread_mutex_unlock(&f->lock);
    1401}
    1402
    1403static void unlink_node(struct fuse *f, struct node *node)
    1404{
    1405 if (f->conf.remember) {
    1406 assert(node->nlookup > 1);
    1407 node->nlookup--;
    1408 }
    1409 unhash_name(f, node);
    1410}
    1411
    1412static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
    1413{
    1414 struct node *node;
    1415
    1416 pthread_mutex_lock(&f->lock);
    1417 node = lookup_node(f, dir, name);
    1418 if (node != NULL)
    1419 unlink_node(f, node);
    1420 pthread_mutex_unlock(&f->lock);
    1421}
    1422
    1423static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
    1424 fuse_ino_t newdir, const char *newname, int hide)
    1425{
    1426 struct node *node;
    1427 struct node *newnode;
    1428 int err = 0;
    1429
    1430 pthread_mutex_lock(&f->lock);
    1431 node = lookup_node(f, olddir, oldname);
    1432 newnode = lookup_node(f, newdir, newname);
    1433 if (node == NULL)
    1434 goto out;
    1435
    1436 if (newnode != NULL) {
    1437 if (hide) {
    1438 fuse_log(FUSE_LOG_ERR, "fuse: hidden file got created during hiding\n");
    1439 err = -EBUSY;
    1440 goto out;
    1441 }
    1442 unlink_node(f, newnode);
    1443 }
    1444
    1445 unhash_name(f, node);
    1446 if (hash_name(f, node, newdir, newname) == -1) {
    1447 err = -ENOMEM;
    1448 goto out;
    1449 }
    1450
    1451 if (hide)
    1452 node->is_hidden = 1;
    1453
    1454out:
    1455 pthread_mutex_unlock(&f->lock);
    1456 return err;
    1457}
    1458
    1459static int exchange_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
    1460 fuse_ino_t newdir, const char *newname)
    1461{
    1462 struct node *oldnode;
    1463 struct node *newnode;
    1464 int err;
    1465
    1466 pthread_mutex_lock(&f->lock);
    1467 oldnode = lookup_node(f, olddir, oldname);
    1468 newnode = lookup_node(f, newdir, newname);
    1469
    1470 if (oldnode)
    1471 unhash_name(f, oldnode);
    1472 if (newnode)
    1473 unhash_name(f, newnode);
    1474
    1475 err = -ENOMEM;
    1476 if (oldnode) {
    1477 if (hash_name(f, oldnode, newdir, newname) == -1)
    1478 goto out;
    1479 }
    1480 if (newnode) {
    1481 if (hash_name(f, newnode, olddir, oldname) == -1)
    1482 goto out;
    1483 }
    1484 err = 0;
    1485out:
    1486 pthread_mutex_unlock(&f->lock);
    1487 return err;
    1488}
    1489
    1490static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
    1491{
    1492 if (!f->conf.use_ino)
    1493 stbuf->st_ino = nodeid;
    1494 if (f->conf.set_mode) {
    1495 if (f->conf.dmask && S_ISDIR(stbuf->st_mode))
    1496 stbuf->st_mode = (stbuf->st_mode & S_IFMT) |
    1497 (0777 & ~f->conf.dmask);
    1498 else if (f->conf.fmask)
    1499 stbuf->st_mode = (stbuf->st_mode & S_IFMT) |
    1500 (0777 & ~f->conf.fmask);
    1501 else
    1502 stbuf->st_mode = (stbuf->st_mode & S_IFMT) |
    1503 (0777 & ~f->conf.umask);
    1504 }
    1505 if (f->conf.set_uid)
    1506 stbuf->st_uid = f->conf.uid;
    1507 if (f->conf.set_gid)
    1508 stbuf->st_gid = f->conf.gid;
    1509}
    1510
    1511#ifdef HAVE_STATX
    1512static void set_statx(struct fuse *f, fuse_ino_t nodeid, struct statx *stxbuf)
    1513{
    1514 if (!f->conf.use_ino)
    1515 stxbuf->stx_ino = nodeid;
    1516 if (f->conf.set_mode) {
    1517 if (f->conf.dmask && S_ISDIR(stxbuf->stx_mode))
    1518 stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
    1519 (0777 & ~f->conf.dmask);
    1520 else if (f->conf.fmask)
    1521 stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
    1522 (0777 & ~f->conf.fmask);
    1523 else
    1524 stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) |
    1525 (0777 & ~f->conf.umask);
    1526 }
    1527 if (f->conf.set_uid)
    1528 stxbuf->stx_uid = f->conf.uid;
    1529 if (f->conf.set_gid)
    1530 stxbuf->stx_gid = f->conf.gid;
    1531}
    1532#endif
    1533
    1534static struct fuse *req_fuse(fuse_req_t req)
    1535{
    1536 return (struct fuse *) fuse_req_userdata(req);
    1537}
    1538
    1539static void fuse_intr_sighandler(int sig)
    1540{
    1541 (void) sig;
    1542 /* Nothing to do */
    1543}
    1544
    1545struct fuse_intr_data {
    1546 pthread_t id;
    1547 pthread_cond_t cond;
    1548 int finished;
    1549};
    1550
    1551static void fuse_interrupt(fuse_req_t req, void *d_)
    1552{
    1553 struct fuse_intr_data *d = d_;
    1554 struct fuse *f = req_fuse(req);
    1555
    1556 if (d->id == pthread_self())
    1557 return;
    1558
    1559 pthread_mutex_lock(&f->lock);
    1560 while (!d->finished) {
    1561 struct timeval now;
    1562 struct timespec timeout;
    1563
    1564 pthread_kill(d->id, f->conf.intr_signal);
    1565 gettimeofday(&now, NULL);
    1566 timeout.tv_sec = now.tv_sec + 1;
    1567 timeout.tv_nsec = now.tv_usec * 1000;
    1568 pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
    1569 }
    1570 pthread_mutex_unlock(&f->lock);
    1571}
    1572
    1573static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
    1574 struct fuse_intr_data *d)
    1575{
    1576 pthread_mutex_lock(&f->lock);
    1577 d->finished = 1;
    1578 pthread_cond_broadcast(&d->cond);
    1579 pthread_mutex_unlock(&f->lock);
    1580 fuse_req_interrupt_func(req, NULL, NULL);
    1581 pthread_cond_destroy(&d->cond);
    1582}
    1583
    1584static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
    1585{
    1586 d->id = pthread_self();
    1587 pthread_cond_init(&d->cond, NULL);
    1588 d->finished = 0;
    1589 fuse_req_interrupt_func(req, fuse_interrupt, d);
    1590}
    1591
    1592static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
    1593 struct fuse_intr_data *d)
    1594{
    1595 if (f->conf.intr)
    1596 fuse_do_finish_interrupt(f, req, d);
    1597}
    1598
    1599static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
    1600 struct fuse_intr_data *d)
    1601{
    1602 if (f->conf.intr)
    1603 fuse_do_prepare_interrupt(req, d);
    1604}
    1605
    1606static const char* file_info_string(struct fuse_file_info *fi,
    1607 char* buf, size_t len)
    1608{
    1609 if(fi == NULL)
    1610 return "NULL";
    1611 snprintf(buf, len, "%llu", (unsigned long long) fi->fh);
    1612 return buf;
    1613}
    1614
    1615int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf,
    1616 struct fuse_file_info *fi)
    1617{
    1618 fuse_get_context()->private_data = fs->user_data;
    1619 if (!fs->op.getattr)
    1620 return -ENOSYS;
    1621
    1622 if (fs->debug) {
    1623 char buf[10];
    1624
    1625 fuse_log(FUSE_LOG_DEBUG, "getattr[%s] %s\n",
    1626 file_info_string(fi, buf, sizeof(buf)),
    1627 path);
    1628 }
    1629 return fs->op.getattr(path, buf, fi);
    1630}
    1631
    1632int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
    1633 const char *newpath, unsigned int flags)
    1634{
    1635 fuse_get_context()->private_data = fs->user_data;
    1636 if (!fs->op.rename)
    1637 return -ENOSYS;
    1638 if (fs->debug)
    1639 fuse_log(FUSE_LOG_DEBUG, "rename %s %s 0x%x\n", oldpath, newpath,
    1640 flags);
    1641
    1642 return fs->op.rename(oldpath, newpath, flags);
    1643}
    1644
    1645int fuse_fs_unlink(struct fuse_fs *fs, const char *path)
    1646{
    1647 fuse_get_context()->private_data = fs->user_data;
    1648 if (!fs->op.unlink)
    1649 return -ENOSYS;
    1650 if (fs->debug)
    1651 fuse_log(FUSE_LOG_DEBUG, "unlink %s\n", path);
    1652
    1653 return fs->op.unlink(path);
    1654}
    1655
    1656int fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
    1657{
    1658 fuse_get_context()->private_data = fs->user_data;
    1659 if (!fs->op.rmdir)
    1660 return -ENOSYS;
    1661 if (fs->debug)
    1662 fuse_log(FUSE_LOG_DEBUG, "rmdir %s\n", path);
    1663
    1664 return fs->op.rmdir(path);
    1665}
    1666
    1667int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
    1668{
    1669 fuse_get_context()->private_data = fs->user_data;
    1670 if (!fs->op.symlink)
    1671 return -ENOSYS;
    1672 if (fs->debug)
    1673 fuse_log(FUSE_LOG_DEBUG, "symlink %s %s\n", linkname, path);
    1674
    1675 return fs->op.symlink(linkname, path);
    1676}
    1677
    1678int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
    1679{
    1680 fuse_get_context()->private_data = fs->user_data;
    1681 if (!fs->op.link)
    1682 return -ENOSYS;
    1683 if (fs->debug)
    1684 fuse_log(FUSE_LOG_DEBUG, "link %s %s\n", oldpath, newpath);
    1685
    1686 return fs->op.link(oldpath, newpath);
    1687}
    1688
    1689int fuse_fs_release(struct fuse_fs *fs, const char *path,
    1690 struct fuse_file_info *fi)
    1691{
    1692 fuse_get_context()->private_data = fs->user_data;
    1693 if (!fs->op.release)
    1694 return 0;
    1695
    1696 if (fs->debug)
    1697 fuse_log(FUSE_LOG_DEBUG, "release%s[%llu] flags: 0x%x\n",
    1698 fi->flush ? "+flush" : "",
    1699 (unsigned long long) fi->fh, fi->flags);
    1700
    1701 return fs->op.release(path, fi);
    1702}
    1703
    1704int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
    1705 struct fuse_file_info *fi)
    1706{
    1707 int err;
    1708
    1709 fuse_get_context()->private_data = fs->user_data;
    1710 if (!fs->op.opendir)
    1711 return 0;
    1712
    1713 if (fs->debug)
    1714 fuse_log(FUSE_LOG_DEBUG, "opendir flags: 0x%x %s\n", fi->flags,
    1715 path);
    1716
    1717 err = fs->op.opendir(path, fi);
    1718
    1719 if (fs->debug && !err)
    1720 fuse_log(FUSE_LOG_DEBUG, " opendir[%llu] flags: 0x%x %s\n",
    1721 (unsigned long long) fi->fh, fi->flags, path);
    1722
    1723 return err;
    1724}
    1725
    1726int fuse_fs_open(struct fuse_fs *fs, const char *path,
    1727 struct fuse_file_info *fi)
    1728{
    1729 int err;
    1730
    1731 fuse_get_context()->private_data = fs->user_data;
    1732 if (!fs->op.open)
    1733 return 0;
    1734
    1735 if (fs->debug)
    1736 fuse_log(FUSE_LOG_DEBUG, "open flags: 0x%x %s\n", fi->flags,
    1737 path);
    1738
    1739 err = fs->op.open(path, fi);
    1740
    1741 if (fs->debug && !err)
    1742 fuse_log(FUSE_LOG_DEBUG, " open[%llu] flags: 0x%x %s\n",
    1743 (unsigned long long) fi->fh, fi->flags, path);
    1744
    1745 return err;
    1746}
    1747
    1748static void fuse_free_buf(struct fuse_bufvec *buf)
    1749{
    1750 if (buf != NULL) {
    1751 size_t i;
    1752
    1753 for (i = 0; i < buf->count; i++)
    1754 if (!(buf->buf[i].flags & FUSE_BUF_IS_FD))
    1755 free(buf->buf[i].mem);
    1756 free(buf);
    1757 }
    1758}
    1759
    1760int fuse_fs_read_buf(struct fuse_fs *fs, const char *path,
    1761 struct fuse_bufvec **bufp, size_t size, off_t off,
    1762 struct fuse_file_info *fi)
    1763{
    1764 int res;
    1765
    1766 fuse_get_context()->private_data = fs->user_data;
    1767 if (!fs->op.read && !fs->op.read_buf)
    1768 return -ENOSYS;
    1769
    1770 if (fs->debug)
    1771 fuse_log(FUSE_LOG_DEBUG,
    1772 "read[%llu] %zu bytes from %llu flags: 0x%x\n",
    1773 (unsigned long long) fi->fh,
    1774 size, (unsigned long long) off, fi->flags);
    1775
    1776 if (fs->op.read_buf) {
    1777 res = fs->op.read_buf(path, bufp, size, off, fi);
    1778 } else {
    1779 struct fuse_bufvec *buf;
    1780 void *mem;
    1781
    1782 buf = malloc(sizeof(struct fuse_bufvec));
    1783 if (buf == NULL)
    1784 return -ENOMEM;
    1785
    1786 mem = malloc(size);
    1787 if (mem == NULL) {
    1788 free(buf);
    1789 return -ENOMEM;
    1790 }
    1791 *buf = FUSE_BUFVEC_INIT(size);
    1792 buf->buf[0].mem = mem;
    1793 *bufp = buf;
    1794
    1795 res = fs->op.read(path, mem, size, off, fi);
    1796 if (res >= 0)
    1797 buf->buf[0].size = res;
    1798 }
    1799
    1800 if (fs->debug && res >= 0)
    1801 fuse_log(FUSE_LOG_DEBUG, " read[%llu] %zu bytes from %llu\n",
    1802 (unsigned long long) fi->fh,
    1803 fuse_buf_size(*bufp),
    1804 (unsigned long long) off);
    1805 if (res >= 0 && fuse_buf_size(*bufp) > size)
    1806 fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n");
    1807
    1808 if (res < 0)
    1809 return res;
    1810
    1811 return 0;
    1812}
    1813
    1814int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size,
    1815 off_t off, struct fuse_file_info *fi)
    1816{
    1817 int res;
    1818
    1819 fuse_get_context()->private_data = fs->user_data;
    1820 if (!fs->op.read && !fs->op.read_buf)
    1821 return -ENOSYS;
    1822
    1823 if (fs->debug)
    1824 fuse_log(FUSE_LOG_DEBUG,
    1825 "read[%llu] %zu bytes from %llu flags: 0x%x\n",
    1826 (unsigned long long) fi->fh,
    1827 size, (unsigned long long) off, fi->flags);
    1828
    1829 if (fs->op.read_buf) {
    1830 struct fuse_bufvec *buf = NULL;
    1831
    1832 res = fs->op.read_buf(path, &buf, size, off, fi);
    1833 if (res == 0) {
    1834 struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size);
    1835
    1836 dst.buf[0].mem = mem;
    1837 res = fuse_buf_copy(&dst, buf, 0);
    1838 }
    1839 fuse_free_buf(buf);
    1840 } else {
    1841 res = fs->op.read(path, mem, size, off, fi);
    1842 }
    1843
    1844 if (fs->debug && res >= 0)
    1845 fuse_log(FUSE_LOG_DEBUG, " read[%llu] %u bytes from %llu\n",
    1846 (unsigned long long) fi->fh,
    1847 res,
    1848 (unsigned long long) off);
    1849 if (res >= 0 && res > (int) size)
    1850 fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n");
    1851
    1852 return res;
    1853}
    1854
    1855int fuse_fs_write_buf(struct fuse_fs *fs, const char *path,
    1856 struct fuse_bufvec *buf, off_t off,
    1857 struct fuse_file_info *fi)
    1858{
    1859 int res;
    1860 size_t size;
    1861
    1862 fuse_get_context()->private_data = fs->user_data;
    1863 if (!fs->op.write_buf && !fs->op.write)
    1864 return -ENOSYS;
    1865
    1866 size = fuse_buf_size(buf);
    1867 assert(buf->idx == 0 && buf->off == 0);
    1868 if (fs->debug)
    1869 fuse_log(FUSE_LOG_DEBUG,
    1870 "write%s[%llu] %zu bytes to %llu flags: 0x%x\n",
    1871 fi->writepage ? "page" : "",
    1872 (unsigned long long) fi->fh,
    1873 size,
    1874 (unsigned long long) off,
    1875 fi->flags);
    1876
    1877 if (fs->op.write_buf) {
    1878 res = fs->op.write_buf(path, buf, off, fi);
    1879 } else {
    1880 void *mem = NULL;
    1881 struct fuse_buf *flatbuf;
    1882 struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size);
    1883
    1884 if (buf->count == 1 &&
    1885 !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
    1886 flatbuf = &buf->buf[0];
    1887 } else {
    1888 res = -ENOMEM;
    1889 mem = malloc(size);
    1890 if (mem == NULL)
    1891 goto out;
    1892
    1893 tmp.buf[0].mem = mem;
    1894 res = fuse_buf_copy(&tmp, buf, 0);
    1895 if (res <= 0)
    1896 goto out_free;
    1897
    1898 tmp.buf[0].size = res;
    1899 flatbuf = &tmp.buf[0];
    1900 }
    1901
    1902 res = fs->op.write(path, flatbuf->mem, flatbuf->size,
    1903 off, fi);
    1904out_free:
    1905 free(mem);
    1906 }
    1907out:
    1908 if (fs->debug && res >= 0)
    1909 fuse_log(FUSE_LOG_DEBUG, " write%s[%llu] %u bytes to %llu\n",
    1910 fi->writepage ? "page" : "",
    1911 (unsigned long long) fi->fh, res,
    1912 (unsigned long long) off);
    1913 if (res > (int) size)
    1914 fuse_log(FUSE_LOG_ERR, "fuse: wrote too many bytes\n");
    1915
    1916 return res;
    1917}
    1918
    1919int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem,
    1920 size_t size, off_t off, struct fuse_file_info *fi)
    1921{
    1922 struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size);
    1923
    1924 bufv.buf[0].mem = (void *) mem;
    1925
    1926 return fuse_fs_write_buf(fs, path, &bufv, off, fi);
    1927}
    1928
    1929int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
    1930 struct fuse_file_info *fi)
    1931{
    1932 fuse_get_context()->private_data = fs->user_data;
    1933 if (!fs->op.fsync)
    1934 return -ENOSYS;
    1935
    1936 if (fs->debug)
    1937 fuse_log(FUSE_LOG_DEBUG, "fsync[%llu] datasync: %i\n",
    1938 (unsigned long long) fi->fh, datasync);
    1939
    1940 return fs->op.fsync(path, datasync, fi);
    1941}
    1942
    1943int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
    1944 struct fuse_file_info *fi)
    1945{
    1946 fuse_get_context()->private_data = fs->user_data;
    1947 if (!fs->op.fsyncdir)
    1948 return -ENOSYS;
    1949
    1950 if (fs->debug)
    1951 fuse_log(FUSE_LOG_DEBUG, "fsyncdir[%llu] datasync: %i\n",
    1952 (unsigned long long) fi->fh, datasync);
    1953
    1954 return fs->op.fsyncdir(path, datasync, fi);
    1955}
    1956
    1957int fuse_fs_flush(struct fuse_fs *fs, const char *path,
    1958 struct fuse_file_info *fi)
    1959{
    1960 fuse_get_context()->private_data = fs->user_data;
    1961 if (!fs->op.flush)
    1962 return -ENOSYS;
    1963 if (fs->debug)
    1964 fuse_log(FUSE_LOG_DEBUG, "flush[%llu]\n",
    1965 (unsigned long long) fi->fh);
    1966
    1967 return fs->op.flush(path, fi);
    1968}
    1969
    1970int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
    1971{
    1972 fuse_get_context()->private_data = fs->user_data;
    1973 if (fs->op.statfs) {
    1974 if (fs->debug)
    1975 fuse_log(FUSE_LOG_DEBUG, "statfs %s\n", path);
    1976
    1977 return fs->op.statfs(path, buf);
    1978 } else {
    1979 buf->f_namemax = 255;
    1980 buf->f_bsize = 512;
    1981 return 0;
    1982 }
    1983}
    1984
    1985int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
    1986 struct fuse_file_info *fi)
    1987{
    1988 fuse_get_context()->private_data = fs->user_data;
    1989 if (!fs->op.releasedir)
    1990 return 0;
    1991
    1992 if (fs->debug)
    1993 fuse_log(FUSE_LOG_DEBUG, "releasedir[%llu] flags: 0x%x\n",
    1994 (unsigned long long) fi->fh, fi->flags);
    1995
    1996 return fs->op.releasedir(path, fi);
    1997}
    1998
    1999int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
    2000 fuse_fill_dir_t filler, off_t off,
    2001 struct fuse_file_info *fi,
    2002 enum fuse_readdir_flags flags)
    2003{
    2004 fuse_get_context()->private_data = fs->user_data;
    2005 if (!fs->op.readdir)
    2006 return -ENOSYS;
    2007 if (fs->debug) {
    2008 fuse_log(FUSE_LOG_DEBUG, "readdir%s[%llu] from %llu\n",
    2009 (flags & FUSE_READDIR_PLUS) ? "plus" : "",
    2010 (unsigned long long) fi->fh,
    2011 (unsigned long long) off);
    2012 }
    2013
    2014 return fs->op.readdir(path, buf, filler, off, fi, flags);
    2015}
    2016
    2017int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
    2018 struct fuse_file_info *fi)
    2019{
    2020 int err;
    2021
    2022 fuse_get_context()->private_data = fs->user_data;
    2023 if (!fs->op.create)
    2024 return -ENOSYS;
    2025
    2026 if (fs->debug)
    2027 fuse_log(FUSE_LOG_DEBUG,
    2028 "create flags: 0x%x %s 0%o umask=0%03o\n",
    2029 fi->flags, path, mode,
    2030 fuse_get_context()->umask);
    2031
    2032 err = fs->op.create(path, mode, fi);
    2033
    2034 if (fs->debug && !err)
    2035 fuse_log(FUSE_LOG_DEBUG, " create[%llu] flags: 0x%x %s\n",
    2036 (unsigned long long) fi->fh, fi->flags, path);
    2037
    2038 return err;
    2039}
    2040
    2041int fuse_fs_lock(struct fuse_fs *fs, const char *path,
    2042 struct fuse_file_info *fi, int cmd, struct flock *lock)
    2043{
    2044 fuse_get_context()->private_data = fs->user_data;
    2045 if (!fs->op.lock)
    2046 return -ENOSYS;
    2047
    2048 if (fs->debug)
    2049 fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n",
    2050 (unsigned long long) fi->fh,
    2051 (cmd == F_GETLK ? "F_GETLK" :
    2052 (cmd == F_SETLK ? "F_SETLK" :
    2053 (cmd == F_SETLKW ? "F_SETLKW" : "???"))),
    2054 (lock->l_type == F_RDLCK ? "F_RDLCK" :
    2055 (lock->l_type == F_WRLCK ? "F_WRLCK" :
    2056 (lock->l_type == F_UNLCK ? "F_UNLCK" :
    2057 "???"))),
    2058 (unsigned long long) lock->l_start,
    2059 (unsigned long long) lock->l_len,
    2060 (unsigned long long) lock->l_pid);
    2061
    2062 return fs->op.lock(path, fi, cmd, lock);
    2063}
    2064
    2065int fuse_fs_flock(struct fuse_fs *fs, const char *path,
    2066 struct fuse_file_info *fi, int op)
    2067{
    2068 fuse_get_context()->private_data = fs->user_data;
    2069 if (!fs->op.flock)
    2070 return -ENOSYS;
    2071
    2072 if (fs->debug) {
    2073 int xop = op & ~LOCK_NB;
    2074
    2075 fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s%s\n",
    2076 (unsigned long long) fi->fh,
    2077 xop == LOCK_SH ? "LOCK_SH" :
    2078 (xop == LOCK_EX ? "LOCK_EX" :
    2079 (xop == LOCK_UN ? "LOCK_UN" : "???")),
    2080 (op & LOCK_NB) ? "|LOCK_NB" : "");
    2081 }
    2082 return fs->op.flock(path, fi, op);
    2083}
    2084
    2085int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid,
    2086 gid_t gid, struct fuse_file_info *fi)
    2087{
    2088 fuse_get_context()->private_data = fs->user_data;
    2089 if (!fs->op.chown)
    2090 return -ENOSYS;
    2091 if (fs->debug) {
    2092 char buf[10];
    2093
    2094 fuse_log(FUSE_LOG_DEBUG, "chown[%s] %s %lu %lu\n",
    2095 file_info_string(fi, buf, sizeof(buf)),
    2096 path, (unsigned long) uid, (unsigned long) gid);
    2097 }
    2098 return fs->op.chown(path, uid, gid, fi);
    2099}
    2100
    2101int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size,
    2102 struct fuse_file_info *fi)
    2103{
    2104 fuse_get_context()->private_data = fs->user_data;
    2105 if (!fs->op.truncate)
    2106 return -ENOSYS;
    2107 if (fs->debug) {
    2108 char buf[10];
    2109
    2110 fuse_log(FUSE_LOG_DEBUG, "truncate[%s] %llu\n",
    2111 file_info_string(fi, buf, sizeof(buf)),
    2112 (unsigned long long) size);
    2113 }
    2114 return fs->op.truncate(path, size, fi);
    2115}
    2116
    2117int fuse_fs_utimens(struct fuse_fs *fs, const char *path,
    2118 const struct timespec tv[2], struct fuse_file_info *fi)
    2119{
    2120 fuse_get_context()->private_data = fs->user_data;
    2121 if (!fs->op.utimens)
    2122 return -ENOSYS;
    2123 if (fs->debug) {
    2124 char buf[10];
    2125
    2126 fuse_log(FUSE_LOG_DEBUG, "utimens[%s] %s %jd.%09ld %jd.%09ld\n",
    2127 file_info_string(fi, buf, sizeof(buf)),
    2128 path, (intmax_t)tv[0].tv_sec, tv[0].tv_nsec,
    2129 (intmax_t)tv[1].tv_sec, tv[1].tv_nsec);
    2130 }
    2131 return fs->op.utimens(path, tv, fi);
    2132}
    2133
    2134int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
    2135{
    2136 fuse_get_context()->private_data = fs->user_data;
    2137 if (!fs->op.access)
    2138 return -ENOSYS;
    2139 if (fs->debug)
    2140 fuse_log(FUSE_LOG_DEBUG, "access %s 0%o\n", path, mask);
    2141
    2142 return fs->op.access(path, mask);
    2143}
    2144
    2145int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
    2146 size_t len)
    2147{
    2148 fuse_get_context()->private_data = fs->user_data;
    2149 if (!fs->op.readlink)
    2150 return -ENOSYS;
    2151 if (fs->debug)
    2152 fuse_log(FUSE_LOG_DEBUG, "readlink %s %lu\n", path,
    2153 (unsigned long) len);
    2154
    2155 return fs->op.readlink(path, buf, len);
    2156}
    2157
    2158int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
    2159 dev_t rdev)
    2160{
    2161 fuse_get_context()->private_data = fs->user_data;
    2162 if (!fs->op.mknod)
    2163 return -ENOSYS;
    2164 if (fs->debug)
    2165 fuse_log(FUSE_LOG_DEBUG, "mknod %s 0%o 0x%llx umask=0%03o\n",
    2166 path, mode, (unsigned long long) rdev,
    2167 fuse_get_context()->umask);
    2168
    2169 return fs->op.mknod(path, mode, rdev);
    2170}
    2171
    2172int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
    2173{
    2174 fuse_get_context()->private_data = fs->user_data;
    2175 if (!fs->op.mkdir)
    2176 return -ENOSYS;
    2177 if (fs->debug)
    2178 fuse_log(FUSE_LOG_DEBUG, "mkdir %s 0%o umask=0%03o\n",
    2179 path, mode, fuse_get_context()->umask);
    2180
    2181 return fs->op.mkdir(path, mode);
    2182}
    2183
    2184int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
    2185 const char *value, size_t size, int flags)
    2186{
    2187 fuse_get_context()->private_data = fs->user_data;
    2188 if (!fs->op.setxattr)
    2189 return -ENOSYS;
    2190 if (fs->debug)
    2191 fuse_log(FUSE_LOG_DEBUG, "setxattr %s %s %lu 0x%x\n",
    2192 path, name, (unsigned long) size, flags);
    2193
    2194 return fs->op.setxattr(path, name, value, size, flags);
    2195}
    2196
    2197int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
    2198 char *value, size_t size)
    2199{
    2200 fuse_get_context()->private_data = fs->user_data;
    2201 if (!fs->op.getxattr)
    2202 return -ENOSYS;
    2203 if (fs->debug)
    2204 fuse_log(FUSE_LOG_DEBUG, "getxattr %s %s %lu\n",
    2205 path, name, (unsigned long) size);
    2206
    2207 return fs->op.getxattr(path, name, value, size);
    2208}
    2209
    2210int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
    2211 size_t size)
    2212{
    2213 fuse_get_context()->private_data = fs->user_data;
    2214 if (!fs->op.listxattr)
    2215 return -ENOSYS;
    2216 if (fs->debug)
    2217 fuse_log(FUSE_LOG_DEBUG, "listxattr %s %lu\n",
    2218 path, (unsigned long) size);
    2219
    2220 return fs->op.listxattr(path, list, size);
    2221}
    2222
    2223int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
    2224 uint64_t *idx)
    2225{
    2226 fuse_get_context()->private_data = fs->user_data;
    2227 if (!fs->op.bmap)
    2228 return -ENOSYS;
    2229 if (fs->debug)
    2230 fuse_log(FUSE_LOG_DEBUG, "bmap %s blocksize: %lu index: %llu\n",
    2231 path, (unsigned long) blocksize,
    2232 (unsigned long long) *idx);
    2233
    2234 return fs->op.bmap(path, blocksize, idx);
    2235}
    2236
    2237int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
    2238{
    2239 fuse_get_context()->private_data = fs->user_data;
    2240 if (!fs->op.removexattr)
    2241 return -ENOSYS;
    2242 if (fs->debug)
    2243 fuse_log(FUSE_LOG_DEBUG, "removexattr %s %s\n", path, name);
    2244
    2245 return fs->op.removexattr(path, name);
    2246}
    2247
    2248int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd,
    2249 void *arg, struct fuse_file_info *fi, unsigned int flags,
    2250 void *data)
    2251{
    2252 fuse_get_context()->private_data = fs->user_data;
    2253 if (!fs->op.ioctl)
    2254 return -ENOSYS;
    2255 if (fs->debug)
    2256 fuse_log(FUSE_LOG_DEBUG, "ioctl[%llu] 0x%x flags: 0x%x\n",
    2257 (unsigned long long) fi->fh, cmd, flags);
    2258
    2259 return fs->op.ioctl(path, cmd, arg, fi, flags, data);
    2260}
    2261
    2262int fuse_fs_poll(struct fuse_fs *fs, const char *path,
    2263 struct fuse_file_info *fi, struct fuse_pollhandle *ph,
    2264 unsigned *reventsp)
    2265{
    2266 int res;
    2267
    2268 fuse_get_context()->private_data = fs->user_data;
    2269
    2270 if (!fs->op.poll) {
    2272 return -ENOSYS;
    2273 }
    2274
    2275 if (fs->debug)
    2276 fuse_log(FUSE_LOG_DEBUG, "poll[%llu] ph: %p, events 0x%x\n",
    2277 (unsigned long long) fi->fh, ph,
    2278 fi->poll_events);
    2279
    2280 res = fs->op.poll(path, fi, ph, reventsp);
    2281
    2282 if (fs->debug && !res)
    2283 fuse_log(FUSE_LOG_DEBUG, " poll[%llu] revents: 0x%x\n",
    2284 (unsigned long long) fi->fh, *reventsp);
    2285
    2286 return res;
    2287}
    2288
    2289int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode,
    2290 off_t offset, off_t length, struct fuse_file_info *fi)
    2291{
    2292 fuse_get_context()->private_data = fs->user_data;
    2293 if (!fs->op.fallocate)
    2294 return -ENOSYS;
    2295 if (fs->debug)
    2296 fuse_log(FUSE_LOG_DEBUG, "fallocate %s mode %x, offset: %llu, length: %llu\n",
    2297 path,
    2298 mode,
    2299 (unsigned long long) offset,
    2300 (unsigned long long) length);
    2301
    2302 return fs->op.fallocate(path, mode, offset, length, fi);
    2303}
    2304
    2305ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, const char *path_in,
    2306 struct fuse_file_info *fi_in, off_t off_in,
    2307 const char *path_out,
    2308 struct fuse_file_info *fi_out, off_t off_out,
    2309 size_t len, int flags)
    2310{
    2311 fuse_get_context()->private_data = fs->user_data;
    2312 if (!fs->op.copy_file_range)
    2313 return -ENOSYS;
    2314 if (fs->debug)
    2315 fuse_log(FUSE_LOG_DEBUG, "copy_file_range from %s:%llu to "
    2316 "%s:%llu, length: %llu\n",
    2317 path_in,
    2318 (unsigned long long) off_in,
    2319 path_out,
    2320 (unsigned long long) off_out,
    2321 (unsigned long long) len);
    2322
    2323 return fs->op.copy_file_range(path_in, fi_in, off_in, path_out,
    2324 fi_out, off_out, len, flags);
    2325}
    2326
    2327off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence,
    2328 struct fuse_file_info *fi)
    2329{
    2330 fuse_get_context()->private_data = fs->user_data;
    2331 if (!fs->op.lseek)
    2332 return -ENOSYS;
    2333 if (fs->debug) {
    2334 char buf[10];
    2335
    2336 fuse_log(FUSE_LOG_DEBUG, "lseek[%s] %llu %d\n",
    2337 file_info_string(fi, buf, sizeof(buf)),
    2338 (unsigned long long) off, whence);
    2339 }
    2340 return fs->op.lseek(path, off, whence, fi);
    2341}
    2342
    2343#ifdef HAVE_STATX
    2344int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask,
    2345 struct statx *stxbuf, struct fuse_file_info *fi)
    2346{
    2347 fuse_get_context()->private_data = fs->user_data;
    2348 if (fs->op.statx) {
    2349 if (fs->debug) {
    2350 char buf[10];
    2351
    2352 fuse_log(FUSE_LOG_DEBUG, "statx[%s] %s %d %d\n",
    2353 file_info_string(fi, buf, sizeof(buf)), path,
    2354 flags, mask);
    2355 }
    2356 return fs->op.statx(path, flags, mask, stxbuf, fi);
    2357 }
    2358
    2359 return -ENOSYS;
    2360}
    2361#else
    2362int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask,
    2363 struct statx *stxbuf, struct fuse_file_info *fi)
    2364{
    2365 (void)fs;
    2366 (void)path;
    2367 (void)flags;
    2368 (void)mask;
    2369 (void)stxbuf;
    2370 (void)fi;
    2371
    2372 return -ENOSYS;
    2373}
    2374#endif
    2375
    2376static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
    2377{
    2378 struct node *node;
    2379 int isopen = 0;
    2380 pthread_mutex_lock(&f->lock);
    2381 node = lookup_node(f, dir, name);
    2382 if (node && node->open_count > 0)
    2383 isopen = 1;
    2384 pthread_mutex_unlock(&f->lock);
    2385 return isopen;
    2386}
    2387
    2388static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
    2389 char *newname, size_t bufsize)
    2390{
    2391 struct stat buf;
    2392 struct node *node;
    2393 struct node *newnode;
    2394 char *newpath;
    2395 int res;
    2396 int failctr = 10;
    2397
    2398 do {
    2399 pthread_mutex_lock(&f->lock);
    2400 node = lookup_node(f, dir, oldname);
    2401 if (node == NULL) {
    2402 pthread_mutex_unlock(&f->lock);
    2403 return NULL;
    2404 }
    2405 do {
    2406 f->hidectr ++;
    2407 snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
    2408 (unsigned int) node->nodeid, f->hidectr);
    2409 newnode = lookup_node(f, dir, newname);
    2410 } while(newnode);
    2411
    2412 res = try_get_path(f, dir, newname, &newpath, NULL, false);
    2413 pthread_mutex_unlock(&f->lock);
    2414 if (res)
    2415 break;
    2416
    2417 memset(&buf, 0, sizeof(buf));
    2418 res = fuse_fs_getattr(f->fs, newpath, &buf, NULL);
    2419 if (res == -ENOENT)
    2420 break;
    2421 free(newpath);
    2422 newpath = NULL;
    2423 } while(res == 0 && --failctr);
    2424
    2425 return newpath;
    2426}
    2427
    2428static int hide_node(struct fuse *f, const char *oldpath,
    2429 fuse_ino_t dir, const char *oldname)
    2430{
    2431 char newname[64];
    2432 char *newpath;
    2433 int err = -EBUSY;
    2434
    2435 newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
    2436 if (newpath) {
    2437 err = fuse_fs_rename(f->fs, oldpath, newpath, 0);
    2438 if (!err)
    2439 err = rename_node(f, dir, oldname, dir, newname, 1);
    2440 free(newpath);
    2441 }
    2442 return err;
    2443}
    2444
    2445static int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
    2446{
    2447 return stbuf->st_mtime == ts->tv_sec &&
    2448 ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
    2449}
    2450
    2451#ifndef CLOCK_MONOTONIC
    2452#define CLOCK_MONOTONIC CLOCK_REALTIME
    2453#endif
    2454
    2455static void curr_time(struct timespec *now)
    2456{
    2457 static clockid_t clockid = CLOCK_MONOTONIC;
    2458 int res = clock_gettime(clockid, now);
    2459 if (res == -1 && errno == EINVAL) {
    2460 clockid = CLOCK_REALTIME;
    2461 res = clock_gettime(clockid, now);
    2462 }
    2463 if (res == -1) {
    2464 perror("fuse: clock_gettime");
    2465 abort();
    2466 }
    2467}
    2468
    2469static void update_stat(struct node *node, const struct stat *stbuf)
    2470{
    2471 if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
    2472 stbuf->st_size != node->size))
    2473 node->cache_valid = 0;
    2474 node->mtime.tv_sec = stbuf->st_mtime;
    2475 node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
    2476 node->size = stbuf->st_size;
    2477 curr_time(&node->stat_updated);
    2478}
    2479
    2480static int do_lookup(struct fuse *f, fuse_ino_t nodeid, const char *name,
    2481 struct fuse_entry_param *e)
    2482{
    2483 struct node *node;
    2484
    2485 node = find_node(f, nodeid, name);
    2486 if (node == NULL)
    2487 return -ENOMEM;
    2488
    2489 e->ino = node->nodeid;
    2490 e->generation = node->generation;
    2491 e->entry_timeout = f->conf.entry_timeout;
    2492 e->attr_timeout = f->conf.attr_timeout;
    2493 if (f->conf.auto_cache) {
    2494 pthread_mutex_lock(&f->lock);
    2495 update_stat(node, &e->attr);
    2496 pthread_mutex_unlock(&f->lock);
    2497 }
    2498 set_stat(f, e->ino, &e->attr);
    2499 return 0;
    2500}
    2501
    2502static int lookup_path(struct fuse *f, fuse_ino_t nodeid,
    2503 const char *name, const char *path,
    2504 struct fuse_entry_param *e, struct fuse_file_info *fi)
    2505{
    2506 int res;
    2507
    2508 memset(e, 0, sizeof(struct fuse_entry_param));
    2509 res = fuse_fs_getattr(f->fs, path, &e->attr, fi);
    2510 if (res == 0) {
    2511 res = do_lookup(f, nodeid, name, e);
    2512 if (res == 0 && f->conf.debug) {
    2513 fuse_log(FUSE_LOG_DEBUG, " NODEID: %llu\n",
    2514 (unsigned long long) e->ino);
    2515 }
    2516 }
    2517 return res;
    2518}
    2519
    2520static struct fuse_context_i *fuse_get_context_internal(void)
    2521{
    2522 return (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
    2523}
    2524
    2525static struct fuse_context_i *fuse_create_context(struct fuse *f)
    2526{
    2527 struct fuse_context_i *c = fuse_get_context_internal();
    2528 if (c == NULL) {
    2529 c = (struct fuse_context_i *)
    2530 calloc(1, sizeof(struct fuse_context_i));
    2531 if (c == NULL) {
    2532 /* This is hard to deal with properly, so just
    2533 abort. If memory is so low that the
    2534 context cannot be allocated, there's not
    2535 much hope for the filesystem anyway */
    2536 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate thread specific data\n");
    2537 abort();
    2538 }
    2539 if (pthread_setspecific(fuse_context_key, c) != 0) {
    2540 fuse_log(FUSE_LOG_ERR, "fuse: failed to set thread specific data\n");
    2541 free(c);
    2542 abort();
    2543 }
    2544 } else {
    2545 memset(c, 0, sizeof(*c));
    2546 }
    2547 c->ctx.fuse = f;
    2548
    2549 return c;
    2550}
    2551
    2552static void fuse_freecontext(void *data)
    2553{
    2554 free(data);
    2555}
    2556
    2557static int fuse_create_context_key(void)
    2558{
    2559 int err = 0;
    2560 pthread_mutex_lock(&fuse_context_lock);
    2561 if (!fuse_context_ref) {
    2562 err = pthread_key_create(&fuse_context_key, fuse_freecontext);
    2563 if (err) {
    2564 fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
    2565 strerror(err));
    2566 pthread_mutex_unlock(&fuse_context_lock);
    2567 return -1;
    2568 }
    2569 }
    2570 fuse_context_ref++;
    2571 pthread_mutex_unlock(&fuse_context_lock);
    2572 return 0;
    2573}
    2574
    2575static void fuse_delete_context_key(void)
    2576{
    2577 pthread_mutex_lock(&fuse_context_lock);
    2578 fuse_context_ref--;
    2579 if (!fuse_context_ref) {
    2580 free(pthread_getspecific(fuse_context_key));
    2581 pthread_key_delete(fuse_context_key);
    2582 }
    2583 pthread_mutex_unlock(&fuse_context_lock);
    2584}
    2585
    2586static struct fuse *req_fuse_prepare(fuse_req_t req)
    2587{
    2588 struct fuse_context_i *c = fuse_create_context(req_fuse(req));
    2589 const struct fuse_ctx *ctx = fuse_req_ctx(req);
    2590 c->req = req;
    2591 c->ctx.uid = ctx->uid;
    2592 c->ctx.gid = ctx->gid;
    2593 c->ctx.pid = ctx->pid;
    2594 c->ctx.umask = ctx->umask;
    2595 return c->ctx.fuse;
    2596}
    2597
    2598static inline void reply_err(fuse_req_t req, int err)
    2599{
    2600 /* fuse_reply_err() uses non-negated errno values */
    2601 fuse_reply_err(req, -err);
    2602}
    2603
    2604static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
    2605 int err)
    2606{
    2607 if (!err) {
    2608 struct fuse *f = req_fuse(req);
    2609 if (fuse_reply_entry(req, e) == -ENOENT) {
    2610 /* Skip forget for negative result */
    2611 if (e->ino != 0)
    2612 forget_node(f, e->ino, 1);
    2613 }
    2614 } else
    2615 reply_err(req, err);
    2616}
    2617
    2618void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn,
    2619 struct fuse_config *cfg)
    2620{
    2621 fuse_get_context()->private_data = fs->user_data;
    2622 if (!fs->op.write_buf)
    2624 if (!fs->op.lock)
    2626 if (!fs->op.flock)
    2628 if (fs->op.init)
    2629 fs->user_data = fs->op.init(conn, cfg);
    2630}
    2631
    2632static int fuse_init_intr_signal(int signum, int *installed);
    2633
    2634static void fuse_lib_init(void *data, struct fuse_conn_info *conn)
    2635{
    2636 struct fuse *f = (struct fuse *) data;
    2637
    2638 fuse_create_context(f);
    2640 fuse_fs_init(f->fs, conn, &f->conf);
    2641
    2642 if (f->conf.intr) {
    2643 if (fuse_init_intr_signal(f->conf.intr_signal,
    2644 &f->intr_installed) == -1)
    2645 fuse_log(FUSE_LOG_ERR, "fuse: failed to init interrupt signal\n");
    2646 } else {
    2647 /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    2648 conn->no_interrupt = 1;
    2649 }
    2650}
    2651
    2652void fuse_fs_destroy(struct fuse_fs *fs)
    2653{
    2654 fuse_get_context()->private_data = fs->user_data;
    2655 if (fs->op.destroy)
    2656 fs->op.destroy(fs->user_data);
    2657}
    2658
    2659static void fuse_lib_destroy(void *data)
    2660{
    2661 struct fuse *f = (struct fuse *) data;
    2662
    2663 fuse_create_context(f);
    2664 fuse_fs_destroy(f->fs);
    2665}
    2666
    2667static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
    2668 const char *name)
    2669{
    2670 struct fuse *f = req_fuse_prepare(req);
    2671 struct fuse_entry_param e = { .ino = 0 }; /* invalid ino */
    2672 char *path;
    2673 int err;
    2674 struct node *dot = NULL;
    2675
    2676 if (name[0] == '.') {
    2677 int len = strlen(name);
    2678
    2679 if (len == 1 || (name[1] == '.' && len == 2)) {
    2680 pthread_mutex_lock(&f->lock);
    2681 if (len == 1) {
    2682 if (f->conf.debug)
    2683 fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOT\n");
    2684 dot = get_node_nocheck(f, parent);
    2685 if (dot == NULL) {
    2686 pthread_mutex_unlock(&f->lock);
    2687 reply_entry(req, &e, -ESTALE);
    2688 return;
    2689 }
    2690 dot->refctr++;
    2691 } else {
    2692 if (f->conf.debug)
    2693 fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOTDOT\n");
    2694 parent = get_node(f, parent)->parent->nodeid;
    2695 }
    2696 pthread_mutex_unlock(&f->lock);
    2697 name = NULL;
    2698 }
    2699 }
    2700
    2701 err = get_path_name(f, parent, name, &path);
    2702 if (!err) {
    2703 struct fuse_intr_data d;
    2704 if (f->conf.debug)
    2705 fuse_log(FUSE_LOG_DEBUG, "LOOKUP %s\n", path);
    2706 fuse_prepare_interrupt(f, req, &d);
    2707 err = lookup_path(f, parent, name, path, &e, NULL);
    2708 if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
    2709 e.ino = 0;
    2710 e.entry_timeout = f->conf.negative_timeout;
    2711 err = 0;
    2712 }
    2713 fuse_finish_interrupt(f, req, &d);
    2714 free_path(f, parent, path);
    2715 }
    2716 if (dot) {
    2717 pthread_mutex_lock(&f->lock);
    2718 unref_node(f, dot);
    2719 pthread_mutex_unlock(&f->lock);
    2720 }
    2721 reply_entry(req, &e, err);
    2722}
    2723
    2724static void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup)
    2725{
    2726 if (f->conf.debug)
    2727 fuse_log(FUSE_LOG_DEBUG, "FORGET %llu/%llu\n", (unsigned long long)ino,
    2728 (unsigned long long) nlookup);
    2729 forget_node(f, ino, nlookup);
    2730}
    2731
    2732static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    2733{
    2734 do_forget(req_fuse(req), ino, nlookup);
    2735 fuse_reply_none(req);
    2736}
    2737
    2738static void fuse_lib_forget_multi(fuse_req_t req, size_t count,
    2739 struct fuse_forget_data *forgets)
    2740{
    2741 struct fuse *f = req_fuse(req);
    2742 size_t i;
    2743
    2744 for (i = 0; i < count; i++)
    2745 do_forget(f, forgets[i].ino, forgets[i].nlookup);
    2746
    2747 fuse_reply_none(req);
    2748}
    2749
    2750
    2751static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
    2752 struct fuse_file_info *fi)
    2753{
    2754 struct fuse *f = req_fuse_prepare(req);
    2755 struct stat buf;
    2756 char *path;
    2757 int err;
    2758
    2759 memset(&buf, 0, sizeof(buf));
    2760
    2761 if (fi != NULL)
    2762 err = get_path_nullok(f, ino, &path);
    2763 else
    2764 err = get_path(f, ino, &path);
    2765 if (!err) {
    2766 struct fuse_intr_data d;
    2767 fuse_prepare_interrupt(f, req, &d);
    2768 err = fuse_fs_getattr(f->fs, path, &buf, fi);
    2769 fuse_finish_interrupt(f, req, &d);
    2770 free_path(f, ino, path);
    2771 }
    2772 if (!err) {
    2773 struct node *node;
    2774
    2775 pthread_mutex_lock(&f->lock);
    2776 node = get_node(f, ino);
    2777 if (node->is_hidden && buf.st_nlink > 0)
    2778 buf.st_nlink--;
    2779 if (f->conf.auto_cache)
    2780 update_stat(node, &buf);
    2781 pthread_mutex_unlock(&f->lock);
    2782 set_stat(f, ino, &buf);
    2783 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
    2784 } else
    2785 reply_err(req, err);
    2786}
    2787
    2788int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode,
    2789 struct fuse_file_info *fi)
    2790{
    2791 fuse_get_context()->private_data = fs->user_data;
    2792 if (!fs->op.chmod)
    2793 return -ENOSYS;
    2794
    2795 if (fs->debug) {
    2796 char buf[10];
    2797
    2798 fuse_log(FUSE_LOG_DEBUG, "chmod[%s] %s %llo\n",
    2799 file_info_string(fi, buf, sizeof(buf)),
    2800 path, (unsigned long long) mode);
    2801 }
    2802 return fs->op.chmod(path, mode, fi);
    2803}
    2804
    2805static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
    2806 int valid, struct fuse_file_info *fi)
    2807{
    2808 struct fuse *f = req_fuse_prepare(req);
    2809 struct stat buf;
    2810 char *path;
    2811 int err;
    2812
    2813 memset(&buf, 0, sizeof(buf));
    2814 if (fi != NULL)
    2815 err = get_path_nullok(f, ino, &path);
    2816 else
    2817 err = get_path(f, ino, &path);
    2818 if (!err) {
    2819 struct fuse_intr_data d;
    2820 fuse_prepare_interrupt(f, req, &d);
    2821 err = 0;
    2822 if (!err && (valid & FUSE_SET_ATTR_MODE))
    2823 err = fuse_fs_chmod(f->fs, path, attr->st_mode, fi);
    2824 if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
    2825 uid_t uid = (valid & FUSE_SET_ATTR_UID) ?
    2826 attr->st_uid : (uid_t) -1;
    2827 gid_t gid = (valid & FUSE_SET_ATTR_GID) ?
    2828 attr->st_gid : (gid_t) -1;
    2829 err = fuse_fs_chown(f->fs, path, uid, gid, fi);
    2830 }
    2831 if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
    2832 err = fuse_fs_truncate(f->fs, path,
    2833 attr->st_size, fi);
    2834 }
    2835#ifdef HAVE_UTIMENSAT
    2836 if (!err &&
    2837 (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
    2838 struct timespec tv[2];
    2839
    2840 tv[0].tv_sec = 0;
    2841 tv[1].tv_sec = 0;
    2842 tv[0].tv_nsec = UTIME_OMIT;
    2843 tv[1].tv_nsec = UTIME_OMIT;
    2844
    2845 if (valid & FUSE_SET_ATTR_ATIME_NOW)
    2846 tv[0].tv_nsec = UTIME_NOW;
    2847 else if (valid & FUSE_SET_ATTR_ATIME)
    2848 tv[0] = attr->st_atim;
    2849
    2850 if (valid & FUSE_SET_ATTR_MTIME_NOW)
    2851 tv[1].tv_nsec = UTIME_NOW;
    2852 else if (valid & FUSE_SET_ATTR_MTIME)
    2853 tv[1] = attr->st_mtim;
    2854
    2855 err = fuse_fs_utimens(f->fs, path, tv, fi);
    2856 } else
    2857#endif
    2858 if (!err &&
    2859 (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
    2860 (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
    2861 struct timespec tv[2];
    2862 tv[0].tv_sec = attr->st_atime;
    2863 tv[0].tv_nsec = ST_ATIM_NSEC(attr);
    2864 tv[1].tv_sec = attr->st_mtime;
    2865 tv[1].tv_nsec = ST_MTIM_NSEC(attr);
    2866 err = fuse_fs_utimens(f->fs, path, tv, fi);
    2867 }
    2868 if (!err) {
    2869 err = fuse_fs_getattr(f->fs, path, &buf, fi);
    2870 }
    2871 fuse_finish_interrupt(f, req, &d);
    2872 free_path(f, ino, path);
    2873 }
    2874 if (!err) {
    2875 if (f->conf.auto_cache) {
    2876 pthread_mutex_lock(&f->lock);
    2877 update_stat(get_node(f, ino), &buf);
    2878 pthread_mutex_unlock(&f->lock);
    2879 }
    2880 set_stat(f, ino, &buf);
    2881 fuse_reply_attr(req, &buf, f->conf.attr_timeout);
    2882 } else
    2883 reply_err(req, err);
    2884}
    2885
    2886static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
    2887{
    2888 struct fuse *f = req_fuse_prepare(req);
    2889 char *path;
    2890 int err;
    2891
    2892 err = get_path(f, ino, &path);
    2893 if (!err) {
    2894 struct fuse_intr_data d;
    2895
    2896 fuse_prepare_interrupt(f, req, &d);
    2897 err = fuse_fs_access(f->fs, path, mask);
    2898 fuse_finish_interrupt(f, req, &d);
    2899 free_path(f, ino, path);
    2900 }
    2901 reply_err(req, err);
    2902}
    2903
    2904static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
    2905{
    2906 struct fuse *f = req_fuse_prepare(req);
    2907 char linkname[PATH_MAX + 1];
    2908 char *path;
    2909 int err;
    2910
    2911 err = get_path(f, ino, &path);
    2912 if (!err) {
    2913 struct fuse_intr_data d;
    2914 fuse_prepare_interrupt(f, req, &d);
    2915 err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
    2916 fuse_finish_interrupt(f, req, &d);
    2917 free_path(f, ino, path);
    2918 }
    2919 if (!err) {
    2920 linkname[PATH_MAX] = '\0';
    2921 fuse_reply_readlink(req, linkname);
    2922 } else
    2923 reply_err(req, err);
    2924}
    2925
    2926static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
    2927 mode_t mode, dev_t rdev)
    2928{
    2929 struct fuse *f = req_fuse_prepare(req);
    2930 struct fuse_entry_param e;
    2931 char *path;
    2932 int err;
    2933
    2934 err = get_path_name(f, parent, name, &path);
    2935 if (!err) {
    2936 struct fuse_intr_data d;
    2937
    2938 fuse_prepare_interrupt(f, req, &d);
    2939 err = -ENOSYS;
    2940 if (S_ISREG(mode)) {
    2941 struct fuse_file_info fi;
    2942
    2943 memset(&fi, 0, sizeof(fi));
    2944 fi.flags = O_CREAT | O_EXCL | O_WRONLY;
    2945 err = fuse_fs_create(f->fs, path, mode, &fi);
    2946 if (!err) {
    2947 err = lookup_path(f, parent, name, path, &e,
    2948 &fi);
    2949 fuse_fs_release(f->fs, path, &fi);
    2950 }
    2951 }
    2952 if (err == -ENOSYS) {
    2953 err = fuse_fs_mknod(f->fs, path, mode, rdev);
    2954 if (!err)
    2955 err = lookup_path(f, parent, name, path, &e,
    2956 NULL);
    2957 }
    2958 fuse_finish_interrupt(f, req, &d);
    2959 free_path(f, parent, path);
    2960 }
    2961 reply_entry(req, &e, err);
    2962}
    2963
    2964static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
    2965 mode_t mode)
    2966{
    2967 struct fuse *f = req_fuse_prepare(req);
    2968 struct fuse_entry_param e;
    2969 char *path;
    2970 int err;
    2971
    2972 err = get_path_name(f, parent, name, &path);
    2973 if (!err) {
    2974 struct fuse_intr_data d;
    2975
    2976 fuse_prepare_interrupt(f, req, &d);
    2977 err = fuse_fs_mkdir(f->fs, path, mode);
    2978 if (!err)
    2979 err = lookup_path(f, parent, name, path, &e, NULL);
    2980 fuse_finish_interrupt(f, req, &d);
    2981 free_path(f, parent, path);
    2982 }
    2983 reply_entry(req, &e, err);
    2984}
    2985
    2986static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
    2987 const char *name)
    2988{
    2989 struct fuse *f = req_fuse_prepare(req);
    2990 struct node *wnode;
    2991 char *path;
    2992 int err;
    2993
    2994 err = get_path_wrlock(f, parent, name, &path, &wnode);
    2995 if (!err) {
    2996 struct fuse_intr_data d;
    2997
    2998 fuse_prepare_interrupt(f, req, &d);
    2999 if (!f->conf.hard_remove && is_open(f, parent, name)) {
    3000 err = hide_node(f, path, parent, name);
    3001 if (!err) {
    3002 /* we have hidden the node so now check again under a lock in case it is not used any more */
    3003 if (!is_open(f, parent, wnode->name)) {
    3004 char *unlinkpath;
    3005
    3006 /* get the hidden file path, to unlink it */
    3007 if (try_get_path(f, wnode->nodeid, NULL, &unlinkpath, NULL, false) == 0) {
    3008 err = fuse_fs_unlink(f->fs, unlinkpath);
    3009 if (!err)
    3010 remove_node(f, parent, wnode->name);
    3011 free(unlinkpath);
    3012 }
    3013 }
    3014 }
    3015 } else {
    3016 err = fuse_fs_unlink(f->fs, path);
    3017 if (!err)
    3018 remove_node(f, parent, name);
    3019 }
    3020 fuse_finish_interrupt(f, req, &d);
    3021 free_path_wrlock(f, parent, wnode, path);
    3022 }
    3023 reply_err(req, err);
    3024}
    3025
    3026static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
    3027{
    3028 struct fuse *f = req_fuse_prepare(req);
    3029 struct node *wnode;
    3030 char *path;
    3031 int err;
    3032
    3033 err = get_path_wrlock(f, parent, name, &path, &wnode);
    3034 if (!err) {
    3035 struct fuse_intr_data d;
    3036
    3037 fuse_prepare_interrupt(f, req, &d);
    3038 err = fuse_fs_rmdir(f->fs, path);
    3039 fuse_finish_interrupt(f, req, &d);
    3040 if (!err)
    3041 remove_node(f, parent, name);
    3042 free_path_wrlock(f, parent, wnode, path);
    3043 }
    3044 reply_err(req, err);
    3045}
    3046
    3047static void fuse_lib_symlink(fuse_req_t req, const char *linkname,
    3048 fuse_ino_t parent, const char *name)
    3049{
    3050 struct fuse *f = req_fuse_prepare(req);
    3051 struct fuse_entry_param e;
    3052 char *path;
    3053 int err;
    3054
    3055 err = get_path_name(f, parent, name, &path);
    3056 if (!err) {
    3057 struct fuse_intr_data d;
    3058
    3059 fuse_prepare_interrupt(f, req, &d);
    3060 err = fuse_fs_symlink(f->fs, linkname, path);
    3061 if (!err)
    3062 err = lookup_path(f, parent, name, path, &e, NULL);
    3063 fuse_finish_interrupt(f, req, &d);
    3064 free_path(f, parent, path);
    3065 }
    3066 reply_entry(req, &e, err);
    3067}
    3068
    3069static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
    3070 const char *oldname, fuse_ino_t newdir,
    3071 const char *newname, unsigned int flags)
    3072{
    3073 struct fuse *f = req_fuse_prepare(req);
    3074 char *oldpath;
    3075 char *newpath;
    3076 struct node *wnode1;
    3077 struct node *wnode2;
    3078 int err;
    3079
    3080 err = get_path2(f, olddir, oldname, newdir, newname,
    3081 &oldpath, &newpath, &wnode1, &wnode2);
    3082 if (!err) {
    3083 struct fuse_intr_data d;
    3084 err = 0;
    3085 fuse_prepare_interrupt(f, req, &d);
    3086 if (!f->conf.hard_remove && !(flags & RENAME_EXCHANGE) &&
    3087 is_open(f, newdir, newname))
    3088 err = hide_node(f, newpath, newdir, newname);
    3089 if (!err) {
    3090 err = fuse_fs_rename(f->fs, oldpath, newpath, flags);
    3091 if (!err) {
    3092 if (flags & RENAME_EXCHANGE) {
    3093 err = exchange_node(f, olddir, oldname,
    3094 newdir, newname);
    3095 } else {
    3096 err = rename_node(f, olddir, oldname,
    3097 newdir, newname, 0);
    3098 }
    3099 }
    3100 }
    3101 fuse_finish_interrupt(f, req, &d);
    3102 free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath);
    3103 }
    3104 reply_err(req, err);
    3105}
    3106
    3107static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
    3108 const char *newname)
    3109{
    3110 struct fuse *f = req_fuse_prepare(req);
    3111 struct fuse_entry_param e;
    3112 char *oldpath;
    3113 char *newpath;
    3114 int err;
    3115
    3116 err = get_path2(f, ino, NULL, newparent, newname,
    3117 &oldpath, &newpath, NULL, NULL);
    3118 if (!err) {
    3119 struct fuse_intr_data d;
    3120
    3121 fuse_prepare_interrupt(f, req, &d);
    3122 err = fuse_fs_link(f->fs, oldpath, newpath);
    3123 if (!err)
    3124 err = lookup_path(f, newparent, newname, newpath,
    3125 &e, NULL);
    3126 fuse_finish_interrupt(f, req, &d);
    3127 free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath);
    3128 }
    3129 reply_entry(req, &e, err);
    3130}
    3131
    3132static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
    3133 struct fuse_file_info *fi)
    3134{
    3135 struct node *node;
    3136 int unlink_hidden = 0;
    3137
    3138 fuse_fs_release(f->fs, path, fi);
    3139
    3140 pthread_mutex_lock(&f->lock);
    3141 node = get_node(f, ino);
    3142 assert(node->open_count > 0);
    3143 --node->open_count;
    3144 if (node->is_hidden && !node->open_count) {
    3145 unlink_hidden = 1;
    3146 node->is_hidden = 0;
    3147 }
    3148 pthread_mutex_unlock(&f->lock);
    3149
    3150 if(unlink_hidden) {
    3151 if (path) {
    3152 fuse_fs_unlink(f->fs, path);
    3153 } else if (f->conf.nullpath_ok) {
    3154 char *unlinkpath;
    3155
    3156 if (get_path(f, ino, &unlinkpath) == 0)
    3157 fuse_fs_unlink(f->fs, unlinkpath);
    3158
    3159 free_path(f, ino, unlinkpath);
    3160 }
    3161 }
    3162}
    3163
    3164static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
    3165 const char *name, mode_t mode,
    3166 struct fuse_file_info *fi)
    3167{
    3168 struct fuse *f = req_fuse_prepare(req);
    3169 struct fuse_intr_data d;
    3170 struct fuse_entry_param e;
    3171 char *path;
    3172 int err;
    3173
    3174 err = get_path_name(f, parent, name, &path);
    3175 if (!err) {
    3176 fuse_prepare_interrupt(f, req, &d);
    3177 err = fuse_fs_create(f->fs, path, mode, fi);
    3178 if (!err) {
    3179 err = lookup_path(f, parent, name, path, &e, fi);
    3180 if (err)
    3181 fuse_fs_release(f->fs, path, fi);
    3182 else if (!S_ISREG(e.attr.st_mode)) {
    3183 err = -EIO;
    3184 fuse_fs_release(f->fs, path, fi);
    3185 forget_node(f, e.ino, 1);
    3186 } else {
    3187 if (f->conf.direct_io)
    3188 fi->direct_io = 1;
    3189 if (f->conf.kernel_cache)
    3190 fi->keep_cache = 1;
    3191 if (fi->direct_io &&
    3192 f->conf.parallel_direct_writes)
    3193 fi->parallel_direct_writes = 1;
    3194 }
    3195 }
    3196 fuse_finish_interrupt(f, req, &d);
    3197 }
    3198 if (!err) {
    3199 pthread_mutex_lock(&f->lock);
    3200 get_node(f, e.ino)->open_count++;
    3201 pthread_mutex_unlock(&f->lock);
    3202 if (fuse_reply_create(req, &e, fi) == -ENOENT) {
    3203 /* The open syscall was interrupted, so it
    3204 must be cancelled */
    3205 fuse_do_release(f, e.ino, path, fi);
    3206 forget_node(f, e.ino, 1);
    3207 }
    3208 } else {
    3209 reply_err(req, err);
    3210 }
    3211
    3212 free_path(f, parent, path);
    3213}
    3214
    3215static double diff_timespec(const struct timespec *t1,
    3216 const struct timespec *t2)
    3217{
    3218 return (t1->tv_sec - t2->tv_sec) +
    3219 ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
    3220}
    3221
    3222static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
    3223 struct fuse_file_info *fi)
    3224{
    3225 struct node *node;
    3226
    3227 pthread_mutex_lock(&f->lock);
    3228 node = get_node(f, ino);
    3229 if (node->cache_valid) {
    3230 struct timespec now;
    3231
    3232 curr_time(&now);
    3233 if (diff_timespec(&now, &node->stat_updated) >
    3234 f->conf.ac_attr_timeout) {
    3235 struct stat stbuf;
    3236 int err;
    3237 pthread_mutex_unlock(&f->lock);
    3238 err = fuse_fs_getattr(f->fs, path, &stbuf, fi);
    3239 pthread_mutex_lock(&f->lock);
    3240 if (!err)
    3241 update_stat(node, &stbuf);
    3242 else
    3243 node->cache_valid = 0;
    3244 }
    3245 }
    3246 if (node->cache_valid)
    3247 fi->keep_cache = 1;
    3248
    3249 node->cache_valid = 1;
    3250 pthread_mutex_unlock(&f->lock);
    3251}
    3252
    3253static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
    3254 struct fuse_file_info *fi)
    3255{
    3256 struct fuse *f = req_fuse_prepare(req);
    3257 struct fuse_intr_data d;
    3258 char *path;
    3259 int err;
    3260
    3261 err = get_path(f, ino, &path);
    3262 if (!err) {
    3263 fuse_prepare_interrupt(f, req, &d);
    3264 err = fuse_fs_open(f->fs, path, fi);
    3265 if (!err) {
    3266 if (f->conf.direct_io)
    3267 fi->direct_io = 1;
    3268 if (f->conf.kernel_cache)
    3269 fi->keep_cache = 1;
    3270
    3271 if (f->conf.auto_cache)
    3272 open_auto_cache(f, ino, path, fi);
    3273
    3274 if (f->conf.no_rofd_flush &&
    3275 (fi->flags & O_ACCMODE) == O_RDONLY)
    3276 fi->noflush = 1;
    3277
    3278 if (fi->direct_io && f->conf.parallel_direct_writes)
    3279 fi->parallel_direct_writes = 1;
    3280
    3281 }
    3282 fuse_finish_interrupt(f, req, &d);
    3283 }
    3284 if (!err) {
    3285 pthread_mutex_lock(&f->lock);
    3286 get_node(f, ino)->open_count++;
    3287 pthread_mutex_unlock(&f->lock);
    3288 if (fuse_reply_open(req, fi) == -ENOENT) {
    3289 /* The open syscall was interrupted, so it
    3290 must be cancelled */
    3291 fuse_do_release(f, ino, path, fi);
    3292 }
    3293 } else
    3294 reply_err(req, err);
    3295
    3296 free_path(f, ino, path);
    3297}
    3298
    3299static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
    3300 off_t off, struct fuse_file_info *fi)
    3301{
    3302 struct fuse *f = req_fuse_prepare(req);
    3303 struct fuse_bufvec *buf = NULL;
    3304 char *path;
    3305 int res;
    3306
    3307 res = get_path_nullok(f, ino, &path);
    3308 if (res == 0) {
    3309 struct fuse_intr_data d;
    3310
    3311 fuse_prepare_interrupt(f, req, &d);
    3312 res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi);
    3313 fuse_finish_interrupt(f, req, &d);
    3314 free_path(f, ino, path);
    3315 }
    3316
    3317 if (res == 0)
    3319 else
    3320 reply_err(req, res);
    3321
    3322 fuse_free_buf(buf);
    3323}
    3324
    3325static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino,
    3326 struct fuse_bufvec *buf, off_t off,
    3327 struct fuse_file_info *fi)
    3328{
    3329 struct fuse *f = req_fuse_prepare(req);
    3330 char *path;
    3331 int res;
    3332
    3333 res = get_path_nullok(f, ino, &path);
    3334 if (res == 0) {
    3335 struct fuse_intr_data d;
    3336
    3337 fuse_prepare_interrupt(f, req, &d);
    3338 res = fuse_fs_write_buf(f->fs, path, buf, off, fi);
    3339 fuse_finish_interrupt(f, req, &d);
    3340 free_path(f, ino, path);
    3341 }
    3342
    3343 if (res >= 0)
    3344 fuse_reply_write(req, res);
    3345 else
    3346 reply_err(req, res);
    3347}
    3348
    3349static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
    3350 struct fuse_file_info *fi)
    3351{
    3352 struct fuse *f = req_fuse_prepare(req);
    3353 char *path;
    3354 int err;
    3355
    3356 err = get_path_nullok(f, ino, &path);
    3357 if (!err) {
    3358 struct fuse_intr_data d;
    3359
    3360 fuse_prepare_interrupt(f, req, &d);
    3361 err = fuse_fs_fsync(f->fs, path, datasync, fi);
    3362 fuse_finish_interrupt(f, req, &d);
    3363 free_path(f, ino, path);
    3364 }
    3365 reply_err(req, err);
    3366}
    3367
    3368static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
    3369 struct fuse_file_info *fi)
    3370{
    3371 struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
    3372 memset(fi, 0, sizeof(struct fuse_file_info));
    3373 fi->fh = dh->fh;
    3374 return dh;
    3375}
    3376
    3377static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
    3378 struct fuse_file_info *llfi)
    3379{
    3380 struct fuse *f = req_fuse_prepare(req);
    3381 struct fuse_intr_data d;
    3382 struct fuse_dh *dh;
    3383 struct fuse_file_info fi;
    3384 char *path;
    3385 int err;
    3386
    3387 dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
    3388 if (dh == NULL) {
    3389 reply_err(req, -ENOMEM);
    3390 return;
    3391 }
    3392 memset(dh, 0, sizeof(struct fuse_dh));
    3393 dh->fuse = f;
    3394 dh->contents = NULL;
    3395 dh->first = NULL;
    3396 dh->len = 0;
    3397 dh->filled = 0;
    3398 dh->nodeid = ino;
    3399 pthread_mutex_init(&dh->lock, NULL);
    3400
    3401 llfi->fh = (uintptr_t) dh;
    3402
    3403 memset(&fi, 0, sizeof(fi));
    3404 fi.flags = llfi->flags;
    3405
    3406 err = get_path(f, ino, &path);
    3407 if (!err) {
    3408 fuse_prepare_interrupt(f, req, &d);
    3409 err = fuse_fs_opendir(f->fs, path, &fi);
    3410 fuse_finish_interrupt(f, req, &d);
    3411 dh->fh = fi.fh;
    3412 llfi->cache_readdir = fi.cache_readdir;
    3413 llfi->keep_cache = fi.keep_cache;
    3414 }
    3415 if (!err) {
    3416 if (fuse_reply_open(req, llfi) == -ENOENT) {
    3417 /* The opendir syscall was interrupted, so it
    3418 must be cancelled */
    3419 fuse_fs_releasedir(f->fs, path, &fi);
    3420 pthread_mutex_destroy(&dh->lock);
    3421 free(dh);
    3422 }
    3423 } else {
    3424 reply_err(req, err);
    3425 pthread_mutex_destroy(&dh->lock);
    3426 free(dh);
    3427 }
    3428 free_path(f, ino, path);
    3429}
    3430
    3431static int extend_contents(struct fuse_dh *dh, unsigned minsize)
    3432{
    3433 if (minsize > dh->size) {
    3434 char *newptr;
    3435 unsigned newsize = dh->size;
    3436 if (!newsize)
    3437 newsize = 1024;
    3438 while (newsize < minsize) {
    3439 if (newsize >= 0x80000000)
    3440 newsize = 0xffffffff;
    3441 else
    3442 newsize *= 2;
    3443 }
    3444
    3445 newptr = (char *) realloc(dh->contents, newsize);
    3446 if (!newptr) {
    3447 dh->error = -ENOMEM;
    3448 return -1;
    3449 }
    3450 dh->contents = newptr;
    3451 dh->size = newsize;
    3452 }
    3453 return 0;
    3454}
    3455
    3456static int fuse_add_direntry_to_dh(struct fuse_dh *dh, const char *name,
    3457 struct stat *st, enum fuse_fill_dir_flags flags)
    3458{
    3459 struct fuse_direntry *de;
    3460
    3461 de = malloc(sizeof(struct fuse_direntry));
    3462 if (!de) {
    3463 dh->error = -ENOMEM;
    3464 return -1;
    3465 }
    3466 de->name = strdup(name);
    3467 if (!de->name) {
    3468 dh->error = -ENOMEM;
    3469 free(de);
    3470 return -1;
    3471 }
    3472 de->flags = flags;
    3473 de->stat = *st;
    3474 de->next = NULL;
    3475
    3476 *dh->last = de;
    3477 dh->last = &de->next;
    3478
    3479 return 0;
    3480}
    3481
    3482static fuse_ino_t lookup_nodeid(struct fuse *f, fuse_ino_t parent,
    3483 const char *name)
    3484{
    3485 struct node *node;
    3486 fuse_ino_t res = FUSE_UNKNOWN_INO;
    3487
    3488 pthread_mutex_lock(&f->lock);
    3489 node = lookup_node(f, parent, name);
    3490 if (node)
    3491 res = node->nodeid;
    3492 pthread_mutex_unlock(&f->lock);
    3493
    3494 return res;
    3495}
    3496
    3497static int fill_dir(void *dh_, const char *name, const struct stat *statp,
    3498 off_t off, enum fuse_fill_dir_flags flags)
    3499{
    3500 struct fuse_dh *dh = (struct fuse_dh *) dh_;
    3501 struct stat stbuf;
    3502
    3503 if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) {
    3504 dh->error = -EIO;
    3505 return 1;
    3506 }
    3507
    3508 if (statp)
    3509 stbuf = *statp;
    3510 else {
    3511 memset(&stbuf, 0, sizeof(stbuf));
    3512 stbuf.st_ino = FUSE_UNKNOWN_INO;
    3513 }
    3514
    3515 if (!dh->fuse->conf.use_ino) {
    3516 stbuf.st_ino = FUSE_UNKNOWN_INO;
    3517 if (dh->fuse->conf.readdir_ino) {
    3518 stbuf.st_ino = (ino_t)
    3519 lookup_nodeid(dh->fuse, dh->nodeid, name);
    3520 }
    3521 }
    3522
    3523 if (off) {
    3524 size_t newlen;
    3525
    3526 if (dh->filled) {
    3527 dh->error = -EIO;
    3528 return 1;
    3529 }
    3530
    3531 if (dh->first) {
    3532 dh->error = -EIO;
    3533 return 1;
    3534 }
    3535
    3536 if (extend_contents(dh, dh->needlen) == -1)
    3537 return 1;
    3538
    3539 newlen = dh->len +
    3540 fuse_add_direntry(dh->req, dh->contents + dh->len,
    3541 dh->needlen - dh->len, name,
    3542 &stbuf, off);
    3543 if (newlen > dh->needlen)
    3544 return 1;
    3545
    3546 dh->len = newlen;
    3547 } else {
    3548 dh->filled = 1;
    3549
    3550 if (fuse_add_direntry_to_dh(dh, name, &stbuf, flags) == -1)
    3551 return 1;
    3552 }
    3553 return 0;
    3554}
    3555
    3556static int is_dot_or_dotdot(const char *name)
    3557{
    3558 return name[0] == '.' && (name[1] == '\0' ||
    3559 (name[1] == '.' && name[2] == '\0'));
    3560}
    3561
    3562static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp,
    3563 off_t off, enum fuse_fill_dir_flags flags)
    3564{
    3565 struct fuse_dh *dh = (struct fuse_dh *) dh_;
    3566 struct fuse_entry_param e = {
    3567 /* ino=0 tells the kernel to ignore readdirplus stat info */
    3568 .ino = 0,
    3569 };
    3570 struct fuse *f = dh->fuse;
    3571 int res;
    3572
    3573 if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) {
    3574 dh->error = -EIO;
    3575 return 1;
    3576 }
    3577
    3578 if (statp && (flags & FUSE_FILL_DIR_PLUS)) {
    3579 e.attr = *statp;
    3580 }
    3581
    3582 e.attr.st_ino = FUSE_UNKNOWN_INO;
    3583 if (statp) {
    3584 e.attr.st_mode = statp->st_mode;
    3585 if (f->conf.use_ino)
    3586 e.attr.st_ino = statp->st_ino;
    3587 }
    3588 if (!f->conf.use_ino && f->conf.readdir_ino) {
    3589 e.attr.st_ino = (ino_t)
    3590 lookup_nodeid(f, dh->nodeid, name);
    3591 }
    3592
    3593 if (off) {
    3594 size_t newlen;
    3595
    3596 if (dh->filled) {
    3597 dh->error = -EIO;
    3598 return 1;
    3599 }
    3600
    3601 if (dh->first) {
    3602 dh->error = -EIO;
    3603 return 1;
    3604 }
    3605 if (extend_contents(dh, dh->needlen) == -1)
    3606 return 1;
    3607
    3608 if (statp && (flags & FUSE_FILL_DIR_PLUS)) {
    3609 if (!is_dot_or_dotdot(name)) {
    3610 res = do_lookup(f, dh->nodeid, name, &e);
    3611 if (res) {
    3612 dh->error = res;
    3613 return 1;
    3614 }
    3615 }
    3616 }
    3617
    3618 newlen = dh->len +
    3619 fuse_add_direntry_plus(dh->req, dh->contents + dh->len,
    3620 dh->needlen - dh->len, name,
    3621 &e, off);
    3622 if (newlen > dh->needlen)
    3623 return 1;
    3624 dh->len = newlen;
    3625 } else {
    3626 dh->filled = 1;
    3627
    3628 if (fuse_add_direntry_to_dh(dh, name, &e.attr, flags) == -1)
    3629 return 1;
    3630 }
    3631
    3632 return 0;
    3633}
    3634
    3635static void free_direntries(struct fuse_direntry *de)
    3636{
    3637 while (de) {
    3638 struct fuse_direntry *next = de->next;
    3639 free(de->name);
    3640 free(de);
    3641 de = next;
    3642 }
    3643}
    3644
    3645static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
    3646 size_t size, off_t off, struct fuse_dh *dh,
    3647 struct fuse_file_info *fi,
    3648 enum fuse_readdir_flags flags)
    3649{
    3650 char *path;
    3651 int err;
    3652
    3653 if (f->fs->op.readdir)
    3654 err = get_path_nullok(f, ino, &path);
    3655 else
    3656 err = get_path(f, ino, &path);
    3657 if (!err) {
    3658 struct fuse_intr_data d;
    3659 fuse_fill_dir_t filler = fill_dir;
    3660
    3661 if (flags & FUSE_READDIR_PLUS)
    3662 filler = fill_dir_plus;
    3663
    3664 free_direntries(dh->first);
    3665 dh->first = NULL;
    3666 dh->last = &dh->first;
    3667 dh->len = 0;
    3668 dh->error = 0;
    3669 dh->needlen = size;
    3670 dh->filled = 0;
    3671 dh->req = req;
    3672 fuse_prepare_interrupt(f, req, &d);
    3673 err = fuse_fs_readdir(f->fs, path, dh, filler, off, fi, flags);
    3674 fuse_finish_interrupt(f, req, &d);
    3675 dh->req = NULL;
    3676 if (!err)
    3677 err = dh->error;
    3678 if (err)
    3679 dh->filled = 0;
    3680 free_path(f, ino, path);
    3681 }
    3682 return err;
    3683}
    3684
    3685static int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh,
    3686 off_t off, enum fuse_readdir_flags flags)
    3687{
    3688 off_t pos;
    3689 struct fuse_direntry *de = dh->first;
    3690 int res;
    3691
    3692 dh->len = 0;
    3693
    3694 if (extend_contents(dh, dh->needlen) == -1)
    3695 return dh->error;
    3696
    3697 for (pos = 0; pos < off; pos++) {
    3698 if (!de)
    3699 break;
    3700
    3701 de = de->next;
    3702 }
    3703 while (de) {
    3704 char *p = dh->contents + dh->len;
    3705 unsigned rem = dh->needlen - dh->len;
    3706 unsigned thislen;
    3707 unsigned newlen;
    3708 pos++;
    3709
    3710 if (flags & FUSE_READDIR_PLUS) {
    3711 struct fuse_entry_param e = {
    3712 .ino = 0,
    3713 .attr = de->stat,
    3714 };
    3715
    3716 if (de->flags & FUSE_FILL_DIR_PLUS &&
    3717 !is_dot_or_dotdot(de->name)) {
    3718 res = do_lookup(dh->fuse, dh->nodeid,
    3719 de->name, &e);
    3720 if (res) {
    3721 dh->error = res;
    3722 return 1;
    3723 }
    3724 }
    3725
    3726 thislen = fuse_add_direntry_plus(req, p, rem,
    3727 de->name, &e, pos);
    3728 } else {
    3729 thislen = fuse_add_direntry(req, p, rem,
    3730 de->name, &de->stat, pos);
    3731 }
    3732 newlen = dh->len + thislen;
    3733 if (newlen > dh->needlen)
    3734 break;
    3735 dh->len = newlen;
    3736 de = de->next;
    3737 }
    3738 return 0;
    3739}
    3740
    3741static void fuse_readdir_common(fuse_req_t req, fuse_ino_t ino, size_t size,
    3742 off_t off, struct fuse_file_info *llfi,
    3743 enum fuse_readdir_flags flags)
    3744{
    3745 struct fuse *f = req_fuse_prepare(req);
    3746 struct fuse_file_info fi;
    3747 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
    3748 int err;
    3749
    3750 pthread_mutex_lock(&dh->lock);
    3751 /* According to SUS, directory contents need to be refreshed on
    3752 rewinddir() */
    3753 if (!off)
    3754 dh->filled = 0;
    3755
    3756 if (!dh->filled) {
    3757 err = readdir_fill(f, req, ino, size, off, dh, &fi, flags);
    3758 if (err) {
    3759 reply_err(req, err);
    3760 goto out;
    3761 }
    3762 }
    3763 if (dh->filled) {
    3764 dh->needlen = size;
    3765 err = readdir_fill_from_list(req, dh, off, flags);
    3766 if (err) {
    3767 reply_err(req, err);
    3768 goto out;
    3769 }
    3770 }
    3771 fuse_reply_buf(req, dh->contents, dh->len);
    3772out:
    3773 pthread_mutex_unlock(&dh->lock);
    3774}
    3775
    3776static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    3777 off_t off, struct fuse_file_info *llfi)
    3778{
    3779 fuse_readdir_common(req, ino, size, off, llfi, 0);
    3780}
    3781
    3782static void fuse_lib_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size,
    3783 off_t off, struct fuse_file_info *llfi)
    3784{
    3785 fuse_readdir_common(req, ino, size, off, llfi, FUSE_READDIR_PLUS);
    3786}
    3787
    3788static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
    3789 struct fuse_file_info *llfi)
    3790{
    3791 struct fuse *f = req_fuse_prepare(req);
    3792 struct fuse_intr_data d;
    3793 struct fuse_file_info fi;
    3794 struct fuse_dh *dh = get_dirhandle(llfi, &fi);
    3795 char *path;
    3796
    3797 get_path_nullok(f, ino, &path);
    3798
    3799 fuse_prepare_interrupt(f, req, &d);
    3800 fuse_fs_releasedir(f->fs, path, &fi);
    3801 fuse_finish_interrupt(f, req, &d);
    3802 free_path(f, ino, path);
    3803
    3804 pthread_mutex_lock(&dh->lock);
    3805 pthread_mutex_unlock(&dh->lock);
    3806 pthread_mutex_destroy(&dh->lock);
    3807 free_direntries(dh->first);
    3808 free(dh->contents);
    3809 free(dh);
    3810 reply_err(req, 0);
    3811}
    3812
    3813static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
    3814 struct fuse_file_info *llfi)
    3815{
    3816 struct fuse *f = req_fuse_prepare(req);
    3817 struct fuse_file_info fi;
    3818 char *path;
    3819 int err;
    3820
    3821 get_dirhandle(llfi, &fi);
    3822
    3823 err = get_path_nullok(f, ino, &path);
    3824 if (!err) {
    3825 struct fuse_intr_data d;
    3826 fuse_prepare_interrupt(f, req, &d);
    3827 err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
    3828 fuse_finish_interrupt(f, req, &d);
    3829 free_path(f, ino, path);
    3830 }
    3831 reply_err(req, err);
    3832}
    3833
    3834static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
    3835{
    3836 struct fuse *f = req_fuse_prepare(req);
    3837 struct statvfs buf;
    3838 char *path = NULL;
    3839 int err = 0;
    3840
    3841 memset(&buf, 0, sizeof(buf));
    3842 if (ino)
    3843 err = get_path(f, ino, &path);
    3844
    3845 if (!err) {
    3846 struct fuse_intr_data d;
    3847 fuse_prepare_interrupt(f, req, &d);
    3848 err = fuse_fs_statfs(f->fs, path ? path : "/", &buf);
    3849 fuse_finish_interrupt(f, req, &d);
    3850 free_path(f, ino, path);
    3851 }
    3852
    3853 if (!err)
    3854 fuse_reply_statfs(req, &buf);
    3855 else
    3856 reply_err(req, err);
    3857}
    3858
    3859static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    3860 const char *value, size_t size, int flags)
    3861{
    3862 struct fuse *f = req_fuse_prepare(req);
    3863 char *path;
    3864 int err;
    3865
    3866 err = get_path(f, ino, &path);
    3867 if (!err) {
    3868 struct fuse_intr_data d;
    3869 fuse_prepare_interrupt(f, req, &d);
    3870 err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
    3871 fuse_finish_interrupt(f, req, &d);
    3872 free_path(f, ino, path);
    3873 }
    3874 reply_err(req, err);
    3875}
    3876
    3877static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
    3878 const char *name, char *value, size_t size)
    3879{
    3880 int err;
    3881 char *path;
    3882
    3883 err = get_path(f, ino, &path);
    3884 if (!err) {
    3885 struct fuse_intr_data d;
    3886 fuse_prepare_interrupt(f, req, &d);
    3887 err = fuse_fs_getxattr(f->fs, path, name, value, size);
    3888 fuse_finish_interrupt(f, req, &d);
    3889 free_path(f, ino, path);
    3890 }
    3891 return err;
    3892}
    3893
    3894static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    3895 size_t size)
    3896{
    3897 struct fuse *f = req_fuse_prepare(req);
    3898 int res;
    3899
    3900 if (size) {
    3901 char *value = (char *) malloc(size);
    3902 if (value == NULL) {
    3903 reply_err(req, -ENOMEM);
    3904 return;
    3905 }
    3906 res = common_getxattr(f, req, ino, name, value, size);
    3907 if (res > 0)
    3908 fuse_reply_buf(req, value, res);
    3909 else
    3910 reply_err(req, res);
    3911 free(value);
    3912 } else {
    3913 res = common_getxattr(f, req, ino, name, NULL, 0);
    3914 if (res >= 0)
    3915 fuse_reply_xattr(req, res);
    3916 else
    3917 reply_err(req, res);
    3918 }
    3919}
    3920
    3921static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
    3922 char *list, size_t size)
    3923{
    3924 char *path;
    3925 int err;
    3926
    3927 err = get_path(f, ino, &path);
    3928 if (!err) {
    3929 struct fuse_intr_data d;
    3930 fuse_prepare_interrupt(f, req, &d);
    3931 err = fuse_fs_listxattr(f->fs, path, list, size);
    3932 fuse_finish_interrupt(f, req, &d);
    3933 free_path(f, ino, path);
    3934 }
    3935 return err;
    3936}
    3937
    3938static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
    3939{
    3940 struct fuse *f = req_fuse_prepare(req);
    3941 int res;
    3942
    3943 if (size) {
    3944 char *list = (char *) malloc(size);
    3945 if (list == NULL) {
    3946 reply_err(req, -ENOMEM);
    3947 return;
    3948 }
    3949 res = common_listxattr(f, req, ino, list, size);
    3950 if (res > 0)
    3951 fuse_reply_buf(req, list, res);
    3952 else
    3953 reply_err(req, res);
    3954 free(list);
    3955 } else {
    3956 res = common_listxattr(f, req, ino, NULL, 0);
    3957 if (res >= 0)
    3958 fuse_reply_xattr(req, res);
    3959 else
    3960 reply_err(req, res);
    3961 }
    3962}
    3963
    3964static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
    3965 const char *name)
    3966{
    3967 struct fuse *f = req_fuse_prepare(req);
    3968 char *path;
    3969 int err;
    3970
    3971 err = get_path(f, ino, &path);
    3972 if (!err) {
    3973 struct fuse_intr_data d;
    3974 fuse_prepare_interrupt(f, req, &d);
    3975 err = fuse_fs_removexattr(f->fs, path, name);
    3976 fuse_finish_interrupt(f, req, &d);
    3977 free_path(f, ino, path);
    3978 }
    3979 reply_err(req, err);
    3980}
    3981
    3982static struct lock *locks_conflict(struct node *node, const struct lock *lock)
    3983{
    3984 struct lock *l;
    3985
    3986 for (l = node->locks; l; l = l->next)
    3987 if (l->owner != lock->owner &&
    3988 lock->start <= l->end && l->start <= lock->end &&
    3989 (l->type == F_WRLCK || lock->type == F_WRLCK))
    3990 break;
    3991
    3992 return l;
    3993}
    3994
    3995static void delete_lock(struct lock **lockp)
    3996{
    3997 struct lock *l = *lockp;
    3998 *lockp = l->next;
    3999 free(l);
    4000}
    4001
    4002static void insert_lock(struct lock **pos, struct lock *lock)
    4003{
    4004 lock->next = *pos;
    4005 *pos = lock;
    4006}
    4007
    4008static int locks_insert(struct node *node, struct lock *lock)
    4009{
    4010 struct lock **lp;
    4011 struct lock *newl1 = NULL;
    4012 struct lock *newl2 = NULL;
    4013
    4014 if (lock->type != F_UNLCK || lock->start != 0 ||
    4015 lock->end != OFFSET_MAX) {
    4016 newl1 = malloc(sizeof(struct lock));
    4017 newl2 = malloc(sizeof(struct lock));
    4018
    4019 if (!newl1 || !newl2) {
    4020 free(newl1);
    4021 free(newl2);
    4022 return -ENOLCK;
    4023 }
    4024 }
    4025
    4026 for (lp = &node->locks; *lp;) {
    4027 struct lock *l = *lp;
    4028 if (l->owner != lock->owner)
    4029 goto skip;
    4030
    4031 if (lock->type == l->type) {
    4032 if (l->end < lock->start - 1)
    4033 goto skip;
    4034 if (lock->end < l->start - 1)
    4035 break;
    4036 if (l->start <= lock->start && lock->end <= l->end)
    4037 goto out;
    4038 if (l->start < lock->start)
    4039 lock->start = l->start;
    4040 if (lock->end < l->end)
    4041 lock->end = l->end;
    4042 goto delete;
    4043 } else {
    4044 if (l->end < lock->start)
    4045 goto skip;
    4046 if (lock->end < l->start)
    4047 break;
    4048 if (lock->start <= l->start && l->end <= lock->end)
    4049 goto delete;
    4050 if (l->end <= lock->end) {
    4051 l->end = lock->start - 1;
    4052 goto skip;
    4053 }
    4054 if (lock->start <= l->start) {
    4055 l->start = lock->end + 1;
    4056 break;
    4057 }
    4058 *newl2 = *l;
    4059 newl2->start = lock->end + 1;
    4060 l->end = lock->start - 1;
    4061 insert_lock(&l->next, newl2);
    4062 newl2 = NULL;
    4063 }
    4064 skip:
    4065 lp = &l->next;
    4066 continue;
    4067
    4068 delete:
    4069 delete_lock(lp);
    4070 }
    4071 if (lock->type != F_UNLCK) {
    4072 *newl1 = *lock;
    4073 insert_lock(lp, newl1);
    4074 newl1 = NULL;
    4075 }
    4076out:
    4077 free(newl1);
    4078 free(newl2);
    4079 return 0;
    4080}
    4081
    4082static void flock_to_lock(struct flock *flock, struct lock *lock)
    4083{
    4084 memset(lock, 0, sizeof(struct lock));
    4085 lock->type = flock->l_type;
    4086 lock->start = flock->l_start;
    4087 lock->end =
    4088 flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
    4089 lock->pid = flock->l_pid;
    4090}
    4091
    4092static void lock_to_flock(struct lock *lock, struct flock *flock)
    4093{
    4094 flock->l_type = lock->type;
    4095 flock->l_start = lock->start;
    4096 flock->l_len =
    4097 (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
    4098 flock->l_pid = lock->pid;
    4099}
    4100
    4101static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
    4102 const char *path, struct fuse_file_info *fi)
    4103{
    4104 struct fuse_intr_data d;
    4105 struct flock lock;
    4106 struct lock l;
    4107 int err;
    4108 int errlock;
    4109
    4110 fuse_prepare_interrupt(f, req, &d);
    4111 memset(&lock, 0, sizeof(lock));
    4112 lock.l_type = F_UNLCK;
    4113 lock.l_whence = SEEK_SET;
    4114 err = fuse_fs_flush(f->fs, path, fi);
    4115 errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
    4116 fuse_finish_interrupt(f, req, &d);
    4117
    4118 if (errlock != -ENOSYS) {
    4119 flock_to_lock(&lock, &l);
    4120 l.owner = fi->lock_owner;
    4121 pthread_mutex_lock(&f->lock);
    4122 locks_insert(get_node(f, ino), &l);
    4123 pthread_mutex_unlock(&f->lock);
    4124
    4125 /* if op.lock() is defined FLUSH is needed regardless
    4126 of op.flush() */
    4127 if (err == -ENOSYS)
    4128 err = 0;
    4129 }
    4130 return err;
    4131}
    4132
    4133static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
    4134 struct fuse_file_info *fi)
    4135{
    4136 struct fuse *f = req_fuse_prepare(req);
    4137 struct fuse_intr_data d;
    4138 char *path;
    4139 int err = 0;
    4140
    4141 get_path_nullok(f, ino, &path);
    4142 if (fi->flush) {
    4143 err = fuse_flush_common(f, req, ino, path, fi);
    4144 if (err == -ENOSYS)
    4145 err = 0;
    4146 }
    4147
    4148 fuse_prepare_interrupt(f, req, &d);
    4149 fuse_do_release(f, ino, path, fi);
    4150 fuse_finish_interrupt(f, req, &d);
    4151 free_path(f, ino, path);
    4152
    4153 reply_err(req, err);
    4154}
    4155
    4156static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
    4157 struct fuse_file_info *fi)
    4158{
    4159 struct fuse *f = req_fuse_prepare(req);
    4160 char *path;
    4161 int err;
    4162
    4163 get_path_nullok(f, ino, &path);
    4164 err = fuse_flush_common(f, req, ino, path, fi);
    4165 free_path(f, ino, path);
    4166
    4167 reply_err(req, err);
    4168}
    4169
    4170static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
    4171 struct fuse_file_info *fi, struct flock *lock,
    4172 int cmd)
    4173{
    4174 struct fuse *f = req_fuse_prepare(req);
    4175 char *path;
    4176 int err;
    4177
    4178 err = get_path_nullok(f, ino, &path);
    4179 if (!err) {
    4180 struct fuse_intr_data d;
    4181 fuse_prepare_interrupt(f, req, &d);
    4182 err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
    4183 fuse_finish_interrupt(f, req, &d);
    4184 free_path(f, ino, path);
    4185 }
    4186 return err;
    4187}
    4188
    4189static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
    4190 struct fuse_file_info *fi, struct flock *lock)
    4191{
    4192 int err;
    4193 struct lock l;
    4194 struct lock *conflict;
    4195 struct fuse *f = req_fuse(req);
    4196
    4197 flock_to_lock(lock, &l);
    4198 l.owner = fi->lock_owner;
    4199 pthread_mutex_lock(&f->lock);
    4200 conflict = locks_conflict(get_node(f, ino), &l);
    4201 if (conflict)
    4202 lock_to_flock(conflict, lock);
    4203 pthread_mutex_unlock(&f->lock);
    4204 if (!conflict)
    4205 err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
    4206 else
    4207 err = 0;
    4208
    4209 if (!err)
    4210 fuse_reply_lock(req, lock);
    4211 else
    4212 reply_err(req, err);
    4213}
    4214
    4215static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
    4216 struct fuse_file_info *fi, struct flock *lock,
    4217 int sleep)
    4218{
    4219 int err = fuse_lock_common(req, ino, fi, lock,
    4220 sleep ? F_SETLKW : F_SETLK);
    4221 if (!err) {
    4222 struct fuse *f = req_fuse(req);
    4223 struct lock l;
    4224 flock_to_lock(lock, &l);
    4225 l.owner = fi->lock_owner;
    4226 pthread_mutex_lock(&f->lock);
    4227 locks_insert(get_node(f, ino), &l);
    4228 pthread_mutex_unlock(&f->lock);
    4229 }
    4230 reply_err(req, err);
    4231}
    4232
    4233static void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino,
    4234 struct fuse_file_info *fi, int op)
    4235{
    4236 struct fuse *f = req_fuse_prepare(req);
    4237 char *path;
    4238 int err;
    4239
    4240 err = get_path_nullok(f, ino, &path);
    4241 if (err == 0) {
    4242 struct fuse_intr_data d;
    4243 fuse_prepare_interrupt(f, req, &d);
    4244 err = fuse_fs_flock(f->fs, path, fi, op);
    4245 fuse_finish_interrupt(f, req, &d);
    4246 free_path(f, ino, path);
    4247 }
    4248 reply_err(req, err);
    4249}
    4250
    4251static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
    4252 uint64_t idx)
    4253{
    4254 struct fuse *f = req_fuse_prepare(req);
    4255 struct fuse_intr_data d;
    4256 char *path;
    4257 int err;
    4258
    4259 err = get_path(f, ino, &path);
    4260 if (!err) {
    4261 fuse_prepare_interrupt(f, req, &d);
    4262 err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
    4263 fuse_finish_interrupt(f, req, &d);
    4264 free_path(f, ino, path);
    4265 }
    4266 if (!err)
    4267 fuse_reply_bmap(req, idx);
    4268 else
    4269 reply_err(req, err);
    4270}
    4271
    4272static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
    4273 void *arg, struct fuse_file_info *llfi,
    4274 unsigned int flags, const void *in_buf,
    4275 size_t in_bufsz, size_t out_bufsz)
    4276{
    4277 struct fuse *f = req_fuse_prepare(req);
    4278 struct fuse_intr_data d;
    4279 struct fuse_file_info fi;
    4280 char *path, *out_buf = NULL;
    4281 int err;
    4282
    4283 err = -EPERM;
    4284 if (flags & FUSE_IOCTL_UNRESTRICTED)
    4285 goto err;
    4286
    4287 if (flags & FUSE_IOCTL_DIR)
    4288 get_dirhandle(llfi, &fi);
    4289 else
    4290 fi = *llfi;
    4291
    4292 if (out_bufsz) {
    4293 err = -ENOMEM;
    4294 out_buf = malloc(out_bufsz);
    4295 if (!out_buf)
    4296 goto err;
    4297 }
    4298
    4299 assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
    4300 if (out_buf && in_bufsz)
    4301 memcpy(out_buf, in_buf, in_bufsz);
    4302
    4303 err = get_path_nullok(f, ino, &path);
    4304 if (err)
    4305 goto err;
    4306
    4307 fuse_prepare_interrupt(f, req, &d);
    4308
    4309 err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
    4310 out_buf ? out_buf : (void *)in_buf);
    4311
    4312 fuse_finish_interrupt(f, req, &d);
    4313 free_path(f, ino, path);
    4314
    4315 if (err < 0)
    4316 goto err;
    4317 fuse_reply_ioctl(req, err, out_buf, out_bufsz);
    4318 goto out;
    4319err:
    4320 reply_err(req, err);
    4321out:
    4322 free(out_buf);
    4323}
    4324
    4325static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino,
    4326 struct fuse_file_info *fi, struct fuse_pollhandle *ph)
    4327{
    4328 struct fuse *f = req_fuse_prepare(req);
    4329 struct fuse_intr_data d;
    4330 char *path;
    4331 int err;
    4332 unsigned revents = 0;
    4333
    4334 err = get_path_nullok(f, ino, &path);
    4335 if (!err) {
    4336 fuse_prepare_interrupt(f, req, &d);
    4337 err = fuse_fs_poll(f->fs, path, fi, ph, &revents);
    4338 fuse_finish_interrupt(f, req, &d);
    4339 free_path(f, ino, path);
    4340 } else {
    4342 }
    4343 if (!err)
    4344 fuse_reply_poll(req, revents);
    4345 else
    4346 reply_err(req, err);
    4347}
    4348
    4349static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode,
    4350 off_t offset, off_t length, struct fuse_file_info *fi)
    4351{
    4352 struct fuse *f = req_fuse_prepare(req);
    4353 struct fuse_intr_data d;
    4354 char *path;
    4355 int err;
    4356
    4357 err = get_path_nullok(f, ino, &path);
    4358 if (!err) {
    4359 fuse_prepare_interrupt(f, req, &d);
    4360 err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi);
    4361 fuse_finish_interrupt(f, req, &d);
    4362 free_path(f, ino, path);
    4363 }
    4364 reply_err(req, err);
    4365}
    4366
    4367static void fuse_lib_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
    4368 off_t off_in, struct fuse_file_info *fi_in,
    4369 fuse_ino_t nodeid_out, off_t off_out,
    4370 struct fuse_file_info *fi_out, size_t len,
    4371 int flags)
    4372{
    4373 struct fuse *f = req_fuse_prepare(req);
    4374 struct fuse_intr_data d;
    4375 char *path_in, *path_out;
    4376 int err;
    4377 ssize_t res;
    4378
    4379 err = get_path_nullok(f, nodeid_in, &path_in);
    4380 if (err) {
    4381 reply_err(req, err);
    4382 return;
    4383 }
    4384
    4385 err = get_path_nullok(f, nodeid_out, &path_out);
    4386 if (err) {
    4387 free_path(f, nodeid_in, path_in);
    4388 reply_err(req, err);
    4389 return;
    4390 }
    4391
    4392 fuse_prepare_interrupt(f, req, &d);
    4393 res = fuse_fs_copy_file_range(f->fs, path_in, fi_in, off_in, path_out,
    4394 fi_out, off_out, len, flags);
    4395 fuse_finish_interrupt(f, req, &d);
    4396
    4397 if (res >= 0)
    4398 fuse_reply_write(req, res);
    4399 else
    4400 reply_err(req, res);
    4401
    4402 free_path(f, nodeid_in, path_in);
    4403 free_path(f, nodeid_out, path_out);
    4404}
    4405
    4406static void fuse_lib_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
    4407 struct fuse_file_info *fi)
    4408{
    4409 struct fuse *f = req_fuse_prepare(req);
    4410 struct fuse_intr_data d;
    4411 char *path;
    4412 int err;
    4413 off_t res;
    4414
    4415 err = get_path(f, ino, &path);
    4416 if (err) {
    4417 reply_err(req, err);
    4418 return;
    4419 }
    4420
    4421 fuse_prepare_interrupt(f, req, &d);
    4422 res = fuse_fs_lseek(f->fs, path, off, whence, fi);
    4423 fuse_finish_interrupt(f, req, &d);
    4424 free_path(f, ino, path);
    4425 if (res >= 0)
    4426 fuse_reply_lseek(req, res);
    4427 else
    4428 reply_err(req, res);
    4429}
    4430
    4431#ifdef HAVE_STATX
    4432static void fuse_lib_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask,
    4433 struct fuse_file_info *fi)
    4434{
    4435 struct fuse *f = req_fuse_prepare(req);
    4436 struct statx stxbuf;
    4437 char *path;
    4438 int err;
    4439
    4440 memset(&stxbuf, 0, sizeof(stxbuf));
    4441
    4442 if (fi != NULL)
    4443 err = get_path_nullok(f, ino, &path);
    4444 else
    4445 err = get_path(f, ino, &path);
    4446
    4447 if (!err) {
    4448 struct fuse_intr_data d;
    4449
    4450 if (!path)
    4451 flags |= AT_EMPTY_PATH;
    4452 fuse_prepare_interrupt(f, req, &d);
    4453 err = fuse_fs_statx(f->fs, path, flags, mask, &stxbuf, fi);
    4454 fuse_finish_interrupt(f, req, &d);
    4455 free_path(f, ino, path);
    4456 }
    4457 if (!err) {
    4458 struct node *node;
    4459
    4460 pthread_mutex_lock(&f->lock);
    4461 node = get_node(f, ino);
    4462 if (node->is_hidden && stxbuf.stx_nlink > 0)
    4463 stxbuf.stx_nlink--;
    4464 if (f->conf.auto_cache) {
    4465 struct stat stbuf;
    4466
    4467 stbuf.st_mtime = stxbuf.stx_mtime.tv_sec;
    4468 ST_MTIM_NSEC_SET(&stbuf, stxbuf.stx_mtime.tv_nsec);
    4469 stbuf.st_size = stxbuf.stx_size;
    4470 update_stat(node, &stbuf);
    4471 }
    4472 pthread_mutex_unlock(&f->lock);
    4473 set_statx(f, ino, &stxbuf);
    4474 fuse_reply_statx(req, 0, &stxbuf, f->conf.attr_timeout);
    4475 } else
    4476 reply_err(req, err);
    4477}
    4478#endif
    4479
    4480static int clean_delay(struct fuse *f)
    4481{
    4482 /*
    4483 * This is calculating the delay between clean runs. To
    4484 * reduce the number of cleans we are doing them 10 times
    4485 * within the remember window.
    4486 */
    4487 int min_sleep = 60;
    4488 int max_sleep = 3600;
    4489 int sleep_time = f->conf.remember / 10;
    4490
    4491 if (sleep_time > max_sleep)
    4492 return max_sleep;
    4493 if (sleep_time < min_sleep)
    4494 return min_sleep;
    4495 return sleep_time;
    4496}
    4497
    4498int fuse_clean_cache(struct fuse *f)
    4499{
    4500 struct node_lru *lnode;
    4501 struct list_head *curr, *next;
    4502 struct node *node;
    4503 struct timespec now;
    4504
    4505 pthread_mutex_lock(&f->lock);
    4506
    4507 curr_time(&now);
    4508
    4509 for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) {
    4510 double age;
    4511
    4512 next = curr->next;
    4513 lnode = list_entry(curr, struct node_lru, lru);
    4514 node = &lnode->node;
    4515
    4516 age = diff_timespec(&now, &lnode->forget_time);
    4517 if (age <= f->conf.remember)
    4518 break;
    4519
    4520 assert(node->nlookup == 1);
    4521
    4522 /* Don't forget active directories */
    4523 if (node->refctr > 1)
    4524 continue;
    4525
    4526 node->nlookup = 0;
    4527 unhash_name(f, node);
    4528 unref_node(f, node);
    4529 }
    4530 pthread_mutex_unlock(&f->lock);
    4531
    4532 return clean_delay(f);
    4533}
    4534
    4535static struct fuse_lowlevel_ops fuse_path_ops = {
    4536 .init = fuse_lib_init,
    4537 .destroy = fuse_lib_destroy,
    4538 .lookup = fuse_lib_lookup,
    4539 .forget = fuse_lib_forget,
    4540 .forget_multi = fuse_lib_forget_multi,
    4541 .getattr = fuse_lib_getattr,
    4542 .setattr = fuse_lib_setattr,
    4543 .access = fuse_lib_access,
    4544 .readlink = fuse_lib_readlink,
    4545 .mknod = fuse_lib_mknod,
    4546 .mkdir = fuse_lib_mkdir,
    4547 .unlink = fuse_lib_unlink,
    4548 .rmdir = fuse_lib_rmdir,
    4549 .symlink = fuse_lib_symlink,
    4550 .rename = fuse_lib_rename,
    4551 .link = fuse_lib_link,
    4552 .create = fuse_lib_create,
    4553 .open = fuse_lib_open,
    4554 .read = fuse_lib_read,
    4555 .write_buf = fuse_lib_write_buf,
    4556 .flush = fuse_lib_flush,
    4557 .release = fuse_lib_release,
    4558 .fsync = fuse_lib_fsync,
    4559 .opendir = fuse_lib_opendir,
    4560 .readdir = fuse_lib_readdir,
    4561 .readdirplus = fuse_lib_readdirplus,
    4562 .releasedir = fuse_lib_releasedir,
    4563 .fsyncdir = fuse_lib_fsyncdir,
    4564 .statfs = fuse_lib_statfs,
    4565 .setxattr = fuse_lib_setxattr,
    4566 .getxattr = fuse_lib_getxattr,
    4567 .listxattr = fuse_lib_listxattr,
    4568 .removexattr = fuse_lib_removexattr,
    4569 .getlk = fuse_lib_getlk,
    4570 .setlk = fuse_lib_setlk,
    4571 .flock = fuse_lib_flock,
    4572 .bmap = fuse_lib_bmap,
    4573 .ioctl = fuse_lib_ioctl,
    4574 .poll = fuse_lib_poll,
    4575 .fallocate = fuse_lib_fallocate,
    4576 .copy_file_range = fuse_lib_copy_file_range,
    4577 .lseek = fuse_lib_lseek,
    4578#ifdef HAVE_STATX
    4579 .statx = fuse_lib_statx,
    4580#endif
    4581};
    4582
    4583int fuse_notify_poll(struct fuse_pollhandle *ph)
    4584{
    4585 return fuse_lowlevel_notify_poll(ph);
    4586}
    4587
    4588struct fuse_session *fuse_get_session(struct fuse *f)
    4589{
    4590 return f->se;
    4591}
    4592
    4593static int fuse_session_loop_remember(struct fuse *f)
    4594{
    4595 struct fuse_session *se = f->se;
    4596 int res = 0;
    4597 struct timespec now;
    4598 time_t next_clean;
    4599 struct pollfd fds = {
    4600 .fd = se->fd,
    4601 .events = POLLIN
    4602 };
    4603 struct fuse_buf fbuf = {
    4604 .mem = NULL,
    4605 };
    4606
    4607 curr_time(&now);
    4608 next_clean = now.tv_sec;
    4609 while (!fuse_session_exited(se)) {
    4610 unsigned timeout;
    4611
    4612 curr_time(&now);
    4613 if (now.tv_sec < next_clean)
    4614 timeout = next_clean - now.tv_sec;
    4615 else
    4616 timeout = 0;
    4617
    4618 res = poll(&fds, 1, timeout * 1000);
    4619 if (res == -1) {
    4620 if (errno == EINTR)
    4621 continue;
    4622 else
    4623 break;
    4624 } else if (res > 0) {
    4625 res = fuse_session_receive_buf_internal(se, &fbuf,
    4626 NULL);
    4627 if (res == -EINTR)
    4628 continue;
    4629 if (res <= 0)
    4630 break;
    4631
    4632 fuse_session_process_buf_internal(se, &fbuf, NULL);
    4633 } else {
    4634 timeout = fuse_clean_cache(f);
    4635 curr_time(&now);
    4636 next_clean = now.tv_sec + timeout;
    4637 }
    4638 }
    4639
    4640 fuse_buf_free(&fbuf);
    4641 return res < 0 ? -1 : 0;
    4642}
    4643
    4644int fuse_loop(struct fuse *f)
    4645{
    4646 if (!f)
    4647 return -1;
    4648
    4649 if (lru_enabled(f))
    4650 return fuse_session_loop_remember(f);
    4651
    4652 return fuse_session_loop(f->se);
    4653}
    4654
    4655FUSE_SYMVER("fuse_loop_mt_312", "fuse_loop_mt@@FUSE_3.12")
    4656int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config)
    4657{
    4658 if (f == NULL)
    4659 return -1;
    4660
    4661 int res = fuse_start_cleanup_thread(f);
    4662 if (res)
    4663 return -1;
    4664
    4665 res = fuse_session_loop_mt_312(fuse_get_session(f), config);
    4667 return res;
    4668}
    4669
    4670int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1);
    4671FUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@FUSE_3.2")
    4672int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1)
    4673{
    4674 struct fuse_loop_config *config = fuse_loop_cfg_create();
    4675 if (config == NULL)
    4676 return ENOMEM;
    4677
    4678 fuse_loop_cfg_convert(config, config_v1);
    4679
    4680 int res = fuse_loop_mt_312(f, config);
    4681
    4682 fuse_loop_cfg_destroy(config);
    4683
    4684 return res;
    4685}
    4686
    4687int fuse_loop_mt_31(struct fuse *f, int clone_fd);
    4688FUSE_SYMVER("fuse_loop_mt_31", "fuse_loop_mt@FUSE_3.0")
    4689int fuse_loop_mt_31(struct fuse *f, int clone_fd)
    4690{
    4691 int err;
    4692 struct fuse_loop_config *config = fuse_loop_cfg_create();
    4693
    4694 if (config == NULL)
    4695 return ENOMEM;
    4696
    4697 fuse_loop_cfg_set_clone_fd(config, clone_fd);
    4698
    4699 err = fuse_loop_mt_312(f, config);
    4700
    4701 fuse_loop_cfg_destroy(config);
    4702
    4703 return err;
    4704}
    4705
    4706void fuse_exit(struct fuse *f)
    4707{
    4708 fuse_session_exit(f->se);
    4709}
    4710
    4712{
    4713 struct fuse_context_i *c = fuse_get_context_internal();
    4714
    4715 if (c)
    4716 return &c->ctx;
    4717 else
    4718 return NULL;
    4719}
    4720
    4721int fuse_getgroups(int size, gid_t list[])
    4722{
    4723 struct fuse_context_i *c = fuse_get_context_internal();
    4724 if (!c)
    4725 return -EINVAL;
    4726
    4727 return fuse_req_getgroups(c->req, size, list);
    4728}
    4729
    4731{
    4732 struct fuse_context_i *c = fuse_get_context_internal();
    4733
    4734 if (c)
    4735 return fuse_req_interrupted(c->req);
    4736 else
    4737 return 0;
    4738}
    4739
    4740int fuse_invalidate_path(struct fuse *f, const char *path) {
    4741 fuse_ino_t ino;
    4742 int err = lookup_path_in_cache(f, path, &ino);
    4743 if (err) {
    4744 return err;
    4745 }
    4746
    4747 return fuse_lowlevel_notify_inval_inode(f->se, ino, 0, 0);
    4748}
    4749
    4750#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
    4751
    4752static const struct fuse_opt fuse_lib_opts[] = {
    4755 FUSE_LIB_OPT("debug", debug, 1),
    4756 FUSE_LIB_OPT("-d", debug, 1),
    4757 FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
    4758 FUSE_LIB_OPT("auto_cache", auto_cache, 1),
    4759 FUSE_LIB_OPT("noauto_cache", auto_cache, 0),
    4760 FUSE_LIB_OPT("no_rofd_flush", no_rofd_flush, 1),
    4761 FUSE_LIB_OPT("umask=", set_mode, 1),
    4762 FUSE_LIB_OPT("umask=%o", umask, 0),
    4763 FUSE_LIB_OPT("fmask=", set_mode, 1),
    4764 FUSE_LIB_OPT("fmask=%o", fmask, 0),
    4765 FUSE_LIB_OPT("dmask=", set_mode, 1),
    4766 FUSE_LIB_OPT("dmask=%o", dmask, 0),
    4767 FUSE_LIB_OPT("uid=", set_uid, 1),
    4768 FUSE_LIB_OPT("uid=%d", uid, 0),
    4769 FUSE_LIB_OPT("gid=", set_gid, 1),
    4770 FUSE_LIB_OPT("gid=%d", gid, 0),
    4771 FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
    4772 FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
    4773 FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0),
    4774 FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1),
    4775 FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
    4776 FUSE_LIB_OPT("noforget", remember, -1),
    4777 FUSE_LIB_OPT("remember=%u", remember, 0),
    4778 FUSE_LIB_OPT("modules=%s", modules, 0),
    4779 FUSE_LIB_OPT("parallel_direct_write=%d", parallel_direct_writes, 0),
    4781};
    4782
    4783static int fuse_lib_opt_proc(void *data, const char *arg, int key,
    4784 struct fuse_args *outargs)
    4785{
    4786 (void) arg; (void) outargs; (void) data; (void) key;
    4787
    4788 /* Pass through unknown options */
    4789 return 1;
    4790}
    4791
    4792
    4793static const struct fuse_opt fuse_help_opts[] = {
    4794 FUSE_LIB_OPT("modules=%s", modules, 1),
    4795 FUSE_OPT_KEY("modules=%s", FUSE_OPT_KEY_KEEP),
    4797};
    4798
    4799static void print_module_help(const char *name,
    4801{
    4802 struct fuse_args a = FUSE_ARGS_INIT(0, NULL);
    4803 if (fuse_opt_add_arg(&a, "") == -1 ||
    4804 fuse_opt_add_arg(&a, "-h") == -1) {
    4806 return;
    4807 }
    4808 printf("\nOptions for %s module:\n", name);
    4809 (*fac)(&a, NULL);
    4811}
    4812
    4813void fuse_lib_help(struct fuse_args *args)
    4814{
    4815 /* These are not all options, but only the ones that
    4816 may be of interest to an end-user */
    4817 printf(
    4818" -o kernel_cache cache files in kernel\n"
    4819" -o [no]auto_cache enable caching based on modification times (off)\n"
    4820" -o no_rofd_flush disable flushing of read-only fd on close (off)\n"
    4821" -o umask=M set file permissions (octal)\n"
    4822" -o fmask=M set file permissions (octal)\n"
    4823" -o dmask=M set dir permissions (octal)\n"
    4824" -o uid=N set file owner\n"
    4825" -o gid=N set file group\n"
    4826" -o entry_timeout=T cache timeout for names (1.0s)\n"
    4827" -o negative_timeout=T cache timeout for deleted names (0.0s)\n"
    4828" -o attr_timeout=T cache timeout for attributes (1.0s)\n"
    4829" -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n"
    4830" -o noforget never forget cached inodes\n"
    4831" -o remember=T remember cached inodes for T seconds (0s)\n"
    4832" -o modules=M1[:M2...] names of modules to push onto filesystem stack\n");
    4833
    4834
    4835 /* Print low-level help */
    4837
    4838 /* Print help for builtin modules */
    4839 print_module_help("subdir", &fuse_module_subdir_factory);
    4840#ifdef HAVE_ICONV
    4841 print_module_help("iconv", &fuse_module_iconv_factory);
    4842#endif
    4843
    4844 /* Parse command line options in case we need to
    4845 activate more modules */
    4846 struct fuse_config conf = { .modules = NULL };
    4847 if (fuse_opt_parse(args, &conf, fuse_help_opts,
    4848 fuse_lib_opt_proc) == -1
    4849 || !conf.modules)
    4850 return;
    4851
    4852 char *module;
    4853 char *next;
    4854 struct fuse_module *m;
    4855
    4856 // Iterate over all modules
    4857 for (module = conf.modules; module; module = next) {
    4858 char *p;
    4859 for (p = module; *p && *p != ':'; p++);
    4860 next = *p ? p + 1 : NULL;
    4861 *p = '\0';
    4862
    4863 m = fuse_get_module(module);
    4864 if (m)
    4865 print_module_help(module, &m->factory);
    4866 }
    4867}
    4868
    4869static int fuse_init_intr_signal(int signum, int *installed)
    4870{
    4871 struct sigaction old_sa;
    4872
    4873 if (sigaction(signum, NULL, &old_sa) == -1) {
    4874 perror("fuse: cannot get old signal handler");
    4875 return -1;
    4876 }
    4877
    4878 if (old_sa.sa_handler == SIG_DFL) {
    4879 struct sigaction sa;
    4880
    4881 memset(&sa, 0, sizeof(struct sigaction));
    4882 sa.sa_handler = fuse_intr_sighandler;
    4883 sigemptyset(&sa.sa_mask);
    4884
    4885 if (sigaction(signum, &sa, NULL) == -1) {
    4886 perror("fuse: cannot set interrupt signal handler");
    4887 return -1;
    4888 }
    4889 *installed = 1;
    4890 }
    4891 return 0;
    4892}
    4893
    4894static void fuse_restore_intr_signal(int signum)
    4895{
    4896 struct sigaction sa;
    4897
    4898 memset(&sa, 0, sizeof(struct sigaction));
    4899 sa.sa_handler = SIG_DFL;
    4900 sigaction(signum, &sa, NULL);
    4901}
    4902
    4903
    4904static int fuse_push_module(struct fuse *f, const char *module,
    4905 struct fuse_args *args)
    4906{
    4907 struct fuse_fs *fs[2] = { f->fs, NULL };
    4908 struct fuse_fs *newfs;
    4909 struct fuse_module *m = fuse_get_module(module);
    4910
    4911 if (!m)
    4912 return -1;
    4913
    4914 newfs = m->factory(args, fs);
    4915 if (!newfs) {
    4916 fuse_put_module(m);
    4917 return -1;
    4918 }
    4919 f->fs = newfs;
    4920 return 0;
    4921}
    4922
    4923struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
    4924 void *user_data)
    4925{
    4926 struct fuse_fs *fs;
    4927
    4928 if (sizeof(struct fuse_operations) < op_size) {
    4929 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not not work\n");
    4930 op_size = sizeof(struct fuse_operations);
    4931 }
    4932
    4933 fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
    4934 if (!fs) {
    4935 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse_fs object\n");
    4936 return NULL;
    4937 }
    4938
    4939 fs->user_data = user_data;
    4940 if (op)
    4941 memcpy(&fs->op, op, op_size);
    4942 return fs;
    4943}
    4944
    4945static int node_table_init(struct node_table *t)
    4946{
    4947 t->size = NODE_TABLE_MIN_SIZE;
    4948 t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size);
    4949 if (t->array == NULL) {
    4950 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    4951 return -1;
    4952 }
    4953 t->use = 0;
    4954 t->split = 0;
    4955
    4956 return 0;
    4957}
    4958
    4959static void *fuse_prune_nodes(void *fuse)
    4960{
    4961 struct fuse *f = fuse;
    4962 int sleep_time;
    4963
    4964 fuse_set_thread_name("fuse_prune_nodes");
    4965
    4966 while(1) {
    4967 sleep_time = fuse_clean_cache(f);
    4968 sleep(sleep_time);
    4969 }
    4970 return NULL;
    4971}
    4972
    4973int fuse_start_cleanup_thread(struct fuse *f)
    4974{
    4975 if (lru_enabled(f))
    4976 return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f);
    4977
    4978 return 0;
    4979}
    4980
    4981void fuse_stop_cleanup_thread(struct fuse *f)
    4982{
    4983 if (lru_enabled(f)) {
    4984 pthread_mutex_lock(&f->lock);
    4985 pthread_cancel(f->prune_thread);
    4986 pthread_mutex_unlock(&f->lock);
    4987 pthread_join(f->prune_thread, NULL);
    4988 }
    4989}
    4990
    4991/*
    4992 * Not supposed to be called directly, but supposed to be called
    4993 * through the fuse_new macro
    4994 */
    4995struct fuse *_fuse_new_31(struct fuse_args *args,
    4996 const struct fuse_operations *op, size_t op_size,
    4997 struct libfuse_version *version, void *user_data)
    4998{
    4999 struct fuse *f;
    5000 struct node *root;
    5001 struct fuse_fs *fs;
    5002 struct fuse_lowlevel_ops llop = fuse_path_ops;
    5003
    5004 f = (struct fuse *) calloc(1, sizeof(struct fuse));
    5005 if (f == NULL) {
    5006 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
    5007 goto out;
    5008 }
    5009
    5010 f->conf.entry_timeout = 1.0;
    5011 f->conf.attr_timeout = 1.0;
    5012 f->conf.negative_timeout = 0.0;
    5013 f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
    5014
    5015 /* Parse options */
    5016 if (fuse_opt_parse(args, &f->conf, fuse_lib_opts,
    5017 fuse_lib_opt_proc) == -1)
    5018 goto out_free;
    5019
    5020 pthread_mutex_lock(&fuse_context_lock);
    5021 static int builtin_modules_registered = 0;
    5022 /* Have the builtin modules already been registered? */
    5023 if (builtin_modules_registered == 0) {
    5024 /* If not, register them. */
    5025 fuse_register_module("subdir", fuse_module_subdir_factory, NULL);
    5026#ifdef HAVE_ICONV
    5027 fuse_register_module("iconv", fuse_module_iconv_factory, NULL);
    5028#endif
    5029 builtin_modules_registered= 1;
    5030 }
    5031 pthread_mutex_unlock(&fuse_context_lock);
    5032
    5033 if (fuse_create_context_key() == -1)
    5034 goto out_free;
    5035
    5036 fs = fuse_fs_new(op, op_size, user_data);
    5037 if (!fs)
    5038 goto out_delete_context_key;
    5039
    5040 f->fs = fs;
    5041
    5042 /* Oh f**k, this is ugly! */
    5043 if (!fs->op.lock) {
    5044 llop.getlk = NULL;
    5045 llop.setlk = NULL;
    5046 }
    5047
    5048 f->pagesize = getpagesize();
    5049 init_list_head(&f->partial_slabs);
    5050 init_list_head(&f->full_slabs);
    5051 init_list_head(&f->lru_table);
    5052
    5053 if (f->conf.modules) {
    5054 char *module;
    5055 char *next;
    5056
    5057 for (module = f->conf.modules; module; module = next) {
    5058 char *p;
    5059 for (p = module; *p && *p != ':'; p++);
    5060 next = *p ? p + 1 : NULL;
    5061 *p = '\0';
    5062 if (module[0] &&
    5063 fuse_push_module(f, module, args) == -1)
    5064 goto out_free_fs;
    5065 }
    5066 }
    5067
    5068 if (!f->conf.ac_attr_timeout_set)
    5069 f->conf.ac_attr_timeout = f->conf.attr_timeout;
    5070
    5071#if defined(__FreeBSD__) || defined(__NetBSD__)
    5072 /*
    5073 * In FreeBSD, we always use these settings as inode numbers
    5074 * are needed to make getcwd(3) work.
    5075 */
    5076 f->conf.readdir_ino = 1;
    5077#endif
    5078
    5079 /* not declared globally, to restrict usage of this function */
    5080 struct fuse_session *fuse_session_new_versioned(
    5081 struct fuse_args *args, const struct fuse_lowlevel_ops *op,
    5082 size_t op_size, struct libfuse_version *version,
    5083 void *userdata);
    5084 f->se = fuse_session_new_versioned(args, &llop, sizeof(llop), version,
    5085 f);
    5086 if (f->se == NULL)
    5087 goto out_free_fs;
    5088
    5089 /* Trace topmost layer by default */
    5090 f->fs->debug = f->conf.debug;
    5091 f->ctr = 0;
    5092 f->generation = 0;
    5093 if (node_table_init(&f->name_table) == -1)
    5094 goto out_free_session;
    5095
    5096 if (node_table_init(&f->id_table) == -1)
    5097 goto out_free_name_table;
    5098
    5099 pthread_mutex_init(&f->lock, NULL);
    5100
    5101 root = alloc_node(f);
    5102 if (root == NULL) {
    5103 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    5104 goto out_free_id_table;
    5105 }
    5106 if (lru_enabled(f)) {
    5107 struct node_lru *lnode = node_lru(root);
    5108 init_list_head(&lnode->lru);
    5109 }
    5110
    5111 strcpy(root->inline_name, "/");
    5112 root->name = root->inline_name;
    5113 root->parent = NULL;
    5114 root->nodeid = FUSE_ROOT_ID;
    5115 inc_nlookup(root);
    5116 hash_id(f, root);
    5117
    5118 return f;
    5119
    5120out_free_id_table:
    5121 free(f->id_table.array);
    5122out_free_name_table:
    5123 free(f->name_table.array);
    5124out_free_session:
    5125 fuse_session_destroy(f->se);
    5126out_free_fs:
    5127 free(f->fs);
    5128 free(f->conf.modules);
    5129out_delete_context_key:
    5130 fuse_delete_context_key();
    5131out_free:
    5132 free(f);
    5133out:
    5134 return NULL;
    5135}
    5136
    5137/* Emulates 3.0-style fuse_new(), which processes --help */
    5138FUSE_SYMVER("_fuse_new_30", "_fuse_new@FUSE_3.0")
    5139struct fuse *_fuse_new_30(struct fuse_args *args,
    5140 const struct fuse_operations *op,
    5141 size_t op_size,
    5142 struct libfuse_version *version,
    5143 void *user_data)
    5144{
    5145 struct fuse_config conf = {0};
    5146
    5147 const struct fuse_opt opts[] = {
    5148 FUSE_LIB_OPT("-h", show_help, 1),
    5149 FUSE_LIB_OPT("--help", show_help, 1),
    5151 };
    5152
    5153 if (fuse_opt_parse(args, &conf, opts,
    5154 fuse_lib_opt_proc) == -1)
    5155 return NULL;
    5156
    5157 if (conf.show_help) {
    5158 fuse_lib_help(args);
    5159 return NULL;
    5160 } else
    5161 return _fuse_new_31(args, op, op_size, version, user_data);
    5162}
    5163
    5164/* ABI compat version */
    5165struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
    5166 size_t op_size, void *user_data);
    5167FUSE_SYMVER("fuse_new_31", "fuse_new@FUSE_3.1")
    5168struct fuse *fuse_new_31(struct fuse_args *args,
    5169 const struct fuse_operations *op,
    5170 size_t op_size, void *user_data)
    5171{
    5172 /* unknown version */
    5173 struct libfuse_version version = { 0 };
    5174
    5175 return _fuse_new_31(args, op, op_size, &version, user_data);
    5176}
    5177
    5178/*
    5179 * ABI compat version
    5180 * Emulates 3.0-style fuse_new(), which processes --help
    5181 */
    5182struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op,
    5183 size_t op_size, void *user_data);
    5184FUSE_SYMVER("fuse_new_30", "fuse_new@FUSE_3.0")
    5185struct fuse *fuse_new_30(struct fuse_args *args,
    5186 const struct fuse_operations *op,
    5187 size_t op_size, void *user_data)
    5188{
    5189 struct fuse_config conf = {0};
    5190
    5191 const struct fuse_opt opts[] = {
    5192 FUSE_LIB_OPT("-h", show_help, 1),
    5193 FUSE_LIB_OPT("--help", show_help, 1),
    5195 };
    5196
    5197 if (fuse_opt_parse(args, &conf, opts,
    5198 fuse_lib_opt_proc) == -1)
    5199 return NULL;
    5200
    5201 if (conf.show_help) {
    5202 fuse_lib_help(args);
    5203 return NULL;
    5204 } else
    5205 return fuse_new_31(args, op, op_size, user_data);
    5206}
    5207
    5208
    5209void fuse_destroy(struct fuse *f)
    5210{
    5211 size_t i;
    5212
    5213 if (f->conf.intr && f->intr_installed)
    5214 fuse_restore_intr_signal(f->conf.intr_signal);
    5215
    5216 if (f->fs) {
    5217 fuse_create_context(f);
    5218
    5219 for (i = 0; i < f->id_table.size; i++) {
    5220 struct node *node;
    5221
    5222 for (node = f->id_table.array[i]; node != NULL;
    5223 node = node->id_next) {
    5224 if (node->is_hidden) {
    5225 char *path;
    5226 if (try_get_path(f, node->nodeid, NULL, &path, NULL, false) == 0) {
    5227 fuse_fs_unlink(f->fs, path);
    5228 free(path);
    5229 }
    5230 }
    5231 }
    5232 }
    5233 }
    5234 for (i = 0; i < f->id_table.size; i++) {
    5235 struct node *node;
    5236 struct node *next;
    5237
    5238 for (node = f->id_table.array[i]; node != NULL; node = next) {
    5239 next = node->id_next;
    5240 free_node(f, node);
    5241 f->id_table.use--;
    5242 }
    5243 }
    5244 assert(list_empty(&f->partial_slabs));
    5245 assert(list_empty(&f->full_slabs));
    5246
    5247 while (fuse_modules) {
    5248 fuse_put_module(fuse_modules);
    5249 }
    5250 free(f->id_table.array);
    5251 free(f->name_table.array);
    5252 pthread_mutex_destroy(&f->lock);
    5253 fuse_session_destroy(f->se);
    5254 free(f->fs);
    5255 free(f->conf.modules);
    5256 free(f);
    5257 fuse_delete_context_key();
    5258}
    5259
    5260int fuse_mount(struct fuse *f, const char *mountpoint) {
    5261 return fuse_session_mount(fuse_get_session(f), mountpoint);
    5262}
    5263
    5264
    5265void fuse_unmount(struct fuse *f) {
    5267}
    5268
    5270{
    5271 return FUSE_VERSION;
    5272}
    5273
    5274const char *fuse_pkgversion(void)
    5275{
    5276 return PACKAGE_VERSION;
    5277}
    int fuse_getgroups(int size, gid_t list[])
    Definition fuse.c:4721
    int fuse_mount(struct fuse *f, const char *mountpoint)
    Definition fuse.c:5260
    int fuse_interrupted(void)
    Definition fuse.c:4730
    void fuse_destroy(struct fuse *f)
    Definition fuse.c:5209
    int fuse_start_cleanup_thread(struct fuse *fuse)
    Definition fuse.c:4973
    int fuse_invalidate_path(struct fuse *f, const char *path)
    Definition fuse.c:4740
    struct fuse_fs *(* fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[])
    Definition fuse.h:1403
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    int fuse_loop(struct fuse *f)
    Definition fuse.c:4644
    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:93
    void fuse_exit(struct fuse *f)
    Definition fuse.c:4706
    int fuse_clean_cache(struct fuse *fuse)
    Definition fuse.c:4498
    void fuse_lib_help(struct fuse_args *args)
    Definition fuse.c:4813
    struct fuse_session * fuse_get_session(struct fuse *f)
    Definition fuse.c:4588
    void fuse_unmount(struct fuse *f)
    Definition fuse.c:5265
    struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
    Definition fuse.c:4923
    void fuse_stop_cleanup_thread(struct fuse *fuse)
    Definition fuse.c:4981
    fuse_fill_dir_flags
    Definition fuse.h:61
    fuse_readdir_flags
    Definition fuse.h:45
    void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_SPLICE_READ
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    @ FUSE_BUF_IS_FD
    #define FUSE_CAP_EXPORT_SUPPORT
    #define FUSE_CAP_POSIX_LOCKS
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    int fuse_version(void)
    Definition fuse.c:5269
    @ FUSE_BUF_SPLICE_MOVE
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_reply_poll(fuse_req_t req, unsigned revents)
    int fuse_reply_err(fuse_req_t req, int err)
    const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
    void * fuse_req_userdata(fuse_req_t req)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    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_session_exited(struct fuse_session *se)
    int fuse_req_interrupted(fuse_req_t req)
    int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
    int fuse_reply_readlink(fuse_req_t req, const char *link)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
    void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
    int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_lseek(fuse_req_t req, off_t off)
    int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_reply_xattr(fuse_req_t req, size_t count)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_KEY_KEEP
    Definition fuse_opt.h:145
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    enum fuse_buf_flags flags
    void * mem
    size_t size
    struct fuse_buf buf[1]
    uint32_t fmask
    Definition fuse.h:294
    int32_t show_help
    Definition fuse.h:285
    int32_t direct_io
    Definition fuse.h:232
    int32_t no_rofd_flush
    Definition fuse.h:303
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t intr_signal
    Definition fuse.h:161
    int32_t remember
    Definition fuse.h:173
    int32_t kernel_cache
    Definition fuse.h:251
    int32_t readdir_ino
    Definition fuse.h:213
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    int32_t set_mode
    Definition fuse.h:126
    int32_t auto_cache
    Definition fuse.h:259
    int32_t intr
    Definition fuse.h:154
    double negative_timeout
    Definition fuse.h:143
    int32_t set_gid
    Definition fuse.h:112
    int32_t set_uid
    Definition fuse.h:119
    int32_t hard_remove
    Definition fuse.h:191
    double attr_timeout
    Definition fuse.h:149
    uint32_t no_interrupt
    void * private_data
    Definition fuse.h:891
    uid_t uid
    Definition fuse.h:882
    pid_t pid
    Definition fuse.h:888
    struct fuse * fuse
    Definition fuse.h:879
    gid_t gid
    Definition fuse.h:885
    mode_t umask
    Definition fuse.h:894
    mode_t umask
    double entry_timeout
    fuse_ino_t ino
    uint64_t generation
    double attr_timeout
    struct stat attr
    uint64_t lock_owner
    uint32_t writepage
    Definition fuse_common.h:60
    uint32_t poll_events
    uint32_t cache_readdir
    Definition fuse_common.h:89
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t noflush
    Definition fuse_common.h:93
    uint32_t flush
    Definition fuse_common.h:74
    uint32_t direct_io
    Definition fuse_common.h:63
    uint32_t keep_cache
    Definition fuse_common.h:69
    void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
    void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
    int(* mknod)(const char *, mode_t, dev_t)
    Definition fuse.h:385
    int(* open)(const char *, struct fuse_file_info *)
    Definition fuse.h:492
    int(* readlink)(const char *, char *, size_t)
    Definition fuse.h:377
    int(* write)(const char *, const char *, size_t, off_t, struct fuse_file_info *)
    Definition fuse.h:515
    int(* fallocate)(const char *, int, off_t, off_t, struct fuse_file_info *)
    Definition fuse.h:834
    int(* read)(const char *, char *, size_t, off_t, struct fuse_file_info *)
    Definition fuse.h:503
    int(* symlink)(const char *, const char *)
    Definition fuse.h:402
    int(* write_buf)(const char *, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *)
    Definition fuse.h:787
    int(* release)(const char *, struct fuse_file_info *)
    Definition fuse.h:566
    int(* access)(const char *, int)
    Definition fuse.h:666
    int(* lock)(const char *, struct fuse_file_info *, int cmd, struct flock *)
    Definition fuse.h:710
    int(* fsyncdir)(const char *, int, struct fuse_file_info *)
    Definition fuse.h:637
    int(* mkdir)(const char *, mode_t)
    Definition fuse.h:393
    int(* chown)(const char *, uid_t, gid_t, struct fuse_file_info *fi)
    Definition fuse.h:433
    int(* unlink)(const char *)
    Definition fuse.h:396
    int(* flush)(const char *, struct fuse_file_info *)
    Definition fuse.h:552
    int(* listxattr)(const char *, char *, size_t)
    Definition fuse.h:582
    int(* truncate)(const char *, off_t, struct fuse_file_info *fi)
    Definition fuse.h:443
    int(* statfs)(const char *, struct statvfs *)
    Definition fuse.h:522
    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)
    Definition fuse.h:849
    int(* create)(const char *, mode_t, struct fuse_file_info *)
    Definition fuse.h:678
    int(* utimens)(const char *, const struct timespec tv[2], struct fuse_file_info *fi)
    Definition fuse.h:725
    off_t(* lseek)(const char *, off_t off, int whence, struct fuse_file_info *)
    Definition fuse.h:858
    int(* getxattr)(const char *, const char *, char *, size_t)
    Definition fuse.h:579
    int(* setxattr)(const char *, const char *, const char *, size_t, int)
    Definition fuse.h:576
    int(* poll)(const char *, struct fuse_file_info *, struct fuse_pollhandle *ph, unsigned *reventsp)
    Definition fuse.h:775
    int(* fsync)(const char *, int, struct fuse_file_info *)
    Definition fuse.h:573
    int(* chmod)(const char *, mode_t, struct fuse_file_info *fi)
    Definition fuse.h:423
    int(* opendir)(const char *, struct fuse_file_info *)
    Definition fuse.h:595
    int(* rmdir)(const char *)
    Definition fuse.h:399
    int(* statx)(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi)
    Definition fuse.h:868
    int(* releasedir)(const char *, struct fuse_file_info *)
    Definition fuse.h:627
    int(* getattr)(const char *, struct stat *, struct fuse_file_info *fi)
    Definition fuse.h:367
    int(* read_buf)(const char *, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *)
    Definition fuse.h:804
    int(* link)(const char *, const char *)
    Definition fuse.h:416
    int(* flock)(const char *, struct fuse_file_info *, int op)
    Definition fuse.h:824
    int(* removexattr)(const char *, const char *)
    Definition fuse.h:585
    int(* ioctl)(const char *, unsigned int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data)
    Definition fuse.h:756
    int(* rename)(const char *, const char *, unsigned int flags)
    Definition fuse.h:413
    int(* readdir)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags)
    Definition fuse.h:619
    void *(* init)(struct fuse_conn_info *conn, struct fuse_config *cfg)
    Definition fuse.h:647
    void(* destroy)(void *private_data)
    Definition fuse.h:655
    int(* bmap)(const char *, size_t blocksize, uint64_t *idx)
    Definition fuse.h:734
    fuse-3.18.3/doc/html/fuse__i_8h_source.html0000644000175000017500000012030015250106404017476 0ustar berndbernd 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 LGPL2.txt
    7*/
    8
    9#ifndef LIB_FUSE_I_H_
    10#define LIB_FUSE_I_H_
    11
    12#include "fuse.h"
    13#include "fuse_lowlevel.h"
    14#include "util.h"
    15
    16#include <pthread.h>
    17#include <semaphore.h>
    18#include <stdint.h>
    19#include <stdbool.h>
    20#include <errno.h>
    21#include <stdatomic.h>
    22
    23#define MIN(a, b) \
    24({ \
    25 typeof(a) _a = (a); \
    26 typeof(b) _b = (b); \
    27 _a < _b ? _a : _b; \
    28})
    29
    30struct mount_opts;
    31struct fuse_ring_pool;
    32
    33struct fuse_req {
    34 struct fuse_session *se;
    35 uint64_t unique;
    36 _Atomic int ref_cnt;
    37 pthread_mutex_t lock;
    38 struct fuse_ctx ctx;
    39 struct fuse_chan *ch;
    40 int interrupted;
    41 struct {
    42 unsigned int ioctl_64bit : 1;
    43 unsigned int is_uring : 1;
    44 unsigned int is_copy_file_range_64 : 1;
    45 } flags;
    46 union {
    47 struct {
    48 uint64_t unique;
    49 } i;
    50 struct {
    52 void *data;
    53 } ni;
    54 } u;
    55 struct fuse_req *next;
    56 struct fuse_req *prev;
    57};
    58
    59struct fuse_notify_req {
    60 uint64_t unique;
    61 void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t,
    62 const void *, const struct fuse_buf *);
    63 struct fuse_notify_req *next;
    64 struct fuse_notify_req *prev;
    65};
    66
    67struct fuse_session_uring {
    68 bool enable;
    69 unsigned int q_depth;
    70 struct fuse_ring_pool *pool;
    71};
    72
    73struct fuse_session {
    74 _Atomic(char *)mountpoint;
    75 int fd;
    76 struct fuse_custom_io *io;
    77 struct mount_opts *mo;
    78 int debug;
    79 int deny_others;
    80 struct fuse_lowlevel_ops op;
    81 int got_init;
    82 struct cuse_data *cuse_data;
    83 void *userdata;
    84 uid_t owner;
    85 struct fuse_conn_info conn;
    86 struct fuse_req list;
    87 struct fuse_req interrupts;
    88 pthread_mutex_t lock;
    89 int got_destroy;
    90 pthread_key_t pipe_key;
    91 int broken_splice_nonblock;
    92 uint64_t notify_ctr;
    93 struct fuse_notify_req notify_list;
    94 _Atomic size_t bufsize;
    95 int error;
    96
    97 /*
    98 * This is useful if any kind of ABI incompatibility is found at
    99 * a later version, to 'fix' it at run time.
    100 */
    101 struct libfuse_version version;
    102
    103 /* thread synchronization */
    104 _Atomic bool mt_exited;
    105 pthread_mutex_t mt_lock;
    106 sem_t mt_finish;
    107
    108 /* true if reading requests from /dev/fuse are handled internally */
    109 bool buf_reallocable;
    110
    111 /* io_uring */
    112 struct fuse_session_uring uring;
    113
    114 /*
    115 * conn->want and conn_want_ext options set by libfuse , needed
    116 * to correctly convert want to want_ext
    117 */
    118 uint32_t conn_want;
    119 uint64_t conn_want_ext;
    120};
    121
    122struct fuse_chan {
    123 pthread_mutex_t lock;
    124 int ctr;
    125 int fd;
    126};
    127
    136 char *name;
    137 fuse_module_factory_t factory;
    138 struct fuse_module *next;
    139 struct fusemod_so *so;
    140 int ctr;
    141};
    142
    151#if FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 12)
    152struct fuse_loop_config
    153{
    154 /* verififier that a correct struct was was passed. This is especially
    155 * needed, as versions below (3, 12) were using a public struct
    156 * (now called fuse_loop_config_v1), which was hard to extend with
    157 * additional parameters, without risking that file system implementations
    158 * would not have noticed and might either pass uninitialized members
    159 * or even too small structs.
    160 * fuse_loop_config_v1 has clone_fd at this offset, which should be either 0
    161 * or 1. v2 or even higher version just need to set a value here
    162 * which not conflicting and very unlikely as having been set by
    163 * file system implementation.
    164 */
    165 int version_id;
    166
    171 int clone_fd;
    184
    190 unsigned int max_threads;
    191};
    192#endif
    193
    194/* ----------------------------------------------------------- *
    195 * Channel interface (when using -o clone_fd) *
    196 * ----------------------------------------------------------- */
    197
    204struct fuse_chan *fuse_chan_get(struct fuse_chan *ch);
    205
    211void fuse_chan_put(struct fuse_chan *ch);
    212
    213struct mount_opts *parse_mount_opts(struct fuse_args *args);
    214void destroy_mount_opts(struct mount_opts *mo);
    215void fuse_mount_version(void);
    216unsigned get_max_read(struct mount_opts *o);
    217void fuse_kern_unmount(const char *mountpoint, int fd);
    218int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo);
    219
    220int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
    221 int count);
    222void fuse_free_req(fuse_req_t req);
    223void list_init_req(struct fuse_req *req);
    224
    225void _cuse_lowlevel_init(fuse_req_t req, const fuse_ino_t nodeid,
    226 const void *req_header, const void *req_payload);
    227void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg);
    228
    229int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg);
    230
    231void fuse_buf_free(struct fuse_buf *buf);
    232
    233int fuse_session_receive_buf_internal(struct fuse_session *se,
    234 struct fuse_buf *buf,
    235 struct fuse_chan *ch);
    236void fuse_session_process_buf_internal(struct fuse_session *se,
    237 const struct fuse_buf *buf,
    238 struct fuse_chan *ch);
    239
    240struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
    241 size_t op_size, void *private_data);
    242int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config);
    243int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config);
    244
    250int fuse_loop_cfg_verify(struct fuse_loop_config *config);
    251
    252
    253/*
    254 * This can be changed dynamically on recent kernels through the
    255 * /proc/sys/fs/fuse/max_pages_limit interface.
    256 *
    257 * Older kernels will always use the default value.
    258 */
    259#define FUSE_DEFAULT_MAX_PAGES_LIMIT 256
    260#define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32
    261
    262/* room needed in buffer to accommodate header */
    263#define FUSE_BUFFER_HEADER_SIZE 0x1000
    264
    265
    266#endif /* LIB_FUSE_I_H_*/
    struct fuse_fs *(* fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[])
    Definition fuse.h:1403
    void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
    struct fuse_req * fuse_req_t
    uint64_t fuse_ino_t
    unsigned int max_threads
    Definition fuse_i.h:190
    unsigned int max_idle_threads
    fuse-3.18.3/doc/html/fuse__log_8c_source.html0000644000175000017500000003171515250106404020035 0ustar berndbernd libfuse: lib/fuse_log.c Source File
    libfuse
    fuse_log.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2019 Red Hat, Inc.
    4
    5 Logging API.
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt
    9*/
    10
    11#include "fuse_log.h"
    12
    13#include <stdio.h>
    14#include <stdbool.h>
    15#include <syslog.h>
    16#include <stdarg.h>
    17
    18#define MAX_SYSLOG_LINE_LEN 512
    19
    20static bool to_syslog = false;
    21
    22static void default_log_func(enum fuse_log_level level, const char *fmt, va_list ap)
    23{
    24 if (to_syslog)
    25 vsyslog(level, fmt, ap);
    26 else
    27 vfprintf(stderr, fmt, ap);
    28}
    29
    30static fuse_log_func_t log_func = default_log_func;
    31
    33{
    34 if (!func)
    35 func = default_log_func;
    36
    37 log_func = func;
    38}
    39
    40void fuse_log(enum fuse_log_level level, const char *fmt, ...)
    41{
    42 va_list ap;
    43
    44 va_start(ap, fmt);
    45 log_func(level, fmt, ap);
    46 va_end(ap);
    47}
    48
    49void fuse_log_enable_syslog(const char *ident, int option, int facility)
    50{
    51 to_syslog = true;
    52
    53 openlog(ident, option, facility);
    54}
    55
    57{
    58 closelog();
    59}
    void fuse_log_close_syslog(void)
    Definition fuse_log.c:56
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void(* fuse_log_func_t)(enum fuse_log_level level, const char *fmt, va_list ap)
    Definition fuse_log.h:52
    void void fuse_log_enable_syslog(const char *ident, int option, int facility)
    Definition fuse_log.c:49
    fuse_log_level
    Definition fuse_log.h:28
    void fuse_set_log_func(fuse_log_func_t func)
    Definition fuse_log.c:32
    fuse-3.18.3/doc/html/fuse__loop_8c_source.html0000644000175000017500000002464615250106404020232 0ustar berndbernd libfuse: lib/fuse_loop.c Source File
    libfuse
    fuse_loop.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Implementation of the single-threaded FUSE session loop.
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt
    9*/
    10
    11#include "fuse_config.h"
    12#include "fuse_lowlevel.h"
    13#include "fuse_i.h"
    14#include "fuse_uring_i.h"
    15#include <stdio.h>
    16#include <stdlib.h>
    17#include <errno.h>
    18
    19int fuse_session_loop(struct fuse_session *se)
    20{
    21 int res = 0;
    22 struct fuse_buf fbuf = {
    23 .mem = NULL,
    24 };
    25
    26 while (!fuse_session_exited(se)) {
    27 res = fuse_session_receive_buf_internal(se, &fbuf, NULL);
    28
    29 if (res == -EINTR)
    30 continue;
    31 if (res <= 0)
    32 break;
    33
    34 fuse_session_process_buf(se, &fbuf);
    35 }
    36
    37 fuse_buf_free(&fbuf);
    38 if(res > 0)
    39 /* No error, just the length of the most recently read
    40 request */
    41 res = 0;
    42 if(se->error != 0)
    43 res = se->error;
    44
    45 if (se->uring.pool)
    46 fuse_uring_stop(se);
    47 return res;
    48}
    void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
    int fuse_session_exited(struct fuse_session *se)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    fuse-3.18.3/doc/html/fuse__loop__mt_8c_source.html0000644000175000017500000024557615250106404021100 0ustar berndbernd libfuse: lib/fuse_loop_mt.c Source File
    libfuse
    fuse_loop_mt.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Implementation of the multi-threaded FUSE session loop.
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt.
    9*/
    10
    11#define _GNU_SOURCE
    12
    13#include "fuse_config.h"
    14#include "fuse_lowlevel.h"
    15#include "fuse_misc.h"
    16#include "fuse_kernel.h"
    17#include "fuse_i.h"
    18#include "fuse_uring_i.h"
    19#include "util.h"
    20
    21#include <stdio.h>
    22#include <stdlib.h>
    23#include <string.h>
    24#include <unistd.h>
    25#include <signal.h>
    26#include <semaphore.h>
    27#include <errno.h>
    28#include <sys/time.h>
    29#include <sys/ioctl.h>
    30#include <assert.h>
    31#include <limits.h>
    32
    33/* Environment var controlling the thread stack size */
    34#define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK"
    35
    36#define FUSE_LOOP_MT_V2_IDENTIFIER INT_MAX - 2
    37#define FUSE_LOOP_MT_DEF_CLONE_FD 0
    38#define FUSE_LOOP_MT_DEF_MAX_THREADS 10
    39#define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled
    40 * by default */
    41
    42/* an arbitrary large value that cannot be valid */
    43#define FUSE_LOOP_MT_MAX_THREADS (100U * 1000)
    44
    45struct fuse_worker {
    46 struct fuse_worker *prev;
    47 struct fuse_worker *next;
    48 pthread_t thread_id;
    49
    50 // We need to include fuse_buf so that we can properly free
    51 // it when a thread is terminated by pthread_cancel().
    52 struct fuse_buf fbuf;
    53 struct fuse_chan *ch;
    54 struct fuse_mt *mt;
    55};
    56
    57/* synchronization via se->mt_lock */
    58struct fuse_mt {
    59 int numworker;
    60 int numavail;
    61 struct fuse_session *se;
    62 struct fuse_worker main;
    63 int error;
    64 int clone_fd;
    65 int max_idle;
    66 int max_threads;
    67};
    68
    69static struct fuse_chan *fuse_chan_new(int fd)
    70{
    71 struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch));
    72 if (ch == NULL) {
    73 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n");
    74 return NULL;
    75 }
    76
    77 memset(ch, 0, sizeof(*ch));
    78 ch->fd = fd;
    79 ch->ctr = 1;
    80 pthread_mutex_init(&ch->lock, NULL);
    81
    82 return ch;
    83}
    84
    85struct fuse_chan *fuse_chan_get(struct fuse_chan *ch)
    86{
    87 assert(ch->ctr > 0);
    88 pthread_mutex_lock(&ch->lock);
    89 ch->ctr++;
    90 pthread_mutex_unlock(&ch->lock);
    91
    92 return ch;
    93}
    94
    95void fuse_chan_put(struct fuse_chan *ch)
    96{
    97 if (ch == NULL)
    98 return;
    99 pthread_mutex_lock(&ch->lock);
    100 ch->ctr--;
    101 if (!ch->ctr) {
    102 pthread_mutex_unlock(&ch->lock);
    103 close(ch->fd);
    104 pthread_mutex_destroy(&ch->lock);
    105 free(ch);
    106 } else
    107 pthread_mutex_unlock(&ch->lock);
    108}
    109
    110static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next)
    111{
    112 struct fuse_worker *prev = next->prev;
    113 w->next = next;
    114 w->prev = prev;
    115 prev->next = w;
    116 next->prev = w;
    117}
    118
    119static void list_del_worker(struct fuse_worker *w)
    120{
    121 struct fuse_worker *prev = w->prev;
    122 struct fuse_worker *next = w->next;
    123 prev->next = next;
    124 next->prev = prev;
    125}
    126
    127static int fuse_loop_start_thread(struct fuse_mt *mt);
    128
    129static void *fuse_do_work(void *data)
    130{
    131 struct fuse_worker *w = (struct fuse_worker *) data;
    132 struct fuse_mt *mt = w->mt;
    133 struct fuse_session *se = mt->se;
    134
    135 fuse_set_thread_name("fuse_worker");
    136
    137 while (!fuse_session_exited(se)) {
    138 int isforget = 0;
    139 int res;
    140
    141 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    142 res = fuse_session_receive_buf_internal(se, &w->fbuf, w->ch);
    143 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    144 if (res == -EINTR)
    145 continue;
    146 if (res <= 0) {
    147 if (res < 0) {
    149 mt->error = res;
    150 }
    151 break;
    152 }
    153
    154 pthread_mutex_lock(&se->mt_lock);
    155 if (fuse_session_exited(se)) {
    156 pthread_mutex_unlock(&se->mt_lock);
    157 return NULL;
    158 }
    159
    160 /*
    161 * This disgusting hack is needed so that zillions of threads
    162 * are not created on a burst of FORGET messages
    163 */
    164 if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) {
    165 struct fuse_in_header *in = w->fbuf.mem;
    166
    167 if (in->opcode == FUSE_FORGET ||
    168 in->opcode == FUSE_BATCH_FORGET)
    169 isforget = 1;
    170 }
    171
    172 if (!isforget)
    173 mt->numavail--;
    174 if (mt->numavail == 0 && mt->numworker < mt->max_threads &&
    175 likely(se->got_init))
    176 fuse_loop_start_thread(mt);
    177 pthread_mutex_unlock(&se->mt_lock);
    178
    179 fuse_session_process_buf_internal(se, &w->fbuf, w->ch);
    180
    181 pthread_mutex_lock(&se->mt_lock);
    182 if (!isforget)
    183 mt->numavail++;
    184
    185 /* creating and destroying threads is rather expensive - and there is
    186 * not much gain from destroying existing threads. It is therefore
    187 * discouraged to set max_idle to anything else than -1. If there
    188 * is indeed a good reason to destruct threads it should be done
    189 * delayed, a moving average might be useful for that.
    190 */
    191 if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) {
    192 if (fuse_session_exited(se)) {
    193 pthread_mutex_unlock(&se->mt_lock);
    194 return NULL;
    195 }
    196 list_del_worker(w);
    197 mt->numavail--;
    198 mt->numworker--;
    199 pthread_mutex_unlock(&se->mt_lock);
    200
    201 pthread_detach(w->thread_id);
    202 fuse_buf_free(&w->fbuf);
    203 fuse_chan_put(w->ch);
    204 free(w);
    205 return NULL;
    206 }
    207 pthread_mutex_unlock(&se->mt_lock);
    208 }
    209
    210 sem_post(&se->mt_finish);
    211 return NULL;
    212}
    213
    214int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg)
    215{
    216 sigset_t oldset;
    217 sigset_t newset;
    218 int res;
    219 pthread_attr_t attr;
    220 char *stack_size;
    221
    222 /* Override default stack size
    223 * XXX: This should ideally be a parameter option. It is rather
    224 * well hidden here.
    225 */
    226 pthread_attr_init(&attr);
    227 stack_size = getenv(ENVNAME_THREAD_STACK);
    228 if (stack_size) {
    229 long size;
    230
    231 res = libfuse_strtol(stack_size, &size);
    232 if (res)
    233 fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n",
    234 stack_size);
    235 else if (pthread_attr_setstacksize(&attr, size))
    236 fuse_log(FUSE_LOG_ERR, "fuse: could not set stack size: %ld\n",
    237 size);
    238 }
    239
    240 /* Disallow signal reception in worker threads */
    241 sigemptyset(&newset);
    242 sigaddset(&newset, SIGTERM);
    243 sigaddset(&newset, SIGINT);
    244 sigaddset(&newset, SIGHUP);
    245 sigaddset(&newset, SIGQUIT);
    246 pthread_sigmask(SIG_BLOCK, &newset, &oldset);
    247 res = pthread_create(thread_id, &attr, func, arg);
    248 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    249 pthread_attr_destroy(&attr);
    250 if (res != 0) {
    251 fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n",
    252 strerror(res));
    253 return -1;
    254 }
    255
    256 return 0;
    257}
    258
    259static int fuse_clone_chan_fd_default(struct fuse_session *se)
    260{
    261 int res;
    262 int clonefd;
    263 uint32_t masterfd;
    264 const char *devname = "/dev/fuse";
    265
    266#ifndef O_CLOEXEC
    267#define O_CLOEXEC 0
    268#endif
    269 clonefd = open(devname, O_RDWR | O_CLOEXEC);
    270 if (clonefd == -1) {
    271 fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname,
    272 strerror(errno));
    273 return -1;
    274 }
    275 if (!O_CLOEXEC) {
    276 res = fcntl(clonefd, F_SETFD, FD_CLOEXEC);
    277 if (res == -1) {
    278 fuse_log(FUSE_LOG_ERR, "fuse: failed to set CLOEXEC: %s\n",
    279 strerror(errno));
    280 close(clonefd);
    281 return -1;
    282 }
    283 }
    284
    285 masterfd = se->fd;
    286 res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd);
    287 if (res == -1) {
    288 fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n",
    289 strerror(errno));
    290 close(clonefd);
    291 return -1;
    292 }
    293 return clonefd;
    294}
    295
    296static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt)
    297{
    298 int clonefd;
    299 struct fuse_session *se = mt->se;
    300 struct fuse_chan *newch;
    301
    302 if (se->io != NULL) {
    303 if (se->io->clone_fd != NULL)
    304 clonefd = se->io->clone_fd(se->fd);
    305 else
    306 return NULL;
    307 } else {
    308 clonefd = fuse_clone_chan_fd_default(se);
    309 }
    310 if (clonefd < 0)
    311 return NULL;
    312
    313 newch = fuse_chan_new(clonefd);
    314 if (newch == NULL)
    315 close(clonefd);
    316
    317 return newch;
    318}
    319
    320static int fuse_loop_start_thread(struct fuse_mt *mt)
    321{
    322 int res;
    323
    324 struct fuse_worker *w = malloc(sizeof(struct fuse_worker));
    325 if (!w) {
    326 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n");
    327 return -1;
    328 }
    329 memset(w, 0, sizeof(struct fuse_worker));
    330 w->fbuf.mem = NULL;
    331 w->mt = mt;
    332
    333 w->ch = NULL;
    334 if (mt->clone_fd) {
    335 w->ch = fuse_clone_chan(mt);
    336 if(!w->ch) {
    337 /* Don't attempt this again */
    338 fuse_log(FUSE_LOG_ERR, "fuse: trying to continue "
    339 "without -o clone_fd.\n");
    340 mt->clone_fd = 0;
    341 }
    342 }
    343
    344 res = fuse_start_thread(&w->thread_id, fuse_do_work, w);
    345 if (res == -1) {
    346 fuse_chan_put(w->ch);
    347 free(w);
    348 return -1;
    349 }
    350 list_add_worker(w, &mt->main);
    351 mt->numavail ++;
    352 mt->numworker ++;
    353
    354 return 0;
    355}
    356
    357static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w)
    358{
    359 pthread_join(w->thread_id, NULL);
    360 pthread_mutex_lock(&mt->se->mt_lock);
    361 list_del_worker(w);
    362 pthread_mutex_unlock(&mt->se->mt_lock);
    363 fuse_buf_free(&w->fbuf);
    364 fuse_chan_put(w->ch);
    365 free(w);
    366}
    367
    368int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config);
    369FUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12")
    370int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config)
    371{
    372int err;
    373 struct fuse_mt mt;
    374 struct fuse_worker *w;
    375 int created_config = 0;
    376
    377 if (config) {
    378 err = fuse_loop_cfg_verify(config);
    379 if (err)
    380 return err;
    381 } else {
    382 /* The caller does not care about parameters - use the default */
    383 config = fuse_loop_cfg_create();
    384 if (!config)
    385 return -ENOMEM;
    386 created_config = 1;
    387 }
    388
    389
    390 memset(&mt, 0, sizeof(struct fuse_mt));
    391 mt.se = se;
    392 mt.clone_fd = config->clone_fd;
    393 mt.error = 0;
    394 mt.numworker = 0;
    395 mt.numavail = 0;
    396 mt.max_idle = config->max_idle_threads;
    397 mt.max_threads = config->max_threads;
    398 mt.main.thread_id = pthread_self();
    399 mt.main.prev = mt.main.next = &mt.main;
    400
    401 pthread_mutex_lock(&se->mt_lock);
    402 err = fuse_loop_start_thread(&mt);
    403 pthread_mutex_unlock(&se->mt_lock);
    404 if (!err) {
    405 while (!fuse_session_exited(se))
    406 sem_wait(&se->mt_finish);
    407 if (se->debug)
    408 fuse_log(FUSE_LOG_DEBUG,
    409 "fuse: session exited, terminating workers\n");
    410
    411 pthread_mutex_lock(&se->mt_lock);
    412 for (w = mt.main.next; w != &mt.main; w = w->next)
    413 pthread_cancel(w->thread_id);
    414 pthread_mutex_unlock(&se->mt_lock);
    415
    416 while (mt.main.next != &mt.main)
    417 fuse_join_worker(&mt, mt.main.next);
    418
    419 err = mt.error;
    420
    421 if (se->uring.pool)
    422 fuse_uring_stop(se);
    423 }
    424
    425 if(se->error != 0)
    426 err = se->error;
    427
    428
    429 if (created_config) {
    430 fuse_loop_cfg_destroy(config);
    431 config = NULL;
    432 }
    433
    434 return err;
    435}
    436
    437int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1);
    438FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2")
    439int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1)
    440{
    441 int err;
    442 struct fuse_loop_config *config = NULL;
    443
    444 if (config_v1 != NULL) {
    445 /* convert the given v1 config */
    446 config = fuse_loop_cfg_create();
    447 if (config == NULL)
    448 return ENOMEM;
    449
    450 fuse_loop_cfg_convert(config, config_v1);
    451 }
    452
    453 err = fuse_session_loop_mt_312(se, config);
    454
    455 fuse_loop_cfg_destroy(config);
    456
    457 return err;
    458}
    459
    460
    461int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd);
    462FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0")
    463int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd)
    464{
    465 int err;
    466 struct fuse_loop_config *config = fuse_loop_cfg_create();
    467 if (!config)
    468 return -ENOMEM;
    469 if (clone_fd > 0)
    470 fuse_loop_cfg_set_clone_fd(config, clone_fd);
    471 err = fuse_session_loop_mt_312(se, config);
    472
    473 fuse_loop_cfg_destroy(config);
    474
    475 return err;
    476}
    477
    478struct fuse_loop_config *fuse_loop_cfg_create(void)
    479{
    480 struct fuse_loop_config *config = calloc(1, sizeof(*config));
    481 if (config == NULL)
    482 return NULL;
    483
    484 config->version_id = FUSE_LOOP_MT_V2_IDENTIFIER;
    485 config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS;
    486 config->max_threads = FUSE_LOOP_MT_DEF_MAX_THREADS;
    487 config->clone_fd = FUSE_LOOP_MT_DEF_CLONE_FD;
    488
    489 return config;
    490}
    491
    492void fuse_loop_cfg_destroy(struct fuse_loop_config *config)
    493{
    494 free(config);
    495}
    496
    497int fuse_loop_cfg_verify(struct fuse_loop_config *config)
    498{
    499 if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER)
    500 return -EINVAL;
    501
    502 return 0;
    503}
    504
    505void fuse_loop_cfg_convert(struct fuse_loop_config *config,
    506 struct fuse_loop_config_v1 *v1_conf)
    507{
    508 fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads);
    509
    510 fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd);
    511}
    512
    513void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config,
    514 unsigned int value)
    515{
    516 if (value > FUSE_LOOP_MT_MAX_THREADS) {
    517 if (value != UINT_MAX)
    518 fuse_log(FUSE_LOG_ERR,
    519 "Ignoring invalid max threads value "
    520 "%u > max (%u).\n", value,
    521 FUSE_LOOP_MT_MAX_THREADS);
    522 return;
    523 }
    524 config->max_idle_threads = value;
    525}
    526
    527void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config,
    528 unsigned int value)
    529{
    530 config->max_threads = value;
    531}
    532
    533void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config,
    534 unsigned int value)
    535{
    536 config->clone_fd = value;
    537}
    538
    @ FUSE_BUF_IS_FD
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_exit(struct fuse_session *se)
    int fuse_session_exited(struct fuse_session *se)
    enum fuse_buf_flags flags
    void * mem
    unsigned int max_threads
    Definition fuse_i.h:190
    unsigned int max_idle_threads
    fuse-3.18.3/doc/html/fuse__lowlevel_8c_source.html0000644000175000017500000313416515250106404021113 0ustar berndbernd libfuse: lib/fuse_lowlevel.c Source File
    libfuse
    fuse_lowlevel.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Implementation of (most of) the low-level FUSE API. The session loop
    6 functions are implemented in separate files.
    7
    8 This program can be distributed under the terms of the GNU LGPLv2.
    9 See the file LGPL2.txt
    10*/
    11
    12#define _GNU_SOURCE
    13
    14#include "fuse_config.h"
    15#include "fuse_i.h"
    16#include "fuse_kernel.h"
    17#include "fuse_opt.h"
    18#include "fuse_misc.h"
    19#include "mount_util.h"
    20#include "util.h"
    21#include "fuse_uring_i.h"
    22
    23#include <pthread.h>
    24#include <stdatomic.h>
    25#include <stdint.h>
    26#include <inttypes.h>
    27#include <stdbool.h>
    28#include <stdio.h>
    29#include <stdlib.h>
    30#include <stddef.h>
    31#include <stdalign.h>
    32#include <string.h>
    33#include <unistd.h>
    34#include <limits.h>
    35#include <errno.h>
    36#include <assert.h>
    37#include <sys/file.h>
    38#include <sys/ioctl.h>
    39#include <stdalign.h>
    40
    41#ifdef USDT_ENABLED
    42#include "usdt.h"
    43#endif
    44
    45#ifndef F_LINUX_SPECIFIC_BASE
    46#define F_LINUX_SPECIFIC_BASE 1024
    47#endif
    48#ifndef F_SETPIPE_SZ
    49#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
    50#endif
    51
    52#ifndef O_CLOEXEC
    53#define O_CLOEXEC 0
    54#endif
    55
    56#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
    57#define OFFSET_MAX 0x7fffffffffffffffLL
    58
    59struct fuse_pollhandle {
    60 uint64_t kh;
    61 struct fuse_session *se;
    62};
    63
    64static size_t pagesize;
    65
    66static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
    67{
    68 pagesize = getpagesize();
    69}
    70
    71#ifdef USDT_ENABLED
    72/* tracepoints */
    73static void trace_request_receive(int err)
    74{
    75 USDT(libfuse, request_receive, err);
    76}
    77
    78static void trace_request_process(unsigned int opcode, unsigned int unique)
    79{
    80 USDT(libfuse, request_process, opcode, unique);
    81}
    82
    83static void trace_request_reply(uint64_t unique, unsigned int len,
    84 int error, int reply_err)
    85{
    86 USDT(libfuse, request_reply, unique, len, error, reply_err);
    87}
    88#else
    89static void trace_request_receive(int err)
    90{
    91 (void)err;
    92}
    93
    94static void trace_request_process(unsigned int opcode, unsigned int unique)
    95{
    96 (void)opcode;
    97 (void)unique;
    98}
    99
    100static void trace_request_reply(uint64_t unique, unsigned int len,
    101 int error, int reply_err)
    102{
    103 (void)unique;
    104 (void)len;
    105 (void)error;
    106 (void)reply_err;
    107}
    108#endif
    109
    110static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
    111{
    112 attr->ino = stbuf->st_ino;
    113 attr->mode = stbuf->st_mode;
    114 attr->nlink = stbuf->st_nlink;
    115 attr->uid = stbuf->st_uid;
    116 attr->gid = stbuf->st_gid;
    117 attr->rdev = stbuf->st_rdev;
    118 attr->size = stbuf->st_size;
    119 attr->blksize = stbuf->st_blksize;
    120 attr->blocks = stbuf->st_blocks;
    121 attr->atime = stbuf->st_atime;
    122 attr->mtime = stbuf->st_mtime;
    123 attr->ctime = stbuf->st_ctime;
    124 attr->atimensec = ST_ATIM_NSEC(stbuf);
    125 attr->mtimensec = ST_MTIM_NSEC(stbuf);
    126 attr->ctimensec = ST_CTIM_NSEC(stbuf);
    127}
    128
    129static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
    130{
    131 stbuf->st_mode = attr->mode;
    132 stbuf->st_uid = attr->uid;
    133 stbuf->st_gid = attr->gid;
    134 stbuf->st_size = attr->size;
    135 stbuf->st_atime = attr->atime;
    136 stbuf->st_mtime = attr->mtime;
    137 stbuf->st_ctime = attr->ctime;
    138 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
    139 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
    140 ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
    141}
    142
    143static size_t iov_length(const struct iovec *iov, size_t count)
    144{
    145 size_t seg;
    146 size_t ret = 0;
    147
    148 for (seg = 0; seg < count; seg++)
    149 ret += iov[seg].iov_len;
    150 return ret;
    151}
    152
    153void list_init_req(struct fuse_req *req)
    154{
    155 req->next = req;
    156 req->prev = req;
    157}
    158
    159static void list_del_req(struct fuse_req *req)
    160{
    161 struct fuse_req *prev = req->prev;
    162 struct fuse_req *next = req->next;
    163 prev->next = next;
    164 next->prev = prev;
    165}
    166
    167static void list_add_req(struct fuse_req *req, struct fuse_req *next)
    168{
    169 struct fuse_req *prev = next->prev;
    170 req->next = next;
    171 req->prev = prev;
    172 prev->next = req;
    173 next->prev = req;
    174}
    175
    176static void destroy_req(fuse_req_t req)
    177{
    178 if (req->flags.is_uring) {
    179 fuse_log(FUSE_LOG_ERR, "Refusing to destruct uring req\n");
    180 return;
    181 }
    182 assert(req->ch == NULL);
    183 pthread_mutex_destroy(&req->lock);
    184 free(req);
    185}
    186
    187void fuse_free_req(fuse_req_t req)
    188{
    189 int ctr;
    190 struct fuse_session *se = req->se;
    191
    192 /* XXX: for now no support for interrupts with io-uring
    193 * It actually might work already, though. But then would add
    194 * a lock across ring queues.
    195 */
    196 if (se->conn.no_interrupt || req->flags.is_uring) {
    197 ctr = --req->ref_cnt;
    198 fuse_chan_put(req->ch);
    199 req->ch = NULL;
    200 } else {
    201 pthread_mutex_lock(&se->lock);
    202 req->u.ni.func = NULL;
    203 req->u.ni.data = NULL;
    204 list_del_req(req);
    205 ctr = --req->ref_cnt;
    206 fuse_chan_put(req->ch);
    207 req->ch = NULL;
    208 pthread_mutex_unlock(&se->lock);
    209 }
    210 if (!ctr)
    211 destroy_req(req);
    212}
    213
    214static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
    215{
    216 struct fuse_req *req;
    217
    218 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
    219 if (req == NULL) {
    220 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
    221 } else {
    222 req->se = se;
    223 req->ref_cnt = 1;
    224 list_init_req(req);
    225 pthread_mutex_init(&req->lock, NULL);
    226 }
    227
    228 return req;
    229}
    230
    231/*
    232 * Send data to fuse-kernel using an fd of the fuse device.
    233 */
    234static int fuse_write_msg_dev(struct fuse_session *se, struct fuse_chan *ch,
    235 struct iovec *iov, int count)
    236{
    237 ssize_t res;
    238 int err;
    239
    240 if (se->io != NULL)
    241
    242 /* se->io->writev is never NULL if se->io is not NULL as
    243 * specified by fuse_session_custom_io()
    244 */
    245 res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
    246 se->userdata);
    247 else
    248 res = writev(ch ? ch->fd : se->fd, iov, count);
    249
    250 if (res == -1) {
    251 /* ENOENT means the operation was interrupted */
    252 err = errno;
    253 if (!fuse_session_exited(se) && err != ENOENT)
    254 perror("fuse: writing device");
    255 return -err;
    256 }
    257
    258 return 0;
    259}
    260
    261static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
    262 struct iovec *iov, int count, fuse_req_t req)
    263{
    264 struct fuse_out_header *out = iov[0].iov_base;
    265 int err;
    266 bool is_uring = req && req->flags.is_uring ? true : false;
    267
    268 if (!is_uring)
    269 assert(se != NULL);
    270 out->len = iov_length(iov, count);
    271
    272 if (se->debug) {
    273 if (out->unique == 0) {
    274 fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
    275 out->error, out->len);
    276 } else if (out->error) {
    277 fuse_log(FUSE_LOG_DEBUG,
    278 " unique: %llu, error: %i (%s), outsize: %i\n",
    279 (unsigned long long) out->unique, out->error,
    280 strerror(-out->error), out->len);
    281 } else {
    282 fuse_log(FUSE_LOG_DEBUG,
    283 " unique: %llu, success, outsize: %i\n",
    284 (unsigned long long) out->unique, out->len);
    285 }
    286 }
    287
    288 if (is_uring)
    289 err = fuse_send_msg_uring(req, iov, count);
    290 else
    291 err = fuse_write_msg_dev(se, ch, iov, count);
    292
    293 trace_request_reply(out->unique, out->len, out->error, err);
    294 return err;
    295}
    296
    297int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
    298 int count)
    299{
    300 struct fuse_out_header out;
    301
    302#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
    303 const char *str = strerrordesc_np(error * -1);
    304 if ((str == NULL && error != 0) || error > 0) {
    305#else
    306 if (error <= -1000 || error > 0) {
    307#endif
    308 fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
    309 error = -ERANGE;
    310 }
    311
    312 out.unique = req->unique;
    313 out.error = error;
    314
    315 iov[0].iov_base = &out;
    316 iov[0].iov_len = sizeof(struct fuse_out_header);
    317
    318 return fuse_send_msg(req->se, req->ch, iov, count, req);
    319}
    320
    321static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
    322 int count)
    323{
    324 int res;
    325
    326 res = fuse_send_reply_iov_nofree(req, error, iov, count);
    327 fuse_free_req(req);
    328 return res;
    329}
    330
    331static int send_reply(fuse_req_t req, int error, const void *arg,
    332 size_t argsize)
    333{
    334 if (req->flags.is_uring)
    335 return send_reply_uring(req, error, arg, argsize);
    336
    337 struct iovec iov[2];
    338 int count = 1;
    339 if (argsize) {
    340 iov[1].iov_base = (void *) arg;
    341 iov[1].iov_len = argsize;
    342 count++;
    343 }
    344 return send_reply_iov(req, error, iov, count);
    345}
    346
    347int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
    348{
    349 int res;
    350 struct iovec *padded_iov;
    351
    352 padded_iov = malloc((count + 1) * sizeof(struct iovec));
    353 if (padded_iov == NULL)
    354 return fuse_reply_err(req, ENOMEM);
    355
    356 memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
    357 count++;
    358
    359 res = send_reply_iov(req, 0, padded_iov, count);
    360 free(padded_iov);
    361
    362 return res;
    363}
    364
    365
    366/* `buf` is allowed to be empty so that the proper size may be
    367 allocated by the caller */
    368size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
    369 const char *name, const struct stat *stbuf, off_t off)
    370{
    371 (void)req;
    372 size_t namelen;
    373 size_t entlen;
    374 size_t entlen_padded;
    375 struct fuse_dirent *dirent;
    376
    377 namelen = strlen(name);
    378 entlen = FUSE_NAME_OFFSET + namelen;
    379 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
    380
    381 if ((buf == NULL) || (entlen_padded > bufsize))
    382 return entlen_padded;
    383
    384 dirent = (struct fuse_dirent*) buf;
    385 dirent->ino = stbuf->st_ino;
    386 dirent->off = off;
    387 dirent->namelen = namelen;
    388 dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
    389 memcpy(dirent->name, name, namelen);
    390 memset(dirent->name + namelen, 0, entlen_padded - entlen);
    391
    392 return entlen_padded;
    393}
    394
    395static void convert_statfs(const struct statvfs *stbuf,
    396 struct fuse_kstatfs *kstatfs)
    397{
    398 kstatfs->bsize = stbuf->f_bsize;
    399 kstatfs->frsize = stbuf->f_frsize;
    400 kstatfs->blocks = stbuf->f_blocks;
    401 kstatfs->bfree = stbuf->f_bfree;
    402 kstatfs->bavail = stbuf->f_bavail;
    403 kstatfs->files = stbuf->f_files;
    404 kstatfs->ffree = stbuf->f_ffree;
    405 kstatfs->namelen = stbuf->f_namemax;
    406}
    407
    408static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
    409{
    410 return send_reply(req, 0, arg, argsize);
    411}
    412
    413int fuse_reply_err(fuse_req_t req, int err)
    414{
    415 return send_reply(req, -err, NULL, 0);
    416}
    417
    419{
    420 if (req->flags.is_uring) {
    421 send_reply_uring(req, 0, NULL, 0);
    422 return;
    423 }
    424 fuse_free_req(req);
    425}
    426
    427static unsigned long calc_timeout_sec(double t)
    428{
    429 if (t > (double) ULONG_MAX)
    430 return ULONG_MAX;
    431 else if (t < 0.0)
    432 return 0;
    433 else
    434 return (unsigned long) t;
    435}
    436
    437static unsigned int calc_timeout_nsec(double t)
    438{
    439 double f = t - (double) calc_timeout_sec(t);
    440 if (f < 0.0)
    441 return 0;
    442 else if (f >= 0.999999999)
    443 return 999999999;
    444 else
    445 return (unsigned int) (f * 1.0e9);
    446}
    447
    448static void fill_entry(struct fuse_entry_out *arg,
    449 const struct fuse_entry_param *e)
    450{
    451 arg->nodeid = e->ino;
    452 arg->generation = e->generation;
    453 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
    454 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
    455 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
    456 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
    457 convert_stat(&e->attr, &arg->attr);
    458}
    459
    460/* `buf` is allowed to be empty so that the proper size may be
    461 allocated by the caller */
    462size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
    463 const char *name,
    464 const struct fuse_entry_param *e, off_t off)
    465{
    466 (void)req;
    467 size_t namelen;
    468 size_t entlen;
    469 size_t entlen_padded;
    470
    471 namelen = strlen(name);
    472 entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
    473 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
    474 if ((buf == NULL) || (entlen_padded > bufsize))
    475 return entlen_padded;
    476
    477 struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
    478 memset(&dp->entry_out, 0, sizeof(dp->entry_out));
    479 fill_entry(&dp->entry_out, e);
    480
    481 struct fuse_dirent *dirent = &dp->dirent;
    482 dirent->ino = e->attr.st_ino;
    483 dirent->off = off;
    484 dirent->namelen = namelen;
    485 dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
    486 memcpy(dirent->name, name, namelen);
    487 memset(dirent->name + namelen, 0, entlen_padded - entlen);
    488
    489 return entlen_padded;
    490}
    491
    492static void fill_open(struct fuse_open_out *arg,
    493 const struct fuse_file_info *f)
    494{
    495 arg->fh = f->fh;
    496 if (f->backing_id > 0) {
    497 arg->backing_id = f->backing_id;
    498 arg->open_flags |= FOPEN_PASSTHROUGH;
    499 }
    500 if (f->direct_io)
    501 arg->open_flags |= FOPEN_DIRECT_IO;
    502 if (f->keep_cache)
    503 arg->open_flags |= FOPEN_KEEP_CACHE;
    504 if (f->cache_readdir)
    505 arg->open_flags |= FOPEN_CACHE_DIR;
    506 if (f->nonseekable)
    507 arg->open_flags |= FOPEN_NONSEEKABLE;
    508 if (f->noflush)
    509 arg->open_flags |= FOPEN_NOFLUSH;
    511 arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
    512}
    513
    515{
    516 struct fuse_entry_out arg;
    517 size_t size = req->se->conn.proto_minor < 9 ?
    518 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
    519
    520 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
    521 negative entry */
    522 if (!e->ino && req->se->conn.proto_minor < 4)
    523 return fuse_reply_err(req, ENOENT);
    524
    525 memset(&arg, 0, sizeof(arg));
    526 fill_entry(&arg, e);
    527 return send_reply_ok(req, &arg, size);
    528}
    529
    531 const struct fuse_file_info *f)
    532{
    533 alignas(uint64_t) char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
    534 size_t entrysize = req->se->conn.proto_minor < 9 ?
    535 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
    536 struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
    537 struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
    538
    539 memset(buf, 0, sizeof(buf));
    540 fill_entry(earg, e);
    541 fill_open(oarg, f);
    542 return send_reply_ok(req, buf,
    543 entrysize + sizeof(struct fuse_open_out));
    544}
    545
    546int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
    547 double attr_timeout)
    548{
    549 struct fuse_attr_out arg;
    550 size_t size = req->se->conn.proto_minor < 9 ?
    551 FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
    552
    553 memset(&arg, 0, sizeof(arg));
    554 arg.attr_valid = calc_timeout_sec(attr_timeout);
    555 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
    556 convert_stat(attr, &arg.attr);
    557
    558 return send_reply_ok(req, &arg, size);
    559}
    560
    561int fuse_reply_readlink(fuse_req_t req, const char *linkname)
    562{
    563 return send_reply_ok(req, linkname, strlen(linkname));
    564}
    565
    567{
    568 struct fuse_backing_map map = { .fd = fd };
    569 int ret;
    570
    571 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map);
    572 if (ret <= 0) {
    573 fuse_log(FUSE_LOG_ERR, "fuse: passthrough_open: %s\n", strerror(errno));
    574 return 0;
    575 }
    576
    577 return ret;
    578}
    579
    580int fuse_passthrough_close(fuse_req_t req, int backing_id)
    581{
    582 int ret;
    583
    584 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id);
    585 if (ret < 0)
    586 fuse_log(FUSE_LOG_ERR, "fuse: passthrough_close: %s\n", strerror(errno));
    587
    588 return ret;
    589}
    590
    592{
    593 struct fuse_open_out arg;
    594
    595 memset(&arg, 0, sizeof(arg));
    596 fill_open(&arg, f);
    597 return send_reply_ok(req, &arg, sizeof(arg));
    598}
    599
    600static int do_fuse_reply_write(fuse_req_t req, size_t count)
    601{
    602 struct fuse_write_out arg;
    603
    604 memset(&arg, 0, sizeof(arg));
    605 arg.size = count;
    606
    607 return send_reply_ok(req, &arg, sizeof(arg));
    608}
    609
    610static int do_fuse_reply_copy(fuse_req_t req, size_t count)
    611{
    612 struct fuse_copy_file_range_out arg;
    613
    614 memset(&arg, 0, sizeof(arg));
    615 arg.bytes_copied = count;
    616
    617 return send_reply_ok(req, &arg, sizeof(arg));
    618}
    619
    620int fuse_reply_write(fuse_req_t req, size_t count)
    621{
    622 /*
    623 * This function is also used by FUSE_COPY_FILE_RANGE and its 64-bit
    624 * variant.
    625 */
    626 if (req->flags.is_copy_file_range_64)
    627 return do_fuse_reply_copy(req, count);
    628 else
    629 return do_fuse_reply_write(req, count);
    630}
    631
    632int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    633{
    634 return send_reply_ok(req, buf, size);
    635}
    636
    637static int fuse_send_data_iov_fallback(struct fuse_session *se,
    638 struct fuse_chan *ch,
    639 struct iovec *iov, int iov_count,
    640 struct fuse_bufvec *buf,
    641 size_t len, fuse_req_t req)
    642{
    643 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
    644 void *mbuf;
    645 int res;
    646
    647 /* Optimize common case */
    648 if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
    649 !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
    650 /* FIXME: also avoid memory copy if there are multiple buffers
    651 but none of them contain an fd */
    652
    653 iov[iov_count].iov_base = buf->buf[0].mem;
    654 iov[iov_count].iov_len = len;
    655 iov_count++;
    656 return fuse_send_msg(se, ch, iov, iov_count, req);
    657 }
    658
    659 res = posix_memalign(&mbuf, pagesize, len);
    660 if (res != 0)
    661 return res;
    662
    663 mem_buf.buf[0].mem = mbuf;
    664 res = fuse_buf_copy(&mem_buf, buf, 0);
    665 if (res < 0) {
    666 free(mbuf);
    667 return -res;
    668 }
    669 len = res;
    670
    671 iov[iov_count].iov_base = mbuf;
    672 iov[iov_count].iov_len = len;
    673 iov_count++;
    674 res = fuse_send_msg(se, ch, iov, iov_count, req);
    675 free(mbuf);
    676
    677 return res;
    678}
    679
    680struct fuse_ll_pipe {
    681 size_t size;
    682 int can_grow;
    683 int pipe[2];
    684};
    685
    686static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
    687{
    688 close(llp->pipe[0]);
    689 close(llp->pipe[1]);
    690 free(llp);
    691}
    692
    693#ifdef HAVE_SPLICE
    694#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
    695static int fuse_pipe(int fds[2])
    696{
    697 int rv = pipe(fds);
    698
    699 if (rv == -1)
    700 return rv;
    701
    702 if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
    703 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
    704 fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
    705 fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
    706 close(fds[0]);
    707 close(fds[1]);
    708 rv = -1;
    709 }
    710 return rv;
    711}
    712#else
    713static int fuse_pipe(int fds[2])
    714{
    715 return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
    716}
    717#endif
    718
    719static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
    720{
    721 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
    722 if (llp == NULL) {
    723 int res;
    724
    725 llp = malloc(sizeof(struct fuse_ll_pipe));
    726 if (llp == NULL)
    727 return NULL;
    728
    729 res = fuse_pipe(llp->pipe);
    730 if (res == -1) {
    731 free(llp);
    732 return NULL;
    733 }
    734
    735 /*
    736 *the default size is 16 pages on linux
    737 */
    738 llp->size = pagesize * 16;
    739 llp->can_grow = 1;
    740
    741 pthread_setspecific(se->pipe_key, llp);
    742 }
    743
    744 return llp;
    745}
    746#endif
    747
    748static void fuse_ll_clear_pipe(struct fuse_session *se)
    749{
    750 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
    751 if (llp) {
    752 pthread_setspecific(se->pipe_key, NULL);
    753 fuse_ll_pipe_free(llp);
    754 }
    755}
    756
    757#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
    758static int read_back(int fd, char *buf, size_t len)
    759{
    760 int res;
    761
    762 res = read(fd, buf, len);
    763 if (res == -1) {
    764 fuse_log(FUSE_LOG_ERR,
    765 "fuse: internal error: failed to read back from pipe: %s\n",
    766 strerror(errno));
    767 return -EIO;
    768 }
    769 if (res != len) {
    770 fuse_log(FUSE_LOG_ERR,
    771 "fuse: internal error: short read back from pipe: %i from %zd\n",
    772 res, len);
    773 return -EIO;
    774 }
    775 return 0;
    776}
    777
    778static int grow_pipe_to_max(int pipefd)
    779{
    780 int res;
    781 long max;
    782 long maxfd;
    783 char buf[32];
    784
    785 maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY | O_CLOEXEC);
    786 if (maxfd < 0)
    787 return -errno;
    788
    789 res = read(maxfd, buf, sizeof(buf) - 1);
    790 if (res < 0) {
    791 int saved_errno;
    792
    793 saved_errno = errno;
    794 close(maxfd);
    795 return -saved_errno;
    796 }
    797 close(maxfd);
    798 buf[res] = '\0';
    799
    800 res = libfuse_strtol(buf, &max);
    801 if (res)
    802 return res;
    803 res = fcntl(pipefd, F_SETPIPE_SZ, max);
    804 if (res < 0)
    805 return -errno;
    806 return max;
    807}
    808
    809static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
    810 struct iovec *iov, int iov_count,
    811 struct fuse_bufvec *buf, unsigned int flags,
    812 fuse_req_t req)
    813{
    814 int res;
    815 size_t len = fuse_buf_size(buf);
    816 struct fuse_out_header *out = iov[0].iov_base;
    817 struct fuse_ll_pipe *llp;
    818 int splice_flags;
    819 size_t pipesize;
    820 size_t total_buf_size;
    821 size_t idx;
    822 size_t headerlen;
    823 struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
    824
    825 if (se->broken_splice_nonblock)
    826 goto fallback;
    827
    828 if (flags & FUSE_BUF_NO_SPLICE)
    829 goto fallback;
    830
    831 total_buf_size = 0;
    832 for (idx = buf->idx; idx < buf->count; idx++) {
    833 total_buf_size += buf->buf[idx].size;
    834 if (idx == buf->idx)
    835 total_buf_size -= buf->off;
    836 }
    837 if (total_buf_size < 2 * pagesize)
    838 goto fallback;
    839
    840 if (se->conn.proto_minor < 14 ||
    841 !(se->conn.want_ext & FUSE_CAP_SPLICE_WRITE))
    842 goto fallback;
    843
    844 llp = fuse_ll_get_pipe(se);
    845 if (llp == NULL)
    846 goto fallback;
    847
    848
    849 headerlen = iov_length(iov, iov_count);
    850
    851 out->len = headerlen + len;
    852
    853 /*
    854 * Heuristic for the required pipe size, does not work if the
    855 * source contains less than page size fragments
    856 */
    857 pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
    858
    859 if (llp->size < pipesize) {
    860 if (llp->can_grow) {
    861 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
    862 if (res == -1) {
    863 res = grow_pipe_to_max(llp->pipe[0]);
    864 if (res > 0)
    865 llp->size = res;
    866 llp->can_grow = 0;
    867 goto fallback;
    868 }
    869 llp->size = res;
    870 }
    871 if (llp->size < pipesize)
    872 goto fallback;
    873 }
    874
    875
    876 res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
    877 if (res == -1)
    878 goto fallback;
    879
    880 if (res != headerlen) {
    881 res = -EIO;
    882 fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
    883 headerlen);
    884 goto clear_pipe;
    885 }
    886
    887 pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
    888 pipe_buf.buf[0].fd = llp->pipe[1];
    889
    890 res = fuse_buf_copy(&pipe_buf, buf,
    892 if (res < 0) {
    893 if (res == -EAGAIN || res == -EINVAL) {
    894 /*
    895 * Should only get EAGAIN on kernels with
    896 * broken SPLICE_F_NONBLOCK support (<=
    897 * 2.6.35) where this error or a short read is
    898 * returned even if the pipe itself is not
    899 * full
    900 *
    901 * EINVAL might mean that splice can't handle
    902 * this combination of input and output.
    903 */
    904 if (res == -EAGAIN)
    905 se->broken_splice_nonblock = 1;
    906
    907 pthread_setspecific(se->pipe_key, NULL);
    908 fuse_ll_pipe_free(llp);
    909 goto fallback;
    910 }
    911 res = -res;
    912 goto clear_pipe;
    913 }
    914
    915 if (res != 0 && res < len) {
    916 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
    917 void *mbuf;
    918 size_t now_len = res;
    919 /*
    920 * For regular files a short count is either
    921 * 1) due to EOF, or
    922 * 2) because of broken SPLICE_F_NONBLOCK (see above)
    923 *
    924 * For other inputs it's possible that we overflowed
    925 * the pipe because of small buffer fragments.
    926 */
    927
    928 res = posix_memalign(&mbuf, pagesize, len);
    929 if (res != 0)
    930 goto clear_pipe;
    931
    932 mem_buf.buf[0].mem = mbuf;
    933 mem_buf.off = now_len;
    934 res = fuse_buf_copy(&mem_buf, buf, 0);
    935 if (res > 0) {
    936 char *tmpbuf;
    937 size_t extra_len = res;
    938 /*
    939 * Trickiest case: got more data. Need to get
    940 * back the data from the pipe and then fall
    941 * back to regular write.
    942 */
    943 tmpbuf = malloc(headerlen);
    944 if (tmpbuf == NULL) {
    945 free(mbuf);
    946 res = ENOMEM;
    947 goto clear_pipe;
    948 }
    949 res = read_back(llp->pipe[0], tmpbuf, headerlen);
    950 free(tmpbuf);
    951 if (res != 0) {
    952 free(mbuf);
    953 goto clear_pipe;
    954 }
    955 res = read_back(llp->pipe[0], mbuf, now_len);
    956 if (res != 0) {
    957 free(mbuf);
    958 goto clear_pipe;
    959 }
    960 len = now_len + extra_len;
    961 iov[iov_count].iov_base = mbuf;
    962 iov[iov_count].iov_len = len;
    963 iov_count++;
    964 res = fuse_send_msg(se, ch, iov, iov_count, req);
    965 free(mbuf);
    966 return res;
    967 }
    968 free(mbuf);
    969 res = now_len;
    970 }
    971 len = res;
    972 out->len = headerlen + len;
    973
    974 if (se->debug) {
    975 fuse_log(FUSE_LOG_DEBUG,
    976 " unique: %llu, success, outsize: %i (splice)\n",
    977 (unsigned long long) out->unique, out->len);
    978 }
    979
    980 splice_flags = 0;
    981 if ((flags & FUSE_BUF_SPLICE_MOVE) &&
    982 (se->conn.want_ext & FUSE_CAP_SPLICE_MOVE))
    983 splice_flags |= SPLICE_F_MOVE;
    984
    985 if (se->io != NULL && se->io->splice_send != NULL) {
    986 res = se->io->splice_send(llp->pipe[0], NULL,
    987 ch ? ch->fd : se->fd, NULL, out->len,
    988 splice_flags, se->userdata);
    989 } else {
    990 res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
    991 out->len, splice_flags);
    992 }
    993 if (res == -1) {
    994 res = -errno;
    995 perror("fuse: splice from pipe");
    996 goto clear_pipe;
    997 }
    998 if (res != out->len) {
    999 res = -EIO;
    1000 fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
    1001 res, out->len);
    1002 goto clear_pipe;
    1003 }
    1004 return 0;
    1005
    1006clear_pipe:
    1007 fuse_ll_clear_pipe(se);
    1008 return res;
    1009
    1010fallback:
    1011 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len, req);
    1012}
    1013#else
    1014static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
    1015 struct iovec *iov, int iov_count,
    1016 struct fuse_bufvec *req_data, unsigned int flags,
    1017 fuse_req_t req)
    1018{
    1019 size_t len = fuse_buf_size(req_data);
    1020 (void) flags;
    1021
    1022 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, req_data, len, req);
    1023}
    1024#endif
    1025
    1027 enum fuse_buf_copy_flags flags)
    1028{
    1029 struct iovec iov[2];
    1030 struct fuse_out_header out;
    1031 int res;
    1032
    1033 if (req->flags.is_uring)
    1034 return fuse_reply_data_uring(req, bufv, flags);
    1035
    1036 iov[0].iov_base = &out;
    1037 iov[0].iov_len = sizeof(struct fuse_out_header);
    1038
    1039 out.unique = req->unique;
    1040 out.error = 0;
    1041
    1042 res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags, req);
    1043 if (res <= 0) {
    1044 fuse_free_req(req);
    1045 return res;
    1046 } else {
    1047 return fuse_reply_err(req, res);
    1048 }
    1049}
    1050
    1051int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    1052{
    1053 struct fuse_statfs_out arg;
    1054 size_t size = req->se->conn.proto_minor < 4 ?
    1055 FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
    1056
    1057 memset(&arg, 0, sizeof(arg));
    1058 convert_statfs(stbuf, &arg.st);
    1059
    1060 return send_reply_ok(req, &arg, size);
    1061}
    1062
    1063int fuse_reply_xattr(fuse_req_t req, size_t count)
    1064{
    1065 struct fuse_getxattr_out arg;
    1066
    1067 memset(&arg, 0, sizeof(arg));
    1068 arg.size = count;
    1069
    1070 return send_reply_ok(req, &arg, sizeof(arg));
    1071}
    1072
    1073int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
    1074{
    1075 struct fuse_lk_out arg;
    1076
    1077 memset(&arg, 0, sizeof(arg));
    1078 arg.lk.type = lock->l_type;
    1079 if (lock->l_type != F_UNLCK) {
    1080 arg.lk.start = lock->l_start;
    1081 if (lock->l_len == 0)
    1082 arg.lk.end = OFFSET_MAX;
    1083 else
    1084 arg.lk.end = lock->l_start + lock->l_len - 1;
    1085 }
    1086 arg.lk.pid = lock->l_pid;
    1087 return send_reply_ok(req, &arg, sizeof(arg));
    1088}
    1089
    1090int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
    1091{
    1092 struct fuse_bmap_out arg;
    1093
    1094 memset(&arg, 0, sizeof(arg));
    1095 arg.block = idx;
    1096
    1097 return send_reply_ok(req, &arg, sizeof(arg));
    1098}
    1099
    1100static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
    1101 size_t count)
    1102{
    1103 struct fuse_ioctl_iovec *fiov;
    1104 size_t i;
    1105
    1106 fiov = malloc(sizeof(fiov[0]) * count);
    1107 if (!fiov)
    1108 return NULL;
    1109
    1110 for (i = 0; i < count; i++) {
    1111 fiov[i].base = (uintptr_t) iov[i].iov_base;
    1112 fiov[i].len = iov[i].iov_len;
    1113 }
    1114
    1115 return fiov;
    1116}
    1117
    1119 const struct iovec *in_iov, size_t in_count,
    1120 const struct iovec *out_iov, size_t out_count)
    1121{
    1122 struct fuse_ioctl_out arg;
    1123 struct fuse_ioctl_iovec *in_fiov = NULL;
    1124 struct fuse_ioctl_iovec *out_fiov = NULL;
    1125 struct iovec iov[4];
    1126 size_t count = 1;
    1127 int res;
    1128
    1129 memset(&arg, 0, sizeof(arg));
    1130 arg.flags |= FUSE_IOCTL_RETRY;
    1131 arg.in_iovs = in_count;
    1132 arg.out_iovs = out_count;
    1133 iov[count].iov_base = &arg;
    1134 iov[count].iov_len = sizeof(arg);
    1135 count++;
    1136
    1137 if (req->se->conn.proto_minor < 16) {
    1138 if (in_count) {
    1139 iov[count].iov_base = (void *)in_iov;
    1140 iov[count].iov_len = sizeof(in_iov[0]) * in_count;
    1141 count++;
    1142 }
    1143
    1144 if (out_count) {
    1145 iov[count].iov_base = (void *)out_iov;
    1146 iov[count].iov_len = sizeof(out_iov[0]) * out_count;
    1147 count++;
    1148 }
    1149 } else {
    1150 /* Can't handle non-compat 64bit ioctls on 32bit */
    1151 if (sizeof(void *) == 4 && req->flags.ioctl_64bit) {
    1152 res = fuse_reply_err(req, EINVAL);
    1153 goto out;
    1154 }
    1155
    1156 if (in_count) {
    1157 in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
    1158 if (!in_fiov)
    1159 goto enomem;
    1160
    1161 iov[count].iov_base = (void *)in_fiov;
    1162 iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
    1163 count++;
    1164 }
    1165 if (out_count) {
    1166 out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
    1167 if (!out_fiov)
    1168 goto enomem;
    1169
    1170 iov[count].iov_base = (void *)out_fiov;
    1171 iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
    1172 count++;
    1173 }
    1174 }
    1175
    1176 res = send_reply_iov(req, 0, iov, count);
    1177out:
    1178 free(in_fiov);
    1179 free(out_fiov);
    1180
    1181 return res;
    1182
    1183enomem:
    1184 res = fuse_reply_err(req, ENOMEM);
    1185 goto out;
    1186}
    1187
    1188int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    1189{
    1190 struct fuse_ioctl_out arg;
    1191 struct iovec iov[3];
    1192 size_t count = 1;
    1193
    1194 memset(&arg, 0, sizeof(arg));
    1195 arg.result = result;
    1196 iov[count].iov_base = &arg;
    1197 iov[count].iov_len = sizeof(arg);
    1198 count++;
    1199
    1200 if (size) {
    1201 iov[count].iov_base = (char *) buf;
    1202 iov[count].iov_len = size;
    1203 count++;
    1204 }
    1205
    1206 return send_reply_iov(req, 0, iov, count);
    1207}
    1208
    1209int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
    1210 int count)
    1211{
    1212 struct iovec *padded_iov;
    1213 struct fuse_ioctl_out arg;
    1214 int res;
    1215
    1216 padded_iov = malloc((count + 2) * sizeof(struct iovec));
    1217 if (padded_iov == NULL)
    1218 return fuse_reply_err(req, ENOMEM);
    1219
    1220 memset(&arg, 0, sizeof(arg));
    1221 arg.result = result;
    1222 padded_iov[1].iov_base = &arg;
    1223 padded_iov[1].iov_len = sizeof(arg);
    1224
    1225 memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
    1226
    1227 res = send_reply_iov(req, 0, padded_iov, count + 2);
    1228 free(padded_iov);
    1229
    1230 return res;
    1231}
    1232
    1233int fuse_reply_poll(fuse_req_t req, unsigned revents)
    1234{
    1235 struct fuse_poll_out arg;
    1236
    1237 memset(&arg, 0, sizeof(arg));
    1238 arg.revents = revents;
    1239
    1240 return send_reply_ok(req, &arg, sizeof(arg));
    1241}
    1242
    1243int fuse_reply_lseek(fuse_req_t req, off_t off)
    1244{
    1245 struct fuse_lseek_out arg;
    1246
    1247 memset(&arg, 0, sizeof(arg));
    1248 arg.offset = off;
    1249
    1250 return send_reply_ok(req, &arg, sizeof(arg));
    1251}
    1252
    1253#ifdef HAVE_STATX
    1254int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx,
    1255 double attr_timeout)
    1256{
    1257 struct fuse_statx_out arg;
    1258
    1259 memset(&arg, 0, sizeof(arg));
    1260 arg.flags = flags;
    1261 arg.attr_valid = calc_timeout_sec(attr_timeout);
    1262 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
    1263 memcpy(&arg.stat, statx, sizeof(arg.stat));
    1264
    1265 return send_reply_ok(req, &arg, sizeof(arg));
    1266}
    1267#else
    1268int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx,
    1269 double attr_timeout)
    1270{
    1271 (void)req;
    1272 (void)flags;
    1273 (void)statx;
    1274 (void)attr_timeout;
    1275
    1276 return -ENOSYS;
    1277}
    1278#endif
    1279
    1280static void _do_lookup(fuse_req_t req, const fuse_ino_t nodeid,
    1281 const void *op_in, const void *in_payload)
    1282{
    1283 (void)op_in;
    1284
    1285 char *name = (char *)in_payload;
    1286
    1287 if (req->se->op.lookup)
    1288 req->se->op.lookup(req, nodeid, name);
    1289 else
    1290 fuse_reply_err(req, ENOSYS);
    1291}
    1292
    1293static void do_lookup(fuse_req_t req, const fuse_ino_t nodeid,
    1294 const void *inarg)
    1295{
    1296 _do_lookup(req, nodeid, NULL, inarg);
    1297}
    1298
    1299static void _do_forget(fuse_req_t req, const fuse_ino_t nodeid,
    1300 const void *op_in, const void *in_payload)
    1301{
    1302 (void)in_payload;
    1303
    1304 struct fuse_forget_in *arg = (struct fuse_forget_in *)op_in;
    1305
    1306 if (req->se->op.forget)
    1307 req->se->op.forget(req, nodeid, arg->nlookup);
    1308 else
    1309 fuse_reply_none(req);
    1310}
    1311
    1312static void do_forget(fuse_req_t req, const fuse_ino_t nodeid,
    1313 const void *inarg)
    1314{
    1315 _do_forget(req, nodeid, inarg, NULL);
    1316}
    1317
    1318static void _do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid,
    1319 const void *op_in, const void *in_payload)
    1320{
    1321 (void)nodeid;
    1322 unsigned int i;
    1323
    1324 const struct fuse_batch_forget_in *arg = op_in;
    1325 const struct fuse_forget_one *forgets = in_payload;
    1326
    1327 if (req->se->op.forget_multi) {
    1328 req->se->op.forget_multi(req, arg->count,
    1329 (struct fuse_forget_data *)in_payload);
    1330 } else if (req->se->op.forget) {
    1331 for (i = 0; i < arg->count; i++) {
    1332 const struct fuse_forget_one *forget = &forgets[i];
    1333 struct fuse_req *dummy_req;
    1334
    1335 dummy_req = fuse_ll_alloc_req(req->se);
    1336 if (dummy_req == NULL)
    1337 break;
    1338
    1339 dummy_req->unique = req->unique;
    1340 dummy_req->ctx = req->ctx;
    1341 dummy_req->ch = NULL;
    1342
    1343 req->se->op.forget(dummy_req, forget->nodeid,
    1344 forget->nlookup);
    1345 }
    1346 fuse_reply_none(req);
    1347 } else {
    1348 fuse_reply_none(req);
    1349 }
    1350}
    1351
    1352static void do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid,
    1353 const void *inarg)
    1354{
    1355 struct fuse_batch_forget_in *arg = (void *)inarg;
    1356 struct fuse_forget_one *param = (void *)PARAM(arg);
    1357
    1358 _do_batch_forget(req, nodeid, inarg, param);
    1359}
    1360
    1361static void _do_getattr(fuse_req_t req, const fuse_ino_t nodeid,
    1362 const void *op_in, const void *in_payload)
    1363{
    1364 struct fuse_getattr_in *arg = (struct fuse_getattr_in *)op_in;
    1365 (void)in_payload;
    1366
    1367 struct fuse_file_info *fip = NULL;
    1368 struct fuse_file_info fi;
    1369
    1370 if (req->se->conn.proto_minor >= 9) {
    1371 if (arg->getattr_flags & FUSE_GETATTR_FH) {
    1372 memset(&fi, 0, sizeof(fi));
    1373 fi.fh = arg->fh;
    1374 fip = &fi;
    1375 }
    1376 }
    1377
    1378 if (req->se->op.getattr)
    1379 req->se->op.getattr(req, nodeid, fip);
    1380 else
    1381 fuse_reply_err(req, ENOSYS);
    1382}
    1383
    1384static void do_getattr(fuse_req_t req, const fuse_ino_t nodeid,
    1385 const void *inarg)
    1386{
    1387 _do_getattr(req, nodeid, inarg, NULL);
    1388}
    1389
    1390static void _do_setattr(fuse_req_t req, const fuse_ino_t nodeid,
    1391 const void *op_in, const void *in_payload)
    1392{
    1393 (void)in_payload;
    1394 const struct fuse_setattr_in *arg = op_in;
    1395 uint32_t valid = arg->valid;
    1396
    1397 if (req->se->op.setattr) {
    1398 struct fuse_file_info *fi = NULL;
    1399 struct fuse_file_info fi_store;
    1400 struct stat stbuf;
    1401 memset(&stbuf, 0, sizeof(stbuf));
    1402 convert_attr(arg, &stbuf);
    1403 if (arg->valid & FATTR_FH) {
    1404 valid &= ~FATTR_FH;
    1405 memset(&fi_store, 0, sizeof(fi_store));
    1406 fi = &fi_store;
    1407 fi->fh = arg->fh;
    1408 }
    1409 valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
    1410 FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
    1411 FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
    1412 FUSE_SET_ATTR_KILL_SUID | FUSE_SET_ATTR_KILL_SGID |
    1413 FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
    1414 FUSE_SET_ATTR_CTIME;
    1415
    1416 req->se->op.setattr(req, nodeid, &stbuf, valid, fi);
    1417 } else
    1418 fuse_reply_err(req, ENOSYS);
    1419}
    1420
    1421static void do_setattr(fuse_req_t req, const fuse_ino_t nodeid,
    1422 const void *inarg)
    1423{
    1424 _do_setattr(req, nodeid, inarg, NULL);
    1425}
    1426
    1427static void _do_access(fuse_req_t req, const fuse_ino_t nodeid,
    1428 const void *op_in, const void *in_payload)
    1429{
    1430 (void)in_payload;
    1431 const struct fuse_access_in *arg = op_in;
    1432
    1433 if (req->se->op.access)
    1434 req->se->op.access(req, nodeid, arg->mask);
    1435 else
    1436 fuse_reply_err(req, ENOSYS);
    1437}
    1438
    1439static void do_access(fuse_req_t req, const fuse_ino_t nodeid,
    1440 const void *inarg)
    1441{
    1442 _do_access(req, nodeid, inarg, NULL);
    1443}
    1444
    1445static void _do_readlink(fuse_req_t req, const fuse_ino_t nodeid,
    1446 const void *op_in, const void *in_payload)
    1447{
    1448 (void)op_in;
    1449 (void)in_payload;
    1450
    1451 if (req->se->op.readlink)
    1452 req->se->op.readlink(req, nodeid);
    1453 else
    1454 fuse_reply_err(req, ENOSYS);
    1455}
    1456
    1457static void do_readlink(fuse_req_t req, const fuse_ino_t nodeid,
    1458 const void *inarg)
    1459{
    1460 _do_readlink(req, nodeid, inarg, NULL);
    1461}
    1462
    1463static void _do_mknod(fuse_req_t req, const fuse_ino_t nodeid,
    1464 const void *op_in, const void *in_payload)
    1465{
    1466 const struct fuse_mknod_in *arg = (struct fuse_mknod_in *)op_in;
    1467 const char *name = in_payload;
    1468
    1469 if (req->se->conn.proto_minor >= 12)
    1470 req->ctx.umask = arg->umask;
    1471
    1472 if (req->se->op.mknod)
    1473 req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
    1474 else
    1475 fuse_reply_err(req, ENOSYS);
    1476}
    1477
    1478static void do_mknod(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1479{
    1480 struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
    1481 char *name = PARAM(arg);
    1482
    1483 if (req->se->conn.proto_minor < 12)
    1484 name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
    1485
    1486 _do_mknod(req, nodeid, inarg, name);
    1487}
    1488
    1489static void _do_mkdir(fuse_req_t req, const fuse_ino_t nodeid,
    1490 const void *op_in, const void *in_payload)
    1491{
    1492 const char *name = in_payload;
    1493 const struct fuse_mkdir_in *arg = op_in;
    1494
    1495 if (req->se->conn.proto_minor >= 12)
    1496 req->ctx.umask = arg->umask;
    1497
    1498 if (req->se->op.mkdir)
    1499 req->se->op.mkdir(req, nodeid, name, arg->mode);
    1500 else
    1501 fuse_reply_err(req, ENOSYS);
    1502}
    1503
    1504static void do_mkdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1505{
    1506 const struct fuse_mkdir_in *arg = inarg;
    1507 const char *name = PARAM(arg);
    1508
    1509 _do_mkdir(req, nodeid, inarg, name);
    1510}
    1511
    1512static void _do_unlink(fuse_req_t req, const fuse_ino_t nodeid,
    1513 const void *op_in, const void *in_payload)
    1514{
    1515 (void)op_in;
    1516 const char *name = in_payload;
    1517
    1518 if (req->se->op.unlink)
    1519 req->se->op.unlink(req, nodeid, name);
    1520 else
    1521 fuse_reply_err(req, ENOSYS);
    1522}
    1523
    1524static void do_unlink(fuse_req_t req, const fuse_ino_t nodeid,
    1525 const void *inarg)
    1526{
    1527 _do_unlink(req, nodeid, NULL, inarg);
    1528}
    1529
    1530static void _do_rmdir(fuse_req_t req, const fuse_ino_t nodeid,
    1531 const void *op_in, const void *in_payload)
    1532{
    1533 (void)op_in;
    1534 const char *name = in_payload;
    1535
    1536 if (req->se->op.rmdir)
    1537 req->se->op.rmdir(req, nodeid, name);
    1538 else
    1539 fuse_reply_err(req, ENOSYS);
    1540}
    1541
    1542static void do_rmdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1543{
    1544 _do_rmdir(req, nodeid, NULL, inarg);
    1545}
    1546
    1547static void _do_symlink(fuse_req_t req, const fuse_ino_t nodeid,
    1548 const void *op_in, const void *in_payload)
    1549{
    1550 (void)op_in;
    1551 const char *name = (char *)in_payload;
    1552 const char *linkname = name + strlen(name) + 1;
    1553
    1554 if (req->se->op.symlink)
    1555 req->se->op.symlink(req, linkname, nodeid, name);
    1556 else
    1557 fuse_reply_err(req, ENOSYS);
    1558}
    1559
    1560static void do_symlink(fuse_req_t req, const fuse_ino_t nodeid,
    1561 const void *inarg)
    1562{
    1563 _do_symlink(req, nodeid, NULL, inarg);
    1564}
    1565
    1566static void _do_rename(fuse_req_t req, const fuse_ino_t nodeid,
    1567 const void *op_in, const void *in_payload)
    1568{
    1569 const struct fuse_rename_in *arg = (struct fuse_rename_in *)op_in;
    1570 const char *oldname = in_payload;
    1571 const char *newname = oldname + strlen(oldname) + 1;
    1572
    1573 if (req->se->op.rename)
    1574 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
    1575 0);
    1576 else
    1577 fuse_reply_err(req, ENOSYS);
    1578}
    1579
    1580static void do_rename(fuse_req_t req, const fuse_ino_t nodeid,
    1581 const void *inarg)
    1582{
    1583 const struct fuse_rename_in *arg = inarg;
    1584 const void *payload = PARAM(arg);
    1585
    1586 _do_rename(req, nodeid, arg, payload);
    1587}
    1588
    1589static void _do_rename2(fuse_req_t req, const fuse_ino_t nodeid,
    1590 const void *op_in, const void *in_payload)
    1591{
    1592 const struct fuse_rename2_in *arg = op_in;
    1593 const char *oldname = in_payload;
    1594 const char *newname = oldname + strlen(oldname) + 1;
    1595
    1596 if (req->se->op.rename)
    1597 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
    1598 arg->flags);
    1599 else
    1600 fuse_reply_err(req, ENOSYS);
    1601}
    1602
    1603static void do_rename2(fuse_req_t req, const fuse_ino_t nodeid,
    1604 const void *inarg)
    1605{
    1606 const struct fuse_rename2_in *arg = inarg;
    1607 const void *payload = PARAM(arg);
    1608
    1609 _do_rename2(req, nodeid, arg, payload);
    1610}
    1611
    1612static void _do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *op_in,
    1613 const void *in_payload)
    1614{
    1615 (void)in_payload;
    1616 const struct fuse_create_in *arg = op_in;
    1617
    1618 if (req->se->op.tmpfile) {
    1619 struct fuse_file_info fi;
    1620
    1621 memset(&fi, 0, sizeof(fi));
    1622 fi.flags = arg->flags;
    1623
    1624 if (req->se->conn.proto_minor >= 12)
    1625 req->ctx.umask = arg->umask;
    1626
    1627 req->se->op.tmpfile(req, nodeid, arg->mode, &fi);
    1628 } else
    1629 fuse_reply_err(req, ENOSYS);
    1630}
    1631
    1632static void do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    1633{
    1634 struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
    1635
    1636 _do_tmpfile(req, nodeid, arg, NULL);
    1637}
    1638
    1639static void _do_link(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    1640 const void *in_payload)
    1641{
    1642 struct fuse_link_in *arg = (struct fuse_link_in *)op_in;
    1643
    1644 if (req->se->op.link)
    1645 req->se->op.link(req, arg->oldnodeid, nodeid, in_payload);
    1646 else
    1647 fuse_reply_err(req, ENOSYS);
    1648}
    1649
    1650static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    1651{
    1652 const struct fuse_link_in *arg = inarg;
    1653 const void *name = PARAM(arg);
    1654
    1655 _do_link(req, nodeid, inarg, name);
    1656}
    1657
    1658static void _do_create(fuse_req_t req, const fuse_ino_t nodeid,
    1659 const void *op_in, const void *in_payload)
    1660{
    1661 const struct fuse_create_in *arg = op_in;
    1662 const char *name = in_payload;
    1663
    1664 if (req->se->op.create) {
    1665 struct fuse_file_info fi;
    1666
    1667 memset(&fi, 0, sizeof(fi));
    1668 fi.flags = arg->flags;
    1669
    1670 if (req->se->conn.proto_minor >= 12)
    1671 req->ctx.umask = arg->umask;
    1672
    1673 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
    1674 fi.kill_suidgid =
    1675 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
    1676
    1677 req->se->op.create(req, nodeid, name, arg->mode, &fi);
    1678 } else {
    1679 fuse_reply_err(req, ENOSYS);
    1680 }
    1681}
    1682
    1683static void do_create(fuse_req_t req, const fuse_ino_t nodeid,
    1684 const void *inarg)
    1685{
    1686 const struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
    1687 void *payload = PARAM(arg);
    1688
    1689 if (req->se->conn.proto_minor < 12)
    1690 payload = (char *)inarg + sizeof(struct fuse_open_in);
    1691
    1692 _do_create(req, nodeid, arg, payload);
    1693}
    1694
    1695static void _do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    1696 const void *in_payload)
    1697{
    1698 (void)in_payload;
    1699 struct fuse_open_in *arg = (struct fuse_open_in *)op_in;
    1700 struct fuse_file_info fi;
    1701
    1702 memset(&fi, 0, sizeof(fi));
    1703 fi.flags = arg->flags;
    1704
    1705 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
    1706 fi.kill_suidgid =
    1707 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
    1708
    1709 if (req->se->op.open)
    1710 req->se->op.open(req, nodeid, &fi);
    1711 else if (req->se->conn.want_ext & FUSE_CAP_NO_OPEN_SUPPORT)
    1712 fuse_reply_err(req, ENOSYS);
    1713 else
    1714 fuse_reply_open(req, &fi);
    1715}
    1716
    1717static void do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1718{
    1719 _do_open(req, nodeid, inarg, NULL);
    1720}
    1721
    1722static void _do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    1723 const void *in_payload)
    1724{
    1725 (void)in_payload;
    1726 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
    1727
    1728 if (req->se->op.read) {
    1729 struct fuse_file_info fi;
    1730
    1731 memset(&fi, 0, sizeof(fi));
    1732 fi.fh = arg->fh;
    1733 if (req->se->conn.proto_minor >= 9) {
    1734 fi.lock_owner = arg->lock_owner;
    1735 fi.flags = arg->flags;
    1736 }
    1737 req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
    1738 } else
    1739 fuse_reply_err(req, ENOSYS);
    1740}
    1741
    1742static void do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1743{
    1744 _do_read(req, nodeid, inarg, NULL);
    1745}
    1746
    1747static void _do_write(fuse_req_t req, const fuse_ino_t nodeid,
    1748 const void *op_in, const void *in_payload)
    1749{
    1750 struct fuse_write_in *arg = (struct fuse_write_in *)op_in;
    1751 const char *buf = in_payload;
    1752 struct fuse_file_info fi;
    1753
    1754 memset(&fi, 0, sizeof(fi));
    1755 fi.fh = arg->fh;
    1756 fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
    1757
    1758 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
    1759 fi.kill_suidgid =
    1760 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
    1761
    1762 if (req->se->conn.proto_minor >= 9) {
    1763 fi.lock_owner = arg->lock_owner;
    1764 fi.flags = arg->flags;
    1765 }
    1766
    1767 if (req->se->op.write)
    1768 req->se->op.write(req, nodeid, buf, arg->size, arg->offset,
    1769 &fi);
    1770 else
    1771 fuse_reply_err(req, ENOSYS);
    1772}
    1773
    1774static void do_write(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1775{
    1776 struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
    1777 const void *payload;
    1778
    1779 if (req->se->conn.proto_minor < 9)
    1780 payload = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
    1781 else
    1782 payload = PARAM(arg);
    1783
    1784 _do_write(req, nodeid, arg, payload);
    1785}
    1786
    1787static void _do_write_buf(fuse_req_t req, const fuse_ino_t nodeid,
    1788 const void *op_in, struct fuse_bufvec *bufv)
    1789{
    1790 struct fuse_session *se = req->se;
    1791 struct fuse_write_in *arg = (struct fuse_write_in *)op_in;
    1792 struct fuse_file_info fi;
    1793
    1794 memset(&fi, 0, sizeof(fi));
    1795 fi.fh = arg->fh;
    1796 fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
    1797
    1798 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
    1799 fi.kill_suidgid =
    1800 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
    1801
    1802 if (se->conn.proto_minor >= 9) {
    1803 fi.lock_owner = arg->lock_owner;
    1804 fi.flags = arg->flags;
    1805 }
    1806
    1807 se->op.write_buf(req, nodeid, bufv, arg->offset, &fi);
    1808}
    1809
    1810static void do_write_buf(fuse_req_t req, const fuse_ino_t nodeid,
    1811 const void *inarg, const struct fuse_buf *ibuf)
    1812{
    1813 struct fuse_session *se = req->se;
    1814 struct fuse_bufvec bufv = {
    1815 .buf[0] = *ibuf,
    1816 .count = 1,
    1817 };
    1818 struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
    1819
    1820 if (se->conn.proto_minor < 9) {
    1821 bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
    1822 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
    1823 FUSE_COMPAT_WRITE_IN_SIZE;
    1824 assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
    1825 } else {
    1826 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
    1827 bufv.buf[0].mem = PARAM(arg);
    1828
    1829 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
    1830 sizeof(struct fuse_write_in);
    1831 }
    1832 if (bufv.buf[0].size < arg->size) {
    1833 fuse_log(FUSE_LOG_ERR,
    1834 "fuse: %s: buffer size too small\n", __func__);
    1835 fuse_reply_err(req, EIO);
    1836 goto out;
    1837 }
    1838 bufv.buf[0].size = arg->size;
    1839
    1840 _do_write_buf(req, nodeid, inarg, &bufv);
    1841
    1842out:
    1843 /* Need to reset the pipe if ->write_buf() didn't consume all data */
    1844 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
    1845 fuse_ll_clear_pipe(se);
    1846}
    1847
    1848static void _do_flush(fuse_req_t req, const fuse_ino_t nodeid,
    1849 const void *op_in, const void *in_payload)
    1850{
    1851 (void)in_payload;
    1852 struct fuse_flush_in *arg = (struct fuse_flush_in *)op_in;
    1853 struct fuse_file_info fi;
    1854
    1855 memset(&fi, 0, sizeof(fi));
    1856 fi.fh = arg->fh;
    1857 fi.flush = 1;
    1858 if (req->se->conn.proto_minor >= 7)
    1859 fi.lock_owner = arg->lock_owner;
    1860
    1861 if (req->se->op.flush)
    1862 req->se->op.flush(req, nodeid, &fi);
    1863 else
    1864 fuse_reply_err(req, ENOSYS);
    1865}
    1866
    1867static void do_flush(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1868{
    1869 _do_flush(req, nodeid, inarg, NULL);
    1870}
    1871
    1872static void _do_release(fuse_req_t req, const fuse_ino_t nodeid,
    1873 const void *op_in, const void *in_payload)
    1874{
    1875 (void)in_payload;
    1876 const struct fuse_release_in *arg = op_in;
    1877 struct fuse_file_info fi;
    1878
    1879 memset(&fi, 0, sizeof(fi));
    1880 fi.flags = arg->flags;
    1881 fi.fh = arg->fh;
    1882 if (req->se->conn.proto_minor >= 8) {
    1883 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
    1884 fi.lock_owner = arg->lock_owner;
    1885 }
    1886 if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
    1887 fi.flock_release = 1;
    1888 fi.lock_owner = arg->lock_owner;
    1889 }
    1890
    1891 if (req->se->op.release)
    1892 req->se->op.release(req, nodeid, &fi);
    1893 else
    1894 fuse_reply_err(req, 0);
    1895}
    1896
    1897static void do_release(fuse_req_t req, const fuse_ino_t nodeid,
    1898 const void *inarg)
    1899{
    1900 _do_release(req, nodeid, inarg, NULL);
    1901}
    1902
    1903static void _do_fsync(fuse_req_t req, const fuse_ino_t nodeid,
    1904 const void *op_in, const void *in_payload)
    1905{
    1906 (void)in_payload;
    1907 const struct fuse_fsync_in *arg = op_in;
    1908 struct fuse_file_info fi;
    1909 int datasync = arg->fsync_flags & 1;
    1910
    1911 memset(&fi, 0, sizeof(fi));
    1912 fi.fh = arg->fh;
    1913
    1914 if (req->se->op.fsync)
    1915 req->se->op.fsync(req, nodeid, datasync, &fi);
    1916 else
    1917 fuse_reply_err(req, ENOSYS);
    1918}
    1919
    1920static void do_fsync(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    1921{
    1922 _do_fsync(req, nodeid, inarg, NULL);
    1923}
    1924
    1925static void _do_opendir(fuse_req_t req, const fuse_ino_t nodeid,
    1926 const void *op_in, const void *in_payload)
    1927{
    1928 (void)in_payload;
    1929 const struct fuse_open_in *arg = op_in;
    1930 struct fuse_file_info fi;
    1931
    1932 memset(&fi, 0, sizeof(fi));
    1933 fi.flags = arg->flags;
    1934 /* XXX: fuse_open_in::open_flags */
    1935
    1936 if (req->se->op.opendir)
    1937 req->se->op.opendir(req, nodeid, &fi);
    1938 else if (req->se->conn.want_ext & FUSE_CAP_NO_OPENDIR_SUPPORT)
    1939 fuse_reply_err(req, ENOSYS);
    1940 else
    1941 fuse_reply_open(req, &fi);
    1942}
    1943
    1944static void do_opendir(fuse_req_t req, const fuse_ino_t nodeid,
    1945 const void *inarg)
    1946{
    1947 _do_opendir(req, nodeid, inarg, NULL);
    1948}
    1949
    1950static void _do_readdir(fuse_req_t req, const fuse_ino_t nodeid,
    1951 const void *op_in, const void *in_payload)
    1952{
    1953 (void)in_payload;
    1954 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
    1955 struct fuse_file_info fi;
    1956
    1957 memset(&fi, 0, sizeof(fi));
    1958 fi.fh = arg->fh;
    1959
    1960 if (req->se->op.readdir)
    1961 req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
    1962 else
    1963 fuse_reply_err(req, ENOSYS);
    1964}
    1965
    1966static void do_readdir(fuse_req_t req, const fuse_ino_t nodeid,
    1967 const void *inarg)
    1968{
    1969 _do_readdir(req, nodeid, inarg, NULL);
    1970}
    1971
    1972static void _do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid,
    1973 const void *op_in, const void *in_payload)
    1974{
    1975 (void)in_payload;
    1976 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
    1977 struct fuse_file_info fi;
    1978
    1979 memset(&fi, 0, sizeof(fi));
    1980 fi.fh = arg->fh;
    1981
    1982 if (req->se->op.readdirplus)
    1983 req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
    1984 else
    1985 fuse_reply_err(req, ENOSYS);
    1986}
    1987
    1988static void do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid,
    1989 const void *inarg)
    1990{
    1991 _do_readdirplus(req, nodeid, inarg, NULL);
    1992}
    1993
    1994static void _do_releasedir(fuse_req_t req, const fuse_ino_t nodeid,
    1995 const void *op_in, const void *in_payload)
    1996{
    1997 (void)in_payload;
    1998 struct fuse_release_in *arg = (struct fuse_release_in *)op_in;
    1999 struct fuse_file_info fi;
    2000
    2001 memset(&fi, 0, sizeof(fi));
    2002 fi.flags = arg->flags;
    2003 fi.fh = arg->fh;
    2004
    2005 if (req->se->op.releasedir)
    2006 req->se->op.releasedir(req, nodeid, &fi);
    2007 else
    2008 fuse_reply_err(req, 0);
    2009}
    2010
    2011static void do_releasedir(fuse_req_t req, const fuse_ino_t nodeid,
    2012 const void *inarg)
    2013{
    2014 _do_releasedir(req, nodeid, inarg, NULL);
    2015}
    2016
    2017static void _do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid,
    2018 const void *op_in, const void *in_payload)
    2019{
    2020 (void)in_payload;
    2021 struct fuse_fsync_in *arg = (struct fuse_fsync_in *)op_in;
    2022 struct fuse_file_info fi;
    2023 int datasync = arg->fsync_flags & 1;
    2024
    2025 memset(&fi, 0, sizeof(fi));
    2026 fi.fh = arg->fh;
    2027
    2028 if (req->se->op.fsyncdir)
    2029 req->se->op.fsyncdir(req, nodeid, datasync, &fi);
    2030 else
    2031 fuse_reply_err(req, ENOSYS);
    2032}
    2033static void do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid,
    2034 const void *inarg)
    2035{
    2036 _do_fsyncdir(req, nodeid, inarg, NULL);
    2037}
    2038
    2039static void _do_statfs(fuse_req_t req, const fuse_ino_t nodeid,
    2040 const void *op_in, const void *in_payload)
    2041{
    2042 (void) nodeid;
    2043 (void)op_in;
    2044 (void)in_payload;
    2045
    2046 if (req->se->op.statfs)
    2047 req->se->op.statfs(req, nodeid);
    2048 else {
    2049 struct statvfs buf = {
    2050 .f_namemax = 255,
    2051 .f_bsize = 512,
    2052 };
    2053 fuse_reply_statfs(req, &buf);
    2054 }
    2055}
    2056static void do_statfs(fuse_req_t req, const fuse_ino_t nodeid,
    2057 const void *inarg)
    2058{
    2059 _do_statfs(req, nodeid, inarg, NULL);
    2060}
    2061
    2062static void _do_setxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2063 const void *op_in, const void *in_payload)
    2064{
    2065 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)op_in;
    2066 const char *name = in_payload;
    2067 const char *value = name + strlen(name) + 1;
    2068
    2069 /* XXX:The API should be extended to support extra_flags/setxattr_flags */
    2070
    2071 if (req->se->op.setxattr)
    2072 req->se->op.setxattr(req, nodeid, name, value, arg->size,
    2073 arg->flags);
    2074 else
    2075 fuse_reply_err(req, ENOSYS);
    2076}
    2077static void do_setxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2078 const void *inarg)
    2079{
    2080 struct fuse_session *se = req->se;
    2081 unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT);
    2082 const struct fuse_setxattr_in *arg = inarg;
    2083 char *payload = xattr_ext ? PARAM(arg) :
    2084 (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
    2085
    2086 _do_setxattr(req, nodeid, arg, payload);
    2087}
    2088
    2089static void _do_getxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2090 const void *op_in, const void *in_payload)
    2091{
    2092 const struct fuse_getxattr_in *arg = op_in;
    2093
    2094 if (req->se->op.getxattr)
    2095 req->se->op.getxattr(req, nodeid, in_payload, arg->size);
    2096 else
    2097 fuse_reply_err(req, ENOSYS);
    2098}
    2099
    2100static void do_getxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2101 const void *inarg)
    2102{
    2103 const struct fuse_getxattr_in *arg = inarg;
    2104 const void *payload = PARAM(arg);
    2105
    2106 _do_getxattr(req, nodeid, arg, payload);
    2107}
    2108
    2109static void _do_listxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2110 const void *inarg, const void *in_payload)
    2111{
    2112 (void)in_payload;
    2113 const struct fuse_getxattr_in *arg = inarg;
    2114
    2115 if (req->se->op.listxattr)
    2116 req->se->op.listxattr(req, nodeid, arg->size);
    2117 else
    2118 fuse_reply_err(req, ENOSYS);
    2119}
    2120static void do_listxattr(fuse_req_t req, const fuse_ino_t nodeid,
    2121 const void *inarg)
    2122{
    2123 _do_listxattr(req, nodeid, inarg, NULL);
    2124}
    2125
    2126static void _do_removexattr(fuse_req_t req, const fuse_ino_t nodeid,
    2127 const void *inarg, const void *in_payload)
    2128{
    2129 (void)inarg;
    2130 const char *name = in_payload;
    2131
    2132 if (req->se->op.removexattr)
    2133 req->se->op.removexattr(req, nodeid, name);
    2134 else
    2135 fuse_reply_err(req, ENOSYS);
    2136}
    2137static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2138{
    2139 _do_removexattr(req, nodeid, NULL, inarg);
    2140}
    2141
    2142static void convert_fuse_file_lock(const struct fuse_file_lock *fl,
    2143 struct flock *flock)
    2144{
    2145 memset(flock, 0, sizeof(struct flock));
    2146 flock->l_type = fl->type;
    2147 flock->l_whence = SEEK_SET;
    2148 flock->l_start = fl->start;
    2149 if (fl->end == OFFSET_MAX)
    2150 flock->l_len = 0;
    2151 else
    2152 flock->l_len = fl->end - fl->start + 1;
    2153 flock->l_pid = fl->pid;
    2154}
    2155
    2156static void _do_getlk(fuse_req_t req, const fuse_ino_t nodeid,
    2157 const void *op_in, const void *in_payload)
    2158{
    2159 (void)in_payload;
    2160 const struct fuse_lk_in *arg = op_in;
    2161 struct fuse_file_info fi;
    2162 struct flock flock;
    2163
    2164 memset(&fi, 0, sizeof(fi));
    2165 fi.fh = arg->fh;
    2166 fi.lock_owner = arg->owner;
    2167
    2168 convert_fuse_file_lock(&arg->lk, &flock);
    2169 if (req->se->op.getlk)
    2170 req->se->op.getlk(req, nodeid, &fi, &flock);
    2171 else
    2172 fuse_reply_err(req, ENOSYS);
    2173}
    2174static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2175{
    2176 _do_getlk(req, nodeid, inarg, NULL);
    2177}
    2178
    2179static void do_setlk_common(fuse_req_t req, const fuse_ino_t nodeid,
    2180 const void *op_in, int sleep)
    2181{
    2182 const struct fuse_lk_in *arg = op_in;
    2183 struct fuse_file_info fi;
    2184 struct flock flock;
    2185
    2186 memset(&fi, 0, sizeof(fi));
    2187 fi.fh = arg->fh;
    2188 fi.lock_owner = arg->owner;
    2189
    2190 if (arg->lk_flags & FUSE_LK_FLOCK) {
    2191 int op = 0;
    2192
    2193 switch (arg->lk.type) {
    2194 case F_RDLCK:
    2195 op = LOCK_SH;
    2196 break;
    2197 case F_WRLCK:
    2198 op = LOCK_EX;
    2199 break;
    2200 case F_UNLCK:
    2201 op = LOCK_UN;
    2202 break;
    2203 }
    2204 if (!sleep)
    2205 op |= LOCK_NB;
    2206
    2207 if (req->se->op.flock)
    2208 req->se->op.flock(req, nodeid, &fi, op);
    2209 else
    2210 fuse_reply_err(req, ENOSYS);
    2211 } else {
    2212 convert_fuse_file_lock(&arg->lk, &flock);
    2213 if (req->se->op.setlk)
    2214 req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
    2215 else
    2216 fuse_reply_err(req, ENOSYS);
    2217 }
    2218}
    2219
    2220static void _do_setlk(fuse_req_t req, const fuse_ino_t nodeid,
    2221 const void *op_in, const void *in_payload)
    2222{
    2223 (void)in_payload;
    2224 do_setlk_common(req, nodeid, op_in, 0);
    2225}
    2226
    2227static void do_setlk(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    2228{
    2229 _do_setlk(req, nodeid, inarg, NULL);
    2230}
    2231
    2232static void _do_setlkw(fuse_req_t req, const fuse_ino_t nodeid,
    2233 const void *op_in, const void *in_payload)
    2234{
    2235 (void)in_payload;
    2236 do_setlk_common(req, nodeid, op_in, 1);
    2237}
    2238static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2239{
    2240 _do_setlkw(req, nodeid, inarg, NULL);
    2241}
    2242
    2243static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
    2244{
    2245 struct fuse_req *curr;
    2246
    2247 for (curr = se->list.next; curr != &se->list; curr = curr->next) {
    2248 if (curr->unique == req->u.i.unique) {
    2250 void *data;
    2251
    2252 curr->ref_cnt++;
    2253 pthread_mutex_unlock(&se->lock);
    2254
    2255 /* Ugh, ugly locking */
    2256 pthread_mutex_lock(&curr->lock);
    2257 pthread_mutex_lock(&se->lock);
    2258 curr->interrupted = 1;
    2259 func = curr->u.ni.func;
    2260 data = curr->u.ni.data;
    2261 pthread_mutex_unlock(&se->lock);
    2262 if (func)
    2263 func(curr, data);
    2264 pthread_mutex_unlock(&curr->lock);
    2265
    2266 pthread_mutex_lock(&se->lock);
    2267 curr->ref_cnt--;
    2268 if (!curr->ref_cnt) {
    2269 destroy_req(curr);
    2270 }
    2271
    2272 return 1;
    2273 }
    2274 }
    2275 for (curr = se->interrupts.next; curr != &se->interrupts;
    2276 curr = curr->next) {
    2277 if (curr->u.i.unique == req->u.i.unique)
    2278 return 1;
    2279 }
    2280 return 0;
    2281}
    2282
    2283static void _do_interrupt(fuse_req_t req, const fuse_ino_t nodeid,
    2284 const void *op_in, const void *in_payload)
    2285{
    2286 (void)in_payload;
    2287 const struct fuse_interrupt_in *arg = op_in;
    2288 struct fuse_session *se = req->se;
    2289
    2290 (void) nodeid;
    2291 if (se->debug)
    2292 fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
    2293 (unsigned long long) arg->unique);
    2294
    2295 req->u.i.unique = arg->unique;
    2296
    2297 pthread_mutex_lock(&se->lock);
    2298 if (find_interrupted(se, req)) {
    2299 fuse_chan_put(req->ch);
    2300 req->ch = NULL;
    2301 destroy_req(req);
    2302 } else
    2303 list_add_req(req, &se->interrupts);
    2304 pthread_mutex_unlock(&se->lock);
    2305}
    2306static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2307{
    2308 _do_interrupt(req, nodeid, inarg, NULL);
    2309}
    2310
    2311static struct fuse_req *check_interrupt(struct fuse_session *se,
    2312 struct fuse_req *req)
    2313{
    2314 struct fuse_req *curr;
    2315
    2316 for (curr = se->interrupts.next; curr != &se->interrupts;
    2317 curr = curr->next) {
    2318 if (curr->u.i.unique == req->unique) {
    2319 req->interrupted = 1;
    2320 list_del_req(curr);
    2321 fuse_chan_put(curr->ch);
    2322 curr->ch = NULL;
    2323 destroy_req(curr);
    2324 return NULL;
    2325 }
    2326 }
    2327 curr = se->interrupts.next;
    2328 if (curr != &se->interrupts) {
    2329 list_del_req(curr);
    2330 list_init_req(curr);
    2331 return curr;
    2332 } else
    2333 return NULL;
    2334}
    2335
    2336static void _do_bmap(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    2337 const void *in_payload)
    2338{
    2339 (void)in_payload;
    2340 const struct fuse_bmap_in *arg = op_in;
    2341
    2342 if (req->se->op.bmap)
    2343 req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
    2344 else
    2345 fuse_reply_err(req, ENOSYS);
    2346}
    2347static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2348{
    2349 _do_bmap(req, nodeid, inarg, NULL);
    2350}
    2351
    2352static void _do_ioctl(fuse_req_t req, const fuse_ino_t nodeid,
    2353 const void *op_in, const void *in_payload)
    2354{
    2355 struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)op_in;
    2356 unsigned int flags = arg->flags;
    2357 const void *in_buf = in_payload;
    2358 struct fuse_file_info fi;
    2359
    2360 if (flags & FUSE_IOCTL_DIR &&
    2361 !(req->se->conn.want_ext & FUSE_CAP_IOCTL_DIR)) {
    2362 fuse_reply_err(req, ENOTTY);
    2363 return;
    2364 }
    2365
    2366 memset(&fi, 0, sizeof(fi));
    2367 fi.fh = arg->fh;
    2368
    2369 if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
    2370 !(flags & FUSE_IOCTL_32BIT)) {
    2371 req->flags.ioctl_64bit = 1;
    2372 }
    2373
    2374 if (req->se->op.ioctl)
    2375 req->se->op.ioctl(req, nodeid, arg->cmd,
    2376 (void *)(uintptr_t)arg->arg, &fi, flags,
    2377 in_buf, arg->in_size, arg->out_size);
    2378 else
    2379 fuse_reply_err(req, ENOSYS);
    2380}
    2381static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2382{
    2383 const struct fuse_ioctl_in *arg = inarg;
    2384 void *in_buf = arg->in_size ? PARAM(arg) : NULL;
    2385
    2386 _do_ioctl(req, nodeid, arg, in_buf);
    2387}
    2388
    2389void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    2390{
    2391 free(ph);
    2392}
    2393
    2394static void _do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    2395 const void *in_payload)
    2396{
    2397 (void)in_payload;
    2398 struct fuse_poll_in *arg = (struct fuse_poll_in *)op_in;
    2399 struct fuse_file_info fi;
    2400
    2401 memset(&fi, 0, sizeof(fi));
    2402 fi.fh = arg->fh;
    2403 fi.poll_events = arg->events;
    2404
    2405 if (req->se->op.poll) {
    2406 struct fuse_pollhandle *ph = NULL;
    2407
    2408 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
    2409 ph = malloc(sizeof(struct fuse_pollhandle));
    2410 if (ph == NULL) {
    2411 fuse_reply_err(req, ENOMEM);
    2412 return;
    2413 }
    2414 ph->kh = arg->kh;
    2415 ph->se = req->se;
    2416 }
    2417
    2418 req->se->op.poll(req, nodeid, &fi, ph);
    2419 } else {
    2420 fuse_reply_err(req, ENOSYS);
    2421 }
    2422}
    2423
    2424static void do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    2425{
    2426 _do_poll(req, nodeid, inarg, NULL);
    2427}
    2428
    2429static void _do_fallocate(fuse_req_t req, const fuse_ino_t nodeid,
    2430 const void *op_in, const void *in_payload)
    2431{
    2432 (void)in_payload;
    2433 const struct fuse_fallocate_in *arg = op_in;
    2434 struct fuse_file_info fi;
    2435
    2436 memset(&fi, 0, sizeof(fi));
    2437 fi.fh = arg->fh;
    2438
    2439 if (req->se->op.fallocate)
    2440 req->se->op.fallocate(req, nodeid, arg->mode, arg->offset,
    2441 arg->length, &fi);
    2442 else
    2443 fuse_reply_err(req, ENOSYS);
    2444}
    2445
    2446static void do_fallocate(fuse_req_t req, const fuse_ino_t nodeid,
    2447 const void *inarg)
    2448{
    2449 _do_fallocate(req, nodeid, inarg, NULL);
    2450}
    2451
    2452static void copy_file_range_common(fuse_req_t req, const fuse_ino_t nodeid_in,
    2453 const struct fuse_copy_file_range_in *arg)
    2454{
    2455 struct fuse_file_info fi_in, fi_out;
    2456
    2457 memset(&fi_in, 0, sizeof(fi_in));
    2458 fi_in.fh = arg->fh_in;
    2459
    2460 memset(&fi_out, 0, sizeof(fi_out));
    2461 fi_out.fh = arg->fh_out;
    2462
    2463 if (req->se->op.copy_file_range)
    2464 req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
    2465 arg->nodeid_out, arg->off_out,
    2466 &fi_out, arg->len, arg->flags);
    2467 else
    2468 fuse_reply_err(req, ENOSYS);
    2469}
    2470
    2471static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
    2472 const void *op_in, const void *in_payload)
    2473{
    2474 const struct fuse_copy_file_range_in *arg = op_in;
    2475 struct fuse_copy_file_range_in arg_tmp;
    2476
    2477 (void) in_payload;
    2478 /* fuse_write_out can only handle 32bit copy size */
    2479 if (arg->len > 0xfffff000) {
    2480 arg_tmp = *arg;
    2481 arg_tmp.len = 0xfffff000;
    2482 arg = &arg_tmp;
    2483 }
    2484 copy_file_range_common(req, nodeid_in, arg);
    2485}
    2486
    2487static void do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
    2488 const void *inarg)
    2489{
    2490 _do_copy_file_range(req, nodeid_in, inarg, NULL);
    2491}
    2492
    2493static void _do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
    2494 const void *op_in, const void *in_payload)
    2495{
    2496 (void) in_payload;
    2497 req->flags.is_copy_file_range_64 = 1;
    2498 /* Limit size on 32bit userspace to avoid conversion overflow */
    2499 if (sizeof(size_t) == 4)
    2500 _do_copy_file_range(req, nodeid_in, op_in, NULL);
    2501 else
    2502 copy_file_range_common(req, nodeid_in, op_in);
    2503}
    2504
    2505static void do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
    2506 const void *inarg)
    2507{
    2508 _do_copy_file_range_64(req, nodeid_in, inarg, NULL);
    2509}
    2510
    2511/*
    2512 * Note that the uint64_t offset in struct fuse_lseek_in is derived from
    2513 * linux kernel loff_t and is therefore signed.
    2514 */
    2515static void _do_lseek(fuse_req_t req, const fuse_ino_t nodeid,
    2516 const void *op_in, const void *in_payload)
    2517{
    2518 (void)in_payload;
    2519 const struct fuse_lseek_in *arg = op_in;
    2520 struct fuse_file_info fi;
    2521
    2522 memset(&fi, 0, sizeof(fi));
    2523 fi.fh = arg->fh;
    2524
    2525 if (req->se->op.lseek)
    2526 req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
    2527 else
    2528 fuse_reply_err(req, ENOSYS);
    2529}
    2530
    2531static void do_lseek(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
    2532{
    2533 _do_lseek(req, nodeid, inarg, NULL);
    2534}
    2535
    2536#ifdef HAVE_STATX
    2537static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid,
    2538 const void *op_in, const void *in_payload)
    2539{
    2540 (void)in_payload;
    2541 const struct fuse_statx_in *arg = op_in;
    2542 struct fuse_file_info *fip = NULL;
    2543 struct fuse_file_info fi;
    2544
    2545 if (arg->getattr_flags & FUSE_GETATTR_FH) {
    2546 memset(&fi, 0, sizeof(fi));
    2547 fi.fh = arg->fh;
    2548 fip = &fi;
    2549 }
    2550
    2551 if (req->se->op.statx)
    2552 req->se->op.statx(req, nodeid, arg->sx_flags, arg->sx_mask, fip);
    2553 else
    2554 fuse_reply_err(req, ENOSYS);
    2555}
    2556#else
    2557static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid,
    2558 const void *op_in, const void *in_payload)
    2559{
    2560 (void)in_payload;
    2561 (void)nodeid;
    2562 (void)op_in;
    2563 fuse_reply_err(req, ENOSYS);
    2564}
    2565#endif
    2566
    2567static void do_statx(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    2568{
    2569 _do_statx(req, nodeid, inarg, NULL);
    2570}
    2571
    2572static bool want_flags_valid(uint64_t capable, uint64_t want)
    2573{
    2574 uint64_t unknown_flags = want & (~capable);
    2575 if (unknown_flags != 0) {
    2576 fuse_log(FUSE_LOG_ERR,
    2577 "fuse: unknown connection 'want' flags: 0x%08llx\n",
    2578 (unsigned long long)unknown_flags);
    2579 return false;
    2580 }
    2581 return true;
    2582}
    2583
    2588{
    2589 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
    2590
    2591 /*
    2592 * Convert want to want_ext if necessary.
    2593 * For the high level interface this function might be called
    2594 * twice, once from the high level interface and once from the
    2595 * low level interface. Both, with different want_ext_default and
    2596 * want_default values. In order to suppress a failure for the
    2597 * second call, we check if the lower 32 bits of want_ext are
    2598 * already set to the value of want.
    2599 */
    2600 if (conn->want != se->conn_want &&
    2601 fuse_lower_32_bits(conn->want_ext) != conn->want) {
    2602 if (conn->want_ext != se->conn_want_ext) {
    2603 fuse_log(FUSE_LOG_ERR,
    2604 "%s: Both conn->want_ext and conn->want are set.\n"
    2605 "want=%x want_ext=%llx, se->want=%x se->want_ext=%llx\n",
    2606 __func__, conn->want,
    2607 (unsigned long long)conn->want_ext,
    2608 se->conn_want,
    2609 (unsigned long long)se->conn_want_ext);
    2610 return -EINVAL;
    2611 }
    2612
    2613 /* high bits from want_ext, low bits from want */
    2614 conn->want_ext = fuse_higher_32_bits(conn->want_ext) |
    2615 conn->want;
    2616 }
    2617
    2618 /* ensure there won't be a second conversion */
    2619 conn->want = fuse_lower_32_bits(conn->want_ext);
    2620
    2621 return 0;
    2622}
    2623
    2625 uint64_t flag)
    2626{
    2627 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
    2628
    2629 if (conn->capable_ext & flag) {
    2630 conn->want_ext |= flag;
    2631 se->conn_want_ext |= flag;
    2632 conn->want |= flag;
    2633 se->conn_want |= flag;
    2634 return true;
    2635 }
    2636 return false;
    2637}
    2638
    2640 uint64_t flag)
    2641{
    2642 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
    2643
    2644 conn->want_ext &= ~flag;
    2645 se->conn_want_ext &= ~flag;
    2646 conn->want &= ~flag;
    2647 se->conn_want &= ~flag;
    2648}
    2649
    2651 uint64_t flag)
    2652{
    2653 return conn->capable_ext & flag ? true : false;
    2654}
    2655
    2656/* Prevent bogus data races (bogus since "init" is called before
    2657 * multi-threading becomes relevant */
    2658static __attribute__((no_sanitize("thread"))) void
    2659_do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
    2660 const void *in_payload)
    2661{
    2662 (void)in_payload;
    2663 const struct fuse_init_in *arg = op_in;
    2664 struct fuse_init_out outarg;
    2665 struct fuse_session *se = req->se;
    2666 size_t bufsize = se->bufsize;
    2667 size_t outargsize = sizeof(outarg);
    2668 uint64_t inargflags = 0;
    2669 uint64_t outargflags = 0;
    2670 bool buf_reallocable = se->buf_reallocable;
    2671 (void) nodeid;
    2672 bool enable_io_uring = false;
    2673
    2674 if (se->debug) {
    2675 fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
    2676 if (arg->major == 7 && arg->minor >= 6) {
    2677 fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
    2678 fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
    2679 arg->max_readahead);
    2680 }
    2681 }
    2682 se->conn.proto_major = arg->major;
    2683 se->conn.proto_minor = arg->minor;
    2684 se->conn.capable_ext = 0;
    2685 se->conn.want_ext = 0;
    2686
    2687 memset(&outarg, 0, sizeof(outarg));
    2688 outarg.major = FUSE_KERNEL_VERSION;
    2689 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
    2690
    2691 if (arg->major < 7) {
    2692 fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
    2693 arg->major, arg->minor);
    2694 fuse_reply_err(req, EPROTO);
    2695 return;
    2696 }
    2697
    2698 if (arg->major > 7) {
    2699 /* Wait for a second INIT request with a 7.X version */
    2700 send_reply_ok(req, &outarg, sizeof(outarg));
    2701 return;
    2702 }
    2703
    2704 if (arg->minor >= 6) {
    2705 if (arg->max_readahead < se->conn.max_readahead)
    2706 se->conn.max_readahead = arg->max_readahead;
    2707 inargflags = arg->flags;
    2708 if (inargflags & FUSE_INIT_EXT)
    2709 inargflags = inargflags | (uint64_t) arg->flags2 << 32;
    2710 if (inargflags & FUSE_ASYNC_READ)
    2711 se->conn.capable_ext |= FUSE_CAP_ASYNC_READ;
    2712 if (inargflags & FUSE_POSIX_LOCKS)
    2713 se->conn.capable_ext |= FUSE_CAP_POSIX_LOCKS;
    2714 if (inargflags & FUSE_ATOMIC_O_TRUNC)
    2715 se->conn.capable_ext |= FUSE_CAP_ATOMIC_O_TRUNC;
    2716 if (inargflags & FUSE_EXPORT_SUPPORT)
    2717 se->conn.capable_ext |= FUSE_CAP_EXPORT_SUPPORT;
    2718 if (inargflags & FUSE_DONT_MASK)
    2719 se->conn.capable_ext |= FUSE_CAP_DONT_MASK;
    2720 if (inargflags & FUSE_FLOCK_LOCKS)
    2721 se->conn.capable_ext |= FUSE_CAP_FLOCK_LOCKS;
    2722 if (inargflags & FUSE_AUTO_INVAL_DATA)
    2723 se->conn.capable_ext |= FUSE_CAP_AUTO_INVAL_DATA;
    2724 if (inargflags & FUSE_DO_READDIRPLUS)
    2725 se->conn.capable_ext |= FUSE_CAP_READDIRPLUS;
    2726 if (inargflags & FUSE_READDIRPLUS_AUTO)
    2727 se->conn.capable_ext |= FUSE_CAP_READDIRPLUS_AUTO;
    2728 if (inargflags & FUSE_ASYNC_DIO)
    2729 se->conn.capable_ext |= FUSE_CAP_ASYNC_DIO;
    2730 if (inargflags & FUSE_WRITEBACK_CACHE)
    2731 se->conn.capable_ext |= FUSE_CAP_WRITEBACK_CACHE;
    2732 if (inargflags & FUSE_NO_OPEN_SUPPORT)
    2733 se->conn.capable_ext |= FUSE_CAP_NO_OPEN_SUPPORT;
    2734 if (inargflags & FUSE_PARALLEL_DIROPS)
    2735 se->conn.capable_ext |= FUSE_CAP_PARALLEL_DIROPS;
    2736 if (inargflags & FUSE_POSIX_ACL)
    2737 se->conn.capable_ext |= FUSE_CAP_POSIX_ACL;
    2738 if (inargflags & FUSE_HANDLE_KILLPRIV)
    2739 se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV;
    2740 if (inargflags & FUSE_HANDLE_KILLPRIV_V2)
    2741 se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV_V2;
    2742 if (inargflags & FUSE_CACHE_SYMLINKS)
    2743 se->conn.capable_ext |= FUSE_CAP_CACHE_SYMLINKS;
    2744 if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
    2745 se->conn.capable_ext |= FUSE_CAP_NO_OPENDIR_SUPPORT;
    2746 if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
    2747 se->conn.capable_ext |= FUSE_CAP_EXPLICIT_INVAL_DATA;
    2748 if (inargflags & FUSE_SETXATTR_EXT)
    2749 se->conn.capable_ext |= FUSE_CAP_SETXATTR_EXT;
    2750 if (!(inargflags & FUSE_MAX_PAGES)) {
    2751 size_t max_bufsize =
    2752 FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
    2753 + FUSE_BUFFER_HEADER_SIZE;
    2754 if (bufsize > max_bufsize) {
    2755 bufsize = max_bufsize;
    2756 }
    2757 buf_reallocable = false;
    2758 }
    2759 if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
    2760 se->conn.capable_ext |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
    2761 if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
    2762 se->conn.capable_ext |= FUSE_CAP_EXPIRE_ONLY;
    2763 if (inargflags & FUSE_PASSTHROUGH)
    2764 se->conn.capable_ext |= FUSE_CAP_PASSTHROUGH;
    2765 if (inargflags & FUSE_NO_EXPORT_SUPPORT)
    2766 se->conn.capable_ext |= FUSE_CAP_NO_EXPORT_SUPPORT;
    2767 if (inargflags & FUSE_OVER_IO_URING)
    2768 se->conn.capable_ext |= FUSE_CAP_OVER_IO_URING;
    2769
    2770 } else {
    2771 se->conn.max_readahead = 0;
    2772 }
    2773
    2774 if (se->conn.proto_minor >= 14) {
    2775#ifdef HAVE_SPLICE
    2776#ifdef HAVE_VMSPLICE
    2777 if ((se->io == NULL) || (se->io->splice_send != NULL)) {
    2778 se->conn.capable_ext |= FUSE_CAP_SPLICE_WRITE |
    2780 }
    2781#endif
    2782 if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
    2783 se->conn.capable_ext |= FUSE_CAP_SPLICE_READ;
    2784 }
    2785#endif
    2786 }
    2787 if (se->conn.proto_minor >= 18)
    2788 se->conn.capable_ext |= FUSE_CAP_IOCTL_DIR;
    2789
    2790 /* Default settings for modern filesystems.
    2791 *
    2792 * Most of these capabilities were disabled by default in
    2793 * libfuse2 for backwards compatibility reasons. In libfuse3,
    2794 * we can finally enable them by default (as long as they're
    2795 * supported by the kernel).
    2796 */
    2797#define LL_SET_DEFAULT(cond, cap) \
    2798 if ((cond)) \
    2799 fuse_set_feature_flag(&se->conn, cap)
    2800
    2801 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
    2802 LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
    2803 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
    2804 LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
    2805 LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
    2806 LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
    2807 LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
    2809 LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
    2810 LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
    2811 LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
    2813 LL_SET_DEFAULT(1, FUSE_CAP_OVER_IO_URING);
    2814
    2815 /* This could safely become default, but libfuse needs an API extension
    2816 * to support it
    2817 * LL_SET_DEFAULT(1, FUSE_CAP_SETXATTR_EXT);
    2818 */
    2819
    2820 se->conn.time_gran = 1;
    2821
    2822 if (se->op.init) {
    2823 // Apply the first 32 bits of capable_ext to capable
    2824 se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext);
    2825
    2826 se->op.init(se->userdata, &se->conn);
    2827
    2828 /*
    2829 * se->conn.want is 32-bit value and deprecated in favour of
    2830 * se->conn.want_ext
    2831 * Userspace might still use conn.want - we need to convert it
    2832 */
    2834 }
    2835
    2836 if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) {
    2837 fuse_reply_err(req, EPROTO);
    2838 se->error = -EPROTO;
    2840 return;
    2841 }
    2842
    2843 unsigned max_read_mo = get_max_read(se->mo);
    2844 if (se->conn.max_read != max_read_mo) {
    2845 fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
    2846 "requested different maximum read size (%u vs %u)\n",
    2847 se->conn.max_read, max_read_mo);
    2848 fuse_reply_err(req, EPROTO);
    2849 se->error = -EPROTO;
    2851 return;
    2852 }
    2853
    2854 if (bufsize < FUSE_MIN_READ_BUFFER) {
    2855 fuse_log(FUSE_LOG_ERR,
    2856 "fuse: warning: buffer size too small: %zu\n",
    2857 bufsize);
    2858 bufsize = FUSE_MIN_READ_BUFFER;
    2859 }
    2860
    2861 if (buf_reallocable)
    2862 bufsize = UINT_MAX;
    2863 se->conn.max_write = MIN(se->conn.max_write, bufsize - FUSE_BUFFER_HEADER_SIZE);
    2864 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
    2865
    2866 if (arg->flags & FUSE_MAX_PAGES) {
    2867 outarg.flags |= FUSE_MAX_PAGES;
    2868 outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
    2869 }
    2870 outargflags = outarg.flags;
    2871 /* Always enable big writes, this is superseded
    2872 by the max_write option */
    2873 outargflags |= FUSE_BIG_WRITES;
    2874
    2875 if (se->conn.want_ext & FUSE_CAP_ASYNC_READ)
    2876 outargflags |= FUSE_ASYNC_READ;
    2877 if (se->conn.want_ext & FUSE_CAP_POSIX_LOCKS)
    2878 outargflags |= FUSE_POSIX_LOCKS;
    2879 if (se->conn.want_ext & FUSE_CAP_ATOMIC_O_TRUNC)
    2880 outargflags |= FUSE_ATOMIC_O_TRUNC;
    2881 if (se->conn.want_ext & FUSE_CAP_EXPORT_SUPPORT)
    2882 outargflags |= FUSE_EXPORT_SUPPORT;
    2883 if (se->conn.want_ext & FUSE_CAP_DONT_MASK)
    2884 outargflags |= FUSE_DONT_MASK;
    2885 if (se->conn.want_ext & FUSE_CAP_FLOCK_LOCKS)
    2886 outargflags |= FUSE_FLOCK_LOCKS;
    2887 if (se->conn.want_ext & FUSE_CAP_AUTO_INVAL_DATA)
    2888 outargflags |= FUSE_AUTO_INVAL_DATA;
    2889 if (se->conn.want_ext & FUSE_CAP_READDIRPLUS)
    2890 outargflags |= FUSE_DO_READDIRPLUS;
    2891 if (se->conn.want_ext & FUSE_CAP_READDIRPLUS_AUTO)
    2892 outargflags |= FUSE_READDIRPLUS_AUTO;
    2893 if (se->conn.want_ext & FUSE_CAP_ASYNC_DIO)
    2894 outargflags |= FUSE_ASYNC_DIO;
    2895 if (se->conn.want_ext & FUSE_CAP_WRITEBACK_CACHE)
    2896 outargflags |= FUSE_WRITEBACK_CACHE;
    2897 if (se->conn.want_ext & FUSE_CAP_PARALLEL_DIROPS)
    2898 outargflags |= FUSE_PARALLEL_DIROPS;
    2899 if (se->conn.want_ext & FUSE_CAP_POSIX_ACL)
    2900 outargflags |= FUSE_POSIX_ACL;
    2901 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV)
    2902 outargflags |= FUSE_HANDLE_KILLPRIV;
    2903 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
    2904 outargflags |= FUSE_HANDLE_KILLPRIV_V2;
    2905 if (se->conn.want_ext & FUSE_CAP_CACHE_SYMLINKS)
    2906 outargflags |= FUSE_CACHE_SYMLINKS;
    2907 if (se->conn.want_ext & FUSE_CAP_EXPLICIT_INVAL_DATA)
    2908 outargflags |= FUSE_EXPLICIT_INVAL_DATA;
    2909 if (se->conn.want_ext & FUSE_CAP_SETXATTR_EXT)
    2910 outargflags |= FUSE_SETXATTR_EXT;
    2911 if (se->conn.want_ext & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
    2912 outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
    2913 if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH) {
    2914 outargflags |= FUSE_PASSTHROUGH;
    2915 /*
    2916 * outarg.max_stack_depth includes the fuse stack layer,
    2917 * so it is one more than max_backing_stack_depth.
    2918 */
    2919 outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
    2920 }
    2921 if (se->conn.want_ext & FUSE_CAP_NO_EXPORT_SUPPORT)
    2922 outargflags |= FUSE_NO_EXPORT_SUPPORT;
    2923 if (se->uring.enable && se->conn.want_ext & FUSE_CAP_OVER_IO_URING) {
    2924 outargflags |= FUSE_OVER_IO_URING;
    2925 enable_io_uring = true;
    2926 }
    2927
    2928 if ((inargflags & FUSE_REQUEST_TIMEOUT) && se->conn.request_timeout) {
    2929 outargflags |= FUSE_REQUEST_TIMEOUT;
    2930 outarg.request_timeout = se->conn.request_timeout;
    2931 }
    2932
    2933 outarg.max_readahead = se->conn.max_readahead;
    2934 outarg.max_write = se->conn.max_write;
    2935 if (se->conn.proto_minor >= 13) {
    2936 if (se->conn.max_background >= (1 << 16))
    2937 se->conn.max_background = (1 << 16) - 1;
    2938 if (se->conn.congestion_threshold > se->conn.max_background)
    2939 se->conn.congestion_threshold = se->conn.max_background;
    2940 if (!se->conn.congestion_threshold) {
    2941 se->conn.congestion_threshold =
    2942 se->conn.max_background * 3 / 4;
    2943 }
    2944
    2945 outarg.max_background = se->conn.max_background;
    2946 outarg.congestion_threshold = se->conn.congestion_threshold;
    2947 }
    2948 if (se->conn.proto_minor >= 23)
    2949 outarg.time_gran = se->conn.time_gran;
    2950
    2951 if (se->debug) {
    2952 fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor);
    2953 fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
    2954 fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
    2955 outarg.max_readahead);
    2956 fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
    2957 fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
    2958 outarg.max_background);
    2959 fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
    2960 outarg.congestion_threshold);
    2961 fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
    2962 outarg.time_gran);
    2963 if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH)
    2964 fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n",
    2965 outarg.max_stack_depth);
    2966 }
    2967 if (arg->minor < 5)
    2968 outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
    2969 else if (arg->minor < 23)
    2970 outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
    2971
    2972 /* XXX: Add an option to make non-available io-uring fatal */
    2973 if (enable_io_uring) {
    2974 int ring_rc = fuse_uring_start(se);
    2975
    2976 if (ring_rc != 0) {
    2977 fuse_log(FUSE_LOG_INFO,
    2978 "fuse: failed to start io-uring: %s\n",
    2979 strerror(ring_rc));
    2980 outargflags &= ~FUSE_OVER_IO_URING;
    2981 enable_io_uring = false;
    2982 }
    2983 }
    2984
    2985 if (inargflags & FUSE_INIT_EXT) {
    2986 outargflags |= FUSE_INIT_EXT;
    2987 outarg.flags2 = outargflags >> 32;
    2988 }
    2989 outarg.flags = outargflags;
    2990
    2991 /*
    2992 * Has to be set before replying, as new kernel requests might
    2993 * immediately arrive and got_init is used for op-code sanity.
    2994 * Especially with external handlers, where we have no control
    2995 * over the thread scheduling.
    2996 */
    2997 se->got_init = 1;
    2998 send_reply_ok(req, &outarg, outargsize);
    2999 if (enable_io_uring)
    3000 fuse_uring_wake_ring_threads(se);
    3001}
    3002
    3003static __attribute__((no_sanitize("thread"))) void
    3004do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    3005{
    3006 _do_init(req, nodeid, inarg, NULL);
    3007}
    3008
    3009static void _do_destroy(fuse_req_t req, const fuse_ino_t nodeid,
    3010 const void *op_in, const void *in_payload)
    3011{
    3012 struct fuse_session *se = req->se;
    3013 char *mountpoint;
    3014
    3015 (void) nodeid;
    3016 (void)op_in;
    3017 (void)in_payload;
    3018
    3019 mountpoint = atomic_exchange(&se->mountpoint, NULL);
    3020 free(mountpoint);
    3021
    3022 se->got_destroy = 1;
    3023 se->got_init = 0;
    3024 if (se->op.destroy)
    3025 se->op.destroy(se->userdata);
    3026
    3027 send_reply_ok(req, NULL, 0);
    3028}
    3029
    3030static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
    3031{
    3032 _do_destroy(req, nodeid, inarg, NULL);
    3033}
    3034
    3035static void list_del_nreq(struct fuse_notify_req *nreq)
    3036{
    3037 struct fuse_notify_req *prev = nreq->prev;
    3038 struct fuse_notify_req *next = nreq->next;
    3039 prev->next = next;
    3040 next->prev = prev;
    3041}
    3042
    3043static void list_add_nreq(struct fuse_notify_req *nreq,
    3044 struct fuse_notify_req *next)
    3045{
    3046 struct fuse_notify_req *prev = next->prev;
    3047 nreq->next = next;
    3048 nreq->prev = prev;
    3049 prev->next = nreq;
    3050 next->prev = nreq;
    3051}
    3052
    3053static void list_init_nreq(struct fuse_notify_req *nreq)
    3054{
    3055 nreq->next = nreq;
    3056 nreq->prev = nreq;
    3057}
    3058
    3059static void _do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
    3060 const void *inarg, const struct fuse_buf *buf)
    3061{
    3062 struct fuse_session *se = req->se;
    3063 struct fuse_notify_req *nreq;
    3064 struct fuse_notify_req *head;
    3065
    3066 pthread_mutex_lock(&se->lock);
    3067 head = &se->notify_list;
    3068 for (nreq = head->next; nreq != head; nreq = nreq->next) {
    3069 if (nreq->unique == req->unique) {
    3070 list_del_nreq(nreq);
    3071 break;
    3072 }
    3073 }
    3074 pthread_mutex_unlock(&se->lock);
    3075
    3076 if (nreq != head)
    3077 nreq->reply(nreq, req, nodeid, inarg, buf);
    3078}
    3079
    3080static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
    3081 const void *inarg, const struct fuse_buf *ibuf)
    3082{
    3083 struct fuse_buf buf = *ibuf;
    3084
    3085 buf.size -= sizeof(struct fuse_in_header);
    3086 _do_notify_reply(req, nodeid, inarg, &buf);
    3087}
    3088
    3089static int send_notify_iov(struct fuse_session *se, int notify_code,
    3090 struct iovec *iov, int count)
    3091{
    3092 struct fuse_out_header out;
    3093 struct fuse_req *req = NULL;
    3094
    3095 if (!se->got_init)
    3096 return -ENOTCONN;
    3097
    3098 out.unique = 0;
    3099 out.error = notify_code;
    3100 iov[0].iov_base = &out;
    3101 iov[0].iov_len = sizeof(struct fuse_out_header);
    3102
    3103 return fuse_send_msg(se, NULL, iov, count, req);
    3104}
    3105
    3106int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
    3107{
    3108 if (ph != NULL) {
    3109 struct fuse_notify_poll_wakeup_out outarg;
    3110 struct iovec iov[2];
    3111
    3112 outarg.kh = ph->kh;
    3113
    3114 iov[1].iov_base = &outarg;
    3115 iov[1].iov_len = sizeof(outarg);
    3116
    3117 return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
    3118 } else {
    3119 return 0;
    3120 }
    3121}
    3122
    3123int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
    3124 off_t off, off_t len)
    3125{
    3126 struct fuse_notify_inval_inode_out outarg;
    3127 struct iovec iov[2];
    3128
    3129 if (!se)
    3130 return -EINVAL;
    3131
    3132 if (se->conn.proto_minor < 12)
    3133 return -ENOSYS;
    3134
    3135 outarg.ino = ino;
    3136 outarg.off = off;
    3137 outarg.len = len;
    3138
    3139 iov[1].iov_base = &outarg;
    3140 iov[1].iov_len = sizeof(outarg);
    3141
    3142 return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
    3143}
    3144
    3145int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
    3146{
    3147 struct iovec iov[1];
    3148
    3149 if (!se)
    3150 return -EINVAL;
    3151
    3152 if (se->conn.proto_minor < 44)
    3153 return -ENOSYS;
    3154
    3155 return send_notify_iov(se, FUSE_NOTIFY_INC_EPOCH, iov, 1);
    3156}
    3157
    3177static int fuse_lowlevel_notify_entry(struct fuse_session *se, fuse_ino_t parent,
    3178 const char *name, size_t namelen,
    3179 enum fuse_notify_entry_flags flags)
    3180{
    3181 struct fuse_notify_inval_entry_out outarg;
    3182 struct iovec iov[3];
    3183
    3184 if (!se)
    3185 return -EINVAL;
    3186
    3187 if (se->conn.proto_minor < 12)
    3188 return -ENOSYS;
    3189
    3190 outarg.parent = parent;
    3191 outarg.namelen = namelen;
    3192 outarg.flags = 0;
    3193 if (flags & FUSE_LL_EXPIRE_ONLY)
    3194 outarg.flags |= FUSE_EXPIRE_ONLY;
    3195
    3196 iov[1].iov_base = &outarg;
    3197 iov[1].iov_len = sizeof(outarg);
    3198 iov[2].iov_base = (void *)name;
    3199 iov[2].iov_len = namelen + 1;
    3200
    3201 return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
    3202}
    3203
    3204int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
    3205 const char *name, size_t namelen)
    3206{
    3207 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE);
    3208}
    3209
    3210int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
    3211 const char *name, size_t namelen)
    3212{
    3213 if (!se)
    3214 return -EINVAL;
    3215
    3216 if (!(se->conn.capable_ext & FUSE_CAP_EXPIRE_ONLY))
    3217 return -ENOSYS;
    3218
    3219 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
    3220}
    3221
    3222
    3223int fuse_lowlevel_notify_delete(struct fuse_session *se,
    3224 fuse_ino_t parent, fuse_ino_t child,
    3225 const char *name, size_t namelen)
    3226{
    3227 struct fuse_notify_delete_out outarg;
    3228 struct iovec iov[3];
    3229
    3230 if (!se)
    3231 return -EINVAL;
    3232
    3233 if (se->conn.proto_minor < 18)
    3234 return -ENOSYS;
    3235
    3236 outarg.parent = parent;
    3237 outarg.child = child;
    3238 outarg.namelen = namelen;
    3239 outarg.padding = 0;
    3240
    3241 iov[1].iov_base = &outarg;
    3242 iov[1].iov_len = sizeof(outarg);
    3243 iov[2].iov_base = (void *)name;
    3244 iov[2].iov_len = namelen + 1;
    3245
    3246 return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
    3247}
    3248
    3249int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
    3250 off_t offset, struct fuse_bufvec *bufv,
    3251 enum fuse_buf_copy_flags flags)
    3252{
    3253 struct fuse_out_header out;
    3254 struct fuse_notify_store_out outarg;
    3255 struct iovec iov[3];
    3256 size_t size = fuse_buf_size(bufv);
    3257 int res;
    3258 struct fuse_req *req = NULL;
    3259
    3260 if (!se)
    3261 return -EINVAL;
    3262
    3263 if (se->conn.proto_minor < 15)
    3264 return -ENOSYS;
    3265
    3266 out.unique = 0;
    3267 out.error = FUSE_NOTIFY_STORE;
    3268
    3269 outarg.nodeid = ino;
    3270 outarg.offset = offset;
    3271 outarg.size = size;
    3272 outarg.padding = 0;
    3273
    3274 iov[0].iov_base = &out;
    3275 iov[0].iov_len = sizeof(out);
    3276 iov[1].iov_base = &outarg;
    3277 iov[1].iov_len = sizeof(outarg);
    3278
    3279 res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags, req);
    3280 if (res > 0)
    3281 res = -res;
    3282
    3283 return res;
    3284}
    3285
    3286struct fuse_retrieve_req {
    3287 struct fuse_notify_req nreq;
    3288 void *cookie;
    3289};
    3290
    3291static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
    3292 fuse_req_t req, fuse_ino_t ino,
    3293 const void *inarg,
    3294 const struct fuse_buf *ibuf)
    3295{
    3296 struct fuse_session *se = req->se;
    3297 struct fuse_retrieve_req *rreq =
    3298 container_of(nreq, struct fuse_retrieve_req, nreq);
    3299 const struct fuse_notify_retrieve_in *arg = inarg;
    3300 struct fuse_bufvec bufv = {
    3301 .buf[0] = *ibuf,
    3302 .count = 1,
    3303 };
    3304
    3305 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
    3306 bufv.buf[0].mem = PARAM(arg);
    3307
    3308 bufv.buf[0].size -= sizeof(struct fuse_notify_retrieve_in);
    3309
    3310 if (bufv.buf[0].size < arg->size) {
    3311 fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
    3312 fuse_reply_none(req);
    3313 goto out;
    3314 }
    3315 bufv.buf[0].size = arg->size;
    3316
    3317 if (se->op.retrieve_reply) {
    3318 se->op.retrieve_reply(req, rreq->cookie, ino,
    3319 arg->offset, &bufv);
    3320 } else {
    3321 fuse_reply_none(req);
    3322 }
    3323out:
    3324 free(rreq);
    3325 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
    3326 fuse_ll_clear_pipe(se);
    3327}
    3328
    3329int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
    3330 size_t size, off_t offset, void *cookie)
    3331{
    3332 struct fuse_notify_retrieve_out outarg;
    3333 struct iovec iov[2];
    3334 struct fuse_retrieve_req *rreq;
    3335 int err;
    3336
    3337 if (!se)
    3338 return -EINVAL;
    3339
    3340 if (se->conn.proto_minor < 15)
    3341 return -ENOSYS;
    3342
    3343 rreq = malloc(sizeof(*rreq));
    3344 if (rreq == NULL)
    3345 return -ENOMEM;
    3346
    3347 pthread_mutex_lock(&se->lock);
    3348 rreq->cookie = cookie;
    3349 rreq->nreq.unique = se->notify_ctr++;
    3350 rreq->nreq.reply = fuse_ll_retrieve_reply;
    3351 list_add_nreq(&rreq->nreq, &se->notify_list);
    3352 pthread_mutex_unlock(&se->lock);
    3353
    3354 outarg.notify_unique = rreq->nreq.unique;
    3355 outarg.nodeid = ino;
    3356 outarg.offset = offset;
    3357 outarg.size = size;
    3358 outarg.padding = 0;
    3359
    3360 iov[1].iov_base = &outarg;
    3361 iov[1].iov_len = sizeof(outarg);
    3362
    3363 err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
    3364 if (err) {
    3365 pthread_mutex_lock(&se->lock);
    3366 list_del_nreq(&rreq->nreq);
    3367 pthread_mutex_unlock(&se->lock);
    3368 free(rreq);
    3369 }
    3370
    3371 return err;
    3372}
    3373
    3375{
    3376 return req->se->userdata;
    3377}
    3378
    3380{
    3381 return &req->ctx;
    3382}
    3383
    3385 void *data)
    3386{
    3387 pthread_mutex_lock(&req->lock);
    3388 pthread_mutex_lock(&req->se->lock);
    3389 req->u.ni.func = func;
    3390 req->u.ni.data = data;
    3391 pthread_mutex_unlock(&req->se->lock);
    3392 if (req->interrupted && func)
    3393 func(req, data);
    3394 pthread_mutex_unlock(&req->lock);
    3395}
    3396
    3398{
    3399 int interrupted;
    3400
    3401 pthread_mutex_lock(&req->se->lock);
    3402 interrupted = req->interrupted;
    3403 pthread_mutex_unlock(&req->se->lock);
    3404
    3405 return interrupted;
    3406}
    3407
    3409{
    3410 return req->flags.is_uring;
    3411}
    3412
    3413#ifndef HAVE_URING
    3414int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz,
    3415 void **mr)
    3416{
    3417 (void)req;
    3418 (void)payload;
    3419 (void)payload_sz;
    3420 (void)mr;
    3421 return -ENOTSUP;
    3422}
    3423#endif
    3424
    3425static struct {
    3426 void (*func)(fuse_req_t req, const fuse_ino_t node, const void *arg);
    3427 const char *name;
    3428} fuse_ll_ops[] = {
    3429 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
    3430 [FUSE_FORGET] = { do_forget, "FORGET" },
    3431 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
    3432 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
    3433 [FUSE_READLINK] = { do_readlink, "READLINK" },
    3434 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
    3435 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
    3436 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
    3437 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
    3438 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
    3439 [FUSE_RENAME] = { do_rename, "RENAME" },
    3440 [FUSE_LINK] = { do_link, "LINK" },
    3441 [FUSE_OPEN] = { do_open, "OPEN" },
    3442 [FUSE_READ] = { do_read, "READ" },
    3443 [FUSE_WRITE] = { do_write, "WRITE" },
    3444 [FUSE_STATFS] = { do_statfs, "STATFS" },
    3445 [FUSE_RELEASE] = { do_release, "RELEASE" },
    3446 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
    3447 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
    3448 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
    3449 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
    3450 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
    3451 [FUSE_FLUSH] = { do_flush, "FLUSH" },
    3452 [FUSE_INIT] = { do_init, "INIT" },
    3453 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
    3454 [FUSE_READDIR] = { do_readdir, "READDIR" },
    3455 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
    3456 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
    3457 [FUSE_GETLK] = { do_getlk, "GETLK" },
    3458 [FUSE_SETLK] = { do_setlk, "SETLK" },
    3459 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
    3460 [FUSE_ACCESS] = { do_access, "ACCESS" },
    3461 [FUSE_CREATE] = { do_create, "CREATE" },
    3462 [FUSE_TMPFILE] = { do_tmpfile, "TMPFILE" },
    3463 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
    3464 [FUSE_BMAP] = { do_bmap, "BMAP" },
    3465 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
    3466 [FUSE_POLL] = { do_poll, "POLL" },
    3467 [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
    3468 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
    3469 [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
    3470 [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
    3471 [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
    3472 [FUSE_RENAME2] = { do_rename2, "RENAME2" },
    3473 [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
    3474 [FUSE_COPY_FILE_RANGE_64] = { do_copy_file_range_64, "COPY_FILE_RANGE_64" },
    3475 [FUSE_LSEEK] = { do_lseek, "LSEEK" },
    3476 [FUSE_STATX] = { do_statx, "STATX" },
    3477 [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
    3478};
    3479
    3480static struct {
    3481 void (*func)(fuse_req_t req, const fuse_ino_t ino, const void *op_in,
    3482 const void *op_payload);
    3483 const char *name;
    3484} fuse_ll_ops2[] __attribute__((unused)) = {
    3485 [FUSE_LOOKUP] = { _do_lookup, "LOOKUP" },
    3486 [FUSE_FORGET] = { _do_forget, "FORGET" },
    3487 [FUSE_GETATTR] = { _do_getattr, "GETATTR" },
    3488 [FUSE_SETATTR] = { _do_setattr, "SETATTR" },
    3489 [FUSE_READLINK] = { _do_readlink, "READLINK" },
    3490 [FUSE_SYMLINK] = { _do_symlink, "SYMLINK" },
    3491 [FUSE_MKNOD] = { _do_mknod, "MKNOD" },
    3492 [FUSE_MKDIR] = { _do_mkdir, "MKDIR" },
    3493 [FUSE_UNLINK] = { _do_unlink, "UNLINK" },
    3494 [FUSE_RMDIR] = { _do_rmdir, "RMDIR" },
    3495 [FUSE_RENAME] = { _do_rename, "RENAME" },
    3496 [FUSE_LINK] = { _do_link, "LINK" },
    3497 [FUSE_OPEN] = { _do_open, "OPEN" },
    3498 [FUSE_READ] = { _do_read, "READ" },
    3499 [FUSE_WRITE] = { _do_write, "WRITE" },
    3500 [FUSE_STATFS] = { _do_statfs, "STATFS" },
    3501 [FUSE_RELEASE] = { _do_release, "RELEASE" },
    3502 [FUSE_FSYNC] = { _do_fsync, "FSYNC" },
    3503 [FUSE_SETXATTR] = { _do_setxattr, "SETXATTR" },
    3504 [FUSE_GETXATTR] = { _do_getxattr, "GETXATTR" },
    3505 [FUSE_LISTXATTR] = { _do_listxattr, "LISTXATTR" },
    3506 [FUSE_REMOVEXATTR] = { _do_removexattr, "REMOVEXATTR" },
    3507 [FUSE_FLUSH] = { _do_flush, "FLUSH" },
    3508 [FUSE_INIT] = { _do_init, "INIT" },
    3509 [FUSE_OPENDIR] = { _do_opendir, "OPENDIR" },
    3510 [FUSE_READDIR] = { _do_readdir, "READDIR" },
    3511 [FUSE_RELEASEDIR] = { _do_releasedir, "RELEASEDIR" },
    3512 [FUSE_FSYNCDIR] = { _do_fsyncdir, "FSYNCDIR" },
    3513 [FUSE_GETLK] = { _do_getlk, "GETLK" },
    3514 [FUSE_SETLK] = { _do_setlk, "SETLK" },
    3515 [FUSE_SETLKW] = { _do_setlkw, "SETLKW" },
    3516 [FUSE_ACCESS] = { _do_access, "ACCESS" },
    3517 [FUSE_CREATE] = { _do_create, "CREATE" },
    3518 [FUSE_TMPFILE] = { _do_tmpfile, "TMPFILE" },
    3519 [FUSE_INTERRUPT] = { _do_interrupt, "INTERRUPT" },
    3520 [FUSE_BMAP] = { _do_bmap, "BMAP" },
    3521 [FUSE_IOCTL] = { _do_ioctl, "IOCTL" },
    3522 [FUSE_POLL] = { _do_poll, "POLL" },
    3523 [FUSE_FALLOCATE] = { _do_fallocate, "FALLOCATE" },
    3524 [FUSE_DESTROY] = { _do_destroy, "DESTROY" },
    3525 [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" },
    3526 [FUSE_BATCH_FORGET] = { _do_batch_forget, "BATCH_FORGET" },
    3527 [FUSE_READDIRPLUS] = { _do_readdirplus, "READDIRPLUS" },
    3528 [FUSE_RENAME2] = { _do_rename2, "RENAME2" },
    3529 [FUSE_COPY_FILE_RANGE] = { _do_copy_file_range, "COPY_FILE_RANGE" },
    3530 [FUSE_COPY_FILE_RANGE_64] = { _do_copy_file_range_64, "COPY_FILE_RANGE_64" },
    3531 [FUSE_LSEEK] = { _do_lseek, "LSEEK" },
    3532 [FUSE_STATX] = { _do_statx, "STATX" },
    3533 [CUSE_INIT] = { _cuse_lowlevel_init, "CUSE_INIT" },
    3534};
    3535
    3536/*
    3537 * For ABI compatibility we cannot allow higher values than CUSE_INIT.
    3538 * Without ABI compatibility we could use the size of the array.
    3539 * #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
    3540 */
    3541#define FUSE_MAXOP (CUSE_INIT + 1)
    3542
    3543
    3548static inline int
    3549fuse_req_opcode_sanity_ok(struct fuse_session *se, enum fuse_opcode in_op)
    3550{
    3551 int err = EIO;
    3552
    3553 if (!se->got_init) {
    3554 enum fuse_opcode expected;
    3555
    3556 expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
    3557 if (in_op != expected)
    3558 return err;
    3559 } else if (in_op == FUSE_INIT || in_op == CUSE_INIT)
    3560 return err;
    3561
    3562 return 0;
    3563}
    3564
    3565static inline void
    3566fuse_session_in2req(struct fuse_req *req, struct fuse_in_header *in)
    3567{
    3568 req->unique = in->unique;
    3569 req->ctx.uid = in->uid;
    3570 req->ctx.gid = in->gid;
    3571 req->ctx.pid = in->pid;
    3572}
    3573
    3577static inline int
    3578fuse_req_check_allow_root(struct fuse_session *se, enum fuse_opcode in_op,
    3579 uid_t in_uid)
    3580{
    3581 int err = EACCES;
    3582
    3583 if (se->deny_others && in_uid != se->owner && in_uid != 0 &&
    3584 in_op != FUSE_INIT && in_op != FUSE_READ &&
    3585 in_op != FUSE_WRITE && in_op != FUSE_FSYNC &&
    3586 in_op != FUSE_RELEASE && in_op != FUSE_READDIR &&
    3587 in_op != FUSE_FSYNCDIR && in_op != FUSE_RELEASEDIR &&
    3588 in_op != FUSE_NOTIFY_REPLY &&
    3589 in_op != FUSE_READDIRPLUS)
    3590 return err;
    3591
    3592 return 0;
    3593}
    3594
    3595static const char *opname(enum fuse_opcode opcode)
    3596{
    3597 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
    3598 return "???";
    3599 else
    3600 return fuse_ll_ops[opcode].name;
    3601}
    3602
    3603static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
    3604 struct fuse_bufvec *src)
    3605{
    3606 ssize_t res = fuse_buf_copy(dst, src, 0);
    3607 if (res < 0) {
    3608 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
    3609 return res;
    3610 }
    3611 if ((size_t)res < fuse_buf_size(dst)) {
    3612 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
    3613 return -1;
    3614 }
    3615 return 0;
    3616}
    3617
    3618void fuse_session_process_buf(struct fuse_session *se,
    3619 const struct fuse_buf *buf)
    3620{
    3621 fuse_session_process_buf_internal(se, buf, NULL);
    3622}
    3623
    3624/* libfuse internal handler */
    3625void fuse_session_process_buf_internal(struct fuse_session *se,
    3626 const struct fuse_buf *buf, struct fuse_chan *ch)
    3627{
    3628 const size_t write_header_size = sizeof(struct fuse_in_header) +
    3629 sizeof(struct fuse_write_in);
    3630 struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
    3631 struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
    3632 struct fuse_in_header *in;
    3633 const void *inarg;
    3634 struct fuse_req *req;
    3635 void *mbuf = NULL;
    3636 int err;
    3637 int res;
    3638
    3639 if (buf->flags & FUSE_BUF_IS_FD) {
    3640 if (buf->size < tmpbuf.buf[0].size)
    3641 tmpbuf.buf[0].size = buf->size;
    3642
    3643 mbuf = malloc(tmpbuf.buf[0].size);
    3644 if (mbuf == NULL) {
    3645 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
    3646 goto clear_pipe;
    3647 }
    3648 tmpbuf.buf[0].mem = mbuf;
    3649
    3650 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
    3651 if (res < 0)
    3652 goto clear_pipe;
    3653
    3654 in = mbuf;
    3655 } else {
    3656 in = buf->mem;
    3657 }
    3658
    3659 trace_request_process(in->opcode, in->unique);
    3660
    3661 if (se->debug) {
    3662 fuse_log(FUSE_LOG_DEBUG,
    3663 "dev unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
    3664 (unsigned long long) in->unique,
    3665 opname((enum fuse_opcode) in->opcode), in->opcode,
    3666 (unsigned long long) in->nodeid, buf->size, in->pid);
    3667 }
    3668
    3669 req = fuse_ll_alloc_req(se);
    3670 if (req == NULL) {
    3671 struct fuse_out_header out = {
    3672 .unique = in->unique,
    3673 .error = -ENOMEM,
    3674 };
    3675 struct iovec iov = {
    3676 .iov_base = &out,
    3677 .iov_len = sizeof(struct fuse_out_header),
    3678 };
    3679
    3680 fuse_send_msg(se, ch, &iov, 1, NULL);
    3681 goto clear_pipe;
    3682 }
    3683
    3684 fuse_session_in2req(req, in);
    3685 req->ch = ch ? fuse_chan_get(ch) : NULL;
    3686
    3687 err = fuse_req_opcode_sanity_ok(se, in->opcode);
    3688 if (err)
    3689 goto reply_err;
    3690
    3691 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
    3692 if (err)
    3693 goto reply_err;
    3694
    3695 err = ENOSYS;
    3696 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
    3697 goto reply_err;
    3698 /* Do not process interrupt request */
    3699 if (se->conn.no_interrupt && in->opcode == FUSE_INTERRUPT) {
    3700 if (se->debug)
    3701 fuse_log(FUSE_LOG_DEBUG, "FUSE_INTERRUPT: reply to kernel to disable interrupt\n");
    3702 goto reply_err;
    3703 }
    3704 if (!se->conn.no_interrupt && in->opcode != FUSE_INTERRUPT) {
    3705 struct fuse_req *intr;
    3706 pthread_mutex_lock(&se->lock);
    3707 intr = check_interrupt(se, req);
    3708 list_add_req(req, &se->list);
    3709 pthread_mutex_unlock(&se->lock);
    3710 if (intr)
    3711 fuse_reply_err(intr, EAGAIN);
    3712 }
    3713
    3714 if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
    3715 (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
    3716 in->opcode != FUSE_NOTIFY_REPLY) {
    3717 void *newmbuf;
    3718
    3719 err = ENOMEM;
    3720 newmbuf = realloc(mbuf, buf->size);
    3721 if (newmbuf == NULL)
    3722 goto reply_err;
    3723 mbuf = newmbuf;
    3724
    3725 tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
    3726 tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
    3727
    3728 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
    3729 err = -res;
    3730 if (res < 0)
    3731 goto reply_err;
    3732
    3733 in = mbuf;
    3734 }
    3735
    3736 inarg = (void *) &in[1];
    3737 if (in->opcode == FUSE_WRITE && se->op.write_buf)
    3738 do_write_buf(req, in->nodeid, inarg, buf);
    3739 else if (in->opcode == FUSE_NOTIFY_REPLY)
    3740 do_notify_reply(req, in->nodeid, inarg, buf);
    3741 else
    3742 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
    3743
    3744out_free:
    3745 free(mbuf);
    3746 return;
    3747
    3748reply_err:
    3749 fuse_reply_err(req, err);
    3750clear_pipe:
    3751 if (buf->flags & FUSE_BUF_IS_FD)
    3752 fuse_ll_clear_pipe(se);
    3753 goto out_free;
    3754}
    3755
    3756void fuse_session_process_uring_cqe(struct fuse_session *se,
    3757 struct fuse_req *req,
    3758 struct fuse_in_header *in, void *op_in,
    3759 void *op_payload, size_t payload_len)
    3760{
    3761 int err;
    3762
    3763 fuse_session_in2req(req, in);
    3764
    3765 err = fuse_req_opcode_sanity_ok(se, in->opcode);
    3766 if (err)
    3767 goto reply_err;
    3768
    3769 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
    3770 if (err)
    3771 goto reply_err;
    3772
    3773 err = ENOSYS;
    3774 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops2[in->opcode].func)
    3775 goto reply_err;
    3776
    3777 if (se->debug) {
    3778 fuse_log(
    3779 FUSE_LOG_DEBUG,
    3780 "cqe unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
    3781 (unsigned long long)in->unique,
    3782 opname((enum fuse_opcode)in->opcode), in->opcode,
    3783 (unsigned long long)in->nodeid, payload_len, in->pid);
    3784 }
    3785
    3786 if (in->opcode == FUSE_WRITE && se->op.write_buf) {
    3787 struct fuse_bufvec bufv = {
    3788 .buf[0] = { .size = payload_len,
    3789 .flags = 0,
    3790 .mem = op_payload },
    3791 .count = 1,
    3792 };
    3793 _do_write_buf(req, in->nodeid, op_in, &bufv);
    3794 } else if (in->opcode == FUSE_NOTIFY_REPLY) {
    3795 struct fuse_buf buf = { .size = payload_len,
    3796 .mem = op_payload };
    3797 _do_notify_reply(req, in->nodeid, op_payload, &buf);
    3798 } else {
    3799 fuse_ll_ops2[in->opcode].func(req, in->nodeid, op_in,
    3800 op_payload);
    3801 }
    3802
    3803 return;
    3804
    3805reply_err:
    3806 fuse_reply_err(req, err);
    3807}
    3808
    3809#define LL_OPTION(n,o,v) \
    3810 { n, offsetof(struct fuse_session, o), v }
    3811
    3812static const struct fuse_opt fuse_ll_opts[] = {
    3813 LL_OPTION("debug", debug, 1),
    3814 LL_OPTION("-d", debug, 1),
    3815 LL_OPTION("--debug", debug, 1),
    3816 LL_OPTION("allow_root", deny_others, 1),
    3817 LL_OPTION("io_uring", uring.enable, 1),
    3818 LL_OPTION("io_uring_q_depth=%u", uring.q_depth, -1),
    3820};
    3821
    3823{
    3824 printf("using FUSE kernel interface version %i.%i\n",
    3825 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
    3826 fuse_mount_version();
    3827}
    3828
    3830{
    3831 /* These are not all options, but the ones that are
    3832 potentially of interest to an end-user */
    3833 printf(
    3834" -o allow_other allow access by all users\n"
    3835" -o allow_root allow access by root\n"
    3836" -o auto_unmount auto unmount on process termination\n"
    3837" -o io_uring enable io-uring\n"
    3838" -o io_uring_q_depth=<n> io-uring queue depth\n"
    3839);
    3840}
    3841
    3842void fuse_session_destroy(struct fuse_session *se)
    3843{
    3844 struct fuse_ll_pipe *llp;
    3845
    3846 if (se->got_init && !se->got_destroy) {
    3847 if (se->op.destroy)
    3848 se->op.destroy(se->userdata);
    3849 }
    3850 llp = pthread_getspecific(se->pipe_key);
    3851 if (llp != NULL)
    3852 fuse_ll_pipe_free(llp);
    3853 pthread_key_delete(se->pipe_key);
    3854 sem_destroy(&se->mt_finish);
    3855 pthread_mutex_destroy(&se->mt_lock);
    3856 pthread_mutex_destroy(&se->lock);
    3857 free(se->cuse_data);
    3858 if (se->fd != -1)
    3859 close(se->fd);
    3860 if (se->io != NULL)
    3861 free(se->io);
    3862 destroy_mount_opts(se->mo);
    3863 free(atomic_exchange(&se->mountpoint, NULL));
    3864 free(se);
    3865}
    3866
    3867
    3868static void fuse_ll_pipe_destructor(void *data)
    3869{
    3870 struct fuse_ll_pipe *llp = data;
    3871 fuse_ll_pipe_free(llp);
    3872}
    3873
    3874void fuse_buf_free(struct fuse_buf *buf)
    3875{
    3876 if (buf->mem == NULL)
    3877 return;
    3878
    3879 size_t write_header_sz =
    3880 sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
    3881
    3882 char *ptr = (char *)buf->mem - pagesize + write_header_sz;
    3883 free(ptr);
    3884 buf->mem = NULL;
    3885}
    3886
    3887/*
    3888 * This is used to allocate buffers that hold fuse requests
    3889 */
    3890static void *buf_alloc(size_t size, bool internal)
    3891{
    3892 /*
    3893 * For libfuse internal caller add in alignment. That cannot be done
    3894 * for an external caller, as it is not guaranteed that the external
    3895 * caller frees the raw pointer.
    3896 */
    3897 if (internal) {
    3898 size_t write_header_sz = sizeof(struct fuse_in_header) +
    3899 sizeof(struct fuse_write_in);
    3900 size_t new_size = ROUND_UP(size + write_header_sz, pagesize);
    3901
    3902 char *buf = aligned_alloc(pagesize, new_size);
    3903 if (buf == NULL)
    3904 return NULL;
    3905
    3906 buf += pagesize - write_header_sz;
    3907
    3908 return buf;
    3909 } else {
    3910 return malloc(size);
    3911 }
    3912}
    3913
    3914/*
    3915 *@param internal true if called from libfuse internal code
    3916 */
    3917static int _fuse_session_receive_buf(struct fuse_session *se,
    3918 struct fuse_buf *buf, struct fuse_chan *ch,
    3919 bool internal)
    3920{
    3921 int err;
    3922 ssize_t res;
    3923 size_t bufsize;
    3924#ifdef HAVE_SPLICE
    3925 struct fuse_ll_pipe *llp;
    3926 struct fuse_buf tmpbuf;
    3927
    3928pipe_retry:
    3929 bufsize = se->bufsize;
    3930
    3931 if (se->conn.proto_minor < 14 ||
    3932 !(se->conn.want_ext & FUSE_CAP_SPLICE_READ))
    3933 goto fallback;
    3934
    3935 llp = fuse_ll_get_pipe(se);
    3936 if (llp == NULL)
    3937 goto fallback;
    3938
    3939 if (llp->size < bufsize) {
    3940 if (llp->can_grow) {
    3941 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
    3942 if (res == -1) {
    3943 llp->can_grow = 0;
    3944 res = grow_pipe_to_max(llp->pipe[0]);
    3945 if (res > 0)
    3946 llp->size = res;
    3947 fuse_ll_clear_pipe(se);
    3948 goto fallback;
    3949 }
    3950 llp->size = res;
    3951 }
    3952 if (llp->size < bufsize) {
    3953 fuse_ll_clear_pipe(se);
    3954 goto fallback;
    3955 }
    3956 }
    3957
    3958 if (se->io != NULL && se->io->splice_receive != NULL) {
    3959 res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
    3960 llp->pipe[1], NULL, bufsize, 0,
    3961 se->userdata);
    3962 } else {
    3963 res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
    3964 bufsize, 0);
    3965 }
    3966 err = errno;
    3967 trace_request_receive(err);
    3968
    3969 if (fuse_session_exited(se))
    3970 return 0;
    3971
    3972 if (res == -1) {
    3973 if (err == ENODEV) {
    3974 /* Filesystem was unmounted, or connection was aborted
    3975 via /sys/fs/fuse/connections */
    3977 return 0;
    3978 }
    3979
    3980 /* FUSE_INIT might have increased the required bufsize */
    3981 if (err == EINVAL && bufsize < se->bufsize) {
    3982 fuse_ll_clear_pipe(se);
    3983 goto pipe_retry;
    3984 }
    3985
    3986 if (err != EINTR && err != EAGAIN)
    3987 perror("fuse: splice from device");
    3988 return -err;
    3989 }
    3990
    3991 if (res < sizeof(struct fuse_in_header)) {
    3992 fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
    3993 return -EIO;
    3994 }
    3995
    3996 tmpbuf = (struct fuse_buf){
    3997 .size = res,
    3998 .flags = FUSE_BUF_IS_FD,
    3999 .fd = llp->pipe[0],
    4000 };
    4001
    4002 /*
    4003 * Don't bother with zero copy for small requests.
    4004 * fuse_loop_mt() needs to check for FORGET so this more than
    4005 * just an optimization.
    4006 */
    4007 if (res < sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) +
    4008 pagesize) {
    4009 struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
    4010 struct fuse_bufvec dst = { .count = 1 };
    4011
    4012 if (!buf->mem) {
    4013 buf->mem = buf_alloc(bufsize, internal);
    4014 if (!buf->mem) {
    4015 fuse_log(
    4016 FUSE_LOG_ERR,
    4017 "fuse: failed to allocate read buffer\n");
    4018 return -ENOMEM;
    4019 }
    4020 buf->mem_size = bufsize;
    4021 }
    4022 buf->size = bufsize;
    4023 buf->flags = 0;
    4024 dst.buf[0] = *buf;
    4025
    4026 res = fuse_buf_copy(&dst, &src, 0);
    4027 if (res < 0) {
    4028 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
    4029 strerror(-res));
    4030 fuse_ll_clear_pipe(se);
    4031 return res;
    4032 }
    4033 if (res < tmpbuf.size) {
    4034 fuse_log(FUSE_LOG_ERR,
    4035 "fuse: copy from pipe: short read\n");
    4036 fuse_ll_clear_pipe(se);
    4037 return -EIO;
    4038 }
    4039 assert(res == tmpbuf.size);
    4040
    4041 } else {
    4042 /* Don't overwrite buf->mem, as that would cause a leak */
    4043 buf->fd = tmpbuf.fd;
    4044 buf->flags = tmpbuf.flags;
    4045 }
    4046 buf->size = tmpbuf.size;
    4047
    4048 return res;
    4049
    4050fallback:
    4051#endif
    4052 bufsize = internal ? buf->mem_size : se->bufsize;
    4053 if (!buf->mem) {
    4054 bufsize = se->bufsize; /* might have changed */
    4055 buf->mem = buf_alloc(bufsize, internal);
    4056 if (!buf->mem) {
    4057 fuse_log(FUSE_LOG_ERR,
    4058 "fuse: failed to allocate read buffer\n");
    4059 return -ENOMEM;
    4060 }
    4061
    4062 if (internal)
    4063 buf->mem_size = bufsize;
    4064 }
    4065
    4066restart:
    4067 if (se->io != NULL) {
    4068 /* se->io->read is never NULL if se->io is not NULL as
    4069 specified by fuse_session_custom_io()*/
    4070 res = se->io->read(ch ? ch->fd : se->fd, buf->mem, bufsize,
    4071 se->userdata);
    4072 } else {
    4073 res = read(ch ? ch->fd : se->fd, buf->mem, bufsize);
    4074 }
    4075 err = errno;
    4076 trace_request_receive(err);
    4077
    4078 if (fuse_session_exited(se))
    4079 return 0;
    4080 if (res == -1) {
    4081 if (err == EINVAL && internal && se->bufsize > bufsize) {
    4082 /* FUSE_INIT might have increased the required bufsize */
    4083 bufsize = se->bufsize;
    4084 void *newbuf = buf_alloc(bufsize, internal);
    4085 if (!newbuf) {
    4086 fuse_log(
    4087 FUSE_LOG_ERR,
    4088 "fuse: failed to (re)allocate read buffer\n");
    4089 return -ENOMEM;
    4090 }
    4091 fuse_buf_free(buf);
    4092 buf->mem = newbuf;
    4093 buf->mem_size = bufsize;
    4094 goto restart;
    4095 }
    4096
    4097 /* ENOENT means the operation was interrupted, it's safe
    4098 to restart */
    4099 if (err == ENOENT)
    4100 goto restart;
    4101
    4102 if (err == ENODEV) {
    4103 /* Filesystem was unmounted, or connection was aborted
    4104 via /sys/fs/fuse/connections */
    4106 return 0;
    4107 }
    4108 /* Errors occurring during normal operation: EINTR (read
    4109 interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
    4110 umounted) */
    4111 if (err != EINTR && err != EAGAIN)
    4112 perror("fuse: reading device");
    4113 return -err;
    4114 }
    4115 if ((size_t)res < sizeof(struct fuse_in_header)) {
    4116 fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
    4117 return -EIO;
    4118 }
    4119
    4120 buf->size = res;
    4121
    4122 return res;
    4123}
    4124
    4125int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
    4126{
    4127 return _fuse_session_receive_buf(se, buf, NULL, false);
    4128}
    4129
    4130/* libfuse internal handler */
    4131int fuse_session_receive_buf_internal(struct fuse_session *se,
    4132 struct fuse_buf *buf,
    4133 struct fuse_chan *ch)
    4134{
    4135 /*
    4136 * if run internally thread buffers are from libfuse - we can
    4137 * reallocate them
    4138 */
    4139 if (unlikely(!se->got_init) && !se->buf_reallocable)
    4140 se->buf_reallocable = true;
    4141
    4142 return _fuse_session_receive_buf(se, buf, ch, true);
    4143}
    4144
    4145struct fuse_session *
    4146fuse_session_new_versioned(struct fuse_args *args,
    4147 const struct fuse_lowlevel_ops *op, size_t op_size,
    4148 struct libfuse_version *version, void *userdata)
    4149{
    4150 int err;
    4151 struct fuse_session *se;
    4152 struct mount_opts *mo;
    4153
    4154 if (op == NULL || op_size == 0) {
    4155 fuse_log(FUSE_LOG_ERR,
    4156 "fuse: warning: empty op list passed to fuse_session_new()\n");
    4157 return NULL;
    4158 }
    4159
    4160 if (version == NULL) {
    4161 fuse_log(FUSE_LOG_ERR, "fuse: warning: version not passed to fuse_session_new()\n");
    4162 return NULL;
    4163 }
    4164
    4165 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
    4166 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
    4167 op_size = sizeof(struct fuse_lowlevel_ops);
    4168 }
    4169
    4170 if (args == NULL || args->argc == 0) {
    4171 fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
    4172 return NULL;
    4173 }
    4174
    4175 se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
    4176 if (se == NULL) {
    4177 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
    4178 goto out1;
    4179 }
    4180 se->fd = -1;
    4181 se->conn.max_write = FUSE_DEFAULT_MAX_PAGES_LIMIT * getpagesize();
    4182 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
    4183 se->conn.max_readahead = UINT_MAX;
    4184
    4185 /*
    4186 * Allow overriding with env, mostly to avoid the need to modify
    4187 * all tests. I.e. to test with and without io-uring being enabled.
    4188 */
    4189 se->uring.enable = getenv("FUSE_URING_ENABLE") ?
    4190 atoi(getenv("FUSE_URING_ENABLE")) :
    4191 SESSION_DEF_URING_ENABLE;
    4192 se->uring.q_depth = getenv("FUSE_URING_QUEUE_DEPTH") ?
    4193 atoi(getenv("FUSE_URING_QUEUE_DEPTH")) :
    4194 SESSION_DEF_URING_Q_DEPTH;
    4195
    4196 /* Parse options */
    4197 if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
    4198 goto out2;
    4199 if(se->deny_others) {
    4200 /* Allowing access only by root is done by instructing
    4201 * kernel to allow access by everyone, and then restricting
    4202 * access to root and mountpoint owner in libfuse.
    4203 */
    4204 // We may be adding the option a second time, but
    4205 // that doesn't hurt.
    4206 if(fuse_opt_add_arg(args, "-oallow_other") == -1)
    4207 goto out2;
    4208 }
    4209 mo = parse_mount_opts(args);
    4210 if (mo == NULL)
    4211 goto out3;
    4212
    4213 if(args->argc == 1 &&
    4214 args->argv[0][0] == '-') {
    4215 fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
    4216 "will be ignored\n");
    4217 } else if (args->argc != 1) {
    4218 int i;
    4219 fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
    4220 for(i = 1; i < args->argc-1; i++)
    4221 fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
    4222 fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
    4223 goto out4;
    4224 }
    4225
    4226 if (se->debug)
    4227 fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
    4228
    4229 list_init_req(&se->list);
    4230 list_init_req(&se->interrupts);
    4231 list_init_nreq(&se->notify_list);
    4232 se->notify_ctr = 1;
    4233 pthread_mutex_init(&se->lock, NULL);
    4234 sem_init(&se->mt_finish, 0, 0);
    4235 pthread_mutex_init(&se->mt_lock, NULL);
    4236
    4237 err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
    4238 if (err) {
    4239 fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
    4240 strerror(err));
    4241 goto out5;
    4242 }
    4243
    4244 memcpy(&se->op, op, op_size);
    4245 se->owner = getuid();
    4246 se->userdata = userdata;
    4247
    4248 se->mo = mo;
    4249
    4250 /* Fuse server application should pass the version it was compiled
    4251 * against and pass it. If a libfuse version accidentally introduces an
    4252 * ABI incompatibility, it might be possible to 'fix' that at run time,
    4253 * by checking the version numbers.
    4254 */
    4255 se->version = *version;
    4256
    4257 return se;
    4258
    4259out5:
    4260 sem_destroy(&se->mt_finish);
    4261 pthread_mutex_destroy(&se->mt_lock);
    4262 pthread_mutex_destroy(&se->lock);
    4263out4:
    4264 fuse_opt_free_args(args);
    4265out3:
    4266 if (mo != NULL)
    4267 destroy_mount_opts(mo);
    4268out2:
    4269 free(se);
    4270out1:
    4271 return NULL;
    4272}
    4273
    4274struct fuse_session *fuse_session_new_30(struct fuse_args *args,
    4275 const struct fuse_lowlevel_ops *op,
    4276 size_t op_size, void *userdata);
    4277struct fuse_session *fuse_session_new_30(struct fuse_args *args,
    4278 const struct fuse_lowlevel_ops *op,
    4279 size_t op_size,
    4280 void *userdata)
    4281{
    4282 struct fuse_lowlevel_ops null_ops = { 0 };
    4283
    4284 /* unknown version */
    4285 struct libfuse_version version = { 0 };
    4286
    4287 /*
    4288 * This function is the ABI interface function from fuse_session_new in
    4289 * compat.c. External libraries like "fuser" might call fuse_session_new()
    4290 * with NULL ops and then pass that session to fuse_session_mount().
    4291 * The actual FUSE operations are handled in their own library.
    4292 */
    4293 if (op == NULL) {
    4294 op = &null_ops;
    4295 op_size = sizeof(null_ops);
    4296 }
    4297
    4298 return fuse_session_new_versioned(args, op, op_size, &version,
    4299 userdata);
    4300}
    4301
    4302FUSE_SYMVER("fuse_session_custom_io_317", "fuse_session_custom_io@@FUSE_3.17")
    4303int fuse_session_custom_io_317(struct fuse_session *se,
    4304 const struct fuse_custom_io *io, size_t op_size, int fd)
    4305{
    4306#ifndef HAVE_CUSTOM_IO
    4307 (void)se;
    4308 (void)io;
    4309 (void)op_size;
    4310 (void)fd;
    4311 fuse_log(FUSE_LOG_ERR, "fuse: custom io is not enabled in this build\n");
    4312 return -ENOTSUP;
    4313#else
    4314 if (sizeof(struct fuse_custom_io) < op_size) {
    4315 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
    4316 op_size = sizeof(struct fuse_custom_io);
    4317 }
    4318
    4319 if (fd < 0) {
    4320 fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to "
    4321 "fuse_session_custom_io()\n", fd);
    4322 return -EBADF;
    4323 }
    4324 if (io == NULL) {
    4325 fuse_log(FUSE_LOG_ERR, "No custom IO passed to "
    4326 "fuse_session_custom_io()\n");
    4327 return -EINVAL;
    4328 } else if (io->read == NULL || io->writev == NULL) {
    4329 /* If the user provides their own file descriptor, we can't
    4330 guarantee that the default behavior of the io operations made
    4331 in libfuse will function properly. Therefore, we enforce the
    4332 user to implement these io operations when using custom io. */
    4333 fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must "
    4334 "implement both io->read() and io->writev\n");
    4335 return -EINVAL;
    4336 }
    4337
    4338 se->io = calloc(1, sizeof(struct fuse_custom_io));
    4339 if (se->io == NULL) {
    4340 fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. "
    4341 "Error: %s\n", strerror(errno));
    4342 return -errno;
    4343 }
    4344
    4345 se->fd = fd;
    4346 memcpy(se->io, io, op_size);
    4347 return 0;
    4348#endif
    4349}
    4350
    4351int fuse_session_custom_io_30(struct fuse_session *se,
    4352 const struct fuse_custom_io *io, int fd);
    4353FUSE_SYMVER("fuse_session_custom_io_30", "fuse_session_custom_io@FUSE_3.0")
    4354int fuse_session_custom_io_30(struct fuse_session *se,
    4355 const struct fuse_custom_io *io, int fd)
    4356{
    4357 return fuse_session_custom_io_317(se, io,
    4358 offsetof(struct fuse_custom_io, clone_fd), fd);
    4359}
    4360
    4361int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
    4362{
    4363 int fd;
    4364 char *mountpoint;
    4365
    4366 if (_mountpoint == NULL) {
    4367 fuse_log(FUSE_LOG_ERR, "Invalid null-ptr mountpoint!\n");
    4368 return -1;
    4369 }
    4370
    4371 mountpoint = strdup(_mountpoint);
    4372 if (mountpoint == NULL) {
    4373 fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for mountpoint. Error: %s\n",
    4374 strerror(errno));
    4375 return -1;
    4376 }
    4377
    4378 /*
    4379 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
    4380 * would ensue.
    4381 */
    4382 do {
    4383 fd = open("/dev/null", O_RDWR);
    4384 if (fd > 2)
    4385 close(fd);
    4386 } while (fd >= 0 && fd <= 2);
    4387
    4388 /*
    4389 * To allow FUSE daemons to run without privileges, the caller may open
    4390 * /dev/fuse before launching the file system and pass on the file
    4391 * descriptor by specifying /dev/fd/N as the mount point. Note that the
    4392 * parent process takes care of performing the mount in this case.
    4393 */
    4394 fd = fuse_mnt_parse_fuse_fd(mountpoint);
    4395 if (fd != -1) {
    4396 if (fcntl(fd, F_GETFD) == -1) {
    4397 fuse_log(FUSE_LOG_ERR,
    4398 "fuse: Invalid file descriptor /dev/fd/%u\n",
    4399 fd);
    4400 goto error_out;
    4401 }
    4402 goto out;
    4403 }
    4404
    4405 /* Open channel */
    4406 fd = fuse_kern_mount(mountpoint, se->mo);
    4407 if (fd == -1)
    4408 goto error_out;
    4409
    4410out:
    4411 se->fd = fd;
    4412 se->mountpoint = mountpoint;
    4413
    4414 return 0;
    4415
    4416error_out:
    4417 free(mountpoint);
    4418 return -1;
    4419}
    4420
    4421int fuse_session_fd(struct fuse_session *se)
    4422{
    4423 return se->fd;
    4424}
    4425
    4426void fuse_session_unmount(struct fuse_session *se)
    4427{
    4428 if (se->mountpoint != NULL) {
    4429 char *mountpoint = atomic_exchange(&se->mountpoint, NULL);
    4430
    4431 fuse_kern_unmount(mountpoint, se->fd);
    4432 se->fd = -1;
    4433 free(mountpoint);
    4434 }
    4435}
    4436
    4437#ifdef linux
    4438int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
    4439{
    4440 char *buf;
    4441 size_t bufsize = 1024;
    4442 char path[128];
    4443 int ret;
    4444 int fd;
    4445 unsigned long pid = req->ctx.pid;
    4446 char *s;
    4447
    4448 sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
    4449
    4450retry:
    4451 buf = malloc(bufsize);
    4452 if (buf == NULL)
    4453 return -ENOMEM;
    4454
    4455 ret = -EIO;
    4456 fd = open(path, O_RDONLY);
    4457 if (fd == -1)
    4458 goto out_free;
    4459
    4460 ret = read(fd, buf, bufsize);
    4461 close(fd);
    4462 if (ret < 0) {
    4463 ret = -EIO;
    4464 goto out_free;
    4465 }
    4466
    4467 if ((size_t)ret == bufsize) {
    4468 free(buf);
    4469 bufsize *= 4;
    4470 goto retry;
    4471 }
    4472
    4473 buf[ret] = '\0';
    4474 ret = -EIO;
    4475 s = strstr(buf, "\nGroups:");
    4476 if (s == NULL)
    4477 goto out_free;
    4478
    4479 s += 8;
    4480 ret = 0;
    4481 while (1) {
    4482 char *end;
    4483 unsigned long val = strtoul(s, &end, 0);
    4484 if (end == s)
    4485 break;
    4486
    4487 s = end;
    4488 if (ret < size)
    4489 list[ret] = val;
    4490 ret++;
    4491 }
    4492
    4493out_free:
    4494 free(buf);
    4495 return ret;
    4496}
    4497#else /* linux */
    4498/*
    4499 * This is currently not implemented on other than Linux...
    4500 */
    4501int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
    4502{
    4503 (void) req; (void) size; (void) list;
    4504 return -ENOSYS;
    4505}
    4506#endif
    4507
    4508/* Prevent spurious data race warning - we don't care
    4509 * about races for this flag */
    4510__attribute__((no_sanitize_thread))
    4511void fuse_session_exit(struct fuse_session *se)
    4512{
    4513 atomic_store_explicit(&se->mt_exited, 1, memory_order_relaxed);
    4514 sem_post(&se->mt_finish);
    4515}
    4516
    4517__attribute__((no_sanitize_thread))
    4518void fuse_session_reset(struct fuse_session *se)
    4519{
    4520 se->mt_exited = false;
    4521 se->error = 0;
    4522}
    4523
    4524__attribute__((no_sanitize_thread))
    4525int fuse_session_exited(struct fuse_session *se)
    4526{
    4527 bool exited =
    4528 atomic_load_explicit(&se->mt_exited, memory_order_relaxed);
    4529
    4530 return exited ? 1 : 0;
    4531}
    #define FUSE_CAP_IOCTL_DIR
    #define FUSE_CAP_DONT_MASK
    void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_HANDLE_KILLPRIV
    #define FUSE_CAP_AUTO_INVAL_DATA
    #define FUSE_CAP_HANDLE_KILLPRIV_V2
    #define FUSE_CAP_SPLICE_READ
    #define FUSE_CAP_PARALLEL_DIROPS
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    #define FUSE_CAP_WRITEBACK_CACHE
    #define FUSE_CAP_EXPIRE_ONLY
    #define FUSE_CAP_ATOMIC_O_TRUNC
    #define FUSE_CAP_ASYNC_READ
    #define FUSE_CAP_SPLICE_WRITE
    #define FUSE_CAP_CACHE_SYMLINKS
    #define FUSE_CAP_POSIX_ACL
    @ FUSE_BUF_IS_FD
    #define FUSE_CAP_EXPORT_SUPPORT
    #define FUSE_CAP_POSIX_LOCKS
    #define FUSE_CAP_EXPLICIT_INVAL_DATA
    #define FUSE_CAP_READDIRPLUS_AUTO
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    #define FUSE_CAP_NO_OPENDIR_SUPPORT
    #define FUSE_CAP_ASYNC_DIO
    #define FUSE_CAP_OVER_IO_URING
    bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_PASSTHROUGH
    #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP
    #define FUSE_CAP_NO_OPEN_SUPPORT
    #define FUSE_CAP_READDIRPLUS
    void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    fuse_buf_copy_flags
    @ FUSE_BUF_SPLICE_NONBLOCK
    @ FUSE_BUF_FORCE_SPLICE
    @ FUSE_BUF_NO_SPLICE
    @ FUSE_BUF_SPLICE_MOVE
    #define FUSE_CAP_SETXATTR_EXT
    #define FUSE_CAP_SPLICE_MOVE
    #define FUSE_CAP_NO_EXPORT_SUPPORT
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_destroy(struct fuse_session *se)
    fuse_notify_entry_flags
    int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    void fuse_session_exit(struct fuse_session *se)
    void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
    int fuse_reply_poll(fuse_req_t req, unsigned revents)
    int fuse_reply_err(fuse_req_t req, int err)
    bool fuse_req_is_uring(fuse_req_t req)
    const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
    void * fuse_req_userdata(fuse_req_t req)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
    int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
    int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
    void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
    int fuse_session_exited(struct fuse_session *se)
    int fuse_session_fd(struct fuse_session *se)
    int fuse_req_interrupted(fuse_req_t req)
    int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
    int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
    int fuse_reply_readlink(fuse_req_t req, const char *link)
    int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
    int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_reply_none(fuse_req_t req)
    int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr)
    int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
    void fuse_lowlevel_help(void)
    int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
    int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
    int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
    void fuse_session_reset(struct fuse_session *se)
    int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_lseek(fuse_req_t req, off_t off)
    void fuse_lowlevel_version(void)
    int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_passthrough_open(fuse_req_t req, int fd)
    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_xattr(fuse_req_t req, size_t count)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    enum fuse_buf_flags flags
    size_t mem_size
    void * mem
    size_t size
    struct fuse_buf buf[1]
    uint32_t proto_minor
    uint64_t capable_ext
    uint64_t want_ext
    mode_t umask
    double entry_timeout
    fuse_ino_t ino
    uint64_t generation
    double attr_timeout
    struct stat attr
    uint64_t lock_owner
    uint32_t kill_suidgid
    uint32_t writepage
    Definition fuse_common.h:60
    uint32_t poll_events
    uint32_t cache_readdir
    Definition fuse_common.h:89
    uint32_t nonseekable
    Definition fuse_common.h:78
    int32_t backing_id
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t noflush
    Definition fuse_common.h:93
    uint32_t flush
    Definition fuse_common.h:74
    uint32_t direct_io
    Definition fuse_common.h:63
    uint32_t keep_cache
    Definition fuse_common.h:69
    void(* fsync)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
    void(* bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
    void(* unlink)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
    void(* rename)(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags)
    void(* releasedir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
    void(* symlink)(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
    void(* statfs)(fuse_req_t req, fuse_ino_t ino)
    void(* tmpfile)(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)
    void(* release)(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(* fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
    void(* create)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)
    void(* link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
    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(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
    void(* flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)
    void(* getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
    void(* setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
    void(* open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name)
    void(* forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
    void(* poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)
    void(* ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)
    void(* rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name)
    void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
    void(* fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
    void(* mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
    void(* statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)
    void(* access)(fuse_req_t req, fuse_ino_t ino, int mask)
    void(* mknod)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
    void(* lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)
    void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
    void(* readlink)(fuse_req_t req, fuse_ino_t ino)
    void(* read)(fuse_req_t req, fuse_ino_t ino, 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(* listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size)
    void(* opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    void(* forget_multi)(fuse_req_t req, size_t count, struct fuse_forget_data *forgets)
    fuse-3.18.3/doc/html/fuse__misc_8h_source.html0000644000175000017500000002366115250106404020215 0ustar berndbernd libfuse: lib/fuse_misc.h Source File
    libfuse
    fuse_misc.h
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU LGPLv2.
    6 See the file LGPL2.txt
    7*/
    8
    9#include <pthread.h>
    10
    11/*
    12 Versioned symbols cannot be used in some cases because it
    13 - not supported on MacOSX (in MachO binary format)
    14
    15 Note: "@@" denotes the default symbol, "@" is binary a compat version.
    16
    17*/
    18#ifdef LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS
    19# if HAVE_SYMVER_ATTRIBUTE
    20# define FUSE_SYMVER(sym1, sym2) __attribute__ ((symver (sym2)))
    21# else
    22# define FUSE_SYMVER(sym1, sym2) __asm__("\t.symver " sym1 "," sym2);
    23# endif
    24#else
    25#define FUSE_SYMVER(sym1, sym2)
    26#endif
    27
    28#ifdef HAVE_STRUCT_STAT_ST_ATIM
    29/* Linux */
    30#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec)
    31#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec)
    32#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec)
    33#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val)
    34#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val)
    35#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val)
    36#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC)
    37/* FreeBSD */
    38#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec)
    39#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec)
    40#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec)
    41#define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val)
    42#define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val)
    43#define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val)
    44#else
    45#define ST_ATIM_NSEC(stbuf) 0
    46#define ST_CTIM_NSEC(stbuf) 0
    47#define ST_MTIM_NSEC(stbuf) 0
    48#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0)
    49#define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0)
    50#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0)
    51#endif
    fuse-3.18.3/doc/html/fuse__opt_8c_source.html0000644000175000017500000023542515250106404020062 0ustar berndbernd libfuse: lib/fuse_opt.c Source File
    libfuse
    fuse_opt.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Implementation of option parsing routines (dealing with `struct
    6 fuse_args`).
    7
    8 This program can be distributed under the terms of the GNU LGPLv2.
    9 See the file LGPL2.txt
    10*/
    11
    12#include "fuse_config.h"
    13#include "fuse_i.h"
    14#include "fuse_opt.h"
    15#include "fuse_misc.h"
    16
    17#include <stdio.h>
    18#include <stdlib.h>
    19#include <string.h>
    20#include <assert.h>
    21
    22struct fuse_opt_context {
    23 void *data;
    24 const struct fuse_opt *opt;
    25 fuse_opt_proc_t proc;
    26 int argctr;
    27 int argc;
    28 char **argv;
    29 struct fuse_args outargs;
    30 char *opts;
    31 int nonopt;
    32};
    33
    34void fuse_opt_free_args(struct fuse_args *args)
    35{
    36 if (args) {
    37 if (args->argv && args->allocated) {
    38 int i;
    39 for (i = 0; i < args->argc; i++)
    40 free(args->argv[i]);
    41 free(args->argv);
    42 }
    43 args->argc = 0;
    44 args->argv = NULL;
    45 args->allocated = 0;
    46 }
    47}
    48
    49static int alloc_failed(void)
    50{
    51 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    52 return -1;
    53}
    54
    55int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    56{
    57 char **newargv;
    58 char *newarg;
    59
    60 assert(!args->argv || args->allocated);
    61
    62 newarg = strdup(arg);
    63 if (!newarg)
    64 return alloc_failed();
    65
    66 newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
    67 if (!newargv) {
    68 free(newarg);
    69 return alloc_failed();
    70 }
    71
    72 args->argv = newargv;
    73 args->allocated = 1;
    74 args->argv[args->argc++] = newarg;
    75 args->argv[args->argc] = NULL;
    76 return 0;
    77}
    78
    79static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos,
    80 const char *arg)
    81{
    82 assert(pos <= args->argc);
    83 if (fuse_opt_add_arg(args, arg) == -1)
    84 return -1;
    85
    86 if (pos != args->argc - 1) {
    87 char *newarg = args->argv[args->argc - 1];
    88 memmove(&args->argv[pos + 1], &args->argv[pos],
    89 sizeof(char *) * (args->argc - pos - 1));
    90 args->argv[pos] = newarg;
    91 }
    92 return 0;
    93}
    94
    95int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
    96{
    97 return fuse_opt_insert_arg_common(args, pos, arg);
    98}
    99
    100static int next_arg(struct fuse_opt_context *ctx, const char *opt)
    101{
    102 if (ctx->argctr + 1 >= ctx->argc) {
    103 fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt);
    104 return -1;
    105 }
    106 ctx->argctr++;
    107 return 0;
    108}
    109
    110static int add_arg(struct fuse_opt_context *ctx, const char *arg)
    111{
    112 return fuse_opt_add_arg(&ctx->outargs, arg);
    113}
    114
    115static int add_opt_common(char **opts, const char *opt, int esc)
    116{
    117 unsigned oldlen = *opts ? strlen(*opts) : 0;
    118 char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1);
    119
    120 if (!d)
    121 return alloc_failed();
    122
    123 *opts = d;
    124 if (oldlen) {
    125 d += oldlen;
    126 *d++ = ',';
    127 }
    128
    129 for (; *opt; opt++) {
    130 if (esc && (*opt == ',' || *opt == '\\'))
    131 *d++ = '\\';
    132 *d++ = *opt;
    133 }
    134 *d = '\0';
    135
    136 return 0;
    137}
    138
    139int fuse_opt_add_opt(char **opts, const char *opt)
    140{
    141 return add_opt_common(opts, opt, 0);
    142}
    143
    144int fuse_opt_add_opt_escaped(char **opts, const char *opt)
    145{
    146 return add_opt_common(opts, opt, 1);
    147}
    148
    149static int add_opt(struct fuse_opt_context *ctx, const char *opt)
    150{
    151 return add_opt_common(&ctx->opts, opt, 1);
    152}
    153
    154static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
    155 int iso)
    156{
    157 if (key == FUSE_OPT_KEY_DISCARD)
    158 return 0;
    159
    160 if (key != FUSE_OPT_KEY_KEEP && ctx->proc) {
    161 int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
    162 if (res == -1 || !res)
    163 return res;
    164 }
    165 if (iso)
    166 return add_opt(ctx, arg);
    167 else
    168 return add_arg(ctx, arg);
    169}
    170
    171static int match_template(const char *t, const char *arg, unsigned *sepp)
    172{
    173 int arglen = strlen(arg);
    174 const char *sep = strchr(t, '=');
    175 sep = sep ? sep : strchr(t, ' ');
    176 if (sep && (!sep[1] || sep[1] == '%')) {
    177 int tlen = sep - t;
    178 if (sep[0] == '=')
    179 tlen ++;
    180 if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
    181 *sepp = sep - t;
    182 return 1;
    183 }
    184 }
    185 if (strcmp(t, arg) == 0) {
    186 *sepp = 0;
    187 return 1;
    188 }
    189 return 0;
    190}
    191
    192static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
    193 const char *arg, unsigned *sepp)
    194{
    195 for (; opt && opt->templ; opt++)
    196 if (match_template(opt->templ, arg, sepp))
    197 return opt;
    198 return NULL;
    199}
    200
    201int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
    202{
    203 unsigned dummy;
    204 return find_opt(opts, opt, &dummy) ? 1 : 0;
    205}
    206
    207static int process_opt_param(void *var, const char *format, const char *param,
    208 const char *arg)
    209{
    210 assert(format[0] == '%');
    211 if (format[1] == 's') {
    212 char **s = var;
    213 char *copy = strdup(param);
    214 if (!copy)
    215 return alloc_failed();
    216
    217 free(*s);
    218 *s = copy;
    219 } else {
    220 if (sscanf(param, format, var) != 1) {
    221 fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", arg);
    222 return -1;
    223 }
    224 }
    225 return 0;
    226}
    227
    228static int process_opt(struct fuse_opt_context *ctx,
    229 const struct fuse_opt *opt, unsigned sep,
    230 const char *arg, int iso)
    231{
    232 if (opt->offset == -1U) {
    233 if (call_proc(ctx, arg, opt->value, iso) == -1)
    234 return -1;
    235 } else {
    236 void *var = (char *)ctx->data + opt->offset;
    237 if (sep && opt->templ[sep + 1]) {
    238 const char *param = arg + sep;
    239 if (opt->templ[sep] == '=')
    240 param ++;
    241 if (process_opt_param(var, opt->templ + sep + 1,
    242 param, arg) == -1)
    243 return -1;
    244 } else
    245 *(int *)var = opt->value;
    246 }
    247 return 0;
    248}
    249
    250static int process_opt_sep_arg(struct fuse_opt_context *ctx,
    251 const struct fuse_opt *opt, unsigned sep,
    252 const char *arg, int iso)
    253{
    254 int res;
    255 char *newarg;
    256 char *param;
    257
    258 if (next_arg(ctx, arg) == -1)
    259 return -1;
    260
    261 param = ctx->argv[ctx->argctr];
    262 newarg = malloc(sep + strlen(param) + 1);
    263 if (!newarg)
    264 return alloc_failed();
    265
    266 memcpy(newarg, arg, sep);
    267 strcpy(newarg + sep, param);
    268 res = process_opt(ctx, opt, sep, newarg, iso);
    269 free(newarg);
    270
    271 return res;
    272}
    273
    274static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
    275{
    276 unsigned sep;
    277 const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
    278 if (opt) {
    279 for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
    280 int res;
    281 if (sep && opt->templ[sep] == ' ' && !arg[sep])
    282 res = process_opt_sep_arg(ctx, opt, sep, arg,
    283 iso);
    284 else
    285 res = process_opt(ctx, opt, sep, arg, iso);
    286 if (res == -1)
    287 return -1;
    288 }
    289 return 0;
    290 } else
    291 return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
    292}
    293
    294static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
    295{
    296 char *s = opts;
    297 char *d = s;
    298 int end = 0;
    299
    300 while (!end) {
    301 if (*s == '\0')
    302 end = 1;
    303 if (*s == ',' || end) {
    304 int res;
    305
    306 *d = '\0';
    307 res = process_gopt(ctx, opts, 1);
    308 if (res == -1)
    309 return -1;
    310 d = opts;
    311 } else {
    312 if (s[0] == '\\' && s[1] != '\0') {
    313 s++;
    314 if (s[0] >= '0' && s[0] <= '3' &&
    315 s[1] >= '0' && s[1] <= '7' &&
    316 s[2] >= '0' && s[2] <= '7') {
    317 *d++ = (s[0] - '0') * 0100 +
    318 (s[1] - '0') * 0010 +
    319 (s[2] - '0');
    320 s += 2;
    321 } else {
    322 *d++ = *s;
    323 }
    324 } else {
    325 *d++ = *s;
    326 }
    327 }
    328 s++;
    329 }
    330
    331 return 0;
    332}
    333
    334static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
    335{
    336 int res;
    337 char *copy = strdup(opts);
    338
    339 if (!copy) {
    340 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    341 return -1;
    342 }
    343 res = process_real_option_group(ctx, copy);
    344 free(copy);
    345 return res;
    346}
    347
    348static int process_one(struct fuse_opt_context *ctx, const char *arg)
    349{
    350 if (ctx->nonopt || arg[0] != '-')
    351 return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
    352 else if (arg[1] == 'o') {
    353 if (arg[2])
    354 return process_option_group(ctx, arg + 2);
    355 else {
    356 if (next_arg(ctx, arg) == -1)
    357 return -1;
    358
    359 return process_option_group(ctx,
    360 ctx->argv[ctx->argctr]);
    361 }
    362 } else if (arg[1] == '-' && !arg[2]) {
    363 if (add_arg(ctx, arg) == -1)
    364 return -1;
    365 ctx->nonopt = ctx->outargs.argc;
    366 return 0;
    367 } else
    368 return process_gopt(ctx, arg, 0);
    369}
    370
    371static int opt_parse(struct fuse_opt_context *ctx)
    372{
    373 if (ctx->argc) {
    374 if (add_arg(ctx, ctx->argv[0]) == -1)
    375 return -1;
    376 }
    377
    378 for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
    379 if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
    380 return -1;
    381
    382 if (ctx->opts) {
    383 if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
    384 fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
    385 return -1;
    386 }
    387
    388 /* If option separator ("--") is the last argument, remove it */
    389 if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc &&
    390 strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) {
    391 free(ctx->outargs.argv[ctx->outargs.argc - 1]);
    392 ctx->outargs.argv[--ctx->outargs.argc] = NULL;
    393 }
    394
    395 return 0;
    396}
    397
    398int fuse_opt_parse(struct fuse_args *args, void *data,
    399 const struct fuse_opt opts[], fuse_opt_proc_t proc)
    400{
    401 int res;
    402 struct fuse_opt_context ctx = {
    403 .data = data,
    404 .opt = opts,
    405 .proc = proc,
    406 };
    407
    408 if (!args || !args->argv || !args->argc)
    409 return 0;
    410
    411 ctx.argc = args->argc;
    412 ctx.argv = args->argv;
    413
    414 res = opt_parse(&ctx);
    415 if (res != -1) {
    416 struct fuse_args tmp = *args;
    417 *args = ctx.outargs;
    418 ctx.outargs = tmp;
    419 }
    420 free(ctx.opts);
    421 fuse_opt_free_args(&ctx.outargs);
    422 return res;
    423}
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int(* fuse_opt_proc_t)(void *data, const char *arg, int key, struct fuse_args *outargs)
    Definition fuse_opt.h:180
    #define FUSE_OPT_KEY_OPT
    Definition fuse_opt.h:129
    int fuse_opt_add_opt_escaped(char **opts, const char *opt)
    Definition fuse_opt.c:144
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_KEY_NONOPT
    Definition fuse_opt.h:137
    #define FUSE_OPT_KEY_DISCARD
    Definition fuse_opt.h:153
    #define FUSE_OPT_KEY_KEEP
    Definition fuse_opt.h:145
    int fuse_opt_add_opt(char **opts, const char *opt)
    Definition fuse_opt.c:139
    int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
    Definition fuse_opt.c:95
    int fuse_opt_match(const struct fuse_opt opts[], const char *opt)
    int allocated
    Definition fuse_opt.h:117
    char ** argv
    Definition fuse_opt.h:114
    const char * templ
    Definition fuse_opt.h:79
    unsigned long offset
    Definition fuse_opt.h:85
    int value
    Definition fuse_opt.h:91
    fuse-3.18.3/doc/html/fuse__signals_8c_source.html0000644000175000017500000010733715250106404020720 0ustar berndbernd libfuse: lib/fuse_signals.c Source File
    libfuse
    fuse_signals.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Utility functions for setting signal handlers.
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt
    9*/
    10
    11#include "fuse_config.h"
    12#include "fuse_lowlevel.h"
    13#include "fuse_i.h"
    14
    15#include <stdio.h>
    16#include <string.h>
    17#include <signal.h>
    18#include <stdlib.h>
    19#include <errno.h>
    20
    21#ifdef HAVE_BACKTRACE
    22#include <execinfo.h>
    23#endif
    24
    25/*
    26 * Must not handle SIGCANCEL, as that is used to wake up threads from
    27 * syscalls reading requests from /dev/fuse
    28 */
    29static int teardown_sigs[] = { SIGHUP, SIGINT, SIGTERM };
    30
    31static int ignore_sigs[] = { SIGPIPE};
    32static int fail_sigs[] = { SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV };
    33static struct fuse_session *fuse_instance;
    34
    35#ifdef HAVE_BACKTRACE
    36#define BT_STACK_SZ (1024 * 1024)
    37static void *backtrace_buffer[BT_STACK_SZ];
    38#endif
    39
    40static void dump_stack(void)
    41{
    42#ifdef HAVE_BACKTRACE
    43 char **strings;
    44
    45 int nptrs = backtrace(backtrace_buffer, BT_STACK_SZ);
    46 strings = backtrace_symbols(backtrace_buffer, nptrs);
    47
    48 if (strings == NULL) {
    49 fuse_log(FUSE_LOG_ERR, "Failed to get backtrace symbols: %s\n",
    50 strerror(errno));
    51 return;
    52 }
    53
    54 for (int idx = 0; idx < nptrs; idx++)
    55 fuse_log(FUSE_LOG_ERR, "%s\n", strings[idx]);
    56
    57 free(strings);
    58#endif
    59}
    60
    61static void exit_handler(int sig)
    62{
    63 if (fuse_instance == NULL) {
    64 fuse_log(FUSE_LOG_ERR, "fuse_instance is NULL\n");
    65 return;
    66 }
    67
    68 if (fuse_instance->debug)
    69 fuse_log(FUSE_LOG_ERR, "exit_handler called with sig %d\n",
    70 sig);
    71
    72 fuse_session_exit(fuse_instance);
    73
    74 if (sig < 0) {
    75 fuse_log(FUSE_LOG_ERR,
    76 "assertion error: signal value <= 0\n");
    77 dump_stack();
    78 abort();
    79 fuse_instance->error = sig;
    80 }
    81
    82 fuse_instance->error = sig;
    83}
    84
    85static void exit_backtrace(int sig)
    86{
    87 if (fuse_instance == NULL)
    88 return;
    89
    90 fuse_session_exit(fuse_instance);
    91
    92 fuse_remove_signal_handlers(fuse_instance);
    93 fuse_log(FUSE_LOG_ERR, "Got signal: %d\n", sig);
    94 dump_stack();
    95 abort();
    96}
    97
    98
    99static void do_nothing(int sig)
    100{
    101 (void) sig;
    102}
    103
    104static int set_one_signal_handler(int sig, void (*handler)(int), int remove)
    105{
    106 struct sigaction sa;
    107 struct sigaction old_sa;
    108
    109 memset(&sa, 0, sizeof(struct sigaction));
    110 sa.sa_handler = remove ? SIG_DFL : handler;
    111 sigemptyset(&(sa.sa_mask));
    112 sa.sa_flags = 0;
    113
    114 if (sigaction(sig, NULL, &old_sa) == -1) {
    115 perror("fuse: cannot get old signal handler");
    116 return -1;
    117 }
    118
    119 if (old_sa.sa_handler == (remove ? handler : SIG_DFL) &&
    120 sigaction(sig, &sa, NULL) == -1) {
    121 perror("fuse: cannot set signal handler");
    122 return -1;
    123 }
    124 return 0;
    125}
    126
    127static int _fuse_set_signal_handlers(int signals[], int nr_signals,
    128 void (*handler)(int))
    129{
    130 for (int idx = 0; idx < nr_signals; idx++) {
    131 int signal = signals[idx];
    132
    133 /*
    134 * If we used SIG_IGN instead of the do_nothing function,
    135 * then we would be unable to tell if we set SIG_IGN (and
    136 * thus should reset to SIG_DFL in fuse_remove_signal_handlers)
    137 * or if it was already set to SIG_IGN (and should be left
    138 * untouched.
    139 */
    140 if (set_one_signal_handler(signal, handler, 0) == -1) {
    141 fuse_log(FUSE_LOG_ERR,
    142 "Failed to install signal handler for sig %d\n",
    143 signal);
    144 return -1;
    145 }
    146 }
    147
    148 return 0;
    149}
    150
    151int fuse_set_signal_handlers(struct fuse_session *se)
    152{
    153 size_t nr_signals;
    154 int rc;
    155
    156 nr_signals = sizeof(teardown_sigs) / sizeof(teardown_sigs[0]);
    157 rc = _fuse_set_signal_handlers(teardown_sigs, nr_signals, exit_handler);
    158 if (rc < 0)
    159 return rc;
    160
    161 nr_signals = sizeof(ignore_sigs) / sizeof(ignore_sigs[0]);
    162 rc = _fuse_set_signal_handlers(ignore_sigs, nr_signals, do_nothing);
    163 if (rc < 0)
    164 return rc;
    165
    166 /*
    167 * needs to be set independently if already set, as some applications
    168 * may have multiple sessions and might rely on traditional behavior
    169 * that the last session is used.
    170 */
    171 fuse_instance = se;
    172
    173 return 0;
    174}
    175
    176int fuse_set_fail_signal_handlers(struct fuse_session *se)
    177{
    178 size_t nr_signals = sizeof(fail_sigs) / sizeof(fail_sigs[0]);
    179
    180 int rc = _fuse_set_signal_handlers(fail_sigs, nr_signals,
    181 exit_backtrace);
    182 if (rc < 0)
    183 return rc;
    184
    185 /* See fuse_set_signal_handlers, why set unconditionally */
    186 fuse_instance = se;
    187
    188 return 0;
    189}
    190
    191static void _fuse_remove_signal_handlers(int signals[], int nr_signals,
    192 void (*handler)(int))
    193{
    194 for (int idx = 0; idx < nr_signals; idx++)
    195 set_one_signal_handler(signals[idx], handler, 1);
    196}
    197
    198void fuse_remove_signal_handlers(struct fuse_session *se)
    199{
    200 size_t nr_signals;
    201
    202 if (fuse_instance != se)
    203 fuse_log(FUSE_LOG_ERR,
    204 "fuse: fuse_remove_signal_handlers: unknown session\n");
    205 else
    206 fuse_instance = NULL;
    207
    208 nr_signals = sizeof(teardown_sigs) / sizeof(teardown_sigs[0]);
    209 _fuse_remove_signal_handlers(teardown_sigs, nr_signals, exit_handler);
    210
    211 nr_signals = sizeof(ignore_sigs) / sizeof(ignore_sigs[0]);
    212 _fuse_remove_signal_handlers(ignore_sigs, nr_signals, do_nothing);
    213
    214 nr_signals = sizeof(fail_sigs) / sizeof(fail_sigs[0]);
    215 _fuse_remove_signal_handlers(fail_sigs, nr_signals, exit_backtrace);
    216}
    int fuse_set_fail_signal_handlers(struct fuse_session *se)
    int fuse_set_signal_handlers(struct fuse_session *se)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_exit(struct fuse_session *se)
    fuse-3.18.3/doc/html/fuse__uring_8c_source.html0000644000175000017500000043517215250106404020405 0ustar berndbernd libfuse: lib/fuse_uring.c Source File
    libfuse
    fuse_uring.c
    1/*
    2 * FUSE: Filesystem in Userspace
    3 * Copyright (C) 2025 Bernd Schubert <bschubert@ddn.com>
    4 *
    5 * Implementation of (most of) FUSE-over-io-uring.
    6 *
    7 * This program can be distributed under the terms of the GNU LGPLv2.
    8 * See the file LGPL2.txt
    9 */
    10
    11#define _GNU_SOURCE
    12
    13#include "fuse_i.h"
    14#include "fuse_kernel.h"
    15#include "fuse_uring_i.h"
    16
    17#include <stdlib.h>
    18#include <liburing.h>
    19#include <sys/sysinfo.h>
    20#include <stdint.h>
    21#include <inttypes.h>
    22#include <stdbool.h>
    23#include <string.h>
    24#include <unistd.h>
    25#include <numa.h>
    26#include <pthread.h>
    27#include <stdio.h>
    28#include <linux/sched.h>
    29#include <poll.h>
    30#include <sys/eventfd.h>
    31
    32/* Size of command data area in SQE when IORING_SETUP_SQE128 is used */
    33#define FUSE_URING_MAX_SQE128_CMD_DATA 80
    34
    35struct fuse_ring_ent {
    36 struct fuse_ring_queue *ring_queue; /* back pointer */
    37 struct fuse_req req;
    38
    39 struct fuse_uring_req_header *req_header;
    40 void *op_payload;
    41 size_t req_payload_sz;
    42
    43 /* commit id of a fuse request */
    44 uint64_t req_commit_id;
    45
    46 enum fuse_uring_cmd last_cmd;
    47
    48 /* header and payload */
    49 struct iovec iov[2];
    50};
    51
    52struct fuse_ring_queue {
    53 /* back pointer */
    54 struct fuse_ring_pool *ring_pool;
    55 int qid;
    56 int numa_node;
    57 pthread_t tid;
    58 int eventfd;
    59 size_t req_header_sz;
    60 struct io_uring ring;
    61
    62 pthread_mutex_t ring_lock;
    63 bool cqe_processing;
    64
    65 /* size depends on queue depth */
    66 struct fuse_ring_ent ent[];
    67};
    68
    73 struct fuse_session *se;
    74
    75 /* number of queues */
    76 size_t nr_queues;
    77
    78 /* number of per queue entries */
    79 size_t queue_depth;
    80
    81 /* max payload size for fuse requests*/
    82 size_t max_req_payload_sz;
    83
    84 /* size of a single queue */
    85 size_t queue_mem_size;
    86
    87 unsigned int started_threads;
    88 unsigned int failed_threads;
    89
    90 /* Avoid sending queue entries before FUSE_INIT reply*/
    91 sem_t init_sem;
    92
    93 pthread_cond_t thread_start_cond;
    94 pthread_mutex_t thread_start_mutex;
    95
    96 /* pointer to the first queue */
    97 struct fuse_ring_queue *queues;
    98};
    99
    100static size_t
    101fuse_ring_queue_size(const size_t q_depth)
    102{
    103 const size_t req_size = sizeof(struct fuse_ring_ent) * q_depth;
    104
    105 return sizeof(struct fuse_ring_queue) + req_size;
    106}
    107
    108static struct fuse_ring_queue *
    109fuse_uring_get_queue(struct fuse_ring_pool *fuse_ring, int qid)
    110{
    111 void *ptr =
    112 ((char *)fuse_ring->queues) + (qid * fuse_ring->queue_mem_size);
    113
    114 return ptr;
    115}
    116
    120static void *fuse_uring_get_sqe_cmd(struct io_uring_sqe *sqe)
    121{
    122 return (void *)&sqe->cmd[0];
    123}
    124
    125static void fuse_uring_sqe_set_req_data(struct fuse_uring_cmd_req *req,
    126 const unsigned int qid,
    127 const uint64_t commit_id)
    128{
    129 req->qid = qid;
    130 req->commit_id = commit_id;
    131 req->flags = 0;
    132}
    133
    134static void
    135fuse_uring_sqe_prepare(struct io_uring_sqe *sqe, struct fuse_ring_ent *req,
    136 __u32 cmd_op)
    137{
    138 /* These fields should be written once, never change */
    139 sqe->opcode = IORING_OP_URING_CMD;
    140
    141 /*
    142 * IOSQE_FIXED_FILE: fd is the index to the fd *array*
    143 * given to io_uring_register_files()
    144 */
    145 sqe->flags = IOSQE_FIXED_FILE;
    146 sqe->fd = 0;
    147
    148 sqe->rw_flags = 0;
    149 sqe->ioprio = 0;
    150 sqe->off = 0;
    151
    152 io_uring_sqe_set_data(sqe, req);
    153
    154 sqe->cmd_op = cmd_op;
    155 sqe->__pad1 = 0;
    156}
    157
    158static int fuse_uring_commit_sqe(struct fuse_ring_pool *ring_pool,
    159 struct fuse_ring_queue *queue,
    160 struct fuse_ring_ent *ring_ent)
    161{
    162 bool locked = false;
    163 struct fuse_session *se = ring_pool->se;
    164 struct fuse_uring_req_header *rrh = ring_ent->req_header;
    165 struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
    166 struct fuse_uring_ent_in_out *ent_in_out =
    167 (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
    168 struct io_uring_sqe *sqe;
    169
    170 if (pthread_self() != queue->tid) {
    171 pthread_mutex_lock(&queue->ring_lock);
    172 locked = true;
    173 }
    174
    175 sqe = io_uring_get_sqe(&queue->ring);
    176
    177 if (sqe == NULL) {
    178 /* This is an impossible condition, unless there is a bug.
    179 * The kernel sent back an SQEs, which is assigned to a request.
    180 * There is no way to get out of SQEs, as the number of
    181 * SQEs matches the number tof requests.
    182 */
    183
    184 se->error = -EIO;
    185 fuse_log(FUSE_LOG_ERR, "Failed to get a ring SQEs\n");
    186
    187 return -EIO;
    188 }
    189
    190 ring_ent->last_cmd = FUSE_IO_URING_CMD_COMMIT_AND_FETCH;
    191 fuse_uring_sqe_prepare(sqe, ring_ent, ring_ent->last_cmd);
    192 fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid,
    193 ring_ent->req_commit_id);
    194
    195 if (se->debug) {
    196 fuse_log(FUSE_LOG_DEBUG, " unique: %" PRIu64 ", result=%d\n",
    197 out->unique, ent_in_out->payload_sz);
    198 }
    199
    200 if (!queue->cqe_processing)
    201 io_uring_submit(&queue->ring);
    202
    203 if (locked)
    204 pthread_mutex_unlock(&queue->ring_lock);
    205
    206 return 0;
    207}
    208
    209int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz,
    210 void **mr)
    211{
    212 struct fuse_ring_ent *ring_ent;
    213
    214 /* Not possible without io-uring interface */
    215 if (!req->flags.is_uring)
    216 return -EINVAL;
    217
    218 ring_ent = container_of(req, struct fuse_ring_ent, req);
    219
    220 *payload = ring_ent->op_payload;
    221 *payload_sz = ring_ent->req_payload_sz;
    222
    223 /*
    224 * For now unused, but will be used later when the application can
    225 * allocate the buffers itself and register them for rdma.
    226 */
    227 if (mr)
    228 *mr = NULL;
    229
    230 return 0;
    231}
    232
    233int send_reply_uring(fuse_req_t req, int error, const void *arg, size_t argsize)
    234{
    235 int res;
    236 struct fuse_ring_ent *ring_ent =
    237 container_of(req, struct fuse_ring_ent, req);
    238 struct fuse_uring_req_header *rrh = ring_ent->req_header;
    239 struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
    240 struct fuse_uring_ent_in_out *ent_in_out =
    241 (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
    242
    243 struct fuse_ring_queue *queue = ring_ent->ring_queue;
    244 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    245 size_t max_payload_sz = ring_pool->max_req_payload_sz;
    246
    247 if (argsize > max_payload_sz) {
    248 fuse_log(FUSE_LOG_ERR, "argsize %zu exceeds buffer size %zu",
    249 argsize, max_payload_sz);
    250 error = -EINVAL;
    251 } else if (argsize) {
    252 if (arg != ring_ent->op_payload)
    253 memcpy(ring_ent->op_payload, arg, argsize);
    254 }
    255 ent_in_out->payload_sz = argsize;
    256
    257 out->error = error;
    258 out->unique = req->unique;
    259
    260 res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
    261
    262 fuse_free_req(req);
    263
    264 return res;
    265}
    266
    267int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv,
    268 enum fuse_buf_copy_flags flags)
    269{
    270 struct fuse_ring_ent *ring_ent =
    271 container_of(req, struct fuse_ring_ent, req);
    272
    273 struct fuse_ring_queue *queue = ring_ent->ring_queue;
    274 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    275 struct fuse_uring_req_header *rrh = ring_ent->req_header;
    276 struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
    277 struct fuse_uring_ent_in_out *ent_in_out =
    278 (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
    279 size_t max_payload_sz = ring_ent->req_payload_sz;
    280 struct fuse_bufvec dest_vec = FUSE_BUFVEC_INIT(max_payload_sz);
    281 int res;
    282
    283 dest_vec.buf[0].mem = ring_ent->op_payload;
    284 dest_vec.buf[0].size = max_payload_sz;
    285
    286 res = fuse_buf_copy(&dest_vec, bufv, flags);
    287
    288 out->error = res < 0 ? res : 0;
    289 out->unique = req->unique;
    290
    291 ent_in_out->payload_sz = res > 0 ? res : 0;
    292
    293 res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
    294
    295 fuse_free_req(req);
    296
    297 return res;
    298}
    299
    303int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count)
    304{
    305 struct fuse_ring_ent *ring_ent =
    306 container_of(req, struct fuse_ring_ent, req);
    307
    308 struct fuse_ring_queue *queue = ring_ent->ring_queue;
    309 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    310 struct fuse_uring_req_header *rrh = ring_ent->req_header;
    311 struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out;
    312 struct fuse_uring_ent_in_out *ent_in_out =
    313 (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out;
    314 size_t max_buf = ring_pool->max_req_payload_sz;
    315 size_t len = 0;
    316 int res = 0;
    317
    318 /* copy iov into the payload, idx=0 is the header section */
    319 for (int idx = 1; idx < count; idx++) {
    320 struct iovec *cur = &iov[idx];
    321
    322 if (len + cur->iov_len > max_buf) {
    323 fuse_log(FUSE_LOG_ERR,
    324 "iov[%d] exceeds buffer size %zu",
    325 idx, max_buf);
    326 res = -EINVAL; /* Gracefully handle this? */
    327 break;
    328 }
    329
    330 memcpy(ring_ent->op_payload + len, cur->iov_base, cur->iov_len);
    331 len += cur->iov_len;
    332 }
    333
    334 ent_in_out->payload_sz = len;
    335
    336 out->error = res;
    337 out->unique = req->unique;
    338 out->len = len;
    339
    340 return fuse_uring_commit_sqe(ring_pool, queue, ring_ent);
    341}
    342
    343static int fuse_queue_setup_io_uring(struct io_uring *ring, size_t qid,
    344 size_t depth, int fd, int evfd)
    345{
    346 int rc;
    347 struct io_uring_params params = {0};
    348 int files[2] = { fd, evfd };
    349
    350 depth += 1; /* for the eventfd poll SQE */
    351
    352 params.flags = IORING_SETUP_SQE128;
    353
    354 /* Replies are batched and flushed in one io_uring_enter; don't let a
    355 * single failing commit SQE stall submission of the rest of the batch.
    356 */
    357 params.flags |= IORING_SETUP_SUBMIT_ALL;
    358
    359 /* Avoid cq overflow */
    360 params.flags |= IORING_SETUP_CQSIZE;
    361 params.cq_entries = depth * 2;
    362
    363 /* These flags should help to increase performance, but actually
    364 * make it a bit slower - reason should get investigated.
    365 */
    366 if (0) {
    367 /* Has the main slow down effect */
    368 params.flags |= IORING_SETUP_SINGLE_ISSUER;
    369
    370 // params.flags |= IORING_SETUP_DEFER_TASKRUN;
    371 params.flags |= IORING_SETUP_TASKRUN_FLAG;
    372
    373 /* Second main effect to make it slower */
    374 params.flags |= IORING_SETUP_COOP_TASKRUN;
    375 }
    376
    377 rc = io_uring_queue_init_params(depth, ring, &params);
    378 if (rc != 0) {
    379 fuse_log(FUSE_LOG_ERR, "Failed to setup qid %zu: %d (%s)\n",
    380 qid, rc, strerror(-rc));
    381 return rc;
    382 }
    383
    384 rc = io_uring_register_files(ring, files, 1);
    385 if (rc != 0) {
    386 rc = -errno;
    387 fuse_log(FUSE_LOG_ERR,
    388 "Failed to register files for ring idx %zu: %s",
    389 qid, strerror(errno));
    390 return rc;
    391 }
    392
    393 return 0;
    394}
    395
    396static void fuse_session_destruct_uring(struct fuse_ring_pool *fuse_ring)
    397{
    398 for (size_t qid = 0; qid < fuse_ring->nr_queues; qid++) {
    399 struct fuse_ring_queue *queue =
    400 fuse_uring_get_queue(fuse_ring, qid);
    401
    402 if (queue->tid != 0) {
    403 uint64_t value = 1ULL;
    404 int rc;
    405
    406 rc = write(queue->eventfd, &value, sizeof(value));
    407 if (rc != sizeof(value))
    408 fprintf(stderr,
    409 "Wrote to eventfd=%d err=%s: rc=%d\n",
    410 queue->eventfd, strerror(errno), rc);
    411 pthread_cancel(queue->tid);
    412 pthread_join(queue->tid, NULL);
    413 queue->tid = 0;
    414 }
    415
    416 if (queue->eventfd >= 0) {
    417 close(queue->eventfd);
    418 queue->eventfd = -1;
    419 }
    420
    421 if (queue->ring.ring_fd != -1)
    422 io_uring_queue_exit(&queue->ring);
    423
    424 for (size_t idx = 0; idx < fuse_ring->queue_depth; idx++) {
    425 struct fuse_ring_ent *ent = &queue->ent[idx];
    426
    427 numa_free(ent->op_payload, ent->req_payload_sz);
    428 numa_free(ent->req_header, queue->req_header_sz);
    429 }
    430
    431 pthread_mutex_destroy(&queue->ring_lock);
    432 }
    433
    434 free(fuse_ring->queues);
    435 pthread_cond_destroy(&fuse_ring->thread_start_cond);
    436 pthread_mutex_destroy(&fuse_ring->thread_start_mutex);
    437 free(fuse_ring);
    438}
    439
    440static int fuse_uring_register_ent(struct fuse_ring_queue *queue,
    441 struct fuse_ring_ent *ent)
    442{
    443 struct io_uring_sqe *sqe;
    444
    445 sqe = io_uring_get_sqe(&queue->ring);
    446 if (sqe == NULL) {
    447 /*
    448 * All SQEs are idle here - no good reason this
    449 * could fail
    450 */
    451 fuse_log(FUSE_LOG_ERR, "Failed to get all ring SQEs");
    452 return -EIO;
    453 }
    454
    455 ent->last_cmd = FUSE_IO_URING_CMD_REGISTER;
    456 fuse_uring_sqe_prepare(sqe, ent, ent->last_cmd);
    457
    458 /* only needed for fetch */
    459 ent->iov[0].iov_base = ent->req_header;
    460 ent->iov[0].iov_len = queue->req_header_sz;
    461
    462 ent->iov[1].iov_base = ent->op_payload;
    463 ent->iov[1].iov_len = ent->req_payload_sz;
    464
    465 sqe->addr = (uint64_t)(ent->iov);
    466 sqe->len = 2;
    467
    468 /* this is a fetch, kernel does not read commit id */
    469 fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid, 0);
    470
    471 return 0;
    472
    473}
    474
    475static int fuse_uring_register_queue(struct fuse_ring_queue *queue)
    476{
    477 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    478 unsigned int sq_ready;
    479 struct io_uring_sqe *sqe;
    480 int res;
    481
    482 for (size_t idx = 0; idx < ring_pool->queue_depth; idx++) {
    483 struct fuse_ring_ent *ent = &queue->ent[idx];
    484
    485 res = fuse_uring_register_ent(queue, ent);
    486 if (res != 0)
    487 return res;
    488 }
    489
    490 sq_ready = io_uring_sq_ready(&queue->ring);
    491 if (sq_ready != ring_pool->queue_depth) {
    492 fuse_log(FUSE_LOG_ERR,
    493 "SQE ready mismatch, expected %zu got %u\n",
    494 ring_pool->queue_depth, sq_ready);
    495 return -EINVAL;
    496 }
    497
    498 /* Poll SQE for the eventfd to wake up on teardown */
    499 sqe = io_uring_get_sqe(&queue->ring);
    500 if (sqe == NULL) {
    501 fuse_log(FUSE_LOG_ERR, "Failed to get eventfd SQE");
    502 return -EIO;
    503 }
    504
    505 io_uring_prep_poll_add(sqe, queue->eventfd, POLLIN);
    506 io_uring_sqe_set_data(sqe, (void *)(uintptr_t)queue->eventfd);
    507
    508 /* Only preparation until here, no submission yet */
    509
    510 return 0;
    511}
    512
    513static struct fuse_ring_pool *fuse_create_ring(struct fuse_session *se)
    514{
    515 struct fuse_ring_pool *fuse_ring = NULL;
    516 const size_t nr_queues = get_nprocs_conf();
    517 size_t payload_sz = se->bufsize - FUSE_BUFFER_HEADER_SIZE;
    518 size_t queue_sz;
    519
    520 if (se->debug)
    521 fuse_log(FUSE_LOG_DEBUG, "starting io-uring q-depth=%d\n",
    522 se->uring.q_depth);
    523
    524 fuse_ring = calloc(1, sizeof(*fuse_ring));
    525 if (fuse_ring == NULL) {
    526 fuse_log(FUSE_LOG_ERR, "Allocating the ring failed\n");
    527 goto err;
    528 }
    529
    530 queue_sz = fuse_ring_queue_size(se->uring.q_depth);
    531 fuse_ring->queues = calloc(1, queue_sz * nr_queues);
    532 if (fuse_ring->queues == NULL) {
    533 fuse_log(FUSE_LOG_ERR, "Allocating the queues failed\n");
    534 goto err;
    535 }
    536
    537 fuse_ring->se = se;
    538 fuse_ring->nr_queues = nr_queues;
    539 fuse_ring->queue_depth = se->uring.q_depth;
    540 fuse_ring->max_req_payload_sz = payload_sz;
    541 fuse_ring->queue_mem_size = queue_sz;
    542
    543 /*
    544 * very basic queue initialization, that cannot fail and will
    545 * allow easy cleanup if something (like mmap) fails in the middle
    546 * below
    547 */
    548 for (size_t qid = 0; qid < nr_queues; qid++) {
    549 struct fuse_ring_queue *queue =
    550 fuse_uring_get_queue(fuse_ring, qid);
    551
    552 queue->ring.ring_fd = -1;
    553 queue->numa_node = numa_node_of_cpu(qid);
    554 queue->qid = qid;
    555 queue->ring_pool = fuse_ring;
    556 queue->eventfd = -1;
    557 pthread_mutex_init(&queue->ring_lock, NULL);
    558 }
    559
    560 pthread_cond_init(&fuse_ring->thread_start_cond, NULL);
    561 pthread_mutex_init(&fuse_ring->thread_start_mutex, NULL);
    562 sem_init(&fuse_ring->init_sem, 0, 0);
    563
    564 return fuse_ring;
    565
    566err:
    567 if (fuse_ring)
    568 fuse_session_destruct_uring(fuse_ring);
    569
    570 return NULL;
    571}
    572
    573static void fuse_uring_resubmit(struct fuse_ring_queue *queue,
    574 struct fuse_ring_ent *ent)
    575{
    576 struct io_uring_sqe *sqe;
    577
    578 sqe = io_uring_get_sqe(&queue->ring);
    579 if (sqe == NULL) {
    580 /* This is an impossible condition, unless there is a bug.
    581 * The kernel sent back an SQEs, which is assigned to a request.
    582 * There is no way to get out of SQEs, as the number of
    583 * SQEs matches the number tof requests.
    584 */
    585
    586 queue->ring_pool->se->error = -EIO;
    587 fuse_log(FUSE_LOG_ERR, "Failed to get a ring SQEs\n");
    588
    589 return;
    590 }
    591
    592 fuse_uring_sqe_prepare(sqe, ent, ent->last_cmd);
    593
    594 switch (ent->last_cmd) {
    595 case FUSE_IO_URING_CMD_REGISTER:
    596 sqe->addr = (uint64_t)(ent->iov);
    597 sqe->len = 2;
    598 fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe),
    599 queue->qid, 0);
    600 break;
    601 case FUSE_IO_URING_CMD_COMMIT_AND_FETCH:
    602 fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe),
    603 queue->qid, ent->req_commit_id);
    604 break;
    605 default:
    606 fuse_log(FUSE_LOG_ERR, "Unknown command type: %d\n",
    607 ent->last_cmd);
    608 queue->ring_pool->se->error = -EINVAL;
    609 break;
    610 }
    611
    612 /* caller submits */
    613}
    614
    615static void fuse_uring_handle_cqe(struct fuse_ring_queue *queue,
    616 struct io_uring_cqe *cqe)
    617{
    618 struct fuse_ring_ent *ent = io_uring_cqe_get_data(cqe);
    619
    620 if (!ent) {
    621 fuse_log(FUSE_LOG_ERR,
    622 "cqe=%p io_uring_cqe_get_data returned NULL\n", cqe);
    623 return;
    624 }
    625
    626 struct fuse_req *req = &ent->req;
    627 struct fuse_ring_pool *fuse_ring = queue->ring_pool;
    628 struct fuse_uring_req_header *rrh = ent->req_header;
    629
    630 struct fuse_in_header *in = (struct fuse_in_header *)&rrh->in_out;
    631 struct fuse_uring_ent_in_out *ent_in_out = &rrh->ring_ent_in_out;
    632
    633 ent->req_commit_id = ent_in_out->commit_id;
    634 if (unlikely(ent->req_commit_id == 0)) {
    635 /*
    636 * If this happens kernel will not find the response - it will
    637 * be stuck forever - better to abort immediately.
    638 */
    639 fuse_log(FUSE_LOG_ERR, "Received invalid commit_id=0\n");
    640 abort();
    641 }
    642
    643 memset(&req->flags, 0, sizeof(req->flags));
    644 memset(&req->u, 0, sizeof(req->u));
    645 req->flags.is_uring = 1;
    646 req->ref_cnt++;
    647 req->ch = NULL; /* not needed for uring */
    648 req->interrupted = 0;
    649 list_init_req(req);
    650
    651 fuse_session_process_uring_cqe(fuse_ring->se, req, in, &rrh->op_in,
    652 ent->op_payload, ent_in_out->payload_sz);
    653}
    654
    655static int fuse_uring_queue_handle_cqes(struct fuse_ring_queue *queue)
    656{
    657 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    658 struct fuse_session *se = ring_pool->se;
    659 size_t num_completed = 0;
    660 struct io_uring_cqe *cqe;
    661 unsigned int head;
    662 struct fuse_ring_ent *ent;
    663 int ret = 0;
    664
    665 io_uring_for_each_cqe(&queue->ring, head, cqe) {
    666 int err = 0;
    667
    668 num_completed++;
    669
    670 err = cqe->res;
    671 if (unlikely(err != 0)) {
    672 if (err > 0 && ((uintptr_t)io_uring_cqe_get_data(cqe) ==
    673 (unsigned int)queue->eventfd)) {
    674 /* teardown from eventfd */
    675 return -ENOTCONN;
    676 }
    677
    678
    679 switch (err) {
    680 case -EAGAIN:
    681 fallthrough;
    682 case -EINTR:
    683 ent = io_uring_cqe_get_data(cqe);
    684 fuse_uring_resubmit(queue, ent);
    685 continue;
    686 default:
    687 break;
    688 }
    689
    690 /* -ENOTCONN is ok on umount */
    691 if (err != -ENOTCONN) {
    692 se->error = cqe->res;
    693
    694 /* return first error */
    695 if (ret == 0)
    696 ret = err;
    697 }
    698
    699 } else {
    700 fuse_uring_handle_cqe(queue, cqe);
    701 }
    702 }
    703
    704 if (num_completed)
    705 io_uring_cq_advance(&queue->ring, num_completed);
    706
    707 return ret == 0 ? 0 : num_completed;
    708}
    709
    714static void fuse_uring_set_thread_core(int qid)
    715{
    716 cpu_set_t mask;
    717 int rc;
    718
    719 CPU_ZERO(&mask);
    720 CPU_SET(qid, &mask);
    721 rc = sched_setaffinity(0, sizeof(cpu_set_t), &mask);
    722 if (rc != 0)
    723 fuse_log(FUSE_LOG_ERR, "Failed to bind qid=%d to its core: %s\n",
    724 qid, strerror(errno));
    725
    726 if (0) {
    727 const int policy = SCHED_IDLE;
    728 const struct sched_param param = {
    729 .sched_priority = sched_get_priority_min(policy),
    730 };
    731
    732 /* Set the lowest possible priority, so that the application
    733 * submitting requests is not moved away from the current core.
    734 */
    735 rc = sched_setscheduler(0, policy, &param);
    736 if (rc != 0)
    737 fuse_log(FUSE_LOG_ERR, "Failed to set scheduler: %s\n",
    738 strerror(errno));
    739 }
    740}
    741
    742/*
    743 * @return negative error code or io-uring file descriptor
    744 */
    745static int fuse_uring_init_queue(struct fuse_ring_queue *queue)
    746{
    747 struct fuse_ring_pool *ring = queue->ring_pool;
    748 struct fuse_session *se = ring->se;
    749 int res;
    750 size_t page_sz = sysconf(_SC_PAGESIZE);
    751
    752 queue->eventfd = eventfd(0, EFD_CLOEXEC);
    753 if (queue->eventfd < 0) {
    754 res = -errno;
    755 fuse_log(FUSE_LOG_ERR,
    756 "Failed to create eventfd for qid %d: %s\n",
    757 queue->qid, strerror(errno));
    758 return res;
    759 }
    760
    761 res = fuse_queue_setup_io_uring(&queue->ring, queue->qid,
    762 ring->queue_depth, se->fd,
    763 queue->eventfd);
    764 if (res != 0) {
    765 fuse_log(FUSE_LOG_ERR, "qid=%d io_uring init failed\n",
    766 queue->qid);
    767 return res;
    768 }
    769
    770 queue->req_header_sz = ROUND_UP(sizeof(struct fuse_uring_req_header),
    771 page_sz);
    772
    773 for (size_t idx = 0; idx < ring->queue_depth; idx++) {
    774 struct fuse_ring_ent *ring_ent = &queue->ent[idx];
    775 struct fuse_req *req = &ring_ent->req;
    776
    777 ring_ent->ring_queue = queue;
    778
    779 /*
    780 * Also allocate the header to have it page aligned, which
    781 * is a requirement for page pinning
    782 */
    783 ring_ent->req_header =
    784 numa_alloc_local(queue->req_header_sz);
    785 if (!ring_ent->req_header)
    786 return -ENOMEM;
    787 ring_ent->req_payload_sz = ring->max_req_payload_sz;
    788
    789 ring_ent->op_payload =
    790 numa_alloc_local(ring_ent->req_payload_sz);
    791 if (!ring_ent->op_payload)
    792 return -ENOMEM;
    793
    794 req->se = se;
    795 pthread_mutex_init(&req->lock, NULL);
    796 req->flags.is_uring = 1;
    797 req->ref_cnt = 1; /* extra ref to avoid destruction */
    798 list_init_req(req);
    799 }
    800
    801 res = fuse_uring_register_queue(queue);
    802 if (res != 0) {
    803 fuse_log(
    804 FUSE_LOG_ERR,
    805 "Grave fuse-uring error on preparing SQEs, aborting\n");
    806 se->error = -EIO;
    808 return res;
    809 }
    810
    811 return queue->ring.ring_fd;
    812}
    813
    814static void *fuse_uring_thread(void *arg)
    815{
    816 struct fuse_ring_queue *queue = arg;
    817 struct fuse_ring_pool *ring_pool = queue->ring_pool;
    818 struct fuse_session *se = ring_pool->se;
    819 int err;
    820 char thread_name[16] = { 0 };
    821
    822 snprintf(thread_name, 16, "fuse-ring-%d", queue->qid);
    823 thread_name[15] = '\0';
    824 fuse_set_thread_name(thread_name);
    825
    826 fuse_uring_set_thread_core(queue->qid);
    827
    828 err = fuse_uring_init_queue(queue);
    829 pthread_mutex_lock(&ring_pool->thread_start_mutex);
    830 if (err < 0)
    831 ring_pool->failed_threads++;
    832 ring_pool->started_threads++;
    833 pthread_cond_broadcast(&ring_pool->thread_start_cond);
    834 pthread_mutex_unlock(&ring_pool->thread_start_mutex);
    835
    836 if (err < 0) {
    837 fuse_log(FUSE_LOG_ERR, "qid=%d queue setup failed\n",
    838 queue->qid);
    839 goto err_non_fatal;
    840 }
    841
    842 sem_wait(&ring_pool->init_sem);
    843
    844 /* Not using fuse_session_exited(se), as that cannot be inlined */
    845 while (!atomic_load_explicit(&se->mt_exited, memory_order_relaxed)) {
    846 io_uring_submit_and_wait(&queue->ring, 1);
    847
    848 pthread_mutex_lock(&queue->ring_lock);
    849 queue->cqe_processing = true;
    850 err = fuse_uring_queue_handle_cqes(queue);
    851 queue->cqe_processing = false;
    852 pthread_mutex_unlock(&queue->ring_lock);
    853 if (err < 0)
    854 goto err;
    855 }
    856
    857 return NULL;
    858
    859err:
    861err_non_fatal:
    862 return NULL;
    863}
    864
    865static int fuse_uring_start_ring_threads(struct fuse_ring_pool *ring)
    866{
    867 int rc = 0;
    868
    869 for (size_t qid = 0; qid < ring->nr_queues; qid++) {
    870 struct fuse_ring_queue *queue = fuse_uring_get_queue(ring, qid);
    871
    872 rc = pthread_create(&queue->tid, NULL, fuse_uring_thread, queue);
    873 if (rc != 0)
    874 break;
    875 }
    876
    877 return rc;
    878}
    879
    880static int fuse_uring_sanity_check(struct fuse_session *se)
    881{
    882 if (se->uring.q_depth == 0) {
    883 fuse_log(FUSE_LOG_ERR, "io-uring queue depth must be > 0\n");
    884 return -EINVAL;
    885 }
    886
    887 _Static_assert(sizeof(struct fuse_uring_cmd_req) <=
    888 FUSE_URING_MAX_SQE128_CMD_DATA,
    889 "SQE128_CMD_DATA has 80B cmd data");
    890
    891 return 0;
    892}
    893
    894int fuse_uring_start(struct fuse_session *se)
    895{
    896 int err = 0;
    897 struct fuse_ring_pool *fuse_ring;
    898
    899 fuse_uring_sanity_check(se);
    900
    901 fuse_ring = fuse_create_ring(se);
    902 if (fuse_ring == NULL) {
    903 err = -EADDRNOTAVAIL;
    904 goto err;
    905 }
    906
    907 se->uring.pool = fuse_ring;
    908
    909 /* Hold off threads from send fuse ring entries (SQEs) */
    910 sem_init(&fuse_ring->init_sem, 0, 0);
    911 pthread_cond_init(&fuse_ring->thread_start_cond, NULL);
    912 pthread_mutex_init(&fuse_ring->thread_start_mutex, NULL);
    913
    914 err = fuse_uring_start_ring_threads(fuse_ring);
    915 if (err)
    916 goto err;
    917
    918 /*
    919 * Wait for all threads to start or to fail
    920 */
    921 pthread_mutex_lock(&fuse_ring->thread_start_mutex);
    922 while (fuse_ring->started_threads < fuse_ring->nr_queues)
    923 pthread_cond_wait(&fuse_ring->thread_start_cond,
    924 &fuse_ring->thread_start_mutex);
    925
    926 if (fuse_ring->failed_threads != 0)
    927 err = -EADDRNOTAVAIL;
    928 pthread_mutex_unlock(&fuse_ring->thread_start_mutex);
    929
    930err:
    931 if (err) {
    932 /* Note all threads need to have been started */
    933 if (fuse_ring)
    934 fuse_session_destruct_uring(fuse_ring);
    935 se->uring.pool = NULL;
    936 }
    937 return err;
    938}
    939
    940int fuse_uring_stop(struct fuse_session *se)
    941{
    942 struct fuse_ring_pool *ring = se->uring.pool;
    943
    944 if (ring == NULL)
    945 return 0;
    946
    947 fuse_session_destruct_uring(ring);
    948
    949 return 0;
    950}
    951
    952void fuse_uring_wake_ring_threads(struct fuse_session *se)
    953{
    954 struct fuse_ring_pool *ring = se->uring.pool;
    955
    956 /* Wake up the threads to let them send SQEs */
    957 for (size_t qid = 0; qid < ring->nr_queues; qid++)
    958 sem_post(&ring->init_sem);
    959}
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    fuse_buf_copy_flags
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_exit(struct fuse_session *se)
    struct fuse_req * fuse_req_t
    int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr)
    void * mem
    size_t size
    struct fuse_buf buf[1]
    fuse-3.18.3/doc/html/fuse__uring__i_8h_source.html0000644000175000017500000004116615250106404021055 0ustar berndbernd libfuse: lib/fuse_uring_i.h Source File
    libfuse
    fuse_uring_i.h
    1/*
    2 * FUSE: Filesystem in Userspace
    3 * Copyright (C) 2025 Bernd Schubert <bschubert@ddn.com>
    4 * This program can be distributed under the terms of the GNU LGPLv2.
    5 * See the file LGPL2.txt
    6 */
    7
    8#ifndef FUSE_URING_I_H_
    9#define FUSE_URING_I_H_
    10
    11#include "fuse_config.h"
    12#include "fuse_lowlevel.h"
    13#include "fuse_kernel.h"
    14
    15#ifndef HAVE_URING
    16#include "util.h"
    17#endif
    18
    19#include <errno.h> // IWYU pragma: keep
    20
    21/* io-uring defaults */
    22#define SESSION_DEF_URING_ENABLE (0)
    23#define SESSION_DEF_URING_Q_DEPTH (8)
    24
    25void fuse_session_process_uring_cqe(struct fuse_session *se,
    26 struct fuse_req *req,
    27 struct fuse_in_header *in, void *in_header,
    28 void *in_payload, size_t payload_len);
    29
    30#ifdef HAVE_URING
    31
    32struct fuse_in_header;
    33
    34int fuse_uring_start(struct fuse_session *se);
    35void fuse_uring_wake_ring_threads(struct fuse_session *se);
    36int fuse_uring_stop(struct fuse_session *se);
    37int send_reply_uring(fuse_req_t req, int error, const void *arg,
    38 size_t argsize);
    39
    40int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv,
    41 enum fuse_buf_copy_flags flags);
    42int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count);
    43
    44#else // HAVE_URING
    45
    46static inline int fuse_uring_start(struct fuse_session *se FUSE_VAR_UNUSED)
    47{
    48 return -ENOTSUP;
    49}
    50
    51static inline void
    52fuse_uring_wake_ring_threads(struct fuse_session *se FUSE_VAR_UNUSED)
    53{
    54}
    55
    56static inline int fuse_uring_stop(struct fuse_session *se FUSE_VAR_UNUSED)
    57{
    58 return -ENOTSUP;
    59}
    60
    61static inline int send_reply_uring(fuse_req_t req FUSE_VAR_UNUSED,
    62 int error FUSE_VAR_UNUSED,
    63 const void *arg FUSE_VAR_UNUSED,
    64 size_t argsize FUSE_VAR_UNUSED)
    65{
    66 return -ENOTSUP;
    67}
    68
    69static inline int
    70fuse_reply_data_uring(fuse_req_t req FUSE_VAR_UNUSED,
    71 struct fuse_bufvec *bufv FUSE_VAR_UNUSED,
    72 enum fuse_buf_copy_flags flags FUSE_VAR_UNUSED)
    73{
    74 return -ENOTSUP;
    75}
    76
    77static inline int fuse_send_msg_uring(fuse_req_t req FUSE_VAR_UNUSED,
    78 struct iovec *iov FUSE_VAR_UNUSED,
    79 int count FUSE_VAR_UNUSED)
    80{
    81 return -ENOTSUP;
    82}
    83
    84#endif // HAVE_URING
    85
    86#endif // FUSE_URING_I_H_
    fuse_buf_copy_flags
    struct fuse_req * fuse_req_t
    fuse-3.18.3/doc/html/helper_8c_source.html0000644000175000017500000032037415250106404017354 0ustar berndbernd libfuse: lib/helper.c Source File
    libfuse
    helper.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Helper functions to create (simple) standalone programs. With the
    6 aid of these functions it should be possible to create full FUSE
    7 file system by implementing nothing but the request handlers.
    8
    9 This program can be distributed under the terms of the GNU LGPLv2.
    10 See the file LGPL2.txt.
    11*/
    12
    13#include "fuse_config.h"
    14#include "fuse_i.h"
    15#include "fuse_misc.h"
    16#include "fuse_opt.h"
    17#include "fuse_lowlevel.h"
    18#include "mount_util.h"
    19
    20#include <stdio.h>
    21#include <stdlib.h>
    22#include <stddef.h>
    23#include <unistd.h>
    24#include <string.h>
    25#include <limits.h>
    26#include <errno.h>
    27#include <sys/param.h>
    28
    29#define FUSE_HELPER_OPT(t, p) \
    30 { t, offsetof(struct fuse_cmdline_opts, p), 1 }
    31
    32static const struct fuse_opt fuse_helper_opts[] = {
    33 FUSE_HELPER_OPT("-h", show_help),
    34 FUSE_HELPER_OPT("--help", show_help),
    35 FUSE_HELPER_OPT("-V", show_version),
    36 FUSE_HELPER_OPT("--version", show_version),
    37 FUSE_HELPER_OPT("-d", debug),
    38 FUSE_HELPER_OPT("debug", debug),
    39 FUSE_HELPER_OPT("-d", foreground),
    40 FUSE_HELPER_OPT("debug", foreground),
    43 FUSE_HELPER_OPT("-f", foreground),
    44 FUSE_HELPER_OPT("-s", singlethread),
    45 FUSE_HELPER_OPT("fsname=", nodefault_subtype),
    47#ifndef __FreeBSD__
    48 FUSE_HELPER_OPT("subtype=", nodefault_subtype),
    50#endif
    51 FUSE_HELPER_OPT("clone_fd", clone_fd),
    52 FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads),
    53 FUSE_HELPER_OPT("max_threads=%u", max_threads),
    55};
    56
    57struct fuse_conn_info_opts {
    58 int atomic_o_trunc;
    59 int no_remote_posix_lock;
    60 int no_remote_flock;
    61 int splice_write;
    62 int splice_move;
    63 int splice_read;
    64 int no_splice_write;
    65 int no_splice_move;
    66 int no_splice_read;
    67 int auto_inval_data;
    68 int no_auto_inval_data;
    69 int no_readdirplus;
    70 int no_readdirplus_auto;
    71 int async_dio;
    72 int no_async_dio;
    73 int writeback_cache;
    74 int no_writeback_cache;
    75 int async_read;
    76 int sync_read;
    77 unsigned max_write;
    78 unsigned max_readahead;
    79 unsigned max_background;
    80 unsigned congestion_threshold;
    81 unsigned time_gran;
    82 int set_max_write;
    83 int set_max_readahead;
    84 int set_max_background;
    85 int set_congestion_threshold;
    86 int set_time_gran;
    87};
    88
    89#define CONN_OPTION(t, p, v) \
    90 { t, offsetof(struct fuse_conn_info_opts, p), v }
    91static const struct fuse_opt conn_info_opt_spec[] = {
    92 CONN_OPTION("max_write=%u", max_write, 0),
    93 CONN_OPTION("max_write=", set_max_write, 1),
    94 CONN_OPTION("max_readahead=%u", max_readahead, 0),
    95 CONN_OPTION("max_readahead=", set_max_readahead, 1),
    96 CONN_OPTION("max_background=%u", max_background, 0),
    97 CONN_OPTION("max_background=", set_max_background, 1),
    98 CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0),
    99 CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1),
    100 CONN_OPTION("sync_read", sync_read, 1),
    101 CONN_OPTION("async_read", async_read, 1),
    102 CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1),
    103 CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1),
    104 CONN_OPTION("no_remote_lock", no_remote_flock, 1),
    105 CONN_OPTION("no_remote_flock", no_remote_flock, 1),
    106 CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1),
    107 CONN_OPTION("splice_write", splice_write, 1),
    108 CONN_OPTION("no_splice_write", no_splice_write, 1),
    109 CONN_OPTION("splice_move", splice_move, 1),
    110 CONN_OPTION("no_splice_move", no_splice_move, 1),
    111 CONN_OPTION("splice_read", splice_read, 1),
    112 CONN_OPTION("no_splice_read", no_splice_read, 1),
    113 CONN_OPTION("auto_inval_data", auto_inval_data, 1),
    114 CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1),
    115 CONN_OPTION("readdirplus=no", no_readdirplus, 1),
    116 CONN_OPTION("readdirplus=yes", no_readdirplus, 0),
    117 CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1),
    118 CONN_OPTION("readdirplus=auto", no_readdirplus, 0),
    119 CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0),
    120 CONN_OPTION("async_dio", async_dio, 1),
    121 CONN_OPTION("no_async_dio", no_async_dio, 1),
    122 CONN_OPTION("writeback_cache", writeback_cache, 1),
    123 CONN_OPTION("no_writeback_cache", no_writeback_cache, 1),
    124 CONN_OPTION("time_gran=%u", time_gran, 0),
    125 CONN_OPTION("time_gran=", set_time_gran, 1),
    127};
    128
    129
    131{
    132 printf(" -h --help print help\n"
    133 " -V --version print version\n"
    134 " -d -o debug enable debug output (implies -f)\n"
    135 " -f foreground operation\n"
    136 " -s disable multi-threaded operation\n"
    137 " -o clone_fd use separate fuse device fd for each thread\n"
    138 " (may improve performance)\n"
    139 " -o max_idle_threads the maximum number of idle worker threads\n"
    140 " allowed (default: -1)\n"
    141 " -o max_threads the maximum number of worker threads\n"
    142 " allowed (default: 10)\n");
    143}
    144
    145static int fuse_helper_opt_proc(void *data, const char *arg, int key,
    146 struct fuse_args *outargs)
    147{
    148 (void) outargs;
    149 struct fuse_cmdline_opts *opts = data;
    150
    151 switch (key) {
    153 if (!opts->mountpoint) {
    154 if (fuse_mnt_parse_fuse_fd(arg) != -1) {
    155 return fuse_opt_add_opt(&opts->mountpoint, arg);
    156 }
    157
    158 char mountpoint[PATH_MAX] = "";
    159 if (realpath(arg, mountpoint) == NULL) {
    160 fuse_log(FUSE_LOG_ERR,
    161 "fuse: bad mount point `%s': %s\n",
    162 arg, strerror(errno));
    163 return -1;
    164 }
    165 return fuse_opt_add_opt(&opts->mountpoint, mountpoint);
    166 } else {
    167 fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg);
    168 return -1;
    169 }
    170
    171 default:
    172 /* Pass through unknown options */
    173 return 1;
    174 }
    175}
    176
    177/* Under FreeBSD, there is no subtype option so this
    178 function actually sets the fsname */
    179static int add_default_subtype(const char *progname, struct fuse_args *args)
    180{
    181 int res;
    182 char *subtype_opt;
    183
    184 const char *basename = strrchr(progname, '/');
    185 if (basename == NULL)
    186 basename = progname;
    187 else if (basename[1] != '\0')
    188 basename++;
    189
    190 subtype_opt = (char *) malloc(strlen(basename) + 64);
    191 if (subtype_opt == NULL) {
    192 fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    193 return -1;
    194 }
    195#ifdef __FreeBSD__
    196 sprintf(subtype_opt, "-ofsname=%s", basename);
    197#else
    198 sprintf(subtype_opt, "-osubtype=%s", basename);
    199#endif
    200 res = fuse_opt_add_arg(args, subtype_opt);
    201 free(subtype_opt);
    202 return res;
    203}
    204
    205int fuse_parse_cmdline_312(struct fuse_args *args,
    206 struct fuse_cmdline_opts *opts);
    207FUSE_SYMVER("fuse_parse_cmdline_312", "fuse_parse_cmdline@@FUSE_3.12")
    208int fuse_parse_cmdline_312(struct fuse_args *args,
    209 struct fuse_cmdline_opts *opts)
    210{
    211 memset(opts, 0, sizeof(struct fuse_cmdline_opts));
    212
    213 opts->max_idle_threads = UINT_MAX; /* new default in fuse version 3.12 */
    214 opts->max_threads = 10;
    215
    216 if (fuse_opt_parse(args, opts, fuse_helper_opts,
    217 fuse_helper_opt_proc) == -1)
    218 return -1;
    219
    220 /* *Linux*: if neither -o subtype nor -o fsname are specified,
    221 set subtype to program's basename.
    222 *FreeBSD*: if fsname is not specified, set to program's
    223 basename. */
    224 if (!opts->nodefault_subtype)
    225 if (add_default_subtype(args->argv[0], args) == -1)
    226 return -1;
    227
    228 return 0;
    229}
    230
    234int fuse_parse_cmdline_30(struct fuse_args *args,
    235 struct fuse_cmdline_opts *opts);
    236FUSE_SYMVER("fuse_parse_cmdline_30", "fuse_parse_cmdline@FUSE_3.0")
    238 struct fuse_cmdline_opts *out_opts)
    239{
    240 struct fuse_cmdline_opts opts;
    241
    242 int rc = fuse_parse_cmdline_312(args, &opts);
    243 if (rc == 0) {
    244 /* copy up to the size of the old pre 3.12 struct */
    245 memcpy(out_opts, &opts,
    246 offsetof(struct fuse_cmdline_opts, max_idle_threads) +
    247 sizeof(opts.max_idle_threads));
    248 }
    249
    250 return rc;
    251}
    252
    253int fuse_daemonize(int foreground)
    254{
    255 if (!foreground) {
    256 int nullfd;
    257 int waiter[2];
    258 char completed;
    259
    260 if (pipe(waiter)) {
    261 perror("fuse_daemonize: pipe");
    262 return -1;
    263 }
    264
    265 /*
    266 * demonize current process by forking it and killing the
    267 * parent. This makes current process as a child of 'init'.
    268 */
    269 switch(fork()) {
    270 case -1:
    271 perror("fuse_daemonize: fork");
    272 close(waiter[0]);
    273 close(waiter[1]);
    274 return -1;
    275 case 0:
    276 /* child */
    277 close(waiter[0]);
    278 waiter[0] = -1;
    279 break;
    280 default:
    281 /* parent */
    282 (void) read(waiter[0], &completed, sizeof(completed));
    283 close(waiter[0]);
    284 close(waiter[1]);
    285 _exit(0);
    286 }
    287
    288 if (setsid() == -1) {
    289 perror("fuse_daemonize: setsid");
    290 close(waiter[1]);
    291 return -1;
    292 }
    293
    294 (void) chdir("/");
    295
    296 nullfd = open("/dev/null", O_RDWR, 0);
    297 if (nullfd != -1) {
    298 (void) dup2(nullfd, 0);
    299 (void) dup2(nullfd, 1);
    300 (void) dup2(nullfd, 2);
    301 if (nullfd > 2)
    302 close(nullfd);
    303 }
    304
    305 /* Propagate completion of daemon initialization */
    306 completed = 1;
    307 (void) write(waiter[1], &completed, sizeof(completed));
    308 close(waiter[1]);
    309 waiter[1] = -1;
    310 } else {
    311 (void)chdir("/");
    312 }
    313
    314 return 0;
    315}
    316
    317int fuse_main_real_versioned(int argc, char *argv[],
    318 const struct fuse_operations *op, size_t op_size,
    319 struct libfuse_version *version, void *user_data)
    320{
    321 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    322 struct fuse *fuse;
    323 struct fuse_cmdline_opts opts;
    324 int res;
    325 struct fuse_loop_config *loop_config = NULL;
    326
    327 if (fuse_parse_cmdline(&args, &opts) != 0)
    328 return 1;
    329
    330 if (opts.show_version) {
    331 printf("FUSE library version %s\n", PACKAGE_VERSION);
    333 res = 0;
    334 goto out1;
    335 }
    336
    337 if (opts.show_help) {
    338 if(args.argv[0][0] != '\0')
    339 printf("usage: %s [options] <mountpoint>\n\n",
    340 args.argv[0]);
    341 printf("FUSE options:\n");
    343 fuse_lib_help(&args);
    344 res = 0;
    345 goto out1;
    346 }
    347
    348 if (!opts.show_help &&
    349 !opts.mountpoint) {
    350 fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n");
    351 res = 2;
    352 goto out1;
    353 }
    354
    355 struct fuse *_fuse_new_31(struct fuse_args *args,
    356 const struct fuse_operations *op, size_t op_size,
    357 struct libfuse_version *version,
    358 void *user_data);
    359 fuse = _fuse_new_31(&args, op, op_size, version, user_data);
    360 if (fuse == NULL) {
    361 res = 3;
    362 goto out1;
    363 }
    364
    365 if (fuse_mount(fuse,opts.mountpoint) != 0) {
    366 res = 4;
    367 goto out2;
    368 }
    369
    370 if (fuse_daemonize(opts.foreground) != 0) {
    371 res = 5;
    372 goto out3;
    373 }
    374
    375 struct fuse_session *se = fuse_get_session(fuse);
    376 if (fuse_set_signal_handlers(se) != 0) {
    377 res = 6;
    378 goto out3;
    379 }
    380
    381 if (opts.singlethread)
    382 res = fuse_loop(fuse);
    383 else {
    384 loop_config = fuse_loop_cfg_create();
    385 if (loop_config == NULL) {
    386 res = 7;
    387 goto out3;
    388 }
    389
    390 fuse_loop_cfg_set_clone_fd(loop_config, opts.clone_fd);
    391
    392 fuse_loop_cfg_set_idle_threads(loop_config, opts.max_idle_threads);
    393 fuse_loop_cfg_set_max_threads(loop_config, opts.max_threads);
    394 res = fuse_loop_mt(fuse, loop_config);
    395 }
    396 if (res)
    397 res = 8;
    398
    400out3:
    401 fuse_unmount(fuse);
    402out2:
    403 fuse_destroy(fuse);
    404out1:
    405 fuse_loop_cfg_destroy(loop_config);
    406 free(opts.mountpoint);
    407 fuse_opt_free_args(&args);
    408 return res;
    409}
    410
    411/* Not symboled, as not part of the official API */
    412int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op,
    413 size_t op_size, void *user_data);
    414int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op,
    415 size_t op_size, void *user_data)
    416{
    417 struct libfuse_version version = { 0 };
    418 return fuse_main_real_versioned(argc, argv, op, op_size, &version,
    419 user_data);
    420}
    421
    422void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts,
    423 struct fuse_conn_info *conn)
    424{
    425 if(opts->set_max_write)
    426 conn->max_write = opts->max_write;
    427 if(opts->set_max_background)
    428 conn->max_background = opts->max_background;
    429 if(opts->set_congestion_threshold)
    430 conn->congestion_threshold = opts->congestion_threshold;
    431 if(opts->set_time_gran)
    432 conn->time_gran = opts->time_gran;
    433 if(opts->set_max_readahead)
    434 conn->max_readahead = opts->max_readahead;
    435
    436#define LL_ENABLE(cond, cap) \
    437 do { \
    438 if (cond) \
    439 fuse_set_feature_flag(conn, cap); \
    440 } while (0)
    441
    442#define LL_DISABLE(cond, cap) \
    443 do { \
    444 if (cond) \
    445 fuse_unset_feature_flag(conn, cap); \
    446 } while (0)
    447
    448 LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ);
    449 LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ);
    450
    451 LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE);
    452 LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE);
    453
    454 LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE);
    455 LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE);
    456
    457 LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
    458 LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA);
    459
    460 LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS);
    461 LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO);
    462
    463 LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO);
    464 LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO);
    465
    466 LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
    467 LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE);
    468
    469 LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ);
    470 LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ);
    471
    472 LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS);
    473 LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS);
    474}
    475
    476struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args)
    477{
    478 struct fuse_conn_info_opts *opts;
    479
    480 opts = calloc(1, sizeof(struct fuse_conn_info_opts));
    481 if(opts == NULL) {
    482 fuse_log(FUSE_LOG_ERR, "calloc failed\n");
    483 return NULL;
    484 }
    485 if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) {
    486 free(opts);
    487 return NULL;
    488 }
    489 return opts;
    490}
    491
    492int fuse_open_channel(const char *mountpoint, const char* options)
    493{
    494 struct mount_opts *opts = NULL;
    495 int fd = -1;
    496 const char *argv[] = { "", "-o", options };
    497 int argc = sizeof(argv) / sizeof(argv[0]);
    498 struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv);
    499
    500 opts = parse_mount_opts(&args);
    501 if (opts == NULL)
    502 return -1;
    503
    504 fd = fuse_kern_mount(mountpoint, opts);
    505 destroy_mount_opts(opts);
    506
    507 return fd;
    508}
    int fuse_mount(struct fuse *f, const char *mountpoint)
    Definition fuse.c:5260
    void fuse_destroy(struct fuse *f)
    Definition fuse.c:5209
    int fuse_main_real_versioned(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data)
    Definition helper.c:317
    int fuse_loop(struct fuse *f)
    Definition fuse.c:4644
    void fuse_lib_help(struct fuse_args *args)
    Definition fuse.c:4813
    int fuse_open_channel(const char *mountpoint, const char *options)
    Definition helper.c:492
    struct fuse_session * fuse_get_session(struct fuse *f)
    Definition fuse.c:4588
    void fuse_unmount(struct fuse *f)
    Definition fuse.c:5265
    #define FUSE_CAP_AUTO_INVAL_DATA
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_SPLICE_READ
    #define FUSE_CAP_WRITEBACK_CACHE
    #define FUSE_CAP_ASYNC_READ
    #define FUSE_CAP_SPLICE_WRITE
    void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
    Definition helper.c:422
    #define FUSE_CAP_POSIX_LOCKS
    #define FUSE_CAP_READDIRPLUS_AUTO
    struct fuse_conn_info_opts * fuse_parse_conn_info_opts(struct fuse_args *args)
    Definition helper.c:476
    #define FUSE_CAP_ASYNC_DIO
    #define FUSE_CAP_READDIRPLUS
    void fuse_remove_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_SPLICE_MOVE
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_cmdline_help(void)
    Definition helper.c:130
    int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts)
    Definition helper.c:237
    void fuse_lowlevel_version(void)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_KEY_NONOPT
    Definition fuse_opt.h:137
    #define FUSE_OPT_KEY_KEEP
    Definition fuse_opt.h:145
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    int fuse_opt_add_opt(char **opts, const char *opt)
    Definition fuse_opt.c:139
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t time_gran
    uint32_t congestion_threshold
    uint32_t max_write
    uint32_t max_readahead
    uint32_t max_background
    fuse-3.18.3/doc/html/iconv_8c_source.html0000644000175000017500000035143515250106404017215 0ustar berndbernd libfuse: lib/modules/iconv.c Source File
    libfuse
    iconv.c
    1/*
    2 fuse iconv module: file name charset conversion
    3 Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU LGPLv2.
    6 See the file LGPL2.txt
    7*/
    8
    9#include <fuse_config.h>
    10
    11#include <fuse.h>
    12#include <stdio.h>
    13#include <stdlib.h>
    14#include <stddef.h>
    15#include <string.h>
    16#include <errno.h>
    17#include <iconv.h>
    18#include <pthread.h>
    19#include <locale.h>
    20#include <langinfo.h>
    21
    22struct iconv {
    23 struct fuse_fs *next;
    24 pthread_mutex_t lock;
    25 char *from_code;
    26 char *to_code;
    27 iconv_t tofs;
    28 iconv_t fromfs;
    29};
    30
    31struct iconv_dh {
    32 struct iconv *ic;
    33 void *prev_buf;
    34 fuse_fill_dir_t prev_filler;
    35};
    36
    37static struct iconv *iconv_get(void)
    38{
    40}
    41
    42static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp,
    43 int fromfs)
    44{
    45 size_t pathlen;
    46 size_t newpathlen;
    47 char *newpath;
    48 size_t plen;
    49 char *p;
    50 size_t res;
    51 int err;
    52
    53 if (path == NULL) {
    54 *newpathp = NULL;
    55 return 0;
    56 }
    57
    58 pathlen = strlen(path);
    59 newpathlen = pathlen * 4;
    60 newpath = malloc(newpathlen + 1);
    61 if (!newpath)
    62 return -ENOMEM;
    63
    64 plen = newpathlen;
    65 p = newpath;
    66 pthread_mutex_lock(&ic->lock);
    67 do {
    68 res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path,
    69 &pathlen, &p, &plen);
    70 if (res == (size_t) -1) {
    71 char *tmp;
    72 size_t inc;
    73
    74 err = -EILSEQ;
    75 if (errno != E2BIG)
    76 goto err;
    77
    78 inc = (pathlen + 1) * 4;
    79 newpathlen += inc;
    80 int dp = p - newpath;
    81 tmp = realloc(newpath, newpathlen + 1);
    82 err = -ENOMEM;
    83 if (!tmp)
    84 goto err;
    85
    86 p = tmp + dp;
    87 plen += inc;
    88 newpath = tmp;
    89 }
    90 } while (res == (size_t) -1);
    91 pthread_mutex_unlock(&ic->lock);
    92 *p = '\0';
    93 *newpathp = newpath;
    94 return 0;
    95
    96err:
    97 iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL);
    98 pthread_mutex_unlock(&ic->lock);
    99 free(newpath);
    100 return err;
    101}
    102
    103static int iconv_getattr(const char *path, struct stat *stbuf,
    104 struct fuse_file_info *fi)
    105{
    106 struct iconv *ic = iconv_get();
    107 char *newpath;
    108 int err = iconv_convpath(ic, path, &newpath, 0);
    109 if (!err) {
    110 err = fuse_fs_getattr(ic->next, newpath, stbuf, fi);
    111 free(newpath);
    112 }
    113 return err;
    114}
    115
    116static int iconv_access(const char *path, int mask)
    117{
    118 struct iconv *ic = iconv_get();
    119 char *newpath;
    120 int err = iconv_convpath(ic, path, &newpath, 0);
    121 if (!err) {
    122 err = fuse_fs_access(ic->next, newpath, mask);
    123 free(newpath);
    124 }
    125 return err;
    126}
    127
    128static int iconv_readlink(const char *path, char *buf, size_t size)
    129{
    130 struct iconv *ic = iconv_get();
    131 char *newpath;
    132 int err = iconv_convpath(ic, path, &newpath, 0);
    133 if (!err) {
    134 err = fuse_fs_readlink(ic->next, newpath, buf, size);
    135 if (!err) {
    136 char *newlink;
    137 err = iconv_convpath(ic, buf, &newlink, 1);
    138 if (!err) {
    139 strncpy(buf, newlink, size - 1);
    140 buf[size - 1] = '\0';
    141 free(newlink);
    142 }
    143 }
    144 free(newpath);
    145 }
    146 return err;
    147}
    148
    149static int iconv_opendir(const char *path, struct fuse_file_info *fi)
    150{
    151 struct iconv *ic = iconv_get();
    152 char *newpath;
    153 int err = iconv_convpath(ic, path, &newpath, 0);
    154 if (!err) {
    155 err = fuse_fs_opendir(ic->next, newpath, fi);
    156 free(newpath);
    157 }
    158 return err;
    159}
    160
    161static int iconv_dir_fill(void *buf, const char *name,
    162 const struct stat *stbuf, off_t off,
    163 enum fuse_fill_dir_flags flags)
    164{
    165 struct iconv_dh *dh = buf;
    166 char *newname;
    167 int res = 0;
    168 if (iconv_convpath(dh->ic, name, &newname, 1) == 0) {
    169 res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags);
    170 free(newname);
    171 }
    172 return res;
    173}
    174
    175static int iconv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    176 off_t offset, struct fuse_file_info *fi,
    177 enum fuse_readdir_flags flags)
    178{
    179 struct iconv *ic = iconv_get();
    180 char *newpath;
    181 int err = iconv_convpath(ic, path, &newpath, 0);
    182 if (!err) {
    183 struct iconv_dh dh;
    184 dh.ic = ic;
    185 dh.prev_buf = buf;
    186 dh.prev_filler = filler;
    187 err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill,
    188 offset, fi, flags);
    189 free(newpath);
    190 }
    191 return err;
    192}
    193
    194static int iconv_releasedir(const char *path, struct fuse_file_info *fi)
    195{
    196 struct iconv *ic = iconv_get();
    197 char *newpath;
    198 int err = iconv_convpath(ic, path, &newpath, 0);
    199 if (!err) {
    200 err = fuse_fs_releasedir(ic->next, newpath, fi);
    201 free(newpath);
    202 }
    203 return err;
    204}
    205
    206static int iconv_mknod(const char *path, mode_t mode, dev_t rdev)
    207{
    208 struct iconv *ic = iconv_get();
    209 char *newpath;
    210 int err = iconv_convpath(ic, path, &newpath, 0);
    211 if (!err) {
    212 err = fuse_fs_mknod(ic->next, newpath, mode, rdev);
    213 free(newpath);
    214 }
    215 return err;
    216}
    217
    218static int iconv_mkdir(const char *path, mode_t mode)
    219{
    220 struct iconv *ic = iconv_get();
    221 char *newpath;
    222 int err = iconv_convpath(ic, path, &newpath, 0);
    223 if (!err) {
    224 err = fuse_fs_mkdir(ic->next, newpath, mode);
    225 free(newpath);
    226 }
    227 return err;
    228}
    229
    230static int iconv_unlink(const char *path)
    231{
    232 struct iconv *ic = iconv_get();
    233 char *newpath;
    234 int err = iconv_convpath(ic, path, &newpath, 0);
    235 if (!err) {
    236 err = fuse_fs_unlink(ic->next, newpath);
    237 free(newpath);
    238 }
    239 return err;
    240}
    241
    242static int iconv_rmdir(const char *path)
    243{
    244 struct iconv *ic = iconv_get();
    245 char *newpath;
    246 int err = iconv_convpath(ic, path, &newpath, 0);
    247 if (!err) {
    248 err = fuse_fs_rmdir(ic->next, newpath);
    249 free(newpath);
    250 }
    251 return err;
    252}
    253
    254static int iconv_symlink(const char *from, const char *to)
    255{
    256 struct iconv *ic = iconv_get();
    257 char *newfrom;
    258 char *newto;
    259 int err = iconv_convpath(ic, from, &newfrom, 0);
    260 if (!err) {
    261 err = iconv_convpath(ic, to, &newto, 0);
    262 if (!err) {
    263 err = fuse_fs_symlink(ic->next, newfrom, newto);
    264 free(newto);
    265 }
    266 free(newfrom);
    267 }
    268 return err;
    269}
    270
    271static int iconv_rename(const char *from, const char *to, unsigned int flags)
    272{
    273 struct iconv *ic = iconv_get();
    274 char *newfrom;
    275 char *newto;
    276 int err = iconv_convpath(ic, from, &newfrom, 0);
    277 if (!err) {
    278 err = iconv_convpath(ic, to, &newto, 0);
    279 if (!err) {
    280 err = fuse_fs_rename(ic->next, newfrom, newto, flags);
    281 free(newto);
    282 }
    283 free(newfrom);
    284 }
    285 return err;
    286}
    287
    288static int iconv_link(const char *from, const char *to)
    289{
    290 struct iconv *ic = iconv_get();
    291 char *newfrom;
    292 char *newto;
    293 int err = iconv_convpath(ic, from, &newfrom, 0);
    294 if (!err) {
    295 err = iconv_convpath(ic, to, &newto, 0);
    296 if (!err) {
    297 err = fuse_fs_link(ic->next, newfrom, newto);
    298 free(newto);
    299 }
    300 free(newfrom);
    301 }
    302 return err;
    303}
    304
    305static int iconv_chmod(const char *path, mode_t mode,
    306 struct fuse_file_info *fi)
    307{
    308 struct iconv *ic = iconv_get();
    309 char *newpath;
    310 int err = iconv_convpath(ic, path, &newpath, 0);
    311 if (!err) {
    312 err = fuse_fs_chmod(ic->next, newpath, mode, fi);
    313 free(newpath);
    314 }
    315 return err;
    316}
    317
    318static int iconv_chown(const char *path, uid_t uid, gid_t gid,
    319 struct fuse_file_info *fi)
    320{
    321 struct iconv *ic = iconv_get();
    322 char *newpath;
    323 int err = iconv_convpath(ic, path, &newpath, 0);
    324 if (!err) {
    325 err = fuse_fs_chown(ic->next, newpath, uid, gid, fi);
    326 free(newpath);
    327 }
    328 return err;
    329}
    330
    331static int iconv_truncate(const char *path, off_t size,
    332 struct fuse_file_info *fi)
    333{
    334 struct iconv *ic = iconv_get();
    335 char *newpath;
    336 int err = iconv_convpath(ic, path, &newpath, 0);
    337 if (!err) {
    338 err = fuse_fs_truncate(ic->next, newpath, size, fi);
    339 free(newpath);
    340 }
    341 return err;
    342}
    343
    344static int iconv_utimens(const char *path, const struct timespec ts[2],
    345 struct fuse_file_info *fi)
    346{
    347 struct iconv *ic = iconv_get();
    348 char *newpath;
    349 int err = iconv_convpath(ic, path, &newpath, 0);
    350 if (!err) {
    351 err = fuse_fs_utimens(ic->next, newpath, ts, fi);
    352 free(newpath);
    353 }
    354 return err;
    355}
    356
    357static int iconv_create(const char *path, mode_t mode,
    358 struct fuse_file_info *fi)
    359{
    360 struct iconv *ic = iconv_get();
    361 char *newpath;
    362 int err = iconv_convpath(ic, path, &newpath, 0);
    363 if (!err) {
    364 err = fuse_fs_create(ic->next, newpath, mode, fi);
    365 free(newpath);
    366 }
    367 return err;
    368}
    369
    370static int iconv_open_file(const char *path, struct fuse_file_info *fi)
    371{
    372 struct iconv *ic = iconv_get();
    373 char *newpath;
    374 int err = iconv_convpath(ic, path, &newpath, 0);
    375 if (!err) {
    376 err = fuse_fs_open(ic->next, newpath, fi);
    377 free(newpath);
    378 }
    379 return err;
    380}
    381
    382static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp,
    383 size_t size, off_t offset, struct fuse_file_info *fi)
    384{
    385 struct iconv *ic = iconv_get();
    386 char *newpath;
    387 int err = iconv_convpath(ic, path, &newpath, 0);
    388 if (!err) {
    389 err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi);
    390 free(newpath);
    391 }
    392 return err;
    393}
    394
    395static int iconv_write_buf(const char *path, struct fuse_bufvec *buf,
    396 off_t offset, struct fuse_file_info *fi)
    397{
    398 struct iconv *ic = iconv_get();
    399 char *newpath;
    400 int err = iconv_convpath(ic, path, &newpath, 0);
    401 if (!err) {
    402 err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi);
    403 free(newpath);
    404 }
    405 return err;
    406}
    407
    408static int iconv_statfs(const char *path, struct statvfs *stbuf)
    409{
    410 struct iconv *ic = iconv_get();
    411 char *newpath;
    412 int err = iconv_convpath(ic, path, &newpath, 0);
    413 if (!err) {
    414 err = fuse_fs_statfs(ic->next, newpath, stbuf);
    415 free(newpath);
    416 }
    417 return err;
    418}
    419
    420static int iconv_flush(const char *path, struct fuse_file_info *fi)
    421{
    422 struct iconv *ic = iconv_get();
    423 char *newpath;
    424 int err = iconv_convpath(ic, path, &newpath, 0);
    425 if (!err) {
    426 err = fuse_fs_flush(ic->next, newpath, fi);
    427 free(newpath);
    428 }
    429 return err;
    430}
    431
    432static int iconv_release(const char *path, struct fuse_file_info *fi)
    433{
    434 struct iconv *ic = iconv_get();
    435 char *newpath;
    436 int err = iconv_convpath(ic, path, &newpath, 0);
    437 if (!err) {
    438 err = fuse_fs_release(ic->next, newpath, fi);
    439 free(newpath);
    440 }
    441 return err;
    442}
    443
    444static int iconv_fsync(const char *path, int isdatasync,
    445 struct fuse_file_info *fi)
    446{
    447 struct iconv *ic = iconv_get();
    448 char *newpath;
    449 int err = iconv_convpath(ic, path, &newpath, 0);
    450 if (!err) {
    451 err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi);
    452 free(newpath);
    453 }
    454 return err;
    455}
    456
    457static int iconv_fsyncdir(const char *path, int isdatasync,
    458 struct fuse_file_info *fi)
    459{
    460 struct iconv *ic = iconv_get();
    461 char *newpath;
    462 int err = iconv_convpath(ic, path, &newpath, 0);
    463 if (!err) {
    464 err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi);
    465 free(newpath);
    466 }
    467 return err;
    468}
    469
    470static int iconv_setxattr(const char *path, const char *name,
    471 const char *value, size_t size, int flags)
    472{
    473 struct iconv *ic = iconv_get();
    474 char *newpath;
    475 int err = iconv_convpath(ic, path, &newpath, 0);
    476 if (!err) {
    477 err = fuse_fs_setxattr(ic->next, newpath, name, value, size,
    478 flags);
    479 free(newpath);
    480 }
    481 return err;
    482}
    483
    484static int iconv_getxattr(const char *path, const char *name, char *value,
    485 size_t size)
    486{
    487 struct iconv *ic = iconv_get();
    488 char *newpath;
    489 int err = iconv_convpath(ic, path, &newpath, 0);
    490 if (!err) {
    491 err = fuse_fs_getxattr(ic->next, newpath, name, value, size);
    492 free(newpath);
    493 }
    494 return err;
    495}
    496
    497static int iconv_listxattr(const char *path, char *list, size_t size)
    498{
    499 struct iconv *ic = iconv_get();
    500 char *newpath;
    501 int err = iconv_convpath(ic, path, &newpath, 0);
    502 if (!err) {
    503 err = fuse_fs_listxattr(ic->next, newpath, list, size);
    504 free(newpath);
    505 }
    506 return err;
    507}
    508
    509static int iconv_removexattr(const char *path, const char *name)
    510{
    511 struct iconv *ic = iconv_get();
    512 char *newpath;
    513 int err = iconv_convpath(ic, path, &newpath, 0);
    514 if (!err) {
    515 err = fuse_fs_removexattr(ic->next, newpath, name);
    516 free(newpath);
    517 }
    518 return err;
    519}
    520
    521static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd,
    522 struct flock *lock)
    523{
    524 struct iconv *ic = iconv_get();
    525 char *newpath;
    526 int err = iconv_convpath(ic, path, &newpath, 0);
    527 if (!err) {
    528 err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock);
    529 free(newpath);
    530 }
    531 return err;
    532}
    533
    534static int iconv_flock(const char *path, struct fuse_file_info *fi, int op)
    535{
    536 struct iconv *ic = iconv_get();
    537 char *newpath;
    538 int err = iconv_convpath(ic, path, &newpath, 0);
    539 if (!err) {
    540 err = fuse_fs_flock(ic->next, newpath, fi, op);
    541 free(newpath);
    542 }
    543 return err;
    544}
    545
    546static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx)
    547{
    548 struct iconv *ic = iconv_get();
    549 char *newpath;
    550 int err = iconv_convpath(ic, path, &newpath, 0);
    551 if (!err) {
    552 err = fuse_fs_bmap(ic->next, newpath, blocksize, idx);
    553 free(newpath);
    554 }
    555 return err;
    556}
    557
    558static off_t iconv_lseek(const char *path, off_t off, int whence,
    559 struct fuse_file_info *fi)
    560{
    561 struct iconv *ic = iconv_get();
    562 char *newpath;
    563 int res = iconv_convpath(ic, path, &newpath, 0);
    564 if (!res) {
    565 res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
    566 free(newpath);
    567 }
    568 return res;
    569}
    570
    571#ifdef HAVE_STATX
    572static int iconv_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    573 struct fuse_file_info *fi)
    574{
    575 struct iconv *ic = iconv_get();
    576 char *newpath;
    577 int res = iconv_convpath(ic, path, &newpath, 0);
    578
    579 if (!res) {
    580 res = fuse_fs_statx(ic->next, newpath, flags, mask, stxbuf, fi);
    581 free(newpath);
    582 }
    583 return res;
    584}
    585#endif
    586
    587static void *iconv_init(struct fuse_conn_info *conn,
    588 struct fuse_config *cfg)
    589{
    590 struct iconv *ic = iconv_get();
    591 fuse_fs_init(ic->next, conn, cfg);
    592 /* Don't touch cfg->nullpath_ok, we can work with
    593 either */
    594 return ic;
    595}
    596
    597static void iconv_destroy(void *data)
    598{
    599 struct iconv *ic = data;
    600 fuse_fs_destroy(ic->next);
    601 iconv_close(ic->tofs);
    602 iconv_close(ic->fromfs);
    603 pthread_mutex_destroy(&ic->lock);
    604 free(ic->from_code);
    605 free(ic->to_code);
    606 free(ic);
    607}
    608
    609static const struct fuse_operations iconv_oper = {
    610 .destroy = iconv_destroy,
    611 .init = iconv_init,
    612 .getattr = iconv_getattr,
    613 .access = iconv_access,
    614 .readlink = iconv_readlink,
    615 .opendir = iconv_opendir,
    616 .readdir = iconv_readdir,
    617 .releasedir = iconv_releasedir,
    618 .mknod = iconv_mknod,
    619 .mkdir = iconv_mkdir,
    620 .symlink = iconv_symlink,
    621 .unlink = iconv_unlink,
    622 .rmdir = iconv_rmdir,
    623 .rename = iconv_rename,
    624 .link = iconv_link,
    625 .chmod = iconv_chmod,
    626 .chown = iconv_chown,
    627 .truncate = iconv_truncate,
    628 .utimens = iconv_utimens,
    629 .create = iconv_create,
    630 .open = iconv_open_file,
    631 .read_buf = iconv_read_buf,
    632 .write_buf = iconv_write_buf,
    633 .statfs = iconv_statfs,
    634 .flush = iconv_flush,
    635 .release = iconv_release,
    636 .fsync = iconv_fsync,
    637 .fsyncdir = iconv_fsyncdir,
    638 .setxattr = iconv_setxattr,
    639 .getxattr = iconv_getxattr,
    640 .listxattr = iconv_listxattr,
    641 .removexattr = iconv_removexattr,
    642 .lock = iconv_lock,
    643 .flock = iconv_flock,
    644 .bmap = iconv_bmap,
    645 .lseek = iconv_lseek,
    646#ifdef HAVE_STATX
    647 .statx = iconv_statx,
    648#endif
    649};
    650
    651static const struct fuse_opt iconv_opts[] = {
    652 FUSE_OPT_KEY("-h", 0),
    653 FUSE_OPT_KEY("--help", 0),
    654 { "from_code=%s", offsetof(struct iconv, from_code), 0 },
    655 { "to_code=%s", offsetof(struct iconv, to_code), 1 },
    657};
    658
    659static void iconv_help(void)
    660{
    661 char *charmap;
    662 const char *old = setlocale(LC_CTYPE, "");
    663
    664 charmap = strdup(nl_langinfo(CODESET));
    665 if (old)
    666 setlocale(LC_CTYPE, old);
    667 else
    668 perror("setlocale");
    669
    670 printf(
    671" -o from_code=CHARSET original encoding of file names (default: UTF-8)\n"
    672" -o to_code=CHARSET new encoding of the file names (default: %s)\n",
    673 charmap);
    674 free(charmap);
    675}
    676
    677static int iconv_opt_proc(void *data, const char *arg, int key,
    678 struct fuse_args *outargs)
    679{
    680 (void) data; (void) arg; (void) outargs;
    681
    682 if (!key) {
    683 iconv_help();
    684 return -1;
    685 }
    686
    687 return 1;
    688}
    689
    690static struct fuse_fs *iconv_new(struct fuse_args *args,
    691 struct fuse_fs *next[])
    692{
    693 struct fuse_fs *fs;
    694 struct iconv *ic;
    695 const char *old = NULL;
    696 const char *from;
    697 const char *to;
    698
    699 ic = calloc(1, sizeof(struct iconv));
    700 if (ic == NULL) {
    701 fuse_log(FUSE_LOG_ERR, "fuse-iconv: memory allocation failed\n");
    702 return NULL;
    703 }
    704
    705 if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1)
    706 goto out_free;
    707
    708 if (!next[0] || next[1]) {
    709 fuse_log(FUSE_LOG_ERR, "fuse-iconv: exactly one next filesystem required\n");
    710 goto out_free;
    711 }
    712
    713 from = ic->from_code ? ic->from_code : "UTF-8";
    714 to = ic->to_code ? ic->to_code : "";
    715 /* FIXME: detect charset equivalence? */
    716 if (!to[0])
    717 old = setlocale(LC_CTYPE, "");
    718 ic->tofs = iconv_open(from, to);
    719 if (ic->tofs == (iconv_t) -1) {
    720 fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n",
    721 to, from);
    722 goto out_free;
    723 }
    724 ic->fromfs = iconv_open(to, from);
    725 if (ic->fromfs == (iconv_t) -1) {
    726 fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n",
    727 from, to);
    728 goto out_iconv_close_to;
    729 }
    730 if (old) {
    731 setlocale(LC_CTYPE, old);
    732 old = NULL;
    733 }
    734
    735 ic->next = next[0];
    736 fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic);
    737 if (!fs)
    738 goto out_iconv_close_from;
    739
    740 return fs;
    741
    742out_iconv_close_from:
    743 iconv_close(ic->fromfs);
    744out_iconv_close_to:
    745 iconv_close(ic->tofs);
    746out_free:
    747 free(ic->from_code);
    748 free(ic->to_code);
    749 free(ic);
    750 if (old) {
    751 setlocale(LC_CTYPE, old);
    752 }
    753 return NULL;
    754}
    755
    756FUSE_REGISTER_MODULE(iconv, iconv_new);
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    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:93
    struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
    Definition fuse.c:4923
    fuse_fill_dir_flags
    Definition fuse.h:61
    fuse_readdir_flags
    Definition fuse.h:45
    #define FUSE_REGISTER_MODULE(name_, factory_)
    Definition fuse.h:1415
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    void * private_data
    Definition fuse.h:891
    fuse-3.18.3/doc/html/subdir_8c_source.html0000644000175000017500000033520015250106404017357 0ustar berndbernd libfuse: lib/modules/subdir.c Source File
    libfuse
    subdir.c
    1/*
    2 fuse subdir module: offset paths with a base directory
    3 Copyright (C) 2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 This program can be distributed under the terms of the GNU LGPLv2.
    6 See the file LGPL2.txt
    7*/
    8
    9#include <fuse_config.h>
    10
    11#include <fuse.h>
    12#include <stdio.h>
    13#include <stdlib.h>
    14#include <stddef.h>
    15#include <string.h>
    16#include <errno.h>
    17
    18struct subdir {
    19 char *base;
    20 size_t baselen;
    21 int rellinks;
    22 struct fuse_fs *next;
    23};
    24
    25static struct subdir *subdir_get(void)
    26{
    28}
    29
    30static int subdir_addpath(struct subdir *d, const char *path, char **newpathp)
    31{
    32 char *newpath = NULL;
    33
    34 if (path != NULL) {
    35 unsigned newlen = d->baselen + strlen(path);
    36
    37 newpath = malloc(newlen + 2);
    38 if (!newpath)
    39 return -ENOMEM;
    40
    41 if (path[0] == '/')
    42 path++;
    43 strcpy(newpath, d->base);
    44 strcpy(newpath + d->baselen, path);
    45 if (!newpath[0])
    46 strcpy(newpath, ".");
    47 }
    48 *newpathp = newpath;
    49
    50 return 0;
    51}
    52
    53static int subdir_getattr(const char *path, struct stat *stbuf,
    54 struct fuse_file_info *fi)
    55{
    56 struct subdir *d = subdir_get();
    57 char *newpath;
    58 int err = subdir_addpath(d, path, &newpath);
    59 if (!err) {
    60 err = fuse_fs_getattr(d->next, newpath, stbuf, fi);
    61 free(newpath);
    62 }
    63 return err;
    64}
    65
    66static int subdir_access(const char *path, int mask)
    67{
    68 struct subdir *d = subdir_get();
    69 char *newpath;
    70 int err = subdir_addpath(d, path, &newpath);
    71 if (!err) {
    72 err = fuse_fs_access(d->next, newpath, mask);
    73 free(newpath);
    74 }
    75 return err;
    76}
    77
    78
    79static int count_components(const char *p)
    80{
    81 int ctr;
    82
    83 for (; *p == '/'; p++);
    84 for (ctr = 0; *p; ctr++) {
    85 for (; *p && *p != '/'; p++);
    86 for (; *p == '/'; p++);
    87 }
    88 return ctr;
    89}
    90
    91static void strip_common(const char **sp, const char **tp)
    92{
    93 const char *s = *sp;
    94 const char *t = *tp;
    95 do {
    96 for (; *s == '/'; s++);
    97 for (; *t == '/'; t++);
    98 *tp = t;
    99 *sp = s;
    100 for (; *s == *t && *s && *s != '/'; s++, t++);
    101 } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
    102}
    103
    104static void transform_symlink(struct subdir *d, const char *path,
    105 char *buf, size_t size)
    106{
    107 const char *l = buf;
    108 size_t llen;
    109 char *s;
    110 int dotdots;
    111 int i;
    112
    113 if (l[0] != '/' || d->base[0] != '/')
    114 return;
    115
    116 strip_common(&l, &path);
    117 if (l - buf < (long) d->baselen)
    118 return;
    119
    120 dotdots = count_components(path);
    121 if (!dotdots)
    122 return;
    123 dotdots--;
    124
    125 llen = strlen(l);
    126 if (dotdots * 3 + llen + 2 > size)
    127 return;
    128
    129 s = buf + dotdots * 3;
    130 if (llen)
    131 memmove(s, l, llen + 1);
    132 else if (!dotdots)
    133 strcpy(s, ".");
    134 else
    135 *s = '\0';
    136
    137 for (s = buf, i = 0; i < dotdots; i++, s += 3)
    138 memcpy(s, "../", 3);
    139}
    140
    141
    142static int subdir_readlink(const char *path, char *buf, size_t size)
    143{
    144 struct subdir *d = subdir_get();
    145 char *newpath;
    146 int err = subdir_addpath(d, path, &newpath);
    147 if (!err) {
    148 err = fuse_fs_readlink(d->next, newpath, buf, size);
    149 if (!err && d->rellinks)
    150 transform_symlink(d, newpath, buf, size);
    151 free(newpath);
    152 }
    153 return err;
    154}
    155
    156static int subdir_opendir(const char *path, struct fuse_file_info *fi)
    157{
    158 struct subdir *d = subdir_get();
    159 char *newpath;
    160 int err = subdir_addpath(d, path, &newpath);
    161 if (!err) {
    162 err = fuse_fs_opendir(d->next, newpath, fi);
    163 free(newpath);
    164 }
    165 return err;
    166}
    167
    168static int subdir_readdir(const char *path, void *buf,
    169 fuse_fill_dir_t filler, off_t offset,
    170 struct fuse_file_info *fi,
    171 enum fuse_readdir_flags flags)
    172{
    173 struct subdir *d = subdir_get();
    174 char *newpath;
    175 int err = subdir_addpath(d, path, &newpath);
    176 if (!err) {
    177 err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
    178 fi, flags);
    179 free(newpath);
    180 }
    181 return err;
    182}
    183
    184static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
    185{
    186 struct subdir *d = subdir_get();
    187 char *newpath;
    188 int err = subdir_addpath(d, path, &newpath);
    189 if (!err) {
    190 err = fuse_fs_releasedir(d->next, newpath, fi);
    191 free(newpath);
    192 }
    193 return err;
    194}
    195
    196static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
    197{
    198 struct subdir *d = subdir_get();
    199 char *newpath;
    200 int err = subdir_addpath(d, path, &newpath);
    201 if (!err) {
    202 err = fuse_fs_mknod(d->next, newpath, mode, rdev);
    203 free(newpath);
    204 }
    205 return err;
    206}
    207
    208static int subdir_mkdir(const char *path, mode_t mode)
    209{
    210 struct subdir *d = subdir_get();
    211 char *newpath;
    212 int err = subdir_addpath(d, path, &newpath);
    213 if (!err) {
    214 err = fuse_fs_mkdir(d->next, newpath, mode);
    215 free(newpath);
    216 }
    217 return err;
    218}
    219
    220static int subdir_unlink(const char *path)
    221{
    222 struct subdir *d = subdir_get();
    223 char *newpath;
    224 int err = subdir_addpath(d, path, &newpath);
    225 if (!err) {
    226 err = fuse_fs_unlink(d->next, newpath);
    227 free(newpath);
    228 }
    229 return err;
    230}
    231
    232static int subdir_rmdir(const char *path)
    233{
    234 struct subdir *d = subdir_get();
    235 char *newpath;
    236 int err = subdir_addpath(d, path, &newpath);
    237 if (!err) {
    238 err = fuse_fs_rmdir(d->next, newpath);
    239 free(newpath);
    240 }
    241 return err;
    242}
    243
    244static int subdir_symlink(const char *from, const char *path)
    245{
    246 struct subdir *d = subdir_get();
    247 char *newpath;
    248 int err = subdir_addpath(d, path, &newpath);
    249 if (!err) {
    250 err = fuse_fs_symlink(d->next, from, newpath);
    251 free(newpath);
    252 }
    253 return err;
    254}
    255
    256static int subdir_rename(const char *from, const char *to, unsigned int flags)
    257{
    258 struct subdir *d = subdir_get();
    259 char *newfrom;
    260 char *newto;
    261 int err = subdir_addpath(d, from, &newfrom);
    262 if (!err) {
    263 err = subdir_addpath(d, to, &newto);
    264 if (!err) {
    265 err = fuse_fs_rename(d->next, newfrom, newto, flags);
    266 free(newto);
    267 }
    268 free(newfrom);
    269 }
    270 return err;
    271}
    272
    273static int subdir_link(const char *from, const char *to)
    274{
    275 struct subdir *d = subdir_get();
    276 char *newfrom;
    277 char *newto;
    278 int err = subdir_addpath(d, from, &newfrom);
    279 if (!err) {
    280 err = subdir_addpath(d, to, &newto);
    281 if (!err) {
    282 err = fuse_fs_link(d->next, newfrom, newto);
    283 free(newto);
    284 }
    285 free(newfrom);
    286 }
    287 return err;
    288}
    289
    290static int subdir_chmod(const char *path, mode_t mode,
    291 struct fuse_file_info *fi)
    292{
    293 struct subdir *d = subdir_get();
    294 char *newpath;
    295 int err = subdir_addpath(d, path, &newpath);
    296 if (!err) {
    297 err = fuse_fs_chmod(d->next, newpath, mode, fi);
    298 free(newpath);
    299 }
    300 return err;
    301}
    302
    303static int subdir_chown(const char *path, uid_t uid, gid_t gid,
    304 struct fuse_file_info *fi)
    305{
    306 struct subdir *d = subdir_get();
    307 char *newpath;
    308 int err = subdir_addpath(d, path, &newpath);
    309 if (!err) {
    310 err = fuse_fs_chown(d->next, newpath, uid, gid, fi);
    311 free(newpath);
    312 }
    313 return err;
    314}
    315
    316static int subdir_truncate(const char *path, off_t size,
    317 struct fuse_file_info *fi)
    318{
    319 struct subdir *d = subdir_get();
    320 char *newpath;
    321 int err = subdir_addpath(d, path, &newpath);
    322 if (!err) {
    323 err = fuse_fs_truncate(d->next, newpath, size, fi);
    324 free(newpath);
    325 }
    326 return err;
    327}
    328
    329static int subdir_utimens(const char *path, const struct timespec ts[2],
    330 struct fuse_file_info *fi)
    331{
    332 struct subdir *d = subdir_get();
    333 char *newpath;
    334 int err = subdir_addpath(d, path, &newpath);
    335 if (!err) {
    336 err = fuse_fs_utimens(d->next, newpath, ts, fi);
    337 free(newpath);
    338 }
    339 return err;
    340}
    341
    342static int subdir_create(const char *path, mode_t mode,
    343 struct fuse_file_info *fi)
    344{
    345 struct subdir *d = subdir_get();
    346 char *newpath;
    347 int err = subdir_addpath(d, path, &newpath);
    348 if (!err) {
    349 err = fuse_fs_create(d->next, newpath, mode, fi);
    350 free(newpath);
    351 }
    352 return err;
    353}
    354
    355static int subdir_open(const char *path, struct fuse_file_info *fi)
    356{
    357 struct subdir *d = subdir_get();
    358 char *newpath;
    359 int err = subdir_addpath(d, path, &newpath);
    360 if (!err) {
    361 err = fuse_fs_open(d->next, newpath, fi);
    362 free(newpath);
    363 }
    364 return err;
    365}
    366
    367static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
    368 size_t size, off_t offset, struct fuse_file_info *fi)
    369{
    370 struct subdir *d = subdir_get();
    371 char *newpath;
    372 int err = subdir_addpath(d, path, &newpath);
    373 if (!err) {
    374 err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
    375 free(newpath);
    376 }
    377 return err;
    378}
    379
    380static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
    381 off_t offset, struct fuse_file_info *fi)
    382{
    383 struct subdir *d = subdir_get();
    384 char *newpath;
    385 int err = subdir_addpath(d, path, &newpath);
    386 if (!err) {
    387 err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
    388 free(newpath);
    389 }
    390 return err;
    391}
    392
    393static int subdir_statfs(const char *path, struct statvfs *stbuf)
    394{
    395 struct subdir *d = subdir_get();
    396 char *newpath;
    397 int err = subdir_addpath(d, path, &newpath);
    398 if (!err) {
    399 err = fuse_fs_statfs(d->next, newpath, stbuf);
    400 free(newpath);
    401 }
    402 return err;
    403}
    404
    405static int subdir_flush(const char *path, struct fuse_file_info *fi)
    406{
    407 struct subdir *d = subdir_get();
    408 char *newpath;
    409 int err = subdir_addpath(d, path, &newpath);
    410 if (!err) {
    411 err = fuse_fs_flush(d->next, newpath, fi);
    412 free(newpath);
    413 }
    414 return err;
    415}
    416
    417static int subdir_release(const char *path, struct fuse_file_info *fi)
    418{
    419 struct subdir *d = subdir_get();
    420 char *newpath;
    421 int err = subdir_addpath(d, path, &newpath);
    422 if (!err) {
    423 err = fuse_fs_release(d->next, newpath, fi);
    424 free(newpath);
    425 }
    426 return err;
    427}
    428
    429static int subdir_fsync(const char *path, int isdatasync,
    430 struct fuse_file_info *fi)
    431{
    432 struct subdir *d = subdir_get();
    433 char *newpath;
    434 int err = subdir_addpath(d, path, &newpath);
    435 if (!err) {
    436 err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
    437 free(newpath);
    438 }
    439 return err;
    440}
    441
    442static int subdir_fsyncdir(const char *path, int isdatasync,
    443 struct fuse_file_info *fi)
    444{
    445 struct subdir *d = subdir_get();
    446 char *newpath;
    447 int err = subdir_addpath(d, path, &newpath);
    448 if (!err) {
    449 err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
    450 free(newpath);
    451 }
    452 return err;
    453}
    454
    455static int subdir_setxattr(const char *path, const char *name,
    456 const char *value, size_t size, int flags)
    457{
    458 struct subdir *d = subdir_get();
    459 char *newpath;
    460 int err = subdir_addpath(d, path, &newpath);
    461 if (!err) {
    462 err = fuse_fs_setxattr(d->next, newpath, name, value, size,
    463 flags);
    464 free(newpath);
    465 }
    466 return err;
    467}
    468
    469static int subdir_getxattr(const char *path, const char *name, char *value,
    470 size_t size)
    471{
    472 struct subdir *d = subdir_get();
    473 char *newpath;
    474 int err = subdir_addpath(d, path, &newpath);
    475 if (!err) {
    476 err = fuse_fs_getxattr(d->next, newpath, name, value, size);
    477 free(newpath);
    478 }
    479 return err;
    480}
    481
    482static int subdir_listxattr(const char *path, char *list, size_t size)
    483{
    484 struct subdir *d = subdir_get();
    485 char *newpath;
    486 int err = subdir_addpath(d, path, &newpath);
    487 if (!err) {
    488 err = fuse_fs_listxattr(d->next, newpath, list, size);
    489 free(newpath);
    490 }
    491 return err;
    492}
    493
    494static int subdir_removexattr(const char *path, const char *name)
    495{
    496 struct subdir *d = subdir_get();
    497 char *newpath;
    498 int err = subdir_addpath(d, path, &newpath);
    499 if (!err) {
    500 err = fuse_fs_removexattr(d->next, newpath, name);
    501 free(newpath);
    502 }
    503 return err;
    504}
    505
    506static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
    507 struct flock *lock)
    508{
    509 struct subdir *d = subdir_get();
    510 char *newpath;
    511 int err = subdir_addpath(d, path, &newpath);
    512 if (!err) {
    513 err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
    514 free(newpath);
    515 }
    516 return err;
    517}
    518
    519static int subdir_flock(const char *path, struct fuse_file_info *fi, int op)
    520{
    521 struct subdir *d = subdir_get();
    522 char *newpath;
    523 int err = subdir_addpath(d, path, &newpath);
    524 if (!err) {
    525 err = fuse_fs_flock(d->next, newpath, fi, op);
    526 free(newpath);
    527 }
    528 return err;
    529}
    530
    531static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
    532{
    533 struct subdir *d = subdir_get();
    534 char *newpath;
    535 int err = subdir_addpath(d, path, &newpath);
    536 if (!err) {
    537 err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
    538 free(newpath);
    539 }
    540 return err;
    541}
    542
    543static off_t subdir_lseek(const char *path, off_t off, int whence,
    544 struct fuse_file_info *fi)
    545{
    546 struct subdir *ic = subdir_get();
    547 char *newpath;
    548 int res = subdir_addpath(ic, path, &newpath);
    549 if (!res) {
    550 res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
    551 free(newpath);
    552 }
    553 return res;
    554}
    555
    556#ifdef HAVE_STATX
    557static int subdir_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    558 struct fuse_file_info *fi)
    559{
    560 struct subdir *ic = subdir_get();
    561 char *newpath;
    562 int res = subdir_addpath(ic, path, &newpath);
    563
    564 if (!res) {
    565 res = fuse_fs_statx(ic->next, newpath, flags, mask, stxbuf, fi);
    566 free(newpath);
    567 }
    568 return res;
    569}
    570#endif
    571
    572static void *subdir_init(struct fuse_conn_info *conn,
    573 struct fuse_config *cfg)
    574{
    575 struct subdir *d = subdir_get();
    576 fuse_fs_init(d->next, conn, cfg);
    577 /* Don't touch cfg->nullpath_ok, we can work with
    578 either */
    579 return d;
    580}
    581
    582static void subdir_destroy(void *data)
    583{
    584 struct subdir *d = data;
    585 fuse_fs_destroy(d->next);
    586 free(d->base);
    587 free(d);
    588}
    589
    590static const struct fuse_operations subdir_oper = {
    591 .destroy = subdir_destroy,
    592 .init = subdir_init,
    593 .getattr = subdir_getattr,
    594 .access = subdir_access,
    595 .readlink = subdir_readlink,
    596 .opendir = subdir_opendir,
    597 .readdir = subdir_readdir,
    598 .releasedir = subdir_releasedir,
    599 .mknod = subdir_mknod,
    600 .mkdir = subdir_mkdir,
    601 .symlink = subdir_symlink,
    602 .unlink = subdir_unlink,
    603 .rmdir = subdir_rmdir,
    604 .rename = subdir_rename,
    605 .link = subdir_link,
    606 .chmod = subdir_chmod,
    607 .chown = subdir_chown,
    608 .truncate = subdir_truncate,
    609 .utimens = subdir_utimens,
    610 .create = subdir_create,
    611 .open = subdir_open,
    612 .read_buf = subdir_read_buf,
    613 .write_buf = subdir_write_buf,
    614 .statfs = subdir_statfs,
    615 .flush = subdir_flush,
    616 .release = subdir_release,
    617 .fsync = subdir_fsync,
    618 .fsyncdir = subdir_fsyncdir,
    619 .setxattr = subdir_setxattr,
    620 .getxattr = subdir_getxattr,
    621 .listxattr = subdir_listxattr,
    622 .removexattr = subdir_removexattr,
    623 .lock = subdir_lock,
    624 .flock = subdir_flock,
    625 .bmap = subdir_bmap,
    626 .lseek = subdir_lseek,
    627#ifdef HAVE_STATX
    628 .statx = subdir_statx,
    629#endif
    630};
    631
    632static const struct fuse_opt subdir_opts[] = {
    633 FUSE_OPT_KEY("-h", 0),
    634 FUSE_OPT_KEY("--help", 0),
    635 { "subdir=%s", offsetof(struct subdir, base), 0 },
    636 { "rellinks", offsetof(struct subdir, rellinks), 1 },
    637 { "norellinks", offsetof(struct subdir, rellinks), 0 },
    639};
    640
    641static void subdir_help(void)
    642{
    643 printf(
    644" -o subdir=DIR prepend this directory to all paths (mandatory)\n"
    645" -o [no]rellinks transform absolute symlinks to relative\n");
    646}
    647
    648static int subdir_opt_proc(void *data, const char *arg, int key,
    649 struct fuse_args *outargs)
    650{
    651 (void) data; (void) arg; (void) outargs;
    652
    653 if (!key) {
    654 subdir_help();
    655 return -1;
    656 }
    657
    658 return 1;
    659}
    660
    661static struct fuse_fs *subdir_new(struct fuse_args *args,
    662 struct fuse_fs *next[])
    663{
    664 struct fuse_fs *fs;
    665 struct subdir *d;
    666
    667 d = calloc(1, sizeof(struct subdir));
    668 if (d == NULL) {
    669 fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n");
    670 return NULL;
    671 }
    672
    673 if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1)
    674 goto out_free;
    675
    676 if (!next[0] || next[1]) {
    677 fuse_log(FUSE_LOG_ERR, "fuse-subdir: exactly one next filesystem required\n");
    678 goto out_free;
    679 }
    680
    681 if (!d->base) {
    682 fuse_log(FUSE_LOG_ERR, "fuse-subdir: missing 'subdir' option\n");
    683 goto out_free;
    684 }
    685
    686 if (d->base[0] && d->base[strlen(d->base)-1] != '/') {
    687 char *tmp = realloc(d->base, strlen(d->base) + 2);
    688 if (!tmp) {
    689 fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n");
    690 goto out_free;
    691 }
    692 d->base = tmp;
    693 strcat(d->base, "/");
    694 }
    695 d->baselen = strlen(d->base);
    696 d->next = next[0];
    697 fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d);
    698 if (!fs)
    699 goto out_free;
    700 return fs;
    701
    702out_free:
    703 free(d->base);
    704 free(d);
    705 return NULL;
    706}
    707
    708FUSE_REGISTER_MODULE(subdir, subdir_new);
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    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:93
    struct fuse_fs * fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data)
    Definition fuse.c:4923
    fuse_readdir_flags
    Definition fuse.h:45
    #define FUSE_REGISTER_MODULE(name_, factory_)
    Definition fuse.h:1415
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    void * private_data
    Definition fuse.h:891
    fuse-3.18.3/doc/html/mount_8c_source.html0000644000175000017500000035126115250106404017236 0ustar berndbernd libfuse: lib/mount.c Source File
    libfuse
    mount.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
    4
    5 Architecture specific file system mounting (Linux).
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt.
    9*/
    10
    11/* For environ */
    12#define _GNU_SOURCE
    13
    14#include "fuse_config.h"
    15#include "fuse_i.h"
    16#include "fuse_misc.h"
    17#include "fuse_opt.h"
    18#include "mount_util.h"
    19
    20#include <stdio.h>
    21#include <stdlib.h>
    22#include <unistd.h>
    23#include <stddef.h>
    24#include <string.h>
    25#include <fcntl.h>
    26#include <errno.h>
    27#include <poll.h>
    28#include <spawn.h>
    29#include <sys/socket.h>
    30#include <sys/un.h>
    31#include <sys/wait.h>
    32
    33#include "fuse_mount_compat.h"
    34
    35#ifdef __NetBSD__
    36#include <perfuse.h>
    37
    38#define MS_RDONLY MNT_RDONLY
    39#define MS_NOSUID MNT_NOSUID
    40#define MS_NODEV MNT_NODEV
    41#define MS_NOEXEC MNT_NOEXEC
    42#define MS_SYNCHRONOUS MNT_SYNCHRONOUS
    43#define MS_NOATIME MNT_NOATIME
    44#define MS_NOSYMFOLLOW MNT_NOSYMFOLLOW
    45
    46#define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0)
    47#endif
    48
    49#define FUSERMOUNT_PROG "fusermount3"
    50#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
    51#define FUSE_COMMFD2_ENV "_FUSE_COMMFD2"
    52#define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE"
    53
    54#ifndef MS_DIRSYNC
    55#define MS_DIRSYNC 128
    56#endif
    57
    58enum {
    59 KEY_KERN_FLAG,
    60 KEY_KERN_OPT,
    61 KEY_FUSERMOUNT_OPT,
    62 KEY_SUBTYPE_OPT,
    63 KEY_MTAB_OPT,
    64 KEY_ALLOW_OTHER,
    65 KEY_RO,
    66};
    67
    68struct mount_opts {
    69 int allow_other;
    70 int flags;
    71 int auto_unmount;
    72 int blkdev;
    73 char *fsname;
    74 char *subtype;
    75 char *subtype_opt;
    76 char *mtab_opts;
    77 char *fusermount_opts;
    78 char *kernel_opts;
    79 unsigned max_read;
    80};
    81
    82#define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
    83
    84static const struct fuse_opt fuse_mount_opts[] = {
    85 FUSE_MOUNT_OPT("allow_other", allow_other),
    86 FUSE_MOUNT_OPT("blkdev", blkdev),
    87 FUSE_MOUNT_OPT("auto_unmount", auto_unmount),
    88 FUSE_MOUNT_OPT("fsname=%s", fsname),
    89 FUSE_MOUNT_OPT("max_read=%u", max_read),
    90 FUSE_MOUNT_OPT("subtype=%s", subtype),
    91 FUSE_OPT_KEY("allow_other", KEY_KERN_OPT),
    92 FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT),
    93 FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT),
    94 FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT),
    95 FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT),
    96 FUSE_OPT_KEY("blksize=", KEY_KERN_OPT),
    97 FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT),
    98 FUSE_OPT_KEY("context=", KEY_KERN_OPT),
    99 FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT),
    100 FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT),
    101 FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT),
    102 FUSE_OPT_KEY("max_read=", KEY_KERN_OPT),
    103 FUSE_OPT_KEY("user=", KEY_MTAB_OPT),
    104 FUSE_OPT_KEY("-n", KEY_MTAB_OPT),
    105 FUSE_OPT_KEY("-r", KEY_RO),
    106 FUSE_OPT_KEY("ro", KEY_KERN_FLAG),
    107 FUSE_OPT_KEY("rw", KEY_KERN_FLAG),
    108 FUSE_OPT_KEY("suid", KEY_KERN_FLAG),
    109 FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG),
    110 FUSE_OPT_KEY("dev", KEY_KERN_FLAG),
    111 FUSE_OPT_KEY("nodev", KEY_KERN_FLAG),
    112 FUSE_OPT_KEY("exec", KEY_KERN_FLAG),
    113 FUSE_OPT_KEY("noexec", KEY_KERN_FLAG),
    114 FUSE_OPT_KEY("async", KEY_KERN_FLAG),
    115 FUSE_OPT_KEY("sync", KEY_KERN_FLAG),
    116 FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG),
    117 FUSE_OPT_KEY("noatime", KEY_KERN_FLAG),
    118 FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG),
    119 FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG),
    120 FUSE_OPT_KEY("symfollow", KEY_KERN_FLAG),
    121 FUSE_OPT_KEY("nosymfollow", KEY_KERN_FLAG),
    123};
    124
    125/*
    126 * Running fusermount by calling 'posix_spawn'
    127 *
    128 * @param out_pid might be NULL
    129 */
    130static int fusermount_posix_spawn(posix_spawn_file_actions_t *action,
    131 char const * const argv[], pid_t *out_pid)
    132{
    133 const char *full_path = FUSERMOUNT_DIR "/" FUSERMOUNT_PROG;
    134 pid_t pid;
    135
    136 /* See man 7 environ for the global environ pointer */
    137
    138 /* first try the install path */
    139 int status = posix_spawn(&pid, full_path, action, NULL,
    140 (char * const *) argv, environ);
    141 if (status != 0) {
    142 /* if that fails, try a system install */
    143 status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL,
    144 (char * const *) argv, environ);
    145 }
    146
    147 if (status != 0) {
    148 fuse_log(FUSE_LOG_ERR, "Failed to call '%s': %s\n",
    149 FUSERMOUNT_PROG, strerror(status));
    150 return -status;
    151 }
    152
    153 if (out_pid)
    154 *out_pid = pid;
    155 else
    156 waitpid(pid, NULL, 0); /* FIXME: check exit code and return error if any */
    157
    158 return 0;
    159}
    160
    161void fuse_mount_version(void)
    162{
    163 char const *const argv[] = {FUSERMOUNT_PROG, "--version", NULL};
    164 int status = fusermount_posix_spawn(NULL, argv, NULL);
    165
    166 if(status != 0)
    167 fuse_log(FUSE_LOG_ERR, "Running '%s --version' failed",
    168 FUSERMOUNT_PROG);
    169}
    170
    171struct mount_flags {
    172 const char *opt;
    173 unsigned long flag;
    174 int on;
    175};
    176
    177static const struct mount_flags mount_flags[] = {
    178 {"rw", MS_RDONLY, 0},
    179 {"ro", MS_RDONLY, 1},
    180 {"suid", MS_NOSUID, 0},
    181 {"nosuid", MS_NOSUID, 1},
    182 {"dev", MS_NODEV, 0},
    183 {"nodev", MS_NODEV, 1},
    184 {"exec", MS_NOEXEC, 0},
    185 {"noexec", MS_NOEXEC, 1},
    186 {"async", MS_SYNCHRONOUS, 0},
    187 {"sync", MS_SYNCHRONOUS, 1},
    188 {"noatime", MS_NOATIME, 1},
    189 {"nodiratime", MS_NODIRATIME, 1},
    190 {"norelatime", MS_RELATIME, 0},
    191 {"nostrictatime", MS_STRICTATIME, 0},
    192 {"symfollow", MS_NOSYMFOLLOW, 0},
    193 {"nosymfollow", MS_NOSYMFOLLOW, 1},
    194#ifndef __NetBSD__
    195 {"dirsync", MS_DIRSYNC, 1},
    196#endif
    197 {NULL, 0, 0}
    198};
    199
    200unsigned get_max_read(struct mount_opts *o)
    201{
    202 return o->max_read;
    203}
    204
    205static void set_mount_flag(const char *s, int *flags)
    206{
    207 int i;
    208
    209 for (i = 0; mount_flags[i].opt != NULL; i++) {
    210 const char *opt = mount_flags[i].opt;
    211 if (strcmp(opt, s) == 0) {
    212 if (mount_flags[i].on)
    213 *flags |= mount_flags[i].flag;
    214 else
    215 *flags &= ~mount_flags[i].flag;
    216 return;
    217 }
    218 }
    219 fuse_log(FUSE_LOG_ERR, "fuse: internal error, can't find mount flag\n");
    220 abort();
    221}
    222
    223static int fuse_mount_opt_proc(void *data, const char *arg, int key,
    224 struct fuse_args *outargs)
    225{
    226 (void) outargs;
    227 struct mount_opts *mo = data;
    228
    229 switch (key) {
    230 case KEY_RO:
    231 arg = "ro";
    232 /* fall through */
    233 case KEY_KERN_FLAG:
    234 set_mount_flag(arg, &mo->flags);
    235 return 0;
    236
    237 case KEY_KERN_OPT:
    238 return fuse_opt_add_opt(&mo->kernel_opts, arg);
    239
    240 case KEY_FUSERMOUNT_OPT:
    241 return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg);
    242
    243 case KEY_SUBTYPE_OPT:
    244 return fuse_opt_add_opt(&mo->subtype_opt, arg);
    245
    246 case KEY_MTAB_OPT:
    247 return fuse_opt_add_opt(&mo->mtab_opts, arg);
    248
    249 /* Third party options like 'x-gvfs-notrash' */
    250 case FUSE_OPT_KEY_OPT:
    251 return (strncmp("x-", arg, 2) == 0) ?
    252 fuse_opt_add_opt(&mo->mtab_opts, arg) :
    253 1;
    254 }
    255
    256 /* Pass through unknown options */
    257 return 1;
    258}
    259
    260/* return value:
    261 * >= 0 => fd
    262 * -1 => error
    263 */
    264static int receive_fd(int fd)
    265{
    266 struct msghdr msg;
    267 struct iovec iov;
    268 char buf[1];
    269 int rv;
    270 size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)];
    271 struct cmsghdr *cmsg;
    272
    273 iov.iov_base = buf;
    274 iov.iov_len = 1;
    275
    276 memset(&msg, 0, sizeof(msg));
    277 msg.msg_name = 0;
    278 msg.msg_namelen = 0;
    279 msg.msg_iov = &iov;
    280 msg.msg_iovlen = 1;
    281 /* old BSD implementations should use msg_accrights instead of
    282 * msg_control; the interface is different. */
    283 msg.msg_control = ccmsg;
    284 msg.msg_controllen = sizeof(ccmsg);
    285
    286 while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR);
    287 if (rv == -1) {
    288 fuse_log(FUSE_LOG_ERR, "recvmsg failed: %s", strerror(errno));
    289 return -1;
    290 }
    291 if(!rv) {
    292 /* EOF */
    293 return -1;
    294 }
    295
    296 cmsg = CMSG_FIRSTHDR(&msg);
    297 if (!cmsg) {
    298 fuse_log(FUSE_LOG_ERR, "error retrieving control message header\n");
    299 return -1;
    300 }
    301 if (cmsg->cmsg_type != SCM_RIGHTS) {
    302 fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n",
    303 cmsg->cmsg_type);
    304 return -1;
    305 }
    306 return *(int*)CMSG_DATA(cmsg);
    307}
    308
    309void fuse_kern_unmount(const char *mountpoint, int fd)
    310{
    311 int res;
    312
    313 if (fd != -1) {
    314 struct pollfd pfd;
    315
    316 pfd.fd = fd;
    317 pfd.events = 0;
    318 res = poll(&pfd, 1, 0);
    319
    320 /* Need to close file descriptor, otherwise synchronous umount
    321 would recurse into filesystem, and deadlock.
    322
    323 Caller expects fuse_kern_unmount to close the fd, so close it
    324 anyway. */
    325 close(fd);
    326
    327 /* If file poll returns POLLERR on the device file descriptor,
    328 then the filesystem is already unmounted or the connection
    329 was severed via /sys/fs/fuse/connections/NNN/abort */
    330 if (res == 1 && (pfd.revents & POLLERR))
    331 return;
    332 }
    333
    334 if (geteuid() == 0) {
    335 fuse_mnt_umount("fuse", mountpoint, mountpoint, 1);
    336 return;
    337 }
    338
    339 res = umount2(mountpoint, MNT_DETACH | UMOUNT_NOFOLLOW);
    340 if (res == 0)
    341 return;
    342
    343 char const * const argv[] =
    344 { FUSERMOUNT_PROG, "--unmount", "--quiet", "--lazy",
    345 "--", mountpoint, NULL };
    346 int status = fusermount_posix_spawn(NULL, argv, NULL);
    347 if(status != 0) {
    348 fuse_log(FUSE_LOG_ERR, "Spawning %s to unmount failed: %s",
    349 FUSERMOUNT_PROG, strerror(-status));
    350 return;
    351 }
    352}
    353
    354static int setup_auto_unmount(const char *mountpoint, int quiet)
    355{
    356 int fds[2];
    357 pid_t pid;
    358 int res;
    359
    360 if (!mountpoint) {
    361 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
    362 return -1;
    363 }
    364
    365 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
    366 if(res == -1) {
    367 fuse_log(FUSE_LOG_ERR, "Setting up auto-unmount socketpair() failed: %s\n",
    368 strerror(errno));
    369 return -1;
    370 }
    371
    372 char arg_fd_entry[30];
    373 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
    374 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
    375 /*
    376 * This helps to identify the FD hold by parent process.
    377 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
    378 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
    379 * One potential use case is to satisfy FD-Leak checks.
    380 */
    381 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
    382 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
    383
    384 char const *const argv[] = {
    385 FUSERMOUNT_PROG,
    386 "--auto-unmount",
    387 "--",
    388 mountpoint,
    389 NULL,
    390 };
    391
    392 // TODO: add error handling for all manipulations of action.
    393 posix_spawn_file_actions_t action;
    394 posix_spawn_file_actions_init(&action);
    395
    396 if (quiet) {
    397 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
    398 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
    399 }
    400 posix_spawn_file_actions_addclose(&action, fds[1]);
    401
    402 /*
    403 * auto-umount runs in the background - it is not waiting for the
    404 * process
    405 */
    406 int status = fusermount_posix_spawn(&action, argv, &pid);
    407
    408 posix_spawn_file_actions_destroy(&action);
    409
    410 if(status != 0) {
    411 close(fds[0]);
    412 close(fds[1]);
    413 fuse_log(FUSE_LOG_ERR, "fuse: Setting up auto-unmount failed (spawn): %s",
    414 strerror(-status));
    415 return -1;
    416 }
    417 // passed to child now, so can close here.
    418 close(fds[0]);
    419
    420 // Now fusermount3 will only exit when fds[1] closes automatically when our
    421 // process exits.
    422 return 0;
    423 // Note: fds[1] is leakend and doesn't get FD_CLOEXEC
    424}
    425
    426static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo,
    427 const char *opts, int quiet)
    428{
    429 int fds[2];
    430 pid_t pid;
    431 int res;
    432
    433 if (!mountpoint) {
    434 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
    435 return -1;
    436 }
    437
    438 res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds);
    439 if(res == -1) {
    440 fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n",
    441 FUSERMOUNT_PROG, strerror(errno));
    442 return -1;
    443 }
    444
    445 char arg_fd_entry[30];
    446 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]);
    447 setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1);
    448 /*
    449 * This helps to identify the FD hold by parent process.
    450 * In auto-unmount case, parent process can close this FD explicitly to do unmount.
    451 * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV).
    452 * One potential use case is to satisfy FD-Leak checks.
    453 */
    454 snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]);
    455 setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1);
    456
    457 char const *const argv[] = {
    458 FUSERMOUNT_PROG,
    459 "-o", opts ? opts : "",
    460 "--",
    461 mountpoint,
    462 NULL,
    463 };
    464
    465
    466 posix_spawn_file_actions_t action;
    467 posix_spawn_file_actions_init(&action);
    468
    469 if (quiet) {
    470 posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0);
    471 posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0);
    472 }
    473 posix_spawn_file_actions_addclose(&action, fds[1]);
    474
    475 int status = fusermount_posix_spawn(&action, argv, &pid);
    476
    477 posix_spawn_file_actions_destroy(&action);
    478
    479 if(status != 0) {
    480 close(fds[0]);
    481 close(fds[1]);
    482 fuse_log(FUSE_LOG_ERR, "posix_spawn(p)() for %s failed: %s",
    483 FUSERMOUNT_PROG, strerror(-status));
    484 return -1;
    485 }
    486
    487 // passed to child now, so can close here.
    488 close(fds[0]);
    489
    490 int fd = receive_fd(fds[1]);
    491
    492 if (!mo->auto_unmount) {
    493 /* with auto_unmount option fusermount3 will not exit until
    494 this socket is closed */
    495 close(fds[1]);
    496 waitpid(pid, NULL, 0); /* bury zombie */
    497 }
    498
    499 if (fd >= 0)
    500 fcntl(fd, F_SETFD, FD_CLOEXEC);
    501
    502 return fd;
    503}
    504
    505#ifndef O_CLOEXEC
    506#define O_CLOEXEC 0
    507#endif
    508
    509static int fuse_mount_sys(const char *mnt, struct mount_opts *mo,
    510 const char *mnt_opts)
    511{
    512 char tmp[128];
    513 const char *devname = getenv(FUSE_KERN_DEVICE_ENV) ?: "/dev/fuse";
    514 char *source = NULL;
    515 char *type = NULL;
    516 struct stat stbuf;
    517 int fd;
    518 int res;
    519
    520 if (!mnt) {
    521 fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n");
    522 return -1;
    523 }
    524
    525 res = stat(mnt, &stbuf);
    526 if (res == -1) {
    527 fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n",
    528 mnt, strerror(errno));
    529 return -1;
    530 }
    531
    532 fd = open(devname, O_RDWR | O_CLOEXEC);
    533 if (fd == -1) {
    534 if (errno == ENODEV || errno == ENOENT)
    535 fuse_log(FUSE_LOG_ERR,
    536 "fuse: device %s not found. Kernel module not loaded?\n",
    537 devname);
    538 else
    539 fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n",
    540 devname, strerror(errno));
    541 return -1;
    542 }
    543 if (!O_CLOEXEC)
    544 fcntl(fd, F_SETFD, FD_CLOEXEC);
    545
    546 snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
    547 fd, stbuf.st_mode & S_IFMT, getuid(), getgid());
    548
    549 res = fuse_opt_add_opt(&mo->kernel_opts, tmp);
    550 if (res == -1)
    551 goto out_close;
    552
    553 source = malloc((mo->fsname ? strlen(mo->fsname) : 0) +
    554 (mo->subtype ? strlen(mo->subtype) : 0) +
    555 strlen(devname) + 32);
    556
    557 type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32);
    558 if (!type || !source) {
    559 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n");
    560 goto out_close;
    561 }
    562
    563 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
    564 if (mo->subtype) {
    565 strcat(type, ".");
    566 strcat(type, mo->subtype);
    567 }
    568 strcpy(source,
    569 mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname));
    570
    571 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
    572 if (res == -1 && errno == ENODEV && mo->subtype) {
    573 /* Probably missing subtype support */
    574 strcpy(type, mo->blkdev ? "fuseblk" : "fuse");
    575 if (mo->fsname) {
    576 if (!mo->blkdev)
    577 sprintf(source, "%s#%s", mo->subtype,
    578 mo->fsname);
    579 } else {
    580 strcpy(source, type);
    581 }
    582 res = mount(source, mnt, type, mo->flags, mo->kernel_opts);
    583 }
    584 if (res == -1) {
    585 /*
    586 * Maybe kernel doesn't support unprivileged mounts, in this
    587 * case try falling back to fusermount3
    588 */
    589 if (errno == EPERM) {
    590 res = -2;
    591 } else {
    592 int errno_save = errno;
    593 if (mo->blkdev && errno == ENODEV &&
    594 !fuse_mnt_check_fuseblk())
    595 fuse_log(FUSE_LOG_ERR,
    596 "fuse: 'fuseblk' support missing\n");
    597 else
    598 fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n",
    599 strerror(errno_save));
    600 }
    601
    602 goto out_close;
    603 }
    604
    605#ifndef IGNORE_MTAB
    606 if (geteuid() == 0) {
    607 char *newmnt = fuse_mnt_resolve_path("fuse", mnt);
    608 res = -1;
    609 if (!newmnt)
    610 goto out_umount;
    611
    612 res = fuse_mnt_add_mount("fuse", source, newmnt, type,
    613 mnt_opts);
    614 free(newmnt);
    615 if (res == -1)
    616 goto out_umount;
    617 }
    618#endif /* IGNORE_MTAB */
    619 free(type);
    620 free(source);
    621
    622 return fd;
    623
    624out_umount:
    625 umount2(mnt, MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */
    626out_close:
    627 free(type);
    628 free(source);
    629 close(fd);
    630 return res;
    631}
    632
    633static int get_mnt_flag_opts(char **mnt_optsp, int flags)
    634{
    635 int i;
    636
    637 if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1)
    638 return -1;
    639
    640 for (i = 0; mount_flags[i].opt != NULL; i++) {
    641 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
    642 fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1)
    643 return -1;
    644 }
    645 return 0;
    646}
    647
    648struct mount_opts *parse_mount_opts(struct fuse_args *args)
    649{
    650 struct mount_opts *mo;
    651
    652 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
    653 if (mo == NULL)
    654 return NULL;
    655
    656 memset(mo, 0, sizeof(struct mount_opts));
    657 mo->flags = MS_NOSUID | MS_NODEV;
    658
    659 if (args &&
    660 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
    661 goto err_out;
    662
    663 return mo;
    664
    665err_out:
    666 destroy_mount_opts(mo);
    667 return NULL;
    668}
    669
    670void destroy_mount_opts(struct mount_opts *mo)
    671{
    672 free(mo->fsname);
    673 free(mo->subtype);
    674 free(mo->fusermount_opts);
    675 free(mo->subtype_opt);
    676 free(mo->kernel_opts);
    677 free(mo->mtab_opts);
    678 free(mo);
    679}
    680
    681
    682int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
    683{
    684 int res = -1;
    685 char *mnt_opts = NULL;
    686
    687 res = -1;
    688 if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1)
    689 goto out;
    690 if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1)
    691 goto out;
    692 if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1)
    693 goto out;
    694
    695 res = fuse_mount_sys(mountpoint, mo, mnt_opts);
    696 if (res >= 0 && mo->auto_unmount) {
    697 if(0 > setup_auto_unmount(mountpoint, 0)) {
    698 // Something went wrong, let's umount like in fuse_mount_sys.
    699 umount2(mountpoint,
    700 MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */
    701 res = -1;
    702 }
    703 } else if (res == -2) {
    704 if (mo->fusermount_opts &&
    705 fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1)
    706 goto out;
    707
    708 if (mo->subtype) {
    709 char *tmp_opts = NULL;
    710
    711 res = -1;
    712 if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 ||
    713 fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) {
    714 free(tmp_opts);
    715 goto out;
    716 }
    717
    718 res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1);
    719 free(tmp_opts);
    720 if (res == -1)
    721 res = fuse_mount_fusermount(mountpoint, mo,
    722 mnt_opts, 0);
    723 } else {
    724 res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0);
    725 }
    726 }
    727out:
    728 free(mnt_opts);
    729 return res;
    730}
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    #define FUSE_OPT_KEY_OPT
    Definition fuse_opt.h:129
    int fuse_opt_add_opt_escaped(char **opts, const char *opt)
    Definition fuse_opt.c:144
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    int fuse_opt_add_opt(char **opts, const char *opt)
    Definition fuse_opt.c:139
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    fuse-3.18.3/doc/html/mount__bsd_8c_source.html0000644000175000017500000013045315250106404020223 0ustar berndbernd libfuse: lib/mount_bsd.c Source File
    libfuse
    mount_bsd.c
    1/*
    2 FUSE: Filesystem in Userspace
    3 Copyright (C) 2005-2008 Csaba Henk <csaba.henk@creo.hu>
    4
    5 Architecture specific file system mounting (FreeBSD).
    6
    7 This program can be distributed under the terms of the GNU LGPLv2.
    8 See the file LGPL2.txt.
    9*/
    10
    11#include "fuse_config.h"
    12#include "fuse_i.h"
    13#include "fuse_misc.h"
    14#include "fuse_opt.h"
    15#include "util.h"
    16
    17#include <sys/param.h>
    18#include "fuse_mount_compat.h"
    19
    20#include <sys/wait.h>
    21#include <stdio.h>
    22#include <stdlib.h>
    23#include <unistd.h>
    24#include <stddef.h>
    25#include <fcntl.h>
    26#include <errno.h>
    27#include <string.h>
    28
    29#define FUSERMOUNT_PROG "mount_fusefs"
    30#define FUSE_DEV_TRUNK "/dev/fuse"
    31
    32enum {
    33 KEY_RO,
    34 KEY_KERN
    35};
    36
    37struct mount_opts {
    38 int allow_other;
    39 char *kernel_opts;
    40 unsigned max_read;
    41};
    42
    43#define FUSE_DUAL_OPT_KEY(templ, key) \
    44 FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key)
    45
    46static const struct fuse_opt fuse_mount_opts[] = {
    47 { "allow_other", offsetof(struct mount_opts, allow_other), 1 },
    48 { "max_read=%u", offsetof(struct mount_opts, max_read), 1 },
    49 FUSE_OPT_KEY("-r", KEY_RO),
    50 /* standard FreeBSD mount options */
    51 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
    52 FUSE_DUAL_OPT_KEY("async", KEY_KERN),
    53 FUSE_DUAL_OPT_KEY("atime", KEY_KERN),
    54 FUSE_DUAL_OPT_KEY("dev", KEY_KERN),
    55 FUSE_DUAL_OPT_KEY("exec", KEY_KERN),
    56 FUSE_DUAL_OPT_KEY("suid", KEY_KERN),
    57 FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN),
    58 FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN),
    59 FUSE_DUAL_OPT_KEY("sync", KEY_KERN),
    60 FUSE_DUAL_OPT_KEY("union", KEY_KERN),
    61 FUSE_DUAL_OPT_KEY("userquota", KEY_KERN),
    62 FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN),
    63 FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN),
    64 FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN),
    65 FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN),
    66 FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN),
    67 FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN),
    68 FUSE_DUAL_OPT_KEY("acls", KEY_KERN),
    69 FUSE_DUAL_OPT_KEY("force", KEY_KERN),
    70 FUSE_DUAL_OPT_KEY("update", KEY_KERN),
    71 FUSE_DUAL_OPT_KEY("ro", KEY_KERN),
    72 FUSE_DUAL_OPT_KEY("rw", KEY_KERN),
    73 FUSE_DUAL_OPT_KEY("auto", KEY_KERN),
    74 FUSE_DUAL_OPT_KEY("automounted", KEY_KERN),
    75 /* options supported under both Linux and FBSD */
    76 FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN),
    77 FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN),
    78 FUSE_OPT_KEY("max_read=", KEY_KERN),
    79 FUSE_OPT_KEY("subtype=", KEY_KERN),
    80 /* FBSD FUSE specific mount options */
    81 FUSE_DUAL_OPT_KEY("private", KEY_KERN),
    82 FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN),
    83 FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN),
    84#if __FreeBSD_version >= 1200519
    85 FUSE_DUAL_OPT_KEY("intr", KEY_KERN),
    86#endif
    87 /* stock FBSD mountopt parsing routine lets anything be negated... */
    88 /*
    89 * Linux specific mount options, but let just the mount util
    90 * handle them
    91 */
    92 FUSE_OPT_KEY("fsname=", KEY_KERN),
    94};
    95
    96void fuse_mount_version(void)
    97{
    98 system(FUSERMOUNT_PROG " --version");
    99}
    100
    101unsigned get_max_read(struct mount_opts *o)
    102{
    103 return o->max_read;
    104}
    105
    106static int fuse_mount_opt_proc(void *data, const char *arg, int key,
    107 struct fuse_args *outargs)
    108{
    109 (void) outargs;
    110 struct mount_opts *mo = data;
    111
    112 switch (key) {
    113 case KEY_RO:
    114 arg = "ro";
    115 /* fall through */
    116
    117 case KEY_KERN:
    118 return fuse_opt_add_opt(&mo->kernel_opts, arg);
    119 }
    120
    121 /* Pass through unknown options */
    122 return 1;
    123}
    124
    125void fuse_kern_unmount(const char *mountpoint, int fd)
    126{
    127 if (close(fd) < 0)
    128 fuse_log(FUSE_LOG_ERR, "closing FD %d failed: %s", fd, strerror(errno));
    129 if (unmount(mountpoint, MNT_FORCE) < 0)
    130 fuse_log(FUSE_LOG_ERR, "unmounting %s failed: %s",
    131 mountpoint, strerror(errno));
    132}
    133
    134static int fuse_mount_core(const char *mountpoint, const char *opts)
    135{
    136 const char *mountprog = FUSERMOUNT_PROG;
    137 long fd;
    138 char *fdnam, *dev;
    139 pid_t pid, cpid;
    140 int status;
    141 int err;
    142
    143 fdnam = getenv("FUSE_DEV_FD");
    144
    145 if (fdnam) {
    146 err = libfuse_strtol(fdnam, &fd);
    147 if (err || fd < 0) {
    148 fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n");
    149 return -1;
    150 }
    151
    152 goto mount;
    153 }
    154
    155 dev = getenv("FUSE_DEV_NAME");
    156
    157 if (! dev)
    158 dev = (char *)FUSE_DEV_TRUNK;
    159
    160 if ((fd = open(dev, O_RDWR)) < 0) {
    161 perror("fuse: failed to open fuse device");
    162 return -1;
    163 }
    164
    165mount:
    166 if (getenv("FUSE_NO_MOUNT") || ! mountpoint)
    167 goto out;
    168
    169 pid = fork();
    170 cpid = pid;
    171
    172 if (pid == -1) {
    173 perror("fuse: fork() failed");
    174 close(fd);
    175 return -1;
    176 }
    177
    178 if (pid == 0) {
    179 pid = fork();
    180
    181 if (pid == -1) {
    182 perror("fuse: fork() failed");
    183 close(fd);
    184 _exit(EXIT_FAILURE);
    185 }
    186
    187 if (pid == 0) {
    188 const char *argv[32];
    189 int a = 0;
    190 int ret = -1;
    191
    192 if (! fdnam)
    193 {
    194 ret = asprintf(&fdnam, "%ld", fd);
    195 if(ret == -1)
    196 {
    197 perror("fuse: failed to assemble mount arguments");
    198 close(fd);
    199 _exit(EXIT_FAILURE);
    200 }
    201 }
    202
    203 argv[a++] = mountprog;
    204 if (opts) {
    205 argv[a++] = "-o";
    206 argv[a++] = opts;
    207 }
    208 argv[a++] = fdnam;
    209 argv[a++] = mountpoint;
    210 argv[a++] = NULL;
    211 execvp(mountprog, (char **) argv);
    212 perror("fuse: failed to exec mount program");
    213 free(fdnam);
    214 _exit(EXIT_FAILURE);
    215 }
    216
    217 waitpid(pid, &status, 0);
    218 if (!WIFEXITED(status))
    219 _exit(EXIT_FAILURE);
    220 _exit(WEXITSTATUS(status));
    221 }
    222
    223 if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) {
    224 perror("fuse: failed to mount file system");
    225 if (close(fd) < 0)
    226 perror("fuse: closing FD");
    227 return -1;
    228 }
    229
    230out:
    231 return fd;
    232}
    233
    234struct mount_opts *parse_mount_opts(struct fuse_args *args)
    235{
    236 struct mount_opts *mo;
    237
    238 mo = (struct mount_opts*) malloc(sizeof(struct mount_opts));
    239 if (mo == NULL)
    240 return NULL;
    241
    242 memset(mo, 0, sizeof(struct mount_opts));
    243
    244 if (args &&
    245 fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1)
    246 goto err_out;
    247
    248 return mo;
    249
    250err_out:
    251 destroy_mount_opts(mo);
    252 return NULL;
    253}
    254
    255void destroy_mount_opts(struct mount_opts *mo)
    256{
    257 free(mo->kernel_opts);
    258 free(mo);
    259}
    260
    261int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo)
    262{
    263 /* mount util should not try to spawn the daemon */
    264 setenv("MOUNT_FUSEFS_SAFE", "1", 1);
    265 /* to notify the mount util it's called from lib */
    266 setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1);
    267
    268 return fuse_mount_core(mountpoint, mo->kernel_opts);
    269}
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    int fuse_opt_add_opt(char **opts, const char *opt)
    Definition fuse_opt.c:139
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    fuse-3.18.3/doc/html/mount__util_8c_source.html0000644000175000017500000017411115250106404020427 0ustar berndbernd 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 LGPL2.txt.
    9*/
    10
    11#include "fuse_config.h"
    12#include "mount_util.h"
    13#include "fuse_log.h"
    14
    15#include <stdio.h>
    16#include <unistd.h>
    17#include <stdlib.h>
    18#include <string.h>
    19#include <signal.h>
    20#include <dirent.h>
    21#include <errno.h>
    22#include <fcntl.h>
    23#include <limits.h>
    24#include <paths.h>
    25#if !defined( __NetBSD__) && !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__ANDROID__)
    26#include <mntent.h>
    27#else
    28#define IGNORE_MTAB
    29#endif
    30#include <sys/stat.h>
    31#include <sys/wait.h>
    32
    33#include "fuse_mount_compat.h"
    34
    35#include <sys/param.h>
    36
    37#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
    38#define umount2(mnt, flags) unmount(mnt, ((flags) == 2) ? MNT_FORCE : 0)
    39#endif
    40
    41#ifdef IGNORE_MTAB
    42#define mtab_needs_update(mnt) 0
    43#else
    44static int mtab_needs_update(const char *mnt)
    45{
    46 int res;
    47 struct stat stbuf;
    48
    49 /* If mtab is within new mount, don't touch it */
    50 if (strncmp(mnt, _PATH_MOUNTED, strlen(mnt)) == 0 &&
    51 _PATH_MOUNTED[strlen(mnt)] == '/')
    52 return 0;
    53
    54 /*
    55 * Skip mtab update if /etc/mtab:
    56 *
    57 * - doesn't exist,
    58 * - is on a read-only filesystem.
    59 */
    60 res = lstat(_PATH_MOUNTED, &stbuf);
    61 if (res == -1) {
    62 if (errno == ENOENT)
    63 return 0;
    64 } else {
    65 uid_t ruid;
    66 int err;
    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 res = access("/run/mount/utab", F_OK);
    81 if (res == -1)
    82 return 0;
    83 }
    84
    85 return 1;
    86}
    87#endif /* IGNORE_MTAB */
    88
    89/*
    90 * These values become command line arguments of /bin/mount and /bin/umount.
    91 * BusyBox mount(8) parses an argument starting with '-' as an option even
    92 * behind an end-of-options marker ("--"); NULL would end the argument list
    93 * early.
    94 *
    95 * @return 1 if @value is unsafe as a /bin/mount or /bin/umount argument.
    96 */
    97static int unsafe_operand(const char *value)
    98{
    99 return value == NULL || value[0] == '-';
    100}
    101
    102static int add_mount(const char *progname, const char *fsname,
    103 const char *mnt, const char *type, const char *opts)
    104{
    105 int res;
    106 int status;
    107 sigset_t blockmask;
    108 sigset_t oldmask;
    109
    110 if (unsafe_operand(fsname) || unsafe_operand(mnt) ||
    111 unsafe_operand(type) || unsafe_operand(opts)) {
    112 fuse_log(FUSE_LOG_DEBUG,
    113 "%s: option-like mount argument, skipping mtab update\n",
    114 progname);
    115 return 0;
    116 }
    117
    118 sigemptyset(&blockmask);
    119 sigaddset(&blockmask, SIGCHLD);
    120 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
    121 if (res == -1) {
    122 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
    123 return -1;
    124 }
    125
    126 res = fork();
    127 if (res == -1) {
    128 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
    129 goto out_restore;
    130 }
    131 if (res == 0) {
    132 char *env = NULL;
    133
    134 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    135
    136 if(setuid(geteuid()) == -1) {
    137 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
    138 res = -1;
    139 goto out_restore;
    140 }
    141
    142 /*
    143 * fsname comes from -ofsname=, so it can start with '-'. The
    144 * setuid() above raises the real uid to 0, so mount(8) is not
    145 * in restricted mode either. Terminate the options with "--"
    146 * to keep it from parsing the operands as further options.
    147 */
    148 execle("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
    149 "-f", "-t", type, "-o", opts, "--", fsname, mnt, NULL,
    150 &env);
    151 fprintf(stderr, "%s: failed to execute /bin/mount: %s\n",
    152 progname, strerror(errno));
    153 exit(1);
    154 }
    155 res = waitpid(res, &status, 0);
    156 if (res == -1)
    157 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
    158
    159 if (status != 0)
    160 res = -1;
    161
    162 out_restore:
    163 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    164
    165 return res;
    166}
    167
    168int fuse_mnt_add_mount(const char *progname, const char *fsname,
    169 const char *mnt, const char *type, const char *opts)
    170{
    171 if (!mtab_needs_update(mnt))
    172 return 0;
    173
    174 return add_mount(progname, fsname, mnt, type, opts);
    175}
    176
    177static int exec_umount(const char *progname, const char *rel_mnt, int lazy)
    178{
    179 int res;
    180 int status;
    181 sigset_t blockmask;
    182 sigset_t oldmask;
    183
    184 sigemptyset(&blockmask);
    185 sigaddset(&blockmask, SIGCHLD);
    186 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
    187 if (res == -1) {
    188 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
    189 return -1;
    190 }
    191
    192 res = fork();
    193 if (res == -1) {
    194 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
    195 goto out_restore;
    196 }
    197 if (res == 0) {
    198 char *env = NULL;
    199
    200 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    201
    202 if(setuid(geteuid()) == -1) {
    203 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
    204 res = -1;
    205 goto out_restore;
    206 }
    207
    208 if (lazy) {
    209 execle("/bin/umount", "/bin/umount", "-i", "-l",
    210 "--", rel_mnt, NULL, &env);
    211 } else {
    212 execle("/bin/umount", "/bin/umount", "-i",
    213 "--", rel_mnt, NULL, &env);
    214 }
    215 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
    216 progname, strerror(errno));
    217 exit(1);
    218 }
    219 res = waitpid(res, &status, 0);
    220 if (res == -1)
    221 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
    222
    223 if (status != 0) {
    224 res = -1;
    225 }
    226
    227 out_restore:
    228 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    229 return res;
    230
    231}
    232
    233int fuse_mnt_umount(const char *progname, const char *abs_mnt,
    234 const char *rel_mnt, int lazy)
    235{
    236 int res;
    237
    238 /*
    239 * umount(8) may read an option-like rel_mnt as an option: unmount here
    240 * instead and leave the mtab/utab record behind
    241 */
    242 if (!mtab_needs_update(abs_mnt) || unsafe_operand(rel_mnt)) {
    243 res = umount2(rel_mnt, lazy ? 2 : 0);
    244 if (res == -1)
    245 fprintf(stderr, "%s: failed to unmount %s: %s\n",
    246 progname, abs_mnt, strerror(errno));
    247 return res;
    248 }
    249
    250 return exec_umount(progname, rel_mnt, lazy);
    251}
    252
    253static int remove_mount(const char *progname, const char *mnt)
    254{
    255 int res;
    256 int status;
    257 sigset_t blockmask;
    258 sigset_t oldmask;
    259
    260 if (unsafe_operand(mnt))
    261 return 0;
    262
    263 sigemptyset(&blockmask);
    264 sigaddset(&blockmask, SIGCHLD);
    265 res = sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
    266 if (res == -1) {
    267 fprintf(stderr, "%s: sigprocmask: %s\n", progname, strerror(errno));
    268 return -1;
    269 }
    270
    271 res = fork();
    272 if (res == -1) {
    273 fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
    274 goto out_restore;
    275 }
    276 if (res == 0) {
    277 char *env = NULL;
    278
    279 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    280
    281 if(setuid(geteuid()) == -1) {
    282 fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno));
    283 res = -1;
    284 goto out_restore;
    285 }
    286
    287 execle("/bin/umount", "/bin/umount", "--no-canonicalize", "-i",
    288 "--fake", "--", mnt, NULL, &env);
    289 fprintf(stderr, "%s: failed to execute /bin/umount: %s\n",
    290 progname, strerror(errno));
    291 exit(1);
    292 }
    293 res = waitpid(res, &status, 0);
    294 if (res == -1)
    295 fprintf(stderr, "%s: waitpid: %s\n", progname, strerror(errno));
    296
    297 if (status != 0)
    298 res = -1;
    299
    300 out_restore:
    301 sigprocmask(SIG_SETMASK, &oldmask, NULL);
    302 return res;
    303}
    304
    305int fuse_mnt_remove_mount(const char *progname, const char *mnt)
    306{
    307 if (!mtab_needs_update(mnt))
    308 return 0;
    309
    310 return remove_mount(progname, mnt);
    311}
    312
    313char *fuse_mnt_resolve_path(const char *progname, const char *orig)
    314{
    315 char buf[PATH_MAX];
    316 char *copy;
    317 char *dst;
    318 char *end;
    319 char *lastcomp;
    320 const char *toresolv;
    321
    322 if (!orig[0]) {
    323 fprintf(stderr, "%s: invalid mountpoint '%s'\n", progname,
    324 orig);
    325 return NULL;
    326 }
    327
    328 copy = strdup(orig);
    329 if (copy == NULL) {
    330 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    331 return NULL;
    332 }
    333
    334 toresolv = copy;
    335 lastcomp = NULL;
    336 for (end = copy + strlen(copy) - 1; end > copy && *end == '/'; end --);
    337 if (end[0] != '/') {
    338 char *tmp;
    339 end[1] = '\0';
    340 tmp = strrchr(copy, '/');
    341 if (tmp == NULL) {
    342 lastcomp = copy;
    343 toresolv = ".";
    344 } else {
    345 lastcomp = tmp + 1;
    346 if (tmp == copy)
    347 toresolv = "/";
    348 }
    349 if (strcmp(lastcomp, ".") == 0 || strcmp(lastcomp, "..") == 0) {
    350 lastcomp = NULL;
    351 toresolv = copy;
    352 }
    353 else if (tmp)
    354 tmp[0] = '\0';
    355 }
    356 if (realpath(toresolv, buf) == NULL) {
    357 fprintf(stderr, "%s: bad mount point %s: %s\n", progname, orig,
    358 strerror(errno));
    359 free(copy);
    360 return NULL;
    361 }
    362 if (lastcomp == NULL)
    363 dst = strdup(buf);
    364 else {
    365 dst = (char *) malloc(strlen(buf) + 1 + strlen(lastcomp) + 1);
    366 if (dst) {
    367 unsigned buflen = strlen(buf);
    368 if (buflen && buf[buflen-1] == '/')
    369 sprintf(dst, "%s%s", buf, lastcomp);
    370 else
    371 sprintf(dst, "%s/%s", buf, lastcomp);
    372 }
    373 }
    374 free(copy);
    375 if (dst == NULL)
    376 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    377 return dst;
    378}
    379
    380int fuse_mnt_check_fuseblk(void)
    381{
    382 char buf[256];
    383 FILE *f = fopen("/proc/filesystems", "r");
    384 if (!f)
    385 return 1;
    386
    387 while (fgets(buf, sizeof(buf), f))
    388 if (strstr(buf, "fuseblk\n")) {
    389 fclose(f);
    390 return 1;
    391 }
    392
    393 fclose(f);
    394 return 0;
    395}
    396
    397int fuse_mnt_parse_fuse_fd(const char *mountpoint)
    398{
    399 int fd = -1;
    400 int len = 0;
    401
    402 if (mountpoint == NULL) {
    403 fprintf(stderr, "Invalid null-ptr mount-point!\n");
    404 return -1;
    405 }
    406
    407 if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 &&
    408 len == strlen(mountpoint)) {
    409 return fd;
    410 }
    411
    412 return -1;
    413}
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    fuse-3.18.3/doc/html/mount__util_8h_source.html0000644000175000017500000001315115250106404020430 0ustar berndbernd 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 LGPL2.txt.
    7*/
    8
    9#include <sys/types.h>
    10
    11int fuse_mnt_add_mount(const char *progname, const char *fsname,
    12 const char *mnt, const char *type, const char *opts);
    13int fuse_mnt_remove_mount(const char *progname, const char *mnt);
    14int fuse_mnt_umount(const char *progname, const char *abs_mnt,
    15 const char *rel_mnt, int lazy);
    16char *fuse_mnt_resolve_path(const char *progname, const char *orig);
    17int fuse_mnt_check_fuseblk(void);
    18int fuse_mnt_parse_fuse_fd(const char *mountpoint);
    fuse-3.18.3/doc/html/usdt_8h_source.html0000644000175000017500000027334115250106404017062 0ustar berndbernd libfuse: lib/usdt.h Source File
    libfuse
    usdt.h
    1/*
    2 * Copied from https://github.com/libbpf/usdt/
    3 */
    4
    5// SPDX-License-Identifier: BSD-2-Clause
    6/*
    7 * This single-header library defines a collection of variadic macros for
    8 * defining and triggering USDTs (User Statically-Defined Tracepoints):
    9 *
    10 * - For USDTs without associated semaphore:
    11 * USDT(group, name, args...)
    12 *
    13 * - For USDTs with implicit (transparent to the user) semaphore:
    14 * USDT_WITH_SEMA(group, name, args...)
    15 * USDT_IS_ACTIVE(group, name)
    16 *
    17 * - For USDTs with explicit (user-defined and provided) semaphore:
    18 * USDT_WITH_EXPLICIT_SEMA(sema, group, name, args...)
    19 * USDT_SEMA_IS_ACTIVE(sema)
    20 *
    21 * all of which emit a NOP instruction into the instruction stream, and so
    22 * have *zero* overhead for the surrounding code. USDTs are identified by
    23 * a combination of `group` and `name` identifiers, which is used by external
    24 * tracing tooling (tracers) for identifying exact USDTs of interest.
    25 *
    26 * USDTs can have an associated (2-byte) activity counter (USDT semaphore),
    27 * automatically maintained by Linux kernel whenever any correctly written
    28 * BPF-based tracer is attached to the USDT. This USDT semaphore can be used
    29 * to check whether there is a need to do any extra data collection and
    30 * processing for a given USDT (if necessary), and otherwise avoid extra work
    31 * for a common case of USDT not being traced ("active").
    32 *
    33 * See documentation for USDT_WITH_SEMA()/USDT_IS_ACTIVE() or
    34 * USDT_WITH_EXPLICIT_SEMA()/USDT_SEMA_IS_ACTIVE() APIs below for details on
    35 * working with USDTs with implicitly or explicitly associated
    36 * USDT semaphores, respectively.
    37 *
    38 * There is also some additional data recorded into an auxiliary note
    39 * section. The data in the note section describes the operands, in terms of
    40 * size and location, used by tracing tooling to know where to find USDT
    41 * arguments. Each location is encoded as an assembler operand string.
    42 * Tracing tools (bpftrace and BPF-based tracers, systemtap, etc) insert
    43 * breakpoints on top of the nop, and decode the location operand-strings,
    44 * like an assembler, to find the values being passed.
    45 *
    46 * The operand strings are selected by the compiler for each operand.
    47 * They are constrained by inline-assembler codes.The default is:
    48 *
    49 * #define USDT_ARG_CONSTRAINT nor
    50 *
    51 * This is a good default if the operands tend to be integral and
    52 * moderate in number (smaller than number of registers). In other
    53 * cases, the compiler may report "'asm' requires impossible reload" or
    54 * similar. In this case, consider simplifying the macro call (fewer
    55 * and simpler operands), reduce optimization, or override the default
    56 * constraints string via:
    57 *
    58 * #define USDT_ARG_CONSTRAINT g
    59 * #include <usdt.h>
    60 *
    61 * For some historical description of USDT v3 format (the one used by this
    62 * library and generally recognized and assumed by BPF-based tracing tools)
    63 * see [0]. The more formal specification can be found at [1]. Additional
    64 * argument constraints information can be found at [2].
    65 *
    66 * Original SystemTap's sys/sdt.h implementation ([3]) was used as a base for
    67 * this USDT library implementation. Current implementation differs *a lot* in
    68 * terms of exposed user API and general usability, which was the main goal
    69 * and focus of the reimplementation work. Nevertheless, underlying recorded
    70 * USDT definitions are fully binary compatible and any USDT-based tooling
    71 * should work equally well with USDTs defined by either SystemTap's or this
    72 * library's USDT implementation.
    73 *
    74 * [0] https://ecos.sourceware.org/ml/systemtap/2010-q3/msg00145.html
    75 * [1] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
    76 * [2] https://gcc.gnu.org/onlinedocs/gcc/Constraints.html
    77 * [3] https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h
    78 */
    79#ifndef __USDT_H
    80#define __USDT_H
    81
    82/*
    83 * Changelog:
    84 *
    85 * 0.1.0
    86 * -----
    87 * - Initial release
    88 */
    89#define USDT_MAJOR_VERSION 0
    90#define USDT_MINOR_VERSION 1
    91#define USDT_PATCH_VERSION 0
    92
    93/* C++20 and C23 added __VA_OPT__ as a standard replacement for non-standard `##__VA_ARGS__` extension */
    94#if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) || (defined(__cplusplus) && __cplusplus > 201703L)
    95#define __usdt_va_opt 1
    96#define __usdt_va_args(...) __VA_OPT__(,) __VA_ARGS__
    97#else
    98#define __usdt_va_args(...) , ##__VA_ARGS__
    99#endif
    100
    101/*
    102 * Trigger USDT with `group`:`name` identifier and pass through `args` as its
    103 * arguments. Zero arguments are acceptable as well. No USDT semaphore is
    104 * associated with this USDT.
    105 *
    106 * Such "semaphoreless" USDTs are commonly used when there is no extra data
    107 * collection or processing needed to collect and prepare USDT arguments and
    108 * they are just available in the surrounding code. USDT() macro will just
    109 * record their locations in CPU registers or in memory for tracing tooling to
    110 * be able to access them, if necessary.
    111 */
    112#ifdef __usdt_va_opt
    113#define USDT(group, name, ...) \
    114 __usdt_probe(group, name, __usdt_sema_none, 0 __VA_OPT__(,) __VA_ARGS__)
    115#else
    116#define USDT(group, name, ...) \
    117 __usdt_probe(group, name, __usdt_sema_none, 0, ##__VA_ARGS__)
    118#endif
    119
    120/*
    121 * Trigger USDT with `group`:`name` identifier and pass through `args` as its
    122 * arguments. Zero arguments are acceptable as well. USDT also get an
    123 * implicitly-defined associated USDT semaphore, which will be "activated" by
    124 * tracing tooling and can be used to check whether USDT is being actively
    125 * observed.
    126 *
    127 * USDTs with semaphore are commonly used when there is a need to perform
    128 * additional data collection and processing to prepare USDT arguments, which
    129 * otherwise might not be necessary for the rest of application logic. In such
    130 * case, USDT semaphore can be used to avoid unnecessary extra work. If USDT
    131 * is not traced (which is presumed to be a common situation), the associated
    132 * USDT semaphore is "inactive", and so there is no need to waste resources to
    133 * prepare USDT arguments. Use USDT_IS_ACTIVE(group, name) to check whether
    134 * USDT is "active".
    135 *
    136 * N.B. There is an inherent (albeit short) gap between checking whether USDT
    137 * is active and triggering corresponding USDT, in which external tracer can
    138 * be attached to an USDT and activate USDT semaphore after the activity check.
    139 * If such a race occurs, tracers might miss one USDT execution. Tracers are
    140 * expected to accommodate such possibility and this is expected to not be
    141 * a problem for applications and tracers.
    142 *
    143 * N.B. Implicit USDT semaphore defined by USDT_WITH_SEMA() is contained
    144 * within a single executable or shared library and is not shared outside
    145 * them. I.e., if you use USDT_WITH_SEMA() with the same USDT group and name
    146 * identifier across executable and shared library, it will work and won't
    147 * conflict, per se, but will define independent USDT semaphores, one for each
    148 * shared library/executable in which USDT_WITH_SEMA(group, name) is used.
    149 * That is, if you attach to this USDT in one shared library (or executable),
    150 * then only USDT semaphore within that shared library (or executable) will be
    151 * updated by the kernel, while other libraries (or executable) will not see
    152 * activated USDT semaphore. In short, it's best to use unique USDT group:name
    153 * identifiers across different shared libraries (and, equivalently, between
    154 * executable and shared library). This is advanced consideration and is
    155 * rarely (if ever) seen in practice, but just to avoid surprises this is
    156 * called out here. (Static libraries become a part of final executable, once
    157 * linked by linker, so the above considerations don't apply to them.)
    158 */
    159#ifdef __usdt_va_opt
    160#define USDT_WITH_SEMA(group, name, ...) \
    161 __usdt_probe(group, name, \
    162 __usdt_sema_implicit, __usdt_sema_name(group, name) \
    163 __VA_OPT__(,) __VA_ARGS__)
    164#else
    165#define USDT_WITH_SEMA(group, name, ...) \
    166 __usdt_probe(group, name, \
    167 __usdt_sema_implicit, __usdt_sema_name(group, name), \
    168 ##__VA_ARGS__)
    169#endif
    170
    171struct usdt_sema { volatile unsigned short active; };
    172
    173/*
    174 * Check if USDT with `group`:`name` identifier is "active" (i.e., whether it
    175 * is attached to by external tracing tooling and is actively observed).
    176 *
    177 * This macro can be used to decide whether any additional and potentially
    178 * expensive data collection or processing should be done to pass extra
    179 * information into the given USDT. It is assumed that USDT is triggered with
    180 * USDT_WITH_SEMA() macro which will implicitly define associated USDT
    181 * semaphore. (If one needs more control over USDT semaphore, see
    182 * USDT_DEFINE_SEMA() and USDT_WITH_EXPLICIT_SEMA() macros below.)
    183 *
    184 * N.B. Such checks are necessarily racy and speculative. Between checking
    185 * whether USDT is active and triggering the USDT itself, tracer can be
    186 * detached with no notification. This race should be extremely rare and worst
    187 * case should result in one-time wasted extra data collection and processing.
    188 */
    189#define USDT_IS_ACTIVE(group, name) ({ \
    190 extern struct usdt_sema __usdt_sema_name(group, name) \
    191 __usdt_asm_name(__usdt_sema_name(group, name)); \
    192 __usdt_sema_implicit(__usdt_sema_name(group, name)); \
    193 __usdt_sema_name(group, name).active > 0; \
    194})
    195
    196/*
    197 * APIs for working with user-defined explicit USDT semaphores.
    198 *
    199 * This is a less commonly used advanced API for use cases in which user needs
    200 * an explicit control over (potentially shared across multiple USDTs) USDT
    201 * semaphore instance. This can be used when there is a group of logically
    202 * related USDTs that all need extra data collection and processing whenever
    203 * any of a family of related USDTs are "activated" (i.e., traced). In such
    204 * a case, all such related USDTs will be associated with the same shared USDT
    205 * semaphore defined with USDT_DEFINE_SEMA() and the USDTs themselves will be
    206 * triggered with USDT_WITH_EXPLICIT_SEMA() macros, taking an explicit extra
    207 * USDT semaphore identifier as an extra parameter.
    208 */
    209
    215#define USDT_SEMA(sema) __usdt_sema_##sema
    216
    217/*
    218 * Define storage for user-defined USDT semaphore `sema`.
    219 *
    220 * Should be used only once in non-header source file to let compiler allocate
    221 * space for the semaphore variable. Just like with any other global variable.
    222 *
    223 * This macro can be used anywhere where global variable declaration is
    224 * allowed. Just like with global variable definitions, there should be only
    225 * one definition of user-defined USDT semaphore with given `sema` identifier,
    226 * otherwise compiler or linker will complain about duplicate variable
    227 * definition.
    228 *
    229 * For C++, it is allowed to use USDT_DEFINE_SEMA() both in global namespace
    230 * and inside namespaces (including nested namespaces). Just make sure that
    231 * USDT_DECLARE_SEMA() is placed within the namespace where this semaphore is
    232 * referenced, or any of its parent namespaces, so the C++ language-level
    233 * identifier is visible to the code that needs to reference the semaphore.
    234 * At the lowest layer, USDT semaphores have global naming and visibility
    235 * (they have a corresponding `__usdt_sema_<name>` symbol, which can be linked
    236 * against from C or C++ code, if necessary). To keep it simple, putting
    237 * USDT_DECLARE_SEMA() declarations into global namespaces is the simplest
    238 * no-brainer solution. All these aspects are irrelevant for plain C, because
    239 * C doesn't have namespaces and everything is always in the global namespace.
    240 *
    241 * N.B. Due to USDT metadata being recorded in non-allocatable ELF note
    242 * section, it has limitations when it comes to relocations, which, in
    243 * practice, means that it's not possible to correctly share USDT semaphores
    244 * between main executable and shared libraries, or even between multiple
    245 * shared libraries. USDT semaphore has to be contained to individual shared
    246 * library or executable to avoid unpleasant surprises with half-working USDT
    247 * semaphores. We enforce this by marking semaphore ELF symbols as having
    248 * a hidden visibility. This is quite an advanced use case and consideration
    249 * and for most users this should have no consequences whatsoever.
    250 */
    251#define USDT_DEFINE_SEMA(sema) \
    252 struct usdt_sema __usdt_sema_sec USDT_SEMA(sema) \
    253 __usdt_asm_name(USDT_SEMA(sema)) \
    254 __attribute__((visibility("hidden"))) = { 0 }
    255
    256/*
    257 * Declare extern reference to user-defined USDT semaphore `sema`.
    258 *
    259 * Refers to a variable defined in another compilation unit by
    260 * USDT_DEFINE_SEMA() and allows to use the same USDT semaphore across
    261 * multiple compilation units (i.e., .c and .cpp files).
    262 *
    263 * See USDT_DEFINE_SEMA() notes above for C++ language usage peculiarities.
    264 */
    265#define USDT_DECLARE_SEMA(sema) \
    266 extern struct usdt_sema USDT_SEMA(sema) __usdt_asm_name(USDT_SEMA(sema))
    267
    268/*
    269 * Check if user-defined USDT semaphore `sema` is "active" (i.e., whether it
    270 * is attached to by external tracing tooling and is actively observed).
    271 *
    272 * This macro can be used to decide whether any additional and potentially
    273 * expensive data collection or processing should be done to pass extra
    274 * information into USDT(s) associated with USDT semaphore `sema`.
    275 *
    276 * N.B. Such checks are necessarily racy. Between checking the state of USDT
    277 * semaphore and triggering associated USDT(s), the active tracer might attach
    278 * or detach. This race should be extremely rare and worst case should result
    279 * in one-time missed USDT event or wasted extra data collection and
    280 * processing. USDT-using tracers should be written with this in mind and is
    281 * not a concern of the application defining USDTs with associated semaphore.
    282 */
    283#define USDT_SEMA_IS_ACTIVE(sema) (USDT_SEMA(sema).active > 0)
    284
    285/*
    286 * Invoke USDT specified by `group` and `name` identifiers and associate
    287 * explicitly user-defined semaphore `sema` with it. Pass through `args` as
    288 * USDT arguments. `args` are optional and zero arguments are acceptable.
    289 *
    290 * Semaphore is defined with the help of USDT_DEFINE_SEMA() macro and can be
    291 * checked whether active with USDT_SEMA_IS_ACTIVE().
    292 */
    293#ifdef __usdt_va_opt
    294#define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \
    295 __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema), ##__VA_ARGS__)
    296#else
    297#define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \
    298 __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema) __VA_OPT__(,) __VA_ARGS__)
    299#endif
    300
    301/*
    302 * Adjustable implementation aspects
    303 */
    304#ifndef USDT_ARG_CONSTRAINT
    305#if defined __powerpc__
    306#define USDT_ARG_CONSTRAINT nZr
    307#elif defined __arm__
    308#define USDT_ARG_CONSTRAINT g
    309#elif defined __loongarch__
    310#define USDT_ARG_CONSTRAINT nmr
    311#else
    312#define USDT_ARG_CONSTRAINT nor
    313#endif
    314#endif /* USDT_ARG_CONSTRAINT */
    315
    316#ifndef USDT_NOP
    317#if defined(__ia64__) || defined(__s390__) || defined(__s390x__)
    318#define USDT_NOP nop 0
    319#else
    320#define USDT_NOP nop
    321#endif
    322#endif /* USDT_NOP */
    323
    324/*
    325 * Implementation details
    326 */
    327/* USDT name for implicitly-defined USDT semaphore, derived from group:name */
    328#define __usdt_sema_name(group, name) __usdt_sema_##group##__##name
    329/* ELF section into which USDT semaphores are put */
    330#define __usdt_sema_sec __attribute__((section(".probes")))
    331
    332#define __usdt_concat(a, b) a ## b
    333#define __usdt_apply(fn, n) __usdt_concat(fn, n)
    334
    335#ifndef __usdt_nth
    336#define __usdt_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
    337#endif
    338
    339#ifndef __usdt_narg
    340#ifdef __usdt_va_opt
    341#define __usdt_narg(...) __usdt_nth(_ __VA_OPT__(,) __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    342#else
    343#define __usdt_narg(...) __usdt_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    344#endif
    345#endif /* __usdt_narg */
    346
    347#define __usdt_hash #
    348#define __usdt_str_(x) #x
    349#define __usdt_str(x) __usdt_str_(x)
    350
    351#ifndef __usdt_asm_name
    352#define __usdt_asm_name(name) __asm__(__usdt_str(name))
    353#endif
    354
    355#define __usdt_asm1(a) __usdt_str(a) "\n"
    356#define __usdt_asm2(a,b) __usdt_str(a) "," __usdt_str(b) "\n"
    357#define __usdt_asm3(a,b,c) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "\n"
    358#define __usdt_asm5(a,b,c,d,e) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "," \
    359 __usdt_str(d) "," __usdt_str(e) "\n"
    360
    361#ifdef __LP64__
    362#define __usdt_asm_addr .8byte
    363#else
    364#define __usdt_asm_addr .4byte
    365#endif
    366
    367#define __usdt_asm_strz_(x) __usdt_asm1(.asciz #x)
    368#define __usdt_asm_strz(x) __usdt_asm_strz_(x)
    369#define __usdt_asm_str_(x) __usdt_asm1(.ascii #x)
    370#define __usdt_asm_str(x) __usdt_asm_str_(x)
    371
    372/* "semaphoreless" USDT case */
    373#ifndef __usdt_sema_none
    374#define __usdt_sema_none(sema)
    375#endif
    376
    377/* implicitly defined __usdt_sema__group__name semaphore (using weak symbols) */
    378#ifndef __usdt_sema_implicit
    379#define __usdt_sema_implicit(sema) \
    380 __asm__ __volatile__ ( \
    381 __usdt_asm1(.ifndef sema) \
    382 __usdt_asm3( .pushsection .probes, "aw", "progbits") \
    383 __usdt_asm1( .weak sema) \
    384 __usdt_asm1( .hidden sema) \
    385 __usdt_asm1( .align 2) \
    386 __usdt_asm1(sema:) \
    387 __usdt_asm1( .zero 2) \
    388 __usdt_asm2( .type sema, @object) \
    389 __usdt_asm2( .size sema, 2) \
    390 __usdt_asm1( .popsection) \
    391 __usdt_asm1(.endif) \
    392 );
    393#endif
    394
    395/* externally defined semaphore using USDT_DEFINE_SEMA() and passed explicitly by user */
    396#ifndef __usdt_sema_explicit
    397#define __usdt_sema_explicit(sema) \
    398 __asm__ __volatile__ ("" :: "m" (sema));
    399#endif
    400
    401/* main USDT definition (nop and .note.stapsdt metadata) */
    402#define __usdt_probe(group, name, sema_def, sema, ...) do { \
    403 sema_def(sema) \
    404 __asm__ __volatile__ ( \
    405 __usdt_asm1(990: USDT_NOP) \
    406 __usdt_asm3( .pushsection .note.stapsdt, "", "note") \
    407 __usdt_asm1( .balign 4) \
    408 __usdt_asm3( .4byte 992f-991f,994f-993f,3) \
    409 __usdt_asm1(991: .asciz "stapsdt") \
    410 __usdt_asm1(992: .balign 4) \
    411 __usdt_asm1(993: __usdt_asm_addr 990b) \
    412 __usdt_asm1( __usdt_asm_addr _.stapsdt.base) \
    413 __usdt_asm1( __usdt_asm_addr sema) \
    414 __usdt_asm_strz(group) \
    415 __usdt_asm_strz(name) \
    416 __usdt_asm_args(__VA_ARGS__) \
    417 __usdt_asm1( .ascii "\0") \
    418 __usdt_asm1(994: .balign 4) \
    419 __usdt_asm1( .popsection) \
    420 __usdt_asm1(.ifndef _.stapsdt.base) \
    421 __usdt_asm5( .pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat)\
    422 __usdt_asm1( .weak _.stapsdt.base) \
    423 __usdt_asm1( .hidden _.stapsdt.base) \
    424 __usdt_asm1(_.stapsdt.base:) \
    425 __usdt_asm1( .space 1) \
    426 __usdt_asm2( .size _.stapsdt.base, 1) \
    427 __usdt_asm1( .popsection) \
    428 __usdt_asm1(.endif) \
    429 :: __usdt_asm_ops(__VA_ARGS__) \
    430 ); \
    431} while (0)
    432
    433/*
    434 * NB: gdb PR24541 highlighted an unspecified corner of the sdt.h
    435 * operand note format.
    436 *
    437 * The named register may be a longer or shorter (!) alias for the
    438 * storage where the value in question is found. For example, on
    439 * i386, 64-bit value may be put in register pairs, and a register
    440 * name stored would identify just one of them. Previously, gcc was
    441 * asked to emit the %w[id] (16-bit alias of some registers holding
    442 * operands), even when a wider 32-bit value was used.
    443 *
    444 * Bottom line: the byte-width given before the @ sign governs. If
    445 * there is a mismatch between that width and that of the named
    446 * register, then a sys/sdt.h note consumer may need to employ
    447 * architecture-specific heuristics to figure out where the compiler
    448 * has actually put the complete value.
    449 */
    450#if defined(__powerpc__) || defined(__powerpc64__)
    451#define __usdt_argref(id) %I[id]%[id]
    452#elif defined(__i386__)
    453#define __usdt_argref(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */
    454#else
    455#define __usdt_argref(id) %[id]
    456#endif
    457
    458#define __usdt_asm_arg(n) __usdt_asm_str(%c[__usdt_asz##n]) \
    459 __usdt_asm1(.ascii "@") \
    460 __usdt_asm_str(__usdt_argref(__usdt_aval##n))
    461
    462#define __usdt_asm_args0 /* no arguments */
    463#define __usdt_asm_args1 __usdt_asm_arg(1)
    464#define __usdt_asm_args2 __usdt_asm_args1 __usdt_asm1(.ascii " ") __usdt_asm_arg(2)
    465#define __usdt_asm_args3 __usdt_asm_args2 __usdt_asm1(.ascii " ") __usdt_asm_arg(3)
    466#define __usdt_asm_args4 __usdt_asm_args3 __usdt_asm1(.ascii " ") __usdt_asm_arg(4)
    467#define __usdt_asm_args5 __usdt_asm_args4 __usdt_asm1(.ascii " ") __usdt_asm_arg(5)
    468#define __usdt_asm_args6 __usdt_asm_args5 __usdt_asm1(.ascii " ") __usdt_asm_arg(6)
    469#define __usdt_asm_args7 __usdt_asm_args6 __usdt_asm1(.ascii " ") __usdt_asm_arg(7)
    470#define __usdt_asm_args8 __usdt_asm_args7 __usdt_asm1(.ascii " ") __usdt_asm_arg(8)
    471#define __usdt_asm_args9 __usdt_asm_args8 __usdt_asm1(.ascii " ") __usdt_asm_arg(9)
    472#define __usdt_asm_args10 __usdt_asm_args9 __usdt_asm1(.ascii " ") __usdt_asm_arg(10)
    473#define __usdt_asm_args11 __usdt_asm_args10 __usdt_asm1(.ascii " ") __usdt_asm_arg(11)
    474#define __usdt_asm_args12 __usdt_asm_args11 __usdt_asm1(.ascii " ") __usdt_asm_arg(12)
    475#define __usdt_asm_args(...) __usdt_apply(__usdt_asm_args, __usdt_narg(__VA_ARGS__))
    476
    477#define __usdt_is_arr(x) (__builtin_classify_type(x) == 14 || __builtin_classify_type(x) == 5)
    478#define __usdt_arg_size(x) (__usdt_is_arr(x) ? sizeof(void *) : sizeof(x))
    479
    480/*
    481 * We can't use __builtin_choose_expr() in C++, so fall back to table-based
    482 * signedness determination for known types, utilizing templates magic.
    483 */
    484#ifdef __cplusplus
    485
    486#define __usdt_is_signed(x) (!__usdt_is_arr(x) && __usdt_t<__typeof(x)>::is_signed)
    487
    488#include <cstddef>
    489
    490template<typename T> struct __usdt_t { static const bool is_signed = false; };
    491template<typename A> struct __usdt_t<A[]> : public __usdt_t<A *> {};
    492template<typename A, size_t N> struct __usdt_t<A[N]> : public __usdt_t<A *> {};
    493
    494#define __usdt_def_signed(T) \
    495template<> struct __usdt_t<T> { static const bool is_signed = true; }; \
    496template<> struct __usdt_t<const T> { static const bool is_signed = true; }; \
    497template<> struct __usdt_t<volatile T> { static const bool is_signed = true; }; \
    498template<> struct __usdt_t<const volatile T> { static const bool is_signed = true; }
    499#define __usdt_maybe_signed(T) \
    500template<> struct __usdt_t<T> { static const bool is_signed = (T)-1 < (T)1; }; \
    501template<> struct __usdt_t<const T> { static const bool is_signed = (T)-1 < (T)1; }; \
    502template<> struct __usdt_t<volatile T> { static const bool is_signed = (T)-1 < (T)1; }; \
    503template<> struct __usdt_t<const volatile T> { static const bool is_signed = (T)-1 < (T)1; }
    504
    505__usdt_def_signed(signed char);
    506__usdt_def_signed(short);
    507__usdt_def_signed(int);
    508__usdt_def_signed(long);
    509__usdt_def_signed(long long);
    510__usdt_maybe_signed(char);
    511__usdt_maybe_signed(wchar_t);
    512
    513#else /* !__cplusplus */
    514
    515#define __usdt_is_inttype(x) (__builtin_classify_type(x) >= 1 && __builtin_classify_type(x) <= 4)
    516#define __usdt_inttype(x) __typeof(__builtin_choose_expr(__usdt_is_inttype(x), (x), 0U))
    517#define __usdt_is_signed(x) ((__usdt_inttype(x))-1 < (__usdt_inttype(x))1)
    518
    519#endif /* __cplusplus */
    520
    521#define __usdt_asm_op(n, x) \
    522 [__usdt_asz##n] "n" ((__usdt_is_signed(x) ? (int)-1 : 1) * (int)__usdt_arg_size(x)), \
    523 [__usdt_aval##n] __usdt_str(USDT_ARG_CONSTRAINT)(x)
    524
    525#define __usdt_asm_ops0() [__usdt_dummy] "g" (0)
    526#define __usdt_asm_ops1(x) __usdt_asm_op(1, x)
    527#define __usdt_asm_ops2(a,x) __usdt_asm_ops1(a), __usdt_asm_op(2, x)
    528#define __usdt_asm_ops3(a,b,x) __usdt_asm_ops2(a,b), __usdt_asm_op(3, x)
    529#define __usdt_asm_ops4(a,b,c,x) __usdt_asm_ops3(a,b,c), __usdt_asm_op(4, x)
    530#define __usdt_asm_ops5(a,b,c,d,x) __usdt_asm_ops4(a,b,c,d), __usdt_asm_op(5, x)
    531#define __usdt_asm_ops6(a,b,c,d,e,x) __usdt_asm_ops5(a,b,c,d,e), __usdt_asm_op(6, x)
    532#define __usdt_asm_ops7(a,b,c,d,e,f,x) __usdt_asm_ops6(a,b,c,d,e,f), __usdt_asm_op(7, x)
    533#define __usdt_asm_ops8(a,b,c,d,e,f,g,x) __usdt_asm_ops7(a,b,c,d,e,f,g), __usdt_asm_op(8, x)
    534#define __usdt_asm_ops9(a,b,c,d,e,f,g,h,x) __usdt_asm_ops8(a,b,c,d,e,f,g,h), __usdt_asm_op(9, x)
    535#define __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,x) __usdt_asm_ops9(a,b,c,d,e,f,g,h,i), __usdt_asm_op(10, x)
    536#define __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,x) __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,j), __usdt_asm_op(11, x)
    537#define __usdt_asm_ops12(a,b,c,d,e,f,g,h,i,j,k,x) __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,k), __usdt_asm_op(12, x)
    538#define __usdt_asm_ops(...) __usdt_apply(__usdt_asm_ops, __usdt_narg(__VA_ARGS__))(__VA_ARGS__)
    539
    540#endif /* __USDT_H */
    fuse-3.18.3/doc/html/util_8c_source.html0000644000175000017500000002225415250106404017046 0ustar berndbernd libfuse: lib/util.c Source File
    libfuse
    util.c
    1
    2#include "fuse_config.h"
    3
    4#ifdef HAVE_PTHREAD_SETNAME_NP
    5#define _GNU_SOURCE
    6#include <pthread.h>
    7#endif
    8
    9#include <errno.h>
    10#include <stdlib.h>
    11#include <errno.h>
    12
    13#ifndef FUSE_USE_VERSION
    14#define FUSE_USE_VERSION (FUSE_MAKE_VERSION(3, 18))
    15#endif
    16
    17#include "util.h"
    18#include "fuse_log.h"
    19#include "fuse_lowlevel.h"
    20#include <stdio.h>
    21
    22int libfuse_strtol(const char *str, long *res)
    23{
    24 char *endptr;
    25 int base = 10;
    26 long val;
    27
    28 errno = 0;
    29
    30 if (!str)
    31 return -EINVAL;
    32
    33 val = strtol(str, &endptr, base);
    34
    35 if (errno)
    36 return -errno;
    37
    38 if (endptr == str || *endptr != '\0')
    39 return -EINVAL;
    40
    41 *res = val;
    42 return 0;
    43}
    44
    45void fuse_set_thread_name(const char *name)
    46{
    47#ifdef HAVE_PTHREAD_SETNAME_NP
    48 pthread_setname_np(pthread_self(), name);
    49#else
    50 (void)name;
    51#endif
    52}
    53
    fuse-3.18.3/doc/html/util_8h_source.html0000644000175000017500000002063115250106404017050 0ustar berndbernd libfuse: lib/util.h Source File
    libfuse
    util.h
    1#ifndef FUSE_UTIL_H_
    2#define FUSE_UTIL_H_
    3
    4#include <stdint.h>
    5#include <stdbool.h>
    6
    7#define ROUND_UP(val, round_to) (((val) + (round_to - 1)) & ~(round_to - 1))
    8
    9#define likely(x) __builtin_expect(!!(x), 1)
    10#define unlikely(x) __builtin_expect(!!(x), 0)
    11
    12struct fuse_conn_info;
    13
    14int libfuse_strtol(const char *str, long *res);
    15void fuse_set_thread_name(const char *name);
    16
    20static inline uint32_t fuse_lower_32_bits(uint64_t nr)
    21{
    22 return (uint32_t)(nr & 0xffffffff);
    23}
    24
    28static inline uint64_t fuse_higher_32_bits(uint64_t nr)
    29{
    30 return nr & ~0xffffffffULL;
    31}
    32
    33#ifndef FUSE_VAR_UNUSED
    34#define FUSE_VAR_UNUSED __attribute__((__unused__))
    35#endif
    36
    37#define container_of(ptr, type, member) \
    38 ({ \
    39 unsigned long __mptr = (unsigned long)(ptr); \
    40 ((type *)(__mptr - offsetof(type, member))); \
    41 })
    42
    43#if __has_attribute(__fallthrough__)
    44#define fallthrough __attribute__((__fallthrough__))
    45#else
    46#define fallthrough do {} while (0)
    47#endif
    48
    49#endif /* FUSE_UTIL_H_ */
    fuse-3.18.3/doc/html/readdir__inode_8c_source.html0000644000175000017500000002463315250106404021023 0ustar berndbernd libfuse: test/readdir_inode.c Source File
    libfuse
    readdir_inode.c
    1/*
    2 * Prints each directory entry, its inode and d_type as returned by 'readdir'.
    3 * Skips '.' and '..' because readdir is not required to return them and
    4 * some of our examples don't. However if they are returned, their d_type
    5 * should be valid.
    6 */
    7
    8#include <stdio.h>
    9#include <string.h>
    10#include <sys/types.h>
    11#include <dirent.h>
    12#include <errno.h>
    13
    14int main(int argc, char* argv[])
    15{
    16 DIR* dirp;
    17 struct dirent* dent;
    18
    19 if (argc != 2) {
    20 fprintf(stderr, "Usage: readdir_inode dir\n");
    21 return 1;
    22 }
    23
    24 dirp = opendir(argv[1]);
    25 if (dirp == NULL) {
    26 perror("failed to open directory");
    27 return 2;
    28 }
    29
    30 errno = 0;
    31 dent = readdir(dirp);
    32 while (dent != NULL) {
    33 if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
    34 printf("%llu %d %s\n", (unsigned long long)dent->d_ino,
    35 (int)dent->d_type, dent->d_name);
    36 if ((long long)dent->d_ino < 0)
    37 fprintf(stderr,"%s : bad d_ino %llu\n",
    38 dent->d_name, (unsigned long long)dent->d_ino);
    39 if ((dent->d_type < 1) || (dent->d_type > 15))
    40 fprintf(stderr,"%s : bad d_type %d\n",
    41 dent->d_name, (int)dent->d_type);
    42 } else {
    43 if (dent->d_type != DT_DIR)
    44 fprintf(stderr,"%s : bad d_type %d\n",
    45 dent->d_name, (int)dent->d_type);
    46 }
    47 dent = readdir(dirp);
    48 }
    49 if (errno != 0) {
    50 perror("failed to read directory entry");
    51 return 3;
    52 }
    53
    54 closedir(dirp);
    55
    56 return 0;
    57}
    fuse-3.18.3/doc/html/release__unlink__race_8c_source.html0000644000175000017500000005230215250106404022356 0ustar berndbernd libfuse: test/release_unlink_race.c Source File
    libfuse
    release_unlink_race.c
    1/*
    2 This program can be distributed under the terms of the GNU GPLv2.
    3 See the file GPL2.txt.
    4*/
    5
    6#define FUSE_USE_VERSION 31
    7
    8#define _GNU_SOURCE
    9
    10#include <fuse.h>
    11
    12#include <stdio.h>
    13#include <stdlib.h>
    14#include <unistd.h>
    15#include <errno.h>
    16
    17static void *xmp_init(struct fuse_conn_info *conn,
    18 struct fuse_config *cfg)
    19{
    20 (void) conn;
    21
    22 cfg->use_ino = 1;
    23 cfg->nullpath_ok = 1;
    24 cfg->entry_timeout = 0;
    25 cfg->attr_timeout = 0;
    26 cfg->negative_timeout = 0;
    27
    28 return NULL;
    29}
    30
    31static int xmp_getattr(const char *path, struct stat *stbuf,
    32 struct fuse_file_info *fi)
    33{
    34 int res;
    35
    36 (void) path;
    37
    38 if(fi)
    39 res = fstat(fi->fh, stbuf);
    40 else
    41 res = lstat(path, stbuf);
    42 if (res == -1)
    43 return -errno;
    44
    45 return 0;
    46}
    47
    48static int xmp_unlink(const char *path)
    49{
    50 int res;
    51
    52 res = unlink(path);
    53 if (res == -1)
    54 return -errno;
    55
    56 return 0;
    57}
    58
    59static int xmp_rename(const char *from, const char *to, unsigned int flags)
    60{
    61 int res;
    62
    63 if (flags)
    64 return -EINVAL;
    65
    66 if(!getenv("RELEASEUNLINKRACE_DELAY_DISABLE")) usleep(100000);
    67
    68 res = rename(from, to);
    69 if (res == -1)
    70 return -errno;
    71
    72 return 0;
    73}
    74
    75static int xmp_create(const char *path, mode_t mode, struct fuse_file_info *fi)
    76{
    77 int fd;
    78
    79 fd = open(path, fi->flags, mode);
    80 if (fd == -1)
    81 return -errno;
    82
    83 fi->fh = fd;
    84 return 0;
    85}
    86
    87static int xmp_release(const char *path, struct fuse_file_info *fi)
    88{
    89 (void) path;
    90
    91 if(!getenv("RELEASEUNLINKRACE_DELAY_DISABLE")) usleep(100000);
    92
    93 close(fi->fh);
    94
    95 return 0;
    96}
    97
    98static const struct fuse_operations xmp_oper = {
    99 .init = xmp_init,
    100 .getattr = xmp_getattr,
    101 .unlink = xmp_unlink,
    102 .rename = xmp_rename,
    103 .create = xmp_create,
    104 .release = xmp_release,
    105};
    106
    107int main(int argc, char *argv[])
    108{
    109 umask(0);
    110 return fuse_main(argc, argv, &xmp_oper, NULL);
    111}
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    fuse-3.18.3/doc/html/stracedecode_8c_source.html0000644000175000017500000010554115250106404020517 0ustar berndbernd libfuse: test/stracedecode.c Source File
    libfuse
    stracedecode.c
    1#include <stdio.h>
    2#include <string.h>
    3#include "fuse_kernel.h"
    4
    5static 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_TMPFILE] = { "TMPFILE" },
    42 [FUSE_INTERRUPT] = { "INTERRUPT" },
    43 [FUSE_BMAP] = { "BMAP" },
    44 [FUSE_DESTROY] = { "DESTROY" },
    45 [FUSE_READDIRPLUS] = { "READDIRPLUS" },
    46};
    47
    48#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
    49
    50static const char *opname(enum fuse_opcode opcode)
    51{
    52 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
    53 return "???";
    54 else
    55 return fuse_ll_ops[opcode].name;
    56}
    57
    58
    59static void process_buf(int dir, char *buf, int len)
    60{
    61 static unsigned long long prevuniq = -1;
    62 static int prevopcode;
    63
    64 if (!dir) {
    65 struct fuse_in_header *in = (struct fuse_in_header *) buf;
    66 buf += sizeof(struct fuse_in_header);
    67
    68 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n",
    69 (unsigned long long) in->unique,
    70 opname((enum fuse_opcode) in->opcode), in->opcode,
    71 (unsigned long) in->nodeid, in->len, len);
    72
    73 switch (in->opcode) {
    74 case FUSE_READ: {
    75 struct fuse_read_in *arg = (struct fuse_read_in *) buf;
    76 printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n",
    77 arg->fh, arg->offset, arg->size, arg->read_flags,
    78 arg->lock_owner, arg->flags);
    79 break;
    80 }
    81 case FUSE_WRITE: {
    82 struct fuse_write_in *arg = (struct fuse_write_in *) buf;
    83 printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n",
    84 arg->fh, arg->offset, arg->size, arg->write_flags,
    85 arg->lock_owner, arg->flags);
    86 break;
    87 }
    88 }
    89 prevuniq = in->unique;
    90 prevopcode = in->opcode;
    91 } else {
    92 struct fuse_out_header *out = (struct fuse_out_header *) buf;
    93 buf += sizeof(struct fuse_out_header);
    94
    95 printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n",
    96 (unsigned long long) out->unique, out->error,
    97 strerror(-out->error), out->len, len);
    98
    99 if (out->unique == prevuniq) {
    100 switch (prevopcode) {
    101 case FUSE_GETATTR: {
    102 struct fuse_attr_out *arg = (struct fuse_attr_out *) buf;
    103 printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n",
    104 arg->attr_valid, arg->attr_valid_nsec,
    105 arg->attr.ino, arg->attr.size, arg->attr.blocks);
    106 break;
    107 }
    108 case FUSE_LOOKUP: {
    109 struct fuse_entry_out *arg = (struct fuse_entry_out *) buf;
    110 printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n",
    111 arg->nodeid, arg->attr_valid, arg->attr_valid_nsec,
    112 arg->attr.ino, arg->attr.size, arg->attr.blocks);
    113 break;
    114 }
    115 }
    116 }
    117 }
    118
    119}
    120
    121int main(void)
    122{
    123 FILE *in = stdin;
    124 while (1) {
    125 int dir;
    126 int res;
    127 char buf[1048576];
    128 unsigned len = 0;
    129
    130 memset(buf, 0, sizeof(buf));
    131 while (1) {
    132 char str[32];
    133
    134 res = fscanf(in, "%30s", str);
    135 if (res != 1 && feof(in))
    136 return 0;
    137
    138 if (res == 0)
    139 continue;
    140
    141 if (strncmp(str, "read(", 5) == 0) {
    142 dir = 0;
    143 break;
    144 } else if (strncmp(str, "writev(", 7) == 0) {
    145 dir = 1;
    146 break;
    147 }
    148 }
    149
    150 while (1) {
    151 int c = getc(in);
    152 if (c == '"') {
    153 while (1) {
    154 int val;
    155
    156 c = getc(in);
    157 if (c == EOF) {
    158 fprintf(stderr, "eof in string\n");
    159 break;
    160 }
    161 if (c == '\n') {
    162 fprintf(stderr, "eol in string\n");
    163 break;
    164 }
    165 if (c == '"')
    166 break;
    167 if (c != '\\') {
    168 val = c;
    169 } else {
    170 c = getc(in);
    171 switch (c) {
    172 case 'n': val = '\n'; break;
    173 case 'r': val = '\r'; break;
    174 case 't': val = '\t'; break;
    175 case '"': val = '"'; break;
    176 case '\\': val = '\\'; break;
    177 case 'x':
    178 res = scanf("%x", &val);
    179 if (res != 1) {
    180 fprintf(stderr, "parse error\n");
    181 continue;
    182 }
    183 break;
    184 default:
    185 fprintf(stderr, "unknown sequence: '\\%c'\n", c);
    186 continue;
    187 }
    188 }
    189 buf[len++] = val;
    190 }
    191 }
    192 if (c == '\n')
    193 break;
    194 }
    195 process_buf(dir, buf, len);
    196 memset(buf, 0, len);
    197 len = 0;
    198 }
    199}
    fuse-3.18.3/doc/html/test__abi_8c_source.html0000644000175000017500000001244215250106404020020 0ustar berndbernd libfuse: test/test_abi.c Source File
    libfuse
    test_abi.c
    1#define FUSE_USE_VERSION 30
    2
    3#include "fuse.h"
    4
    5#include <stdio.h>
    6#include <stdlib.h>
    7
    8int main(void)
    9{
    10 if (sizeof(struct fuse_file_info) != 64) {
    11 fprintf(stderr, "struct fuse_file_info size mismatch\n");
    12 exit(1);
    13 }
    14 if (sizeof(struct fuse_conn_info) != 128) {
    15 fprintf(stderr, "struct fuse_conn_info size mismatch\n");
    16 exit(1);
    17 }
    18}
    fuse-3.18.3/doc/html/test__api__30_8c_source.html0000644000175000017500000014451515250106404020506 0ustar berndbernd libfuse: test/test_api_30.c Source File
    libfuse
    test_api_30.c
    1/*
    2 * FUSE: Filesystem in Userspace
    3 *
    4 * Minimal low level filesystem built against the FUSE_USE_VERSION 30 API,
    5 * so that the old API keeps being compiled and exercised.
    6 *
    7 * This program can be distributed under the terms of the GNU GPLv2.
    8 * See the file GPL2.txt.
    9 */
    10
    11#define FUSE_USE_VERSION 30
    12
    13/* the high level header has to keep building at this version as well */
    14#include <fuse.h>
    15
    16#include <fuse_config.h>
    17#include <fuse_lowlevel.h>
    18#include <assert.h>
    19#include <dirent.h>
    20#include <errno.h>
    21#include <fcntl.h>
    22#include <pthread.h>
    23#include <signal.h>
    24#include <stdio.h>
    25#include <stdlib.h>
    26#include <string.h>
    27#include <unistd.h>
    28
    29#ifndef __linux__
    30#include <limits.h>
    31#else
    32#include <linux/limits.h>
    33#endif
    34
    35#define FILE_INO 2
    36
    37static const char file_name[] = "hello";
    38static const char file_contents[] = "Hello World!\n";
    39
    40static int tfs_stat(fuse_ino_t ino, struct stat *stbuf)
    41{
    42 stbuf->st_ino = ino;
    43 switch (ino) {
    44 case FUSE_ROOT_ID:
    45 stbuf->st_mode = S_IFDIR | 0755;
    46 stbuf->st_nlink = 2;
    47 break;
    48
    49 case FILE_INO:
    50 stbuf->st_mode = S_IFREG | 0444;
    51 stbuf->st_nlink = 1;
    52 stbuf->st_size = strlen(file_contents);
    53 break;
    54
    55 default:
    56 return -1;
    57 }
    58 return 0;
    59}
    60
    61static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    62{
    63 struct fuse_entry_param e;
    64
    65 if (parent != FUSE_ROOT_ID || strcmp(name, file_name) != 0) {
    66 fuse_reply_err(req, ENOENT);
    67 return;
    68 }
    69
    70 memset(&e, 0, sizeof(e));
    71 e.ino = FILE_INO;
    72 e.attr_timeout = 1.0;
    73 e.entry_timeout = 1.0;
    74 tfs_stat(e.ino, &e.attr);
    75
    76 fuse_reply_entry(req, &e);
    77}
    78
    79static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    80 struct fuse_file_info *fi)
    81{
    82 struct stat stbuf;
    83
    84 (void) fi;
    85
    86 memset(&stbuf, 0, sizeof(stbuf));
    87 if (tfs_stat(ino, &stbuf) == -1)
    88 fuse_reply_err(req, ENOENT);
    89 else
    90 fuse_reply_attr(req, &stbuf, 1.0);
    91}
    92
    93struct dirbuf {
    94 char *p;
    95 size_t size;
    96};
    97
    98static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    99 fuse_ino_t ino)
    100{
    101 struct stat stbuf;
    102 size_t oldsize = b->size;
    103
    104 b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    105 b->p = realloc(b->p, b->size);
    106 assert(b->p != NULL);
    107
    108 memset(&stbuf, 0, sizeof(stbuf));
    109 stbuf.st_ino = ino;
    110 fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    111 b->size);
    112}
    113
    114static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    115 off_t off, size_t maxsize)
    116{
    117 size_t offset = (size_t) off;
    118
    119 if (off < 0 || offset >= bufsize)
    120 return fuse_reply_buf(req, NULL, 0);
    121
    122 if (bufsize - offset < maxsize)
    123 maxsize = bufsize - offset;
    124
    125 return fuse_reply_buf(req, buf + offset, maxsize);
    126}
    127
    128static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    129 off_t off, struct fuse_file_info *fi)
    130{
    131 struct dirbuf b;
    132
    133 (void) fi;
    134
    135 if (ino != FUSE_ROOT_ID) {
    136 fuse_reply_err(req, ENOTDIR);
    137 return;
    138 }
    139
    140 memset(&b, 0, sizeof(b));
    141 dirbuf_add(req, &b, ".", FUSE_ROOT_ID);
    142 dirbuf_add(req, &b, "..", FUSE_ROOT_ID);
    143 dirbuf_add(req, &b, file_name, FILE_INO);
    144 reply_buf_limited(req, b.p, b.size, off, size);
    145 free(b.p);
    146}
    147
    148static void tfs_open(fuse_req_t req, fuse_ino_t ino,
    149 struct fuse_file_info *fi)
    150{
    151 if (ino != FILE_INO)
    152 fuse_reply_err(req, EISDIR);
    153 else if ((fi->flags & O_ACCMODE) != O_RDONLY)
    154 fuse_reply_err(req, EACCES);
    155 else
    156 fuse_reply_open(req, fi);
    157}
    158
    159static void tfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
    160 struct fuse_file_info *fi)
    161{
    162 (void) fi;
    163
    164 assert(ino == FILE_INO);
    165 reply_buf_limited(req, file_contents, strlen(file_contents), off, size);
    166}
    167
    168static const struct fuse_lowlevel_ops tfs_oper = {
    169 .lookup = tfs_lookup,
    170 .getattr = tfs_getattr,
    171 .readdir = tfs_readdir,
    172 .open = tfs_open,
    173 .read = tfs_read,
    174};
    175
    176static void *run_fs(void *data)
    177{
    178 struct fuse_session *se = (struct fuse_session *)data;
    179
    180 assert(fuse_session_loop(se) == 0);
    181 return NULL;
    182}
    183
    184static void check_readdir(const char *mountpoint)
    185{
    186 DIR *dir = opendir(mountpoint);
    187 const struct dirent *ent;
    188 int found = 0;
    189
    190 assert(dir != NULL);
    191 while ((ent = readdir(dir)) != NULL) {
    192 if (strcmp(ent->d_name, file_name) == 0)
    193 found = 1;
    194 }
    195 assert(closedir(dir) == 0);
    196 assert(found == 1);
    197}
    198
    199static void check_read(const char *mountpoint)
    200{
    201 char path[PATH_MAX];
    202 char buf[sizeof(file_contents)];
    203 int fd;
    204 ssize_t len;
    205
    206 assert(snprintf(path, PATH_MAX, "%s/%s", mountpoint, file_name) > 0);
    207 fd = open(path, O_RDONLY);
    208 if (fd == -1) {
    209 perror(path);
    210 assert(0);
    211 }
    212
    213 len = read(fd, buf, sizeof(buf));
    214 assert(len == (ssize_t) strlen(file_contents));
    215 assert(memcmp(buf, file_contents, len) == 0);
    216 assert(close(fd) == 0);
    217}
    218
    219int main(int argc, char *argv[])
    220{
    221 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    222 struct fuse_session *se;
    223 struct fuse_cmdline_opts fuse_opts;
    224 pthread_t fs_thread;
    225
    226 assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
    227#ifndef __FreeBSD__
    228 assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0);
    229#endif
    230 se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL);
    231 assert(se != NULL);
    232 assert(fuse_set_signal_handlers(se) == 0);
    233 assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0);
    234
    235 assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0);
    236
    237 check_readdir(fuse_opts.mountpoint);
    238 check_read(fuse_opts.mountpoint);
    239
    240 /*
    241 * fuse_session_exit() does not interrupt read(), so nudge this thread
    242 * with the ignored signal to let the loop free its receive buffer.
    243 */
    245 assert(pthread_kill(fs_thread, SIGPIPE) == 0);
    246 assert(pthread_join(fs_thread, NULL) == 0);
    247
    251 free(fuse_opts.mountpoint);
    252 fuse_opt_free_args(&args);
    253
    254 printf("Test completed successfully.\n");
    255 return 0;
    256}
    int fuse_set_signal_handlers(struct fuse_session *se)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    fuse_ino_t ino
    fuse-3.18.3/doc/html/test__setattr_8c_source.html0000644000175000017500000011363015250106404020754 0ustar berndbernd 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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    9
    10#define FUSE_USE_VERSION 30
    11
    12/* Not really needed - just to test build with FUSE_USE_VERSION == 30 */
    13#include <fuse.h>
    14
    15#include <fuse_config.h>
    16#include <fuse_lowlevel.h>
    17#include <stdio.h>
    18#include <stdlib.h>
    19#include <string.h>
    20#include <errno.h>
    21#include <fcntl.h>
    22#include <assert.h>
    23#include <stddef.h>
    24#include <unistd.h>
    25#include <pthread.h>
    26
    27#ifndef __linux__
    28#include <limits.h>
    29#else
    30#include <linux/limits.h>
    31#endif
    32
    33#define FILE_INO 2
    34#define FILE_NAME "truncate_me"
    35
    36static int got_fh;
    37static mode_t file_mode = S_IFREG | 0644;
    38
    39static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) {
    40 stbuf->st_ino = ino;
    41 if (ino == FUSE_ROOT_ID) {
    42 stbuf->st_mode = S_IFDIR | 0755;
    43 stbuf->st_nlink = 1;
    44 }
    45
    46 else if (ino == FILE_INO) {
    47 stbuf->st_mode = file_mode;
    48 stbuf->st_nlink = 1;
    49 stbuf->st_size = 0;
    50 }
    51
    52 else
    53 return -1;
    54
    55 return 0;
    56}
    57
    58static void tfs_lookup(fuse_req_t req, fuse_ino_t parent,
    59 const char *name) {
    60 struct fuse_entry_param e;
    61 memset(&e, 0, sizeof(e));
    62
    63 if (parent != FUSE_ROOT_ID)
    64 goto err_out;
    65 else if (strcmp(name, FILE_NAME) == 0)
    66 e.ino = FILE_INO;
    67 else
    68 goto err_out;
    69
    70 if (tfs_stat(e.ino, &e.attr) != 0)
    71 goto err_out;
    72 fuse_reply_entry(req, &e);
    73 return;
    74
    75err_out:
    76 fuse_reply_err(req, ENOENT);
    77}
    78
    79static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    80 struct fuse_file_info *fi) {
    81 struct stat stbuf;
    82
    83 (void) fi;
    84
    85 memset(&stbuf, 0, sizeof(stbuf));
    86 if (tfs_stat(ino, &stbuf) != 0)
    87 fuse_reply_err(req, ENOENT);
    88 else
    89 fuse_reply_attr(req, &stbuf, 5);
    90}
    91
    92static void tfs_open(fuse_req_t req, fuse_ino_t ino,
    93 struct fuse_file_info *fi) {
    94 if (ino == FUSE_ROOT_ID)
    95 fuse_reply_err(req, EISDIR);
    96 else {
    97 assert(ino == FILE_INO);
    98 fi->fh = FILE_INO;
    99 fuse_reply_open(req, fi);
    100 }
    101}
    102
    103static void tfs_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr,
    104 int to_set, struct fuse_file_info *fi) {
    105 if(ino != FILE_INO ||
    106 !(to_set & FUSE_SET_ATTR_MODE)) {
    107 fuse_reply_err(req, EINVAL);
    108 return;
    109 }
    110
    111 if(fi == NULL)
    112 fprintf(stderr, "setattr with fi == NULL\n");
    113 else if (fi->fh != FILE_INO)
    114 fprintf(stderr, "setattr with wrong fi->fh\n");
    115 else {
    116 fprintf(stderr, "setattr ok\n");
    117 got_fh = 1;
    118 file_mode = attr->st_mode;
    119 }
    120
    121 tfs_getattr(req, ino, fi);
    122}
    123
    124static struct fuse_lowlevel_ops tfs_oper = {
    125 .lookup = tfs_lookup,
    126 .getattr = tfs_getattr,
    127 .open = tfs_open,
    128 .setattr = tfs_setattr,
    129};
    130
    131static void* run_fs(void *data) {
    132 struct fuse_session *se = (struct fuse_session*) data;
    133 assert(fuse_session_loop(se) == 0);
    134 return NULL;
    135}
    136
    137static void test_fs(char *mountpoint) {
    138 char fname[PATH_MAX];
    139 int fd;
    140
    141 assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME,
    142 mountpoint) > 0);
    143 fd = open(fname, O_WRONLY);
    144 if (fd == -1) {
    145 perror(fname);
    146 assert(0);
    147 }
    148
    149 assert(fchmod(fd, 0600) == 0);
    150 close(fd);
    151}
    152
    153int main(int argc, char *argv[]) {
    154 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    155 struct fuse_session *se;
    156 struct fuse_cmdline_opts fuse_opts;
    157 pthread_t fs_thread;
    158
    159 assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
    160#ifndef __FreeBSD__
    161 assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0);
    162#endif
    163 se = fuse_session_new(&args, &tfs_oper,
    164 sizeof(tfs_oper), NULL);
    165 assert (se != NULL);
    166 assert(fuse_set_signal_handlers(se) == 0);
    167 assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0);
    168
    169 /* Start file-system thread */
    170 assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0);
    171
    172 /* Do test */
    173 test_fs(fuse_opts.mountpoint);
    174
    175 /* Stop file system */
    176 assert(pthread_cancel(fs_thread) == 0);
    177
    179 assert(got_fh == 1);
    182
    183 printf("Test completed successfully.\n");
    184 return 0;
    185}
    186
    187
    int fuse_set_signal_handlers(struct fuse_session *se)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    uint64_t fuse_ino_t
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    fuse_ino_t ino
    fuse-3.18.3/doc/html/test__signals_8c_source.html0000644000175000017500000011174515250106404020733 0ustar berndbernd libfuse: test/test_signals.c Source File
    libfuse
    test_signals.c
    1/*
    2 * FUSE: Filesystem in Userspace
    3 * Copyright (C) 2025 Bernd Schubert <bernd@bsbernd.com>
    4 *
    5 * Test for signal handling in libfuse.
    6 *
    7 * This program can be distributed under the terms of the GNU LGPLv2.
    8 * See the file GPL2.txt
    9 */
    10
    11#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
    12
    13#include "fuse_config.h"
    14#include "fuse_lowlevel.h"
    15#include "fuse_i.h"
    16
    17#include <pthread.h>
    18#include <stdatomic.h>
    19#include <stdio.h>
    20#include <stdlib.h>
    21#include <string.h>
    22#include <unistd.h>
    23#include <signal.h>
    24#include <errno.h>
    25#include <sys/types.h>
    26#include <sys/wait.h>
    27
    28static void test_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    29{
    30 (void)parent;
    31 (void)name;
    32 /* Simulate slow lookup to test signal interruption */
    33 sleep(2);
    34 fuse_reply_err(req, ENOENT);
    35}
    36
    37static void test_ll_getattr(fuse_req_t req, fuse_ino_t ino,
    38 struct fuse_file_info *fi)
    39{
    40 (void)ino;
    41 (void)fi;
    42 /* Simulate slow getattr to test signal interruption */
    43 sleep(2);
    44 fuse_reply_err(req, ENOENT);
    45}
    46
    47static const struct fuse_lowlevel_ops test_ll_ops = {
    48 .lookup = test_ll_lookup,
    49 .getattr = test_ll_getattr,
    50};
    51
    52static void *signal_sender_thread(void *arg)
    53{
    54 (void)arg;
    55
    56 usleep(2 * 1000 * 1000);
    57
    58 /* Send SIGTERM to the process */
    59 kill(getpid(), SIGTERM);
    60 return NULL;
    61}
    62
    63static void fork_child(void)
    64{
    65 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
    66 struct fuse_session *se;
    67 struct fuse_loop_config *loop_config;
    68 pthread_t sig_thread;
    69 char *mountpoint = NULL;
    70 int ret = -1;
    71
    72 /* Add the program name to arg[0] */
    73 if (fuse_opt_add_arg(&args, "test_signals")) {
    74 fprintf(stderr, "Failed to add argument\n");
    75 goto out_free_mountpoint;
    76 }
    77
    78 /* Add debug flag to see more output */
    79 fuse_opt_add_arg(&args, "-d");
    80
    81 /* Create temporary mount point */
    82 mountpoint = strdup("/tmp/fuse_test_XXXXXX");
    83 if (!mountpoint || !mkdtemp(mountpoint)) {
    84 fprintf(stderr, "Failed to create temp dir\n");
    85 goto out_free_args;
    86 }
    87
    88 /* Create session */
    89 se = fuse_session_new(&args, &test_ll_ops, sizeof(test_ll_ops), NULL);
    90 if (!se) {
    91 fprintf(stderr, "Failed to create FUSE session\n");
    92 goto out_free_mountpoint;
    93 }
    94
    95 /* Mount filesystem */
    96 if (fuse_session_mount(se, mountpoint)) {
    97 fprintf(stderr, "Failed to mount FUSE filesystem\n");
    98 goto out_destroy_session;
    99 }
    100
    101 /* Create loop config */
    102 loop_config = fuse_loop_cfg_create();
    103 if (!loop_config) {
    104 fprintf(stderr, "Failed to create loop config\n");
    105 goto out_unmount;
    106 }
    107 fuse_loop_cfg_set_clone_fd(loop_config, 0);
    108 fuse_loop_cfg_set_max_threads(loop_config, 2);
    109
    110 /* Set up signal handlers */
    111 if (fuse_set_signal_handlers(se)) {
    112 fprintf(stderr, "Failed to set up signal handlers\n");
    113 goto out_destroy_config;
    114 }
    115
    116 /* Create thread that will send signals */
    117 if (pthread_create(&sig_thread, NULL, signal_sender_thread, NULL)) {
    118 fprintf(stderr, "Failed to create signal sender thread\n");
    119 goto out_remove_handlers;
    120 }
    121
    122 /* Enter FUSE loop */
    123 ret = fuse_session_loop_mt_312(se, loop_config);
    124
    125 printf("Debug: fuse_session_loop_mt_312 returned %d\n", ret);
    126 printf("Debug: session exited state: %d\n", fuse_session_exited(se));
    127 printf("Debug: session status: %d\n", se->error);
    128
    129 /* Check exit status before cleanup */
    130 int clean_exit = (fuse_session_exited(se) && se->error == SIGTERM);
    131
    132 /* Clean up */
    133 pthread_join(sig_thread, NULL);
    137 fuse_loop_cfg_destroy(loop_config);
    138 rmdir(mountpoint);
    139 free(mountpoint);
    140 fuse_opt_free_args(&args);
    141
    142 /* Use saved exit status */
    143 if (clean_exit) {
    144 printf("Debug: Clean shutdown via SIGTERM\n");
    145 exit(0);
    146 }
    147 printf("Debug: Exiting with status %d\n", ret != 0);
    148 exit(ret != 0);
    149
    150out_remove_handlers:
    152out_destroy_config:
    153 fuse_loop_cfg_destroy(loop_config);
    154out_unmount:
    156out_destroy_session:
    158out_free_mountpoint:
    159 rmdir(mountpoint);
    160 free(mountpoint);
    161out_free_args:
    162 fuse_opt_free_args(&args);
    163 exit(1);
    164}
    165
    166static void run_test_in_child(void)
    167{
    168 pid_t child;
    169 int status;
    170
    171 child = fork();
    172 if (child == -1) {
    173 perror("fork");
    174 exit(1);
    175 }
    176
    177 if (child == 0)
    178 fork_child();
    179
    180 /* In parent process */
    181 if (waitpid(child, &status, 0) == -1) {
    182 perror("waitpid");
    183 exit(1);
    184 }
    185
    186 /* Check if child exited due to SIGTERM - this is expected */
    187 if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) {
    188 printf("Child process terminated by SIGTERM as expected\n");
    189 exit(0);
    190 }
    191
    192 /* For any other type of exit, maintain existing behavior */
    193 exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1);
    194}
    195
    196int main(void)
    197{
    198 printf("Testing SIGTERM handling in libfuse\n");
    199 run_test_in_child();
    200 printf("SIGTERM handling test passed\n");
    201 return 0;
    202}
    int fuse_set_signal_handlers(struct fuse_session *se)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    struct fuse_req * fuse_req_t
    int fuse_session_exited(struct fuse_session *se)
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    uint64_t fuse_ino_t
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    fuse-3.18.3/doc/html/test__syscalls_8c_source.html0000644000175000017500000116654315250106404021137 0ustar berndbernd libfuse: test/test_syscalls.c Source File
    libfuse
    test_syscalls.c
    1#define _GNU_SOURCE
    2#include "fuse_config.h"
    3
    4#include <stdio.h>
    5#include <stdlib.h>
    6#include <stdarg.h>
    7#include <string.h>
    8#include <unistd.h>
    9#include <fcntl.h>
    10#include <dirent.h>
    11#include <utime.h>
    12#include <errno.h>
    13#include <assert.h>
    14#include <time.h>
    15#include <sys/socket.h>
    16#include <sys/types.h>
    17#include <sys/stat.h>
    18#include <sys/un.h>
    19
    20#ifndef ALLPERMS
    21# define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)/* 07777 */
    22#endif
    23
    24
    25static const char *basepath;
    26static const char *basepath_r;
    27static char testfile[1024];
    28static char testfile2[1024];
    29static char testdir[1024];
    30static char testdir2[1024];
    31static char testsock[1024];
    32static char subfile[1280];
    33
    34static char testfile_r[1024];
    35static char testfile2_r[1024];
    36static char testdir_r[1024];
    37static char testdir2_r[1024];
    38static char subfile_r[1280];
    39
    40static char testname[256];
    41static char testdata[] = "abcdefghijklmnopqrstuvwxyz";
    42static char testdata2[] = "1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./";
    43static const char *testdir_files[] = { "f1", "f2", NULL};
    44static long seekdir_offsets[4];
    45static char zerodata[4096];
    46static int testdatalen = sizeof(testdata) - 1;
    47static int testdata2len = sizeof(testdata2) - 1;
    48static unsigned int testnum = 0;
    49static unsigned int select_test = 0;
    50static unsigned int skip_test = 0;
    51static unsigned int unlinked_test = 0;
    52
    53#define MAX_ENTRIES 1024
    54#define MAX_TESTS 100
    55
    56static struct test {
    57 int fd;
    58 struct stat stat;
    59} tests[MAX_TESTS];
    60
    61static void test_perror(const char *func, const char *msg)
    62{
    63 fprintf(stderr, "%s %s() - %s: %s\n", testname, func, msg,
    64 strerror(errno));
    65}
    66
    67static void test_error(const char *func, const char *msg, ...)
    68 __attribute__ ((format (printf, 2, 3)));
    69
    70static void __start_test(const char *fmt, ...)
    71 __attribute__ ((format (printf, 1, 2)));
    72
    73static void test_error(const char *func, const char *msg, ...)
    74{
    75 va_list ap;
    76 fprintf(stderr, "%s %s() - ", testname, func);
    77 va_start(ap, msg);
    78 vfprintf(stderr, msg, ap);
    79 va_end(ap);
    80 fprintf(stderr, "\n");
    81}
    82
    83static int is_dot_or_dotdot(const char *name) {
    84 return name[0] == '.' &&
    85 (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
    86}
    87
    88/*
    89 * Seconds since the first line this process printed. The origin is taken
    90 * lazily so it needs no init call and cannot precede the first test.
    91 */
    92static double test_elapsed(void)
    93{
    94 static struct timespec start;
    95 struct timespec now;
    96
    97 clock_gettime(CLOCK_MONOTONIC, &now);
    98 if (start.tv_sec == 0 && start.tv_nsec == 0)
    99 start = now;
    100 return (now.tv_sec - start.tv_sec) +
    101 (now.tv_nsec - start.tv_nsec) / 1e9;
    102}
    103
    104static void success(void)
    105{
    106 fprintf(stderr, "+%8.3fs %s OK\n", test_elapsed(), testname);
    107}
    108
    109#define this_test (&tests[testnum-1])
    110#define next_test (&tests[testnum])
    111
    112static void __start_test(const char *fmt, ...)
    113{
    114 unsigned int n;
    115 va_list ap;
    116 n = sprintf(testname, "%3i [", testnum);
    117 va_start(ap, fmt);
    118 n += vsprintf(testname + n, fmt, ap);
    119 va_end(ap);
    120 sprintf(testname + n, "]");
    121 // Use dedicated testfile per test
    122 sprintf(testfile, "%s/testfile.%d", basepath, testnum);
    123 sprintf(testfile_r, "%s/testfile.%d", basepath_r, testnum);
    124 if (testnum > MAX_TESTS) {
    125 fprintf(stderr, "%s - too many tests\n", testname);
    126 exit(1);
    127 }
    128 /* A test that never finishes prints nothing otherwise, leaving the log
    129 * ending at the last test that passed. stderr, so a SIGKILL cannot
    130 * swallow it.
    131 */
    132 fprintf(stderr, "+%8.3fs %s START\n", test_elapsed(), testname);
    133 this_test->fd = -1;
    134}
    135
    136#define start_test(msg, args...) { \
    137 testnum++; \
    138 if ((select_test && testnum != select_test) || \
    139 (testnum == skip_test)) { \
    140 return 0; \
    141 } \
    142 __start_test(msg, ##args); \
    143}
    144
    145#define PERROR(msg) test_perror(__FUNCTION__, msg)
    146#define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args)
    147
    148#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
    149
    150static int st_check_size(struct stat *st, int len)
    151{
    152 if (st->st_size != len) {
    153 ERROR("length %u instead of %u", (int) st->st_size,
    154 (int) len);
    155 return -1;
    156 }
    157 return 0;
    158}
    159
    160static int check_size(const char *path, int len)
    161{
    162 struct stat stbuf;
    163 int res = stat(path, &stbuf);
    164 if (res == -1) {
    165 PERROR("stat");
    166 return -1;
    167 }
    168 return st_check_size(&stbuf, len);
    169}
    170
    171static int check_testfile_size(const char *path, int len)
    172{
    173 this_test->stat.st_size = len;
    174 return check_size(path, len);
    175}
    176
    177static int st_check_type(struct stat *st, mode_t type)
    178{
    179 if ((st->st_mode & S_IFMT) != type) {
    180 ERROR("type 0%o instead of 0%o", st->st_mode & S_IFMT, type);
    181 return -1;
    182 }
    183 return 0;
    184}
    185
    186static int check_type(const char *path, mode_t type)
    187{
    188 struct stat stbuf;
    189 int res = lstat(path, &stbuf);
    190 if (res == -1) {
    191 PERROR("lstat");
    192 return -1;
    193 }
    194 return st_check_type(&stbuf, type);
    195}
    196
    197static int st_check_mode(struct stat *st, mode_t mode)
    198{
    199 if ((st->st_mode & ALLPERMS) != mode) {
    200 ERROR("mode 0%o instead of 0%o", st->st_mode & ALLPERMS,
    201 mode);
    202 return -1;
    203 }
    204 return 0;
    205}
    206
    207static int check_mode(const char *path, mode_t mode)
    208{
    209 struct stat stbuf;
    210 int res = lstat(path, &stbuf);
    211 if (res == -1) {
    212 PERROR("lstat");
    213 return -1;
    214 }
    215 return st_check_mode(&stbuf, mode);
    216}
    217
    218static int check_testfile_mode(const char *path, mode_t mode)
    219{
    220 this_test->stat.st_mode &= ~ALLPERMS;
    221 this_test->stat.st_mode |= mode;
    222 return check_mode(path, mode);
    223}
    224
    225static int check_times(const char *path, time_t atime, time_t mtime)
    226{
    227 int err = 0;
    228 struct stat stbuf;
    229 int res = lstat(path, &stbuf);
    230 if (res == -1) {
    231 PERROR("lstat");
    232 return -1;
    233 }
    234 if (stbuf.st_atime != atime) {
    235 ERROR("atime %li instead of %li", stbuf.st_atime, atime);
    236 err--;
    237 }
    238 if (stbuf.st_mtime != mtime) {
    239 ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
    240 err--;
    241 }
    242 if (err)
    243 return -1;
    244
    245 return 0;
    246}
    247
    248#if 0
    249static int fcheck_times(int fd, time_t atime, time_t mtime)
    250{
    251 int err = 0;
    252 struct stat stbuf;
    253 int res = fstat(fd, &stbuf);
    254 if (res == -1) {
    255 PERROR("fstat");
    256 return -1;
    257 }
    258 if (stbuf.st_atime != atime) {
    259 ERROR("atime %li instead of %li", stbuf.st_atime, atime);
    260 err--;
    261 }
    262 if (stbuf.st_mtime != mtime) {
    263 ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
    264 err--;
    265 }
    266 if (err)
    267 return -1;
    268
    269 return 0;
    270}
    271#endif
    272
    273static int st_check_nlink(struct stat *st, nlink_t nlink)
    274{
    275 if (st->st_nlink != nlink) {
    276 ERROR("nlink %li instead of %li", (long) st->st_nlink,
    277 (long) nlink);
    278 return -1;
    279 }
    280 return 0;
    281}
    282
    283static int check_nlink(const char *path, nlink_t nlink)
    284{
    285 struct stat stbuf;
    286 int res = lstat(path, &stbuf);
    287 if (res == -1) {
    288 PERROR("lstat");
    289 return -1;
    290 }
    291 return st_check_nlink(&stbuf, nlink);
    292}
    293
    294static int fcheck_stat(int fd, int flags, struct stat *st)
    295{
    296 struct stat stbuf;
    297 int res = fstat(fd, &stbuf);
    298 if (res == -1) {
    299 if (flags & O_PATH) {
    300 // With O_PATH fd, the server does not have to keep
    301 // the inode alive so FUSE inode may be stale or bad
    302 if (errno == ESTALE || errno == EIO ||
    303 errno == ENOENT || errno == EBADF)
    304 return 0;
    305 }
    306 PERROR("fstat");
    307 return -1;
    308 }
    309
    310 int err = 0;
    311 err += st_check_type(&stbuf, st->st_mode & S_IFMT);
    312 err += st_check_mode(&stbuf, st->st_mode & ALLPERMS);
    313 err += st_check_size(&stbuf, st->st_size);
    314 err += st_check_nlink(&stbuf, st->st_nlink);
    315
    316 return err;
    317}
    318
    319static int check_nonexist(const char *path)
    320{
    321 struct stat stbuf;
    322 int res = lstat(path, &stbuf);
    323 if (res == 0) {
    324 ERROR("file should not exist");
    325 return -1;
    326 }
    327 if (errno != ENOENT) {
    328 ERROR("file should not exist: %s", strerror(errno));
    329 return -1;
    330 }
    331 return 0;
    332}
    333
    334static int check_buffer(const char *buf, const char *data, unsigned len)
    335{
    336 if (memcmp(buf, data, len) != 0) {
    337 ERROR("data mismatch");
    338 return -1;
    339 }
    340 return 0;
    341}
    342
    343static int check_data(const char *path, const char *data, int offset,
    344 unsigned len)
    345{
    346 char buf[4096];
    347 int res;
    348 int fd = open(path, O_RDONLY);
    349 if (fd == -1) {
    350 PERROR("open");
    351 return -1;
    352 }
    353 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
    354 PERROR("lseek");
    355 close(fd);
    356 return -1;
    357 }
    358 while (len) {
    359 int rdlen = len < sizeof(buf) ? len : sizeof(buf);
    360 res = read(fd, buf, rdlen);
    361 if (res == -1) {
    362 PERROR("read");
    363 close(fd);
    364 return -1;
    365 }
    366 if (res != rdlen) {
    367 ERROR("short read: %u instead of %u", res, rdlen);
    368 close(fd);
    369 return -1;
    370 }
    371 if (check_buffer(buf, data, rdlen) != 0) {
    372 close(fd);
    373 return -1;
    374 }
    375 data += rdlen;
    376 len -= rdlen;
    377 }
    378 res = close(fd);
    379 if (res == -1) {
    380 PERROR("close");
    381 return -1;
    382 }
    383 return 0;
    384}
    385
    386static int fcheck_data(int fd, const char *data, int offset,
    387 unsigned len)
    388{
    389 char buf[4096];
    390 int res;
    391 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
    392 PERROR("lseek");
    393 return -1;
    394 }
    395 while (len) {
    396 int rdlen = len < sizeof(buf) ? len : sizeof(buf);
    397 res = read(fd, buf, rdlen);
    398 if (res == -1) {
    399 PERROR("read");
    400 return -1;
    401 }
    402 if (res != rdlen) {
    403 ERROR("short read: %u instead of %u", res, rdlen);
    404 return -1;
    405 }
    406 if (check_buffer(buf, data, rdlen) != 0) {
    407 return -1;
    408 }
    409 data += rdlen;
    410 len -= rdlen;
    411 }
    412 return 0;
    413}
    414
    415static int check_dir_contents(const char *path, const char **contents)
    416{
    417 int i;
    418 int res;
    419 int err = 0;
    420 int found[MAX_ENTRIES];
    421 const char *cont[MAX_ENTRIES];
    422 DIR *dp;
    423
    424 for (i = 0; contents[i]; i++) {
    425 assert(i < MAX_ENTRIES - 3);
    426 found[i] = 0;
    427 cont[i] = contents[i];
    428 }
    429 cont[i] = NULL;
    430
    431 dp = opendir(path);
    432 if (dp == NULL) {
    433 PERROR("opendir");
    434 return -1;
    435 }
    436 memset(found, 0, sizeof(found));
    437 while(1) {
    438 struct dirent *de;
    439 errno = 0;
    440 de = readdir(dp);
    441 if (de == NULL) {
    442 if (errno) {
    443 PERROR("readdir");
    444 closedir(dp);
    445 return -1;
    446 }
    447 break;
    448 }
    449 if (is_dot_or_dotdot(de->d_name))
    450 continue;
    451 for (i = 0; cont[i] != NULL; i++) {
    452 assert(i < MAX_ENTRIES);
    453 if (strcmp(cont[i], de->d_name) == 0) {
    454 if (found[i]) {
    455 ERROR("duplicate entry <%s>",
    456 de->d_name);
    457 err--;
    458 } else
    459 found[i] = 1;
    460 break;
    461 }
    462 }
    463 if (!cont[i]) {
    464 ERROR("unexpected entry <%s>", de->d_name);
    465 err --;
    466 }
    467 }
    468 for (i = 0; cont[i] != NULL; i++) {
    469 if (!found[i]) {
    470 ERROR("missing entry <%s>", cont[i]);
    471 err--;
    472 }
    473 }
    474 res = closedir(dp);
    475 if (res == -1) {
    476 PERROR("closedir");
    477 return -1;
    478 }
    479 if (err)
    480 return -1;
    481
    482 return 0;
    483}
    484
    485static int create_file(const char *path, const char *data, int len)
    486{
    487 int res;
    488 int fd;
    489
    490 unlink(path);
    491 fd = creat(path, 0644);
    492 if (fd == -1) {
    493 PERROR("creat");
    494 return -1;
    495 }
    496 if (len) {
    497 res = write(fd, data, len);
    498 if (res == -1) {
    499 PERROR("write");
    500 close(fd);
    501 return -1;
    502 }
    503 if (res != len) {
    504 ERROR("write is short: %u instead of %u", res, len);
    505 close(fd);
    506 return -1;
    507 }
    508 }
    509 res = close(fd);
    510 if (res == -1) {
    511 PERROR("close");
    512 return -1;
    513 }
    514 res = check_type(path, S_IFREG);
    515 if (res == -1)
    516 return -1;
    517 res = check_mode(path, 0644);
    518 if (res == -1)
    519 return -1;
    520 res = check_nlink(path, 1);
    521 if (res == -1)
    522 return -1;
    523 res = check_size(path, len);
    524 if (res == -1)
    525 return -1;
    526
    527 if (len) {
    528 res = check_data(path, data, 0, len);
    529 if (res == -1)
    530 return -1;
    531 }
    532
    533 return 0;
    534}
    535
    536static int create_path_fd(const char *path, const char *data, int len)
    537{
    538 int path_fd;
    539 int res;
    540
    541 res = create_file(path, data, len);
    542 if (res == -1)
    543 return -1;
    544
    545 path_fd = open(path, O_PATH);
    546 if (path_fd == -1)
    547 PERROR("open(O_PATH)");
    548
    549 return path_fd;
    550}
    551
    552// Can be called once per test
    553static int create_testfile(const char *path, const char *data, int len)
    554{
    555 struct test *t = this_test;
    556 struct stat *st = &t->stat;
    557 int res, fd;
    558
    559 if (t->fd > 0) {
    560 ERROR("testfile already created");
    561 return -1;
    562 }
    563
    564 fd = create_path_fd(path, data, len);
    565 if (fd == -1)
    566 return -1;
    567
    568 t->fd = fd;
    569
    570 res = fstat(fd, st);
    571 if (res == -1) {
    572 PERROR("fstat");
    573 return -1;
    574 }
    575
    576 return 0;
    577}
    578
    579static int check_unlinked_testfile(int fd)
    580{
    581 struct stat *st = &this_test->stat;
    582
    583 st->st_nlink = 0;
    584 return fcheck_stat(fd, O_PATH, st);
    585}
    586
    587// Check recorded testfiles after all tests completed
    588static int check_unlinked_testfiles(void)
    589{
    590 int fd;
    591 int res, err = 0;
    592 int num = testnum;
    593
    594 if (!unlinked_test)
    595 return 0;
    596
    597 testnum = 0;
    598 while (testnum < num) {
    599 fd = next_test->fd;
    600 start_test("check_unlinked_testfile");
    601 if (fd == -1)
    602 continue;
    603
    604 err += check_unlinked_testfile(fd);
    605 res = close(fd);
    606 if (res == -1) {
    607 PERROR("close(test_fd)");
    608 err--;
    609 }
    610 }
    611
    612 if (err) {
    613 fprintf(stderr, "%i unlinked testfile checks failed\n", -err);
    614 return 1;
    615 }
    616
    617 return err;
    618}
    619
    620static int cleanup_dir(const char *path, const char **dir_files, int quiet)
    621{
    622 int i;
    623 int err = 0;
    624
    625 for (i = 0; dir_files[i]; i++) {
    626 int res;
    627 char fpath[1280];
    628 sprintf(fpath, "%s/%s", path, dir_files[i]);
    629 res = unlink(fpath);
    630 if (res == -1 && !quiet) {
    631 PERROR("unlink");
    632 err --;
    633 }
    634 }
    635 if (err)
    636 return -1;
    637
    638 return 0;
    639}
    640
    641static int create_dir(const char *path, const char **dir_files)
    642{
    643 int res;
    644 int i;
    645
    646 rmdir(path);
    647 res = mkdir(path, 0755);
    648 if (res == -1) {
    649 PERROR("mkdir");
    650 return -1;
    651 }
    652 res = check_type(path, S_IFDIR);
    653 if (res == -1)
    654 return -1;
    655 res = check_mode(path, 0755);
    656 if (res == -1)
    657 return -1;
    658
    659 for (i = 0; dir_files[i]; i++) {
    660 char fpath[1280];
    661 sprintf(fpath, "%s/%s", path, dir_files[i]);
    662 res = create_file(fpath, "", 0);
    663 if (res == -1) {
    664 cleanup_dir(path, dir_files, 1);
    665 return -1;
    666 }
    667 }
    668 res = check_dir_contents(path, dir_files);
    669 if (res == -1) {
    670 cleanup_dir(path, dir_files, 1);
    671 return -1;
    672 }
    673
    674 return 0;
    675}
    676
    677static int test_truncate(int len)
    678{
    679 const char *data = testdata;
    680 int datalen = testdatalen;
    681 int res;
    682
    683 start_test("truncate(%u)", (int) len);
    684 res = create_testfile(testfile, data, datalen);
    685 if (res == -1)
    686 return -1;
    687
    688 res = truncate(testfile, len);
    689 if (res == -1) {
    690 PERROR("truncate");
    691 return -1;
    692 }
    693 res = check_testfile_size(testfile, len);
    694 if (res == -1)
    695 return -1;
    696
    697 if (len > 0) {
    698 if (len <= datalen) {
    699 res = check_data(testfile, data, 0, len);
    700 if (res == -1)
    701 return -1;
    702 } else {
    703 res = check_data(testfile, data, 0, datalen);
    704 if (res == -1)
    705 return -1;
    706 res = check_data(testfile, zerodata, datalen,
    707 len - datalen);
    708 if (res == -1)
    709 return -1;
    710 }
    711 }
    712 res = unlink(testfile);
    713 if (res == -1) {
    714 PERROR("unlink");
    715 return -1;
    716 }
    717 res = check_nonexist(testfile);
    718 if (res == -1)
    719 return -1;
    720
    721 success();
    722 return 0;
    723}
    724
    725static int test_ftruncate(int len, int mode)
    726{
    727 const char *data = testdata;
    728 int datalen = testdatalen;
    729 int res;
    730 int fd;
    731
    732 start_test("ftruncate(%u) mode: 0%03o", len, mode);
    733 res = create_testfile(testfile, data, datalen);
    734 if (res == -1)
    735 return -1;
    736
    737 fd = open(testfile, O_WRONLY);
    738 if (fd == -1) {
    739 PERROR("open");
    740 return -1;
    741 }
    742
    743 res = fchmod(fd, mode);
    744 if (res == -1) {
    745 PERROR("fchmod");
    746 close(fd);
    747 return -1;
    748 }
    749 res = check_testfile_mode(testfile, mode);
    750 if (res == -1) {
    751 close(fd);
    752 return -1;
    753 }
    754 res = ftruncate(fd, len);
    755 if (res == -1) {
    756 PERROR("ftruncate");
    757 close(fd);
    758 return -1;
    759 }
    760 close(fd);
    761 res = check_testfile_size(testfile, len);
    762 if (res == -1)
    763 return -1;
    764
    765 if (len > 0) {
    766 if (len <= datalen) {
    767 res = check_data(testfile, data, 0, len);
    768 if (res == -1)
    769 return -1;
    770 } else {
    771 res = check_data(testfile, data, 0, datalen);
    772 if (res == -1)
    773 return -1;
    774 res = check_data(testfile, zerodata, datalen,
    775 len - datalen);
    776 if (res == -1)
    777 return -1;
    778 }
    779 }
    780 res = unlink(testfile);
    781 if (res == -1) {
    782 PERROR("unlink");
    783 return -1;
    784 }
    785 res = check_nonexist(testfile);
    786 if (res == -1)
    787 return -1;
    788
    789 success();
    790 return 0;
    791}
    792
    793static int test_seekdir(void)
    794{
    795 int i;
    796 int res;
    797 DIR *dp;
    798 struct dirent *de = NULL;
    799
    800 start_test("seekdir");
    801 res = create_dir(testdir, testdir_files);
    802 if (res == -1)
    803 return res;
    804
    805 dp = opendir(testdir);
    806 if (dp == NULL) {
    807 PERROR("opendir");
    808 return -1;
    809 }
    810
    811 /* Remember dir offsets */
    812 for (i = 0; i < ARRAY_SIZE(seekdir_offsets); i++) {
    813 seekdir_offsets[i] = telldir(dp);
    814 errno = 0;
    815 de = readdir(dp);
    816 if (de == NULL) {
    817 if (errno) {
    818 PERROR("readdir");
    819 goto fail;
    820 }
    821 break;
    822 }
    823 }
    824
    825 /* Walk until the end of directory */
    826 while (de)
    827 de = readdir(dp);
    828
    829 /* Start from the last valid dir offset and seek backwards */
    830 for (i--; i >= 0; i--) {
    831 seekdir(dp, seekdir_offsets[i]);
    832 de = readdir(dp);
    833 if (de == NULL) {
    834 ERROR("Unexpected end of directory after seekdir()");
    835 goto fail;
    836 }
    837 }
    838
    839 closedir(dp);
    840 res = cleanup_dir(testdir, testdir_files, 0);
    841 if (!res)
    842 success();
    843 return res;
    844fail:
    845 closedir(dp);
    846 cleanup_dir(testdir, testdir_files, 1);
    847 return -1;
    848}
    849
    850#ifdef HAVE_COPY_FILE_RANGE
    851static int test_copy_file_range(void)
    852{
    853 const char *data = testdata;
    854 int datalen = testdatalen;
    855 int err = 0;
    856 int res;
    857 int fd_in, fd_out;
    858 off_t pos_in = 0, pos_out = 0;
    859
    860 start_test("copy_file_range");
    861 unlink(testfile);
    862 fd_in = open(testfile, O_CREAT | O_RDWR, 0644);
    863 if (fd_in == -1) {
    864 PERROR("creat");
    865 return -1;
    866 }
    867 res = write(fd_in, data, datalen);
    868 if (res == -1) {
    869 PERROR("write");
    870 close(fd_in);
    871 return -1;
    872 }
    873 if (res != datalen) {
    874 ERROR("write is short: %u instead of %u", res, datalen);
    875 close(fd_in);
    876 return -1;
    877 }
    878
    879 unlink(testfile2);
    880 fd_out = creat(testfile2, 0644);
    881 if (fd_out == -1) {
    882 PERROR("creat");
    883 close(fd_in);
    884 return -1;
    885 }
    886 res = copy_file_range(fd_in, &pos_in, fd_out, &pos_out, datalen, 0);
    887 if (res == -1) {
    888 PERROR("copy_file_range");
    889 close(fd_in);
    890 close(fd_out);
    891 return -1;
    892 }
    893 if (res != datalen) {
    894 ERROR("copy is short: %u instead of %u", res, datalen);
    895 close(fd_in);
    896 close(fd_out);
    897 return -1;
    898 }
    899
    900 res = close(fd_in);
    901 if (res == -1) {
    902 PERROR("close");
    903 close(fd_out);
    904 return -1;
    905 }
    906 res = close(fd_out);
    907 if (res == -1) {
    908 PERROR("close");
    909 return -1;
    910 }
    911
    912 err = check_data(testfile2, data, 0, datalen);
    913
    914 res = unlink(testfile);
    915 if (res == -1) {
    916 PERROR("unlink");
    917 return -1;
    918 }
    919 res = check_nonexist(testfile);
    920 if (res == -1)
    921 return -1;
    922 if (err)
    923 return -1;
    924
    925 res = unlink(testfile2);
    926 if (res == -1) {
    927 PERROR("unlink");
    928 return -1;
    929 }
    930 res = check_nonexist(testfile2);
    931 if (res == -1)
    932 return -1;
    933 if (err)
    934 return -1;
    935
    936 success();
    937 return 0;
    938}
    939#else
    940static int test_copy_file_range(void)
    941{
    942 return 0;
    943}
    944#endif
    945
    946#ifdef HAVE_STATX
    947static int test_statx(void)
    948{
    949 struct statx sb;
    950 char msg[] = "hi";
    951 size_t msg_size = sizeof(msg);
    952 struct timespec tp;
    953 int res;
    954
    955 memset(&sb, 0, sizeof(sb));
    956 unlink(testfile);
    957
    958 start_test("statx");
    959
    960 res = create_testfile(testfile, msg, msg_size);
    961 if (res == -1)
    962 return -1;
    963
    964 res = statx(-1, testfile, AT_EMPTY_PATH,
    965 STATX_BASIC_STATS | STATX_BTIME, &sb);
    966 if (res == -1)
    967 return -1;
    968
    969 if (sb.stx_size != msg_size)
    970 return -1;
    971
    972 clock_gettime(CLOCK_REALTIME, &tp);
    973
    974 if (sb.stx_btime.tv_sec > tp.tv_sec)
    975 return -1;
    976
    977 if (sb.stx_btime.tv_sec == tp.tv_sec &&
    978 sb.stx_btime.tv_nsec >= tp.tv_nsec)
    979 return -1;
    980
    981 unlink(testfile);
    982
    983 success();
    984 return 0;
    985}
    986#else
    987static int test_statx(void)
    988{
    989 return 0;
    990}
    991#endif
    992
    993static int test_utime(void)
    994{
    995 struct utimbuf utm;
    996 time_t atime = 987631200;
    997 time_t mtime = 123116400;
    998 int res;
    999
    1000 start_test("utime");
    1001 res = create_testfile(testfile, NULL, 0);
    1002 if (res == -1)
    1003 return -1;
    1004
    1005 utm.actime = atime;
    1006 utm.modtime = mtime;
    1007 res = utime(testfile, &utm);
    1008 if (res == -1) {
    1009 PERROR("utime");
    1010 return -1;
    1011 }
    1012 res = check_times(testfile, atime, mtime);
    1013 if (res == -1) {
    1014 return -1;
    1015 }
    1016 res = unlink(testfile);
    1017 if (res == -1) {
    1018 PERROR("unlink");
    1019 return -1;
    1020 }
    1021 res = check_nonexist(testfile);
    1022 if (res == -1)
    1023 return -1;
    1024
    1025 success();
    1026 return 0;
    1027}
    1028
    1029static int test_create(void)
    1030{
    1031 const char *data = testdata;
    1032 int datalen = testdatalen;
    1033 int err = 0;
    1034 int res;
    1035 int fd;
    1036
    1037 start_test("create");
    1038 unlink(testfile);
    1039 fd = creat(testfile, 0644);
    1040 if (fd == -1) {
    1041 PERROR("creat");
    1042 return -1;
    1043 }
    1044 res = write(fd, data, datalen);
    1045 if (res == -1) {
    1046 PERROR("write");
    1047 close(fd);
    1048 return -1;
    1049 }
    1050 if (res != datalen) {
    1051 ERROR("write is short: %u instead of %u", res, datalen);
    1052 close(fd);
    1053 return -1;
    1054 }
    1055 res = close(fd);
    1056 if (res == -1) {
    1057 PERROR("close");
    1058 return -1;
    1059 }
    1060 res = check_type(testfile, S_IFREG);
    1061 if (res == -1)
    1062 return -1;
    1063 err += check_mode(testfile, 0644);
    1064 err += check_nlink(testfile, 1);
    1065 err += check_size(testfile, datalen);
    1066 err += check_data(testfile, data, 0, datalen);
    1067 res = unlink(testfile);
    1068 if (res == -1) {
    1069 PERROR("unlink");
    1070 return -1;
    1071 }
    1072 res = check_nonexist(testfile);
    1073 if (res == -1)
    1074 return -1;
    1075 if (err)
    1076 return -1;
    1077
    1078 success();
    1079 return 0;
    1080}
    1081
    1082static int test_create_unlink(void)
    1083{
    1084 const char *data = testdata;
    1085 int datalen = testdatalen;
    1086 int err = 0;
    1087 int res;
    1088 int fd;
    1089
    1090 start_test("create+unlink");
    1091 unlink(testfile);
    1092 fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644);
    1093 if (fd == -1) {
    1094 PERROR("creat");
    1095 return -1;
    1096 }
    1097 res = unlink(testfile);
    1098 if (res == -1) {
    1099 PERROR("unlink");
    1100 close(fd);
    1101 return -1;
    1102 }
    1103 res = check_nonexist(testfile);
    1104 if (res == -1) {
    1105 close(fd);
    1106 return -1;
    1107 }
    1108 res = write(fd, data, datalen);
    1109 if (res == -1) {
    1110 PERROR("write");
    1111 close(fd);
    1112 return -1;
    1113 }
    1114 if (res != datalen) {
    1115 ERROR("write is short: %u instead of %u", res, datalen);
    1116 close(fd);
    1117 return -1;
    1118 }
    1119 struct stat st = {
    1120 .st_mode = S_IFREG | 0644,
    1121 .st_size = datalen,
    1122 };
    1123 err = fcheck_stat(fd, O_RDWR, &st);
    1124 err += fcheck_data(fd, data, 0, datalen);
    1125 res = close(fd);
    1126 if (res == -1) {
    1127 PERROR("close");
    1128 err--;
    1129 }
    1130 if (err)
    1131 return -1;
    1132
    1133 success();
    1134 return 0;
    1135}
    1136
    1137static int test_mknod(void)
    1138{
    1139 int err = 0;
    1140 int res;
    1141
    1142 start_test("mknod");
    1143 unlink(testfile);
    1144 res = mknod(testfile, 0644, 0);
    1145 if (res == -1) {
    1146 PERROR("mknod");
    1147 return -1;
    1148 }
    1149 res = check_type(testfile, S_IFREG);
    1150 if (res == -1)
    1151 return -1;
    1152 err += check_mode(testfile, 0644);
    1153 err += check_nlink(testfile, 1);
    1154 err += check_size(testfile, 0);
    1155 res = unlink(testfile);
    1156 if (res == -1) {
    1157 PERROR("unlink");
    1158 return -1;
    1159 }
    1160 res = check_nonexist(testfile);
    1161 if (res == -1)
    1162 return -1;
    1163 if (err)
    1164 return -1;
    1165
    1166 success();
    1167 return 0;
    1168}
    1169
    1170#define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode)
    1171
    1172static int do_test_open(int exist, int flags, const char *flags_str, int mode)
    1173{
    1174 char buf[4096];
    1175 const char *data = testdata;
    1176 int datalen = testdatalen;
    1177 unsigned currlen = 0;
    1178 int err = 0;
    1179 int res;
    1180 int fd;
    1181 off_t off;
    1182
    1183 start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode);
    1184 unlink(testfile);
    1185 if (exist) {
    1186 res = create_file(testfile_r, testdata2, testdata2len);
    1187 if (res == -1)
    1188 return -1;
    1189
    1190 currlen = testdata2len;
    1191 }
    1192
    1193 fd = open(testfile, flags, mode);
    1194 if ((flags & O_CREAT) && (flags & O_EXCL) && exist) {
    1195 if (fd != -1) {
    1196 ERROR("open should have failed");
    1197 close(fd);
    1198 return -1;
    1199 } else if (errno == EEXIST)
    1200 goto succ;
    1201 }
    1202 if (!(flags & O_CREAT) && !exist) {
    1203 if (fd != -1) {
    1204 ERROR("open should have failed");
    1205 close(fd);
    1206 return -1;
    1207 } else if (errno == ENOENT)
    1208 goto succ;
    1209 }
    1210 if (fd == -1) {
    1211 PERROR("open");
    1212 return -1;
    1213 }
    1214
    1215 if (flags & O_TRUNC)
    1216 currlen = 0;
    1217
    1218 err += check_type(testfile, S_IFREG);
    1219 if (exist)
    1220 err += check_mode(testfile, 0644);
    1221 else
    1222 err += check_mode(testfile, mode);
    1223 err += check_nlink(testfile, 1);
    1224 err += check_size(testfile, currlen);
    1225 if (exist && !(flags & O_TRUNC) && (mode & S_IRUSR))
    1226 err += check_data(testfile, testdata2, 0, testdata2len);
    1227
    1228 res = write(fd, data, datalen);
    1229 if ((flags & O_ACCMODE) != O_RDONLY) {
    1230 if (res == -1) {
    1231 PERROR("write");
    1232 err --;
    1233 } else if (res != datalen) {
    1234 ERROR("write is short: %u instead of %u", res, datalen);
    1235 err --;
    1236 } else {
    1237 if (datalen > (int) currlen)
    1238 currlen = datalen;
    1239
    1240 err += check_size(testfile, currlen);
    1241
    1242 if (mode & S_IRUSR) {
    1243 err += check_data(testfile, data, 0, datalen);
    1244 if (exist && !(flags & O_TRUNC) &&
    1245 testdata2len > datalen)
    1246 err += check_data(testfile,
    1247 testdata2 + datalen,
    1248 datalen,
    1249 testdata2len - datalen);
    1250 }
    1251 }
    1252 } else {
    1253 if (res != -1) {
    1254 ERROR("write should have failed");
    1255 err --;
    1256 } else if (errno != EBADF) {
    1257 PERROR("write");
    1258 err --;
    1259 }
    1260 }
    1261 off = lseek(fd, SEEK_SET, 0);
    1262 if (off == (off_t) -1) {
    1263 PERROR("lseek");
    1264 err--;
    1265 } else if (off != 0) {
    1266 ERROR("offset should have returned 0");
    1267 err --;
    1268 }
    1269 res = read(fd, buf, sizeof(buf));
    1270 if ((flags & O_ACCMODE) != O_WRONLY) {
    1271 if (res == -1) {
    1272 PERROR("read");
    1273 err--;
    1274 } else {
    1275 int readsize =
    1276 currlen < sizeof(buf) ? currlen : sizeof(buf);
    1277 if (res != readsize) {
    1278 ERROR("read is short: %i instead of %u",
    1279 res, readsize);
    1280 err--;
    1281 } else {
    1282 if ((flags & O_ACCMODE) != O_RDONLY) {
    1283 err += check_buffer(buf, data, datalen);
    1284 if (exist && !(flags & O_TRUNC) &&
    1285 testdata2len > datalen)
    1286 err += check_buffer(buf + datalen,
    1287 testdata2 + datalen,
    1288 testdata2len - datalen);
    1289 } else if (exist)
    1290 err += check_buffer(buf, testdata2,
    1291 testdata2len);
    1292 }
    1293 }
    1294 } else {
    1295 if (res != -1) {
    1296 ERROR("read should have failed");
    1297 err --;
    1298 } else if (errno != EBADF) {
    1299 PERROR("read");
    1300 err --;
    1301 }
    1302 }
    1303
    1304 res = close(fd);
    1305 if (res == -1) {
    1306 PERROR("close");
    1307 return -1;
    1308 }
    1309 res = unlink(testfile);
    1310 if (res == -1) {
    1311 PERROR("unlink");
    1312 return -1;
    1313 }
    1314 res = check_nonexist(testfile);
    1315 if (res == -1)
    1316 return -1;
    1317 res = check_nonexist(testfile_r);
    1318 if (res == -1)
    1319 return -1;
    1320 if (err)
    1321 return -1;
    1322
    1323succ:
    1324 success();
    1325 return 0;
    1326}
    1327
    1328#define test_open_acc(flags, mode, err) \
    1329 do_test_open_acc(flags, #flags, mode, err)
    1330
    1331static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
    1332{
    1333 const char *data = testdata;
    1334 int datalen = testdatalen;
    1335 int res;
    1336 int fd;
    1337
    1338 start_test("open_acc(%s) mode: 0%03o message: '%s'", flags_str, mode,
    1339 strerror(err));
    1340 unlink(testfile);
    1341 res = create_testfile(testfile, data, datalen);
    1342 if (res == -1)
    1343 return -1;
    1344
    1345 res = chmod(testfile, mode);
    1346 if (res == -1) {
    1347 PERROR("chmod");
    1348 return -1;
    1349 }
    1350
    1351 res = check_testfile_mode(testfile, mode);
    1352 if (res == -1)
    1353 return -1;
    1354
    1355 fd = open(testfile, flags);
    1356 if (fd == -1) {
    1357 if (err != errno) {
    1358 PERROR("open");
    1359 return -1;
    1360 }
    1361 } else {
    1362 if (err) {
    1363 ERROR("open should have failed");
    1364 close(fd);
    1365 return -1;
    1366 }
    1367 close(fd);
    1368 }
    1369
    1370 res = unlink(testfile);
    1371 if (res == -1) {
    1372 PERROR("unlink");
    1373 return -1;
    1374 }
    1375 res = check_nonexist(testfile);
    1376 if (res == -1)
    1377 return -1;
    1378 res = check_nonexist(testfile_r);
    1379 if (res == -1)
    1380 return -1;
    1381
    1382 success();
    1383 return 0;
    1384}
    1385
    1386static int test_symlink(void)
    1387{
    1388 char buf[1024];
    1389 const char *data = testdata;
    1390 int datalen = testdatalen;
    1391 int linklen = strlen(testfile);
    1392 int err = 0;
    1393 int res;
    1394
    1395 start_test("symlink");
    1396 res = create_testfile(testfile, data, datalen);
    1397 if (res == -1)
    1398 return -1;
    1399
    1400 unlink(testfile2);
    1401 res = symlink(testfile, testfile2);
    1402 if (res == -1) {
    1403 PERROR("symlink");
    1404 return -1;
    1405 }
    1406 res = check_type(testfile2, S_IFLNK);
    1407 if (res == -1)
    1408 return -1;
    1409 err += check_mode(testfile2, 0777);
    1410 err += check_nlink(testfile2, 1);
    1411 res = readlink(testfile2, buf, sizeof(buf));
    1412 if (res == -1) {
    1413 PERROR("readlink");
    1414 err--;
    1415 }
    1416 if (res != linklen) {
    1417 ERROR("short readlink: %u instead of %u", res, linklen);
    1418 err--;
    1419 }
    1420 if (memcmp(buf, testfile, linklen) != 0) {
    1421 ERROR("link mismatch");
    1422 err--;
    1423 }
    1424 err += check_size(testfile2, datalen);
    1425 err += check_data(testfile2, data, 0, datalen);
    1426 res = unlink(testfile2);
    1427 if (res == -1) {
    1428 PERROR("unlink");
    1429 return -1;
    1430 }
    1431 res = check_nonexist(testfile2);
    1432 if (res == -1)
    1433 return -1;
    1434 if (err)
    1435 return -1;
    1436
    1437 res = unlink(testfile);
    1438 if (res == -1) {
    1439 PERROR("unlink");
    1440 return -1;
    1441 }
    1442 res = check_nonexist(testfile);
    1443 if (res == -1)
    1444 return -1;
    1445
    1446 success();
    1447 return 0;
    1448}
    1449
    1450static int test_link(void)
    1451{
    1452 const char *data = testdata;
    1453 int datalen = testdatalen;
    1454 int err = 0;
    1455 int res;
    1456
    1457 start_test("link");
    1458 res = create_testfile(testfile, data, datalen);
    1459 if (res == -1)
    1460 return -1;
    1461
    1462 unlink(testfile2);
    1463 res = link(testfile, testfile2);
    1464 if (res == -1) {
    1465 PERROR("link");
    1466 return -1;
    1467 }
    1468 res = check_type(testfile2, S_IFREG);
    1469 if (res == -1)
    1470 return -1;
    1471 err += check_mode(testfile2, 0644);
    1472 err += check_nlink(testfile2, 2);
    1473 err += check_size(testfile2, datalen);
    1474 err += check_data(testfile2, data, 0, datalen);
    1475 res = unlink(testfile);
    1476 if (res == -1) {
    1477 PERROR("unlink");
    1478 return -1;
    1479 }
    1480 res = check_nonexist(testfile);
    1481 if (res == -1)
    1482 return -1;
    1483
    1484 err += check_nlink(testfile2, 1);
    1485 res = unlink(testfile2);
    1486 if (res == -1) {
    1487 PERROR("unlink");
    1488 return -1;
    1489 }
    1490 res = check_nonexist(testfile2);
    1491 if (res == -1)
    1492 return -1;
    1493 if (err)
    1494 return -1;
    1495
    1496 success();
    1497 return 0;
    1498}
    1499
    1500static int test_link2(void)
    1501{
    1502 const char *data = testdata;
    1503 int datalen = testdatalen;
    1504 int err = 0;
    1505 int res;
    1506
    1507 start_test("link-unlink-link");
    1508 res = create_testfile(testfile, data, datalen);
    1509 if (res == -1)
    1510 return -1;
    1511
    1512 unlink(testfile2);
    1513 res = link(testfile, testfile2);
    1514 if (res == -1) {
    1515 PERROR("link");
    1516 return -1;
    1517 }
    1518 res = unlink(testfile);
    1519 if (res == -1) {
    1520 PERROR("unlink");
    1521 return -1;
    1522 }
    1523 res = check_nonexist(testfile);
    1524 if (res == -1)
    1525 return -1;
    1526 res = link(testfile2, testfile);
    1527 if (res == -1) {
    1528 PERROR("link");
    1529 }
    1530 res = check_type(testfile, S_IFREG);
    1531 if (res == -1)
    1532 return -1;
    1533 err += check_mode(testfile, 0644);
    1534 err += check_nlink(testfile, 2);
    1535 err += check_size(testfile, datalen);
    1536 err += check_data(testfile, data, 0, datalen);
    1537
    1538 res = unlink(testfile2);
    1539 if (res == -1) {
    1540 PERROR("unlink");
    1541 return -1;
    1542 }
    1543 err += check_nlink(testfile, 1);
    1544 res = unlink(testfile);
    1545 if (res == -1) {
    1546 PERROR("unlink");
    1547 return -1;
    1548 }
    1549 res = check_nonexist(testfile);
    1550 if (res == -1)
    1551 return -1;
    1552 if (err)
    1553 return -1;
    1554
    1555 success();
    1556 return 0;
    1557}
    1558
    1559static int test_rename_file(void)
    1560{
    1561 const char *data = testdata;
    1562 int datalen = testdatalen;
    1563 int err = 0;
    1564 int res;
    1565
    1566 start_test("rename file");
    1567 res = create_testfile(testfile, data, datalen);
    1568 if (res == -1)
    1569 return -1;
    1570
    1571 unlink(testfile2);
    1572 res = rename(testfile, testfile2);
    1573 if (res == -1) {
    1574 PERROR("rename");
    1575 return -1;
    1576 }
    1577 res = check_nonexist(testfile);
    1578 if (res == -1)
    1579 return -1;
    1580 res = check_type(testfile2, S_IFREG);
    1581 if (res == -1)
    1582 return -1;
    1583 err += check_mode(testfile2, 0644);
    1584 err += check_nlink(testfile2, 1);
    1585 err += check_size(testfile2, datalen);
    1586 err += check_data(testfile2, data, 0, datalen);
    1587 res = unlink(testfile2);
    1588 if (res == -1) {
    1589 PERROR("unlink");
    1590 return -1;
    1591 }
    1592 res = check_nonexist(testfile2);
    1593 if (res == -1)
    1594 return -1;
    1595 if (err)
    1596 return -1;
    1597
    1598 success();
    1599 return 0;
    1600}
    1601
    1602static int test_rename_dir(void)
    1603{
    1604 int err = 0;
    1605 int res;
    1606
    1607 start_test("rename dir");
    1608 res = create_dir(testdir, testdir_files);
    1609 if (res == -1)
    1610 return -1;
    1611
    1612 rmdir(testdir2);
    1613 res = rename(testdir, testdir2);
    1614 if (res == -1) {
    1615 PERROR("rename");
    1616 cleanup_dir(testdir, testdir_files, 1);
    1617 return -1;
    1618 }
    1619 res = check_nonexist(testdir);
    1620 if (res == -1) {
    1621 cleanup_dir(testdir, testdir_files, 1);
    1622 return -1;
    1623 }
    1624 res = check_type(testdir2, S_IFDIR);
    1625 if (res == -1) {
    1626 cleanup_dir(testdir2, testdir_files, 1);
    1627 return -1;
    1628 }
    1629 err += check_mode(testdir2, 0755);
    1630 err += check_dir_contents(testdir2, testdir_files);
    1631 err += cleanup_dir(testdir2, testdir_files, 0);
    1632 res = rmdir(testdir2);
    1633 if (res == -1) {
    1634 PERROR("rmdir");
    1635 return -1;
    1636 }
    1637 res = check_nonexist(testdir2);
    1638 if (res == -1)
    1639 return -1;
    1640 if (err)
    1641 return -1;
    1642
    1643 success();
    1644 return 0;
    1645}
    1646
    1647static int test_rename_dir_loop(void)
    1648{
    1649#define PATH(p) (snprintf(path, sizeof path, "%s/%s", testdir, p), path)
    1650#define PATH2(p) (snprintf(path2, sizeof path2, "%s/%s", testdir, p), path2)
    1651
    1652 char path[1280], path2[1280];
    1653 int err = 0;
    1654 int res;
    1655
    1656 start_test("rename dir loop");
    1657
    1658 res = create_dir(testdir, testdir_files);
    1659 if (res == -1)
    1660 return -1;
    1661
    1662 res = mkdir(PATH("a"), 0755);
    1663 if (res == -1) {
    1664 PERROR("mkdir");
    1665 goto fail;
    1666 }
    1667
    1668 res = rename(PATH("a"), PATH2("a"));
    1669 if (res == -1) {
    1670 PERROR("rename");
    1671 goto fail;
    1672 }
    1673
    1674 errno = 0;
    1675 res = rename(PATH("a"), PATH2("a/b"));
    1676 if (res == 0 || errno != EINVAL) {
    1677 PERROR("rename");
    1678 goto fail;
    1679 }
    1680
    1681 res = mkdir(PATH("a/b"), 0755);
    1682 if (res == -1) {
    1683 PERROR("mkdir");
    1684 goto fail;
    1685 }
    1686
    1687 res = mkdir(PATH("a/b/c"), 0755);
    1688 if (res == -1) {
    1689 PERROR("mkdir");
    1690 goto fail;
    1691 }
    1692
    1693 errno = 0;
    1694 res = rename(PATH("a"), PATH2("a/b/c"));
    1695 if (res == 0 || errno != EINVAL) {
    1696 PERROR("rename");
    1697 goto fail;
    1698 }
    1699
    1700 errno = 0;
    1701 res = rename(PATH("a"), PATH2("a/b/c/a"));
    1702 if (res == 0 || errno != EINVAL) {
    1703 PERROR("rename");
    1704 goto fail;
    1705 }
    1706
    1707 errno = 0;
    1708 res = rename(PATH("a/b/c"), PATH2("a"));
    1709 if (res == 0 || errno != ENOTEMPTY) {
    1710 PERROR("rename");
    1711 goto fail;
    1712 }
    1713
    1714 res = open(PATH("a/foo"), O_CREAT, 0644);
    1715 if (res == -1) {
    1716 PERROR("open");
    1717 goto fail;
    1718 }
    1719 close(res);
    1720
    1721 res = rename(PATH("a/foo"), PATH2("a/bar"));
    1722 if (res == -1) {
    1723 PERROR("rename");
    1724 goto fail;
    1725 }
    1726
    1727 res = rename(PATH("a/bar"), PATH2("a/foo"));
    1728 if (res == -1) {
    1729 PERROR("rename");
    1730 goto fail;
    1731 }
    1732
    1733 res = rename(PATH("a/foo"), PATH2("a/b/bar"));
    1734 if (res == -1) {
    1735 PERROR("rename");
    1736 goto fail;
    1737 }
    1738
    1739 res = rename(PATH("a/b/bar"), PATH2("a/foo"));
    1740 if (res == -1) {
    1741 PERROR("rename");
    1742 goto fail;
    1743 }
    1744
    1745 res = rename(PATH("a/foo"), PATH2("a/b/c/bar"));
    1746 if (res == -1) {
    1747 PERROR("rename");
    1748 goto fail;
    1749 }
    1750
    1751 res = rename(PATH("a/b/c/bar"), PATH2("a/foo"));
    1752 if (res == -1) {
    1753 PERROR("rename");
    1754 goto fail;
    1755 }
    1756
    1757 res = open(PATH("a/bar"), O_CREAT, 0644);
    1758 if (res == -1) {
    1759 PERROR("open");
    1760 goto fail;
    1761 }
    1762 close(res);
    1763
    1764 res = rename(PATH("a/foo"), PATH2("a/bar"));
    1765 if (res == -1) {
    1766 PERROR("rename");
    1767 goto fail;
    1768 }
    1769
    1770 unlink(PATH("a/bar"));
    1771
    1772 res = rename(PATH("a/b"), PATH2("a/d"));
    1773 if (res == -1) {
    1774 PERROR("rename");
    1775 goto fail;
    1776 }
    1777
    1778 res = rename(PATH("a/d"), PATH2("a/b"));
    1779 if (res == -1) {
    1780 PERROR("rename");
    1781 goto fail;
    1782 }
    1783
    1784 res = mkdir(PATH("a/d"), 0755);
    1785 if (res == -1) {
    1786 PERROR("mkdir");
    1787 goto fail;
    1788 }
    1789
    1790 res = rename(PATH("a/b"), PATH2("a/d"));
    1791 if (res == -1) {
    1792 PERROR("rename");
    1793 goto fail;
    1794 }
    1795
    1796 res = rename(PATH("a/d"), PATH2("a/b"));
    1797 if (res == -1) {
    1798 PERROR("rename");
    1799 goto fail;
    1800 }
    1801
    1802 res = mkdir(PATH("a/d"), 0755);
    1803 if (res == -1) {
    1804 PERROR("mkdir");
    1805 goto fail;
    1806 }
    1807
    1808 res = mkdir(PATH("a/d/e"), 0755);
    1809 if (res == -1) {
    1810 PERROR("mkdir");
    1811 goto fail;
    1812 }
    1813
    1814 errno = 0;
    1815 res = rename(PATH("a/b"), PATH2("a/d"));
    1816 if (res == 0 || (errno != ENOTEMPTY && errno != EEXIST)) {
    1817 PERROR("rename");
    1818 goto fail;
    1819 }
    1820
    1821 rmdir(PATH("a/d/e"));
    1822 rmdir(PATH("a/d"));
    1823
    1824 rmdir(PATH("a/b/c"));
    1825 rmdir(PATH("a/b"));
    1826 rmdir(PATH("a"));
    1827
    1828 err += cleanup_dir(testdir, testdir_files, 0);
    1829 res = rmdir(testdir);
    1830 if (res == -1) {
    1831 PERROR("rmdir");
    1832 goto fail;
    1833 }
    1834 res = check_nonexist(testdir);
    1835 if (res == -1)
    1836 return -1;
    1837 if (err)
    1838 return -1;
    1839
    1840 success();
    1841 return 0;
    1842
    1843fail:
    1844 unlink(PATH("a/bar"));
    1845
    1846 rmdir(PATH("a/d/e"));
    1847 rmdir(PATH("a/d"));
    1848
    1849 rmdir(PATH("a/b/c"));
    1850 rmdir(PATH("a/b"));
    1851 rmdir(PATH("a"));
    1852
    1853 cleanup_dir(testdir, testdir_files, 1);
    1854 rmdir(testdir);
    1855
    1856 return -1;
    1857
    1858#undef PATH2
    1859#undef PATH
    1860}
    1861
    1862static int test_mkfifo(void)
    1863{
    1864 int res;
    1865 int err = 0;
    1866
    1867 start_test("mkfifo");
    1868 unlink(testfile);
    1869 res = mkfifo(testfile, 0644);
    1870 if (res == -1) {
    1871 PERROR("mkfifo");
    1872 return -1;
    1873 }
    1874 res = check_type(testfile, S_IFIFO);
    1875 if (res == -1)
    1876 return -1;
    1877 err += check_mode(testfile, 0644);
    1878 err += check_nlink(testfile, 1);
    1879 res = unlink(testfile);
    1880 if (res == -1) {
    1881 PERROR("unlink");
    1882 return -1;
    1883 }
    1884 res = check_nonexist(testfile);
    1885 if (res == -1)
    1886 return -1;
    1887 if (err)
    1888 return -1;
    1889
    1890 success();
    1891 return 0;
    1892}
    1893
    1894static int test_mkdir(void)
    1895{
    1896 int res;
    1897 int err = 0;
    1898 const char *dir_contents[] = {NULL};
    1899
    1900 start_test("mkdir");
    1901 rmdir(testdir);
    1902 res = mkdir(testdir, 0755);
    1903 if (res == -1) {
    1904 PERROR("mkdir");
    1905 return -1;
    1906 }
    1907 res = check_type(testdir, S_IFDIR);
    1908 if (res == -1)
    1909 return -1;
    1910 err += check_mode(testdir, 0755);
    1911 /* Some file systems (like btrfs) don't track link
    1912 count for directories */
    1913 //err += check_nlink(testdir, 2);
    1914 err += check_dir_contents(testdir, dir_contents);
    1915 res = rmdir(testdir);
    1916 if (res == -1) {
    1917 PERROR("rmdir");
    1918 return -1;
    1919 }
    1920 res = check_nonexist(testdir);
    1921 if (res == -1)
    1922 return -1;
    1923 if (err)
    1924 return -1;
    1925
    1926 success();
    1927 return 0;
    1928}
    1929
    1930static int test_socket(void)
    1931{
    1932 struct sockaddr_un su;
    1933 int fd;
    1934 int res;
    1935 int err = 0;
    1936 const size_t test_sock_len = strlen(testsock) + 1;
    1937
    1938 start_test("socket");
    1939 if (test_sock_len > sizeof(su.sun_path)) {
    1940 fprintf(stderr, "Need to shorten mount point by %zu chars\n",
    1941 strlen(testsock) + 1 - sizeof(su.sun_path));
    1942 return -1;
    1943 }
    1944 unlink(testsock);
    1945 fd = socket(AF_UNIX, SOCK_STREAM, 0);
    1946 if (fd < 0) {
    1947 PERROR("socket");
    1948 return -1;
    1949 }
    1950 su.sun_family = AF_UNIX;
    1951
    1952 strncpy(su.sun_path, testsock, test_sock_len);
    1953 su.sun_path[sizeof(su.sun_path) - 1] = '\0';
    1954 res = bind(fd, (struct sockaddr*)&su, sizeof(su));
    1955 if (res == -1) {
    1956 PERROR("bind");
    1957 return -1;
    1958 }
    1959
    1960 res = check_type(testsock, S_IFSOCK);
    1961 if (res == -1) {
    1962 close(fd);
    1963 return -1;
    1964 }
    1965 err += check_nlink(testsock, 1);
    1966 close(fd);
    1967 res = unlink(testsock);
    1968 if (res == -1) {
    1969 PERROR("unlink");
    1970 return -1;
    1971 }
    1972 res = check_nonexist(testsock);
    1973 if (res == -1)
    1974 return -1;
    1975 if (err)
    1976 return -1;
    1977
    1978 success();
    1979 return 0;
    1980}
    1981
    1982#define test_create_ro_dir(flags) \
    1983 do_test_create_ro_dir(flags, #flags)
    1984
    1985static int do_test_create_ro_dir(int flags, const char *flags_str)
    1986{
    1987 int res;
    1988 int err = 0;
    1989 int fd;
    1990
    1991 start_test("open(%s) in read-only directory", flags_str);
    1992 rmdir(testdir);
    1993 res = mkdir(testdir, 0555);
    1994 if (res == -1) {
    1995 PERROR("mkdir");
    1996 return -1;
    1997 }
    1998 fd = open(subfile, flags, 0644);
    1999 if (fd != -1) {
    2000 close(fd);
    2001 unlink(subfile);
    2002 ERROR("open should have failed");
    2003 err--;
    2004 } else {
    2005 res = check_nonexist(subfile);
    2006 if (res == -1)
    2007 err--;
    2008 }
    2009 unlink(subfile);
    2010 res = rmdir(testdir);
    2011 if (res == -1) {
    2012 PERROR("rmdir");
    2013 return -1;
    2014 }
    2015 res = check_nonexist(testdir);
    2016 if (res == -1)
    2017 return -1;
    2018 if (err)
    2019 return -1;
    2020
    2021 success();
    2022 return 0;
    2023}
    2024
    2025#ifndef __FreeBSD__
    2026/* this tests open with O_TMPFILE
    2027 note that this will only work with the fuse low level api
    2028 you will get ENOTSUP with the high level api */
    2029static int test_create_tmpfile(void)
    2030{
    2031 rmdir(testdir);
    2032 int res = mkdir(testdir, 0777);
    2033 if (res)
    2034 return -1;
    2035
    2036 start_test("create tmpfile");
    2037
    2038 int fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
    2039 if(fd == -1) {
    2040 if (errno == ENOTSUP) {
    2041 /* don't bother if we're working on an old kernel
    2042 or on the high level API */
    2043 return 0;
    2044 }
    2045
    2046 PERROR("open O_TMPFILE | O_RDWR");
    2047 return -1;
    2048 }
    2049 close(fd);
    2050
    2051 fd = open(testdir, O_TMPFILE | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
    2052 if(fd == -1){
    2053 PERROR("open with O_TMPFILE | O_WRONLY | O_EXCL");
    2054 return -1;
    2055 };
    2056 close(fd);
    2057
    2058 fd = open(testdir, O_TMPFILE | O_RDONLY, S_IRUSR);
    2059 if (fd != -1) {
    2060 ERROR("open with O_TMPFILE | O_RDONLY succeeded");
    2061 return -1;
    2062 }
    2063
    2064 success();
    2065 return 0;
    2066}
    2067
    2068static int test_create_and_link_tmpfile(void)
    2069{
    2070 /* skip this test for now since the github runner will fail in the linkat call below */
    2071 return 0;
    2072
    2073 rmdir(testdir);
    2074 unlink(testfile);
    2075
    2076 int res = mkdir(testdir, 0777);
    2077 if (res)
    2078 return -1;
    2079
    2080 start_test("create and link tmpfile");
    2081
    2082 int fd = open(testdir, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
    2083 if(fd == -1) {
    2084 if (errno == ENOTSUP) {
    2085 /* don't bother if we're working on an old kernel
    2086 or on the high level API */
    2087 return 0;
    2088 }
    2089 PERROR("open with O_TMPFILE | O_RDWR | O_EXCL");
    2090 return -1;
    2091 }
    2092
    2093 if (!linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) {
    2094 ERROR("linkat succeeded on a tmpfile opened with O_EXCL");
    2095 return -1;
    2096 }
    2097 close(fd);
    2098
    2099 fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
    2100 if(fd == -1) {
    2101 PERROR("open O_TMPFILE");
    2102 return -1;
    2103 }
    2104
    2105 if (check_nonexist(testfile)) {
    2106 return -1;
    2107 }
    2108
    2109 if (linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) {
    2110 PERROR("linkat tempfile");
    2111 return -1;
    2112 }
    2113 close(fd);
    2114
    2115 if (check_nlink(testfile, 1)) {
    2116 return -1;
    2117 }
    2118 unlink(testfile);
    2119
    2120 success();
    2121 return 0;
    2122}
    2123#endif
    2124
    2125int main(int argc, char *argv[])
    2126{
    2127 int err = 0;
    2128 int a;
    2129 int is_root;
    2130
    2131 /* Piped stdout is fully buffered, so a killed test loses whatever it
    2132 * had printed about what it was doing.
    2133 */
    2134 setvbuf(stdout, NULL, _IOLBF, 0);
    2135
    2136 umask(0);
    2137 if (argc < 2 || argc > 4) {
    2138 fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#] [-u]\n", argv[0]);
    2139 return 1;
    2140 }
    2141 basepath = argv[1];
    2142 basepath_r = basepath;
    2143 for (a = 2; a < argc; a++) {
    2144 char *endptr;
    2145 char *arg = argv[a];
    2146 if (arg[0] == ':') {
    2147 basepath_r = arg + 1;
    2148 } else {
    2149 if (arg[0] == '-') {
    2150 arg++;
    2151 if (arg[0] == 'u') {
    2152 unlinked_test = 1;
    2153 endptr = arg + 1;
    2154 } else {
    2155 skip_test = strtoul(arg, &endptr, 10);
    2156 }
    2157 } else {
    2158 select_test = strtoul(arg, &endptr, 10);
    2159 }
    2160 if (arg[0] == '\0' || *endptr != '\0') {
    2161 fprintf(stderr, "invalid option: '%s'\n", argv[a]);
    2162 return 1;
    2163 }
    2164 }
    2165 }
    2166 assert(strlen(basepath) < 512);
    2167 assert(strlen(basepath_r) < 512);
    2168 if (basepath[0] != '/') {
    2169 fprintf(stderr, "testdir must be an absolute path\n");
    2170 return 1;
    2171 }
    2172
    2173 sprintf(testfile, "%s/testfile", basepath);
    2174 sprintf(testfile2, "%s/testfile2", basepath);
    2175 sprintf(testdir, "%s/testdir", basepath);
    2176 sprintf(testdir2, "%s/testdir2", basepath);
    2177 sprintf(subfile, "%s/subfile", testdir2);
    2178 sprintf(testsock, "%s/testsock", basepath);
    2179
    2180 sprintf(testfile_r, "%s/testfile", basepath_r);
    2181 sprintf(testfile2_r, "%s/testfile2", basepath_r);
    2182 sprintf(testdir_r, "%s/testdir", basepath_r);
    2183 sprintf(testdir2_r, "%s/testdir2", basepath_r);
    2184 sprintf(subfile_r, "%s/subfile", testdir2_r);
    2185
    2186 is_root = (geteuid() == 0);
    2187
    2188 err += test_create();
    2189 err += test_create_unlink();
    2190 err += test_symlink();
    2191 err += test_link();
    2192 err += test_link2();
    2193 err += test_mknod();
    2194 err += test_mkfifo();
    2195 err += test_mkdir();
    2196 err += test_rename_file();
    2197 err += test_rename_dir();
    2198 err += test_rename_dir_loop();
    2199 err += test_seekdir();
    2200 err += test_socket();
    2201 err += test_utime();
    2202 err += test_truncate(0);
    2203 err += test_truncate(testdatalen / 2);
    2204 err += test_truncate(testdatalen);
    2205 err += test_truncate(testdatalen + 100);
    2206 err += test_ftruncate(0, 0600);
    2207 err += test_ftruncate(testdatalen / 2, 0600);
    2208 err += test_ftruncate(testdatalen, 0600);
    2209 err += test_ftruncate(testdatalen + 100, 0600);
    2210 err += test_ftruncate(0, 0400);
    2211 err += test_ftruncate(0, 0200);
    2212 err += test_ftruncate(0, 0000);
    2213 err += test_open(0, O_RDONLY, 0);
    2214 err += test_open(1, O_RDONLY, 0);
    2215 err += test_open(1, O_RDWR, 0);
    2216 err += test_open(1, O_WRONLY, 0);
    2217 err += test_open(0, O_RDWR | O_CREAT, 0600);
    2218 err += test_open(1, O_RDWR | O_CREAT, 0600);
    2219 err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600);
    2220 err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600);
    2221 err += test_open(0, O_RDONLY | O_CREAT, 0600);
    2222 err += test_open(0, O_RDONLY | O_CREAT, 0400);
    2223 err += test_open(0, O_RDONLY | O_CREAT, 0200);
    2224 err += test_open(0, O_RDONLY | O_CREAT, 0000);
    2225 err += test_open(0, O_WRONLY | O_CREAT, 0600);
    2226 err += test_open(0, O_WRONLY | O_CREAT, 0400);
    2227 err += test_open(0, O_WRONLY | O_CREAT, 0200);
    2228 err += test_open(0, O_WRONLY | O_CREAT, 0000);
    2229 err += test_open(0, O_RDWR | O_CREAT, 0400);
    2230 err += test_open(0, O_RDWR | O_CREAT, 0200);
    2231 err += test_open(0, O_RDWR | O_CREAT, 0000);
    2232 err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600);
    2233 err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600);
    2234 err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000);
    2235 err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000);
    2236 err += test_open_acc(O_RDONLY, 0600, 0);
    2237 err += test_open_acc(O_WRONLY, 0600, 0);
    2238 err += test_open_acc(O_RDWR, 0600, 0);
    2239 err += test_open_acc(O_RDONLY, 0400, 0);
    2240 err += test_open_acc(O_WRONLY, 0200, 0);
    2241 if(!is_root) {
    2242 err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES);
    2243 err += test_open_acc(O_WRONLY, 0400, EACCES);
    2244 err += test_open_acc(O_RDWR, 0400, EACCES);
    2245 err += test_open_acc(O_RDONLY, 0200, EACCES);
    2246 err += test_open_acc(O_RDWR, 0200, EACCES);
    2247 err += test_open_acc(O_RDONLY, 0000, EACCES);
    2248 err += test_open_acc(O_WRONLY, 0000, EACCES);
    2249 err += test_open_acc(O_RDWR, 0000, EACCES);
    2250 }
    2251 err += test_create_ro_dir(O_CREAT);
    2252 err += test_create_ro_dir(O_CREAT | O_EXCL);
    2253 err += test_create_ro_dir(O_CREAT | O_WRONLY);
    2254 err += test_create_ro_dir(O_CREAT | O_TRUNC);
    2255 err += test_copy_file_range();
    2256 err += test_statx();
    2257#ifndef __FreeBSD__
    2258 err += test_create_tmpfile();
    2259 err += test_create_and_link_tmpfile();
    2260#endif
    2261
    2262 unlink(testfile2);
    2263 unlink(testsock);
    2264 rmdir(testdir);
    2265 rmdir(testdir2);
    2266
    2267 if (err) {
    2268 fprintf(stderr, "%i tests failed\n", -err);
    2269 return 1;
    2270 }
    2271
    2272 return check_unlinked_testfiles();
    2273}
    fuse-3.18.3/doc/html/test__want__conversion_8c_source.html0000644000175000017500000012717415250106404022653 0ustar berndbernd libfuse: test/test_want_conversion.c Source File
    libfuse
    test_want_conversion.c
    1#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17)
    2
    3#include "util.h"
    4#include "fuse_i.h"
    5#include "fuse_lowlevel.h"
    6#include <stdio.h>
    7#include <assert.h>
    8#include <inttypes.h>
    9#include <stdbool.h>
    10#include <err.h>
    11
    12static void print_conn_info(const char *prefix, struct fuse_conn_info *conn)
    13{
    14 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
    15
    16 printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64
    17 " want_default=0x%" PRIx32 " want_ext_default=0x%" PRIx64 "\n",
    18 prefix, conn->want, conn->want_ext, se->conn_want,
    19 se->conn_want_ext);
    20}
    21
    22static void application_init_old_style(struct fuse_conn_info *conn)
    23{
    24 /* Simulate application init the old style */
    27
    28 /*
    29 * Also use new style API, as that might happen through
    30 * fuse_apply_conn_info_opts()
    31 */
    33}
    34
    35static void application_init_new_style(struct fuse_conn_info *conn)
    36{
    37 /* Simulate application init the new style */
    41}
    42
    43static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style)
    44{
    45 /* High-level init */
    47
    48 if (new_style)
    49 application_init_new_style(conn);
    50 else
    51 application_init_old_style(conn);
    52}
    53
    54static void test_do_init(struct fuse_conn_info *conn, bool new_style)
    55{
    56 /* Initial setup */
    61 conn->capable = fuse_lower_32_bits(conn->capable_ext);
    62
    66
    67 print_conn_info("Initial state", conn);
    68
    69 int rc;
    70
    71 test_fuse_fs_init(conn, new_style);
    72 print_conn_info("After init", conn);
    73
    75 assert(rc == 0);
    76
    77 /* Verify all expected flags are set */
    78 assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ));
    79 assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE);
    80 assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE);
    81 assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT);
    82 assert(conn->want_ext & FUSE_CAP_ASYNC_READ);
    83 assert(conn->want_ext & FUSE_CAP_IOCTL_DIR);
    84
    85 /* Verify no other flags are set */
    86 assert(conn->want_ext ==
    90
    91 print_conn_info("After init", conn);
    92}
    93
    94static void test_want_conversion_basic(void)
    95{
    96 const struct fuse_lowlevel_ops ops = { 0 };
    97 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
    98 struct fuse_session *se;
    99 struct fuse_conn_info *conn;
    100
    101 /* Add the program name to arg[0] */
    102 if (fuse_opt_add_arg(&args, "test_signals")) {
    103 fprintf(stderr, "Failed to add argument\n");
    104 errx(1, "Failed to add argument");
    105 }
    106
    107
    108 se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
    109 assert(se);
    110 conn = &se->conn;
    111 printf("\nTesting basic want conversion, old style:\n");
    112 test_do_init(conn, false);
    114
    115 se = fuse_session_new(&args, &ops, sizeof(ops), NULL);
    116 assert(se);
    117 conn = &se->conn;
    118 printf("\nTesting basic want conversion, new style:\n");
    119 test_do_init(conn, true);
    120 print_conn_info("After init", conn);
    122
    123 fuse_opt_free_args(&args);
    124
    125}
    126
    127static void test_want_conversion_conflict(void)
    128{
    129 struct fuse_conn_info conn = { 0 };
    130 int rc;
    131
    132 printf("\nTesting want conversion conflict:\n");
    133
    134 /* Test conflicting values */
    135 /* Initialize like fuse_lowlevel.c does */
    139 conn.capable = fuse_lower_32_bits(conn.capable_ext);
    140 conn.want_ext = conn.capable_ext;
    141 conn.want = fuse_lower_32_bits(conn.want_ext);
    142 print_conn_info("Test conflict initial", &conn);
    143
    144 /* Simulate application init modifying capabilities */
    145 conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */
    146 conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */
    147
    149 assert(rc == -EINVAL);
    150 print_conn_info("Test conflict after", &conn);
    151
    152 printf("Want conversion conflict test passed\n");
    153}
    154
    155static void test_want_conversion_high_bits(void)
    156{
    157 struct fuse_conn_info conn = { 0 };
    158 int rc;
    159
    160 printf("\nTesting want conversion high bits preservation:\n");
    161
    162 /* Test high bits preservation */
    163 conn.want_ext = (1ULL << 33) | FUSE_CAP_ASYNC_READ;
    164 conn.want = fuse_lower_32_bits(conn.want_ext);
    165 print_conn_info("Test high bits initial", &conn);
    166
    168 assert(rc == 0);
    169 assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ));
    170 print_conn_info("Test high bits after", &conn);
    171
    172 printf("Want conversion high bits test passed\n");
    173}
    174
    175int main(void)
    176{
    177 test_want_conversion_basic();
    178 test_want_conversion_conflict();
    179 test_want_conversion_high_bits();
    180 return 0;
    181}
    #define FUSE_CAP_IOCTL_DIR
    void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_SPLICE_READ
    #define FUSE_CAP_ATOMIC_O_TRUNC
    #define FUSE_CAP_ASYNC_READ
    #define FUSE_CAP_SPLICE_WRITE
    #define FUSE_CAP_EXPORT_SUPPORT
    #define FUSE_CAP_POSIX_LOCKS
    #define FUSE_CAP_SPLICE_MOVE
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    uint64_t capable_ext
    uint32_t capable
    uint64_t want_ext
    fuse-3.18.3/doc/html/test__write__cache_8c_source.html0000644000175000017500000017037315250106404021711 0ustar berndbernd libfuse: test/test_write_cache.c Source File
    libfuse
    test_write_cache.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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    9#define FUSE_USE_VERSION 30
    10
    11/* Not really needed - just to test build with FUSE_USE_VERSION == 30 */
    12#include <fuse.h>
    13
    14#include <fuse_config.h>
    15#include <fuse_lowlevel.h>
    16#include <stdio.h>
    17#include <stdlib.h>
    18#include <string.h>
    19#include <errno.h>
    20#include <fcntl.h>
    21#include <assert.h>
    22#include <stddef.h>
    23#include <unistd.h>
    24#include <sys/stat.h>
    25#include <pthread.h>
    26#include <stdatomic.h>
    27
    28#ifndef __linux__
    29#include <limits.h>
    30#else
    31#include <linux/limits.h>
    32#endif
    33
    34#define FILE_INO 2
    35#define FILE_NAME "write_me"
    36
    37/* Command line parsing */
    38struct options {
    39 int writeback;
    40 int data_size;
    41 int delay_ms;
    42} options = {
    43 .writeback = 0,
    44 .data_size = 2048,
    45 .delay_ms = 0,
    46};
    47
    48#define WRITE_SYSCALLS 64
    49
    50#define OPTION(t, p) { t, offsetof(struct options, p), 1 }
    51static const struct fuse_opt option_spec[] = {
    52 OPTION("writeback_cache", writeback),
    53 OPTION("--data-size=%d", data_size), OPTION("--delay_ms=%d", delay_ms),
    55};
    56static int got_write;
    57static atomic_int write_cnt;
    58
    59pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    60pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    61static int write_start, write_done;
    62
    63static void tfs_init(void *userdata, struct fuse_conn_info *conn)
    64{
    65 (void)userdata;
    66
    67 if (options.writeback) {
    70 }
    71}
    72
    73static int tfs_stat(fuse_ino_t ino, struct stat *stbuf)
    74{
    75 stbuf->st_ino = ino;
    76 if (ino == FUSE_ROOT_ID) {
    77 stbuf->st_mode = S_IFDIR | 0755;
    78 stbuf->st_nlink = 1;
    79 }
    80
    81 else if (ino == FILE_INO) {
    82 stbuf->st_mode = S_IFREG | 0222;
    83 stbuf->st_nlink = 1;
    84 stbuf->st_size = 0;
    85 }
    86
    87 else
    88 return -1;
    89
    90 return 0;
    91}
    92
    93static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    94{
    95 struct fuse_entry_param e;
    96
    97 memset(&e, 0, sizeof(e));
    98
    99 if (parent != FUSE_ROOT_ID)
    100 goto err_out;
    101 else if (strcmp(name, FILE_NAME) == 0)
    102 e.ino = FILE_INO;
    103 else
    104 goto err_out;
    105
    106 if (tfs_stat(e.ino, &e.attr) != 0)
    107 goto err_out;
    108 fuse_reply_entry(req, &e);
    109 return;
    110
    111err_out:
    112 fuse_reply_err(req, ENOENT);
    113}
    114
    115static void tfs_getattr(fuse_req_t req, fuse_ino_t ino,
    116 struct fuse_file_info *fi)
    117{
    118 struct stat stbuf;
    119
    120 (void)fi;
    121
    122 memset(&stbuf, 0, sizeof(stbuf));
    123 if (tfs_stat(ino, &stbuf) != 0)
    124 fuse_reply_err(req, ENOENT);
    125 else
    126 fuse_reply_attr(req, &stbuf, 5);
    127}
    128
    129static void tfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
    130{
    131 if (ino == FUSE_ROOT_ID)
    132 fuse_reply_err(req, EISDIR);
    133 else {
    134 assert(ino == FILE_INO);
    135 /* Test close(rofd) does not block waiting for pending writes */
    136 fi->noflush = !options.writeback && options.delay_ms &&
    137 (fi->flags & O_ACCMODE) == O_RDONLY;
    138 fuse_reply_open(req, fi);
    139 }
    140}
    141
    142static void tfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
    143 size_t size, off_t off, struct fuse_file_info *fi)
    144{
    145 (void)fi;
    146 (void)buf;
    147 (void)off;
    148 size_t expected;
    149
    150 assert(ino == FILE_INO);
    151 expected = options.data_size;
    152 if (options.writeback)
    153 expected *= 2;
    154
    155 write_cnt++;
    156
    157 if (size != expected && !options.writeback)
    158 fprintf(stderr, "ERROR: Expected %zd bytes, got %zd\n!",
    159 expected, size);
    160 else
    161 got_write = 1;
    162
    163 /* Simulate waiting for pending writes */
    164 if (options.delay_ms) {
    165 pthread_mutex_lock(&lock);
    166 write_start = 1;
    167 pthread_cond_signal(&cond);
    168 pthread_mutex_unlock(&lock);
    169
    170 usleep(options.delay_ms * 1000);
    171
    172 pthread_mutex_lock(&lock);
    173 write_done = 1;
    174 pthread_cond_signal(&cond);
    175 pthread_mutex_unlock(&lock);
    176 }
    177
    178 fuse_reply_write(req, size);
    179}
    180
    181static struct fuse_lowlevel_ops tfs_oper = {
    182 .init = tfs_init,
    183 .lookup = tfs_lookup,
    184 .getattr = tfs_getattr,
    185 .open = tfs_open,
    186 .write = tfs_write,
    187};
    188
    189static void *close_rofd(void *data)
    190{
    191 int rofd = (int)(long)data;
    192
    193 /* Wait for first write to start */
    194 pthread_mutex_lock(&lock);
    195 while (!write_start && !write_done)
    196 pthread_cond_wait(&cond, &lock);
    197 pthread_mutex_unlock(&lock);
    198
    199 close(rofd);
    200 printf("rofd closed. write_start: %d write_done: %d\n", write_start,
    201 write_done);
    202
    203 /* First write should not have been completed */
    204 if (write_done)
    205 fprintf(stderr, "ERROR: close(rofd) blocked on write!\n");
    206
    207 return NULL;
    208}
    209
    210static void *run_fs(void *data)
    211{
    212 struct fuse_session *se = (struct fuse_session *)data;
    213
    214 assert(fuse_session_loop(se) == 0);
    215 return NULL;
    216}
    217
    218static void test_fs(char *mountpoint)
    219{
    220 char fname[PATH_MAX];
    221 char *buf;
    222 const size_t iosize = options.data_size;
    223 const size_t dsize = options.data_size * WRITE_SYSCALLS;
    224 int fd, rofd;
    225 pthread_t rofd_thread;
    226 off_t off = 0;
    227
    228 buf = malloc(dsize);
    229 assert(buf != NULL);
    230 assert((fd = open("/dev/urandom", O_RDONLY)) != -1);
    231 assert(read(fd, buf, dsize) == dsize);
    232 close(fd);
    233
    234 assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME, mountpoint) > 0);
    235 fd = open(fname, O_WRONLY);
    236 if (fd == -1) {
    237 perror(fname);
    238 assert(0);
    239 }
    240
    241 if (options.delay_ms) {
    242 /* Verify that close(rofd) does not block waiting for pending writes */
    243 rofd = open(fname, O_RDONLY);
    244 assert(pthread_create(&rofd_thread, NULL, close_rofd,
    245 (void *)(long)rofd) == 0);
    246 /* Give close_rofd time to start */
    247 usleep(options.delay_ms * 1000);
    248 }
    249
    250 for (int cnt = 0; cnt < WRITE_SYSCALLS; cnt++) {
    251 assert(pwrite(fd, buf + off, iosize, off) == iosize);
    252 off += iosize;
    253 assert(off <= dsize);
    254 }
    255 free(buf);
    256 close(fd);
    257
    258 if (options.delay_ms) {
    259 printf("rwfd closed. write_start: %d write_done: %d\n",
    260 write_start, write_done);
    261 assert(pthread_join(rofd_thread, NULL) == 0);
    262 }
    263}
    264
    265int main(int argc, char *argv[])
    266{
    267 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    268 struct fuse_session *se;
    269 struct fuse_cmdline_opts fuse_opts;
    270 pthread_t fs_thread;
    271
    272 assert(fuse_opt_parse(&args, &options, option_spec, NULL) == 0);
    273 assert(fuse_parse_cmdline(&args, &fuse_opts) == 0);
    274#ifndef __FreeBSD__
    275 assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0);
    276#endif
    277 se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL);
    278 fuse_opt_free_args(&args);
    279 assert(se != NULL);
    280 assert(fuse_set_signal_handlers(se) == 0);
    281 assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0);
    282
    283 /* Start file-system thread */
    284 assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0);
    285
    286 /* Write test data */
    287 test_fs(fuse_opts.mountpoint);
    288 free(fuse_opts.mountpoint);
    289
    290 /* Stop file system */
    293 assert(pthread_join(fs_thread, NULL) == 0);
    294
    295 assert(got_write == 1);
    296
    297 /*
    298 * when writeback cache is enabled, kernel side can merge requests, but
    299 * memory pressure, system 'sync' might trigger data flushes before - flush
    300 * might happen in between write syscalls - merging subpage writes into
    301 * a single page and pages into large fuse requests might or might not work.
    302 * Though we can expect that that at least some (but maybe all) write
    303 * system calls can be merged.
    304 */
    305 if (options.writeback)
    306 assert(write_cnt < WRITE_SYSCALLS);
    307 else
    308 assert(write_cnt == WRITE_SYSCALLS);
    309
    312
    313 printf("Test completed successfully.\n");
    314 return 0;
    315}
    316
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_WRITEBACK_CACHE
    bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    void fuse_remove_signal_handlers(struct fuse_session *se)
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    uint64_t fuse_ino_t
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    fuse_ino_t ino
    uint32_t noflush
    Definition fuse_common.h:93
    fuse-3.18.3/doc/html/fusermount_8c_source.html0000644000175000017500000102542415250106404020303 0ustar berndbernd 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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8/* This program does the mounting and unmounting of FUSE filesystems */
    9
    10#define _GNU_SOURCE /* for clone,strchrnul and close_range */
    11#include "fuse_config.h"
    12#include "mount_util.h"
    13#include "util.h"
    14
    15#include <stdio.h>
    16#include <stdlib.h>
    17#include <string.h>
    18#include <ctype.h>
    19#include <unistd.h>
    20#include <getopt.h>
    21#include <errno.h>
    22#include <fcntl.h>
    23#include <pwd.h>
    24#include <paths.h>
    25#include <mntent.h>
    26#include <sys/wait.h>
    27#include <sys/stat.h>
    28#include <sys/param.h>
    29
    30#include "fuse_mount_compat.h"
    31
    32#include <sys/fsuid.h>
    33#include <sys/socket.h>
    34#include <sys/utsname.h>
    35#include <sched.h>
    36#include <stdbool.h>
    37#include <sys/vfs.h>
    38
    39#if defined HAVE_CLOSE_RANGE && defined linux
    40#include <linux/close_range.h>
    41#endif
    42
    43#if defined HAVE_LISTMOUNT
    44#include <linux/mount.h>
    45#include <syscall.h>
    46#include <stdint.h>
    47#endif
    48
    49#define FUSE_COMMFD_ENV "_FUSE_COMMFD"
    50#define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE"
    51
    52#define FUSE_DEV "/dev/fuse"
    53
    54static const char *progname;
    55
    56static int user_allow_other = 0;
    57static int mount_max = 1000;
    58
    59static int auto_unmount = 0;
    60
    61#ifdef GETMNTENT_NEEDS_UNESCAPING
    62// Older versions of musl libc don't unescape entries in /etc/mtab
    63
    64// unescapes octal sequences like \040 in-place
    65// That's ok, because unescaping can not extend the length of the string.
    66static void unescape(char *buf) {
    67 char *src = buf;
    68 char *dest = buf;
    69 while (1) {
    70 char *next_src = strchrnul(src, '\\');
    71 int offset = next_src - src;
    72 memmove(dest, src, offset);
    73 src = next_src;
    74 dest += offset;
    75
    76 if(*src == '\0') {
    77 *dest = *src;
    78 return;
    79 }
    80 src++;
    81
    82 if('0' <= src[0] && src[0] < '2' &&
    83 '0' <= src[1] && src[1] < '8' &&
    84 '0' <= src[2] && src[2] < '8') {
    85 *dest++ = (src[0] - '0') << 6
    86 | (src[1] - '0') << 3
    87 | (src[2] - '0') << 0;
    88 src += 3;
    89 } else if (src[0] == '\\') {
    90 *dest++ = '\\';
    91 src += 1;
    92 } else {
    93 *dest++ = '\\';
    94 }
    95 }
    96}
    97
    98static struct mntent *GETMNTENT(FILE *stream)
    99{
    100 struct mntent *entp = getmntent(stream);
    101 if(entp != NULL) {
    102 unescape(entp->mnt_fsname);
    103 unescape(entp->mnt_dir);
    104 unescape(entp->mnt_type);
    105 unescape(entp->mnt_opts);
    106 }
    107 return entp;
    108}
    109#else
    110#define GETMNTENT getmntent
    111#endif // GETMNTENT_NEEDS_UNESCAPING
    112
    113/*
    114 * Take a ',' separated option string and extract "x-" options
    115 */
    116static int extract_x_options(const char *original, char **non_x_opts,
    117 char **x_opts)
    118{
    119 size_t orig_len;
    120 const char *opt, *opt_end;
    121
    122 orig_len = strlen(original) + 1;
    123
    124 *non_x_opts = calloc(1, orig_len);
    125 *x_opts = calloc(1, orig_len);
    126
    127 size_t non_x_opts_len = orig_len;
    128 size_t x_opts_len = orig_len;
    129
    130 if (*non_x_opts == NULL || *x_opts == NULL) {
    131 fprintf(stderr, "%s: Failed to allocate %zuB.\n",
    132 __func__, orig_len);
    133 return -ENOMEM;
    134 }
    135
    136 for (opt = original; opt < original + orig_len; opt = opt_end + 1) {
    137 char *opt_buf;
    138
    139 opt_end = strchr(opt, ',');
    140 if (opt_end == NULL)
    141 opt_end = original + orig_len;
    142
    143 size_t opt_len = opt_end - opt;
    144 size_t opt_len_left = orig_len - (opt - original);
    145 size_t buf_len;
    146 bool is_x_opts;
    147
    148 if (strncmp(opt, "x-", MIN(2, opt_len_left)) == 0) {
    149 buf_len = x_opts_len;
    150 is_x_opts = true;
    151 opt_buf = *x_opts;
    152 } else {
    153 buf_len = non_x_opts_len;
    154 is_x_opts = false;
    155 opt_buf = *non_x_opts;
    156 }
    157
    158 if (buf_len < orig_len) {
    159 strncat(opt_buf, ",", 2);
    160 buf_len -= 1;
    161 }
    162
    163 /* omits ',' */
    164 if ((ssize_t)(buf_len - opt_len) < 0) {
    165 /* This would be a bug */
    166 fprintf(stderr, "%s: no buf space left in copy, orig='%s'\n",
    167 __func__, original);
    168 return -EIO;
    169 }
    170
    171 strncat(opt_buf, opt, opt_end - opt);
    172 buf_len -= opt_len;
    173
    174 if (is_x_opts)
    175 x_opts_len = buf_len;
    176 else
    177 non_x_opts_len = buf_len;
    178 }
    179
    180 return 0;
    181}
    182
    183static const char *get_user_name(void)
    184{
    185 struct passwd *pw = getpwuid(getuid());
    186 if (pw != NULL && pw->pw_name != NULL)
    187 return pw->pw_name;
    188 else {
    189 fprintf(stderr, "%s: could not determine username\n", progname);
    190 return NULL;
    191 }
    192}
    193
    194static uid_t oldfsuid;
    195static gid_t oldfsgid;
    196
    197static void drop_privs(void)
    198{
    199 if (getuid() != 0) {
    200 oldfsuid = setfsuid(getuid());
    201 oldfsgid = setfsgid(getgid());
    202 }
    203}
    204
    205static void restore_privs(void)
    206{
    207 if (getuid() != 0) {
    208 setfsuid(oldfsuid);
    209 setfsgid(oldfsgid);
    210 }
    211}
    212
    213#ifndef IGNORE_MTAB
    214/*
    215 * Make sure that /etc/mtab is checked and updated atomically
    216 */
    217static int lock_umount(void)
    218{
    219 const char *mtab_lock = _PATH_MOUNTED ".fuselock";
    220 int mtablock;
    221 int res;
    222 struct stat mtab_stat;
    223
    224 /* /etc/mtab could be a symlink to /proc/mounts */
    225 if (lstat(_PATH_MOUNTED, &mtab_stat) == 0 && S_ISLNK(mtab_stat.st_mode))
    226 return -1;
    227
    228 mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
    229 if (mtablock == -1) {
    230 fprintf(stderr, "%s: unable to open fuse lock file: %s\n",
    231 progname, strerror(errno));
    232 return -1;
    233 }
    234 res = lockf(mtablock, F_LOCK, 0);
    235 if (res < 0) {
    236 fprintf(stderr, "%s: error getting lock: %s\n", progname,
    237 strerror(errno));
    238 close(mtablock);
    239 return -1;
    240 }
    241
    242 return mtablock;
    243}
    244
    245static void unlock_umount(int mtablock)
    246{
    247 if (mtablock >= 0) {
    248 int res;
    249
    250 res = lockf(mtablock, F_ULOCK, 0);
    251 if (res < 0) {
    252 fprintf(stderr, "%s: error releasing lock: %s\n",
    253 progname, strerror(errno));
    254 }
    255 close(mtablock);
    256 }
    257}
    258
    259static int add_mount(const char *source, const char *mnt, const char *type,
    260 const char *opts)
    261{
    262 return fuse_mnt_add_mount(progname, source, mnt, type, opts);
    263}
    264
    265static int may_unmount(const char *mnt, int quiet)
    266{
    267 struct mntent *entp;
    268 FILE *fp;
    269 const char *user = NULL;
    270 char uidstr[32];
    271 unsigned uidlen = 0;
    272 int found;
    273 const char *mtab = _PATH_MOUNTED;
    274
    275 user = get_user_name();
    276 if (user == NULL)
    277 return -1;
    278
    279 fp = setmntent(mtab, "r");
    280 if (fp == NULL) {
    281 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
    282 strerror(errno));
    283 return -1;
    284 }
    285
    286 uidlen = sprintf(uidstr, "%u", getuid());
    287
    288 found = 0;
    289 while ((entp = GETMNTENT(fp)) != NULL) {
    290 if (!found && strcmp(entp->mnt_dir, mnt) == 0 &&
    291 (strcmp(entp->mnt_type, "fuse") == 0 ||
    292 strcmp(entp->mnt_type, "fuseblk") == 0 ||
    293 strncmp(entp->mnt_type, "fuse.", 5) == 0 ||
    294 strncmp(entp->mnt_type, "fuseblk.", 8) == 0)) {
    295 char *p = strstr(entp->mnt_opts, "user=");
    296 if (p &&
    297 (p == entp->mnt_opts || *(p-1) == ',') &&
    298 strcmp(p + 5, user) == 0) {
    299 found = 1;
    300 break;
    301 }
    302 /* /etc/mtab is a link pointing to
    303 /proc/mounts: */
    304 else if ((p =
    305 strstr(entp->mnt_opts, "user_id=")) &&
    306 (p == entp->mnt_opts ||
    307 *(p-1) == ',') &&
    308 strncmp(p + 8, uidstr, uidlen) == 0 &&
    309 (*(p+8+uidlen) == ',' ||
    310 *(p+8+uidlen) == '\0')) {
    311 found = 1;
    312 break;
    313 }
    314 }
    315 }
    316 endmntent(fp);
    317
    318 if (!found) {
    319 if (!quiet)
    320 fprintf(stderr,
    321 "%s: entry for %s not found in %s\n",
    322 progname, mnt, mtab);
    323 return -1;
    324 }
    325
    326 return 0;
    327}
    328#endif
    329
    330/*
    331 * Check whether the file specified in "fusermount3 -u" is really a
    332 * mountpoint and not a symlink. This is necessary otherwise the user
    333 * could move the mountpoint away and replace it with a symlink
    334 * pointing to an arbitrary mount, thereby tricking fusermount3 into
    335 * unmounting that (umount(2) will follow symlinks).
    336 *
    337 * This is the child process running in a separate mount namespace, so
    338 * we don't mess with the global namespace and if the process is
    339 * killed for any reason, mounts are automatically cleaned up.
    340 *
    341 * First make sure nothing is propagated back into the parent
    342 * namespace by marking all mounts "private".
    343 *
    344 * Then bind mount parent onto a stable base where the user can't move
    345 * it around.
    346 *
    347 * Finally check /proc/mounts for an entry matching the requested
    348 * mountpoint. If it's found then we are OK, and the user can't move
    349 * it around within the parent directory as rename() will return
    350 * EBUSY. Be careful to ignore any mounts that existed before the
    351 * bind.
    352 */
    353static int check_is_mount_child(void *p)
    354{
    355 const char **a = p;
    356 const char *last = a[0];
    357 const char *mnt = a[1];
    358 const char *type = a[2];
    359 int res;
    360 const char *procmounts = "/proc/mounts";
    361 int found;
    362 FILE *fp;
    363 struct mntent *entp;
    364 int count;
    365
    366 res = mount("", "/", "", MS_PRIVATE | MS_REC, NULL);
    367 if (res == -1) {
    368 fprintf(stderr, "%s: failed to mark mounts private: %s\n",
    369 progname, strerror(errno));
    370 return 1;
    371 }
    372
    373 fp = setmntent(procmounts, "r");
    374 if (fp == NULL) {
    375 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
    376 procmounts, strerror(errno));
    377 return 1;
    378 }
    379
    380 count = 0;
    381 while (GETMNTENT(fp) != NULL)
    382 count++;
    383 endmntent(fp);
    384
    385 fp = setmntent(procmounts, "r");
    386 if (fp == NULL) {
    387 fprintf(stderr, "%s: failed to open %s: %s\n", progname,
    388 procmounts, strerror(errno));
    389 return 1;
    390 }
    391
    392 res = mount(".", "/", "", MS_BIND | MS_REC, NULL);
    393 if (res == -1) {
    394 fprintf(stderr, "%s: failed to bind parent to /: %s\n",
    395 progname, strerror(errno));
    396 return 1;
    397 }
    398
    399 found = 0;
    400 while ((entp = GETMNTENT(fp)) != NULL) {
    401 if (count > 0) {
    402 count--;
    403 continue;
    404 }
    405 if (entp->mnt_dir[0] == '/' &&
    406 strcmp(entp->mnt_dir + 1, last) == 0 &&
    407 (!type || strcmp(entp->mnt_type, type) == 0)) {
    408 found = 1;
    409 break;
    410 }
    411 }
    412 endmntent(fp);
    413
    414 if (!found) {
    415 fprintf(stderr, "%s: %s not mounted\n", progname, mnt);
    416 return 1;
    417 }
    418
    419 return 0;
    420}
    421
    422static pid_t clone_newns(void *a)
    423{
    424 char buf[131072];
    425 char *stack = buf + (sizeof(buf) / 2 - ((size_t) buf & 15));
    426
    427#ifdef __ia64__
    428 extern int __clone2(int (*fn)(void *),
    429 void *child_stack_base, size_t stack_size,
    430 int flags, void *arg, pid_t *ptid,
    431 void *tls, pid_t *ctid);
    432
    433 return __clone2(check_is_mount_child, stack, sizeof(buf) / 2,
    434 CLONE_NEWNS, a, NULL, NULL, NULL);
    435#else
    436 return clone(check_is_mount_child, stack, CLONE_NEWNS, a);
    437#endif
    438}
    439
    440static int check_is_mount(const char *last, const char *mnt, const char *type)
    441{
    442 pid_t pid, p;
    443 int status;
    444 const char *a[3] = { last, mnt, type };
    445
    446 pid = clone_newns((void *) a);
    447 if (pid == (pid_t) -1) {
    448 fprintf(stderr, "%s: failed to clone namespace: %s\n",
    449 progname, strerror(errno));
    450 return -1;
    451 }
    452 p = waitpid(pid, &status, __WCLONE);
    453 if (p == (pid_t) -1) {
    454 fprintf(stderr, "%s: waitpid failed: %s\n",
    455 progname, strerror(errno));
    456 return -1;
    457 }
    458 if (!WIFEXITED(status)) {
    459 fprintf(stderr, "%s: child terminated abnormally (status %i)\n",
    460 progname, status);
    461 return -1;
    462 }
    463 if (WEXITSTATUS(status) != 0)
    464 return -1;
    465
    466 return 0;
    467}
    468
    469static int chdir_to_parent(char *copy, const char **lastp)
    470{
    471 char *tmp;
    472 const char *parent;
    473 char buf[65536];
    474 int res;
    475
    476 tmp = strrchr(copy, '/');
    477 if (tmp == NULL || tmp[1] == '\0') {
    478 fprintf(stderr, "%s: internal error: invalid abs path: <%s>\n",
    479 progname, copy);
    480 return -1;
    481 }
    482 if (tmp != copy) {
    483 *tmp = '\0';
    484 parent = copy;
    485 *lastp = tmp + 1;
    486 } else if (tmp[1] != '\0') {
    487 *lastp = tmp + 1;
    488 parent = "/";
    489 } else {
    490 *lastp = ".";
    491 parent = "/";
    492 }
    493
    494 res = chdir(parent);
    495 if (res == -1) {
    496 fprintf(stderr, "%s: failed to chdir to %s: %s\n",
    497 progname, parent, strerror(errno));
    498 return -1;
    499 }
    500
    501 if (getcwd(buf, sizeof(buf)) == NULL) {
    502 fprintf(stderr, "%s: failed to obtain current directory: %s\n",
    503 progname, strerror(errno));
    504 return -1;
    505 }
    506 if (strcmp(buf, parent) != 0) {
    507 fprintf(stderr, "%s: mountpoint moved (%s -> %s)\n", progname,
    508 parent, buf);
    509 return -1;
    510
    511 }
    512
    513 return 0;
    514}
    515
    516#ifndef IGNORE_MTAB
    517static int unmount_fuse_locked(const char *mnt, int quiet, int lazy)
    518{
    519 int res;
    520 char *copy;
    521 const char *last;
    522 int umount_flags = (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW;
    523
    524 if (getuid() != 0) {
    525 res = may_unmount(mnt, quiet);
    526 if (res == -1)
    527 return -1;
    528 }
    529
    530 copy = strdup(mnt);
    531 if (copy == NULL) {
    532 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    533 return -1;
    534 }
    535
    536 drop_privs();
    537 res = chdir_to_parent(copy, &last);
    538 if (res == -1) {
    539 restore_privs();
    540 goto out;
    541 }
    542
    543 res = umount2(last, umount_flags);
    544 restore_privs();
    545 if (res == -1 && !quiet) {
    546 fprintf(stderr, "%s: failed to unmount %s: %s\n",
    547 progname, mnt, strerror(errno));
    548 }
    549
    550out:
    551 free(copy);
    552 if (res == -1)
    553 return -1;
    554
    555 res = chdir("/");
    556 if (res == -1) {
    557 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
    558 return -1;
    559 }
    560
    561 return fuse_mnt_remove_mount(progname, mnt);
    562}
    563
    564static int unmount_fuse(const char *mnt, int quiet, int lazy)
    565{
    566 int res;
    567 int mtablock = lock_umount();
    568
    569 res = unmount_fuse_locked(mnt, quiet, lazy);
    570 unlock_umount(mtablock);
    571
    572 return res;
    573}
    574
    575static int count_fuse_fs_mtab(void)
    576{
    577 struct mntent *entp;
    578 int count = 0;
    579 const char *mtab = _PATH_MOUNTED;
    580 FILE *fp = setmntent(mtab, "r");
    581 if (fp == NULL) {
    582 fprintf(stderr, "%s: failed to open %s: %s\n", progname, mtab,
    583 strerror(errno));
    584 return -1;
    585 }
    586 while ((entp = GETMNTENT(fp)) != NULL) {
    587 if (strcmp(entp->mnt_type, "fuse") == 0 ||
    588 strncmp(entp->mnt_type, "fuse.", 5) == 0)
    589 count ++;
    590 }
    591 endmntent(fp);
    592 return count;
    593}
    594
    595#ifdef HAVE_LISTMOUNT
    596static int count_fuse_fs_ls_mnt(void)
    597{
    598 #define SMBUF_SIZE 1024
    599 #define MNT_ID_LEN 128
    600
    601 int fuse_count = 0;
    602 int n_mounts = 0;
    603 int ret = 0;
    604 uint64_t mnt_ids[MNT_ID_LEN];
    605 unsigned char smbuf[SMBUF_SIZE];
    606 struct mnt_id_req req = {
    607 .size = sizeof(struct mnt_id_req),
    608 };
    609 struct statmount *sm;
    610
    611 for (;;) {
    612 req.mnt_id = LSMT_ROOT;
    613
    614 n_mounts = syscall(SYS_listmount, &req, &mnt_ids, MNT_ID_LEN, 0);
    615 if (n_mounts == -1) {
    616 if (errno != ENOSYS) {
    617 fprintf(stderr, "%s: failed to list mounts: %s\n", progname,
    618 strerror(errno));
    619 }
    620 return -1;
    621 }
    622
    623 for (int i = 0; i < n_mounts; i++) {
    624 req.mnt_id = mnt_ids[i];
    625 req.param = STATMOUNT_FS_TYPE;
    626 ret = syscall(SYS_statmount, &req, &smbuf, SMBUF_SIZE, 0);
    627 if (ret) {
    628 if (errno == ENOENT)
    629 continue;
    630
    631 fprintf(stderr, "%s: failed to stat mount %lld: %s\n", progname,
    632 req.mnt_id, strerror(errno));
    633 return -1;
    634 }
    635
    636 sm = (struct statmount *)smbuf;
    637 if (sm->mask & STATMOUNT_FS_TYPE &&
    638 strcmp(&sm->str[sm->fs_type], "fuse") == 0)
    639 fuse_count++;
    640 }
    641
    642 if (n_mounts < MNT_ID_LEN)
    643 break;
    644 req.param = mnt_ids[MNT_ID_LEN - 1];
    645 }
    646 return fuse_count;
    647}
    648
    649static int count_fuse_fs(void)
    650{
    651 int count = count_fuse_fs_ls_mnt();
    652
    653 return count >= 0 ? count : count_fuse_fs_mtab();
    654}
    655#else
    656static int count_fuse_fs(void)
    657{
    658 return count_fuse_fs_mtab();
    659}
    660#endif
    661
    662#else /* IGNORE_MTAB */
    663static int count_fuse_fs(void)
    664{
    665 return 0;
    666}
    667
    668static int add_mount(const char *source, const char *mnt, const char *type,
    669 const char *opts)
    670{
    671 (void) source;
    672 (void) mnt;
    673 (void) type;
    674 (void) opts;
    675 return 0;
    676}
    677
    678static int unmount_fuse(const char *mnt, int quiet, int lazy)
    679{
    680 (void) quiet;
    681 return fuse_mnt_umount(progname, mnt, mnt, lazy);
    682}
    683#endif /* IGNORE_MTAB */
    684
    685static void strip_line(char *line)
    686{
    687 char *s = strchr(line, '#');
    688 size_t len;
    689
    690 if (s != NULL)
    691 s[0] = '\0';
    692 /*
    693 * Count down rather than walk a pointer back: an empty or all-blank
    694 * line would form line - 1, which is undefined behaviour even though
    695 * the store that follows lands inside the buffer.
    696 */
    697 len = strlen(line);
    698 while (len > 0 && isspace((unsigned char) line[len - 1]))
    699 len--;
    700 line[len] = '\0';
    701 for (s = line; isspace((unsigned char) *s); s++);
    702 if (s != line)
    703 memmove(line, s, strlen(s)+1);
    704}
    705
    706static void parse_line(char *line, int linenum)
    707{
    708 int tmp;
    709 if (strcmp(line, "user_allow_other") == 0)
    710 user_allow_other = 1;
    711 else if (sscanf(line, "mount_max = %i", &tmp) == 1) {
    712 if (tmp < -1)
    713 fprintf(stderr,
    714 "%s: invalid mount_max = %i in %s at line %i\n",
    715 progname, tmp, FUSE_CONF, linenum);
    716 else
    717 mount_max = tmp;
    718 }
    719 else if(line[0])
    720 fprintf(stderr,
    721 "%s: unknown parameter in %s at line %i: '%s'\n",
    722 progname, FUSE_CONF, linenum, line);
    723}
    724
    725static void read_conf(void)
    726{
    727 FILE *fp = fopen(FUSE_CONF, "r");
    728 if (fp != NULL) {
    729 int linenum = 1;
    730 char line[256];
    731 int isnewline = 1;
    732 while (fgets(line, sizeof(line), fp) != NULL) {
    733 if (isnewline) {
    734 if (line[strlen(line)-1] == '\n') {
    735 strip_line(line);
    736 parse_line(line, linenum);
    737 } else {
    738 isnewline = 0;
    739 }
    740 } else if(line[strlen(line)-1] == '\n') {
    741 fprintf(stderr, "%s: reading %s: line %i too long\n", progname, FUSE_CONF, linenum);
    742
    743 isnewline = 1;
    744 }
    745 if (isnewline)
    746 linenum ++;
    747 }
    748 if (!isnewline) {
    749 fprintf(stderr, "%s: reading %s: missing newline at end of file\n", progname, FUSE_CONF);
    750
    751 }
    752 if (ferror(fp)) {
    753 fprintf(stderr, "%s: reading %s: read failed\n", progname, FUSE_CONF);
    754 exit(1);
    755 }
    756 fclose(fp);
    757 } else if (errno != ENOENT) {
    758 bool fatal = (errno != EACCES && errno != ELOOP &&
    759 errno != ENAMETOOLONG && errno != ENOTDIR &&
    760 errno != EOVERFLOW);
    761 fprintf(stderr, "%s: failed to open %s: %s\n",
    762 progname, FUSE_CONF, strerror(errno));
    763 if (fatal)
    764 exit(1);
    765 }
    766}
    767
    768static int begins_with(const char *s, const char *beg)
    769{
    770 if (strncmp(s, beg, strlen(beg)) == 0)
    771 return 1;
    772 else
    773 return 0;
    774}
    775
    776struct mount_flags {
    777 const char *opt;
    778 unsigned long flag;
    779 int on;
    780 int safe;
    781};
    782
    783static struct mount_flags mount_flags[] = {
    784 {"rw", MS_RDONLY, 0, 1},
    785 {"ro", MS_RDONLY, 1, 1},
    786 {"suid", MS_NOSUID, 0, 0},
    787 {"nosuid", MS_NOSUID, 1, 1},
    788 {"dev", MS_NODEV, 0, 0},
    789 {"nodev", MS_NODEV, 1, 1},
    790 {"exec", MS_NOEXEC, 0, 1},
    791 {"noexec", MS_NOEXEC, 1, 1},
    792 {"async", MS_SYNCHRONOUS, 0, 1},
    793 {"sync", MS_SYNCHRONOUS, 1, 1},
    794 {"atime", MS_NOATIME, 0, 1},
    795 {"noatime", MS_NOATIME, 1, 1},
    796 {"diratime", MS_NODIRATIME, 0, 1},
    797 {"nodiratime", MS_NODIRATIME, 1, 1},
    798 {"lazytime", MS_LAZYTIME, 1, 1},
    799 {"nolazytime", MS_LAZYTIME, 0, 1},
    800 {"relatime", MS_RELATIME, 1, 1},
    801 {"norelatime", MS_RELATIME, 0, 1},
    802 {"strictatime", MS_STRICTATIME, 1, 1},
    803 {"nostrictatime", MS_STRICTATIME, 0, 1},
    804 {"dirsync", MS_DIRSYNC, 1, 1},
    805 {"symfollow", MS_NOSYMFOLLOW, 0, 1},
    806 {"nosymfollow", MS_NOSYMFOLLOW, 1, 1},
    807 {NULL, 0, 0, 0}
    808};
    809
    810static int find_mount_flag(const char *s, unsigned len, int *on, int *flag)
    811{
    812 int i;
    813
    814 for (i = 0; mount_flags[i].opt != NULL; i++) {
    815 const char *opt = mount_flags[i].opt;
    816 if (strlen(opt) == len && strncmp(opt, s, len) == 0) {
    817 *on = mount_flags[i].on;
    818 *flag = mount_flags[i].flag;
    819 if (!mount_flags[i].safe && getuid() != 0) {
    820 *flag = 0;
    821 fprintf(stderr,
    822 "%s: unsafe option %s ignored\n",
    823 progname, opt);
    824 }
    825 return 1;
    826 }
    827 }
    828 return 0;
    829}
    830
    831static int add_option(char **optsp, const char *opt, unsigned expand)
    832{
    833 char *newopts;
    834 if (*optsp == NULL)
    835 newopts = strdup(opt);
    836 else {
    837 unsigned oldsize = strlen(*optsp);
    838 unsigned newsize = oldsize + 1 + strlen(opt) + expand + 1;
    839 newopts = (char *) realloc(*optsp, newsize);
    840 if (newopts)
    841 sprintf(newopts + oldsize, ",%s", opt);
    842 }
    843 if (newopts == NULL) {
    844 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    845 return -1;
    846 }
    847 *optsp = newopts;
    848 return 0;
    849}
    850
    851static int get_mnt_opts(int flags, char *opts, char **mnt_optsp)
    852{
    853 int i;
    854 int l;
    855
    856 if (!(flags & MS_RDONLY) && add_option(mnt_optsp, "rw", 0) == -1)
    857 return -1;
    858
    859 for (i = 0; mount_flags[i].opt != NULL; i++) {
    860 if (mount_flags[i].on && (flags & mount_flags[i].flag) &&
    861 add_option(mnt_optsp, mount_flags[i].opt, 0) == -1)
    862 return -1;
    863 }
    864
    865 if (add_option(mnt_optsp, opts, 0) == -1)
    866 return -1;
    867 /* remove comma from end of opts*/
    868 l = strlen(*mnt_optsp);
    869 if (l > 0 && (*mnt_optsp)[l-1] == ',')
    870 (*mnt_optsp)[l-1] = '\0';
    871 if (getuid() != 0) {
    872 const char *user = get_user_name();
    873 if (user == NULL)
    874 return -1;
    875
    876 if (add_option(mnt_optsp, "user=", strlen(user)) == -1)
    877 return -1;
    878 strcat(*mnt_optsp, user);
    879 }
    880 return 0;
    881}
    882
    883static int opt_eq(const char *s, unsigned len, const char *opt)
    884{
    885 if(strlen(opt) == len && strncmp(s, opt, len) == 0)
    886 return 1;
    887 else
    888 return 0;
    889}
    890
    891static int get_string_opt(const char *s, unsigned len, const char *opt,
    892 char **val)
    893{
    894 int i;
    895 unsigned opt_len = strlen(opt);
    896 char *d;
    897
    898 if (*val)
    899 free(*val);
    900 *val = (char *) malloc(len - opt_len + 1);
    901 if (!*val) {
    902 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    903 return 0;
    904 }
    905
    906 d = *val;
    907 s += opt_len;
    908 len -= opt_len;
    909 for (i = 0; i < len; i++) {
    910 if (s[i] == '\\' && i + 1 < len)
    911 i++;
    912 *d++ = s[i];
    913 }
    914 *d = '\0';
    915 return 1;
    916}
    917
    918/* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters.
    919 * This can be dangerous if it e.g. truncates the option "group_id=1000" to
    920 * "group_id=1".
    921 * This wrapper detects this case and bails out with an error.
    922 */
    923static int mount_notrunc(const char *source, const char *target,
    924 const char *filesystemtype, unsigned long mountflags,
    925 const char *data) {
    926 if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) {
    927 fprintf(stderr, "%s: mount options too long\n", progname);
    928 errno = EINVAL;
    929 return -1;
    930 }
    931 return mount(source, target, filesystemtype, mountflags, data);
    932}
    933
    934
    935static int do_mount(const char *mnt, const char **typep, mode_t rootmode,
    936 int fd, const char *opts, const char *dev, char **sourcep,
    937 char **mnt_optsp)
    938{
    939 int res;
    940 int flags = MS_NOSUID | MS_NODEV;
    941 char *optbuf;
    942 char *mnt_opts = NULL;
    943 const char *s;
    944 char *d;
    945 char *fsname = NULL;
    946 char *subtype = NULL;
    947 char *source = NULL;
    948 char *type = NULL;
    949 int blkdev = 0;
    950
    951 optbuf = (char *) malloc(strlen(opts) + 128);
    952 if (!optbuf) {
    953 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    954 return -1;
    955 }
    956
    957 for (s = opts, d = optbuf; *s;) {
    958 unsigned len;
    959 const char *fsname_str = "fsname=";
    960 const char *subtype_str = "subtype=";
    961 bool escape_ok = begins_with(s, fsname_str) ||
    962 begins_with(s, subtype_str);
    963 for (len = 0; s[len]; len++) {
    964 if (escape_ok && s[len] == '\\' && s[len + 1])
    965 len++;
    966 else if (s[len] == ',')
    967 break;
    968 }
    969 if (begins_with(s, fsname_str)) {
    970 if (!get_string_opt(s, len, fsname_str, &fsname))
    971 goto err;
    972 } else if (begins_with(s, subtype_str)) {
    973 if (!get_string_opt(s, len, subtype_str, &subtype))
    974 goto err;
    975 } else if (opt_eq(s, len, "blkdev")) {
    976 if (getuid() != 0) {
    977 fprintf(stderr,
    978 "%s: option blkdev is privileged\n",
    979 progname);
    980 goto err;
    981 }
    982 blkdev = 1;
    983 } else if (opt_eq(s, len, "auto_unmount")) {
    984 auto_unmount = 1;
    985 } else if (!opt_eq(s, len, "nonempty") &&
    986 !begins_with(s, "fd=") &&
    987 !begins_with(s, "rootmode=") &&
    988 !begins_with(s, "user_id=") &&
    989 !begins_with(s, "group_id=")) {
    990 int on;
    991 int flag;
    992 int skip_option = 0;
    993 if (opt_eq(s, len, "large_read")) {
    994 struct utsname utsname;
    995 unsigned kmaj, kmin;
    996 res = uname(&utsname);
    997 if (res == 0 &&
    998 sscanf(utsname.release, "%u.%u",
    999 &kmaj, &kmin) == 2 &&
    1000 (kmaj > 2 || (kmaj == 2 && kmin > 4))) {
    1001 fprintf(stderr, "%s: note: 'large_read' mount option is deprecated for %i.%i kernels\n", progname, kmaj, kmin);
    1002 skip_option = 1;
    1003 }
    1004 }
    1005 if (getuid() != 0 && !user_allow_other &&
    1006 (opt_eq(s, len, "allow_other") ||
    1007 opt_eq(s, len, "allow_root"))) {
    1008 fprintf(stderr, "%s: option %.*s only allowed if 'user_allow_other' is set in %s\n", progname, len, s, FUSE_CONF);
    1009 goto err;
    1010 }
    1011 if (!skip_option) {
    1012 if (find_mount_flag(s, len, &on, &flag)) {
    1013 if (on)
    1014 flags |= flag;
    1015 else
    1016 flags &= ~flag;
    1017 } else if (opt_eq(s, len, "default_permissions") ||
    1018 opt_eq(s, len, "allow_other") ||
    1019 begins_with(s, "max_read=") ||
    1020 begins_with(s, "blksize=")) {
    1021 memcpy(d, s, len);
    1022 d += len;
    1023 *d++ = ',';
    1024 } else {
    1025 fprintf(stderr, "%s: unknown option '%.*s'\n", progname, len, s);
    1026 exit(1);
    1027 }
    1028 }
    1029 }
    1030 s += len;
    1031 if (*s)
    1032 s++;
    1033 }
    1034 *d = '\0';
    1035 res = get_mnt_opts(flags, optbuf, &mnt_opts);
    1036 if (res == -1)
    1037 goto err;
    1038
    1039 sprintf(d, "fd=%i,rootmode=%o,user_id=%u,group_id=%u",
    1040 fd, rootmode, getuid(), getgid());
    1041
    1042 source = malloc((fsname ? strlen(fsname) : 0) +
    1043 (subtype ? strlen(subtype) : 0) + strlen(dev) + 32);
    1044
    1045 type = malloc((subtype ? strlen(subtype) : 0) + 32);
    1046 if (!type || !source) {
    1047 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    1048 goto err;
    1049 }
    1050
    1051 if (subtype)
    1052 sprintf(type, "%s.%s", blkdev ? "fuseblk" : "fuse", subtype);
    1053 else
    1054 strcpy(type, blkdev ? "fuseblk" : "fuse");
    1055
    1056 if (fsname)
    1057 strcpy(source, fsname);
    1058 else
    1059 strcpy(source, subtype ? subtype : dev);
    1060
    1061 res = mount_notrunc(source, mnt, type, flags, optbuf);
    1062 if (res == -1 && errno == ENODEV && subtype) {
    1063 /* Probably missing subtype support */
    1064 strcpy(type, blkdev ? "fuseblk" : "fuse");
    1065 if (fsname) {
    1066 if (!blkdev)
    1067 sprintf(source, "%s#%s", subtype, fsname);
    1068 } else {
    1069 strcpy(source, type);
    1070 }
    1071
    1072 res = mount_notrunc(source, mnt, type, flags, optbuf);
    1073 }
    1074 if (res == -1 && errno == EINVAL) {
    1075 /* It could be an old version not supporting group_id */
    1076 sprintf(d, "fd=%i,rootmode=%o,user_id=%u",
    1077 fd, rootmode, getuid());
    1078 res = mount_notrunc(source, mnt, type, flags, optbuf);
    1079 }
    1080 if (res == -1) {
    1081 int errno_save = errno;
    1082 if (blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk())
    1083 fprintf(stderr, "%s: 'fuseblk' support missing\n",
    1084 progname);
    1085 else
    1086 fprintf(stderr, "%s: mount failed: %s\n", progname,
    1087 strerror(errno_save));
    1088 goto err;
    1089 }
    1090 *sourcep = source;
    1091 *typep = type;
    1092 *mnt_optsp = mnt_opts;
    1093 free(fsname);
    1094 free(optbuf);
    1095
    1096 return 0;
    1097
    1098err:
    1099 free(fsname);
    1100 free(subtype);
    1101 free(source);
    1102 free(type);
    1103 free(mnt_opts);
    1104 free(optbuf);
    1105 return -1;
    1106}
    1107
    1108/*
    1109 * Resolve the caller-supplied mountpoint exactly once and hand back a
    1110 * descriptor for the inode it named. O_NOFOLLOW refuses a symlink outright for
    1111 * an unprivileged caller; root keeps following them, as it always has.
    1112 */
    1113static int pin_mountpoint(const char *mnt, bool is_root, struct stat *stbuf)
    1114{
    1115 int open_flags = O_PATH | O_CLOEXEC;
    1116 int fd;
    1117
    1118 if (!is_root)
    1119 open_flags |= O_NOFOLLOW;
    1120
    1121 fd = open(mnt, open_flags);
    1122 if (fd == -1) {
    1123 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
    1124 progname, mnt, strerror(errno));
    1125 return -1;
    1126 }
    1127
    1128 if (fstat(fd, stbuf) == -1) {
    1129 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
    1130 progname, mnt, strerror(errno));
    1131 close(fd);
    1132 return -1;
    1133 }
    1134
    1135 return fd;
    1136}
    1137
    1138static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd)
    1139{
    1140 int res;
    1141 int fd;
    1142 const char *mnt = *mntp;
    1143 const bool is_root = getuid() == 0;
    1144 struct statfs fs_buf;
    1145 size_t i;
    1146
    1147 fd = pin_mountpoint(mnt, is_root, stbuf);
    1148 if (fd == -1)
    1149 return -1;
    1150
    1151 /* No permission checking is done for root */
    1152 if (is_root) {
    1153 *mountpoint_fd = fd;
    1154 return 0;
    1155 }
    1156
    1157 if (S_ISDIR(stbuf->st_mode)) {
    1158 res = fchdir(fd);
    1159 if (res == -1) {
    1160 fprintf(stderr,
    1161 "%s: failed to chdir to mountpoint: %s\n",
    1162 progname, strerror(errno));
    1163 goto out_close;
    1164 }
    1165 /*
    1166 * The pinned directory is the CWD, so "." names it without
    1167 * going through the caller-supplied path a second time.
    1168 */
    1169 *mntp = ".";
    1170
    1171 if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) {
    1172 fprintf(stderr, "%s: mountpoint %s not owned by user\n",
    1173 progname, mnt);
    1174 res = -1;
    1175 goto out_close;
    1176 }
    1177
    1178 res = access(*mntp, W_OK);
    1179 if (res == -1) {
    1180 fprintf(stderr, "%s: user has no write access to mountpoint %s\n",
    1181 progname, mnt);
    1182 goto out_close;
    1183 }
    1184 } else if (S_ISREG(stbuf->st_mode)) {
    1185 static char procfile[256];
    1186 int wfd;
    1187
    1188 snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd);
    1189
    1190 /*
    1191 * Reopening the pinned inode through its magic link both tests
    1192 * write access and yields the descriptor mount(2) is pointed
    1193 * at, so the caller's path is never resolved again.
    1194 */
    1195 wfd = open(procfile, O_WRONLY);
    1196 if (wfd == -1) {
    1197 fprintf(stderr, "%s: failed to open %s: %s\n",
    1198 progname, mnt, strerror(errno));
    1199 res = -1;
    1200 goto out_close;
    1201 }
    1202 close(fd);
    1203 fd = wfd;
    1204
    1205 snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd);
    1206 *mntp = procfile;
    1207 } else {
    1208 fprintf(stderr,
    1209 "%s: mountpoint %s is not a directory or a regular file\n",
    1210 progname, mnt);
    1211 res = -1;
    1212 goto out_close;
    1213 }
    1214
    1215 /* Do not permit mounting over anything in procfs - it has a couple
    1216 * places to which we have "write access" without being supposed to be
    1217 * able to just put anything we want there.
    1218 * Luckily, without allow_other, we can't get other users to actually
    1219 * use any fake information we try to put there anyway.
    1220 * Use a whitelist to be safe. */
    1221 if (statfs(*mntp, &fs_buf)) {
    1222 fprintf(stderr, "%s: failed to access mountpoint %s: %s\n",
    1223 progname, mnt, strerror(errno));
    1224 res = -1;
    1225 goto out_close;
    1226 }
    1227
    1228 /* Define permitted filesystems for the mount target. This was
    1229 * originally the same list as used by the ecryptfs mount helper
    1230 * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225)
    1231 * but got expanded as we found more filesystems that needed to be
    1232 * overlaid. */
    1233 typeof(fs_buf.f_type) f_type_whitelist[] = {
    1234 0x61756673 /* AUFS_SUPER_MAGIC */,
    1235 0x00000187 /* AUTOFS_SUPER_MAGIC */,
    1236 0xCA451A4E /* BCACHEFS_STATFS_MAGIC */,
    1237 0x9123683E /* BTRFS_SUPER_MAGIC */,
    1238 0x00C36400 /* CEPH_SUPER_MAGIC */,
    1239 0xFF534D42 /* CIFS_MAGIC_NUMBER */,
    1240 0x0000F15F /* ECRYPTFS_SUPER_MAGIC */,
    1241 0X2011BAB0 /* EXFAT_SUPER_MAGIC */,
    1242 0x0000EF53 /* EXT[234]_SUPER_MAGIC */,
    1243 0xF2F52010 /* F2FS_SUPER_MAGIC */,
    1244 0x65735546 /* FUSE_SUPER_MAGIC */,
    1245 0x01161970 /* GFS2_MAGIC */,
    1246 0x47504653 /* GPFS_SUPER_MAGIC */,
    1247 0x0000482b /* HFSPLUS_SUPER_MAGIC */,
    1248 0x000072B6 /* JFFS2_SUPER_MAGIC */,
    1249 0x3153464A /* JFS_SUPER_MAGIC */,
    1250 0x0BD00BD0 /* LL_SUPER_MAGIC */,
    1251 0X00004D44 /* MSDOS_SUPER_MAGIC */,
    1252 0x0000564C /* NCP_SUPER_MAGIC */,
    1253 0x00006969 /* NFS_SUPER_MAGIC */,
    1254 0x00003434 /* NILFS_SUPER_MAGIC */,
    1255 0x5346544E /* NTFS_SB_MAGIC */,
    1256 0x7366746E /* NTFS3_SUPER_MAGIC */,
    1257 0x5346414f /* OPENAFS_SUPER_MAGIC */,
    1258 0x794C7630 /* OVERLAYFS_SUPER_MAGIC */,
    1259 0xAAD7AAEA /* PANFS_SUPER_MAGIC */,
    1260 0x52654973 /* REISERFS_SUPER_MAGIC */,
    1261 0xFE534D42 /* SMB2_SUPER_MAGIC */,
    1262 0x73717368 /* SQUASHFS_MAGIC */,
    1263 0x01021994 /* TMPFS_MAGIC */,
    1264 0x24051905 /* UBIFS_SUPER_MAGIC */,
    1265 0x18031977 /* WEKAFS_SUPER_MAGIC */,
    1266#if __SIZEOF_LONG__ > 4
    1267 0x736675005346544e /* UFSD */,
    1268#endif
    1269 0x58465342 /* XFS_SB_MAGIC */,
    1270 0x2FC12FC1 /* ZFS_SUPER_MAGIC */,
    1271 0x858458f6 /* RAMFS_MAGIC */,
    1272 };
    1273 for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) {
    1274 if (f_type_whitelist[i] == fs_buf.f_type) {
    1275 *mountpoint_fd = fd;
    1276 return 0;
    1277 }
    1278 }
    1279
    1280 fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n",
    1281 progname, (unsigned long)fs_buf.f_type);
    1282 res = -1;
    1283
    1284out_close:
    1285 close(fd);
    1286 return res;
    1287}
    1288
    1289static int open_fuse_device(const char *dev)
    1290{
    1291 int fd;
    1292
    1293 drop_privs();
    1294 fd = open(dev, O_RDWR);
    1295 if (fd == -1) {
    1296 if (errno == ENODEV || errno == ENOENT)/* check for ENOENT too, for the udev case */
    1297 fprintf(stderr,
    1298 "%s: fuse device %s not found. Kernel module not loaded?\n",
    1299 progname, dev);
    1300 else
    1301 fprintf(stderr,
    1302 "%s: failed to open %s: %s\n", progname, dev, strerror(errno));
    1303 }
    1304 restore_privs();
    1305 return fd;
    1306}
    1307
    1308static int mount_fuse(const char *mnt, const char *opts, const char **type)
    1309{
    1310 int res;
    1311 int fd;
    1312 const char *dev = getenv(FUSE_KERN_DEVICE_ENV) ?: FUSE_DEV;
    1313 struct stat stbuf;
    1314 char *source = NULL;
    1315 char *mnt_opts = NULL;
    1316 const char *real_mnt = mnt;
    1317 int mountpoint_fd = -1;
    1318 char *do_mount_opts = NULL;
    1319 char *x_opts = NULL;
    1320
    1321 fd = open_fuse_device(dev);
    1322 if (fd == -1)
    1323 return -1;
    1324
    1325 drop_privs();
    1326 read_conf();
    1327
    1328 if (getuid() != 0 && mount_max != -1) {
    1329 int mount_count = count_fuse_fs();
    1330 if (mount_count >= mount_max) {
    1331 fprintf(stderr, "%s: too many FUSE filesystems mounted; mount_max=N can be set in %s\n", progname, FUSE_CONF);
    1332 goto fail_close_fd;
    1333 }
    1334 }
    1335
    1336 // Extract any options starting with "x-"
    1337 res= extract_x_options(opts, &do_mount_opts, &x_opts);
    1338 if (res)
    1339 goto fail_close_fd;
    1340
    1341 res = check_perm(&real_mnt, &stbuf, &mountpoint_fd);
    1342 restore_privs();
    1343 if (res != -1)
    1344 res = do_mount(real_mnt, type, stbuf.st_mode & S_IFMT,
    1345 fd, do_mount_opts, dev, &source, &mnt_opts);
    1346
    1347 if (mountpoint_fd != -1)
    1348 close(mountpoint_fd);
    1349
    1350 if (res == -1)
    1351 goto fail_close_fd;
    1352
    1353 res = chdir("/");
    1354 if (res == -1) {
    1355 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
    1356 goto fail_close_fd;
    1357 }
    1358
    1359 if (geteuid() == 0) {
    1360 if (x_opts && strlen(x_opts) > 0) {
    1361 /*
    1362 * Add back the options starting with "x-" to opts from
    1363 * do_mount. +2 for ',' and '\0'
    1364 */
    1365 size_t mnt_opts_len = strlen(mnt_opts);
    1366 size_t x_mnt_opts_len = mnt_opts_len+
    1367 strlen(x_opts) + 2;
    1368 char *x_mnt_opts = calloc(1, x_mnt_opts_len);
    1369
    1370 if (mnt_opts_len) {
    1371 strcpy(x_mnt_opts, mnt_opts);
    1372 strncat(x_mnt_opts, ",", 2);
    1373 }
    1374
    1375 strncat(x_mnt_opts, x_opts,
    1376 x_mnt_opts_len - mnt_opts_len - 2);
    1377
    1378 free(mnt_opts);
    1379 mnt_opts = x_mnt_opts;
    1380 }
    1381
    1382 res = add_mount(source, mnt, *type, mnt_opts);
    1383 if (res == -1) {
    1384 /* Can't clean up mount in a non-racy way */
    1385 goto fail_close_fd;
    1386 }
    1387 }
    1388
    1389out_free:
    1390 free(source);
    1391 free(mnt_opts);
    1392 free(x_opts);
    1393 free(do_mount_opts);
    1394
    1395 return fd;
    1396
    1397fail_close_fd:
    1398 close(fd);
    1399 fd = -1;
    1400 goto out_free;
    1401}
    1402
    1403static int send_fd(int sock_fd, int fd)
    1404{
    1405 int retval;
    1406 struct msghdr msg;
    1407 struct cmsghdr *p_cmsg;
    1408 struct iovec vec;
    1409 size_t cmsgbuf[CMSG_SPACE(sizeof(fd)) / sizeof(size_t)];
    1410 int *p_fds;
    1411 char sendchar = 0;
    1412
    1413 msg.msg_control = cmsgbuf;
    1414 msg.msg_controllen = sizeof(cmsgbuf);
    1415 p_cmsg = CMSG_FIRSTHDR(&msg);
    1416 p_cmsg->cmsg_level = SOL_SOCKET;
    1417 p_cmsg->cmsg_type = SCM_RIGHTS;
    1418 p_cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
    1419 p_fds = (int *) CMSG_DATA(p_cmsg);
    1420 *p_fds = fd;
    1421 msg.msg_controllen = p_cmsg->cmsg_len;
    1422 msg.msg_name = NULL;
    1423 msg.msg_namelen = 0;
    1424 msg.msg_iov = &vec;
    1425 msg.msg_iovlen = 1;
    1426 msg.msg_flags = 0;
    1427 /* "To pass file descriptors or credentials you need to send/read at
    1428 * least one byte" (man 7 unix) */
    1429 vec.iov_base = &sendchar;
    1430 vec.iov_len = sizeof(sendchar);
    1431 while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
    1432 if (retval != 1) {
    1433 perror("sending file descriptor");
    1434 return -1;
    1435 }
    1436 return 0;
    1437}
    1438
    1439/* Helper for should_auto_unmount
    1440 *
    1441 * Try opening `mnt` with uid and gid of the calling process.
    1442 */
    1443static int check_ENOTCONN_as_owner(const char *mnt)
    1444{
    1445 int pid = fork();
    1446 if(pid == -1) {
    1447 perror("fuse: recheck_ENOTCONN_as_owner can't fork");
    1448 _exit(EXIT_FAILURE);
    1449 } else if(pid == 0) {
    1450 uid_t uid = getuid();
    1451 gid_t gid = getgid();
    1452 if(setresgid(gid, gid, gid) == -1) {
    1453 perror("fuse: can't set resgid");
    1454 _exit(EXIT_FAILURE);
    1455 }
    1456 if(setresuid(uid, uid, uid) == -1) {
    1457 perror("fuse: can't set resuid");
    1458 _exit(EXIT_FAILURE);
    1459 }
    1460
    1461 int fd = open(mnt, O_RDONLY);
    1462 if (fd == -1 && (errno == ENOTCONN || errno == ECONNABORTED))
    1463 _exit(EXIT_SUCCESS);
    1464 else
    1465 _exit(EXIT_FAILURE);
    1466 } else {
    1467 int status;
    1468 int res = waitpid(pid, &status, 0);
    1469 if (res == -1) {
    1470 perror("fuse: waiting for child failed");
    1471 _exit(EXIT_FAILURE);
    1472 }
    1473 return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS;
    1474 }
    1475}
    1476
    1477/* The parent fuse process has died: decide whether to auto_unmount.
    1478 *
    1479 * In the normal case (umount or fusermount -u), the filesystem
    1480 * has already been unmounted. If we simply unmount again we can
    1481 * cause problems with stacked mounts (e.g. autofs).
    1482 *
    1483 * So we unmount here only in abnormal case where fuse process has
    1484 * died without unmount happening. To detect this, we first look in
    1485 * the mount table to make sure the mountpoint is still mounted and
    1486 * has proper type. If so, we then see if opening the mount dir is
    1487 * returning 'Transport endpoint is not connected'.
    1488 *
    1489 * The order of these is important, because if autofs is in use,
    1490 * opening the dir to check for ENOTCONN will cause a new mount
    1491 * in the normal case where filesystem has been unmounted cleanly.
    1492 */
    1493static int should_auto_unmount(const char *mnt, const char *type)
    1494{
    1495 char *copy;
    1496 const char *last;
    1497 int result = 0;
    1498
    1499 copy = strdup(mnt);
    1500 if (copy == NULL) {
    1501 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    1502 return 0;
    1503 }
    1504
    1505 if (chdir_to_parent(copy, &last) == -1)
    1506 goto out;
    1507 if (check_is_mount(last, mnt, type) == -1)
    1508 goto out;
    1509
    1510 result = check_ENOTCONN_as_owner(mnt);
    1511out:
    1512 free(copy);
    1513 return result;
    1514}
    1515
    1516static void usage(void)
    1517{
    1518 printf("%s: [options] mountpoint\n"
    1519 "Options:\n"
    1520 " -h print help\n"
    1521 " -V print version\n"
    1522 " -o opt[,opt...] mount options\n"
    1523 " -u unmount\n"
    1524 " -q quiet\n"
    1525 " -z lazy unmount\n",
    1526 progname);
    1527 exit(1);
    1528}
    1529
    1530static void show_version(void)
    1531{
    1532 printf("fusermount3 version: %s\n", PACKAGE_VERSION);
    1533 exit(0);
    1534}
    1535
    1536static void close_range_loop(int min_fd, int max_fd, int cfd)
    1537{
    1538 for (int fd = min_fd; fd <= max_fd; fd++)
    1539 if (fd != cfd)
    1540 close(fd);
    1541}
    1542
    1543/*
    1544 * Close all inherited fds that are not needed
    1545 * Ideally these wouldn't come up at all, applications should better
    1546 * use FD_CLOEXEC / O_CLOEXEC
    1547 */
    1548static int close_inherited_fds(int cfd)
    1549{
    1550 int rc = -1;
    1551 int nullfd;
    1552
    1553 /* We can't even report an error */
    1554 if (cfd <= STDERR_FILENO)
    1555 return -EINVAL;
    1556
    1557#ifdef HAVE_CLOSE_RANGE
    1558 if (cfd < STDERR_FILENO + 2) {
    1559 close_range_loop(STDERR_FILENO + 1, cfd - 1, cfd);
    1560 } else {
    1561 rc = close_range(STDERR_FILENO + 1, cfd - 1, 0);
    1562 if (rc < 0)
    1563 goto fallback;
    1564 }
    1565
    1566 /* Close high range */
    1567 rc = close_range(cfd + 1, ~0U, 0);
    1568#else
    1569 goto fallback; /* make use of fallback to avoid compiler warnings */
    1570#endif
    1571
    1572fallback:
    1573 if (rc < 0) {
    1574 int max_fd = sysconf(_SC_OPEN_MAX) - 1;
    1575
    1576 close_range_loop(STDERR_FILENO + 1, max_fd, cfd);
    1577 }
    1578
    1579 nullfd = open("/dev/null", O_RDWR);
    1580 if (nullfd < 0) {
    1581 perror("fusermount: cannot open /dev/null");
    1582 return -errno;
    1583 }
    1584
    1585 /* Redirect stdin, stdout, stderr to /dev/null */
    1586 dup2(nullfd, STDIN_FILENO);
    1587 dup2(nullfd, STDOUT_FILENO);
    1588 dup2(nullfd, STDERR_FILENO);
    1589 if (nullfd > STDERR_FILENO)
    1590 close(nullfd);
    1591
    1592 return 0;
    1593}
    1594
    1595int main(int argc, char *argv[])
    1596{
    1597 sigset_t sigset;
    1598 int ch;
    1599 int fd;
    1600 int res;
    1601 char *origmnt;
    1602 char *mnt;
    1603 static int unmount = 0;
    1604 static int lazy = 0;
    1605 static int quiet = 0;
    1606 char *commfd = NULL;
    1607 long cfd;
    1608 const char *opts = "";
    1609 const char *type = NULL;
    1610 int setup_auto_unmount_only = 0;
    1611
    1612 static const struct option long_opts[] = {
    1613 {"unmount", no_argument, NULL, 'u'},
    1614 {"lazy", no_argument, NULL, 'z'},
    1615 {"quiet", no_argument, NULL, 'q'},
    1616 {"help", no_argument, NULL, 'h'},
    1617 {"version", no_argument, NULL, 'V'},
    1618 {"options", required_argument, NULL, 'o'},
    1619 // Note: auto-unmount and comm-fd don't have short versions.
    1620 // They'ne meant for internal use by mount.c
    1621 {"auto-unmount", no_argument, NULL, 'U'},
    1622 {"comm-fd", required_argument, NULL, 'c'},
    1623 {0, 0, 0, 0}};
    1624
    1625 progname = strdup(argc > 0 ? argv[0] : "fusermount");
    1626 if (progname == NULL) {
    1627 fprintf(stderr, "%s: failed to allocate memory\n", argv[0]);
    1628 exit(1);
    1629 }
    1630
    1631 while ((ch = getopt_long(argc, argv, "hVo:uzq", long_opts,
    1632 NULL)) != -1) {
    1633 switch (ch) {
    1634 case 'h':
    1635 usage();
    1636 break;
    1637
    1638 case 'V':
    1639 show_version();
    1640 break;
    1641
    1642 case 'o':
    1643 opts = optarg;
    1644 break;
    1645
    1646 case 'u':
    1647 unmount = 1;
    1648 break;
    1649 case 'U':
    1650 unmount = 1;
    1651 auto_unmount = 1;
    1652 setup_auto_unmount_only = 1;
    1653 break;
    1654 case 'c':
    1655 commfd = optarg;
    1656 break;
    1657 case 'z':
    1658 lazy = 1;
    1659 break;
    1660
    1661 case 'q':
    1662 quiet = 1;
    1663 break;
    1664
    1665 default:
    1666 exit(1);
    1667 }
    1668 }
    1669
    1670 if (lazy && !unmount) {
    1671 fprintf(stderr, "%s: -z can only be used with -u\n", progname);
    1672 exit(1);
    1673 }
    1674
    1675 if (optind >= argc) {
    1676 fprintf(stderr, "%s: missing mountpoint argument\n", progname);
    1677 exit(1);
    1678 } else if (argc > optind + 1) {
    1679 fprintf(stderr, "%s: extra arguments after the mountpoint\n",
    1680 progname);
    1681 exit(1);
    1682 }
    1683
    1684 origmnt = argv[optind];
    1685
    1686 drop_privs();
    1687 mnt = fuse_mnt_resolve_path(progname, origmnt);
    1688 if (mnt != NULL) {
    1689 res = chdir("/");
    1690 if (res == -1) {
    1691 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
    1692 goto err_out;
    1693 }
    1694 }
    1695 restore_privs();
    1696 if (mnt == NULL)
    1697 exit(1);
    1698
    1699 umask(033);
    1700 if (!setup_auto_unmount_only && unmount)
    1701 goto do_unmount;
    1702
    1703 if(commfd == NULL)
    1704 commfd = getenv(FUSE_COMMFD_ENV);
    1705 if (commfd == NULL) {
    1706 fprintf(stderr, "%s: old style mounting not supported\n",
    1707 progname);
    1708 goto err_out;
    1709 }
    1710
    1711 res = libfuse_strtol(commfd, &cfd);
    1712 if (res) {
    1713 fprintf(stderr,
    1714 "%s: invalid _FUSE_COMMFD: %s\n",
    1715 progname, commfd);
    1716 goto err_out;
    1717
    1718 }
    1719
    1720 {
    1721 struct stat statbuf;
    1722 if (fstat(cfd, &statbuf) == -1) {
    1723 fprintf(stderr,
    1724 "%s: fstat of comm fd %li failed: %s\n",
    1725 progname, cfd, strerror(errno));
    1726 goto err_out;
    1727 }
    1728 if(!S_ISSOCK(statbuf.st_mode)) {
    1729 fprintf(stderr,
    1730 "%s: file descriptor %li is not a socket, can't send fuse fd\n",
    1731 progname, cfd);
    1732 goto err_out;
    1733 }
    1734 }
    1735
    1736 if (setup_auto_unmount_only)
    1737 goto wait_for_auto_unmount;
    1738
    1739 fd = mount_fuse(mnt, opts, &type);
    1740 if (fd == -1)
    1741 goto err_out;
    1742
    1743 res = send_fd(cfd, fd);
    1744 if (res != 0) {
    1745 unmount_fuse(mnt, 1, 1); /* lazy umount */
    1746 goto err_out;
    1747 }
    1748 close(fd);
    1749
    1750 if (!auto_unmount) {
    1751 free(mnt);
    1752 free((void*) type);
    1753 return 0;
    1754 }
    1755
    1756wait_for_auto_unmount:
    1757 /* Become a daemon and wait for the parent to exit or die.
    1758 ie For the control socket to get closed.
    1759 Btw, we don't want to use daemon() function here because
    1760 it forks and messes with the file descriptors. */
    1761
    1762 res = close_inherited_fds(cfd);
    1763 if (res < 0)
    1764 exit(EXIT_FAILURE);
    1765
    1766 setsid();
    1767 res = chdir("/");
    1768 if (res == -1) {
    1769 fprintf(stderr, "%s: failed to chdir to '/'\n", progname);
    1770 goto err_out;
    1771 }
    1772
    1773 sigfillset(&sigset);
    1774 sigprocmask(SIG_BLOCK, &sigset, NULL);
    1775
    1776 lazy = 1;
    1777 quiet = 1;
    1778
    1779 while (1) {
    1780 unsigned char buf[16];
    1781 int n = recv(cfd, buf, sizeof(buf), 0);
    1782 if (!n)
    1783 break;
    1784
    1785 if (n < 0) {
    1786 if (errno == EINTR)
    1787 continue;
    1788 break;
    1789 }
    1790 }
    1791
    1792 if (!should_auto_unmount(mnt, type)) {
    1793 goto success_out;
    1794 }
    1795
    1796do_unmount:
    1797 if (geteuid() == 0)
    1798 res = unmount_fuse(mnt, quiet, lazy);
    1799 else {
    1800 res = umount2(mnt, (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW);
    1801 if (res == -1 && !quiet)
    1802 fprintf(stderr,
    1803 "%s: failed to unmount %s: %s\n",
    1804 progname, mnt, strerror(errno));
    1805 }
    1806 if (res == -1)
    1807 goto err_out;
    1808
    1809success_out:
    1810 free((void*) type);
    1811 free(mnt);
    1812 return 0;
    1813
    1814err_out:
    1815 free((void*) type);
    1816 free(mnt);
    1817 exit(1);
    1818}
    fuse-3.18.3/doc/html/mount_8fuse_8c_source.html0000644000175000017500000021125215250106404020343 0ustar berndbernd 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 GPLv2.
    6 See the file GPL2.txt.
    7*/
    8
    9#include "fuse_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/* for 2.6 kernels */
    27#if !defined(SECBIT_KEEP_CAPS) && defined(SECURE_KEEP_CAPS)
    28#define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS))
    29#endif
    30#if !defined(SECBIT_KEEP_CAPS_LOCKED) && defined(SECURE_KEEP_CAPS_LOCKED)
    31#define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED))
    32#endif
    33#if !defined(SECBIT_NO_SETUID_FIXUP) && defined(SECURE_NO_SETUID_FIXUP)
    34#define SECBIT_NO_SETUID_FIXUP (issecure_mask(SECURE_NO_SETUID_FIXUP))
    35#endif
    36#if !defined(SECBIT_NO_SETUID_FIXUP_LOCKED) && defined(SECURE_NO_SETUID_FIXUP_LOCKED)
    37#define SECBIT_NO_SETUID_FIXUP_LOCKED (issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED))
    38#endif
    39#if !defined(SECBIT_NOROOT) && defined(SECURE_NOROOT)
    40#define SECBIT_NOROOT (issecure_mask(SECURE_NOROOT))
    41#endif
    42#if !defined(SECBIT_NOROOT_LOCKED) && defined(SECURE_NOROOT_LOCKED)
    43#define SECBIT_NOROOT_LOCKED (issecure_mask(SECURE_NOROOT_LOCKED))
    44#endif
    45#endif
    46/* linux < 3.5 */
    47#ifndef PR_SET_NO_NEW_PRIVS
    48#define PR_SET_NO_NEW_PRIVS 38
    49#endif
    50
    51#include "fuse.h"
    52
    53static char *progname;
    54
    55static char *xstrdup(const char *s)
    56{
    57 char *t = strdup(s);
    58 if (!t) {
    59 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    60 exit(1);
    61 }
    62 return t;
    63}
    64
    65static void *xrealloc(void *oldptr, size_t size)
    66{
    67 void *ptr = realloc(oldptr, size);
    68 if (!ptr) {
    69 fprintf(stderr, "%s: failed to allocate memory\n", progname);
    70 exit(1);
    71 }
    72 return ptr;
    73}
    74
    75static void add_arg(char **cmdp, const char *opt)
    76{
    77 size_t optlen = strlen(opt);
    78 size_t cmdlen = *cmdp ? strlen(*cmdp) : 0;
    79 if (optlen >= (SIZE_MAX - cmdlen - 4)/4) {
    80 fprintf(stderr, "%s: argument too long\n", progname);
    81 exit(1);
    82 }
    83 char *cmd = xrealloc(*cmdp, cmdlen + optlen * 4 + 4);
    84 char *s;
    85 s = cmd + cmdlen;
    86 if (*cmdp)
    87 *s++ = ' ';
    88
    89 *s++ = '\'';
    90 for (; *opt; opt++) {
    91 if (*opt == '\'') {
    92 *s++ = '\'';
    93 *s++ = '\\';
    94 *s++ = '\'';
    95 *s++ = '\'';
    96 } else
    97 *s++ = *opt;
    98 }
    99 *s++ = '\'';
    100 *s = '\0';
    101 *cmdp = cmd;
    102}
    103
    104static char *add_option(const char *opt, char *options)
    105{
    106 int oldlen = options ? strlen(options) : 0;
    107
    108 options = xrealloc(options, oldlen + 1 + strlen(opt) + 1);
    109 if (!oldlen)
    110 strcpy(options, opt);
    111 else {
    112 strcat(options, ",");
    113 strcat(options, opt);
    114 }
    115 return options;
    116}
    117
    118static int prepare_fuse_fd(const char *mountpoint, const char* subtype,
    119 const char *options)
    120{
    121 int fuse_fd = -1;
    122 int flags = -1;
    123 int subtype_len = strlen(subtype) + 9;
    124 char* options_copy = xrealloc(NULL, subtype_len);
    125
    126 snprintf(options_copy, subtype_len, "subtype=%s", subtype);
    127 options_copy = add_option(options, options_copy);
    128 fuse_fd = fuse_open_channel(mountpoint, options_copy);
    129 if (fuse_fd == -1) {
    130 exit(1);
    131 }
    132
    133 flags = fcntl(fuse_fd, F_GETFD);
    134 if (flags == -1 || fcntl(fuse_fd, F_SETFD, flags & ~FD_CLOEXEC) == -1) {
    135 fprintf(stderr, "%s: Failed to clear CLOEXEC: %s\n",
    136 progname, strerror(errno));
    137 exit(1);
    138 }
    139
    140 return fuse_fd;
    141}
    142
    143#ifdef linux
    144static uint64_t get_capabilities(void)
    145{
    146 /*
    147 * This invokes the capset syscall directly to avoid the libcap
    148 * dependency, which isn't really justified just for this.
    149 */
    150 struct __user_cap_header_struct header = {
    151 .version = _LINUX_CAPABILITY_VERSION_3,
    152 .pid = 0,
    153 };
    154 struct __user_cap_data_struct data[2];
    155 memset(data, 0, sizeof(data));
    156 if (syscall(SYS_capget, &header, data) == -1) {
    157 fprintf(stderr, "%s: Failed to get capabilities: %s\n",
    158 progname, strerror(errno));
    159 exit(1);
    160 }
    161
    162 return data[0].effective | ((uint64_t) data[1].effective << 32);
    163}
    164
    165static void set_capabilities(uint64_t caps)
    166{
    167 /*
    168 * This invokes the capset syscall directly to avoid the libcap
    169 * dependency, which isn't really justified just for this.
    170 */
    171 struct __user_cap_header_struct header = {
    172 .version = _LINUX_CAPABILITY_VERSION_3,
    173 .pid = 0,
    174 };
    175 struct __user_cap_data_struct data[2];
    176 memset(data, 0, sizeof(data));
    177 data[0].effective = data[0].permitted = caps;
    178 data[1].effective = data[1].permitted = caps >> 32;
    179 if (syscall(SYS_capset, &header, data) == -1) {
    180 fprintf(stderr, "%s: Failed to set capabilities: %s\n",
    181 progname, strerror(errno));
    182 exit(1);
    183 }
    184}
    185
    186static void drop_and_lock_capabilities(void)
    187{
    188 /* Set and lock securebits. */
    189 if (prctl(PR_SET_SECUREBITS,
    190 SECBIT_KEEP_CAPS_LOCKED |
    191 SECBIT_NO_SETUID_FIXUP |
    192 SECBIT_NO_SETUID_FIXUP_LOCKED |
    193 SECBIT_NOROOT |
    194 SECBIT_NOROOT_LOCKED) == -1) {
    195 fprintf(stderr, "%s: Failed to set securebits %s\n",
    196 progname, strerror(errno));
    197 exit(1);
    198 }
    199
    200 /* Clear the capability bounding set. */
    201 int cap;
    202 for (cap = 0; ; cap++) {
    203 int cap_status = prctl(PR_CAPBSET_READ, cap);
    204 if (cap_status == 0) {
    205 continue;
    206 }
    207 if (cap_status == -1 && errno == EINVAL) {
    208 break;
    209 }
    210
    211 if (cap_status != 1) {
    212 fprintf(stderr,
    213 "%s: Failed to get capability %u: %s\n",
    214 progname, cap, strerror(errno));
    215 exit(1);
    216 }
    217 if (prctl(PR_CAPBSET_DROP, cap) == -1) {
    218 fprintf(stderr,
    219 "%s: Failed to drop capability %u: %s\n",
    220 progname, cap, strerror(errno));
    221 }
    222 }
    223
    224 /* Drop capabilities. */
    225 set_capabilities(0);
    226
    227 /* Prevent re-acquisition of privileges. */
    228 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
    229 fprintf(stderr, "%s: Failed to set no_new_privs: %s\n",
    230 progname, strerror(errno));
    231 exit(1);
    232 }
    233}
    234#endif
    235
    236int main(int argc, char *argv[])
    237{
    238 char *type = NULL;
    239 char *source;
    240 char *dup_source = NULL;
    241 const char *mountpoint;
    242 char *basename;
    243 char *options = NULL;
    244 char *command = NULL;
    245 char *setuid_name = NULL;
    246 int i;
    247 int dev = 1;
    248 int suid = 1;
    249 int pass_fuse_fd = 0;
    250 int fuse_fd = 0;
    251 int drop_privileges = 0;
    252 char *dev_fd_mountpoint = NULL;
    253
    254 progname = argv[0];
    255 basename = strrchr(argv[0], '/');
    256 if (basename)
    257 basename++;
    258 else
    259 basename = argv[0];
    260
    261 if (strncmp(basename, "mount.fuse.", 11) == 0)
    262 type = basename + 11;
    263 if (strncmp(basename, "mount.fuseblk.", 14) == 0)
    264 type = basename + 14;
    265
    266 if (type && !type[0])
    267 type = NULL;
    268
    269 if (argc < 3) {
    270 fprintf(stderr,
    271 "usage: %s %s destination [-t type] [-o opt[,opts...]]\n",
    272 progname, type ? "source" : "type#[source]");
    273 exit(1);
    274 }
    275
    276 source = argv[1];
    277 if (!source[0])
    278 source = NULL;
    279
    280 mountpoint = argv[2];
    281
    282 for (i = 3; i < argc; i++) {
    283 if (strcmp(argv[i], "-v") == 0) {
    284 continue;
    285 } else if (strcmp(argv[i], "-t") == 0) {
    286 i++;
    287
    288 if (i == argc) {
    289 fprintf(stderr,
    290 "%s: missing argument to option '-t'\n",
    291 progname);
    292 exit(1);
    293 }
    294 type = argv[i];
    295 if (strncmp(type, "fuse.", 5) == 0)
    296 type += 5;
    297 else if (strncmp(type, "fuseblk.", 8) == 0)
    298 type += 8;
    299
    300 if (!type[0]) {
    301 fprintf(stderr,
    302 "%s: empty type given as argument to option '-t'\n",
    303 progname);
    304 exit(1);
    305 }
    306 } else if (strcmp(argv[i], "-o") == 0) {
    307 char *opts;
    308 char *opt;
    309 i++;
    310 if (i == argc)
    311 break;
    312
    313 opts = xstrdup(argv[i]);
    314 opt = strtok(opts, ",");
    315 while (opt) {
    316 int j;
    317 int ignore = 0;
    318 const char *ignore_opts[] = { "",
    319 "user",
    320 "nofail",
    321 "nouser",
    322 "users",
    323 "auto",
    324 "noauto",
    325 "_netdev",
    326 NULL};
    327 if (strncmp(opt, "setuid=", 7) == 0) {
    328 setuid_name = xstrdup(opt + 7);
    329 ignore = 1;
    330 } else if (strcmp(opt,
    331 "drop_privileges") == 0) {
    332 pass_fuse_fd = 1;
    333 drop_privileges = 1;
    334 ignore = 1;
    335 }
    336 for (j = 0; ignore_opts[j]; j++)
    337 if (strcmp(opt, ignore_opts[j]) == 0)
    338 ignore = 1;
    339
    340 if (!ignore) {
    341 if (strcmp(opt, "nodev") == 0)
    342 dev = 0;
    343 else if (strcmp(opt, "nosuid") == 0)
    344 suid = 0;
    345
    346 options = add_option(opt, options);
    347 }
    348 opt = strtok(NULL, ",");
    349 }
    350 free(opts);
    351 }
    352 }
    353
    354 if (drop_privileges) {
    355 uint64_t required_caps = CAP_TO_MASK(CAP_SETPCAP) |
    356 CAP_TO_MASK(CAP_SYS_ADMIN);
    357 if ((get_capabilities() & required_caps) != required_caps) {
    358 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",
    359 progname, progname);
    360 exit(1);
    361 }
    362 }
    363
    364 if (dev)
    365 options = add_option("dev", options);
    366 if (suid)
    367 options = add_option("suid", options);
    368
    369 if (!type) {
    370 if (source) {
    371 dup_source = xstrdup(source);
    372 type = dup_source;
    373 source = strchr(type, '#');
    374 if (source)
    375 *source++ = '\0';
    376 if (!type[0]) {
    377 fprintf(stderr, "%s: empty filesystem type\n",
    378 progname);
    379 exit(1);
    380 }
    381 } else {
    382 fprintf(stderr, "%s: empty source\n", progname);
    383 exit(1);
    384 }
    385 }
    386
    387 if (setuid_name && setuid_name[0]) {
    388#ifdef linux
    389 if (drop_privileges) {
    390 /*
    391 * Make securebits more permissive before calling
    392 * setuid(). Specifically, if SECBIT_KEEP_CAPS and
    393 * SECBIT_NO_SETUID_FIXUP weren't set, setuid() would
    394 * have the side effect of dropping all capabilities,
    395 * and we need to retain CAP_SETPCAP in order to drop
    396 * all privileges before exec().
    397 */
    398 if (prctl(PR_SET_SECUREBITS,
    399 SECBIT_KEEP_CAPS |
    400 SECBIT_NO_SETUID_FIXUP) == -1) {
    401 fprintf(stderr,
    402 "%s: Failed to set securebits %s\n",
    403 progname, strerror(errno));
    404 exit(1);
    405 }
    406 }
    407#endif
    408
    409 struct passwd *pwd = getpwnam(setuid_name);
    410 if (!pwd || setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) {
    411 fprintf(stderr, "%s: Failed to setuid to %s: %s\n",
    412 progname, setuid_name, strerror(errno));
    413 exit(1);
    414 }
    415 } else if (!getenv("HOME")) {
    416 /* Hack to make filesystems work in the boot environment */
    417 setenv("HOME", "/root", 0);
    418 }
    419
    420 if (pass_fuse_fd) {
    421 fuse_fd = prepare_fuse_fd(mountpoint, type, options);
    422 dev_fd_mountpoint = xrealloc(NULL, 20);
    423 snprintf(dev_fd_mountpoint, 20, "/dev/fd/%u", fuse_fd);
    424 mountpoint = dev_fd_mountpoint;
    425 }
    426
    427#ifdef linux
    428 if (drop_privileges) {
    429 drop_and_lock_capabilities();
    430 }
    431#endif
    432 add_arg(&command, type);
    433 if (source)
    434 add_arg(&command, source);
    435 add_arg(&command, mountpoint);
    436 if (options) {
    437 add_arg(&command, "-o");
    438 add_arg(&command, options);
    439 }
    440
    441 free(options);
    442 free(dev_fd_mountpoint);
    443 free(dup_source);
    444 free(setuid_name);
    445
    446 execl("/bin/sh", "/bin/sh", "-c", command, NULL);
    447 fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname,
    448 strerror(errno));
    449
    450 if (pass_fuse_fd)
    451 close(fuse_fd);
    452 free(command);
    453 return 1;
    454}
    int fuse_open_channel(const char *mountpoint, const char *options)
    Definition helper.c:492
    fuse-3.18.3/doc/html/cuse_8c.html0000644000175000017500000011466615250106404015461 0ustar berndbernd 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 GPLv2.
    See the file GPL2.txt.
    */
    #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_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    }
    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 = {
    .init = cusexmp_init,
    .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;
    int ret = 1;
    if (fuse_opt_parse(&args, &param, cusexmp_opts, cusexmp_process_arg)) {
    printf("failed to parse option\n");
    free(param.dev_name);
    goto out;
    }
    if (!param.is_help) {
    if (!param.dev_name) {
    fprintf(stderr, "Error: device name missing\n");
    goto out;
    }
    strncat(dev_name, param.dev_name, sizeof(dev_name) - sizeof("DEVNAME="));
    free(param.dev_name);
    }
    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;
    ret = cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop, NULL);
    out:
    return ret;
    }
    #define FUSE_IOCTL_COMPAT
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
    int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
    Definition fuse_opt.c:55
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_OPT_KEY(templ, key)
    Definition fuse_opt.h:98
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt

    Definition in file cuse.c.

    fuse-3.18.3/doc/html/cuse__client_8c.html0000644000175000017500000003375715250106404017157 0ustar berndbernd libfuse: example/cuse_client.c File Reference
    libfuse
    cuse_client.c File Reference
    #include <sys/types.h>
    #include <fcntl.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <errno.h>
    #include <unistd.h>
    #include "ioctl.h"

    Go to the source code of this file.

    Detailed Description

    This program tests the cuse.c example file system.

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

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

    Compiling this example

    gcc -Wall cuse_client.c -o cuse_client
    

    Source Code

    /*
    FUSE fioclient: FUSE ioctl example client
    Copyright (C) 2008 SUSE Linux Products GmbH
    Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #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 <unistd.h>
    #include "ioctl.h"
    /* keeps a mistyped SIZE from asking for the machine's memory */
    #define MAX_XFER_SIZE (16 * 1024 * 1024)
    const char *usage =
    "Usage: cuse_client FIOC_FILE COMMAND\n"
    "\n"
    "COMMANDS\n"
    " s [SIZE] : get size if SIZE is omitted, set size otherwise\n"
    " r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n"
    " w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n"
    "\n";
    static int do_rw(int fd, int is_read, size_t size, off_t offset,
    size_t *prev_size, size_t *new_size)
    {
    struct fioc_rw_arg arg = { .offset = offset };
    ssize_t ret;
    if (size > MAX_XFER_SIZE) {
    fprintf(stderr, "size %zu exceeds limit of %d bytes\n",
    size, MAX_XFER_SIZE);
    return -1;
    }
    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");
    goto error;
    }
    printf("%zu\n", size);
    } else {
    size = param[0];
    if (ioctl(fd, FIOC_SET_SIZE, &size)) {
    perror("ioctl");
    goto error;
    }
    }
    close(fd);
    return 0;
    case 'r':
    case 'w':
    rc = do_rw(fd, cmd == 'r', param[0], param[1],
    &prev_size, &new_size);
    if (rc < 0)
    goto error;
    fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n",
    rc, prev_size, new_size);
    close(fd);
    return 0;
    }
    usage:
    fprintf(stderr, "%s", usage);
    return 1;
    error:
    close(fd);
    return 1;
    }

    Definition in file cuse_client.c.

    fuse-3.18.3/doc/html/example_2hello_8c.html0000644000175000017500000006602115250106404017411 0ustar berndbernd libfuse: example/hello.c File Reference
    libfuse
    hello.c File Reference
    #include <fuse.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stddef.h>
    #include <assert.h>

    Go to the source code of this file.

    Detailed Description

    minimal example filesystem using high-level API

    Compile with:

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

    Source code

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

    Definition in file hello.c.

    fuse-3.18.3/doc/html/test_2hello_8c.html0000644000175000017500000006600615250106404016740 0ustar berndbernd libfuse: test/hello.c File Reference
    libfuse
    hello.c File Reference
    #include <fuse.h>
    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <stddef.h>
    #include <assert.h>

    Go to the source code of this file.

    Detailed Description

    minimal example filesystem using high-level API

    Compile with:

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

    Source code

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

    Definition in file hello.c.

    fuse-3.18.3/doc/html/hello__ll_8c.html0000644000175000017500000012262415250106404016444 0ustar berndbernd libfuse: example/hello_ll.c File Reference
    libfuse
    hello_ll.c File Reference
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <assert.h>

    Go to the source code of this file.

    Detailed Description

    minimal example filesystem using low-level API

    Compile with:

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

    Note: If the pkg-config command fails due to the absence of the fuse3.pc file, you should configure the path to the fuse3.pc file in the PKG_CONFIG_PATH variable.

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <assert.h>
    static const char *hello_str = "Hello World!\n";
    static const char *hello_name = "hello";
    static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
    {
    stbuf->st_ino = ino;
    switch (ino) {
    case 1:
    stbuf->st_mode = S_IFDIR | 0755;
    stbuf->st_nlink = 2;
    break;
    case 2:
    stbuf->st_mode = S_IFREG | 0444;
    stbuf->st_nlink = 1;
    stbuf->st_size = strlen(hello_str);
    break;
    default:
    return -1;
    }
    return 0;
    }
    static void hello_ll_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    /* Test setting flags the old way */
    }
    static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
    struct fuse_file_info *fi)
    {
    struct stat stbuf;
    (void) fi;
    memset(&stbuf, 0, sizeof(stbuf));
    if (hello_stat(ino, &stbuf) == -1)
    fuse_reply_err(req, ENOENT);
    else
    fuse_reply_attr(req, &stbuf, 1.0);
    }
    static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    {
    struct fuse_entry_param e;
    if (parent != 1 || strcmp(name, hello_name) != 0)
    fuse_reply_err(req, ENOENT);
    else {
    memset(&e, 0, sizeof(e));
    e.ino = 2;
    e.attr_timeout = 1.0;
    e.entry_timeout = 1.0;
    hello_stat(e.ino, &e.attr);
    fuse_reply_entry(req, &e);
    }
    }
    struct dirbuf {
    char *p;
    size_t size;
    };
    static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    {
    struct stat stbuf;
    size_t oldsize = b->size;
    b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    b->p = (char *) realloc(b->p, b->size);
    memset(&stbuf, 0, sizeof(stbuf));
    stbuf.st_ino = ino;
    fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    b->size);
    }
    #define min(x, y) ((x) < (y) ? (x) : (y))
    static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    off_t off, size_t maxsize)
    {
    if (off < bufsize)
    return fuse_reply_buf(req, buf + off,
    min(bufsize - off, maxsize));
    else
    return fuse_reply_buf(req, NULL, 0);
    }
    static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    off_t off, struct fuse_file_info *fi)
    {
    (void) fi;
    if (ino != 1)
    fuse_reply_err(req, ENOTDIR);
    else {
    struct dirbuf b;
    memset(&b, 0, sizeof(b));
    dirbuf_add(req, &b, ".", 1);
    dirbuf_add(req, &b, "..", 1);
    dirbuf_add(req, &b, hello_name, 2);
    reply_buf_limited(req, b.p, b.size, off, size);
    free(b.p);
    }
    }
    static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
    struct fuse_file_info *fi)
    {
    if (ino != 2)
    fuse_reply_err(req, EISDIR);
    else if ((fi->flags & O_ACCMODE) != 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 void hello_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    size_t size)
    {
    (void)size;
    assert(ino == 1 || ino == 2);
    if (strcmp(name, "hello_ll_getxattr_name") == 0)
    {
    const char *buf = "hello_ll_getxattr_value";
    fuse_reply_buf(req, buf, strlen(buf));
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static void hello_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    const char *value, size_t size, int flags)
    {
    (void)flags;
    (void)size;
    assert(ino == 1 || ino == 2);
    const char* exp_val = "hello_ll_setxattr_value";
    if (strcmp(name, "hello_ll_setxattr_name") == 0 &&
    strlen(exp_val) == size &&
    strncmp(value, exp_val, size) == 0)
    {
    fuse_reply_err(req, 0);
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static void hello_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
    {
    assert(ino == 1 || ino == 2);
    if (strcmp(name, "hello_ll_removexattr_name") == 0)
    {
    fuse_reply_err(req, 0);
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static const struct fuse_lowlevel_ops hello_ll_oper = {
    .init = hello_ll_init,
    .lookup = hello_ll_lookup,
    .getattr = hello_ll_getattr,
    .readdir = hello_ll_readdir,
    .open = hello_ll_open,
    .read = hello_ll_read,
    .setxattr = hello_ll_setxattr,
    .getxattr = hello_ll_getxattr,
    .removexattr = hello_ll_removexattr,
    };
    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 fuse_loop_config *config;
    int ret = -1;
    if (fuse_parse_cmdline(&args, &opts) != 0)
    return 1;
    if (opts.show_help) {
    printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
    ret = 0;
    goto err_out1;
    } else if (opts.show_version) {
    printf("FUSE library version %s\n", fuse_pkgversion());
    ret = 0;
    goto err_out1;
    }
    if(opts.mountpoint == NULL) {
    printf("usage: %s [options] <mountpoint>\n", argv[0]);
    printf(" %s --help\n", argv[0]);
    ret = 1;
    goto err_out1;
    }
    se = fuse_session_new(&args, &hello_ll_oper,
    sizeof(hello_ll_oper), NULL);
    if (se == NULL)
    goto err_out1;
    goto err_out2;
    if (fuse_session_mount(se, opts.mountpoint) != 0)
    goto err_out3;
    fuse_daemonize(opts.foreground);
    /* Block until ctrl+c or fusermount -u */
    if (opts.singlethread)
    ret = fuse_session_loop(se);
    else {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    return ret ? 1 : 0;
    }
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_ASYNC_READ
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt

    Definition in file hello_ll.c.

    fuse-3.18.3/doc/html/hello__ll__uds_8c.html0000644000175000017500000012276715250106404017466 0ustar berndbernd libfuse: example/hello_ll_uds.c File Reference
    libfuse
    hello_ll_uds.c File Reference
    #include <fuse_lowlevel.h>
    #include <fuse_kernel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <assert.h>
    #include <sys/socket.h>
    #include <sys/un.h>

    Go to the source code of this file.

    Detailed Description

    minimal example filesystem using low-level API and a custom io. This custom io is implemented using UNIX domain sockets (of type SOCK_STREAM)

    Compile with:

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

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <assert.h>
    static const char *hello_str = "Hello World!\n";
    static const char *hello_name = "hello";
    static int hello_stat(fuse_ino_t ino, struct stat *stbuf)
    {
    stbuf->st_ino = ino;
    switch (ino) {
    case 1:
    stbuf->st_mode = S_IFDIR | 0755;
    stbuf->st_nlink = 2;
    break;
    case 2:
    stbuf->st_mode = S_IFREG | 0444;
    stbuf->st_nlink = 1;
    stbuf->st_size = strlen(hello_str);
    break;
    default:
    return -1;
    }
    return 0;
    }
    static void hello_ll_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    /* Test setting flags the old way */
    }
    static void hello_ll_getattr(fuse_req_t req, fuse_ino_t ino,
    struct fuse_file_info *fi)
    {
    struct stat stbuf;
    (void) fi;
    memset(&stbuf, 0, sizeof(stbuf));
    if (hello_stat(ino, &stbuf) == -1)
    fuse_reply_err(req, ENOENT);
    else
    fuse_reply_attr(req, &stbuf, 1.0);
    }
    static void hello_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
    {
    struct fuse_entry_param e;
    if (parent != 1 || strcmp(name, hello_name) != 0)
    fuse_reply_err(req, ENOENT);
    else {
    memset(&e, 0, sizeof(e));
    e.ino = 2;
    e.attr_timeout = 1.0;
    e.entry_timeout = 1.0;
    hello_stat(e.ino, &e.attr);
    fuse_reply_entry(req, &e);
    }
    }
    struct dirbuf {
    char *p;
    size_t size;
    };
    static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    {
    struct stat stbuf;
    size_t oldsize = b->size;
    b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    b->p = (char *) realloc(b->p, b->size);
    memset(&stbuf, 0, sizeof(stbuf));
    stbuf.st_ino = ino;
    fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    b->size);
    }
    #define min(x, y) ((x) < (y) ? (x) : (y))
    static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    off_t off, size_t maxsize)
    {
    if (off < bufsize)
    return fuse_reply_buf(req, buf + off,
    min(bufsize - off, maxsize));
    else
    return fuse_reply_buf(req, NULL, 0);
    }
    static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
    off_t off, struct fuse_file_info *fi)
    {
    (void) fi;
    if (ino != 1)
    fuse_reply_err(req, ENOTDIR);
    else {
    struct dirbuf b;
    memset(&b, 0, sizeof(b));
    dirbuf_add(req, &b, ".", 1);
    dirbuf_add(req, &b, "..", 1);
    dirbuf_add(req, &b, hello_name, 2);
    reply_buf_limited(req, b.p, b.size, off, size);
    free(b.p);
    }
    }
    static void hello_ll_open(fuse_req_t req, fuse_ino_t ino,
    struct fuse_file_info *fi)
    {
    if (ino != 2)
    fuse_reply_err(req, EISDIR);
    else if ((fi->flags & O_ACCMODE) != 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 void hello_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    size_t size)
    {
    (void)size;
    assert(ino == 1 || ino == 2);
    if (strcmp(name, "hello_ll_getxattr_name") == 0)
    {
    const char *buf = "hello_ll_getxattr_value";
    fuse_reply_buf(req, buf, strlen(buf));
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static void hello_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
    const char *value, size_t size, int flags)
    {
    (void)flags;
    (void)size;
    assert(ino == 1 || ino == 2);
    const char* exp_val = "hello_ll_setxattr_value";
    if (strcmp(name, "hello_ll_setxattr_name") == 0 &&
    strlen(exp_val) == size &&
    strncmp(value, exp_val, size) == 0)
    {
    fuse_reply_err(req, 0);
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static void hello_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
    {
    assert(ino == 1 || ino == 2);
    if (strcmp(name, "hello_ll_removexattr_name") == 0)
    {
    fuse_reply_err(req, 0);
    }
    else
    {
    fuse_reply_err(req, ENOTSUP);
    }
    }
    static const struct fuse_lowlevel_ops hello_ll_oper = {
    .init = hello_ll_init,
    .lookup = hello_ll_lookup,
    .getattr = hello_ll_getattr,
    .readdir = hello_ll_readdir,
    .open = hello_ll_open,
    .read = hello_ll_read,
    .setxattr = hello_ll_setxattr,
    .getxattr = hello_ll_getxattr,
    .removexattr = hello_ll_removexattr,
    };
    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 fuse_loop_config *config;
    int ret = -1;
    if (fuse_parse_cmdline(&args, &opts) != 0)
    return 1;
    if (opts.show_help) {
    printf("usage: %s [options] <mountpoint>\n\n", argv[0]);
    ret = 0;
    goto err_out1;
    } else if (opts.show_version) {
    printf("FUSE library version %s\n", fuse_pkgversion());
    ret = 0;
    goto err_out1;
    }
    if(opts.mountpoint == NULL) {
    printf("usage: %s [options] <mountpoint>\n", argv[0]);
    printf(" %s --help\n", argv[0]);
    ret = 1;
    goto err_out1;
    }
    se = fuse_session_new(&args, &hello_ll_oper,
    sizeof(hello_ll_oper), NULL);
    if (se == NULL)
    goto err_out1;
    goto err_out2;
    if (fuse_session_mount(se, opts.mountpoint) != 0)
    goto err_out3;
    fuse_daemonize(opts.foreground);
    /* Block until ctrl+c or fusermount -u */
    if (opts.singlethread)
    ret = fuse_session_loop(se);
    else {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    return ret ? 1 : 0;
    }
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_ASYNC_READ
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt

    Definition in file hello_ll_uds.c.

    fuse-3.18.3/doc/html/invalidate__path_8c.html0000644000175000017500000011752615250106404020013 0ustar berndbernd 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 invalidate_path.c `pkg-config fuse3 --cflags --libs` -o invalidate_path
    

    Source code

    /*
    FUSE: Filesystem in Userspace
    Copyright (C) 2016 Nikolaus Rath <Nikolaus@rath.org>
    (C) 2017 EditShare LLC <slawek.rudnicki@editshare.com>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION 34
    #include <fuse.h>
    #include <fuse_lowlevel.h> /* for fuse_cmdline_opts */
    #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
    #define MAX_STR_LEN 128
    #define TIME_FILE_NAME "current_time"
    #define TIME_FILE_INO 2
    #define GROW_FILE_NAME "growing"
    #define GROW_FILE_INO 3
    static char time_file_contents[MAX_STR_LEN];
    static size_t grow_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 void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
    {
    (void) conn;
    cfg->entry_timeout = NO_TIMEOUT;
    cfg->attr_timeout = NO_TIMEOUT;
    cfg->negative_timeout = 0;
    return NULL;
    }
    static int xmp_getattr(const char *path,
    struct stat *stbuf, struct fuse_file_info* fi) {
    (void) fi;
    if (strcmp(path, "/") == 0) {
    stbuf->st_ino = 1;
    stbuf->st_mode = S_IFDIR | 0755;
    stbuf->st_nlink = 1;
    } else if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
    stbuf->st_ino = TIME_FILE_INO;
    stbuf->st_mode = S_IFREG | 0444;
    stbuf->st_nlink = 1;
    stbuf->st_size = strlen(time_file_contents);
    } else if (strcmp(path, "/" GROW_FILE_NAME) == 0) {
    stbuf->st_ino = GROW_FILE_INO;
    stbuf->st_mode = S_IFREG | 0444;
    stbuf->st_nlink = 1;
    stbuf->st_size = grow_file_size;
    } else {
    return -ENOENT;
    }
    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) {
    (void) fi;
    (void) offset;
    (void) flags;
    if (strcmp(path, "/") != 0) {
    return -ENOTDIR;
    } else {
    (void) filler;
    (void) buf;
    struct stat file_stat;
    xmp_getattr("/" TIME_FILE_NAME, &file_stat, NULL);
    filler(buf, TIME_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS);
    xmp_getattr("/" GROW_FILE_NAME, &file_stat, NULL);
    filler(buf, GROW_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS);
    return 0;
    }
    }
    static int xmp_open(const char *path, struct fuse_file_info *fi) {
    (void) path;
    /* Make cache persistent even if file is closed,
    this makes it easier to see the effects */
    fi->keep_cache = 1;
    return 0;
    }
    static int xmp_read(const char *path, char *buf, size_t size, off_t offset,
    struct fuse_file_info *fi) {
    (void) fi;
    (void) offset;
    if (strcmp(path, "/" TIME_FILE_NAME) == 0) {
    int file_length = strlen(time_file_contents);
    int to_copy = offset + size <= file_length
    ? size
    : file_length - offset;
    memcpy(buf, time_file_contents, to_copy);
    return to_copy;
    } else {
    assert(strcmp(path, "/" GROW_FILE_NAME) == 0);
    int to_copy = offset + size <= grow_file_size
    ? size
    : grow_file_size - offset;
    memset(buf, 'x', to_copy);
    return to_copy;
    }
    }
    static const struct fuse_operations xmp_oper = {
    .init = xmp_init,
    .getattr = xmp_getattr,
    .readdir = xmp_readdir,
    .open = xmp_open,
    .read = xmp_read,
    };
    static void update_fs(void) {
    static int count = 0;
    struct tm tmbuf;
    struct tm *now;
    time_t t;
    t = time(NULL);
    now = localtime_r(&t, &tmbuf);
    assert(now != NULL);
    int time_file_size = strftime(time_file_contents, MAX_STR_LEN,
    "The current time is %H:%M:%S\n", now);
    assert(time_file_size != 0);
    grow_file_size = count++;
    }
    static int invalidate(struct fuse *fuse, const char *path) {
    int status = fuse_invalidate_path(fuse, path);
    if (status == -ENOENT) {
    return 0;
    } else {
    return status;
    }
    }
    static void* update_fs_loop(void *data) {
    struct fuse *fuse = (struct fuse*) data;
    while (1) {
    update_fs();
    if (!options.no_notify) {
    assert(invalidate(fuse, "/" TIME_FILE_NAME) == 0);
    assert(invalidate(fuse, "/" GROW_FILE_NAME) == 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 *fuse;
    struct fuse_cmdline_opts opts;
    struct fuse_loop_config config;
    int res;
    /* Initialize the files */
    update_fs();
    if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    return 1;
    if (fuse_parse_cmdline(&args, &opts) != 0)
    return 1;
    if (opts.show_version) {
    printf("FUSE library version %s\n", fuse_pkgversion());
    res = 0;
    goto out1;
    } else if (opts.show_help) {
    show_help(argv[0]);
    fuse_lib_help(&args);
    res = 0;
    goto out1;
    } else if (!opts.mountpoint) {
    fprintf(stderr, "error: no mountpoint specified\n");
    res = 1;
    goto out1;
    }
    fuse = fuse_new(&args, &xmp_oper, sizeof(xmp_oper), NULL);
    if (fuse == NULL) {
    res = 1;
    goto out1;
    }
    if (fuse_mount(fuse,opts.mountpoint) != 0) {
    res = 1;
    goto out2;
    }
    if (fuse_daemonize(opts.foreground) != 0) {
    res = 1;
    goto out3;
    }
    pthread_t updater; /* Start thread to update file contents */
    int ret = pthread_create(&updater, NULL, update_fs_loop, (void *) fuse);
    if (ret != 0) {
    fprintf(stderr, "pthread_create failed with %s\n", strerror(ret));
    return 1;
    };
    struct fuse_session *se = fuse_get_session(fuse);
    if (fuse_set_signal_handlers(se) != 0) {
    res = 1;
    goto out3;
    }
    if (opts.singlethread)
    res = fuse_loop(fuse);
    else {
    config.clone_fd = opts.clone_fd;
    config.max_idle_threads = opts.max_idle_threads;
    res = fuse_loop_mt(fuse, &config);
    }
    if (res)
    res = 1;
    out3:
    fuse_unmount(fuse);
    out2:
    fuse_destroy(fuse);
    out1:
    free(opts.mountpoint);
    return res;
    }
    int fuse_mount(struct fuse *f, const char *mountpoint)
    Definition fuse.c:5260
    void fuse_destroy(struct fuse *f)
    Definition fuse.c:5209
    int fuse_invalidate_path(struct fuse *f, const char *path)
    Definition fuse.c:4740
    int fuse_loop(struct fuse *f)
    Definition fuse.c:4644
    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:93
    void fuse_lib_help(struct fuse_args *args)
    Definition fuse.c:4813
    struct fuse_session * fuse_get_session(struct fuse *f)
    Definition fuse.c:4588
    void fuse_unmount(struct fuse *f)
    Definition fuse.c:5265
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_lowlevel_version(void)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint32_t keep_cache
    Definition fuse_common.h:69
    unsigned long offset
    Definition fuse_opt.h:85

    Definition in file invalidate_path.c.

    fuse-3.18.3/doc/html/ioctl_8c.html0000644000175000017500000005350315250106404015624 0ustar berndbernd libfuse: example/ioctl.c File Reference
    libfuse
    ioctl.c File Reference
    #include <fuse.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
    #include <errno.h>
    #include "ioctl.h"

    Go to the source code of this file.

    Detailed Description

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

    Compile with:

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

    Source code

    /*
    FUSE fioc: FUSE ioctl example
    Copyright (C) 2008 SUSE Linux Products GmbH
    Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION 35
    #include <fuse.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
    #include <errno.h>
    #include "ioctl.h"
    #define FIOC_NAME "fioc"
    enum {
    FIOC_NONE,
    FIOC_ROOT,
    FIOC_FILE,
    };
    static void *fioc_buf;
    static size_t fioc_size;
    static int fioc_resize(size_t new_size)
    {
    void *new_buf;
    if (new_size == fioc_size)
    return 0;
    new_buf = realloc(fioc_buf, new_size);
    if (!new_buf && new_size)
    return -ENOMEM;
    if (new_size > fioc_size)
    memset(new_buf + fioc_size, 0, new_size - fioc_size);
    fioc_buf = new_buf;
    fioc_size = new_size;
    return 0;
    }
    static int fioc_expand(size_t new_size)
    {
    if (new_size > fioc_size)
    return fioc_resize(new_size);
    return 0;
    }
    static int fioc_file_type(const char *path)
    {
    if (strcmp(path, "/") == 0)
    return FIOC_ROOT;
    if (strcmp(path, "/" FIOC_NAME) == 0)
    return FIOC_FILE;
    return FIOC_NONE;
    }
    static int fioc_getattr(const char *path, struct stat *stbuf,
    struct fuse_file_info *fi)
    {
    (void) fi;
    stbuf->st_uid = getuid();
    stbuf->st_gid = getgid();
    stbuf->st_atime = stbuf->st_mtime = time(NULL);
    switch (fioc_file_type(path)) {
    case FIOC_ROOT:
    stbuf->st_mode = S_IFDIR | 0755;
    stbuf->st_nlink = 2;
    break;
    case FIOC_FILE:
    stbuf->st_mode = S_IFREG | 0644;
    stbuf->st_nlink = 1;
    stbuf->st_size = fioc_size;
    break;
    case FIOC_NONE:
    return -ENOENT;
    }
    return 0;
    }
    static int fioc_open(const char *path, struct fuse_file_info *fi)
    {
    (void) fi;
    if (fioc_file_type(path) != FIOC_NONE)
    return 0;
    return -ENOENT;
    }
    static int fioc_do_read(char *buf, size_t size, off_t offset)
    {
    if (offset >= fioc_size)
    return 0;
    if (size > fioc_size - offset)
    size = fioc_size - offset;
    memcpy(buf, fioc_buf + offset, size);
    return size;
    }
    static int fioc_read(const char *path, char *buf, size_t size,
    off_t offset, struct fuse_file_info *fi)
    {
    (void) fi;
    if (fioc_file_type(path) != FIOC_FILE)
    return -EINVAL;
    return fioc_do_read(buf, size, offset);
    }
    static int fioc_do_write(const char *buf, size_t size, off_t offset)
    {
    if (fioc_expand(offset + size))
    return -ENOMEM;
    memcpy(fioc_buf + offset, buf, size);
    return size;
    }
    static int fioc_write(const char *path, const char *buf, size_t size,
    off_t offset, struct fuse_file_info *fi)
    {
    (void) fi;
    if (fioc_file_type(path) != FIOC_FILE)
    return -EINVAL;
    return fioc_do_write(buf, size, offset);
    }
    static int fioc_truncate(const char *path, off_t size,
    struct fuse_file_info *fi)
    {
    (void) fi;
    if (fioc_file_type(path) != FIOC_FILE)
    return -EINVAL;
    return fioc_resize(size);
    }
    static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
    off_t offset, struct fuse_file_info *fi,
    enum fuse_readdir_flags flags)
    {
    (void) fi;
    (void) offset;
    (void) flags;
    if (fioc_file_type(path) != FIOC_ROOT)
    return -ENOENT;
    filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    filler(buf, FIOC_NAME, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    return 0;
    }
    static int fioc_ioctl(const char *path, unsigned 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 const 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);
    }
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    #define FUSE_IOCTL_COMPAT

    Definition in file ioctl.c.

    fuse-3.18.3/doc/html/ioctl_8h.html0000644000175000017500000001256315250106404015632 0ustar berndbernd libfuse: example/ioctl.h File Reference
    libfuse
    ioctl.h File Reference
    #include <sys/types.h>
    #include <sys/uio.h>
    #include <sys/ioctl.h>

    Go to the source code of this file.

    Detailed Description

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

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

    Definition in file ioctl.h.

    fuse-3.18.3/doc/html/ioctl__client_8c.html0000644000175000017500000001761415250106404017324 0ustar berndbernd 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 <unistd.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 can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #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 <unistd.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;
    int ret = 0;
    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");
    ret = 1;
    goto out;
    }
    printf("%zu\n", size);
    } else {
    size = strtoul(argv[2], NULL, 0);
    if (ioctl(fd, FIOC_SET_SIZE, &size)) {
    perror("ioctl");
    ret = 1;
    goto out;
    }
    }
    out:
    close(fd);
    return ret;
    }

    Definition in file ioctl_client.c.

    fuse-3.18.3/doc/html/notify__inval__entry_8c.html0000644000175000017500000014744315250106404020741 0ustar berndbernd libfuse: example/notify_inval_entry.c File Reference
    libfuse
    notify_inval_entry.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 <signal.h>
    #include <stddef.h>
    #include <sys/stat.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 file name changes dynamically to reflect the current time.

    It illustrates the use of the fuse_lowlevel_notify_inval_entry() and fuse_lowlevel_notify_expire_entry() functions.

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

    $ notify_inval_entry --update-interval=1 --timeout=30 --no-notify mnt/
    

    Observe that ls always prints the correct directory contents (since readdir output is not cached)::

    $ ls mnt; sleep 1; ls mnt; sleep 1; ls mnt
    Time_is_15h_48m_33s  current_time
    Time_is_15h_48m_34s  current_time
    Time_is_15h_48m_35s  current_time
    

    However, if you try to access a file by name the kernel will report that it still exists:

    $ file=$(ls mnt/); echo $file
    Time_is_15h_50m_09s
    $ sleep 5; stat mnt/$file
      File: ‘mnt/Time_is_15h_50m_09s’
      Size: 32                Blocks: 0          IO Block: 4096   regular file
    Device: 2ah/42d     Inode: 3           Links: 1
    Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 1969-12-31 16:00:00.000000000 -0800
    Modify: 1969-12-31 16:00:00.000000000 -0800
    Change: 1969-12-31 16:00:00.000000000 -0800
     Birth: -
    

    Only once the kernel cache timeout has been reached will the stat call fail:

    $ sleep 30; stat mnt/$file
    stat: cannot stat ‘mnt/Time_is_15h_50m_09s’: No such file or directory
    

    In contrast, if you enable notifications you will be unable to stat the file as soon as the file system updates its name:

    $ notify_inval_entry --update-interval=1 --timeout=30 mnt/
    $ file=$(ls mnt/); stat mnt/$file
      File: ‘mnt/Time_is_20h_42m_11s’
      Size: 0                 Blocks: 0          IO Block: 4096   regular empty file
    Device: 2ah/42d     Inode: 2           Links: 1
    Access: (0000/----------)  Uid: (    0/    root)   Gid: (    0/    root)
    Access: 1969-12-31 16:00:00.000000000 -0800
    Modify: 1969-12-31 16:00:00.000000000 -0800
    Change: 1969-12-31 16:00:00.000000000 -0800
     Birth: -
    $ sleep 1; stat mnt/$file
    stat: cannot stat ‘mnt/Time_is_20h_42m_11s’: No such file or directory
    

    To use the function fuse_lowlevel_notify_expire_entry() instead of fuse_lowlevel_notify_inval_entry(), use the command line option –only-expire

    Another possible command-line option is –inc-epoch, which will use the FUSE low-level function fuse_lowlevel_notify_increment_epoch() instead. This will function will force the invalidation of all dentries next time they are revalidated. Note that –inc-epoch and –only-expire options are mutually exclusive.

    Compilation

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

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <assert.h>
    #include <signal.h>
    #include <stddef.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <pthread.h>
    #define MAX_STR_LEN 128
    static char file_name[MAX_STR_LEN];
    static fuse_ino_t file_ino = 2;
    static int lookup_cnt = 0;
    static pthread_t main_thread;
    /* Command line parsing */
    struct options {
    int no_notify;
    float timeout;
    int update_interval;
    int only_expire;
    int inc_epoch;
    };
    static struct options options = {
    .timeout = 5,
    .no_notify = 0,
    .update_interval = 1,
    .only_expire = 0,
    .inc_epoch = 0,
    };
    #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),
    OPTION("--timeout=%f", timeout),
    OPTION("--only-expire", only_expire),
    OPTION("--inc-epoch", inc_epoch),
    };
    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 | 0000;
    stbuf->st_nlink = 1;
    stbuf->st_size = 0;
    }
    else
    return -1;
    return 0;
    }
    static void tfs_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    }
    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 = options.timeout;
    e.entry_timeout = options.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, options.timeout);
    }
    struct dirbuf {
    char *p;
    size_t size;
    };
    static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
    {
    struct stat stbuf;
    size_t oldsize = b->size;
    b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
    b->p = (char *)realloc(b->p, b->size);
    memset(&stbuf, 0, sizeof(stbuf));
    stbuf.st_ino = ino;
    fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
    b->size);
    }
    #define min(x, y) ((x) < (y) ? (x) : (y))
    static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize,
    off_t off, size_t maxsize)
    {
    if (off < bufsize)
    return fuse_reply_buf(req, buf + off,
    min(bufsize - off, maxsize));
    else
    return fuse_reply_buf(req, NULL, 0);
    }
    static void 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 const struct fuse_lowlevel_ops tfs_oper = {
    .init = tfs_init,
    .lookup = tfs_lookup,
    .getattr = tfs_getattr,
    .readdir = tfs_readdir,
    .forget = tfs_forget,
    };
    static void update_fs(void)
    {
    time_t t;
    struct tm tmbuf;
    struct tm *now;
    ssize_t ret;
    t = time(NULL);
    now = localtime_r(&t, &tmbuf);
    assert(now != NULL);
    ret = strftime(file_name, MAX_STR_LEN, "Time_is_%Hh_%Mm_%Ss", now);
    assert(ret != 0);
    }
    static void *update_fs_loop(void *data)
    {
    struct fuse_session *se = (struct fuse_session *)data;
    char *old_name;
    int ret = 0;
    while (!fuse_session_exited(se)) {
    old_name = strdup(file_name);
    update_fs();
    if (!options.no_notify && lookup_cnt) {
    if (options.only_expire) { // expire entry
    se, FUSE_ROOT_ID, old_name,
    strlen(old_name));
    // no kernel support
    if (ret == -ENOSYS) {
    printf("%s not supported by kernel\n",
    "fuse_lowlevel_notify_expire_entry");
    break;
    }
    // 1) ret == 0: successful expire of an existing entry
    // 2) ret == -ENOENT: kernel has already expired the entry /
    // entry does not exist anymore in the kernel
    assert(ret == 0 || ret == -ENOENT);
    } else if (options.inc_epoch) { // increment epoch
    if (ret == -ENOSYS) {
    printf("%s not supported by kernel\n",
    "fuse_lowlevel_notify_increment_epoch");
    break;
    }
    assert(ret == 0);
    } else { // invalidate entry
    se, FUSE_ROOT_ID, old_name,
    strlen(old_name)) == 0);
    }
    }
    free(old_name);
    sleep(options.update_interval);
    }
    if (ret == -ENOSYS) {
    printf("Exiting...\n");
    // Make sure to exit now, rather than on next request from userspace
    pthread_kill(main_thread, SIGPIPE);
    }
    return NULL;
    }
    static void show_help(const char *progname)
    {
    printf("usage: %s [options] <mountpoint>\n\n", progname);
    printf("File-system specific options:\n"
    " --timeout=<secs> Timeout for kernel caches\n"
    " --update-interval=<secs> Update-rate of file system contents\n"
    " --no-notify Disable kernel notifications\n"
    " --only-expire Expire entries instead of invalidating them\n"
    " --inc-epoch Increment epoch, invalidating all dentries\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;
    struct fuse_loop_config *config;
    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)
    return 1;
    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;
    }
    if (options.only_expire && options.inc_epoch) {
    printf("'only-expire' and 'inc-epoch' options are exclusive\n");
    ret = 0;
    goto err_out1;
    }
    /* Initial contents */
    update_fs();
    se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), &se);
    if (se == NULL)
    goto err_out1;
    goto err_out2;
    if (fuse_session_mount(se, opts.mountpoint) != 0)
    goto err_out3;
    fuse_daemonize(opts.foreground);
    // Needed to ensure that the main thread continues/restarts processing as soon
    // as the fuse session ends (immediately after calling fuse_session_exit() )
    // and not only on the next request from userspace
    main_thread = pthread_self();
    /* 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 {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    return ret ? 1 : 0;
    }
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_exited(struct fuse_session *se)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
    int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse_ino_t ino

    Definition in file notify_inval_entry.c.

    fuse-3.18.3/doc/html/notify__inval__inode_8c.html0000644000175000017500000014253715250106404020675 0ustar berndbernd 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>
    #include <stdbool.h>
    #include <stdatomic.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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    #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>
    #include <stdbool.h>
    #include <stdatomic.h>
    /* We can't actually tell the kernel that there is no
    timeout, so we just send a big value */
    #define NO_TIMEOUT 500000
    #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;
    static _Atomic bool is_stop = false;
    /* 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), FUSE_OPT_END
    };
    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_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    }
    static void tfs_destroy(void *userarg)
    {
    (void)userarg;
    is_stop = true;
    }
    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,
    {
    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 & O_ACCMODE) != 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 const struct fuse_lowlevel_ops tfs_oper = {
    .init = tfs_init,
    .destroy = tfs_destroy,
    .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 tmbuf;
    struct tm *now;
    time_t t;
    t = time(NULL);
    now = localtime_r(&t, &tmbuf);
    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 (!is_stop) {
    update_fs();
    if (!options.no_notify && lookup_cnt) {
    /* Only send notification if the kernel is aware of the inode */
    /* Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they
    * might come up during umount, when kernel side already releases
    * all inodes, but does not send FUSE_DESTROY yet.
    */
    int ret = fuse_lowlevel_notify_inval_inode(se, FILE_INO,
    0, 0);
    if ((ret != 0 && !is_stop) && ret != -ENOENT &&
    ret != -EBADF && ret != -ENODEV) {
    fprintf(stderr,
    "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n",
    strerror(-ret), -ret);
    abort();
    }
    }
    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;
    struct fuse_loop_config *config;
    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 {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    return ret ? 1 : 0;
    }
    int fuse_set_signal_handlers(struct fuse_session *se)
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    uint32_t no_interrupt
    fuse_ino_t ino
    uint32_t keep_cache
    Definition fuse_common.h:69

    Definition in file notify_inval_inode.c.

    fuse-3.18.3/doc/html/notify__store__retrieve_8c.html0000644000175000017500000016241715250106404021446 0ustar berndbernd libfuse: example/notify_store_retrieve.c File Reference
    libfuse
    notify_store_retrieve.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>
    #include <stdbool.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_inval_inode.c uses fuse_lowlevel_notify_inval_inode() to let the kernel know that it has to invalidate the cache, this example actively pushes the updated data into the kernel cache using fuse_lowlevel_notify_store().

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

    $ notify_store_retrieve --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_store_retrieve --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_store_retrieve.c `pkg-config fuse3 --cflags --libs` -o notify_store_retrieve
    

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12)
    #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>
    #include <stdbool.h>
    /* We can't actually tell the kernel that there is no
    timeout, so we just send a big value */
    #define NO_TIMEOUT 500000
    #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 int open_cnt = 0;
    static size_t file_size;
    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
    /* Keep track if we ever stored data (==1), and
    received it back correctly (==2) */
    static int retrieve_status = 0;
    static bool is_umount = false;
    /* updater thread tid */
    static pthread_t updater;
    /* 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), FUSE_OPT_END
    };
    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_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void)userdata;
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    }
    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;
    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);
    /*
    * must only be set when the kernel knows about the entry,
    * otherwise update_fs_loop() might see a positive count, but kernel
    * would not have the entry yet
    */
    if (e.ino == FILE_INO) {
    pthread_mutex_lock(&lock);
    lookup_cnt++;
    pthread_mutex_unlock(&lock);
    }
    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) {
    pthread_mutex_lock(&lock);
    lookup_cnt -= nlookup;
    pthread_mutex_unlock(&lock);
    } 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,
    {
    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 & O_ACCMODE) != O_RDONLY)
    fuse_reply_err(req, EACCES);
    else if (ino == FILE_INO) {
    fuse_reply_open(req, fi);
    pthread_mutex_lock(&lock);
    open_cnt++;
    pthread_mutex_unlock(&lock);
    } 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 void tfs_retrieve_reply(fuse_req_t req, void *cookie, fuse_ino_t ino,
    off_t offset, struct fuse_bufvec *data)
    {
    struct fuse_bufvec bufv;
    char buf[MAX_STR_LEN];
    char *expected;
    ssize_t ret;
    assert(ino == FILE_INO);
    assert(offset == 0);
    expected = (char *)cookie;
    bufv.count = 1;
    bufv.idx = 0;
    bufv.off = 0;
    bufv.buf[0].size = MAX_STR_LEN;
    bufv.buf[0].mem = buf;
    bufv.buf[0].flags = 0;
    ret = fuse_buf_copy(&bufv, data, 0);
    assert(ret > 0);
    assert(strncmp(buf, expected, ret) == 0);
    free(expected);
    retrieve_status = 2;
    }
    static void tfs_destroy(void *userdata)
    {
    (void)userdata;
    is_umount = true;
    pthread_join(updater, NULL);
    }
    static const struct fuse_lowlevel_ops tfs_oper = {
    .init = tfs_init,
    .lookup = tfs_lookup,
    .getattr = tfs_getattr,
    .readdir = tfs_readdir,
    .open = tfs_open,
    .read = tfs_read,
    .forget = tfs_forget,
    .retrieve_reply = tfs_retrieve_reply,
    .destroy = tfs_destroy,
    };
    static void update_fs(void)
    {
    struct tm tmbuf;
    struct tm *now;
    time_t t;
    t = time(NULL);
    now = localtime_r(&t, &tmbuf);
    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;
    struct fuse_bufvec bufv;
    int ret;
    while (!is_umount) {
    update_fs();
    pthread_mutex_lock(&lock);
    if (!options.no_notify && open_cnt && lookup_cnt) {
    /* Only send notification if the kernel
    is aware of the inode */
    bufv.count = 1;
    bufv.idx = 0;
    bufv.off = 0;
    bufv.buf[0].size = file_size;
    bufv.buf[0].mem = file_contents;
    bufv.buf[0].flags = 0;
    /*
    * Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they
    * might come up during umount, when kernel side already releases
    * all inodes, but does not send FUSE_DESTROY yet.
    */
    ret = fuse_lowlevel_notify_store(se, FILE_INO, 0, &bufv,
    0);
    if ((ret != 0 && !is_umount) && ret != -ENOENT &&
    ret != -EBADF && ret != -ENODEV) {
    fprintf(stderr,
    "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n",
    strerror(-ret), -ret);
    abort();
    }
    /* To make sure that everything worked correctly, ask the
    kernel to send us back the stored data */
    se, FILE_INO, MAX_STR_LEN, 0,
    (void *)strdup(file_contents));
    assert((ret == 0 || is_umount) || ret == -ENOENT ||
    ret == -EBADF || ret != -ENODEV);
    if (retrieve_status == 0)
    retrieve_status = 1;
    }
    pthread_mutex_unlock(&lock);
    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;
    struct fuse_loop_config *config;
    int ret = -1;
    if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1)
    return 1;
    if (fuse_parse_cmdline(&args, &opts) != 0)
    return 1;
    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 {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    assert(retrieve_status != 1);
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    return ret ? 1 : 0;
    }
    int fuse_set_signal_handlers(struct fuse_session *se)
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    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)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    enum fuse_buf_flags flags
    struct fuse_buf buf[1]
    uint32_t no_interrupt
    fuse_ino_t ino
    uint32_t keep_cache
    Definition fuse_common.h:69

    Definition in file notify_store_retrieve.c.

    fuse-3.18.3/doc/html/null_8c.html0000644000175000017500000021516415250106404015467 0ustar berndbernd libfuse: example/null.c File Reference
    libfuse
    null.c File Reference
    #include <fuse.h>
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
    #include <errno.h>

    Go to the source code of this file.

    Detailed Description

    This "filesystem" provides only a single file. The mountpoint needs to be a file rather than a directory. All writes to the file will be discarded, and reading the file always returns \0.

    Compile with:

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

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    #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) */
    #include "passthrough_helpers.h"
    static void *xmp_init(struct fuse_conn_info *conn,
    struct fuse_config *cfg)
    {
    (void) conn;
    cfg->use_ino = 1;
    cfg->nullpath_ok = 1;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need either set cfg->direct_io
    in current function (recommended in high level API) or set fi->direct_io
    in xmp_create() or xmp_open(). */
    // cfg->direct_io = 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;
    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;
    /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    for writes to the same file). */
    if (fi->flags & O_DIRECT) {
    fi->direct_io = 1;
    }
    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;
    }
    static int xmp_fallocate(const char *path, int mode,
    off_t offset, off_t length, struct fuse_file_info *fi)
    {
    (void) path;
    return do_fallocate(fi->fh, mode, offset, length);
    }
    #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 off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
    {
    off_t res;
    (void) path;
    res = lseek(fi->fh, off, whence);
    if (res == -1)
    return -errno;
    return res;
    }
    #ifdef HAVE_STATX
    static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    struct fuse_file_info *fi)
    {
    int fd = -1;
    int res;
    if (fi)
    fd = fi->fh;
    res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf);
    if (res == -1)
    return -errno;
    return 0;
    }
    #endif
    static const 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,
    .fallocate = xmp_fallocate,
    #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
    .lseek = xmp_lseek,
    #ifdef HAVE_STATX
    .statx = xmp_statx,
    #endif
    };
    int main(int argc, char *argv[])
    {
    umask(0);
    return fuse_main(argc, argv, &xmp_oper, NULL);
    }
    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:93
    fuse_fill_dir_flags
    Definition fuse.h:61
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    @ FUSE_BUF_SPLICE_NONBLOCK
    enum fuse_buf_flags flags
    off_t pos
    struct fuse_buf buf[1]
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint64_t lock_owner
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63

    Definition in file null.c.

    fuse-3.18.3/doc/html/passthrough_8c.html0000644000175000017500000015344115250106404017063 0ustar berndbernd 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>
    #include "passthrough_helpers.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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    #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
    #include "passthrough_helpers.h"
    static int fill_dir_plus = 0;
    static int readdir_zero_ino;
    static void *xmp_init(struct fuse_conn_info *conn,
    struct fuse_config *cfg)
    {
    (void) conn;
    cfg->use_ino = !readdir_zero_ino;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need either set cfg->direct_io
    in current function (recommended in high level API) or set fi->direct_io
    in xmp_create() or xmp_open(). */
    // cfg->direct_io = 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. */
    if (!cfg->auto_cache) {
    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;
    if (fill_dir_plus) {
    fstatat(dirfd(dp), de->d_name, &st,
    AT_SYMLINK_NOFOLLOW);
    } else {
    memset(&st, 0, sizeof(st));
    st.st_ino = de->d_ino;
    st.st_mode = de->d_type << 12;
    }
    if (readdir_zero_ino)
    st.st_ino = 0;
    if (filler(buf, de->d_name, &st, 0, fill_dir_plus))
    break;
    }
    closedir(dp);
    return 0;
    }
    static int xmp_mknod(const char *path, mode_t mode, dev_t rdev)
    {
    int res;
    res = mknod_wrapper(AT_FDCWD, path, NULL, 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;
    /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    for writes to the same file). */
    if (fi->flags & O_DIRECT) {
    fi->direct_io = 1;
    }
    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;
    }
    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(fi == NULL)
    fd = open(path, O_WRONLY);
    else
    fd = fi->fh;
    if (fd == -1)
    return -errno;
    res = do_fallocate(fd, mode, offset, length);
    if(fi == NULL)
    close(fd);
    return res;
    }
    #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;
    if (fi_out == NULL)
    close(fd_out);
    if (fi_in == NULL)
    close(fd_in);
    return res;
    }
    #endif
    static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
    {
    int fd;
    off_t res;
    if (fi == NULL)
    fd = open(path, O_RDONLY);
    else
    fd = fi->fh;
    if (fd == -1)
    return -errno;
    res = lseek(fd, off, whence);
    if (res == -1)
    res = -errno;
    if (fi == NULL)
    close(fd);
    return res;
    }
    #ifdef HAVE_STATX
    static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    struct fuse_file_info *fi)
    {
    int fd = -1;
    int res;
    if (fi)
    fd = fi->fh;
    res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf);
    if (res == -1)
    return -errno;
    return 0;
    }
    #endif
    static const 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,
    .fallocate = xmp_fallocate,
    #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
    .lseek = xmp_lseek,
    #ifdef HAVE_STATX
    .statx = xmp_statx,
    #endif
    };
    int main(int argc, char *argv[])
    {
    enum { MAX_ARGS = 10 };
    int i,new_argc;
    char *new_argv[MAX_ARGS];
    umask(0);
    /* Process the "--plus" option apart */
    for (i=0, new_argc=0; (i<argc) && (new_argc<MAX_ARGS); i++) {
    if (!strcmp(argv[i], "--plus")) {
    fill_dir_plus = FUSE_FILL_DIR_PLUS;
    } else if (!strcmp(argv[i], "--readdir-zero-inodes")) {
    // Return zero inodes from readdir
    readdir_zero_ino = 1;
    } else {
    new_argv[new_argc++] = argv[i];
    }
    }
    return fuse_main(new_argc, new_argv, &xmp_oper, NULL);
    }
    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:93
    fuse_readdir_flags
    Definition fuse.h:45
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    int32_t auto_cache
    Definition fuse.h:259
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63

    Definition in file passthrough.c.

    fuse-3.18.3/doc/html/passthrough__fh_8c.html0000644000175000017500000021602415250106404017674 0ustar berndbernd 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>
    #include "passthrough_helpers.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 GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    #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) */
    #include "passthrough_helpers.h"
    static void *xmp_init(struct fuse_conn_info *conn,
    struct fuse_config *cfg)
    {
    (void) conn;
    cfg->use_ino = 1;
    cfg->nullpath_ok = 1;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need either set cfg->direct_io
    in current function (recommended in high level API) or set fi->direct_io
    in xmp_create() or xmp_open(). */
    // cfg->direct_io = 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;
    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;
    /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    for writes to the same file). */
    if (fi->flags & O_DIRECT) {
    fi->direct_io = 1;
    }
    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;
    }
    static int xmp_fallocate(const char *path, int mode,
    off_t offset, off_t length, struct fuse_file_info *fi)
    {
    (void) path;
    return do_fallocate(fi->fh, mode, offset, length);
    }
    #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 off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi)
    {
    off_t res;
    (void) path;
    res = lseek(fi->fh, off, whence);
    if (res == -1)
    return -errno;
    return res;
    }
    #ifdef HAVE_STATX
    static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf,
    struct fuse_file_info *fi)
    {
    int fd = -1;
    int res;
    if (fi)
    fd = fi->fh;
    res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf);
    if (res == -1)
    return -errno;
    return 0;
    }
    #endif
    static const 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,
    .fallocate = xmp_fallocate,
    #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
    .lseek = xmp_lseek,
    #ifdef HAVE_STATX
    .statx = xmp_statx,
    #endif
    };
    int main(int argc, char *argv[])
    {
    umask(0);
    return fuse_main(argc, argv, &xmp_oper, NULL);
    }
    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:93
    fuse_fill_dir_flags
    Definition fuse.h:61
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    @ FUSE_BUF_SPLICE_NONBLOCK
    enum fuse_buf_flags flags
    off_t pos
    struct fuse_buf buf[1]
    int32_t nullpath_ok
    Definition fuse.h:279
    int32_t parallel_direct_writes
    Definition fuse.h:318
    int32_t use_ino
    Definition fuse.h:204
    double entry_timeout
    Definition fuse.h:133
    double negative_timeout
    Definition fuse.h:143
    double attr_timeout
    Definition fuse.h:149
    uint64_t lock_owner
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63

    Definition in file passthrough_fh.c.

    fuse-3.18.3/doc/html/passthrough__ll_8c.html0000644000175000017500000050522715250106404017714 0ustar berndbernd libfuse: example/passthrough_ll.c File Reference
    libfuse
    passthrough_ll.c File Reference
    #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 <inttypes.h>
    #include <pthread.h>
    #include <sys/file.h>
    #include <sys/xattr.h>
    #include "passthrough_helpers.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.

    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 GPLv2.
    See the file GPL2.txt.
    */
    #define _GNU_SOURCE
    #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18)
    #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 <inttypes.h>
    #include <pthread.h>
    #include <sys/file.h>
    #include <sys/xattr.h>
    #include "passthrough_helpers.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;
    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;
    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 void passthrough_ll_help(void)
    {
    printf(
    " -o writeback Enable writeback\n"
    " -o no_writeback Disable write back\n"
    " -o source=/home/dir Source directory to be mounted\n"
    " -o flock Enable flock\n"
    " -o no_flock Disable flock\n"
    " -o xattr Enable xattr\n"
    " -o no_xattr Disable xattr\n"
    " -o timeout=1.0 Caching timeout\n"
    " -o timeout=0/1 Timeout is set\n"
    " -o cache=never Disable cache\n"
    " -o cache=auto Auto enable cache\n"
    " -o cache=always Cache always\n");
    }
    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;
    bool has_flag;
    if (lo->writeback) {
    if (lo->debug && has_flag)
    fuse_log(FUSE_LOG_DEBUG,
    "lo_init: activating writeback\n");
    }
    if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) {
    if (lo->debug && has_flag)
    fuse_log(FUSE_LOG_DEBUG,
    "lo_init: activating flock locks\n");
    }
    /* Disable the receiving and processing of FUSE_INTERRUPT requests */
    conn->no_interrupt = 1;
    }
    static void lo_destroy(void *userdata)
    {
    struct lo_data *lo = (struct lo_data*) userdata;
    while (lo->root.next != &lo->root) {
    struct lo_inode* next = lo->root.next;
    lo->root.next = next->next;
    close(next->fd);
    free(next);
    }
    }
    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);
    int fd = fi ? fi->fh : lo_fd(req, ino);
    (void) fi;
    res = fstatat(fd, "", &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 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 {
    sprintf(procname, "/proc/self/fd/%i", ifd);
    res = utimensat(AT_FDCWD, procname, tv, 0);
    }
    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 struct lo_inode *create_new_inode(int fd, struct fuse_entry_param *e, struct lo_data* lo)
    {
    struct lo_inode *inode = NULL;
    struct lo_inode *prev, *next;
    inode = calloc(1, sizeof(struct lo_inode));
    if (!inode)
    return NULL;
    inode->refcount = 1;
    inode->fd = fd;
    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);
    return inode;
    }
    static int fill_entry_param_new_inode(fuse_req_t req, fuse_ino_t parent, int fd, struct fuse_entry_param *e)
    {
    int res;
    struct lo_data *lo = lo_data(req);
    memset(e, 0, sizeof(*e));
    e->attr_timeout = lo->timeout;
    e->entry_timeout = lo->timeout;
    res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW);
    if (res == -1)
    return errno;
    e->ino = (uintptr_t) create_new_inode(dup(fd), e, lo);
    if (lo_debug(req))
    fuse_log(FUSE_LOG_DEBUG, " %lli/%d -> %lli\n",
    (unsigned long long) parent, fd, (unsigned long long) e->ino);
    return 0;
    }
    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 {
    inode = create_new_inode(newfd, e, lo);
    if (!inode)
    goto out_err;
    }
    e->ino = (uintptr_t) inode;
    if (lo_debug(req))
    fuse_log(FUSE_LOG_DEBUG, " %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))
    fuse_log(FUSE_LOG_DEBUG, "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 res;
    int saverr;
    struct lo_inode *dir = lo_inode(req, parent);
    struct fuse_entry_param e;
    res = mknod_wrapper(dir->fd, name, link, 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))
    fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n",
    (unsigned long long) parent, name, (unsigned long long) e.ino);
    fuse_reply_entry(req, &e);
    return;
    out:
    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 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;
    char procname[64];
    int saverr;
    memset(&e, 0, sizeof(struct fuse_entry_param));
    e.attr_timeout = lo->timeout;
    e.entry_timeout = lo->timeout;
    sprintf(procname, "/proc/self/fd/%i", inode->fd);
    res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name,
    AT_SYMLINK_FOLLOW);
    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))
    fuse_log(FUSE_LOG_DEBUG, " %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)) {
    fuse_log(FUSE_LOG_DEBUG, " 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 {
    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;
    int fd = -1;
    d = calloc(1, sizeof(struct lo_dirp));
    if (d == NULL)
    goto out_err;
    fd = openat(lo_fd(req, ino), ".", O_RDONLY);
    if (fd == -1)
    goto out_errno;
    d->dp = fdopendir(fd);
    if (d->dp == NULL)
    goto out_errno;
    d->offset = 0;
    d->entry = NULL;
    fi->fh = (uintptr_t) d;
    if (lo->cache != CACHE_NEVER)
    fi->cache_readdir = 1;
    if (lo->cache == CACHE_ALWAYS)
    fi->keep_cache = 1;
    fuse_reply_open(req, fi);
    return;
    out_errno:
    error = errno;
    out_err:
    if (d) {
    if (fd != -1)
    close(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_tmpfile(fuse_req_t req, fuse_ino_t parent,
    mode_t mode, struct fuse_file_info *fi)
    {
    int fd;
    struct lo_data *lo = lo_data(req);
    struct fuse_entry_param e;
    int err;
    if (lo_debug(req))
    fuse_log(FUSE_LOG_DEBUG, "lo_tmpfile(parent=%" PRIu64 ")\n",
    parent);
    fd = openat(lo_fd(req, parent), ".",
    (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode);
    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;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need set fi->direct_io
    in current function. */
    err = fill_entry_param_new_inode(req, parent, fd, &e);
    if (err)
    fuse_reply_err(req, err);
    else
    fuse_reply_create(req, &e, fi);
    }
    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 lo_data *lo = lo_data(req);
    struct fuse_entry_param e;
    int err;
    if (lo_debug(req))
    fuse_log(FUSE_LOG_DEBUG, "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;
    if (lo->cache == CACHE_NEVER)
    fi->direct_io = 1;
    else if (lo->cache == CACHE_ALWAYS)
    fi->keep_cache = 1;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need set fi->direct_io
    in current function. */
    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))
    fuse_log(FUSE_LOG_DEBUG, "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;
    /* Enable direct_io when open has flags O_DIRECT to enjoy the feature
    parallel_direct_writes (i.e., to get a shared lock, not exclusive lock,
    for writes to the same file in the kernel). */
    if (fi->flags & O_DIRECT)
    fi->direct_io = 1;
    /* parallel_direct_writes feature depends on direct_io features.
    To make parallel_direct_writes valid, need set fi->direct_io
    in current function. */
    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))
    fuse_log(FUSE_LOG_DEBUG, "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))
    fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%jd)\n",
    ino, out_buf.buf[0].size, (intmax_t) 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;
    err = -do_fallocate(fi->fh, mode, 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)) {
    fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n",
    ino, name, size);
    }
    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)) {
    fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n",
    ino, size);
    }
    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)) {
    fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n",
    ino, name, value, size);
    }
    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)) {
    fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n",
    ino, name);
    }
    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))
    fuse_log(FUSE_LOG_DEBUG,
    "%s(ino=%lld fd=%lld off=%jd ino=%lld fd=%lld off=%jd, size=%zd, flags=0x%x)\n",
    __func__, (unsigned long long)ino_in,
    (unsigned long long)fi_in->fh,
    (intmax_t) off_in, (unsigned long long)ino_out,
    (unsigned long long)fi_out->fh, (intmax_t) 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 void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
    struct fuse_file_info *fi)
    {
    off_t res;
    (void)ino;
    res = lseek(fi->fh, off, whence);
    if (res != -1)
    fuse_reply_lseek(req, res);
    else
    fuse_reply_err(req, errno);
    }
    #ifdef HAVE_STATX
    static void lo_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask,
    struct fuse_file_info *fi)
    {
    struct lo_data *lo = lo_data(req);
    struct statx buf;
    int res;
    int fd;
    if (fi)
    fd = fi->fh;
    else
    fd = lo_fd(req, ino);
    res = statx(fd, "", flags | AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, mask, &buf);
    if (res == -1)
    fuse_reply_err(req, errno);
    else
    fuse_reply_statx(req, 0, &buf, lo->timeout);
    }
    #endif
    static const struct fuse_lowlevel_ops lo_oper = {
    .init = lo_init,
    .destroy = lo_destroy,
    .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,
    .tmpfile = lo_tmpfile,
    .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
    .lseek = lo_lseek,
    #ifdef HAVE_STATX
    .statx = lo_statx,
    #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 fuse_loop_config *config;
    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]);
    passthrough_ll_help();
    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) {
    fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n",
    lo.source);
    exit(1);
    }
    if (!S_ISDIR(stat.st_mode)) {
    fuse_log(FUSE_LOG_ERR, "source is not a directory\n");
    exit(1);
    }
    } else {
    lo.source = strdup("/");
    if(!lo.source) {
    fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n");
    exit(1);
    }
    }
    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) {
    fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n",
    lo.timeout);
    exit(1);
    }
    lo.root.fd = open(lo.source, O_PATH);
    if (lo.root.fd == -1) {
    fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n",
    lo.source);
    exit(1);
    }
    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 {
    config = fuse_loop_cfg_create();
    fuse_loop_cfg_set_clone_fd(config, opts.clone_fd);
    fuse_loop_cfg_set_max_threads(config, opts.max_threads);
    ret = fuse_session_loop_mt(se, config);
    fuse_loop_cfg_destroy(config);
    config = NULL;
    }
    err_out3:
    err_out2:
    err_out1:
    free(opts.mountpoint);
    if (lo.root.fd >= 0)
    close(lo.root.fd);
    free(lo.source);
    return ret ? 1 : 0;
    }
    bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    int fuse_set_signal_handlers(struct fuse_session *se)
    size_t fuse_buf_size(const struct fuse_bufvec *bufv)
    Definition buffer.c:22
    #define FUSE_CAP_WRITEBACK_CACHE
    @ FUSE_BUF_FD_SEEK
    @ FUSE_BUF_IS_FD
    ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    Definition buffer.c:284
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    @ FUSE_BUF_SPLICE_MOVE
    int fuse_daemonize(int foreground)
    Definition helper.c:253
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void fuse_session_destroy(struct fuse_session *se)
    int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_err(fuse_req_t req, int err)
    void * fuse_req_userdata(fuse_req_t req)
    int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    struct fuse_req * fuse_req_t
    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_readlink(fuse_req_t req, const char *link)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    void fuse_session_unmount(struct fuse_session *se)
    void fuse_cmdline_help(void)
    Definition helper.c:130
    void fuse_reply_none(fuse_req_t req)
    void fuse_lowlevel_help(void)
    int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_write(fuse_req_t req, size_t count)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_lseek(fuse_req_t req, off_t off)
    void fuse_lowlevel_version(void)
    int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    uint64_t fuse_ino_t
    size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_xattr(fuse_req_t req, size_t count)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    Definition fuse_opt.c:398
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    #define FUSE_OPT_END
    Definition fuse_opt.h:104
    char ** argv
    Definition fuse_opt.h:114
    enum fuse_buf_flags flags
    off_t pos
    size_t size
    struct fuse_buf buf[1]
    uint32_t no_interrupt
    uint32_t capable
    double entry_timeout
    fuse_ino_t ino
    double attr_timeout
    struct stat attr
    uint32_t cache_readdir
    Definition fuse_common.h:89
    uint32_t parallel_direct_writes
    Definition fuse_common.h:97
    uint32_t direct_io
    Definition fuse_common.h:63
    uint32_t keep_cache
    Definition fuse_common.h:69

    Definition in file passthrough_ll.c.

    fuse-3.18.3/doc/html/poll_8c.html0000644000175000017500000007576515250106404015476 0ustar berndbernd libfuse: example/poll.c File Reference
    libfuse
    poll.c File Reference
    #include <fuse.h>
    #include <unistd.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <time.h>
    #include <pthread.h>
    #include <poll.h>
    #include <stdbool.h>

    Go to the source code of this file.

    Detailed Description

    This example illustrates how to write a FUSE file system that supports polling for changes that don't come through the kernel. It can be tested with the poll_client.c program.

    Compile with:

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

    Source code

    /*
    FUSE fsel: FUSE select example
    Copyright (C) 2008 SUSE Linux Products GmbH
    Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION 31
    #include <fuse.h>
    #include <unistd.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <time.h>
    #include <pthread.h>
    #include <poll.h>
    #include <stdbool.h>
    /*
    * 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 up to 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 _Atomic bool fsel_stop = false;
    static pthread_t fsel_producer_thread;
    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 void fsel_destroy(void *private_data)
    {
    (void)private_data;
    fsel_stop = true;
    pthread_join(fsel_producer_thread, NULL);
    }
    static int fsel_getattr(const char *path, struct stat *stbuf,
    struct fuse_file_info *fi)
    {
    (void) fi;
    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,
    enum fuse_readdir_flags flags)
    {
    char name[2] = { };
    int i;
    (void) offset;
    (void) fi;
    (void) flags;
    if (strcmp(path, "/") != 0)
    return -ENOENT;
    for (i = 0; i < FSEL_FILES; i++) {
    name[0] = fsel_hex_map[i];
    filler(buf, name, NULL, 0, FUSE_FILL_DIR_DEFAULTS);
    }
    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 & O_ACCMODE) != 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)
    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 const struct fuse_operations fsel_oper = {
    .destroy = fsel_destroy,
    .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 (!fsel_stop) {
    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);
    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_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(&fsel_producer_thread, &attr, fsel_producer, NULL);
    if (errno) {
    perror("pthread_create");
    return 1;
    }
    ret = fuse_main(argc, argv, &fsel_oper, NULL);
    return ret;
    }
    struct fuse_context * fuse_get_context(void)
    Definition fuse.c:4711
    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:93
    @ FUSE_FILL_DIR_DEFAULTS
    Definition fuse.h:74
    fuse_readdir_flags
    Definition fuse.h:45
    void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
    struct fuse * fuse
    Definition fuse.h:879
    uint32_t nonseekable
    Definition fuse_common.h:78
    uint32_t direct_io
    Definition fuse_common.h:63

    Definition in file poll.c.

    fuse-3.18.3/doc/html/poll__client_8c.html0000644000175000017500000002156115250106404017154 0ustar berndbernd libfuse: example/poll_client.c File Reference
    libfuse
    poll_client.c File Reference
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>

    Go to the source code of this file.

    Detailed Description

    This program tests the poll.c example file systsem.

    Compile with:

     gcc -Wall poll_client.c -o poll_client
    

    Source code

    /*
    FUSE fselclient: FUSE select example client
    Copyright (C) 2008 SUSE Linux Products GmbH
    Copyright (C) 2008 Tejun Heo <teheo@suse.de>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #include <sys/select.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    int main(void)
    {
    static const char hex_map[] = "0123456789ABCDEF";
    const size_t fsel_files = sizeof(hex_map) - 1;
    int fds[sizeof(hex_map) - 1];
    size_t i, tries;
    int 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;
    for (tries = 0; tries < fsel_files; tries++) {
    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("%zX:", i);
    rc = read(fds[i], buf, sizeof(buf));
    if (rc < 0) {
    perror("read");
    return 1;
    }
    printf("%02d ", rc);
    }
    printf("\n");
    }
    return 0;
    }

    Definition in file poll_client.c.

    fuse-3.18.3/doc/html/printcap_8c.html0000644000175000017500000010432115250106404016325 0ustar berndbernd libfuse: example/printcap.c File Reference
    libfuse
    printcap.c File Reference
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>

    Go to the source code of this file.

    Detailed Description

    minimal example filesystem that prints out all capabilities supported by the kernel and then exits.

    Compile with:

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

    Source code

    /*
    FUSE: Filesystem in Userspace
    Copyright (C) 2017 Nikolaus Rath <Nikolaus@rath.org>
    This program can be distributed under the terms of the GNU GPLv2.
    See the file GPL2.txt.
    */
    #define FUSE_USE_VERSION 31
    #include <fuse_lowlevel.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <stdlib.h>
    struct fuse_session *se;
    // Define a structure to hold capability information
    struct cap_info {
    uint64_t flag;
    const char *name;
    };
    // Define an array of all capabilities
    static const struct cap_info capabilities[] = {
    {FUSE_CAP_ASYNC_READ, "FUSE_CAP_ASYNC_READ"},
    {FUSE_CAP_POSIX_LOCKS, "FUSE_CAP_POSIX_LOCKS"},
    {FUSE_CAP_ATOMIC_O_TRUNC, "FUSE_CAP_ATOMIC_O_TRUNC"},
    {FUSE_CAP_EXPORT_SUPPORT, "FUSE_CAP_EXPORT_SUPPORT"},
    {FUSE_CAP_DONT_MASK, "FUSE_CAP_DONT_MASK"},
    {FUSE_CAP_SPLICE_MOVE, "FUSE_CAP_SPLICE_MOVE"},
    {FUSE_CAP_SPLICE_READ, "FUSE_CAP_SPLICE_READ"},
    {FUSE_CAP_SPLICE_WRITE, "FUSE_CAP_SPLICE_WRITE"},
    {FUSE_CAP_FLOCK_LOCKS, "FUSE_CAP_FLOCK_LOCKS"},
    {FUSE_CAP_IOCTL_DIR, "FUSE_CAP_IOCTL_DIR"},
    {FUSE_CAP_AUTO_INVAL_DATA, "FUSE_CAP_AUTO_INVAL_DATA"},
    {FUSE_CAP_READDIRPLUS, "FUSE_CAP_READDIRPLUS"},
    {FUSE_CAP_READDIRPLUS_AUTO, "FUSE_CAP_READDIRPLUS_AUTO"},
    {FUSE_CAP_ASYNC_DIO, "FUSE_CAP_ASYNC_DIO"},
    {FUSE_CAP_WRITEBACK_CACHE, "FUSE_CAP_WRITEBACK_CACHE"},
    {FUSE_CAP_NO_OPEN_SUPPORT, "FUSE_CAP_NO_OPEN_SUPPORT"},
    {FUSE_CAP_PARALLEL_DIROPS, "FUSE_CAP_PARALLEL_DIROPS"},
    {FUSE_CAP_POSIX_ACL, "FUSE_CAP_POSIX_ACL"},
    {FUSE_CAP_CACHE_SYMLINKS, "FUSE_CAP_CACHE_SYMLINKS"},
    {FUSE_CAP_NO_OPENDIR_SUPPORT, "FUSE_CAP_NO_OPENDIR_SUPPORT"},
    {FUSE_CAP_EXPLICIT_INVAL_DATA, "FUSE_CAP_EXPLICIT_INVAL_DATA"},
    {FUSE_CAP_EXPIRE_ONLY, "FUSE_CAP_EXPIRE_ONLY"},
    {FUSE_CAP_SETXATTR_EXT, "FUSE_CAP_SETXATTR_EXT"},
    {FUSE_CAP_HANDLE_KILLPRIV, "FUSE_CAP_HANDLE_KILLPRIV"},
    {FUSE_CAP_HANDLE_KILLPRIV_V2, "FUSE_CAP_HANDLE_KILLPRIV_V2"},
    {FUSE_CAP_DIRECT_IO_ALLOW_MMAP, "FUSE_CAP_DIRECT_IO_ALLOW_MMAP"},
    {FUSE_CAP_NO_EXPORT_SUPPORT, "FUSE_CAP_NO_EXPORT_SUPPORT"},
    {FUSE_CAP_PASSTHROUGH, "FUSE_CAP_PASSTHROUGH"},
    // Add any new capabilities here
    {0, NULL} // Sentinel to mark the end of the array
    };
    static void print_capabilities(struct fuse_conn_info *conn)
    {
    printf("Capabilities:\n");
    for (const struct cap_info *cap = capabilities; cap->name != NULL; cap++) {
    if (fuse_get_feature_flag(conn, cap->flag)) {
    printf("\t%s\n", cap->name);
    }
    }
    }
    static void pc_init(void *userdata, struct fuse_conn_info *conn)
    {
    (void) userdata;
    printf("Protocol version: %d.%d\n", conn->proto_major,
    conn->proto_minor);
    print_capabilities(conn);
    }
    static const struct fuse_lowlevel_ops pc_oper = {
    .init = pc_init,
    };
    int main(int argc, char **argv)
    {
    struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
    char *mountpoint;
    int ret = -1;
    mountpoint = strdup("/tmp/fuse_printcap_XXXXXX");
    if(mkdtemp(mountpoint) == NULL) {
    perror("mkdtemp");
    return 1;
    }
    printf("FUSE library version %s\n", fuse_pkgversion());
    se = fuse_session_new(&args, &pc_oper,
    sizeof(pc_oper), NULL);
    if (se == NULL)
    goto err_out1;
    goto err_out2;
    if (fuse_session_mount(se, mountpoint) != 0)
    goto err_out3;
    ret = fuse_session_loop(se);
    err_out3:
    err_out2:
    err_out1:
    rmdir(mountpoint);
    free(mountpoint);
    return ret ? 1 : 0;
    }
    #define FUSE_CAP_IOCTL_DIR
    #define FUSE_CAP_DONT_MASK
    #define FUSE_CAP_HANDLE_KILLPRIV
    #define FUSE_CAP_AUTO_INVAL_DATA
    int fuse_set_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_HANDLE_KILLPRIV_V2
    #define FUSE_CAP_SPLICE_READ
    #define FUSE_CAP_PARALLEL_DIROPS
    #define FUSE_CAP_WRITEBACK_CACHE
    #define FUSE_CAP_EXPIRE_ONLY
    #define FUSE_CAP_ATOMIC_O_TRUNC
    #define FUSE_CAP_ASYNC_READ
    #define FUSE_CAP_SPLICE_WRITE
    #define FUSE_CAP_CACHE_SYMLINKS
    #define FUSE_CAP_POSIX_ACL
    #define FUSE_CAP_EXPORT_SUPPORT
    #define FUSE_CAP_POSIX_LOCKS
    #define FUSE_CAP_EXPLICIT_INVAL_DATA
    #define FUSE_CAP_READDIRPLUS_AUTO
    #define FUSE_CAP_NO_OPENDIR_SUPPORT
    #define FUSE_CAP_ASYNC_DIO
    bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
    #define FUSE_CAP_PASSTHROUGH
    #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP
    #define FUSE_CAP_NO_OPEN_SUPPORT
    #define FUSE_CAP_READDIRPLUS
    const char * fuse_pkgversion(void)
    Definition fuse.c:5274
    void fuse_remove_signal_handlers(struct fuse_session *se)
    #define FUSE_CAP_SETXATTR_EXT
    #define FUSE_CAP_SPLICE_MOVE
    #define FUSE_CAP_NO_EXPORT_SUPPORT
    #define FUSE_CAP_FLOCK_LOCKS
    void fuse_session_destroy(struct fuse_session *se)
    void fuse_session_exit(struct fuse_session *se)
    int fuse_session_loop(struct fuse_session *se)
    Definition fuse_loop.c:19
    void fuse_session_unmount(struct fuse_session *se)
    int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
    void fuse_lowlevel_version(void)
    void fuse_opt_free_args(struct fuse_args *args)
    Definition fuse_opt.c:34
    #define FUSE_ARGS_INIT(argc, argv)
    Definition fuse_opt.h:123
    char ** argv
    Definition fuse_opt.h:114
    uint32_t proto_major
    uint32_t proto_minor

    Definition in file printcap.c.

    fuse-3.18.3/doc/html/fuse_8h.html0000644000175000017500000012617115250106404015463 0ustar berndbernd libfuse: include/fuse.h File Reference
    libfuse
    fuse.h File Reference
    #include "fuse_common.h"
    #include <fcntl.h>
    #include <time.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/statvfs.h>
    #include <sys/uio.h>

    Go to the source code of this file.

    Data Structures

    struct  fuse_config
    struct  fuse_operations
    struct  fuse_context

    Macros

    #define FUSE_REGISTER_MODULE(name_, factory_)

    Typedefs

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

    Enumerations

    enum  fuse_readdir_flags { FUSE_READDIR_DEFAULTS = 0 , FUSE_READDIR_PLUS = (1 << 0) }
    enum  fuse_fill_dir_flags { FUSE_FILL_DIR_DEFAULTS = 0 , FUSE_FILL_DIR_PLUS = (1 << 1) }

    Functions

    int fuse_main_real_versioned (int argc, char *argv[], const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data)
    void fuse_lib_help (struct fuse_args *args)
    int fuse_mount (struct fuse *f, const char *mountpoint)
    void fuse_unmount (struct fuse *f)
    void fuse_destroy (struct fuse *f)
    int fuse_loop (struct fuse *f)
    void fuse_exit (struct fuse *f)
    struct fuse_context * fuse_get_context (void)
    int fuse_getgroups (int size, gid_t list[])
    int fuse_interrupted (void)
    int fuse_invalidate_path (struct fuse *f, const char *path)
    int fuse_start_cleanup_thread (struct fuse *fuse)
    void fuse_stop_cleanup_thread (struct fuse *fuse)
    int fuse_clean_cache (struct fuse *fuse)
    struct fuse_fs * fuse_fs_new (const struct fuse_operations *op, size_t op_size, void *private_data)
    struct fuse_session * fuse_get_session (struct fuse *f)
    int fuse_open_channel (const char *mountpoint, const char *options)

    Detailed Description

    This file defines the library interface of FUSE

    IMPORTANT: you should define FUSE_USE_VERSION before including this header.

    Definition in file fuse.h.

    Macro Definition Documentation

    ◆ FUSE_REGISTER_MODULE

    #define FUSE_REGISTER_MODULE ( name_,
    factory_ )
    Value:
    fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_
    struct fuse_fs *(* fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[])
    Definition fuse.h:1403

    Register filesystem module

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

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

    Definition at line 1415 of file fuse.h.

    Typedef Documentation

    ◆ fuse_fill_dir_t

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

    Function to add an entry in a readdir() operation

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

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

    Definition at line 93 of file fuse.h.

    ◆ fuse_module_factory_t

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

    Factory for creating filesystem objects

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

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

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

    Definition at line 1386 of file fuse.h.

    Enumeration Type Documentation

    ◆ fuse_fill_dir_flags

    Readdir flags, passed to fuse_fill_dir_t callback.

    Enumerator
    FUSE_FILL_DIR_DEFAULTS 

    "Plus" mode: file attributes are valid

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

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

    This does not make libfuse honor the 'st_ino' field. That is controlled by the 'use_ino' option instead.

    Definition at line 61 of file fuse.h.

    ◆ fuse_readdir_flags

    Readdir flags, passed to ->readdir()

    Enumerator
    FUSE_READDIR_DEFAULTS 

    "Plus" mode.

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

    Definition at line 45 of file fuse.h.

    Function Documentation

    ◆ fuse_clean_cache()

    int fuse_clean_cache ( struct fuse * fuse)

    Iterate over cache removing stale entries use in conjunction with "-oremember"

    NOTE: This is already done for the standard sessions

    Parameters
    fusestruct fuse pointer for fuse instance
    Returns
    the number of seconds until the next cleanup

    Definition at line 4498 of file fuse.c.

    ◆ fuse_destroy()

    void fuse_destroy ( struct fuse * f)

    Destroy the FUSE handle.

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

    Parameters
    fthe FUSE handle

    Definition at line 5209 of file fuse.c.

    ◆ fuse_exit()

    void fuse_exit ( struct fuse * f)

    Flag session as terminated

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

    Parameters
    fthe FUSE handle

    Definition at line 4706 of file fuse.c.

    ◆ fuse_fs_new()

    struct fuse_fs * fuse_fs_new ( const struct fuse_operations * op,
    size_t op_size,
    void * private_data )

    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.

    Parameters
    opthe filesystem operations
    op_sizethe size of the fuse_operations structure
    private_dataInitial value for the private_data field of struct fuse_context. May be overridden by the struct fuse_operations.init handler.
    Returns
    a new filesystem object

    Definition at line 4923 of file fuse.c.

    ◆ fuse_get_context()

    struct fuse_context * fuse_get_context ( void )

    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.

    Returns
    the context

    Definition at line 4711 of file fuse.c.

    ◆ fuse_get_session()

    struct fuse_session * fuse_get_session ( struct fuse * f)

    Get session from fuse object

    Definition at line 4588 of file fuse.c.

    ◆ fuse_getgroups()

    int fuse_getgroups ( int size,
    gid_t list[] )

    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.

    Parameters
    sizesize of given array
    listarray of group IDs to be filled in
    Returns
    the total number of supplementary group IDs or -errno on failure

    Definition at line 4721 of file fuse.c.

    ◆ fuse_interrupted()

    int fuse_interrupted ( void )

    Check if the current request has already been interrupted

    Returns
    1 if the request has been interrupted, 0 otherwise

    Definition at line 4730 of file fuse.c.

    ◆ fuse_invalidate_path()

    int fuse_invalidate_path ( struct fuse * f,
    const char * path )

    Invalidates cache for the given path.

    This calls fuse_lowlevel_notify_inval_inode internally.

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

    Definition at line 4740 of file fuse.c.

    ◆ fuse_lib_help()

    void fuse_lib_help ( struct fuse_args * args)

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

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

    Parameters
    argsthe argument vector.

    Definition at line 4813 of file fuse.c.

    ◆ fuse_loop()

    int fuse_loop ( struct fuse * f)

    FUSE event loop.

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

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

    Parameters
    fthe FUSE handle
    Returns
    see fuse_session_loop()

    See also: fuse_loop_mt()

    Definition at line 4644 of file fuse.c.

    ◆ fuse_main_real_versioned()

    int fuse_main_real_versioned ( int argc,
    char * argv[],
    const struct fuse_operations * op,
    size_t op_size,
    struct libfuse_version * version,
    void * user_data )

    The real main function

    Do not call this directly, use fuse_main()

    Definition at line 317 of file helper.c.

    ◆ fuse_mount()

    int fuse_mount ( struct fuse * f,
    const char * mountpoint )

    Mount a FUSE file system.

    Parameters
    mountpointthe mount point path
    fthe FUSE handle
    Returns
    0 on success, -1 on failure.

    Definition at line 5260 of file fuse.c.

    ◆ fuse_open_channel()

    int fuse_open_channel ( const char * mountpoint,
    const char * options )

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

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

    Definition at line 492 of file helper.c.

    ◆ fuse_start_cleanup_thread()

    int fuse_start_cleanup_thread ( struct fuse * fuse)

    Start the cleanup thread when using option "remember".

    This is done automatically by fuse_loop_mt()

    Parameters
    fusestruct fuse pointer for fuse instance
    Returns
    0 on success and -1 on error

    Definition at line 4973 of file fuse.c.

    ◆ fuse_stop_cleanup_thread()

    void fuse_stop_cleanup_thread ( struct fuse * fuse)

    Stop the cleanup thread when using option "remember".

    This is done automatically by fuse_loop_mt()

    Parameters
    fusestruct fuse pointer for fuse instance

    Definition at line 4981 of file fuse.c.

    ◆ fuse_unmount()

    void fuse_unmount ( struct fuse * f)

    Unmount a FUSE file system.

    See fuse_session_unmount() for additional information.

    Parameters
    fthe FUSE handle

    Definition at line 5265 of file fuse.c.

    fuse-3.18.3/doc/html/fuse__common_8h.html0000644000175000017500000024405515250106404017174 0ustar berndbernd libfuse: include/fuse_common.h File Reference
    libfuse
    fuse_common.h File Reference
    #include "libfuse_config.h"
    #include "fuse_opt.h"
    #include "fuse_log.h"
    #include <stdint.h>
    #include <stdbool.h>
    #include <sys/types.h>
    #include <assert.h>

    Go to the source code of this file.

    Data Structures

    struct  fuse_file_info
    struct  fuse_loop_config
    struct  fuse_conn_info
    struct  fuse_buf
    struct  fuse_bufvec
    struct  libfuse_version

    Macros

    #define FUSE_CAP_ASYNC_READ   (1UL << 0)
    #define FUSE_CAP_POSIX_LOCKS   (1UL << 1)
    #define FUSE_CAP_ATOMIC_O_TRUNC   (1UL << 3)
    #define FUSE_CAP_EXPORT_SUPPORT   (1UL << 4)
    #define FUSE_CAP_DONT_MASK   (1UL << 6)
    #define FUSE_CAP_SPLICE_WRITE   (1UL << 7)
    #define FUSE_CAP_SPLICE_MOVE   (1UL << 8)
    #define FUSE_CAP_SPLICE_READ   (1UL << 9)
    #define FUSE_CAP_FLOCK_LOCKS   (1UL << 10)
    #define FUSE_CAP_IOCTL_DIR   (1UL << 11)
    #define FUSE_CAP_AUTO_INVAL_DATA   (1UL << 12)
    #define FUSE_CAP_READDIRPLUS   (1UL << 13)
    #define FUSE_CAP_READDIRPLUS_AUTO   (1UL << 14)
    #define FUSE_CAP_ASYNC_DIO   (1UL << 15)
    #define FUSE_CAP_WRITEBACK_CACHE   (1UL << 16)
    #define FUSE_CAP_NO_OPEN_SUPPORT   (1UL << 17)
    #define FUSE_CAP_PARALLEL_DIROPS   (1UL << 18)
    #define FUSE_CAP_POSIX_ACL   (1UL << 19)
    #define FUSE_CAP_HANDLE_KILLPRIV   (1UL << 20)
    #define FUSE_CAP_HANDLE_KILLPRIV_V2   (1UL << 21)
    #define FUSE_CAP_CACHE_SYMLINKS   (1UL << 23)
    #define FUSE_CAP_NO_OPENDIR_SUPPORT   (1UL << 24)
    #define FUSE_CAP_EXPLICIT_INVAL_DATA   (1UL << 25)
    #define FUSE_CAP_EXPIRE_ONLY   (1UL << 26)
    #define FUSE_CAP_SETXATTR_EXT   (1UL << 27)
    #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP   (1UL << 28)
    #define FUSE_CAP_PASSTHROUGH   (1UL << 29)
    #define FUSE_CAP_NO_EXPORT_SUPPORT   (1UL << 30)
    #define FUSE_CAP_OVER_IO_URING   (1UL << 31)
    #define FUSE_IOCTL_COMPAT   (1 << 0)
    #define FUSE_BACKING_STACKED_UNDER   (0)

    Enumerations

    enum  fuse_buf_flags { FUSE_BUF_IS_FD = (1 << 1) , FUSE_BUF_FD_SEEK = (1 << 2) , FUSE_BUF_FD_RETRY = (1 << 3) }
    enum  fuse_buf_copy_flags { FUSE_BUF_NO_SPLICE = (1 << 1) , FUSE_BUF_FORCE_SPLICE = (1 << 2) , FUSE_BUF_SPLICE_MOVE = (1 << 3) , FUSE_BUF_SPLICE_NONBLOCK = (1 << 4) }

    Functions

    struct fuse_conn_info_opts * fuse_parse_conn_info_opts (struct fuse_args *args)
    void fuse_apply_conn_info_opts (struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn)
    int fuse_daemonize (int foreground)
    int fuse_version (void)
    const char * fuse_pkgversion (void)
    void fuse_pollhandle_destroy (struct fuse_pollhandle *ph)
    size_t fuse_buf_size (const struct fuse_bufvec *bufv)
    ssize_t fuse_buf_copy (struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
    int fuse_set_signal_handlers (struct fuse_session *se)
    int fuse_set_fail_signal_handlers (struct fuse_session *se)
    void fuse_remove_signal_handlers (struct fuse_session *se)
    bool fuse_set_feature_flag (struct fuse_conn_info *conn, uint64_t flag)
    void fuse_unset_feature_flag (struct fuse_conn_info *conn, uint64_t flag)
    bool fuse_get_feature_flag (struct fuse_conn_info *conn, uint64_t flag)
    int fuse_convert_to_conn_want_ext (struct fuse_conn_info *conn)

    Macro Definition Documentation

    ◆ FUSE_BACKING_STACKED_UNDER

    #define FUSE_BACKING_STACKED_UNDER   (0)

    When FUSE_CAP_PASSTHROUGH is enabled, this is the maximum allowed stacking depth of the backing files. In current kernel, the maximum allowed stack depth if FILESYSTEM_MAX_STACK_DEPTH (2), which includes the FUSE passthrough layer, so the maximum stacking depth for backing files is 1.

    The default is FUSE_BACKING_STACKED_UNDER (0), meaning that the backing files cannot be on a stacked filesystem, but another stacked filesystem can be stacked over this FUSE passthrough filesystem.

    Set this to FUSE_BACKING_STACKED_OVER (1) if backing files may be on a stacked filesystem, such as overlayfs or another FUSE passthrough. In this configuration, another stacked filesystem cannot be stacked over this FUSE passthrough filesystem.

    Definition at line 678 of file fuse_common.h.

    ◆ FUSE_CAP_ASYNC_DIO

    #define FUSE_CAP_ASYNC_DIO   (1UL << 15)

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

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

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

    Definition at line 336 of file fuse_common.h.

    ◆ FUSE_CAP_ASYNC_READ

    #define FUSE_CAP_ASYNC_READ   (1UL << 0)

    Indicates that the filesystem supports asynchronous read requests.

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

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

    Definition at line 185 of file fuse_common.h.

    ◆ FUSE_CAP_ATOMIC_O_TRUNC

    #define FUSE_CAP_ATOMIC_O_TRUNC   (1UL << 3)

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

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

    Definition at line 202 of file fuse_common.h.

    ◆ FUSE_CAP_AUTO_INVAL_DATA

    #define FUSE_CAP_AUTO_INVAL_DATA   (1UL << 12)

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

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

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

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

    Definition at line 289 of file fuse_common.h.

    ◆ FUSE_CAP_CACHE_SYMLINKS

    #define FUSE_CAP_CACHE_SYMLINKS   (1UL << 23)

    Indicates that the kernel supports caching symlinks in its page cache.

    When this feature is enabled, symlink targets are saved in the page cache. You can invalidate a cached link by calling: fuse_lowlevel_notify_inval_inode(se, ino, 0, 0);

    This feature is disabled by default. If the kernel supports it (>= 4.20), you can enable this feature by setting this flag in the want field of the fuse_conn_info structure.

    Definition at line 426 of file fuse_common.h.

    ◆ FUSE_CAP_DIRECT_IO_ALLOW_MMAP

    #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP   (1UL << 28)

    Files opened with FUSE_DIRECT_IO do not support MAP_SHARED mmap. This restriction is relaxed through FUSE_CAP_DIRECT_IO_RELAX (kernel flag: FUSE_DIRECT_IO_RELAX). MAP_SHARED is disabled by default for FUSE_DIRECT_IO, as this flag can be used to ensure coherency between mount points (or network clients) and with kernel page cache as enforced by mmap that cannot be guaranteed anymore.

    Definition at line 496 of file fuse_common.h.

    ◆ FUSE_CAP_DONT_MASK

    #define FUSE_CAP_DONT_MASK   (1UL << 6)

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

    This feature is disabled by default.

    Definition at line 222 of file fuse_common.h.

    ◆ FUSE_CAP_EXPIRE_ONLY

    #define FUSE_CAP_EXPIRE_ONLY   (1UL << 26)

    Indicates support that dentries can be expired.

    Expiring dentries, instead of invalidating them, makes a difference for overmounted dentries, where plain invalidation would detach all submounts before dropping the dentry from the cache. If only expiry is set on the dentry, then any overmounts are left alone and until ->d_revalidate() is called.

    Note: ->d_revalidate() is not called for the case of following a submount, so invalidation will only be triggered for the non-overmounted case. The dentry could also be mounted in a different mount instance, in which case any submounts will still be detached.

    Definition at line 480 of file fuse_common.h.

    ◆ FUSE_CAP_EXPLICIT_INVAL_DATA

    #define FUSE_CAP_EXPLICIT_INVAL_DATA   (1UL << 25)

    Indicates support for invalidating cached pages only on explicit request.

    If this flag is set in the capable field of the fuse_conn_info structure, then the FUSE kernel module supports invalidating cached pages only on explicit request by the filesystem through fuse_lowlevel_notify_inval_inode() or fuse_invalidate_path().

    By setting this flag in the want field of the fuse_conn_info structure, the filesystem is responsible for invalidating cached pages through explicit requests to the kernel.

    Note that setting this flag does not prevent the cached pages from being flushed by OS itself and/or through user actions.

    Note that if both FUSE_CAP_EXPLICIT_INVAL_DATA and FUSE_CAP_AUTO_INVAL_DATA are set in the capable field of the fuse_conn_info structure then FUSE_CAP_AUTO_INVAL_DATA takes precedence.

    This feature is disabled by default.

    Definition at line 464 of file fuse_common.h.

    ◆ FUSE_CAP_EXPORT_SUPPORT

    #define FUSE_CAP_EXPORT_SUPPORT   (1UL << 4)

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

    When this flag is set, the filesystem must be prepared to receive requests for invalid inodes (i.e., for which a FORGET request was received or which have been used in a previous instance of the filesystem daemon) and must not reuse node-ids (even when setting generation numbers).

    This feature is disabled by default.

    Definition at line 214 of file fuse_common.h.

    ◆ FUSE_CAP_FLOCK_LOCKS

    #define FUSE_CAP_FLOCK_LOCKS   (1UL << 10)

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

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

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

    Definition at line 260 of file fuse_common.h.

    ◆ FUSE_CAP_HANDLE_KILLPRIV

    #define FUSE_CAP_HANDLE_KILLPRIV   (1UL << 20)

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

    This feature is disabled by default.

    Definition at line 396 of file fuse_common.h.

    ◆ FUSE_CAP_HANDLE_KILLPRIV_V2

    #define FUSE_CAP_HANDLE_KILLPRIV_V2   (1UL << 21)

    Indicates that the filesystem is responsible for unsetting setuid and setgid bit and additionally cap (stored as xattr) when a file is written, truncated, or its owner is changed. Upon write/truncate suid/sgid is only killed if caller does not have CAP_FSETID. Additionally upon write/truncate sgid is killed only if file has group execute permission. (Same as Linux VFS behavior). KILLPRIV_V2 requires handling of

    • FUSE_OPEN_KILL_SUIDGID (set in struct fuse_create_in::open_flags)
    • FATTR_KILL_SUIDGID (set in struct fuse_setattr_in::valid)
    • FUSE_WRITE_KILL_SUIDGID (set in struct fuse_write_in::write_flags)

    This feature is disabled by default.

    Definition at line 413 of file fuse_common.h.

    ◆ FUSE_CAP_IOCTL_DIR

    #define FUSE_CAP_IOCTL_DIR   (1UL << 11)

    Indicates that the filesystem supports ioctl's on directories.

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

    Definition at line 267 of file fuse_common.h.

    ◆ FUSE_CAP_NO_EXPORT_SUPPORT

    #define FUSE_CAP_NO_EXPORT_SUPPORT   (1UL << 30)

    Indicates that the file system cannot handle NFS export

    If this flag is set NFS export and name_to_handle_at is not going to work at all and will fail with EOPNOTSUPP.

    Definition at line 516 of file fuse_common.h.

    ◆ FUSE_CAP_NO_OPEN_SUPPORT

    #define FUSE_CAP_NO_OPEN_SUPPORT   (1UL << 17)

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

    Setting this flag in the want field enables this behavior automatically within libfuse for low level API users. If non-low level users wish to have this behavior you must return ENOSYS from the open() handler on supporting kernels.

    Definition at line 360 of file fuse_common.h.

    ◆ FUSE_CAP_NO_OPENDIR_SUPPORT

    #define FUSE_CAP_NO_OPENDIR_SUPPORT   (1UL << 24)

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

    Setting this flag in the want field enables this behavior automatically within libfuse for low level API users. If non-low level users with to have this behavior you must return ENOSYS from the opendir() handler on supporting kernels.

    Definition at line 441 of file fuse_common.h.

    ◆ FUSE_CAP_OVER_IO_URING

    #define FUSE_CAP_OVER_IO_URING   (1UL << 31)

    Indicates support for io-uring between fuse-server and fuse-client

    Definition at line 521 of file fuse_common.h.

    ◆ FUSE_CAP_PARALLEL_DIROPS

    #define FUSE_CAP_PARALLEL_DIROPS   (1UL << 18)

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

    Definition at line 368 of file fuse_common.h.

    ◆ FUSE_CAP_PASSTHROUGH

    #define FUSE_CAP_PASSTHROUGH   (1UL << 29)

    Indicates support for passthrough mode access for read/write operations.

    If this flag is set in the capable field of the fuse_conn_info structure, then the FUSE kernel module supports redirecting read/write operations to the backing file instead of letting them to be handled by the FUSE daemon.

    This feature is disabled by default.

    Definition at line 508 of file fuse_common.h.

    ◆ FUSE_CAP_POSIX_ACL

    #define FUSE_CAP_POSIX_ACL   (1UL << 19)

    Indicates support for POSIX ACLs.

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

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

    This feature is disabled by default.

    Definition at line 387 of file fuse_common.h.

    ◆ FUSE_CAP_POSIX_LOCKS

    #define FUSE_CAP_POSIX_LOCKS   (1UL << 1)

    Indicates that the filesystem supports "remote" locking.

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

    Definition at line 193 of file fuse_common.h.

    ◆ FUSE_CAP_READDIRPLUS

    #define FUSE_CAP_READDIRPLUS   (1UL << 13)

    Indicates that the filesystem supports readdirplus.

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

    Definition at line 297 of file fuse_common.h.

    ◆ FUSE_CAP_READDIRPLUS_AUTO

    #define FUSE_CAP_READDIRPLUS_AUTO   (1UL << 14)

    Indicates that the filesystem supports adaptive readdirplus.

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

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

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

    As of Linux 4.20, the algorithm is as follows: when userspace starts to read directory entries, issue a READDIRPLUS request to the filesystem. If any entry attributes have been looked up by the time userspace requests the next batch of entries continue with READDIRPLUS, otherwise switch to plain READDIR. This will reasult in eg plain "ls" triggering READDIRPLUS first then READDIR after that because it doesn't do lookups. "ls -l" should result in all READDIRPLUS, except if dentries are already cached.

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

    Definition at line 325 of file fuse_common.h.

    ◆ FUSE_CAP_SETXATTR_EXT

    #define FUSE_CAP_SETXATTR_EXT   (1UL << 27)

    Indicates that an extended 'struct fuse_setxattr' is used by the kernel side - extra_flags are passed, which are used (as of now by acl) processing. For example FUSE_SETXATTR_ACL_KILL_SGID might be set.

    Definition at line 487 of file fuse_common.h.

    ◆ FUSE_CAP_SPLICE_MOVE

    #define FUSE_CAP_SPLICE_MOVE   (1UL << 8)

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

    This feature is disabled by default.

    Definition at line 238 of file fuse_common.h.

    ◆ FUSE_CAP_SPLICE_READ

    #define FUSE_CAP_SPLICE_READ   (1UL << 9)

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

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

    Definition at line 247 of file fuse_common.h.

    ◆ FUSE_CAP_SPLICE_WRITE

    #define FUSE_CAP_SPLICE_WRITE   (1UL << 7)

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

    This feature is disabled by default.

    Definition at line 230 of file fuse_common.h.

    ◆ FUSE_CAP_WRITEBACK_CACHE

    #define FUSE_CAP_WRITEBACK_CACHE   (1UL << 16)

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

    This feature is disabled by default.

    Definition at line 345 of file fuse_common.h.

    ◆ FUSE_IOCTL_COMPAT

    #define FUSE_IOCTL_COMPAT   (1 << 0)

    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

    Definition at line 533 of file fuse_common.h.

    Enumeration Type Documentation

    ◆ fuse_buf_copy_flags

    Buffer copy flags

    Enumerator
    FUSE_BUF_NO_SPLICE 

    Don't use splice(2)

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

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

    FUSE_BUF_FORCE_SPLICE 

    Force splice

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

    FUSE_BUF_SPLICE_MOVE 

    Try to move data with splice.

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

    FUSE_BUF_SPLICE_NONBLOCK 

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

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

    Definition at line 848 of file fuse_common.h.

    ◆ fuse_buf_flags

    Buffer flags

    Enumerator
    FUSE_BUF_IS_FD 

    Buffer contains a file descriptor

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

    FUSE_BUF_FD_SEEK 

    Seek on the file descriptor

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

    FUSE_BUF_FD_RETRY 

    Retry operation on file descriptor

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

    Definition at line 817 of file fuse_common.h.

    Function Documentation

    ◆ fuse_apply_conn_info_opts()

    void fuse_apply_conn_info_opts ( struct fuse_conn_info_opts * opts,
    struct fuse_conn_info * conn )

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

    Definition at line 422 of file helper.c.

    ◆ fuse_buf_copy()

    ssize_t fuse_buf_copy ( struct fuse_bufvec * dst,
    struct fuse_bufvec * src,
    enum fuse_buf_copy_flags flags )

    Copy data from one buffer vector to another

    Parameters
    dstdestination buffer vector
    srcsource buffer vector
    flagsflags controlling the copy
    Returns
    actual number of bytes copied or -errno on error

    Definition at line 284 of file buffer.c.

    ◆ fuse_buf_size()

    size_t fuse_buf_size ( const struct fuse_bufvec * bufv)

    Get total size of data in a fuse buffer vector

    Parameters
    bufvbuffer vector
    Returns
    size of data

    Definition at line 22 of file buffer.c.

    ◆ fuse_convert_to_conn_want_ext()

    int fuse_convert_to_conn_want_ext ( struct fuse_conn_info * conn)

    Get the wanted capability flags, converting from old format if necessary

    Definition at line 2587 of file fuse_lowlevel.c.

    ◆ fuse_daemonize()

    int fuse_daemonize ( int foreground)

    Go into the background

    Parameters
    foregroundif true, stay in the foreground
    Returns
    0 on success, -1 on failure

    Definition at line 253 of file helper.c.

    ◆ fuse_get_feature_flag()

    bool fuse_get_feature_flag ( struct fuse_conn_info * conn,
    uint64_t flag )

    Get the value of a feature flag in the want_ext field of fuse_conn_info.

    Parameters
    connconnection information
    flagfeature flag to be checked
    Returns
    true if the flag is set, false otherwise

    Definition at line 2650 of file fuse_lowlevel.c.

    ◆ fuse_parse_conn_info_opts()

    struct fuse_conn_info_opts * fuse_parse_conn_info_opts ( struct fuse_args * args)

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

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

    The following options are recognized:

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

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

    Parameters
    argsargument vector (input+output)
    Returns
    parsed options

    Definition at line 476 of file helper.c.

    ◆ fuse_pkgversion()

    const char * fuse_pkgversion ( void )

    Get the full package version string of the library

    Returns
    the package version

    Definition at line 5274 of file fuse.c.

    ◆ fuse_pollhandle_destroy()

    void fuse_pollhandle_destroy ( struct fuse_pollhandle * ph)

    Destroy poll handle

    Parameters
    phthe poll handle

    Definition at line 2389 of file fuse_lowlevel.c.

    ◆ fuse_remove_signal_handlers()

    void fuse_remove_signal_handlers ( struct fuse_session * se)

    Restore default signal handlers

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

    Parameters
    sethe same session as given in fuse_set_signal_handlers()

    See also: fuse_set_signal_handlers()

    Definition at line 198 of file fuse_signals.c.

    ◆ fuse_set_fail_signal_handlers()

    int fuse_set_fail_signal_handlers ( struct fuse_session * se)

    Print a stack backtrace diagnostic on critical signals ()

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

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

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

    See also: fuse_remove_signal_handlers()

    Definition at line 176 of file fuse_signals.c.

    ◆ fuse_set_feature_flag()

    bool fuse_set_feature_flag ( struct fuse_conn_info * conn,
    uint64_t flag )

    Config operations. These APIs are introduced in version 312 (FUSE_MAKE_VERSION(3, 12)). Using them in earlier versions will result in errors. Set a feature flag in the want_ext field of fuse_conn_info.

    Parameters
    connconnection information
    flagfeature flag to be set
    Returns
    true if the flag was set, false if the flag is not supported

    Definition at line 2624 of file fuse_lowlevel.c.

    ◆ fuse_set_signal_handlers()

    int fuse_set_signal_handlers ( struct fuse_session * se)

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

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

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

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

    See also: fuse_remove_signal_handlers()

    Definition at line 151 of file fuse_signals.c.

    ◆ fuse_unset_feature_flag()

    void fuse_unset_feature_flag ( struct fuse_conn_info * conn,
    uint64_t flag )

    Unset a feature flag in the want_ext field of fuse_conn_info.

    Parameters
    connconnection information
    flagfeature flag to be unset

    Definition at line 2639 of file fuse_lowlevel.c.

    ◆ fuse_version()

    int fuse_version ( void )

    Get the version of the library

    Returns
    the version

    Definition at line 5269 of file fuse.c.

    fuse-3.18.3/doc/html/fuse__log_8h.html0000644000175000017500000003146415250106404016463 0ustar berndbernd libfuse: include/fuse_log.h File Reference
    libfuse
    fuse_log.h File Reference
    #include <stdarg.h>

    Go to the source code of this file.

    Typedefs

    typedef void(* fuse_log_func_t) (enum fuse_log_level level, const char *fmt, va_list ap)

    Enumerations

    enum  fuse_log_level

    Functions

    void fuse_set_log_func (fuse_log_func_t func)
    void fuse_log (enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
    void void fuse_log_enable_syslog (const char *ident, int option, int facility)
    void fuse_log_close_syslog (void)

    Detailed Description

    This file defines the logging interface of FUSE

    Definition in file fuse_log.h.

    Typedef Documentation

    ◆ fuse_log_func_t

    typedef void(* fuse_log_func_t) (enum fuse_log_level level, const char *fmt, va_list ap)

    Log message handler function.

    This function must be thread-safe. It may be called from any libfuse function, including fuse_parse_cmdline() and other functions invoked before a FUSE filesystem is created.

    Install a custom log message handler function using fuse_set_log_func().

    Parameters
    levellog severity level
    fmtsprintf-style format string including newline
    apformat string arguments

    Definition at line 52 of file fuse_log.h.

    Enumeration Type Documentation

    ◆ fuse_log_level

    Log severity level

    These levels correspond to syslog(2) log levels since they are widely used.

    Definition at line 28 of file fuse_log.h.

    Function Documentation

    ◆ fuse_log()

    void fuse_log ( enum fuse_log_level level,
    const char * fmt,
    ... )

    Emit a log message

    Parameters
    levelseverity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc)
    fmtsprintf-style format string including newline

    ◆ fuse_log_close_syslog()

    void fuse_log_close_syslog ( void )

    To be called at teardown to close syslog.

    Definition at line 56 of file fuse_log.c.

    ◆ fuse_log_enable_syslog()

    void void fuse_log_enable_syslog ( const char * ident,
    int option,
    int facility )

    Switch default log handler from stderr to syslog

    Passed options are according to 'man 3 openlog'

    Definition at line 49 of file fuse_log.c.

    ◆ fuse_set_log_func()

    void fuse_set_log_func ( fuse_log_func_t func)

    Install a custom log handler function.

    Log messages are emitted by libfuse functions to report errors and debug information. Messages are printed to stderr by default but this can be overridden by installing a custom log message handler function.

    The log message handler function is global and affects all FUSE filesystems created within this process.

    Parameters
    funca custom log message handler function or NULL to revert to the default

    Definition at line 32 of file fuse_log.c.

    fuse-3.18.3/doc/html/fuse__lowlevel_8h.html0000644000175000017500000037725315250106404017544 0ustar berndbernd libfuse: include/fuse_lowlevel.h File Reference
    libfuse
    fuse_lowlevel.h File Reference
    #include "fuse_common.h"
    #include <stddef.h>
    #include <utime.h>
    #include <fcntl.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/statvfs.h>
    #include <sys/uio.h>

    Go to the source code of this file.

    Data Structures

    struct  fuse_entry_param
    struct  fuse_ctx
    struct  fuse_lowlevel_ops
    struct  fuse_cmdline_opts

    Macros

    #define FUSE_ROOT_ID   1

    Typedefs

    typedef uint64_t fuse_ino_t
    typedef struct fuse_req * fuse_req_t
    typedef void(* fuse_interrupt_func_t) (fuse_req_t req, void *data)

    Enumerations

    enum  fuse_notify_entry_flags

    Functions

    int fuse_reply_err (fuse_req_t req, int err)
    void fuse_reply_none (fuse_req_t req)
    int fuse_reply_entry (fuse_req_t req, const struct fuse_entry_param *e)
    int fuse_reply_create (fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
    int fuse_reply_attr (fuse_req_t req, const struct stat *attr, double attr_timeout)
    int fuse_reply_readlink (fuse_req_t req, const char *link)
    int fuse_passthrough_open (fuse_req_t req, int fd)
    int fuse_reply_open (fuse_req_t req, const struct fuse_file_info *fi)
    int fuse_reply_write (fuse_req_t req, size_t count)
    int fuse_reply_buf (fuse_req_t req, const char *buf, size_t size)
    int fuse_reply_data (fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_reply_iov (fuse_req_t req, const struct iovec *iov, int count)
    int fuse_reply_statfs (fuse_req_t req, const struct statvfs *stbuf)
    int fuse_reply_xattr (fuse_req_t req, size_t count)
    int fuse_reply_lock (fuse_req_t req, const struct flock *lock)
    int fuse_reply_bmap (fuse_req_t req, uint64_t idx)
    size_t fuse_add_direntry (fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
    size_t fuse_add_direntry_plus (fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off)
    int fuse_reply_ioctl_retry (fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count)
    int fuse_reply_ioctl (fuse_req_t req, int result, const void *buf, size_t size)
    int fuse_reply_ioctl_iov (fuse_req_t req, int result, const struct iovec *iov, int count)
    int fuse_reply_poll (fuse_req_t req, unsigned revents)
    int fuse_reply_lseek (fuse_req_t req, off_t off)
    int fuse_reply_statx (fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
    int fuse_lowlevel_notify_poll (struct fuse_pollhandle *ph)
    int fuse_lowlevel_notify_inval_inode (struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
    int fuse_lowlevel_notify_increment_epoch (struct fuse_session *se)
    int fuse_lowlevel_notify_inval_entry (struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    int fuse_lowlevel_notify_expire_entry (struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
    int fuse_lowlevel_notify_delete (struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
    int fuse_lowlevel_notify_store (struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
    int fuse_lowlevel_notify_retrieve (struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
    void * fuse_req_userdata (fuse_req_t req)
    const struct fuse_ctx * fuse_req_ctx (fuse_req_t req)
    int fuse_req_getgroups (fuse_req_t req, int size, gid_t list[])
    void fuse_req_interrupt_func (fuse_req_t req, fuse_interrupt_func_t func, void *data)
    int fuse_req_interrupted (fuse_req_t req)
    void fuse_lowlevel_version (void)
    void fuse_lowlevel_help (void)
    void fuse_cmdline_help (void)
    int fuse_parse_cmdline_30 (struct fuse_args *args, struct fuse_cmdline_opts *opts)
    int fuse_session_mount (struct fuse_session *se, const char *mountpoint)
    int fuse_session_loop (struct fuse_session *se)
    void fuse_session_exit (struct fuse_session *se)
    void fuse_session_reset (struct fuse_session *se)
    int fuse_session_exited (struct fuse_session *se)
    void fuse_session_unmount (struct fuse_session *se)
    void fuse_session_destroy (struct fuse_session *se)
    int fuse_session_fd (struct fuse_session *se)
    void fuse_session_process_buf (struct fuse_session *se, const struct fuse_buf *buf)
    int fuse_session_receive_buf (struct fuse_session *se, struct fuse_buf *buf)
    bool fuse_req_is_uring (fuse_req_t req)
    int fuse_req_get_payload (fuse_req_t req, char **payload, size_t *payload_sz, void **mr)

    Detailed Description

    Low level API

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

    Definition in file fuse_lowlevel.h.

    Macro Definition Documentation

    ◆ FUSE_ROOT_ID

    #define FUSE_ROOT_ID   1

    The node ID of the root inode

    Definition at line 44 of file fuse_lowlevel.h.

    Typedef Documentation

    ◆ fuse_ino_t

    typedef uint64_t fuse_ino_t

    Inode number type

    Definition at line 47 of file fuse_lowlevel.h.

    ◆ fuse_interrupt_func_t

    typedef void(* fuse_interrupt_func_t) (fuse_req_t req, void *data)

    Callback function for an interrupt

    Parameters
    reqinterrupted request
    datauser data

    Definition at line 1992 of file fuse_lowlevel.h.

    ◆ fuse_req_t

    typedef struct fuse_req* fuse_req_t

    Request pointer type

    Definition at line 50 of file fuse_lowlevel.h.

    Enumeration Type Documentation

    ◆ fuse_notify_entry_flags

    Flags for fuse_lowlevel_notify_entry() 0 = invalidate entry FUSE_LL_EXPIRE_ONLY = expire entry

    Definition at line 151 of file fuse_lowlevel.h.

    Function Documentation

    ◆ fuse_add_direntry()

    size_t fuse_add_direntry ( fuse_req_t req,
    char * buf,
    size_t bufsize,
    const char * name,
    const struct stat * stbuf,
    off_t off )

    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.

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

    Parameters
    reqrequest handle
    bufthe point where the new entry will be added to the buffer
    bufsizeremaining size of the buffer
    namethe name of the entry
    stbufthe file attributes
    offthe offset of the next entry
    Returns
    the space needed for the entry

    Definition at line 368 of file fuse_lowlevel.c.

    ◆ fuse_add_direntry_plus()

    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 )

    Add a directory entry to the buffer with the attributes

    See documentation of fuse_add_direntry() for more details.

    Parameters
    reqrequest handle
    bufthe point where the new entry will be added to the buffer
    bufsizeremaining size of the buffer
    namethe name of the entry
    ethe directory entry
    offthe offset of the next entry
    Returns
    the space needed for the entry

    Definition at line 462 of file fuse_lowlevel.c.

    ◆ fuse_cmdline_help()

    void fuse_cmdline_help ( void )

    Print available options for fuse_parse_cmdline().

    Definition at line 130 of file helper.c.

    ◆ fuse_lowlevel_help()

    void fuse_lowlevel_help ( void )

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

    Definition at line 3829 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_delete()

    int fuse_lowlevel_notify_delete ( struct fuse_session * se,
    fuse_ino_t parent,
    fuse_ino_t child,
    const char * name,
    size_t namelen )

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

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

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

    When called correctly, this function will never block.

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

    Parameters
    sethe session object
    parentinode number
    childinode number
    namefile name
    namelenstrlen() of file name
    Returns
    zero for success, -errno for failure

    Definition at line 3223 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_expire_entry()

    int fuse_lowlevel_notify_expire_entry ( struct fuse_session * se,
    fuse_ino_t parent,
    const char * name,
    size_t namelen )

    Notify to expire parent attributes and the dentry matching parent/name

    Same restrictions apply as for fuse_lowlevel_notify_inval_entry()

    Compared to invalidating an entry, expiring the entry results not in a forceful removal of that entry from kernel cache but instead the next access to it forces a lookup from the filesystem.

    This makes a difference for overmounted dentries, where plain invalidation would detach all submounts before dropping the dentry from the cache. If only expiry is set on the dentry, then any overmounts are left alone and until ->d_revalidate() is called.

    Note: ->d_revalidate() is not called for the case of following a submount, so invalidation will only be triggered for the non-overmounted case. The dentry could also be mounted in a different mount instance, in which case any submounts will still be detached.

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

    Parameters
    sethe session object
    parentinode number
    namefile name
    namelenstrlen() of file name
    Returns
    zero for success, -errno for failure, -enosys if no kernel support

    Definition at line 3210 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_increment_epoch()

    int fuse_lowlevel_notify_increment_epoch ( struct fuse_session * se)

    Notify to increment the epoch for the current

    Each fuse connection has an 'epoch', which is initialized during INIT. Caching will then be validated against the epoch value: if the current epoch is higher than an object being revalidated, the object is invalid.

    This function simply increment the current epoch value.

    Parameters
    sethe session object
    Returns
    zero for success, -errno for failure

    Definition at line 3145 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_inval_entry()

    int fuse_lowlevel_notify_inval_entry ( struct fuse_session * se,
    fuse_ino_t parent,
    const char * name,
    size_t namelen )

    Notify to invalidate parent attributes and the dentry matching parent/name

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

    When called correctly, this function will never block.

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

    Parameters
    sethe session object
    parentinode number
    namefile name
    namelenstrlen() of file name
    Returns
    zero for success, -errno for failure

    Definition at line 3204 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_inval_inode()

    int fuse_lowlevel_notify_inval_inode ( struct fuse_session * se,
    fuse_ino_t ino,
    off_t off,
    off_t len )

    Notify to invalidate cache for an inode.

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

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

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

    Parameters
    sethe session object
    inothe inode number
    offthe offset in the inode where to start invalidating or negative to invalidate attributes only
    lenthe amount of cache to invalidate or 0 for all
    Returns
    zero for success, -errno for failure

    Definition at line 3123 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_poll()

    int fuse_lowlevel_notify_poll ( struct fuse_pollhandle * ph)

    Notify IO readiness event

    For more information, please read comment for poll operation.

    Parameters
    phpoll handle to notify IO readiness event for

    Definition at line 3106 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_retrieve()

    int fuse_lowlevel_notify_retrieve ( struct fuse_session * se,
    fuse_ino_t ino,
    size_t size,
    off_t offset,
    void * cookie )

    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.

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

    Parameters
    sethe session object
    inothe inode number
    sizethe number of bytes to retrieve
    offsetthe starting offset into the file to retrieve from
    cookieuser data to supply to the reply callback
    Returns
    zero for success, -errno for failure

    Definition at line 3329 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_notify_store()

    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 )

    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.

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

    Parameters
    sethe session object
    inothe inode number
    offsetthe starting offset into the file to store to
    bufvbuffer vector
    flagsflags controlling the copy
    Returns
    zero for success, -errno for failure

    Definition at line 3249 of file fuse_lowlevel.c.

    ◆ fuse_lowlevel_version()

    void fuse_lowlevel_version ( void )

    Print low-level version information to stdout.

    Definition at line 3822 of file fuse_lowlevel.c.

    ◆ fuse_parse_cmdline_30()

    int fuse_parse_cmdline_30 ( struct fuse_args * args,
    struct fuse_cmdline_opts * opts )

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

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

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

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

    struct fuse_cmdline_opts got extended in libfuse-3.12

    Definition at line 237 of file helper.c.

    ◆ fuse_passthrough_open()

    int fuse_passthrough_open ( fuse_req_t req,
    int fd )

    Setup passthrough backing file for open reply

    Currently there should be only one backing id per node / backing file.

    Possible requests: open, opendir, create

    Parameters
    reqrequest handle
    fdbacking file descriptor
    Returns
    positive backing id for success, 0 for failure

    Definition at line 566 of file fuse_lowlevel.c.

    ◆ fuse_reply_attr()

    int fuse_reply_attr ( fuse_req_t req,
    const struct stat * attr,
    double attr_timeout )

    Reply with attributes

    Possible requests: getattr, setattr

    Parameters
    reqrequest handle
    attrthe attributes
    attr_timeoutvalidity timeout (in seconds) for the attributes
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 546 of file fuse_lowlevel.c.

    ◆ fuse_reply_bmap()

    int fuse_reply_bmap ( fuse_req_t req,
    uint64_t idx )

    Reply with block index

    Possible requests: bmap

    Parameters
    reqrequest handle
    idxblock index within device
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1090 of file fuse_lowlevel.c.

    ◆ fuse_reply_buf()

    int fuse_reply_buf ( fuse_req_t req,
    const char * buf,
    size_t size )

    Reply with data

    Possible requests: read, readdir, getxattr, listxattr

    Parameters
    reqrequest handle
    bufbuffer containing data
    sizethe size of data in bytes
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 632 of file fuse_lowlevel.c.

    ◆ fuse_reply_create()

    int fuse_reply_create ( fuse_req_t req,
    const struct fuse_entry_param * e,
    const struct fuse_file_info * fi )

    Reply with a directory entry and open parameters

    currently the following members of 'fi' are used: fh, direct_io, keep_cache, cache_readdir, nonseekable, noflush, parallel_direct_writes

    Possible requests: create

    Side effects: increments the lookup count on success

    Parameters
    reqrequest handle
    ethe entry parameters
    fifile information
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 530 of file fuse_lowlevel.c.

    ◆ fuse_reply_data()

    int fuse_reply_data ( fuse_req_t req,
    struct fuse_bufvec * bufv,
    enum fuse_buf_copy_flags flags )

    Reply with data copied/moved from buffer(s)

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

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

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

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

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

    The FUSE_BUF_SPLICE_FORCE_SPLICE and FUSE_BUF_SPLICE_NONBLOCK flags are silently ignored.

    Possible requests: read, readdir, getxattr, listxattr

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

    Parameters
    reqrequest handle
    bufvbuffer vector
    flagsflags controlling the copy
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1026 of file fuse_lowlevel.c.

    ◆ fuse_reply_entry()

    int fuse_reply_entry ( fuse_req_t req,
    const struct fuse_entry_param * e )

    Reply with a directory entry

    Possible requests: lookup, mknod, mkdir, symlink, link

    Side effects: increments the lookup count on success

    Parameters
    reqrequest handle
    ethe entry parameters
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 514 of file fuse_lowlevel.c.

    ◆ fuse_reply_err()

    int fuse_reply_err ( fuse_req_t req,
    int err )

    Reply with an error code or success.

    Possible requests: all except forget, forget_multi, retrieve_reply

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

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

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

    Parameters
    reqrequest handle
    errthe positive error value, or zero for success
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 413 of file fuse_lowlevel.c.

    ◆ fuse_reply_ioctl()

    int fuse_reply_ioctl ( fuse_req_t req,
    int result,
    const void * buf,
    size_t size )

    Reply to finish ioctl

    Possible requests: ioctl

    Parameters
    reqrequest handle
    resultresult to be passed to the caller
    bufbuffer containing output data
    sizelength of output data

    Definition at line 1188 of file fuse_lowlevel.c.

    ◆ fuse_reply_ioctl_iov()

    int fuse_reply_ioctl_iov ( fuse_req_t req,
    int result,
    const struct iovec * iov,
    int count )

    Reply to finish ioctl with iov buffer

    Possible requests: ioctl

    Parameters
    reqrequest handle
    resultresult to be passed to the caller
    iovthe vector containing the data
    countthe size of vector

    Definition at line 1209 of file fuse_lowlevel.c.

    ◆ fuse_reply_ioctl_retry()

    int fuse_reply_ioctl_retry ( fuse_req_t req,
    const struct iovec * in_iov,
    size_t in_count,
    const struct iovec * out_iov,
    size_t out_count )

    Reply to ask for data fetch and output buffer preparation. ioctl will be retried with the specified input data fetched and output buffer prepared.

    Possible requests: ioctl

    Parameters
    reqrequest handle
    in_ioviovec specifying data to fetch from the caller
    in_countnumber of entries in in_iov
    out_ioviovec specifying addresses to write output to
    out_countnumber of entries in out_iov
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1118 of file fuse_lowlevel.c.

    ◆ fuse_reply_iov()

    int fuse_reply_iov ( fuse_req_t req,
    const struct iovec * iov,
    int count )

    Reply with data vector

    Possible requests: read, readdir, getxattr, listxattr

    Parameters
    reqrequest handle
    iovthe vector containing the data
    countthe size of vector
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 347 of file fuse_lowlevel.c.

    ◆ fuse_reply_lock()

    int fuse_reply_lock ( fuse_req_t req,
    const struct flock * lock )

    Reply with file lock information

    Possible requests: getlk

    Parameters
    reqrequest handle
    lockthe lock information
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1073 of file fuse_lowlevel.c.

    ◆ fuse_reply_lseek()

    int fuse_reply_lseek ( fuse_req_t req,
    off_t off )

    Reply with offset

    Possible requests: lseek

    Parameters
    reqrequest handle
    offoffset of next data or hole
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1243 of file fuse_lowlevel.c.

    ◆ fuse_reply_none()

    void fuse_reply_none ( fuse_req_t req)

    Don't send reply

    Possible requests: forget forget_multi retrieve_reply

    Parameters
    reqrequest handle

    Definition at line 418 of file fuse_lowlevel.c.

    ◆ fuse_reply_open()

    int fuse_reply_open ( fuse_req_t req,
    const struct fuse_file_info * fi )

    Reply with open parameters

    currently the following members of 'fi' are used: fh, direct_io, keep_cache, cache_readdir, nonseekable, noflush, parallel_direct_writes,

    Possible requests: open, opendir

    Parameters
    reqrequest handle
    fifile information
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 591 of file fuse_lowlevel.c.

    ◆ fuse_reply_poll()

    int fuse_reply_poll ( fuse_req_t req,
    unsigned revents )

    Reply with poll result event mask

    Parameters
    reqrequest handle
    reventspoll result event mask

    Definition at line 1233 of file fuse_lowlevel.c.

    ◆ fuse_reply_readlink()

    int fuse_reply_readlink ( fuse_req_t req,
    const char * link )

    Reply with the contents of a symbolic link

    Possible requests: readlink

    Parameters
    reqrequest handle
    linksymbolic link contents
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 561 of file fuse_lowlevel.c.

    ◆ fuse_reply_statfs()

    int fuse_reply_statfs ( fuse_req_t req,
    const struct statvfs * stbuf )

    Reply with filesystem statistics

    Possible requests: statfs

    Parameters
    reqrequest handle
    stbuffilesystem statistics
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1051 of file fuse_lowlevel.c.

    ◆ fuse_reply_statx()

    int fuse_reply_statx ( fuse_req_t req,
    int flags,
    struct statx * statx,
    double attr_timeout )

    Reply with extended file attributes.

    Possible requests: statx

    Parameters
    reqrequest handle
    flagsstatx flags
    statxthe attributes
    attr_timeoutvalidity timeout (in seconds) for the attributes
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1268 of file fuse_lowlevel.c.

    ◆ fuse_reply_write()

    int fuse_reply_write ( fuse_req_t req,
    size_t count )

    Reply with number of bytes written

    Possible requests: write

    Parameters
    reqrequest handle
    countthe number of bytes written
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 620 of file fuse_lowlevel.c.

    ◆ fuse_reply_xattr()

    int fuse_reply_xattr ( fuse_req_t req,
    size_t count )

    Reply with needed buffer size

    Possible requests: getxattr, listxattr

    Parameters
    reqrequest handle
    countthe buffer size needed in bytes
    Returns
    zero for success, -errno for failure to send reply

    Definition at line 1063 of file fuse_lowlevel.c.

    ◆ fuse_req_ctx()

    const struct fuse_ctx * fuse_req_ctx ( fuse_req_t req)

    Get the context from the request

    The pointer returned by this function will only be valid for the request's lifetime

    Parameters
    reqrequest handle
    Returns
    the context structure

    Definition at line 3379 of file fuse_lowlevel.c.

    ◆ fuse_req_get_payload()

    int fuse_req_get_payload ( fuse_req_t req,
    char ** payload,
    size_t * payload_sz,
    void ** mr )

    Get the payload of a request (for requests submitted through fuse-io-uring only)

    This is useful for a file system that wants to write data directly to the request buffer. With io-uring the req is the buffer owner and the file system can write directly to the buffer and avoid extra copying. For example useful for network file systems.

    Parameters
    reqthe request
    payloadpointer to the payload
    payload_szsize of the payload
    mrmemory registration handle, currently unused
    Returns
    0 on success, -errno on failure

    Definition at line 3414 of file fuse_lowlevel.c.

    ◆ fuse_req_getgroups()

    int fuse_req_getgroups ( fuse_req_t req,
    int size,
    gid_t list[] )

    Get the current supplementary group IDs for the specified request

    Similar to the getgroups(2) system call, except the return value is always the total number of group IDs, even if it is larger than the specified size.

    The current fuse kernel module in linux (as of 2.6.30) doesn't pass the group list to userspace, hence this function needs to parse "/proc/$TID/task/$TID/status" to get the group IDs.

    This feature may not be supported on all operating systems. In such a case this function will return -ENOSYS.

    Parameters
    reqrequest handle
    sizesize of given array
    listarray of group IDs to be filled in
    Returns
    the total number of supplementary group IDs or -errno on failure

    Definition at line 4501 of file fuse_lowlevel.c.

    ◆ fuse_req_interrupt_func()

    void fuse_req_interrupt_func ( fuse_req_t req,
    fuse_interrupt_func_t func,
    void * data )

    Register/unregister callback for an interrupt

    If an interrupt has already happened, then the callback function is called from within this function, hence it's not possible for interrupts to be lost.

    Parameters
    reqrequest handle
    functhe callback function or NULL for unregister
    datauser data passed to the callback function

    Definition at line 3384 of file fuse_lowlevel.c.

    ◆ fuse_req_interrupted()

    int fuse_req_interrupted ( fuse_req_t req)

    Check if a request has already been interrupted

    Parameters
    reqrequest handle
    Returns
    1 if the request has been interrupted, 0 otherwise

    Definition at line 3397 of file fuse_lowlevel.c.

    ◆ fuse_req_is_uring()

    bool fuse_req_is_uring ( fuse_req_t req)

    Check if the request is submitted through fuse-io-uring

    Definition at line 3408 of file fuse_lowlevel.c.

    ◆ fuse_req_userdata()

    void * fuse_req_userdata ( fuse_req_t req)

    Get the userdata from the request

    Parameters
    reqrequest handle
    Returns
    the user data passed to fuse_session_new()

    Definition at line 3374 of file fuse_lowlevel.c.

    ◆ fuse_session_destroy()

    void fuse_session_destroy ( struct fuse_session * se)

    Destroy a session

    Parameters
    sethe session

    Definition at line 3842 of file fuse_lowlevel.c.

    ◆ fuse_session_exit()

    void fuse_session_exit ( struct fuse_session * se)

    Flag a session as terminated.

    This will cause any running event loop to terminate on the next opportunity. fuse_session_loop_mt(), and fuse_session_loop() from FUSE_USE_VERSION 3.19 on, are woken up directly and return without waiting for a request, no matter which thread calls this.

    The deprecated fuse_session_loop() below FUSE_USE_VERSION 3.19 is not woken up and only notices the flag once the next request is received, which may be far in the future if the filesystem is not currently being used by any clients. Sending a signal to its thread afterwards avoids that delay - if fuse_set_signal_handlers() is used, SIGPIPE will cause the thread to wake-up but otherwise be ignored.

    Parameters
    sethe session

    ◆ fuse_session_exited()

    int fuse_session_exited ( struct fuse_session * se)

    Query the terminated flag of a session

    Parameters
    sethe session
    Returns
    1 if exited, 0 if not exited

    ◆ fuse_session_fd()

    int fuse_session_fd ( struct fuse_session * se)

    Return file descriptor for communication with kernel.

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

    The returned file descriptor is valid until fuse_session_unmount is called.

    Parameters
    sethe session
    Returns
    a file descriptor

    Definition at line 4421 of file fuse_lowlevel.c.

    ◆ fuse_session_loop()

    int fuse_session_loop ( struct fuse_session * se)

    Enter a single threaded, blocking event loop.

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

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

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

    Parameters
    sethe session
    Returns
    0, -errno, or a signal value

    Definition at line 19 of file fuse_loop.c.

    ◆ fuse_session_mount()

    int fuse_session_mount ( struct fuse_session * se,
    const char * mountpoint )

    Mount a FUSE file system.

    Parameters
    mountpointthe mount point path
    sesession object
    Returns
    0 on success, -1 on failure.

    Definition at line 4361 of file fuse_lowlevel.c.

    ◆ fuse_session_process_buf()

    void fuse_session_process_buf ( struct fuse_session * se,
    const struct fuse_buf * buf )

    Process a raw request supplied in a generic buffer

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

    Parameters
    sethe session
    bufthe fuse_buf containing the request

    Definition at line 3618 of file fuse_lowlevel.c.

    ◆ fuse_session_receive_buf()

    int fuse_session_receive_buf ( struct fuse_session * se,
    struct fuse_buf * buf )

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

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

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

    Definition at line 4125 of file fuse_lowlevel.c.

    ◆ fuse_session_reset()

    void fuse_session_reset ( struct fuse_session * se)

    Reset the terminated flag of a session

    Parameters
    sethe session

    ◆ fuse_session_unmount()

    void fuse_session_unmount ( struct fuse_session * se)

    Ensure that file system is unmounted.

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

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

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

    Parameters
    sethe session

    Definition at line 4426 of file fuse_lowlevel.c.

    fuse-3.18.3/doc/html/fuse__opt_8h.html0000644000175000017500000007113715250106404016505 0ustar berndbernd libfuse: include/fuse_opt.h File Reference
    libfuse
    fuse_opt.h File Reference

    Go to the source code of this file.

    Data Structures

    struct  fuse_opt
    struct  fuse_args

    Macros

    #define FUSE_OPT_KEY(templ, key)
    #define FUSE_OPT_END   { NULL, 0, 0 }
    #define FUSE_ARGS_INIT(argc, argv)
    #define FUSE_OPT_KEY_OPT   -1
    #define FUSE_OPT_KEY_NONOPT   -2
    #define FUSE_OPT_KEY_KEEP   -3
    #define FUSE_OPT_KEY_DISCARD   -4

    Typedefs

    typedef int(* fuse_opt_proc_t) (void *data, const char *arg, int key, struct fuse_args *outargs)

    Functions

    int fuse_opt_parse (struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
    int fuse_opt_add_opt (char **opts, const char *opt)
    int fuse_opt_add_opt_escaped (char **opts, const char *opt)
    int fuse_opt_add_arg (struct fuse_args *args, const char *arg)
    int fuse_opt_insert_arg (struct fuse_args *args, int pos, const char *arg)
    void fuse_opt_free_args (struct fuse_args *args)
    int fuse_opt_match (const struct fuse_opt opts[], const char *opt)

    Detailed Description

    This file defines the option parsing interface of FUSE

    Definition in file fuse_opt.h.

    Macro Definition Documentation

    ◆ FUSE_ARGS_INIT

    #define FUSE_ARGS_INIT ( argc,
    argv )
    Value:
    { argc, argv, 0 }

    Initializer for 'struct fuse_args'

    Definition at line 123 of file fuse_opt.h.

    ◆ FUSE_OPT_END

    #define FUSE_OPT_END   { NULL, 0, 0 }

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

    Definition at line 104 of file fuse_opt.h.

    ◆ FUSE_OPT_KEY

    #define FUSE_OPT_KEY ( templ,
    key )
    Value:
    { templ, -1U, key }

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

    Definition at line 98 of file fuse_opt.h.

    ◆ FUSE_OPT_KEY_DISCARD

    #define FUSE_OPT_KEY_DISCARD   -4

    Special key value for options to discard

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

    Definition at line 153 of file fuse_opt.h.

    ◆ FUSE_OPT_KEY_KEEP

    #define FUSE_OPT_KEY_KEEP   -3

    Special key value for options to keep

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

    Definition at line 145 of file fuse_opt.h.

    ◆ FUSE_OPT_KEY_NONOPT

    #define FUSE_OPT_KEY_NONOPT   -2

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

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

    Definition at line 137 of file fuse_opt.h.

    ◆ FUSE_OPT_KEY_OPT

    #define FUSE_OPT_KEY_OPT   -1

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

    Definition at line 129 of file fuse_opt.h.

    Typedef Documentation

    ◆ fuse_opt_proc_t

    typedef int(* fuse_opt_proc_t) (void *data, const char *arg, int key, struct fuse_args *outargs)

    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.

    Parameters
    datais the user data passed to the fuse_opt_parse() function
    argis the whole argument or option
    keydetermines why the processing function was called
    outargsthe current output argument list
    Returns
    -1 on error, 0 if arg is to be discarded, 1 if arg should be kept

    Definition at line 180 of file fuse_opt.h.

    Function Documentation

    ◆ fuse_opt_add_arg()

    int fuse_opt_add_arg ( struct fuse_args * args,
    const char * arg )

    Add an argument to a NULL terminated argument vector

    Parameters
    argsis the structure containing the current argument list
    argis the new argument to add
    Returns
    -1 on allocation error, 0 on success

    Definition at line 55 of file fuse_opt.c.

    ◆ fuse_opt_add_opt()

    int fuse_opt_add_opt ( char ** opts,
    const char * opt )

    Add an option to a comma separated option list

    Parameters
    optsis a pointer to an option list, may point to a NULL value
    optis the option to add
    Returns
    -1 on allocation error, 0 on success

    Definition at line 139 of file fuse_opt.c.

    ◆ fuse_opt_add_opt_escaped()

    int fuse_opt_add_opt_escaped ( char ** opts,
    const char * opt )

    Add an option, escaping commas, to a comma separated option list

    Parameters
    optsis a pointer to an option list, may point to a NULL value
    optis the option to add
    Returns
    -1 on allocation error, 0 on success

    Definition at line 144 of file fuse_opt.c.

    ◆ fuse_opt_free_args()

    void fuse_opt_free_args ( struct fuse_args * args)

    Free the contents of argument list

    The structure itself is not freed

    Parameters
    argsis the structure containing the argument list

    Definition at line 34 of file fuse_opt.c.

    ◆ fuse_opt_insert_arg()

    int fuse_opt_insert_arg ( struct fuse_args * args,
    int pos,
    const char * arg )

    Add an argument at the specified position in a NULL terminated argument vector

    Adds the argument to the N-th position. This is useful for adding options at the beginning of the array which must not come after the special '–' option.

    Parameters
    argsis the structure containing the current argument list
    posis the position at which to add the argument
    argis the new argument to add
    Returns
    -1 on allocation error, 0 on success

    Definition at line 95 of file fuse_opt.c.

    ◆ fuse_opt_match()

    int fuse_opt_match ( const struct fuse_opt opts[],
    const char * opt )

    Check if an option matches

    Parameters
    optsis the option description array
    optis the option to match
    Returns
    1 if a match is found, 0 if not

    ◆ fuse_opt_parse()

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

    Option parsing function

    If 'args' was returned from a previous call to fuse_opt_parse() or it was constructed from

    A NULL 'args' is equivalent to an empty argument vector

    A NULL 'opts' is equivalent to an 'opts' array containing a single end marker

    A NULL 'proc' is equivalent to a processing function always returning '1'

    Parameters
    argsis the input and output argument list
    datais the user data
    optsis the option description array
    procis the processing function
    Returns
    -1 on error, 0 on success

    Definition at line 398 of file fuse_opt.c.

    fuse-3.18.3/doc/html/structfuse__args.html0000644000175000017500000001314115250106404017474 0ustar berndbernd 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-3.18.3/doc/html/structfuse__buf.html0000644000175000017500000002152215250106404017316 0ustar berndbernd 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
    size_t mem_size

    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 893 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 916 of file fuse_common.h.

    ◆ flags

    enum fuse_buf_flags fuse_buf::flags

    Buffer flags

    Definition at line 902 of file fuse_common.h.

    ◆ mem

    void* fuse_buf::mem

    Memory pointer

    Used unless FUSE_BUF_IS_FD flag is set.

    Definition at line 909 of file fuse_common.h.

    ◆ mem_size

    size_t fuse_buf::mem_size

    Size of memory pointer

    Used only if mem was internally allocated. Not used if mem was user-provided.

    Definition at line 931 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 923 of file fuse_common.h.

    ◆ size

    size_t fuse_buf::size

    Size of data in bytes

    Definition at line 897 of file fuse_common.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__bufvec.html0000644000175000017500000001554215250106404020021 0ustar berndbernd 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 942 of file fuse_common.h.

    Field Documentation

    ◆ buf

    struct fuse_buf fuse_bufvec::buf[1]

    Array of buffers

    Definition at line 961 of file fuse_common.h.

    ◆ count

    size_t fuse_bufvec::count

    Number of buffers in the array

    Definition at line 946 of file fuse_common.h.

    ◆ idx

    size_t fuse_bufvec::idx

    Index of current buffer within the array

    Definition at line 951 of file fuse_common.h.

    ◆ off

    size_t fuse_bufvec::off

    Current offset within the current buffer

    Definition at line 956 of file fuse_common.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__cmdline__opts.html0000644000175000017500000000534115250106404021362 0ustar berndbernd libfuse: fuse_cmdline_opts Struct Reference
    libfuse
    fuse_cmdline_opts Struct Reference

    #include <fuse_lowlevel.h>

    Detailed Description

    Note: Any addition to this struct needs to create a compatibility symbol for fuse_parse_cmdline(). For ABI compatibility reasons it is also not possible to remove struct members.

    Definition at line 2047 of file fuse_lowlevel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__config.html0000644000175000017500000007224715250106404020021 0ustar berndbernd libfuse: fuse_config Struct Reference
    libfuse
    fuse_config Struct Reference

    #include <fuse.h>

    Data Fields

    int32_t set_gid
    int32_t set_uid
    int32_t set_mode
    double entry_timeout
    double negative_timeout
    double attr_timeout
    int32_t intr
    int32_t intr_signal
    int32_t remember
    int32_t hard_remove
    int32_t use_ino
    int32_t readdir_ino
    int32_t direct_io
    int32_t kernel_cache
    int32_t auto_cache
    int32_t nullpath_ok
    int32_t show_help
    uint32_t fmask
    int32_t no_rofd_flush
    int32_t parallel_direct_writes
    uint32_t flags
    uint64_t reserved [48]

    Detailed Description

    Configuration of the high-level API

    This structure is initialized from the arguments passed to fuse_new(), and then passed to the file system's init() handler which should ensure that the configuration is compatible with the file system implementation.

    Note: this data structure is ABI sensitive, new options have to be appended at the end of the structure

    Definition at line 107 of file fuse.h.

    Field Documentation

    ◆ attr_timeout

    double fuse_config::attr_timeout

    The timeout in seconds for which file/directory attributes (as returned by e.g. the getattr handler) are cached.

    Definition at line 149 of file fuse.h.

    ◆ auto_cache

    int32_t fuse_config::auto_cache

    This option is an alternative to kernel_cache. Instead of unconditionally keeping cached data, the cached data is invalidated on open(2) if if the modification time or the size of the file has changed since it was last opened.

    Definition at line 259 of file fuse.h.

    ◆ direct_io

    int32_t fuse_config::direct_io

    This option disables the use of page cache (file content cache) in the kernel for this filesystem. This has several affects:

    1. Each read(2) or write(2) system call will initiate one or more read or write operations, data will not be cached in the kernel.
    2. The return value of the read() and write() system calls will correspond to the return values of the read and write operations. This is useful for example if the file size is not known in advance (before reading it).

    Internally, enabling this option causes fuse to set the direct_io field of struct fuse_file_info - overwriting any value that was put there by the file system.

    Definition at line 232 of file fuse.h.

    ◆ entry_timeout

    double fuse_config::entry_timeout

    The timeout in seconds for which name lookups will be cached.

    Definition at line 133 of file fuse.h.

    ◆ flags

    uint32_t fuse_config::flags

    Reserved for future use.

    Definition at line 324 of file fuse.h.

    ◆ fmask

    uint32_t fuse_config::fmask

    fmask and dmask function the same way as umask, but apply to files and directories separately. If non-zero, fmask and dmask take precedence over the umask setting.

    Definition at line 294 of file fuse.h.

    ◆ hard_remove

    int32_t fuse_config::hard_remove

    The default behavior is that if an open file is deleted, the file is renamed to a hidden file (.fuse_hiddenXXX), and only removed when the file is finally released. This relieves the filesystem implementation of having to deal with this problem. This option disables the hiding behavior, and files are removed immediately in an unlink operation (or in a rename operation which overwrites an existing file).

    It is recommended that you not use the hard_remove option. When hard_remove is set, the following libc functions fail on unlinked files (returning errno of ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2), ftruncate(2), fstat(2), fchmod(2), fchown(2)

    Definition at line 191 of file fuse.h.

    ◆ intr

    int32_t fuse_config::intr

    Allow requests to be interrupted

    Definition at line 154 of file fuse.h.

    ◆ intr_signal

    int32_t fuse_config::intr_signal

    Specify which signal number to send to the filesystem when a request is interrupted. The default is hardcoded to USR1.

    Definition at line 161 of file fuse.h.

    ◆ kernel_cache

    int32_t fuse_config::kernel_cache

    This option disables flushing the cache of the file contents on every open(2). This should only be enabled on filesystems where the file data is never changed externally (not through the mounted FUSE filesystem). Thus it is not suitable for network filesystems and other intermediate filesystems.

    NOTE: if this option is not specified (and neither direct_io) data is still cached after the open(2), so a read(2) system call will not always initiate a read operation.

    Internally, enabling this option causes fuse to set the keep_cache field of struct fuse_file_info - overwriting any value that was put there by the file system.

    Definition at line 251 of file fuse.h.

    ◆ negative_timeout

    double fuse_config::negative_timeout

    The timeout in seconds for which a negative lookup will be cached. This means, that if file did not exist (lookup returned ENOENT), the lookup will only be redone after the timeout, and the file/directory will be assumed to not exist until then. A value of zero means that negative lookups are not cached.

    Definition at line 143 of file fuse.h.

    ◆ no_rofd_flush

    int32_t fuse_config::no_rofd_flush

    By default, fuse waits for all pending writes to complete and calls the FLUSH operation on close(2) of every fuse fd. With this option, wait and FLUSH are not done for read-only fuse fd, similar to the behavior of NFS/SMB clients.

    Definition at line 303 of file fuse.h.

    ◆ nullpath_ok

    int32_t fuse_config::nullpath_ok

    If this option is given the file-system handlers for the following operations will not receive path information: read, write, flush, release, fallocate, fsync, readdir, releasedir, fsyncdir, lock, ioctl and poll.

    For the truncate, getattr, chmod, chown and utimens operations the path will be provided only if the struct fuse_file_info argument is NULL.

    Definition at line 279 of file fuse.h.

    ◆ parallel_direct_writes

    int32_t fuse_config::parallel_direct_writes

    Allow parallel direct-io writes to operate on the same file.

    FUSE implementations which do not handle parallel writes on same file/region should NOT enable this option at all as it might lead to data inconsistencies.

    For the FUSE implementations which have their own mechanism of cache/data integrity are beneficiaries of this setting as it now open doors to parallel writes on the same file (without enabling this setting, all direct writes on the same file are serialized, resulting in huge data bandwidth loss).

    Definition at line 318 of file fuse.h.

    ◆ readdir_ino

    int32_t fuse_config::readdir_ino

    If use_ino option is not given, still try to fill in the d_ino field in readdir(2). If the name was previously looked up, and is still in the cache, the inode number found there will be used. Otherwise it will be set to -1. If use_ino option is given, this option is ignored.

    Definition at line 213 of file fuse.h.

    ◆ remember

    int32_t fuse_config::remember

    Normally, FUSE assigns inodes to paths only for as long as the kernel is aware of them. With this option inodes are instead remembered for at least this many seconds. This will require more memory, but may be necessary when using applications that make use of inode numbers.

    A number of -1 means that inodes will be remembered for the entire life-time of the file-system process.

    Definition at line 173 of file fuse.h.

    ◆ reserved

    uint64_t fuse_config::reserved[48]

    Reserved for future use.

    Definition at line 329 of file fuse.h.

    ◆ set_gid

    int32_t fuse_config::set_gid

    If set_gid is non-zero, the st_gid attribute of each file is overwritten with the value of gid.

    Definition at line 112 of file fuse.h.

    ◆ set_mode

    int32_t fuse_config::set_mode

    If set_mode is non-zero, the any permissions bits set in umask are unset in the st_mode attribute of each file.

    Definition at line 126 of file fuse.h.

    ◆ set_uid

    int32_t fuse_config::set_uid

    If set_uid is non-zero, the st_uid attribute of each file is overwritten with the value of uid.

    Definition at line 119 of file fuse.h.

    ◆ show_help

    int32_t fuse_config::show_help

    These 3 options are used by libfuse internally and should not be touched.

    Definition at line 285 of file fuse.h.

    ◆ use_ino

    int32_t fuse_config::use_ino

    Honor the st_ino field in the functions getattr() and fill_dir(). This value is used to fill in the st_ino field in the stat(2), lstat(2), fstat(2) functions and the d_ino field in the readdir(2) function. The filesystem does not have to guarantee uniqueness, however some applications rely on this value being unique for the whole filesystem.

    Note that this does not affect the inode that libfuse and the kernel use internally (also called the "nodeid").

    Definition at line 204 of file fuse.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__conn__info.html0000644000175000017500000005332015250106404020652 0ustar berndbernd libfuse: fuse_conn_info Struct Reference
    libfuse
    fuse_conn_info Struct Reference

    #include <fuse_common.h>

    Data Fields

    uint32_t proto_major
    uint32_t proto_minor
    uint32_t max_write
    uint32_t max_read
    uint32_t max_readahead
    uint32_t capable
    uint32_t want
    uint32_t max_background
    uint32_t congestion_threshold
    uint32_t time_gran
    uint32_t no_interrupt: 1
    uint64_t capable_ext
    uint64_t want_ext
    uint16_t request_timeout
    uint16_t reserved [31]

    Detailed Description

    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.

    Note: The capable and want fields are limited to 32 bits for ABI compatibility. For full 64-bit capability support, use the capable_ext and want_ext fields instead.

    Definition at line 551 of file fuse_common.h.

    Field Documentation

    ◆ capable

    uint32_t fuse_conn_info::capable

    Capability flags that the kernel supports (read-only)

    Deprecated left over for ABI compatibility, use capable_ext

    Definition at line 591 of file fuse_common.h.

    ◆ capable_ext

    uint64_t fuse_conn_info::capable_ext

    Extended capability flags that the kernel supports (read-only) This field provides full 64-bit capability support.

    Definition at line 699 of file fuse_common.h.

    ◆ congestion_threshold

    uint32_t fuse_conn_info::congestion_threshold

    Kernel congestion threshold parameter. If the number of pending background requests exceeds this number, the FUSE kernel module will mark the filesystem as "congested". This instructs the kernel to expect that queued requests will take some time to complete, and to adjust its algorithms accordingly (e.g. by putting a waiting thread to sleep instead of using a busy-loop).

    Definition at line 643 of file fuse_common.h.

    ◆ max_background

    uint32_t fuse_conn_info::max_background

    Maximum number of pending "background" requests. A background request is any type of request for which the total number is not limited by other means. As of kernel 4.8, only two types of requests fall into this category:

    1. Read-ahead requests
    2. Asynchronous direct I/O requests

    Read-ahead requests are generated (if max_readahead is non-zero) by the kernel to preemptively fill its caches when it anticipates that userspace will soon read more data.

    Asynchronous direct I/O requests are generated if FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large direct I/O request. In this case the kernel will internally split it up into multiple smaller requests and submit them to the filesystem concurrently.

    Note that the following requests are not background requests: writeback requests (limited by the kernel's flusher algorithm), regular (i.e., synchronous and buffered) userspace read/write requests (limited to one per thread), asynchronous read requests (Linux's io_submit(2) call actually blocks, so these are also limited to one per thread).

    Definition at line 633 of file fuse_common.h.

    ◆ max_read

    uint32_t fuse_conn_info::max_read

    Maximum size of read requests. A value of zero indicates no limit. However, even if the filesystem does not specify a limit, the maximum size of read requests will still be limited by the kernel.

    NOTE: For the time being, the maximum size of read requests must be set both here and passed to fuse_session_new() using the -o max_read=<n> mount option. At some point in the future, specifying the mount option will no longer be necessary.

    Definition at line 579 of file fuse_common.h.

    ◆ max_readahead

    uint32_t fuse_conn_info::max_readahead

    Maximum readahead

    Definition at line 584 of file fuse_common.h.

    ◆ max_write

    uint32_t fuse_conn_info::max_write

    Maximum size of the write buffer

    Definition at line 565 of file fuse_common.h.

    ◆ no_interrupt

    uint32_t fuse_conn_info::no_interrupt

    Disable FUSE_INTERRUPT requests.

    Enable no_interrupt option to: 1) Avoid unnecessary locking operations and list operations, 2) Return ENOSYS for the reply of FUSE_INTERRUPT request to inform the kernel not to send the FUSE_INTERRUPT request.

    Definition at line 690 of file fuse_common.h.

    ◆ proto_major

    uint32_t fuse_conn_info::proto_major

    Major version of the protocol (read-only)

    Definition at line 555 of file fuse_common.h.

    ◆ proto_minor

    uint32_t fuse_conn_info::proto_minor

    Minor version of the protocol (read-only)

    Definition at line 560 of file fuse_common.h.

    ◆ request_timeout

    uint16_t fuse_conn_info::request_timeout

    Request timeout (in seconds). If the request is not answered by this timeout, the connection will be aborted by the kernel.

    Definition at line 715 of file fuse_common.h.

    ◆ reserved

    uint16_t fuse_conn_info::reserved[31]

    For future use.

    Definition at line 720 of file fuse_common.h.

    ◆ time_gran

    uint32_t fuse_conn_info::time_gran

    When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible for updating mtime and ctime when write requests are received. The updated values are passed to the filesystem with setattr() requests. However, if the filesystem does not support the full resolution of the kernel timestamps (nanoseconds), the mtime and ctime values used by kernel and filesystem will differ (and result in an apparent change of times after a cache flush).

    To prevent this problem, this variable can be used to inform the kernel about the timestamp granularity supported by the file-system. The value should be power of 10. The default is 1, i.e. full nano-second resolution. Filesystems supporting only second resolution should set this to 1000000000.

    Definition at line 660 of file fuse_common.h.

    ◆ want

    uint32_t fuse_conn_info::want

    Capability flags that the filesystem wants to enable.

    libfuse attempts to initialize this field with reasonable default values before calling the init() handler.

    Deprecated left over for ABI compatibility. Use want_ext with the helper functions fuse_set_feature_flag() / fuse_unset_feature_flag()

    Definition at line 603 of file fuse_common.h.

    ◆ want_ext

    uint64_t fuse_conn_info::want_ext

    Extended capability flags that the filesystem wants to enable. This field provides full 64-bit capability support.

    Don't set this field directly, but use the helper functions fuse_set_feature_flag() / fuse_unset_feature_flag()

    Definition at line 709 of file fuse_common.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__context.html0000644000175000017500000002057115250106404020231 0ustar berndbernd 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 877 of file fuse.h.

    Field Documentation

    ◆ fuse

    struct fuse* fuse_context::fuse

    Pointer to the fuse object

    Definition at line 879 of file fuse.h.

    ◆ gid

    gid_t fuse_context::gid

    Group ID of the calling process

    Definition at line 885 of file fuse.h.

    ◆ pid

    pid_t fuse_context::pid

    Process ID of the calling thread

    Definition at line 888 of file fuse.h.

    ◆ private_data

    void* fuse_context::private_data

    Private filesystem data

    Definition at line 891 of file fuse.h.

    ◆ uid

    uid_t fuse_context::uid

    User ID of the calling process

    Definition at line 882 of file fuse.h.

    ◆ umask

    mode_t fuse_context::umask

    Umask of the calling process

    Definition at line 894 of file fuse.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__ctx.html0000644000175000017500000001560415250106404017344 0ustar berndbernd libfuse: fuse_ctx Struct Reference
    libfuse
    fuse_ctx Struct Reference

    #include <fuse_lowlevel.h>

    Data Fields

    uid_t uid
    gid_t gid
    pid_t pid
    mode_t umask

    Detailed Description

    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.

    Definition at line 115 of file fuse_lowlevel.h.

    Field Documentation

    ◆ gid

    gid_t fuse_ctx::gid

    Group ID of the calling process

    Definition at line 120 of file fuse_lowlevel.h.

    ◆ pid

    pid_t fuse_ctx::pid

    Thread ID of the calling process

    Definition at line 123 of file fuse_lowlevel.h.

    ◆ uid

    uid_t fuse_ctx::uid

    User ID of the calling process

    Definition at line 117 of file fuse_lowlevel.h.

    ◆ umask

    mode_t fuse_ctx::umask

    Umask of the calling process

    Definition at line 126 of file fuse_lowlevel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__entry__param.html0000644000175000017500000002166615250106404021233 0ustar berndbernd libfuse: fuse_entry_param Struct Reference
    libfuse
    fuse_entry_param Struct Reference

    #include <fuse_lowlevel.h>

    Data Fields

    fuse_ino_t ino
    uint64_t generation
    struct stat attr
    double attr_timeout
    double entry_timeout

    Detailed Description

    Directory entry parameters supplied to fuse_reply_entry()

    Definition at line 63 of file fuse_lowlevel.h.

    Field Documentation

    ◆ attr

    struct stat fuse_entry_param::attr

    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.

    Definition at line 92 of file fuse_lowlevel.h.

    ◆ attr_timeout

    double fuse_entry_param::attr_timeout

    Validity timeout (in seconds) for inode attributes. If attributes only change as a result of requests that come through the kernel, this should be set to a very large value.

    Definition at line 98 of file fuse_lowlevel.h.

    ◆ entry_timeout

    double fuse_entry_param::entry_timeout

    Validity timeout (in seconds) for the name. If directory entries are changed/deleted only as a result of requests that come through the kernel, this should be set to a very large value.

    Definition at line 104 of file fuse_lowlevel.h.

    ◆ generation

    uint64_t fuse_entry_param::generation

    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.

    Definition at line 83 of file fuse_lowlevel.h.

    ◆ ino

    fuse_ino_t fuse_entry_param::ino

    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.

    Definition at line 71 of file fuse_lowlevel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__ext__header.html0000644000175000017500000000546315250106404021017 0ustar berndbernd libfuse: fuse_ext_header Struct Reference
    libfuse
    fuse_ext_header Struct Reference

    #include <fuse_kernel.h>

    Detailed Description

    struct fuse_ext_header - extension header @size: total size of this extension including this header @type: type of extension

    This is made compatible with fuse_secctx_header by using type values > FUSE_MAX_NR_SECCTX

    Definition at line 1225 of file fuse_kernel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__file__info.html0000644000175000017500000004776215250106404020651 0ustar berndbernd libfuse: fuse_file_info Struct Reference
    libfuse
    fuse_file_info Struct Reference

    #include <fuse_common.h>

    Data Fields

    int32_t flags
    uint32_t writepage: 1
    uint32_t direct_io: 1
    uint32_t keep_cache: 1
    uint32_t flush: 1
    uint32_t nonseekable: 1
    uint32_t cache_readdir: 1
    uint32_t noflush: 1
    uint32_t parallel_direct_writes: 1
    uint32_t kill_suidgid: 1
    uint32_t padding: 22
    uint64_t fh
    uint64_t lock_owner
    uint32_t poll_events
    int32_t backing_id
    uint64_t compat_flags

    Detailed Description

    Information about an open file.

    File Handles are created by the open, opendir, and create methods and closed by the release and releasedir methods. Multiple file handles may be concurrently open for the same file. Generally, a client will create one file handle per file descriptor, though in some cases multiple file descriptors can share a single file handle.

    Note: This data structure is ABI sensitive, new parameters have to be added within padding/padding2 bits and always below existing parameters.

    Definition at line 50 of file fuse_common.h.

    Field Documentation

    ◆ backing_id

    int32_t fuse_file_info::backing_id

    Passthrough backing file id. May be filled in by filesystem in create and open. It is used to create a passthrough connection between FUSE file and backing file.

    Definition at line 127 of file fuse_common.h.

    ◆ cache_readdir

    uint32_t fuse_file_info::cache_readdir

    Can be filled in by opendir. It signals the kernel to enable caching of entries returned by readdir(). Has no effect when set in other contexts (in particular it does nothing when set by open()).

    Definition at line 89 of file fuse_common.h.

    ◆ compat_flags

    uint64_t fuse_file_info::compat_flags

    struct fuse_file_info api and abi flags

    Definition at line 130 of file fuse_common.h.

    ◆ direct_io

    uint32_t fuse_file_info::direct_io

    Can be filled in by open/create, to use direct I/O on this file.

    Definition at line 63 of file fuse_common.h.

    ◆ fh

    uint64_t fuse_file_info::fh

    File handle id. May be filled in by filesystem in create, open, and opendir(). Available in most other file operations on the same file handle.

    Definition at line 115 of file fuse_common.h.

    ◆ flags

    int32_t fuse_file_info::flags

    Open flags. Available in open(), release() and create()

    Definition at line 52 of file fuse_common.h.

    ◆ flush

    uint32_t fuse_file_info::flush

    Indicates a flush operation. Set in flush operation, also maybe set in highlevel lock operation and lowlevel release operation.

    Definition at line 74 of file fuse_common.h.

    ◆ keep_cache

    uint32_t fuse_file_info::keep_cache

    Can be filled in by open and opendir. It signals the kernel that any currently cached data (ie., data that the filesystem provided the last time the file/directory was open) need not be invalidated when the file/directory is closed.

    Definition at line 69 of file fuse_common.h.

    ◆ kill_suidgid

    uint32_t fuse_file_info::kill_suidgid

    Set in open, create and write when KILLPRIV_V2 was negotiated and the application issuing the syscall lacks CAP_FSETID; the filesystem's own privileges do not matter. The filesystem then has to remove setuid/setgid bits.

    Definition at line 105 of file fuse_common.h.

    ◆ lock_owner

    uint64_t fuse_file_info::lock_owner

    Lock owner id. Available in locking operations and flush

    Definition at line 118 of file fuse_common.h.

    ◆ noflush

    uint32_t fuse_file_info::noflush

    Can be filled in by open, to indicate that flush is not needed on close.

    Definition at line 93 of file fuse_common.h.

    ◆ nonseekable

    uint32_t fuse_file_info::nonseekable

    Can be filled in by open, to indicate that the file is not seekable.

    Definition at line 78 of file fuse_common.h.

    ◆ padding

    uint32_t fuse_file_info::padding

    Padding. Reserved for future use

    Definition at line 108 of file fuse_common.h.

    ◆ parallel_direct_writes

    uint32_t fuse_file_info::parallel_direct_writes

    Can be filled by open/create, to allow parallel direct writes on this file

    Definition at line 97 of file fuse_common.h.

    ◆ poll_events

    uint32_t fuse_file_info::poll_events

    Requested poll events. Available in ->poll. Only set on kernels which support it. If unsupported, this field is set to zero.

    Definition at line 122 of file fuse_common.h.

    ◆ writepage

    uint32_t fuse_file_info::writepage

    In case of a write operation indicates if this was caused by a delayed write from the page cache. If so, then the context's pid, uid, and gid fields will not be valid, and the fh value may not match the fh value that would have been sent with the corresponding individual write requests if write caching had been disabled.

    Definition at line 60 of file fuse_common.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__loop__config.html0000644000175000017500000001764315250106404021210 0ustar berndbernd libfuse: fuse_loop_config Struct Reference
    libfuse
    fuse_loop_config Struct Reference

    #include <fuse_i.h>

    Data Fields

    int clone_fd
    unsigned int max_idle_threads
    int max_idle_threads
    unsigned int max_threads

    Detailed Description

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

    Internal API to avoid exposing the plain data structure and causing compat issues after adding or removing struct members.

    Definition at line 147 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 155 of file fuse_common.h.

    ◆ max_idle_threads [1/2]

    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 167 of file fuse_common.h.

    ◆ max_idle_threads [2/2]

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

    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. The special value of -1 means that this parameter is disabled.

    Definition at line 183 of file fuse_i.h.

    ◆ max_threads

    unsigned int fuse_loop_config::max_threads

    max number of threads taking and processing kernel requests

    As of now threads are created dynamically

    Definition at line 190 of file fuse_i.h.


    The documentation for this struct was generated from the following files:
    fuse-3.18.3/doc/html/structfuse__lowlevel__ops.html0000644000175000017500000034462715250106404021431 0ustar berndbernd libfuse: fuse_lowlevel_ops Struct Reference
    libfuse
    fuse_lowlevel_ops Struct Reference

    #include <fuse_lowlevel.h>

    Data Fields

    void(* init )(void *userdata, struct fuse_conn_info *conn)
    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, uint64_t 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, unsigned int flags)
    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, fuse_ino_t ino)
    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)
    void(* getlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
    void(* setlk )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
    void(* bmap )(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
    void(* ioctl )(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)
    void(* poll )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)
    void(* write_buf )(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, off_t off, struct fuse_file_info *fi)
    void(* retrieve_reply )(fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv)
    void(* forget_multi )(fuse_req_t req, size_t count, struct fuse_forget_data *forgets)
    void(* flock )(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)
    void(* fallocate )(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
    void(* readdirplus )(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
    void(* copy_file_range )(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
    void(* lseek )(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)
    void(* tmpfile )(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)
    void(* statx )(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)

    Detailed Description

    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.

    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_session_new(). In this case, methods will only be called if the kernel's permission check has succeeded.

    It is generally not really necessary to check the fuse_reply_* return values for errors, as any error in sending a reply indicates an unrecoverable problem with the kernel fuse connection, which will also terminate the session loop anyway.

    This data structure is ABI sensitive, on adding new functions these need to be appended at the end of the struct

    Definition at line 208 of file fuse_lowlevel.h.

    Field Documentation

    ◆ access

    void(* fuse_lowlevel_ops::access) (fuse_req_t req, fuse_ino_t ino, int mask)

    Check file access permissions

    This will be called for the access() and chdir() system calls. 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

    If this request is answered with an error code of ENOSYS, this is treated as a permanent success, i.e. this and all future access() requests will succeed without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    maskrequested access mode

    Definition at line 953 of file fuse_lowlevel.h.

    ◆ bmap

    void(* fuse_lowlevel_ops::bmap) (fuse_req_t req, fuse_ino_t ino, 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

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure, i.e. all future bmap() requests will fail with the same error code without being send to the filesystem process.

    Valid replies: fuse_reply_bmap fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    blocksizeunit of block index
    idxblock index within file

    Definition at line 1046 of file fuse_lowlevel.h.

    ◆ copy_file_range

    void(* fuse_lowlevel_ops::copy_file_range) (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)

    Copy a range of data from one file to another

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

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

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future copy_file_range() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_write fuse_reply_err

    Parameters
    reqrequest handle
    ino_inthe inode number or the source file
    off_instarting point from were the data should be read
    fi_infile information of the source file
    ino_outthe inode number or the destination file
    off_outstarting point where the data should be written
    fi_outfile information of the destination file
    lenmaximum size of the data to copy
    flagspassed along with the copy_file_range() syscall

    Definition at line 1281 of file fuse_lowlevel.h.

    ◆ create

    void(* fuse_lowlevel_ops::create) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)

    Create and open a file

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

    See the description of the open handler for more information.

    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.

    If this request is answered with an error code of ENOSYS, the handler is treated as not implemented (i.e., for this and future requests the mknod() and open() handlers will be called instead).

    Valid replies: fuse_reply_create fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    nameto create
    modefile type and mode with which to create the new file
    fifile information

    Definition at line 982 of file fuse_lowlevel.h.

    ◆ destroy

    void(* fuse_lowlevel_ops::destroy) (void *userdata)

    Clean up filesystem.

    Called on filesystem exit. When this method is called, the connection to the kernel may be gone already, so that eg. calls to fuse_lowlevel_notify_* will fail.

    There's no reply to this function

    Parameters
    userdatathe user data passed to fuse_session_new()

    Definition at line 238 of file fuse_lowlevel.h.

    ◆ fallocate

    void(* fuse_lowlevel_ops::fallocate) (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)

    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.

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future fallocate() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    offsetstarting point for allocated region
    lengthsize of allocated region
    modedetermines the operation to be performed on the given range, see fallocate(2)

    Definition at line 1220 of file fuse_lowlevel.h.

    ◆ flock

    void(* fuse_lowlevel_ops::flock) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)

    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.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information
    opthe locking operation, see flock(2)

    Definition at line 1197 of file fuse_lowlevel.h.

    ◆ flush

    void(* fuse_lowlevel_ops::flush) (fuse_req_t req, fuse_ino_t ino, 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 during close. However, such use is non-portable because POSIX does not require close to wait for delayed I/O to complete.

    If the filesystem supports file locking operations (setlk, getlk) it should remove all locks belonging to 'fi->owner'.

    If this request is answered with an error code of ENOSYS, this is treated as success and future calls to flush() will succeed automatically without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information

    Definition at line 654 of file fuse_lowlevel.h.

    ◆ forget

    void(* fuse_lowlevel_ops::forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)

    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, rmdir 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

    Parameters
    reqrequest handle
    inothe inode number
    nlookupthe number of lookups to forget

    Definition at line 289 of file fuse_lowlevel.h.

    ◆ forget_multi

    void(* fuse_lowlevel_ops::forget_multi) (fuse_req_t req, size_t count, struct fuse_forget_data *forgets)

    Forget about multiple inodes

    See description of the forget function for more information.

    Valid replies: fuse_reply_none

    Parameters
    reqrequest handle

    Definition at line 1179 of file fuse_lowlevel.h.

    ◆ fsync

    void(* fuse_lowlevel_ops::fsync) (fuse_req_t req, fuse_ino_t ino, int datasync, 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.

    If this request is answered with an error code of ENOSYS, this is treated as success and future calls to fsync() will succeed automatically without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    datasyncflag indicating if only data should be flushed
    fifile information

    Definition at line 704 of file fuse_lowlevel.h.

    ◆ fsyncdir

    void(* fuse_lowlevel_ops::fsyncdir) (fuse_req_t req, fuse_ino_t ino, int datasync, 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.

    If this request is answered with an error code of ENOSYS, this is treated as success and future calls to fsyncdir() will succeed automatically without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    datasyncflag indicating if only data should be flushed
    fifile information

    Definition at line 826 of file fuse_lowlevel.h.

    ◆ getattr

    void(* fuse_lowlevel_ops::getattr) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)

    Get file attributes.

    If writeback caching is enabled, the kernel may have a better idea of a file's length than the FUSE file system (eg if there has been a write that extended the file size, but that has not yet been passed to the filesystem.

    In this case, the st_size value provided by the file system will be ignored.

    Valid replies: fuse_reply_attr fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information, or NULL

    Definition at line 310 of file fuse_lowlevel.h.

    ◆ getlk

    void(* fuse_lowlevel_ops::getlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)

    Test for a POSIX file lock

    Valid replies: fuse_reply_lock fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information
    lockthe region/type to test

    Definition at line 997 of file fuse_lowlevel.h.

    ◆ getxattr

    void(* fuse_lowlevel_ops::getxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)

    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.

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future getxattr() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_buf fuse_reply_data fuse_reply_xattr fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    nameof the extended attribute
    sizemaximum size of the value to send

    Definition at line 883 of file fuse_lowlevel.h.

    ◆ init

    void(* fuse_lowlevel_ops::init) (void *userdata, struct fuse_conn_info *conn)

    Initialize filesystem

    This function is called when libfuse establishes communication with the FUSE kernel module. The file system should use this module to inspect and/or modify the connection parameters provided in the conn structure.

    Note that some parameters may be overwritten by options passed to fuse_session_new() which take precedence over the values set in this handler.

    There's no reply to this function

    Parameters
    userdatathe user data passed to fuse_session_new()

    Definition at line 225 of file fuse_lowlevel.h.

    ◆ ioctl

    void(* fuse_lowlevel_ops::ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)

    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.

    Valid replies: fuse_reply_ioctl_retry fuse_reply_ioctl fuse_reply_ioctl_iov fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    cmdioctl command
    argioctl argument
    fifile information
    flagsfor FUSE_IOCTL_* flags
    in_bufdata fetched from the caller
    in_bufsznumber of fetched bytes
    out_bufszmaximum size of output data

    Note : the unsigned long request submitted by the application is truncated to 32 bits.

    Definition at line 1082 of file fuse_lowlevel.h.

    ◆ link

    void(* fuse_lowlevel_ops::link) (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)

    Create a hard link

    Valid replies: fuse_reply_entry fuse_reply_err

    Parameters
    reqrequest handle
    inothe old inode number
    newparentinode number of the new parent directory
    newnamenew name to create

    Definition at line 490 of file fuse_lowlevel.h.

    ◆ listxattr

    void(* fuse_lowlevel_ops::listxattr) (fuse_req_t req, fuse_ino_t ino, 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.

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future listxattr() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_buf fuse_reply_data fuse_reply_xattr fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    sizemaximum size of the list to send

    Definition at line 914 of file fuse_lowlevel.h.

    ◆ lookup

    void(* fuse_lowlevel_ops::lookup) (fuse_req_t req, fuse_ino_t parent, const char *name)

    Look up a directory entry by name and get its attributes.

    Valid replies: fuse_reply_entry fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    namethe name to look up

    Definition at line 251 of file fuse_lowlevel.h.

    ◆ lseek

    void(* fuse_lowlevel_ops::lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)

    Find next data or hole after the specified offset

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure, i.e. all future lseek() requests will fail with the same error code without being send to the filesystem process.

    Valid replies: fuse_reply_lseek fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    offoffset to start search from
    whenceeither SEEK_DATA or SEEK_HOLE
    fifile information

    Definition at line 1305 of file fuse_lowlevel.h.

    ◆ mkdir

    void(* fuse_lowlevel_ops::mkdir) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)

    Create a directory

    Valid replies: fuse_reply_entry fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    nameto create
    modewith which to create the new file

    Definition at line 393 of file fuse_lowlevel.h.

    ◆ mknod

    void(* fuse_lowlevel_ops::mknod) (fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)

    Create file node

    Create a regular file, character device, block device, fifo or socket node.

    Valid replies: fuse_reply_entry fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    nameto create
    modefile type and mode with which to create the new file
    rdevthe device number (only valid if created file is a device)

    Definition at line 378 of file fuse_lowlevel.h.

    ◆ open

    void(* fuse_lowlevel_ops::open) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)

    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 and release will also succeed without being sent to the filesystem process.

    To get this behavior without providing an opendir handler, you may set FUSE_CAP_NO_OPEN_SUPPORT in fuse_conn_info.want on supported kernels to automatically get the zero message open().

    If this callback is not provided and FUSE_CAP_NO_OPEN_SUPPORT is not set in fuse_conn_info.want then an empty reply will be sent.

    Valid replies: fuse_reply_open fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information

    Definition at line 556 of file fuse_lowlevel.h.

    ◆ opendir

    void(* fuse_lowlevel_ops::opendir) (fuse_req_t req, fuse_ino_t ino, 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).

    If this request is answered with an error code of ENOSYS and FUSE_CAP_NO_OPENDIR_SUPPORT is set in fuse_conn_info.capable, this is treated as success and future calls to opendir and releasedir will also succeed without being sent to the filesystem process. In addition, the kernel will cache readdir results as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR.

    To get this behavior without providing an opendir handler, you may set FUSE_CAP_NO_OPENDIR_SUPPORT in fuse_conn_info.want on supported kernels to automatically get the zero message opendir().

    If this callback is not provided and FUSE_CAP_NO_OPENDIR_SUPPORT is not set in fuse_conn_info.want then an empty reply will be sent.

    Valid replies: fuse_reply_open fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information

    Definition at line 736 of file fuse_lowlevel.h.

    ◆ poll

    void(* fuse_lowlevel_ops::poll) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)

    Poll for IO readiness

    The client should immediately respond with fuse_reply_poll(), setting revents appropriately according to which events are ready.

    Additionally, if ph is non-NULL, the client must retain it and notify when all future IO readiness events occur by calling fuse_lowlevel_notify_poll() with the specified ph.

    Regardless of the number of times poll with a non-NULL ph is received, a single notify_poll is enough to service all. (Notifying more times incurs overhead but doesn't harm correctness.) Any additional received handles can be immediately destroyed.

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

    If this request is answered with an error code of ENOSYS, this is treated as success (with a kernel-defined default poll-mask) and future calls to poll() will succeed the same way without being send to the filesystem process.

    Valid replies: fuse_reply_poll fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information
    phpoll handle to be used for notification

    Definition at line 1119 of file fuse_lowlevel.h.

    ◆ read

    void(* fuse_lowlevel_ops::read) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, 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

    Parameters
    reqrequest handle
    inothe inode number
    sizenumber of bytes to read
    offoffset to read from
    fifile information

    Definition at line 584 of file fuse_lowlevel.h.

    ◆ readdir

    void(* fuse_lowlevel_ops::readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, 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.

    Returning a directory entry from readdir() does not affect its lookup count.

    If off_t is non-zero, then it will correspond to one of the off_t values that was previously returned by readdir() for the same directory handle. In this case, readdir() should skip over entries coming before the position defined by the off_t value. If entries are added or removed while the directory handle is open, the filesystem may still include the entries that have been removed, and may not report the entries that have been created. However, addition or removal of entries must never cause readdir() to skip over unrelated entries or to report them more than once. This means that off_t can not be a simple index that enumerates the entries that have been returned but must contain sufficient information to uniquely determine the next directory entry to return even when the set of entries is changing.

    The function does not have to report the '.' and '..' entries, but is allowed to do so. Note that, if readdir does not return '.' or '..', they will not be implicitly returned, and this behavior is observable by the caller.

    Valid replies: fuse_reply_buf fuse_reply_data fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    sizemaximum number of bytes to send
    offoffset to continue reading the directory stream
    fifile information

    Definition at line 782 of file fuse_lowlevel.h.

    ◆ readdirplus

    void(* fuse_lowlevel_ops::readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)

    Read directory with attributes

    Send a buffer filled using fuse_add_direntry_plus(), with size not exceeding the requested size. Send an empty buffer on end of stream.

    fi->fh will contain the value set by the opendir method, or will be undefined if the opendir method didn't set any value.

    In contrast to readdir() (which does not affect the lookup counts), the lookup count of every entry returned by readdirplus(), except "." and "..", is incremented by one.

    Valid replies: fuse_reply_buf fuse_reply_data fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    sizemaximum number of bytes to send
    offoffset to continue reading the directory stream
    fifile information

    Definition at line 1248 of file fuse_lowlevel.h.

    ◆ readlink

    void(* fuse_lowlevel_ops::readlink) (fuse_req_t req, fuse_ino_t ino)

    Read symbolic link

    Valid replies: fuse_reply_readlink fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number

    Definition at line 360 of file fuse_lowlevel.h.

    ◆ release

    void(* fuse_lowlevel_ops::release) (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 (unless the filesystem is force-unmounted).

    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

    Parameters
    reqrequest handle
    inothe inode number
    fifile information

    Definition at line 682 of file fuse_lowlevel.h.

    ◆ releasedir

    void(* fuse_lowlevel_ops::releasedir) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)

    Release an open directory

    For every opendir call there will be exactly one releasedir call (unless the filesystem is force-unmounted).

    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

    Parameters
    reqrequest handle
    inothe inode number
    fifile information

    Definition at line 801 of file fuse_lowlevel.h.

    ◆ removexattr

    void(* fuse_lowlevel_ops::removexattr) (fuse_req_t req, fuse_ino_t ino, const char *name)

    Remove an extended attribute

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future removexattr() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    nameof the extended attribute

    Definition at line 931 of file fuse_lowlevel.h.

    ◆ rename

    void(* fuse_lowlevel_ops::rename) (fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags)

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

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EINVAL, i.e. all future rename requests will fail with EINVAL without being send to the filesystem process.

    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.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the old parent directory
    nameold name
    newparentinode number of the new parent directory
    newnamenew name

    Definition at line 474 of file fuse_lowlevel.h.

    ◆ retrieve_reply

    void(* fuse_lowlevel_ops::retrieve_reply) (fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv)

    Callback function for the retrieve request

    Valid replies: fuse_reply_none

    Parameters
    reqrequest handle
    cookieuser data supplied to fuse_lowlevel_notify_retrieve()
    inothe inode number supplied to fuse_lowlevel_notify_retrieve()
    offsetthe offset supplied to fuse_lowlevel_notify_retrieve()
    bufvthe buffer containing the returned data

    Definition at line 1165 of file fuse_lowlevel.h.

    ◆ rmdir

    void(* fuse_lowlevel_ops::rmdir) (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

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    nameto remove

    Definition at line 428 of file fuse_lowlevel.h.

    ◆ setattr

    void(* fuse_lowlevel_ops::setattr) (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, 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.

    Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is expected to reset the setuid and setgid bits if the file size or owner is being changed.

    This method will not be called to update st_atime or st_ctime implicitly (eg. after a read() request), and only be called to implicitly update st_mtime if writeback caching is active. It is the filesystem's responsibility to update these timestamps when needed, and (if desired) to implement mount options like noatime or relatime.

    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

    Parameters
    reqrequest handle
    inothe inode number
    attrthe attributes
    to_setbit mask of attributes which should be set
    fifile information, or NULL

    Definition at line 347 of file fuse_lowlevel.h.

    ◆ setlk

    void(* fuse_lowlevel_ops::setlk) (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)

    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.

    Valid replies: fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    fifile information
    lockthe region/type to set
    sleeplocking operation may sleep

    Definition at line 1022 of file fuse_lowlevel.h.

    ◆ setxattr

    void(* fuse_lowlevel_ops::setxattr) (fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)

    Set an extended attribute

    If this request is answered with an error code of ENOSYS, this is treated as a permanent failure with error code EOPNOTSUPP, i.e. all future setxattr() requests will fail with EOPNOTSUPP without being send to the filesystem process.

    Valid replies: fuse_reply_err

    Definition at line 852 of file fuse_lowlevel.h.

    ◆ statfs

    void(* fuse_lowlevel_ops::statfs) (fuse_req_t req, fuse_ino_t ino)

    Get file system statistics

    Valid replies: fuse_reply_statfs fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number, zero means "undefined"

    Definition at line 839 of file fuse_lowlevel.h.

    ◆ statx

    void(* fuse_lowlevel_ops::statx) (fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)

    Get extended file attributes.

    Valid replies: fuse_reply_statx fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    flagsbitmask of requested flags
    maskbitmask of requested fields
    fifile information (may be NULL)

    Definition at line 1342 of file fuse_lowlevel.h.

    ◆ symlink

    void(* fuse_lowlevel_ops::symlink) (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)

    Create a symbolic link

    Valid replies: fuse_reply_entry fuse_reply_err

    Parameters
    reqrequest handle
    linkthe contents of the symbolic link
    parentinode number of the parent directory
    nameto create

    Definition at line 442 of file fuse_lowlevel.h.

    ◆ tmpfile

    void(* fuse_lowlevel_ops::tmpfile) (fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)

    Create a tempfile

    Tempfile means an anonymous file. It can be made into a normal file later by using linkat or such.

    If this is answered with an error ENOSYS this is treated by the kernel as a permanent failure and it will disable the feature and not ask again.

    Valid replies: fuse_reply_create fuse_reply_err

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    modefile type and mode with which to create the new file
    fifile information

    Definition at line 1326 of file fuse_lowlevel.h.

    ◆ unlink

    void(* fuse_lowlevel_ops::unlink) (fuse_req_t req, fuse_ino_t parent, const char *name)

    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

    Parameters
    reqrequest handle
    parentinode number of the parent directory
    nameto remove

    Definition at line 411 of file fuse_lowlevel.h.

    ◆ write

    void(* fuse_lowlevel_ops::write) (fuse_req_t req, fuse_ino_t ino, const char *buf, 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.

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

    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

    Parameters
    reqrequest handle
    inothe inode number
    bufdata to write
    sizenumber of bytes to write
    offoffset to write to
    fifile information

    Definition at line 613 of file fuse_lowlevel.h.

    ◆ write_buf

    void(* fuse_lowlevel_ops::write_buf) (fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv, off_t off, struct fuse_file_info *fi)

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

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

    Valid replies: fuse_reply_write fuse_reply_err

    Parameters
    reqrequest handle
    inothe inode number
    bufvbuffer containing the data
    offoffset to write to
    fifile information

    Definition at line 1149 of file fuse_lowlevel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__module.html0000644000175000017500000000522615250106404020032 0ustar berndbernd libfuse: fuse_module Struct Reference
    libfuse
    fuse_module Struct Reference

    #include <fuse_i.h>

    Detailed Description

    Filesystem module

    Filesystem modules are registered with the FUSE_REGISTER_MODULE() macro.

    Definition at line 135 of file fuse_i.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__operations.html0000644000175000017500000020215115250106404020724 0ustar berndbernd 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 *, unsigned 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)
    off_t(* lseek )(const char *, off_t off, int whence, struct fuse_file_info *)
    int(* statx )(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi)

    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 355 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 666 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 734 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 currently open, but may also be NULL if the file is open.

    Definition at line 423 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 currently 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 433 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, applications are expected to fall back to a regular file copy. (Some glibc versions did this emulation automatically, but the emulation has been removed from all glibc release branches.)

    Definition at line 849 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 678 of file fuse.h.

    ◆ destroy

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

    Clean up filesystem

    Called on filesystem exit.

    Definition at line 655 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 834 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 824 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, as opposed to release which is called on the close of the last file descriptor for a file. Under Linux, errors returned by flush() will be passed to userspace as errors from close(), so flush() is a good place to write back any cached dirty data. However, many applications ignore errors on close(), and on non-Linux systems, close() may succeed even if flush() returns an error. For these reasons, filesystems should not assume that errors returned by flush will ever be noticed or even delivered.

    NOTE: The flush() method may be called more than once for each open(). This happens if more than one file descriptor refers to an open file handle, e.g. 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 be called at any particular point. It may be called more times than expected, or not at all.

    Definition at line 552 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 573 of file fuse.h.

    ◆ fsyncdir

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

    Synchronize directory contents

    If the directory has been removed after the call to opendir, the path parameter will be NULL.

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

    Definition at line 637 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 367 of file fuse.h.

    ◆ getxattr

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

    Get extended attributes

    Definition at line 579 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 647 of file fuse.h.

    ◆ ioctl

    int(* fuse_operations::ioctl) (const char *, unsigned 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.

    Note : the unsigned long request submitted by the application is truncated to 32 bits.

    Definition at line 756 of file fuse.h.

    ◆ link

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

    Create a hard link to a file

    Definition at line 416 of file fuse.h.

    ◆ listxattr

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

    List extended attributes

    Definition at line 582 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 710 of file fuse.h.

    ◆ lseek

    off_t(* fuse_operations::lseek) (const char *, off_t off, int whence, struct fuse_file_info *)

    Find next data or hole after the specified offset

    Definition at line 858 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 393 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 385 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, O_EXEC, O_SEARCH) 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 sent to the filesystem process.

    Definition at line 492 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 595 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 775 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 503 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 804 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'.

    When FUSE_READDIR_PLUS is not set, only some parameters of the fill function (the fuse_fill_dir_t parameter) are actually used: The file type (which is part of stat::st_mode) is used. And if fuse_config::use_ino is set, the inode (stat::st_ino) is also used. The other fields are ignored when FUSE_READDIR_PLUS is not set.

    Definition at line 619 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 377 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 handle. 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 566 of file fuse.h.

    ◆ releasedir

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

    Release directory

    If the directory has been removed after the call to opendir, the path parameter will be NULL.

    Definition at line 627 of file fuse.h.

    ◆ removexattr

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

    Remove extended attributes

    Definition at line 585 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 413 of file fuse.h.

    ◆ rmdir

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

    Remove a directory

    Definition at line 399 of file fuse.h.

    ◆ setxattr

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

    Set extended attributes

    Definition at line 576 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 522 of file fuse.h.

    ◆ statx

    int(* fuse_operations::statx) (const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi)

    Get extended file attributes.

    fi may be NULL.

    If path is NULL, then the AT_EMPTY_PATH bit in flags will be already set.

    Definition at line 868 of file fuse.h.

    ◆ symlink

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

    Create a symbolic link

    Definition at line 402 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 currently 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 443 of file fuse.h.

    ◆ unlink

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

    Remove a file

    Definition at line 396 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 currently open, but may also be NULL if the file is open.

    See the utimensat(2) man page for details.

    Definition at line 725 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 515 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 787 of file fuse.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__opt.html0000644000175000017500000001705115250106404017346 0ustar berndbernd 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-3.18.3/doc/html/structfuse__ring__pool.html0000644000175000017500000000473115250106404020674 0ustar berndbernd libfuse: fuse_ring_pool Struct Reference
    libfuse
    fuse_ring_pool Struct Reference

    Detailed Description

    Main fuse_ring structure, holds all fuse-ring data

    Definition at line 72 of file fuse_uring.c.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__supp__groups.html0000644000175000017500000000533515250106404021273 0ustar berndbernd libfuse: fuse_supp_groups Struct Reference
    libfuse
    fuse_supp_groups Struct Reference

    #include <fuse_kernel.h>

    Detailed Description

    struct fuse_supp_groups - Supplementary group extension @nr_groups: number of supplementary groups @groups: flexible array of group IDs

    Definition at line 1235 of file fuse_kernel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__uring__cmd__req.html0000644000175000017500000000510615250106404021656 0ustar berndbernd libfuse: fuse_uring_cmd_req Struct Reference
    libfuse
    fuse_uring_cmd_req Struct Reference

    #include <fuse_kernel.h>

    Detailed Description

    In the 80B command area of the SQE.

    Definition at line 1292 of file fuse_kernel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structfuse__uring__req__header.html0000644000175000017500000000511615250106404022344 0ustar berndbernd libfuse: fuse_uring_req_header Struct Reference
    libfuse
    fuse_uring_req_header Struct Reference

    #include <fuse_kernel.h>

    Detailed Description

    Header for all fuse-io-uring requests

    Definition at line 1266 of file fuse_kernel.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/structlibfuse__version.html0000644000175000017500000000520315250106404020714 0ustar berndbernd libfuse: libfuse_version Struct Reference
    libfuse
    libfuse_version Struct Reference

    #include <fuse_common.h>

    Detailed Description

    libfuse version a file system was compiled with. Should be filled in from defines in 'libfuse_config.h'

    Definition at line 968 of file fuse_common.h.


    The documentation for this struct was generated from the following file:
    fuse-3.18.3/doc/html/dir_e68e8157741866f444e17edd764ebbae.html0000644000175000017500000000401115250106404021354 0ustar berndbernd libfuse: doc Directory Reference
    libfuse
    doc Directory Reference
    fuse-3.18.3/doc/html/dir_cfafba98a580ce4b62f8a6fa96d7cbb0.html0000644000175000017500000002125715250106404022003 0ustar berndbernd libfuse: example Directory Reference
    libfuse
    fuse-3.18.3/doc/html/dir_d44c64559bbebec7f509842c48db8b23.html0000644000175000017500000001125015250106404021422 0ustar berndbernd libfuse: include Directory Reference
    libfuse
    include Directory Reference

    Files

     
    cuse_lowlevel.h
     
    fuse.h
     
    fuse_common.h
     
    fuse_kernel.h
     
    fuse_log.h
     
    fuse_lowlevel.h
     
    fuse_mount_compat.h
     
    fuse_opt.h
    fuse-3.18.3/doc/html/dir_97aefd0d527b934f1d99a682da8fe6a9.html0000644000175000017500000002134415250106404021525 0ustar berndbernd libfuse: lib Directory Reference
    libfuse
    lib Directory Reference

    Directories

     
    modules

    Files

     
    buffer.c
     
    compat.c
     
    cuse_lowlevel.c
     
    fuse.c
     
    fuse_i.h
     
    fuse_log.c
     
    fuse_loop.c
     
    fuse_loop_mt.c
     
    fuse_lowlevel.c
     
    fuse_misc.h
     
    fuse_opt.c
     
    fuse_signals.c
     
    fuse_uring.c
     
    fuse_uring_i.h
     
    helper.c
     
    mount.c
     
    mount_bsd.c
     
    mount_util.c
     
    mount_util.h
     
    usdt.h
     
    util.c
     
    util.h
    fuse-3.18.3/doc/html/dir_e1dbc8ba94a86723d4c32227b7c46099.html0000644000175000017500000000537615250106404021267 0ustar berndbernd libfuse: lib/modules Directory Reference
    libfuse
    modules Directory Reference

    Files

     
    iconv.c
     
    subdir.c
    fuse-3.18.3/doc/html/dir_13e138d54eb8818da29c3992edef070a.html0000644000175000017500000001276215250106404021347 0ustar berndbernd libfuse: test Directory Reference
    libfuse
    test Directory Reference

    Files

     
    hello.c
     
    readdir_inode.c
     
    stracedecode.c
     
    test_abi.c
     
    test_api_30.c
     
    test_setattr.c
     
    test_signals.c
     
    test_syscalls.c
     
    test_want_conversion.c
     
    test_write_cache.c
    fuse-3.18.3/doc/html/dir_23ec12649285f9fabf3a6b7380226c28.html0000644000175000017500000000536715250106404021207 0ustar berndbernd libfuse: util Directory Reference
    libfuse
    util Directory Reference

    Files

     
    fusermount.c
     
    mount.fuse.c
    fuse-3.18.3/doc/html/menudata.js0000644000175000017500000000762415250106404015371 0ustar berndbernd/* @licstart The following is the entire license notice for the JavaScript code in this file. The MIT License (MIT) Copyright (C) 1997-2020 by Dimitri van Heesch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @licend The above is the entire license notice for the JavaScript code in this file */ var menudata={children:[ {text:"Main Page",url:"index.html"}, {text:"Data Structures",url:"annotated.html",children:[ {text:"Data Structures",url:"annotated.html"}, {text:"Data Fields",url:"functions.html",children:[ {text:"All",url:"functions.html",children:[ {text:"a",url:"functions.html#index_a"}, {text:"b",url:"functions.html#index_b"}, {text:"c",url:"functions.html#index_c"}, {text:"d",url:"functions.html#index_d"}, {text:"e",url:"functions.html#index_e"}, {text:"f",url:"functions.html#index_f"}, {text:"g",url:"functions.html#index_g"}, {text:"h",url:"functions.html#index_h"}, {text:"i",url:"functions.html#index_i"}, {text:"k",url:"functions.html#index_k"}, {text:"l",url:"functions.html#index_l"}, {text:"m",url:"functions.html#index_m"}, {text:"n",url:"functions.html#index_n"}, {text:"o",url:"functions.html#index_o"}, {text:"p",url:"functions.html#index_p"}, {text:"r",url:"functions.html#index_r"}, {text:"s",url:"functions.html#index_s"}, {text:"t",url:"functions.html#index_t"}, {text:"u",url:"functions.html#index_u"}, {text:"v",url:"functions.html#index_v"}, {text:"w",url:"functions.html#index_w"}]}, {text:"Variables",url:"functions_vars.html",children:[ {text:"a",url:"functions_vars.html#index_a"}, {text:"b",url:"functions_vars.html#index_b"}, {text:"c",url:"functions_vars.html#index_c"}, {text:"d",url:"functions_vars.html#index_d"}, {text:"e",url:"functions_vars.html#index_e"}, {text:"f",url:"functions_vars.html#index_f"}, {text:"g",url:"functions_vars.html#index_g"}, {text:"h",url:"functions_vars.html#index_h"}, {text:"i",url:"functions_vars.html#index_i"}, {text:"k",url:"functions_vars.html#index_k"}, {text:"l",url:"functions_vars.html#index_l"}, {text:"m",url:"functions_vars.html#index_m"}, {text:"n",url:"functions_vars.html#index_n"}, {text:"o",url:"functions_vars.html#index_o"}, {text:"p",url:"functions_vars.html#index_p"}, {text:"r",url:"functions_vars.html#index_r"}, {text:"s",url:"functions_vars.html#index_s"}, {text:"t",url:"functions_vars.html#index_t"}, {text:"u",url:"functions_vars.html#index_u"}, {text:"v",url:"functions_vars.html#index_v"}, {text:"w",url:"functions_vars.html#index_w"}]}]}]}, {text:"Files",url:"files.html",children:[ {text:"File List",url:"files.html"}, {text:"Globals",url:"globals.html",children:[ {text:"All",url:"globals.html",children:[ {text:"f",url:"globals.html#index_f"}]}, {text:"Functions",url:"globals_func.html",children:[ {text:"f",url:"globals_func.html#index_f"}]}, {text:"Typedefs",url:"globals_type.html"}, {text:"Enumerations",url:"globals_enum.html"}, {text:"Enumerator",url:"globals_eval.html"}, {text:"Macros",url:"globals_defs.html",children:[ {text:"f",url:"globals_defs.html#index_f"}]}]}]}]} fuse-3.18.3/doc/html/index.html0000644000175000017500000001071215250106404015222 0ustar berndbernd libfuse: libfuse API documentation
    libfuse
    libfuse API documentation

    FUSE (Filesystem in Userspace) is an interface for userspace programs to export a filesystem to the Linux kernel. The FUSE project consists of two components: the fuse kernel module (maintained in the regular kernel repositories) and the libfuse userspace library. libfuse provides the reference implementation for communicating with the FUSE kernel module.

    A FUSE file system is typically implemented as a standalone application that links with libfuse. libfuse provides functions to mount the file system, unmount it, read requests from the kernel, and send responses back.

    Getting started

    libfuse offers two APIs: a "high-level", synchronous API, and a "low-level" asynchronous API. In both cases, incoming requests from the kernel are passed to the main program using callbacks. When using the high-level API, the callbacks may work with file names and paths instead of inodes, and processing of a request finishes when the callback function returns. When using the low-level API, the callbacks must work with inodes and responses must be sent explicitly using a separate set of API functions.

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

    Examples

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

    FUSE internals

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

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

    fuse-3.18.3/doc/html/annotated.html0000644000175000017500000001731715250106404016100 0ustar berndbernd libfuse: Data Structures
    libfuse
    fuse-3.18.3/doc/html/classes.html0000644000175000017500000000745315250106404015560 0ustar berndbernd libfuse: Data Structure Index
    libfuse
    fuse-3.18.3/doc/html/functions.html0000644000175000017500000006146115250106404016132 0ustar berndbernd libfuse: Data Fields
    libfuse
    Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:

    - a -

    - b -

    - c -

    - d -

    - e -

    - f -

    - g -

    - h -

    - i -

    - k -

    - l -

    - m -

    - n -

    - o -

    - p -

    - r -

    - s -

    - t -

    - u -

    - v -

    - w -

    fuse-3.18.3/doc/html/functions_vars.html0000644000175000017500000006145715250106404017172 0ustar berndbernd libfuse: Data Fields - Variables
    libfuse
    Here is a list of all documented variables with links to the struct/union documentation for each field:

    - a -

    - b -

    - c -

    - d -

    - e -

    - f -

    - g -

    - h -

    - i -

    - k -

    - l -

    - m -

    - n -

    - o -

    - p -

    - r -

    - s -

    - t -

    - u -

    - v -

    - w -

    fuse-3.18.3/doc/html/files.html0000644000175000017500000005541315250106404015224 0ustar berndbernd libfuse: File List
    libfuse
    File List
    Here is a list of all documented files with brief descriptions:
    [detail level 123]
     
    example
     
    cuse.c
     
    cuse_client.c
     
    hello.c
     
    hello_ll.c
     
    hello_ll_uds.c
     
    invalidate_path.c
     
    ioctl.c
     
    ioctl.h
     
    ioctl_client.c
     
    notify_inval_entry.c
     
    notify_inval_inode.c
     
    notify_store_retrieve.c
     
    null.c
     
    passthrough.c
     
    passthrough_fh.c
     
    passthrough_helpers.h
     
    passthrough_ll.c
     
    poll.c
     
    poll_client.c
     
    printcap.c
     
    include
     
    cuse_lowlevel.h
     
    fuse.h
     
    fuse_common.h
     
    fuse_kernel.h
     
    fuse_log.h
     
    fuse_lowlevel.h
     
    fuse_mount_compat.h
     
    fuse_opt.h
     
    lib
     
    modules
     
    iconv.c
     
    subdir.c
     
    buffer.c
     
    compat.c
     
    cuse_lowlevel.c
     
    fuse.c
     
    fuse_i.h
     
    fuse_log.c
     
    fuse_loop.c
     
    fuse_loop_mt.c
     
    fuse_lowlevel.c
     
    fuse_misc.h
     
    fuse_opt.c
     
    fuse_signals.c
     
    fuse_uring.c
     
    fuse_uring_i.h
     
    helper.c
     
    mount.c
     
    mount_bsd.c
     
    mount_util.c
     
    mount_util.h
     
    usdt.h
     
    util.c
     
    util.h
     
    test
     
    hello.c
     
    readdir_inode.c
     
    release_unlink_race.c
     
    stracedecode.c
     
    test_abi.c
     
    test_api_30.c
     
    test_setattr.c
     
    test_signals.c
     
    test_syscalls.c
     
    test_want_conversion.c
     
    test_write_cache.c
     
    util
     
    fusermount.c
     
    mount.fuse.c
    fuse-3.18.3/doc/html/globals.html0000644000175000017500000005612115250106404015542 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented functions, variables, defines, enums, and typedefs with links to the documentation:

    - f -

    fuse-3.18.3/doc/html/globals_func.html0000644000175000017500000003526615250106404016564 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented functions with links to the documentation:

    - f -

    fuse-3.18.3/doc/html/globals_type.html0000644000175000017500000000541415250106404016602 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented typedefs with links to the documentation:
    fuse-3.18.3/doc/html/globals_enum.html0000644000175000017500000000522315250106404016563 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented enums with links to the documentation:
    fuse-3.18.3/doc/html/globals_eval.html0000644000175000017500000000654215250106404016553 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented enum values with links to the documentation:
    fuse-3.18.3/doc/html/globals_defs.html0000644000175000017500000001640115250106404016540 0ustar berndbernd libfuse: Globals
    libfuse
    Here is a list of all documented macros with links to the documentation:

    - f -

    fuse-3.18.3/example/0000755000175000017500000000000015250106404013146 5ustar berndberndfuse-3.18.3/example/README.compile0000644000175000017500000000025215250106036015455 0ustar berndberndNote: * If the pkg-config command fails due to the absence of the fuse3.pc file, you should configure the path to the fuse3.pc file in the PKG_CONFIG_PATH variable.fuse-3.18.3/example/cuse.c0000644000175000017500000001665315250106036014265 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * 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 ## * \include cuse.c */ #define FUSE_USE_VERSION 31 #include #include #include #include #include #include #include #include #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_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } 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), 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 = { .init = cusexmp_init, .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; int ret = 1; if (fuse_opt_parse(&args, ¶m, cusexmp_opts, cusexmp_process_arg)) { printf("failed to parse option\n"); free(param.dev_name); goto out; } if (!param.is_help) { if (!param.dev_name) { fprintf(stderr, "Error: device name missing\n"); goto out; } strncat(dev_name, param.dev_name, sizeof(dev_name) - sizeof("DEVNAME=")); free(param.dev_name); } 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; ret = cuse_lowlevel_main(args.argc, args.argv, &ci, &cusexmp_clop, NULL); out: fuse_opt_free_args(&args); return ret; } fuse-3.18.3/example/cuse_client.c0000644000175000017500000000642315250106036015615 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * This program tests the cuse.c example file system. * * Example usage (assuming that /dev/foobar is a CUSE device provided * by the cuse.c example file system): * * $ cuse_client /dev/foobar s * 0 * * $ echo "hello" | cuse_client /dev/foobar w 6 * Writing 6 bytes * transferred 6 bytes (0 -> 6) * * $ cuse_client /dev/foobar s * 6 * * $ cuse_client /dev/foobar r 10 * hello * transferred 6 bytes (6 -> 6) * * Compiling this example * * gcc -Wall cuse_client.c -o cuse_client * * ## Source Code ## * \include cuse_client.c */ #include #include #include #include #include #include #include #include #include #include "ioctl.h" /* keeps a mistyped SIZE from asking for the machine's memory */ #define MAX_XFER_SIZE (16 * 1024 * 1024) const char *usage = "Usage: cuse_client FIOC_FILE COMMAND\n" "\n" "COMMANDS\n" " s [SIZE] : get size if SIZE is omitted, set size otherwise\n" " r SIZE [OFF] : read SIZE bytes @ OFF (dfl 0) and output to stdout\n" " w SIZE [OFF] : write SIZE bytes @ OFF (dfl 0) from stdin\n" "\n"; static int do_rw(int fd, int is_read, size_t size, off_t offset, size_t *prev_size, size_t *new_size) { struct fioc_rw_arg arg = { .offset = offset }; ssize_t ret; if (size > MAX_XFER_SIZE) { fprintf(stderr, "size %zu exceeds limit of %d bytes\n", size, MAX_XFER_SIZE); return -1; } 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"); goto error; } printf("%zu\n", size); } else { size = param[0]; if (ioctl(fd, FIOC_SET_SIZE, &size)) { perror("ioctl"); goto error; } } close(fd); return 0; case 'r': case 'w': rc = do_rw(fd, cmd == 'r', param[0], param[1], &prev_size, &new_size); if (rc < 0) goto error; fprintf(stderr, "transferred %d bytes (%zu -> %zu)\n", rc, prev_size, new_size); close(fd); return 0; } usage: fprintf(stderr, "%s", usage); return 1; error: close(fd); return 1; } fuse-3.18.3/example/cxxopts.hpp0000644000175000017500000012322315250106036015373 0ustar berndbernd/* Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef CXXOPTS_HPP_INCLUDED #define CXXOPTS_HPP_INCLUDED #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cpp_lib_optional #include #define CXXOPTS_HAS_OPTIONAL #endif #ifndef CXXOPTS_VECTOR_DELIMITER #define CXXOPTS_VECTOR_DELIMITER ',' #endif #define CXXOPTS__VERSION_MAJOR 2 #define CXXOPTS__VERSION_MINOR 2 #define CXXOPTS__VERSION_PATCH 1 namespace cxxopts { static constexpr struct { uint8_t major, minor, patch; } version = { CXXOPTS__VERSION_MAJOR, CXXOPTS__VERSION_MINOR, CXXOPTS__VERSION_PATCH }; } //when we ask cxxopts to use Unicode, help strings are processed using ICU, //which results in the correct lengths being computed for strings when they //are formatted for the help output //it is necessary to make sure that can be found by the //compiler, and that icu-uc is linked in to the binary. #ifdef CXXOPTS_USE_UNICODE #include namespace cxxopts { typedef icu::UnicodeString String; inline String toLocalString(std::string s) { return icu::UnicodeString::fromUTF8(std::move(s)); } class UnicodeStringIterator : public std::iterator { public: UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) : s(string) , i(pos) { } value_type operator*() const { return s->char32At(i); } bool operator==(const UnicodeStringIterator& rhs) const { return s == rhs.s && i == rhs.i; } bool operator!=(const UnicodeStringIterator& rhs) const { return !(*this == rhs); } UnicodeStringIterator& operator++() { ++i; return *this; } UnicodeStringIterator operator+(int32_t v) { return UnicodeStringIterator(s, i + v); } private: const icu::UnicodeString* s; int32_t i; }; inline String& stringAppend(String&s, String a) { return s.append(std::move(a)); } inline String& stringAppend(String& s, int n, UChar32 c) { for (int i = 0; i != n; ++i) { s.append(c); } return s; } template String& stringAppend(String& s, Iterator begin, Iterator end) { while (begin != end) { s.append(*begin); ++begin; } return s; } inline size_t stringLength(const String& s) { return s.length(); } inline std::string toUTF8String(const String& s) { std::string result; s.toUTF8String(result); return result; } inline bool empty(const String& s) { return s.isEmpty(); } } namespace std { inline cxxopts::UnicodeStringIterator begin(const icu::UnicodeString& s) { return cxxopts::UnicodeStringIterator(&s, 0); } inline cxxopts::UnicodeStringIterator end(const icu::UnicodeString& s) { return cxxopts::UnicodeStringIterator(&s, s.length()); } } //ifdef CXXOPTS_USE_UNICODE #else namespace cxxopts { typedef std::string String; template T toLocalString(T&& t) { return std::forward(t); } inline size_t stringLength(const String& s) { return s.length(); } inline String& stringAppend(String&s, String a) { return s.append(std::move(a)); } inline String& stringAppend(String& s, size_t n, char c) { return s.append(n, c); } template String& stringAppend(String& s, Iterator begin, Iterator end) { return s.append(begin, end); } template std::string toUTF8String(T&& t) { return std::forward(t); } inline bool empty(const std::string& s) { return s.empty(); } } //ifdef CXXOPTS_USE_UNICODE #endif namespace cxxopts { namespace { #ifdef _WIN32 const std::string LQUOTE("\'"); const std::string RQUOTE("\'"); #else const std::string LQUOTE("‘"); const std::string RQUOTE("’"); #endif } class Value : public std::enable_shared_from_this { public: virtual ~Value() = default; virtual std::shared_ptr clone() const = 0; virtual void parse(const std::string& text) const = 0; virtual void parse() const = 0; virtual bool has_default() const = 0; virtual bool is_container() const = 0; virtual bool has_implicit() const = 0; virtual std::string get_default_value() const = 0; virtual std::string get_implicit_value() const = 0; virtual std::shared_ptr default_value(const std::string& value) = 0; virtual std::shared_ptr implicit_value(const std::string& value) = 0; virtual std::shared_ptr no_implicit_value() = 0; virtual bool is_boolean() const = 0; }; class OptionException : public std::exception { public: OptionException(const std::string& message) : m_message(message) { } virtual const char* what() const noexcept { return m_message.c_str(); } private: std::string m_message; }; class OptionSpecException : public OptionException { public: OptionSpecException(const std::string& message) : OptionException(message) { } }; class OptionParseException : public OptionException { public: OptionParseException(const std::string& message) : OptionException(message) { } }; class option_exists_error : public OptionSpecException { public: option_exists_error(const std::string& option) : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") { } }; class invalid_option_format_error : public OptionSpecException { public: invalid_option_format_error(const std::string& format) : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) { } }; class option_syntax_exception : public OptionParseException { public: option_syntax_exception(const std::string& text) : OptionParseException("Argument " + LQUOTE + text + RQUOTE + " starts with a - but has incorrect syntax") { } }; class option_not_exists_exception : public OptionParseException { public: option_not_exists_exception(const std::string& option) : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") { } }; class missing_argument_exception : public OptionParseException { public: missing_argument_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " is missing an argument" ) { } }; class option_requires_argument_exception : public OptionParseException { public: option_requires_argument_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " requires an argument" ) { } }; class option_not_has_argument_exception : public OptionParseException { public: option_not_has_argument_exception ( const std::string& option, const std::string& arg ) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " does not take an argument, but argument " + LQUOTE + arg + RQUOTE + " given" ) { } }; class option_not_present_exception : public OptionParseException { public: option_not_present_exception(const std::string& option) : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") { } }; class argument_incorrect_type : public OptionParseException { public: argument_incorrect_type ( const std::string& arg ) : OptionParseException( "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" ) { } }; class option_required_exception : public OptionParseException { public: option_required_exception(const std::string& option) : OptionParseException( "Option " + LQUOTE + option + RQUOTE + " is required but not present" ) { } }; namespace values { namespace { std::basic_regex integer_pattern ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); std::basic_regex truthy_pattern ("(t|T)(rue)?|1"); std::basic_regex falsy_pattern ("(f|F)(alse)?|0"); } namespace detail { template struct SignedCheck; template struct SignedCheck { template void operator()(bool negative, U u, const std::string& text) { if (negative) { if (u > static_cast((std::numeric_limits::min)())) { throw argument_incorrect_type(text); } } else { if (u > static_cast((std::numeric_limits::max)())) { throw argument_incorrect_type(text); } } } }; template struct SignedCheck { template void operator()(bool, U, const std::string&) {} }; template void check_signed_range(bool negative, U value, const std::string& text) { SignedCheck::is_signed>()(negative, value, text); } } template R checked_negate(T&& t, const std::string&, std::true_type) { // if we got to here, then `t` is a positive number that fits into // `R`. So to avoid MSVC C4146, we first cast it to `R`. // See https://github.com/jarro2783/cxxopts/issues/62 for more details. return -static_cast(t-1)-1; } template T checked_negate(T&&, const std::string& text, std::false_type) { throw argument_incorrect_type(text); } template void integer_parser(const std::string& text, T& value) { std::smatch match; std::regex_match(text, match, integer_pattern); if (match.length() == 0) { throw argument_incorrect_type(text); } if (match.length(4) > 0) { value = 0; return; } using US = typename std::make_unsigned::type; constexpr bool is_signed = std::numeric_limits::is_signed; const bool negative = match.length(1) > 0; const uint8_t base = match.length(2) > 0 ? 16 : 10; auto value_match = match[3]; US result = 0; for (auto iter = value_match.first; iter != value_match.second; ++iter) { US digit = 0; if (*iter >= '0' && *iter <= '9') { digit = static_cast(*iter - '0'); } else if (base == 16 && *iter >= 'a' && *iter <= 'f') { digit = static_cast(*iter - 'a' + 10); } else if (base == 16 && *iter >= 'A' && *iter <= 'F') { digit = static_cast(*iter - 'A' + 10); } else { throw argument_incorrect_type(text); } US next = result * base + digit; if (result > next) { throw argument_incorrect_type(text); } result = next; } detail::check_signed_range(negative, result, text); if (negative) { value = checked_negate(result, text, std::integral_constant()); } else { value = static_cast(result); } } template void stringstream_parser(const std::string& text, T& value) { std::stringstream in(text); in >> value; if (!in) { throw argument_incorrect_type(text); } } inline void parse_value(const std::string& text, uint8_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, int8_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, uint16_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, int16_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, uint32_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, int32_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, uint64_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, int64_t& value) { integer_parser(text, value); } inline void parse_value(const std::string& text, bool& value) { std::smatch result; std::regex_match(text, result, truthy_pattern); if (!result.empty()) { value = true; return; } std::regex_match(text, result, falsy_pattern); if (!result.empty()) { value = false; return; } throw argument_incorrect_type(text); } inline void parse_value(const std::string& text, std::string& value) { value = text; } // The fallback parser. It uses the stringstream parser to parse all types // that have not been overloaded explicitly. It has to be placed in the // source code before all other more specialized templates. template void parse_value(const std::string& text, T& value) { stringstream_parser(text, value); } template void parse_value(const std::string& text, std::vector& value) { std::stringstream in(text); std::string token; while(in.eof() == false && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { T v; parse_value(token, v); value.emplace_back(std::move(v)); } } #ifdef CXXOPTS_HAS_OPTIONAL template void parse_value(const std::string& text, std::optional& value) { T result; parse_value(text, result); value = std::move(result); } #endif template struct type_is_container { static constexpr bool value = false; }; template struct type_is_container> { static constexpr bool value = true; }; template class abstract_value : public Value { using Self = abstract_value; public: abstract_value() : m_result(std::make_shared()) , m_store(m_result.get()) { } abstract_value(T* t) : m_store(t) { } virtual ~abstract_value() = default; abstract_value(const abstract_value& rhs) { if (rhs.m_result) { m_result = std::make_shared(); m_store = m_result.get(); } else { m_store = rhs.m_store; } m_default = rhs.m_default; m_implicit = rhs.m_implicit; m_default_value = rhs.m_default_value; m_implicit_value = rhs.m_implicit_value; } void parse(const std::string& text) const { parse_value(text, *m_store); } bool is_container() const { return type_is_container::value; } void parse() const { parse_value(m_default_value, *m_store); } bool has_default() const { return m_default; } bool has_implicit() const { return m_implicit; } std::shared_ptr default_value(const std::string& value) { m_default = true; m_default_value = value; return shared_from_this(); } std::shared_ptr implicit_value(const std::string& value) { m_implicit = true; m_implicit_value = value; return shared_from_this(); } std::shared_ptr no_implicit_value() { m_implicit = false; return shared_from_this(); } std::string get_default_value() const { return m_default_value; } std::string get_implicit_value() const { return m_implicit_value; } bool is_boolean() const { return std::is_same::value; } const T& get() const { if (m_store == nullptr) { return *m_result; } else { return *m_store; } } protected: std::shared_ptr m_result; T* m_store; bool m_default = false; bool m_implicit = false; std::string m_default_value; std::string m_implicit_value; }; template class standard_value : public abstract_value { public: using abstract_value::abstract_value; std::shared_ptr clone() const { return std::make_shared>(*this); } }; template <> class standard_value : public abstract_value { public: ~standard_value() = default; standard_value() { set_default_and_implicit(); } standard_value(bool* b) : abstract_value(b) { set_default_and_implicit(); } std::shared_ptr clone() const { return std::make_shared>(*this); } private: void set_default_and_implicit() { m_default = true; m_default_value = "false"; m_implicit = true; m_implicit_value = "true"; } }; } template std::shared_ptr value() { return std::make_shared>(); } template std::shared_ptr value(T& t) { return std::make_shared>(&t); } class OptionAdder; class OptionDetails { public: OptionDetails ( const std::string& short_, const std::string& long_, const String& desc, std::shared_ptr val ) : m_short(short_) , m_long(long_) , m_desc(desc) , m_value(val) , m_count(0) { } OptionDetails(const OptionDetails& rhs) : m_desc(rhs.m_desc) , m_count(rhs.m_count) { m_value = rhs.m_value->clone(); } OptionDetails(OptionDetails&& rhs) = default; const String& description() const { return m_desc; } const Value& value() const { return *m_value; } std::shared_ptr make_storage() const { return m_value->clone(); } const std::string& short_name() const { return m_short; } const std::string& long_name() const { return m_long; } private: std::string m_short; std::string m_long; String m_desc; std::shared_ptr m_value; int m_count; }; struct HelpOptionDetails { std::string s; std::string l; String desc; bool has_default; std::string default_value; bool has_implicit; std::string implicit_value; std::string arg_help; bool is_container; bool is_boolean; }; struct HelpGroupDetails { std::string name; std::string description; std::vector options; }; class OptionValue { public: void parse ( std::shared_ptr details, const std::string& text ) { ensure_value(details); ++m_count; m_value->parse(text); } void parse_default(std::shared_ptr details) { ensure_value(details); m_default = true; m_value->parse(); } size_t count() const noexcept { return m_count; } // TODO: maybe default options should count towards the number of arguments bool has_default() const noexcept { return m_default; } template const T& as() const { if (m_value == nullptr) { throw std::domain_error("No value"); } #ifdef CXXOPTS_NO_RTTI return static_cast&>(*m_value).get(); #else return dynamic_cast&>(*m_value).get(); #endif } private: void ensure_value(std::shared_ptr details) { if (m_value == nullptr) { m_value = details->make_storage(); } } std::shared_ptr m_value; size_t m_count = 0; bool m_default = false; }; class KeyValue { public: KeyValue(std::string key_, std::string value_) : m_key(std::move(key_)) , m_value(std::move(value_)) { } const std::string& key() const { return m_key; } const std::string& value() const { return m_value; } template T as() const { T result; values::parse_value(m_value, result); return result; } private: std::string m_key; std::string m_value; }; class ParseResult { public: ParseResult( const std::shared_ptr< std::unordered_map> >, std::vector, bool allow_unrecognised, int&, char**&); size_t count(const std::string& o) const { auto iter = m_options->find(o); if (iter == m_options->end()) { return 0; } auto riter = m_results.find(iter->second); return riter->second.count(); } const OptionValue& operator[](const std::string& option) const { auto iter = m_options->find(option); if (iter == m_options->end()) { throw option_not_present_exception(option); } auto riter = m_results.find(iter->second); return riter->second; } const std::vector& arguments() const { return m_sequential; } private: void parse(int& argc, char**& argv); void add_to_option(const std::string& option, const std::string& arg); bool consume_positional(std::string a); void parse_option ( std::shared_ptr value, const std::string& name, const std::string& arg = "" ); void parse_default(std::shared_ptr details); void checked_parse_arg ( int argc, char* argv[], int& current, std::shared_ptr value, const std::string& name ); const std::shared_ptr< std::unordered_map> > m_options; std::vector m_positional; std::vector::iterator m_next_positional; std::unordered_set m_positional_set; std::unordered_map, OptionValue> m_results; bool m_allow_unrecognised; std::vector m_sequential; }; class Options { typedef std::unordered_map> OptionMap; public: Options(std::string program, std::string help_string = "") : m_program(std::move(program)) , m_help_string(toLocalString(std::move(help_string))) , m_custom_help("[OPTION...]") , m_positional_help("positional parameters") , m_show_positional(false) , m_allow_unrecognised(false) , m_options(std::make_shared()) , m_next_positional(m_positional.end()) { } Options& positional_help(std::string help_text) { m_positional_help = std::move(help_text); return *this; } Options& custom_help(std::string help_text) { m_custom_help = std::move(help_text); return *this; } Options& show_positional_help() { m_show_positional = true; return *this; } Options& allow_unrecognised_options() { m_allow_unrecognised = true; return *this; } ParseResult parse(int& argc, char**& argv); OptionAdder add_options(std::string group = ""); void add_option ( const std::string& group, const std::string& s, const std::string& l, std::string desc, std::shared_ptr value, std::string arg_help ); //parse positional arguments into the given option void parse_positional(std::string option); void parse_positional(std::vector options); void parse_positional(std::initializer_list options); template void parse_positional(Iterator begin, Iterator end) { parse_positional(std::vector{begin, end}); } std::string help(const std::vector& groups = {}) const; const std::vector groups() const; const HelpGroupDetails& group_help(const std::string& group) const; private: void add_one_option ( const std::string& option, std::shared_ptr details ); String help_one_group(const std::string& group) const; void generate_group_help ( String& result, const std::vector& groups ) const; void generate_all_groups_help(String& result) const; std::string m_program; String m_help_string; std::string m_custom_help; std::string m_positional_help; bool m_show_positional; bool m_allow_unrecognised; std::shared_ptr m_options; std::vector m_positional; std::vector::iterator m_next_positional; std::unordered_set m_positional_set; //mapping from groups to help options std::map m_help; }; class OptionAdder { public: OptionAdder(Options& options, std::string group) : m_options(options), m_group(std::move(group)) { } OptionAdder& operator() ( const std::string& opts, const std::string& desc, std::shared_ptr value = ::cxxopts::value(), std::string arg_help = "" ); private: Options& m_options; std::string m_group; }; namespace { constexpr int OPTION_LONGEST = 30; constexpr int OPTION_DESC_GAP = 2; std::basic_regex option_matcher ("--([[:alnum:]][-_[:alnum:]]+)(=(.*))?|-([[:alnum:]]+)"); std::basic_regex option_specifier ("(([[:alnum:]]),)?[ ]*([[:alnum:]][-_[:alnum:]]*)?"); String format_option ( const HelpOptionDetails& o ) { auto& s = o.s; auto& l = o.l; String result = " "; if (s.size() > 0) { result += "-" + toLocalString(s) + ","; } else { result += " "; } if (l.size() > 0) { result += " --" + toLocalString(l); } auto arg = o.arg_help.size() > 0 ? toLocalString(o.arg_help) : "arg"; if (!o.is_boolean) { if (o.has_implicit) { result += " [=" + arg + "(=" + toLocalString(o.implicit_value) + ")]"; } else { result += " " + arg; } } return result; } String format_description ( const HelpOptionDetails& o, size_t start, size_t width ) { auto desc = o.desc; if (o.has_default && (!o.is_boolean || o.default_value != "false")) { desc += toLocalString(" (default: " + o.default_value + ")"); } String result; auto current = std::begin(desc); auto startLine = current; auto lastSpace = current; auto size = size_t{}; while (current != std::end(desc)) { if (*current == ' ') { lastSpace = current; } if (*current == '\n') { startLine = current + 1; lastSpace = startLine; } else if (size > width) { if (lastSpace == startLine) { stringAppend(result, startLine, current + 1); stringAppend(result, "\n"); stringAppend(result, start, ' '); startLine = current + 1; lastSpace = startLine; } else { stringAppend(result, startLine, lastSpace); stringAppend(result, "\n"); stringAppend(result, start, ' '); startLine = lastSpace + 1; lastSpace = startLine; } size = 0; } else { ++size; } ++current; } //append whatever is left stringAppend(result, startLine, current); return result; } } inline ParseResult::ParseResult ( const std::shared_ptr< std::unordered_map> > options, std::vector positional, bool allow_unrecognised, int& argc, char**& argv ) : m_options(options) , m_positional(std::move(positional)) , m_next_positional(m_positional.begin()) , m_allow_unrecognised(allow_unrecognised) { parse(argc, argv); } inline OptionAdder Options::add_options(std::string group) { return OptionAdder(*this, std::move(group)); } inline OptionAdder& OptionAdder::operator() ( const std::string& opts, const std::string& desc, std::shared_ptr value, std::string arg_help ) { std::match_results result; std::regex_match(opts.c_str(), result, option_specifier); if (result.empty()) { throw invalid_option_format_error(opts); } const auto& short_match = result[2]; const auto& long_match = result[3]; if (!short_match.length() && !long_match.length()) { throw invalid_option_format_error(opts); } else if (long_match.length() == 1 && short_match.length()) { throw invalid_option_format_error(opts); } auto option_names = [] ( const std::sub_match& short_, const std::sub_match& long_ ) { if (long_.length() == 1) { return std::make_tuple(long_.str(), short_.str()); } else { return std::make_tuple(short_.str(), long_.str()); } }(short_match, long_match); m_options.add_option ( m_group, std::get<0>(option_names), std::get<1>(option_names), desc, value, std::move(arg_help) ); return *this; } inline void ParseResult::parse_default(std::shared_ptr details) { m_results[details].parse_default(details); } inline void ParseResult::parse_option ( std::shared_ptr value, const std::string& /*name*/, const std::string& arg ) { auto& result = m_results[value]; result.parse(value, arg); m_sequential.emplace_back(value->long_name(), arg); } inline void ParseResult::checked_parse_arg ( int argc, char* argv[], int& current, std::shared_ptr value, const std::string& name ) { if (current + 1 >= argc) { if (value->value().has_implicit()) { parse_option(value, name, value->value().get_implicit_value()); } else { throw missing_argument_exception(name); } } else { if (value->value().has_implicit()) { parse_option(value, name, value->value().get_implicit_value()); } else { parse_option(value, name, argv[current + 1]); ++current; } } } inline void ParseResult::add_to_option(const std::string& option, const std::string& arg) { auto iter = m_options->find(option); if (iter == m_options->end()) { throw option_not_exists_exception(option); } parse_option(iter->second, option, arg); } inline bool ParseResult::consume_positional(std::string a) { while (m_next_positional != m_positional.end()) { auto iter = m_options->find(*m_next_positional); if (iter != m_options->end()) { auto& result = m_results[iter->second]; if (!iter->second->value().is_container()) { if (result.count() == 0) { add_to_option(*m_next_positional, a); ++m_next_positional; return true; } else { ++m_next_positional; continue; } } else { add_to_option(*m_next_positional, a); return true; } } else { throw option_not_exists_exception(*m_next_positional); } } return false; } inline void Options::parse_positional(std::string option) { parse_positional(std::vector{std::move(option)}); } inline void Options::parse_positional(std::vector options) { m_positional = std::move(options); m_next_positional = m_positional.begin(); m_positional_set.insert(m_positional.begin(), m_positional.end()); } inline void Options::parse_positional(std::initializer_list options) { parse_positional(std::vector(std::move(options))); } inline ParseResult Options::parse(int& argc, char**& argv) { ParseResult result(m_options, m_positional, m_allow_unrecognised, argc, argv); return result; } inline void ParseResult::parse(int& argc, char**& argv) { int current = 1; int nextKeep = 1; bool consume_remaining = false; while (current != argc) { if (strcmp(argv[current], "--") == 0) { consume_remaining = true; ++current; break; } std::match_results result; std::regex_match(argv[current], result, option_matcher); if (result.empty()) { //not a flag // but if it starts with a `-`, then it's an error if (argv[current][0] == '-' && argv[current][1] != '\0') { if (!m_allow_unrecognised) { throw option_syntax_exception(argv[current]); } } //if true is returned here then it was consumed, otherwise it is //ignored if (consume_positional(argv[current])) { } else { argv[nextKeep] = argv[current]; ++nextKeep; } //if we return from here then it was parsed successfully, so continue } else { //short or long option? if (result[4].length() != 0) { const std::string& s = result[4]; for (std::size_t i = 0; i != s.size(); ++i) { std::string name(1, s[i]); auto iter = m_options->find(name); if (iter == m_options->end()) { if (m_allow_unrecognised) { continue; } else { //error throw option_not_exists_exception(name); } } auto value = iter->second; if (i + 1 == s.size()) { //it must be the last argument checked_parse_arg(argc, argv, current, value, name); } else if (value->value().has_implicit()) { parse_option(value, name, value->value().get_implicit_value()); } else { //error throw option_requires_argument_exception(name); } } } else if (result[1].length() != 0) { const std::string& name = result[1]; auto iter = m_options->find(name); if (iter == m_options->end()) { if (m_allow_unrecognised) { // keep unrecognised options in argument list, skip to next argument argv[nextKeep] = argv[current]; ++nextKeep; ++current; continue; } else { //error throw option_not_exists_exception(name); } } auto opt = iter->second; //equals provided for long option? if (result[2].length() != 0) { //parse the option given parse_option(opt, name, result[3]); } else { //parse the next argument checked_parse_arg(argc, argv, current, opt, name); } } } ++current; } for (auto& opt : *m_options) { auto& detail = opt.second; auto& value = detail->value(); auto& store = m_results[detail]; if(value.has_default() && !store.count() && !store.has_default()){ parse_default(detail); } } if (consume_remaining) { while (current < argc) { if (!consume_positional(argv[current])) { break; } ++current; } //adjust argv for any that couldn't be swallowed while (current != argc) { argv[nextKeep] = argv[current]; ++nextKeep; ++current; } } argc = nextKeep; } inline void Options::add_option ( const std::string& group, const std::string& s, const std::string& l, std::string desc, std::shared_ptr value, std::string arg_help ) { auto stringDesc = toLocalString(std::move(desc)); auto option = std::make_shared(s, l, stringDesc, value); if (s.size() > 0) { add_one_option(s, option); } if (l.size() > 0) { add_one_option(l, option); } //add the help details auto& options = m_help[group]; options.options.emplace_back(HelpOptionDetails{s, l, stringDesc, value->has_default(), value->get_default_value(), value->has_implicit(), value->get_implicit_value(), std::move(arg_help), value->is_container(), value->is_boolean()}); } inline void Options::add_one_option ( const std::string& option, std::shared_ptr details ) { auto in = m_options->emplace(option, details); if (!in.second) { throw option_exists_error(option); } } inline String Options::help_one_group(const std::string& g) const { typedef std::vector> OptionHelp; auto group = m_help.find(g); if (group == m_help.end()) { return ""; } OptionHelp format; size_t longest = 0; String result; if (!g.empty()) { result += toLocalString(" " + g + " options:\n"); } for (const auto& o : group->second.options) { if (m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) { continue; } auto s = format_option(o); longest = (std::max)(longest, stringLength(s)); format.push_back(std::make_pair(s, String())); } longest = (std::min)(longest, static_cast(OPTION_LONGEST)); //widest allowed description auto allowed = size_t{76} - longest - OPTION_DESC_GAP; auto fiter = format.begin(); for (const auto& o : group->second.options) { if (m_positional_set.find(o.l) != m_positional_set.end() && !m_show_positional) { continue; } auto d = format_description(o, longest + OPTION_DESC_GAP, allowed); result += fiter->first; if (stringLength(fiter->first) > longest) { result += '\n'; result += toLocalString(std::string(longest + OPTION_DESC_GAP, ' ')); } else { result += toLocalString(std::string(longest + OPTION_DESC_GAP - stringLength(fiter->first), ' ')); } result += d; result += '\n'; ++fiter; } return result; } inline void Options::generate_group_help ( String& result, const std::vector& print_groups ) const { for (size_t i = 0; i != print_groups.size(); ++i) { const String& group_help_text = help_one_group(print_groups[i]); if (empty(group_help_text)) { continue; } result += group_help_text; if (i < print_groups.size() - 1) { result += '\n'; } } } inline void Options::generate_all_groups_help(String& result) const { std::vector all_groups; all_groups.reserve(m_help.size()); for (auto& group : m_help) { all_groups.push_back(group.first); } generate_group_help(result, all_groups); } inline std::string Options::help(const std::vector& help_groups) const { String result = m_help_string + "\nUsage:\n " + toLocalString(m_program) + " " + toLocalString(m_custom_help); if (m_positional.size() > 0 && m_positional_help.size() > 0) { result += " " + toLocalString(m_positional_help); } result += "\n\n"; if (help_groups.size() == 0) { generate_all_groups_help(result); } else { generate_group_help(result, help_groups); } return toUTF8String(result); } inline const std::vector Options::groups() const { std::vector g; std::transform( m_help.begin(), m_help.end(), std::back_inserter(g), [] (const std::map::value_type& pair) { return pair.first; } ); return g; } inline const HelpGroupDetails& Options::group_help(const std::string& group) const { return m_help.at(group); } } #endif //CXXOPTS_HPP_INCLUDED fuse-3.18.3/example/hello.c0000644000175000017500000001047015250106036014420 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * minimal example filesystem using high-level API * * Compile with: * * gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello * * ## Source code ## * \include hello.c */ #define FUSE_USE_VERSION 31 #include #include #include #include #include #include #include /* * Command line options * * We can't set default values for the char* fields here because * fuse_opt_parse would attempt to free() them when the user specifies * different values on the command line. */ static struct options { const char *filename; const char *contents; int show_help; } options; #define OPTION(t, p) \ { t, offsetof(struct options, p), 1 } static const struct fuse_opt option_spec[] = { OPTION("--name=%s", filename), OPTION("--contents=%s", contents), OPTION("-h", show_help), OPTION("--help", show_help), FUSE_OPT_END }; static void *hello_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void) conn; cfg->kernel_cache = 1; /* Test setting flags the old way */ fuse_set_feature_flag(conn, FUSE_CAP_ASYNC_READ); fuse_unset_feature_flag(conn, FUSE_CAP_ASYNC_READ); return NULL; } static int hello_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void) fi; int res = 0; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; } else if (strcmp(path+1, options.filename) == 0) { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(options.contents); } else res = -ENOENT; return res; } static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { (void) offset; (void) fi; (void) flags; if (strcmp(path, "/") != 0) return -ENOENT; filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, options.filename, NULL, 0, FUSE_FILL_DIR_DEFAULTS); return 0; } static int hello_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path+1, options.filename) != 0) return -ENOENT; if ((fi->flags & O_ACCMODE) != O_RDONLY) return -EACCES; return 0; } static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t len; (void) fi; if(strcmp(path+1, options.filename) != 0) return -ENOENT; len = strlen(options.contents); if (offset < len) { if (offset + size > len) size = len - offset; memcpy(buf, options.contents + offset, size); } else size = 0; return size; } static const struct fuse_operations hello_oper = { .init = hello_init, .getattr = hello_getattr, .readdir = hello_readdir, .open = hello_open, .read = hello_read, }; static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --name= Name of the \"hello\" file\n" " (default: \"hello\")\n" " --contents= Contents \"hello\" file\n" " (default \"Hello, World!\\n\")\n" "\n"); } int main(int argc, char *argv[]) { int ret; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); /* Set defaults -- we have to use strdup so that fuse_opt_parse can free the defaults if other values are specified */ options.filename = strdup("hello"); options.contents = strdup("Hello World!\n"); /* Parse options */ if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) return 1; /* When --help is specified, first print our own file-system specific help text, then signal fuse_main to show additional help (by adding `--help` to the options again) without usage: line (by setting argv[0] to the empty string) */ if (options.show_help) { show_help(argv[0]); assert(fuse_opt_add_arg(&args, "--help") == 0); args.argv[0][0] = '\0'; } ret = fuse_main(args.argc, args.argv, &hello_oper, NULL); fuse_opt_free_args(&args); return ret; } fuse-3.18.3/example/hello_ll.c0000644000175000017500000001505515250106036015113 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * minimal example filesystem using low-level API * * Compile with: * * gcc -Wall hello_ll.c `pkg-config fuse3 --cflags --libs` -o hello_ll * * Note: If the pkg-config command fails due to the absence of the fuse3.pc * file, you should configure the path to the fuse3.pc file in the * PKG_CONFIG_PATH variable. * * ## Source code ## * \include hello_ll.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12) #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_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; /* Test setting flags the old way */ conn->want = FUSE_CAP_ASYNC_READ; conn->want &= ~FUSE_CAP_ASYNC_READ; } 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 & O_ACCMODE) != 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 void hello_ll_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { (void)size; assert(ino == 1 || ino == 2); if (strcmp(name, "hello_ll_getxattr_name") == 0) { const char *buf = "hello_ll_getxattr_value"; fuse_reply_buf(req, buf, strlen(buf)); } else { fuse_reply_err(req, ENOTSUP); } } static void hello_ll_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { (void)flags; (void)size; assert(ino == 1 || ino == 2); const char* exp_val = "hello_ll_setxattr_value"; if (strcmp(name, "hello_ll_setxattr_name") == 0 && strlen(exp_val) == size && strncmp(value, exp_val, size) == 0) { fuse_reply_err(req, 0); } else { fuse_reply_err(req, ENOTSUP); } } static void hello_ll_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { assert(ino == 1 || ino == 2); if (strcmp(name, "hello_ll_removexattr_name") == 0) { fuse_reply_err(req, 0); } else { fuse_reply_err(req, ENOTSUP); } } static const struct fuse_lowlevel_ops hello_ll_oper = { .init = hello_ll_init, .lookup = hello_ll_lookup, .getattr = hello_ll_getattr, .readdir = hello_ll_readdir, .open = hello_ll_open, .read = hello_ll_read, .setxattr = hello_ll_setxattr, .getxattr = hello_ll_getxattr, .removexattr = hello_ll_removexattr, }; 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 fuse_loop_config *config; int ret = -1; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_help) { printf("usage: %s [options] \n\n", argv[0]); fuse_cmdline_help(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); ret = 0; goto err_out1; } if(opts.mountpoint == NULL) { printf("usage: %s [options] \n", argv[0]); printf(" %s --help\n", argv[0]); ret = 1; goto err_out1; } se = fuse_session_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), NULL); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) 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 { config = fuse_loop_cfg_create(); fuse_loop_cfg_set_clone_fd(config, opts.clone_fd); fuse_loop_cfg_set_max_threads(config, opts.max_threads); ret = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); config = NULL; } fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } fuse-3.18.3/example/hello_ll_uds.c0000644000175000017500000002135415250106036015765 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Copyright (C) 2022 Tofik Sonono This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * minimal example filesystem using low-level API and a custom io. This custom * io is implemented using UNIX domain sockets (of type SOCK_STREAM) * * Compile with: * * gcc -Wall hello_ll_uds.c `pkg-config fuse3 --cflags --libs` -o hello_ll_uds * * ## Source code ## * \include hello_ll.c */ #define FUSE_USE_VERSION 34 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include static const char *hello_str = "Hello World!\n"; static const char *hello_name = "hello"; #define DEFAULT_SOCKET_PATH "/tmp/libfuse-hello-ll.sock" static struct options { const char *socket_path; } options; #define OPTION(t, p) \ { t, offsetof(struct options, p), 1 } static const struct fuse_opt option_spec[] = { OPTION("--socket=%s", socket_path), FUSE_OPT_END }; 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_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } 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 & O_ACCMODE) != 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 const struct fuse_lowlevel_ops hello_ll_oper = { .init = hello_ll_init, .lookup = hello_ll_lookup, .getattr = hello_ll_getattr, .readdir = hello_ll_readdir, .open = hello_ll_open, .read = hello_ll_read, }; static int create_socket(const char *socket_path) { struct sockaddr_un addr; if (strnlen(socket_path, sizeof(addr.sun_path)) >= sizeof(addr.sun_path)) { printf("Socket path may not be longer than %zu characters\n", sizeof(addr.sun_path) - 1); return -1; } if (remove(socket_path) == -1 && errno != ENOENT) { printf("Could not delete previous socket file entry at %s. Error: " "%s\n", socket_path, strerror(errno)); return -1; } memset(&addr, 0, sizeof(struct sockaddr_un)); strcpy(addr.sun_path, socket_path); int sfd = socket(AF_UNIX, SOCK_STREAM, 0); if (sfd == -1) { printf("Could not create socket. Error: %s\n", strerror(errno)); return -1; } addr.sun_family = AF_UNIX; if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) { printf("Could not bind socket. Error: %s\n", strerror(errno)); return -1; } if (listen(sfd, 1) == -1) return -1; printf("Awaiting connection on socket at %s...\n", socket_path); int cfd = accept(sfd, NULL, NULL); if (cfd == -1) { printf("Could not accept connection. Error: %s\n", strerror(errno)); return -1; } else { printf("Accepted connection!\n"); } return cfd; } static ssize_t stream_writev(int fd, struct iovec *iov, int count, void *userdata) { (void)userdata; ssize_t written = 0; int cur = 0; for (;;) { written = writev(fd, iov+cur, count-cur); if (written < 0) return written; while (cur < count && written >= iov[cur].iov_len) written -= iov[cur++].iov_len; if (cur == count) break; iov[cur].iov_base = (char *)iov[cur].iov_base + written; iov[cur].iov_len -= written; } return written; } static ssize_t readall(int fd, void *buf, size_t len) { size_t count = 0; while (count < len) { int i = read(fd, (char *)buf + count, len - count); if (!i) break; if (i < 0) return i; count += i; } return count; } static ssize_t stream_read(int fd, void *buf, size_t buf_len, void *userdata) { (void)userdata; int res = readall(fd, buf, sizeof(struct fuse_in_header)); if (res == -1) return res; uint32_t packet_len = ((struct fuse_in_header *)buf)->len; if (packet_len > buf_len) return -1; int prev_res = res; res = readall(fd, (char *)buf + sizeof(struct fuse_in_header), packet_len - sizeof(struct fuse_in_header)); return (res == -1) ? res : (res + prev_res); } static ssize_t stream_splice_send(int fdin, off_t *offin, int fdout, off_t *offout, size_t len, unsigned int flags, void *userdata) { (void)userdata; size_t count = 0; while (count < len) { int i = splice(fdin, offin, fdout, offout, len - count, flags); if (i < 1) return i; count += i; } return count; } static void fuse_cmdline_help_uds(void) { printf(" -h --help print help\n" " -V --version print version\n" " -d -o debug enable debug output (implies -f)\n" " --socket=PATH serve on PATH\n" " (default: " DEFAULT_SOCKET_PATH ")\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; const struct fuse_custom_io io = { .writev = stream_writev, .read = stream_read, .splice_receive = NULL, .splice_send = stream_splice_send, }; int cfd = -1; int ret = -1; /* strdup: fuse_opt_parse frees the old value if --socket is given */ options.socket_path = strdup(DEFAULT_SOCKET_PATH); if (options.socket_path == NULL) return 1; if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) return 1; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_help) { printf("usage: %s [options]\n\n", argv[0]); fuse_cmdline_help_uds(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); ret = 0; goto err_out1; } se = fuse_session_new(&args, &hello_ll_oper, sizeof(hello_ll_oper), NULL); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) goto err_out2; cfd = create_socket(options.socket_path); if (cfd == -1) goto err_out3; if (fuse_session_custom_io(se, &io, cfd) != 0) goto err_out3; /* Block until ctrl+c */ ret = fuse_session_loop(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } fuse-3.18.3/example/invalidate_path.c0000644000175000017500000001560315250106036016454 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath (C) 2017 EditShare LLC This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * 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 invalidate_path.c `pkg-config fuse3 --cflags --libs` -o invalidate_path * * ## Source code ## * \include invalidate_path.c */ #define FUSE_USE_VERSION 34 #include #include /* for fuse_cmdline_opts */ #include #include #include #include #include #include #include #include #include /* We can't actually tell the kernel that there is no timeout, so we just send a big value */ #define NO_TIMEOUT 500000 #define MAX_STR_LEN 128 #define TIME_FILE_NAME "current_time" #define TIME_FILE_INO 2 #define GROW_FILE_NAME "growing" #define GROW_FILE_INO 3 static char time_file_contents[MAX_STR_LEN]; static size_t grow_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), FUSE_OPT_END }; static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void) conn; cfg->entry_timeout = NO_TIMEOUT; cfg->attr_timeout = NO_TIMEOUT; cfg->negative_timeout = 0; return NULL; } static int xmp_getattr(const char *path, struct stat *stbuf, struct fuse_file_info* fi) { (void) fi; if (strcmp(path, "/") == 0) { stbuf->st_ino = 1; stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 1; } else if (strcmp(path, "/" TIME_FILE_NAME) == 0) { stbuf->st_ino = TIME_FILE_INO; stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(time_file_contents); } else if (strcmp(path, "/" GROW_FILE_NAME) == 0) { stbuf->st_ino = GROW_FILE_INO; stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = grow_file_size; } else { return -ENOENT; } 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) { (void) fi; (void) offset; (void) flags; if (strcmp(path, "/") != 0) { return -ENOTDIR; } else { (void) filler; (void) buf; struct stat file_stat; xmp_getattr("/" TIME_FILE_NAME, &file_stat, NULL); filler(buf, TIME_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS); xmp_getattr("/" GROW_FILE_NAME, &file_stat, NULL); filler(buf, GROW_FILE_NAME, &file_stat, 0, FUSE_FILL_DIR_DEFAULTS); return 0; } } static int xmp_open(const char *path, struct fuse_file_info *fi) { (void) path; /* Make cache persistent even if file is closed, this makes it easier to see the effects */ fi->keep_cache = 1; return 0; } static int xmp_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; (void) offset; if (strcmp(path, "/" TIME_FILE_NAME) == 0) { int file_length = strlen(time_file_contents); int to_copy = offset + size <= file_length ? size : file_length - offset; memcpy(buf, time_file_contents, to_copy); return to_copy; } else { assert(strcmp(path, "/" GROW_FILE_NAME) == 0); int to_copy = offset + size <= grow_file_size ? size : grow_file_size - offset; memset(buf, 'x', to_copy); return to_copy; } } static const struct fuse_operations xmp_oper = { .init = xmp_init, .getattr = xmp_getattr, .readdir = xmp_readdir, .open = xmp_open, .read = xmp_read, }; static void update_fs(void) { static int count = 0; struct tm tmbuf; struct tm *now; time_t t; t = time(NULL); now = localtime_r(&t, &tmbuf); assert(now != NULL); int time_file_size = strftime(time_file_contents, MAX_STR_LEN, "The current time is %H:%M:%S\n", now); assert(time_file_size != 0); grow_file_size = count++; } static int invalidate(struct fuse *fuse, const char *path) { int status = fuse_invalidate_path(fuse, path); if (status == -ENOENT) { return 0; } else { return status; } } static void* update_fs_loop(void *data) { struct fuse *fuse = (struct fuse*) data; while (1) { update_fs(); if (!options.no_notify) { assert(invalidate(fuse, "/" TIME_FILE_NAME) == 0); assert(invalidate(fuse, "/" GROW_FILE_NAME) == 0); } sleep(options.update_interval); } return NULL; } static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --update-interval= 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 *fuse; struct fuse_cmdline_opts opts; struct fuse_loop_config config; int res; /* Initialize the files */ update_fs(); if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) return 1; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); res = 0; goto out1; } else if (opts.show_help) { show_help(argv[0]); fuse_cmdline_help(); fuse_lib_help(&args); res = 0; goto out1; } else if (!opts.mountpoint) { fprintf(stderr, "error: no mountpoint specified\n"); res = 1; goto out1; } fuse = fuse_new(&args, &xmp_oper, sizeof(xmp_oper), NULL); if (fuse == NULL) { res = 1; goto out1; } if (fuse_mount(fuse,opts.mountpoint) != 0) { res = 1; goto out2; } if (fuse_daemonize(opts.foreground) != 0) { res = 1; goto out3; } pthread_t updater; /* Start thread to update file contents */ int ret = pthread_create(&updater, NULL, update_fs_loop, (void *) fuse); if (ret != 0) { fprintf(stderr, "pthread_create failed with %s\n", strerror(ret)); return 1; }; struct fuse_session *se = fuse_get_session(fuse); if (fuse_set_signal_handlers(se) != 0) { res = 1; goto out3; } if (opts.singlethread) res = fuse_loop(fuse); else { config.clone_fd = opts.clone_fd; config.max_idle_threads = opts.max_idle_threads; res = fuse_loop_mt(fuse, &config); } if (res) res = 1; fuse_remove_signal_handlers(se); out3: fuse_unmount(fuse); out2: fuse_destroy(fuse); out1: free(opts.mountpoint); fuse_opt_free_args(&args); return res; } fuse-3.18.3/example/ioctl.c0000644000175000017500000001047315250106036014432 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * @tableofcontents * * This example illustrates how to write a FUSE file system that can * process (a restricted set of) ioctls. It can be tested with the * ioctl_client.c program. * * Compile with: * * gcc -Wall ioctl.c `pkg-config fuse3 --cflags --libs` -o ioctl * * ## Source code ## * \include ioctl.c */ #define FUSE_USE_VERSION 35 #include #include #include #include #include #include #include #include "ioctl.h" #define FIOC_NAME "fioc" enum { FIOC_NONE, FIOC_ROOT, FIOC_FILE, }; static void *fioc_buf; static size_t fioc_size; static int fioc_resize(size_t new_size) { void *new_buf; if (new_size == fioc_size) return 0; new_buf = realloc(fioc_buf, new_size); if (!new_buf && new_size) return -ENOMEM; if (new_size > fioc_size) memset(new_buf + fioc_size, 0, new_size - fioc_size); fioc_buf = new_buf; fioc_size = new_size; return 0; } static int fioc_expand(size_t new_size) { if (new_size > fioc_size) return fioc_resize(new_size); return 0; } static int fioc_file_type(const char *path) { if (strcmp(path, "/") == 0) return FIOC_ROOT; if (strcmp(path, "/" FIOC_NAME) == 0) return FIOC_FILE; return FIOC_NONE; } static int fioc_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void) fi; stbuf->st_uid = getuid(); stbuf->st_gid = getgid(); stbuf->st_atime = stbuf->st_mtime = time(NULL); switch (fioc_file_type(path)) { case FIOC_ROOT: stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; break; case FIOC_FILE: stbuf->st_mode = S_IFREG | 0644; stbuf->st_nlink = 1; stbuf->st_size = fioc_size; break; case FIOC_NONE: return -ENOENT; } return 0; } static int fioc_open(const char *path, struct fuse_file_info *fi) { (void) fi; if (fioc_file_type(path) != FIOC_NONE) return 0; return -ENOENT; } static int fioc_do_read(char *buf, size_t size, off_t offset) { if (offset >= fioc_size) return 0; if (size > fioc_size - offset) size = fioc_size - offset; memcpy(buf, fioc_buf + offset, size); return size; } static int fioc_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; if (fioc_file_type(path) != FIOC_FILE) return -EINVAL; return fioc_do_read(buf, size, offset); } static int fioc_do_write(const char *buf, size_t size, off_t offset) { if (fioc_expand(offset + size)) return -ENOMEM; memcpy(fioc_buf + offset, buf, size); return size; } static int fioc_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { (void) fi; if (fioc_file_type(path) != FIOC_FILE) return -EINVAL; return fioc_do_write(buf, size, offset); } static int fioc_truncate(const char *path, off_t size, struct fuse_file_info *fi) { (void) fi; if (fioc_file_type(path) != FIOC_FILE) return -EINVAL; return fioc_resize(size); } static int fioc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { (void) fi; (void) offset; (void) flags; if (fioc_file_type(path) != FIOC_ROOT) return -ENOENT; filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, FIOC_NAME, NULL, 0, FUSE_FILL_DIR_DEFAULTS); return 0; } static int fioc_ioctl(const char *path, unsigned 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 const 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-3.18.3/example/ioctl.h0000644000175000017500000000164015250106036014433 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * @tableofcontents * * Header file to share definitions between the ioctl.c example file * system and the ioctl_client.c test program. * * \include ioctl.h */ #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-3.18.3/example/ioctl_client.c0000644000175000017500000000241515250106036015765 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * This program tests the ioctl.c example file systsem. * * Compile with: * * gcc -Wall ioctl_client.c -o ioctl_client * * ## Source code ## * \include ioctl_client.c */ #include #include #include #include #include #include #include #include #include #include "ioctl.h" const char *usage = "Usage: fioclient FIOC_FILE [size]\n" "\n" "Get size if is omitted, set size otherwise\n" "\n"; int main(int argc, char **argv) { size_t size; int fd; int ret = 0; 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"); ret = 1; goto out; } printf("%zu\n", size); } else { size = strtoul(argv[2], NULL, 0); if (ioctl(fd, FIOC_SET_SIZE, &size)) { perror("ioctl"); ret = 1; goto out; } } out: close(fd); return ret; } fuse-3.18.3/example/memfs_ll.cc0000644000175000017500000006354315250106036015267 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2024 DataDirect Networks. This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LINUX_LIMITS_H #include #endif #define MEMFS_ATTR_TIMEOUT 0.0 #define MEMFS_ENTRY_TIMEOUT 0.0 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) class Inodes; class Inode; class Dentry; static void memfs_panic(std::string_view message); struct DirHandle { std::vector > > entries; size_t offset; DirHandle(const std::vector< std::pair > > &entries) : entries(entries) , offset(0) { } }; class Inode { private: uint64_t ino; // Unique inode number std::string name; bool is_dir_; time_t ctime; time_t mtime; time_t atime; mode_t mode; std::vector content; std::vector dentries; mutable std::mutex mutex; uint64_t nlookup; mutable std::mutex attr_mutex; std::atomic nlink; uid_t uid; gid_t gid; friend class Inodes; public: Inode(uint64_t ino, const std::string &n, bool dir) : ino(ino) , name(n) , is_dir_(dir) , ctime(time(NULL)) , mtime(ctime) , atime(ctime) , mode(dir ? S_IFDIR | 0755 : S_IFREG | 0644) , nlookup(1) , nlink(dir ? 2 : 1) , uid(0) , gid(0) { } uint64_t get_ino() const { return ino; } // Method to lock the mutex void lock() const { mutex.lock(); } // Method to unlock the mutex void unlock() const { mutex.unlock(); } void inc_lookup() { std::lock_guard lock(mutex); nlookup++; } uint64_t dec_lookup(uint64_t count) { std::unique_lock lock(mutex); if (nlookup < count) { lock.unlock(); memfs_panic("Lookup count mismatch detected"); } nlookup -= count; return nlookup; } const std::string &get_name() const { return name; } bool is_dir() const { return is_dir_; } time_t get_ctime() const { return ctime; } time_t get_mtime() const { std::lock_guard lock(mutex); return mtime; } mode_t get_mode() const { std::lock_guard lock(attr_mutex); return mode; } size_t content_size() const { return content.size(); } void read_content(char *buf, size_t size, off_t offset) const { size_t bytes_to_read = std::min(size, content.size() - (size_t)offset); std::copy(content.begin() + offset, content.begin() + offset + bytes_to_read, buf); } void write_content(const char *buf, size_t size, off_t offset) { std::lock_guard lock(mutex); if (offset + size > content.size()) { content.resize(offset + size); } std::copy(buf, buf + size, content.begin() + offset); mtime = time(NULL); } void set_uid(uid_t _uid) { std::lock_guard lock(attr_mutex); uid = _uid; } void set_gid(gid_t _gid) { std::lock_guard lock(attr_mutex); gid = _gid; } void set_mode(mode_t new_mode) { std::lock_guard lock(attr_mutex); mode = new_mode; } void set_atime(const struct timespec &_atime) { std::lock_guard lock(attr_mutex); atime = _atime.tv_sec; } void set_mtime(const struct timespec &_mtime) { std::lock_guard lock(mutex); mtime = _mtime.tv_sec; } void truncate(off_t size) { std::lock_guard attr_lock(mutex); if (size < content.size()) { content.resize(size); } else if (size > content.size()) { content.resize(size, 0); } mtime = time(NULL); } void get_attr(struct stat *stbuf) const { // consistent cross-domain snapshot: content lock then attr lock std::lock_guard lock(mutex); std::lock_guard attr_lock(attr_mutex); stbuf->st_ino = ino; stbuf->st_mode = mode; stbuf->st_nlink = nlink; stbuf->st_uid = uid; stbuf->st_gid = gid; stbuf->st_size = content.size(); stbuf->st_blocks = DIV_ROUND_UP(content.size(), 512); stbuf->st_atime = atime; stbuf->st_mtime = mtime; stbuf->st_ctime = ctime; } bool is_empty() const { std::lock_guard lock(mutex); return dentries.empty(); } void inc_nlink() { nlink++; } nlink_t dec_nlink() { nlink_t old_value = nlink.fetch_sub(1, std::memory_order_relaxed); if (old_value == 0) { memfs_panic("Attempting to decrement nlink below zero"); } return old_value - 1; } nlink_t get_nlink() const { return nlink.load(std::memory_order_relaxed); } /** * Methods that need Dentry knowledge */ int add_child_locked(const std::string &name, Dentry *child_dentry); int add_child(const std::string &name, Dentry *child_dentry); int remove_child(const std::string &name); std::vector > > get_children() const; Dentry *find_child_locked(const std::string &name) const; Dentry *find_child(const std::string &name) const; }; class Dentry { public: std::string name; std::shared_ptr inode; Dentry(const std::string &n, std::shared_ptr i) : name(n) , inode(std::move(i)) { } uint64_t get_ino() const { return inode->get_ino(); } bool is_dir() const { return inode->is_dir(); } const std::string &get_name() const { return name; } time_t get_ctime() const { return inode->get_ctime(); } time_t get_mtime() const { return inode->get_mtime(); } mode_t get_mode() const { return inode->get_mode(); } size_t content_size() const { return inode->content_size(); } Inode *get_inode() const { return inode.get(); } void inc_lookup() { inode->inc_lookup(); } }; class Inodes { private: std::unordered_map > inodes; mutable std::shared_mutex inodes_mutex; std::atomic next_ino{ FUSE_ROOT_ID + 1 }; public: Inodes() { auto root = std::make_shared(FUSE_ROOT_ID, "/", true); root->mode = S_IFDIR | 0755; root->nlink = 2; // . and .. inodes[FUSE_ROOT_ID] = std::move(root); } // New lock method void lock() { inodes_mutex.lock(); } // New unlock method void unlock() { inodes_mutex.unlock(); } void erase_locked(Inode *inode) { if (inode) { inodes.erase(inode->get_ino()); } } void erase(Inode *inode) { std::unique_lock lock(inodes_mutex); erase_locked(inode); } std::shared_ptr find_locked(fuse_ino_t ino) { auto it = inodes.find(ino); if (it == inodes.end()) { return nullptr; } return it->second; } std::shared_ptr find(fuse_ino_t ino) { std::shared_lock lock(inodes_mutex); return find_locked(ino); } std::shared_ptr create(const std::string &name, bool is_dir, mode_t mode) { std::unique_lock lock(inodes_mutex); uint64_t ino = next_ino.fetch_add(1, std::memory_order_relaxed); auto new_inode = std::make_shared(ino, name, is_dir); new_inode->set_mode(mode); auto [it, inserted] = inodes.emplace(ino, std::move(new_inode)); if (!inserted) { // This should never happen, but let's handle it just in case return nullptr; } return it->second; } size_t size() const { std::shared_lock lock(inodes_mutex); return inodes.size(); } }; int Inode::add_child_locked(const std::string &name, Dentry *child_dentry) { if (!is_dir_) { return ENOTDIR; } // Check if a child with this name already exists auto it = std::find_if(dentries.begin(), dentries.end(), [&name](const Dentry *dentry) { return dentry->get_name() == name; }); if (it != dentries.end()) { return EEXIST; } dentries.push_back(child_dentry); if (child_dentry->is_dir()) { nlink++; } return 0; } int Inode::add_child(const std::string &name, Dentry *child_dentry) { std::lock_guard lock(mutex); return add_child_locked(name, child_dentry); } int Inode::remove_child(const std::string &name) { if (!is_dir_) { return ENOTDIR; } auto it = std::find_if(dentries.begin(), dentries.end(), [&name](const Dentry *dentry) { return dentry->get_name() == name; }); if (it == dentries.end()) { return ENOENT; } Dentry *child_dentry = *it; dentries.erase(it); if (child_dentry->is_dir()) { nlink--; } delete child_dentry; return 0; } Dentry *Inode::find_child_locked(const std::string &name) const { if (!is_dir_) { return nullptr; } auto it = std::find_if(dentries.begin(), dentries.end(), [&name](const Dentry *dentry) { return dentry->get_name() == name; }); return (it != dentries.end()) ? *it : nullptr; } Dentry *Inode::find_child(const std::string &name) const { std::lock_guard lock(mutex); return find_child_locked(name); } std::vector > > Inode::get_children() const { std::lock_guard lock(mutex); if (!is_dir_) { return {}; // Return an empty vector if this is not a directory } std::vector > > children; children.reserve(dentries.size()); for (const Dentry *dentry : dentries) { children.emplace_back(dentry->name, dentry->inode); } return children; } static Inodes Inodes; static void memfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { auto parentInode = Inodes.find(parent); if (!parentInode) { fuse_reply_err(req, ENOENT); return; } if (!parentInode->is_dir()) { fuse_reply_err(req, ENOTDIR); return; } parentInode->lock(); Dentry *child = parentInode->find_child_locked(name); if (!child) { parentInode->unlock(); fuse_reply_err(req, ENOENT); return; } std::shared_ptr child_inode = child->inode; parentInode->unlock(); struct fuse_entry_param e; memset(&e, 0, sizeof(e)); e.ino = child_inode->get_ino(); e.attr_timeout = MEMFS_ATTR_TIMEOUT; e.entry_timeout = MEMFS_ENTRY_TIMEOUT; e.attr.st_ino = child_inode->get_ino(); e.attr.st_mode = child_inode->get_mode(); e.attr.st_nlink = child_inode->is_dir() ? 2 : 1; child_inode->inc_lookup(); fuse_reply_entry(req, &e); } static void memfs_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { fuse_ino_t actual_ino = fi ? fi->fh : ino; if (actual_ino == 0) { fuse_reply_err(req, EBADF); return; } auto inode_data = Inodes.find(actual_ino); if (!inode_data) { fuse_reply_err(req, ENOENT); return; } struct stat stbuf; inode_data->get_attr(&stbuf); stbuf.st_ino = actual_ino; // Ensure the correct inode number is set fuse_reply_attr(req, &stbuf, MEMFS_ATTR_TIMEOUT); } static void memfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { auto parentInode = Inodes.find(parent); if (!parentInode || !parentInode->is_dir()) { fuse_reply_err(req, ENOENT); return; } if (parentInode->find_child(name)) { fuse_reply_err(req, EEXIST); return; } auto new_inode = Inodes.create(name, false, mode); if (!new_inode) { fuse_reply_err(req, EIO); return; } // Create a new Dentry and add it to the parent Dentry *new_dentry = new Dentry(name, new_inode); //std::cout << "Debug: Created new Dentry at address " // << (void *)new_dentry << ", name: '" << name // << "', inode address: " << (void *)new_inode << std::endl; int error = parentInode->add_child(name, new_dentry); if (error != 0) { delete new_dentry; Inodes.erase(new_inode.get()); fuse_reply_err(req, error); return; } struct fuse_entry_param e; memset(&e, 0, sizeof(e)); e.ino = new_inode->get_ino(); e.attr_timeout = MEMFS_ATTR_TIMEOUT; e.entry_timeout = MEMFS_ENTRY_TIMEOUT; new_inode->get_attr(&e.attr); fi->fh = e.ino; fuse_reply_create(req, &e, fi); } static void memfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t offset, [[maybe_unused]] struct fuse_file_info *fi) { auto inode = Inodes.find(ino); if (!inode) { fuse_reply_err(req, ENOENT); return; } if (inode->is_dir()) { fuse_reply_err(req, EISDIR); return; } // A negative offset, or an end position past the content vector's index // type, would convert to a huge value in write_content and abort the // resize. PTRDIFF_MAX is the std::vector size/index ceiling on both 32- // and 64-bit builds. if (offset < 0) { fuse_reply_err(req, EINVAL); return; } if ((uint64_t)offset > (uint64_t)PTRDIFF_MAX - size) { fuse_reply_err(req, EFBIG); return; } inode->write_content(buf, size, offset); fuse_reply_write(req, size); } static void memfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, [[maybe_unused]] struct fuse_file_info *fi) { auto inode = Inodes.find(ino); if (!inode || inode->is_dir()) { fuse_reply_err(req, ENOENT); return; } // A negative offset would slip past the offset >= content_size() guard // on a 32-bit build (signed compare) and index before the buffer. if (offset < 0) { fuse_reply_err(req, EINVAL); return; } inode->lock(); if (offset >= inode->content_size()) { fuse_reply_buf(req, nullptr, 0); inode->unlock(); return; } std::vector content( std::min(size, inode->content_size() - (size_t)offset)); inode->read_content(content.data(), content.size(), offset); inode->unlock(); fuse_reply_buf(req, content.data(), content.size()); } static void memfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { auto inode_data = Inodes.find(ino); if (!inode_data || inode_data->is_dir()) { fuse_reply_err(req, ENOENT); return; } // Use the inode number as the file handle fi->fh = ino; fuse_reply_open(req, fi); } static void memfs_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { auto inode = Inodes.find(ino); if (!inode || !inode->is_dir()) { fuse_reply_err(req, ENOTDIR); return; } // Create a new DirHandle auto dir_handle = new DirHandle(inode->get_children()); // Store the pointer to the DirHandle in fi->fh fi->fh = reinterpret_cast(dir_handle); fuse_reply_open(req, fi); } static void memfs_readdir(fuse_req_t req, [[maybe_unused]] fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { auto *dir_handle = reinterpret_cast(fi->fh); if (!dir_handle) { fuse_reply_err(req, EBADF); return; } char *buffer = new char[size]; size_t buf_size = 0; for (off_t i = offset; i < static_cast(dir_handle->entries.size()); ++i) { const auto &entry = dir_handle->entries[i]; const std::string &name = entry.first; const std::shared_ptr &inode = entry.second; struct stat stbuf; memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = inode->get_ino(); inode->get_attr(&stbuf); size_t entry_size = fuse_add_direntry(req, nullptr, 0, name.c_str(), nullptr, 0); if (buf_size + entry_size > size) { break; } fuse_add_direntry(req, buffer + buf_size, size - buf_size, name.c_str(), &stbuf, i + 1); buf_size += entry_size; } fuse_reply_buf(req, buffer, buf_size); delete[] buffer; } static void memfs_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { // No need to remove file handle (void)fi; (void)ino; fuse_reply_err(req, 0); } static void memfs_releasedir(fuse_req_t req, [[maybe_unused]] fuse_ino_t ino, struct fuse_file_info *fi) { auto *dir_handle = reinterpret_cast(fi->fh); delete dir_handle; fuse_reply_err(req, 0); } static void memfs_panic(std::string_view message) { std::cerr << "MEMFS PANIC: " << message << std::endl; std::abort(); } static void memfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { Inodes.lock(); auto inode = Inodes.find_locked(ino); uint64_t res; if (inode) { res = inode->dec_lookup(nlookup); if (res == 0 && inode->get_nlink() == 0) Inodes.erase_locked(inode.get()); } Inodes.unlock(); fuse_reply_none(req); } static void memfs_forget_multi(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { Inodes.lock(); for (size_t i = 0; i < count; i++) { auto inode = Inodes.find_locked(forgets[i].ino); if (inode && inode->dec_lookup(forgets[i].nlookup) == 0 && inode->get_nlink() == 0) Inodes.erase_locked(inode.get()); } Inodes.unlock(); fuse_reply_none(req); } static void memfs_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { fuse_ino_t actual_ino = fi ? fi->fh : ino; if (actual_ino == 0) { fuse_reply_err(req, EBADF); return; } auto inode_data = Inodes.find(actual_ino); if (!inode_data) { fuse_reply_err(req, ENOENT); return; } if (to_set & FUSE_SET_ATTR_MODE) inode_data->set_mode(attr->st_mode); if (to_set & FUSE_SET_ATTR_UID) inode_data->set_uid(attr->st_uid); if (to_set & FUSE_SET_ATTR_GID) inode_data->set_gid(attr->st_gid); if (to_set & FUSE_SET_ATTR_SIZE) inode_data->truncate(attr->st_size); if (to_set & FUSE_SET_ATTR_ATIME) inode_data->set_atime(attr->st_atim); if (to_set & FUSE_SET_ATTR_MTIME) inode_data->set_mtime(attr->st_mtim); struct stat st; inode_data->get_attr(&st); fuse_reply_attr(req, &st, MEMFS_ATTR_TIMEOUT); } static void memfs_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { int error = 0; std::shared_ptr parentInode = nullptr; std::shared_ptr new_inode = nullptr; Dentry *new_dentry = nullptr; struct fuse_entry_param e; parentInode = Inodes.find(parent); if (!parentInode || !parentInode->is_dir()) { error = ENOENT; goto out; } new_inode = Inodes.create(name, true, mode | S_IFDIR); if (!new_inode) { error = EIO; goto out; } new_dentry = new Dentry(name, new_inode); error = parentInode->add_child(name, new_dentry); if (error != 0) { goto out_cleanup; } memset(&e, 0, sizeof(e)); e.ino = new_inode->get_ino(); e.attr_timeout = MEMFS_ATTR_TIMEOUT; e.entry_timeout = MEMFS_ENTRY_TIMEOUT; new_inode->get_attr(&e.attr); out: if (error == 0) { fuse_reply_entry(req, &e); } else { fuse_reply_err(req, error); } return; out_cleanup: delete new_dentry; Inodes.erase(new_inode.get()); goto out; } static void memfs_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { auto parentInode = Inodes.find(parent); if (!parentInode || !parentInode->is_dir()) { fuse_reply_err(req, ENOENT); return; } parentInode->lock(); auto child_dentry = parentInode->find_child_locked(name); if (child_dentry == nullptr) { parentInode->unlock(); fuse_reply_err(req, ENOENT); return; } Inode *child = child_dentry->get_inode(); if (!child || !child->is_dir() || !child->is_empty()) { parentInode->unlock(); fuse_reply_err(req, child ? (child->is_empty() ? ENOTDIR : ENOTEMPTY) : ENOENT); return; } parentInode->remove_child(name); child->dec_nlink(); // This should handle removal if nlink reaches 0 parentInode->unlock(); fuse_reply_err(req, 0); } static void memfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { auto parentInode = Inodes.find(parent); if (!parentInode || !parentInode->is_dir()) { fuse_reply_err(req, ENOENT); return; } parentInode->lock(); auto child_dentry = parentInode->find_child_locked(name); if (child_dentry == nullptr) { parentInode->unlock(); fuse_reply_err(req, ENOENT); return; } Inode *child = child_dentry->get_inode(); if (!child || child->is_dir()) { parentInode->unlock(); fuse_reply_err(req, child ? EISDIR : ENOENT); return; } parentInode->remove_child(name); child->dec_nlink(); parentInode->unlock(); fuse_reply_err(req, 0); } static void memfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags) { int error = 0; std::shared_ptr parentInode = nullptr; std::shared_ptr newparentInode = nullptr; Dentry *child_dentry = nullptr; Dentry *child_dentry_copy = nullptr; Dentry *existing_dentry = nullptr; Inode *inode_a = nullptr; Inode *inode_b = nullptr; #if defined(RENAME_EXCHANGE) && defined(RENAME_NOREPLACE) if (flags & (RENAME_EXCHANGE | RENAME_NOREPLACE)) { fuse_reply_err(req, EINVAL); return; } #else (void)flags; #endif Inodes.lock(); parentInode = Inodes.find_locked(parent); newparentInode = Inodes.find_locked(newparent); if (!parentInode || !parentInode->is_dir() || !newparentInode || !newparentInode->is_dir()) { error = ENOENT; goto out_unlock_global; } inode_a = parentInode.get(); inode_b = (parent != newparent) ? newparentInode.get() : nullptr; if (inode_b && inode_a->get_ino() > inode_b->get_ino()) std::swap(inode_a, inode_b); // always lock lower ino first inode_a->lock(); if (inode_b) inode_b->lock(); child_dentry = parentInode->find_child_locked(name); if (child_dentry == nullptr) { error = ENOENT; goto out_unlock; } existing_dentry = newparentInode->find_child_locked(newname); if (existing_dentry) { Inode *existing_inode = existing_dentry->get_inode(); if (existing_inode->is_dir() && !existing_inode->is_empty()) { error = ENOTEMPTY; goto out_unlock; } // remove_child() frees the dentry and already decrements // newparent's nlink for a dir child; resolve the inode first. newparentInode->remove_child(newname); existing_inode->dec_nlink(); } child_dentry_copy = new Dentry(newname, child_dentry->inode); parentInode->remove_child(name); newparentInode->add_child_locked(newname, child_dentry_copy); out_unlock: if (inode_b) inode_b->unlock(); inode_a->unlock(); out_unlock_global: Inodes.unlock(); fuse_reply_err(req, error); } static void memfs_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) { int error = 0; std::shared_ptr src_inode = nullptr; std::shared_ptr parent_inode = nullptr; struct fuse_entry_param e; Dentry *new_dentry = nullptr; Inodes.lock(); src_inode = Inodes.find_locked(ino); if (!src_inode) { error = ENOENT; goto out_unlock_global; } parent_inode = Inodes.find_locked(newparent); if (!parent_inode || !parent_inode->is_dir()) { error = ENOENT; goto out_unlock_global; } parent_inode->lock(); // Check if the new name already exists in the parent directory if (parent_inode->find_child_locked(newname) != nullptr) { error = EEXIST; goto out_unlock_parent; } src_inode->inc_nlink(); new_dentry = new Dentry(newname, src_inode); error = parent_inode->add_child_locked(newname, new_dentry); if (error != 0) { delete new_dentry; src_inode->dec_nlink(); goto out_unlock_parent; } // the reply below hands the kernel a new lookup reference src_inode->inc_lookup(); memset(&e, 0, sizeof(e)); e.ino = ino; e.attr_timeout = MEMFS_ATTR_TIMEOUT; e.entry_timeout = MEMFS_ENTRY_TIMEOUT; src_inode->get_attr(&e.attr); out_unlock_parent: parent_inode->unlock(); out_unlock_global: Inodes.unlock(); if (error == 0) { fuse_reply_entry(req, &e); } else { fuse_reply_err(req, error); } } static void memfs_statfs(fuse_req_t req, [[maybe_unused]] fuse_ino_t ino) { struct statvfs stbuf; memset(&stbuf, 0, sizeof(stbuf)); stbuf.f_bsize = 4096; stbuf.f_frsize = 4096; stbuf.f_namemax = PATH_MAX; // Maximum filename length stbuf.f_files = Inodes.size(); // Total inodes (files + directories) stbuf.f_ffree = std::numeric_limits::max() - stbuf.f_files; // Free inodes // Set total and free blocks // For simplicity, we'll set a fixed total number of blocks and calculate free blocks based on used inodes stbuf.f_blocks = 1000000; // arbitrary number, needs to be a parameter stbuf.f_bfree = stbuf.f_blocks - (stbuf.f_files * 10); // Assume each file uses 10 blocks on average stbuf.f_bavail = stbuf.f_bfree; stbuf.f_fsid = 0; // Set flags stbuf.f_flag = ST_NOSUID; fuse_reply_statfs(req, &stbuf); } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-field-initializers" static const struct fuse_lowlevel_ops memfs_oper = { .lookup = memfs_lookup, .forget = memfs_forget, .getattr = memfs_getattr, .setattr = memfs_setattr, .mkdir = memfs_mkdir, .unlink = memfs_unlink, .rmdir = memfs_rmdir, .rename = memfs_rename, .link = memfs_link, .open = memfs_open, .read = memfs_read, .write = memfs_write, .release = memfs_release, .opendir = memfs_opendir, .readdir = memfs_readdir, .releasedir = memfs_releasedir, .statfs = memfs_statfs, .create = memfs_create, .forget_multi = memfs_forget_multi, }; #pragma GCC diagnostic pop int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts opts; int ret = -1; struct fuse_loop_config *config = fuse_loop_cfg_create(); if (config == NULL) { std::cerr << "fuse_loop_cfg_create failed" << std::endl; exit(EXIT_FAILURE); } if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_help) { printf("usage: %s [options] \n\n", argv[0]); printf("File-system specific options:\n" " -o opt,[opt...] mount options\n" " -h --help print help\n" "\n"); fuse_cmdline_help(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); ret = 0; goto err_out1; } if (opts.mountpoint == NULL) { printf("usage: %s [options] \n", argv[0]); printf(" %s --help\n", argv[0]); ret = 1; goto err_out1; } se = fuse_session_new(&args, &memfs_oper, sizeof(memfs_oper), NULL); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) goto err_out2; if (fuse_session_mount(se, opts.mountpoint) != 0) goto err_out3; fuse_daemonize(opts.foreground); ret = fuse_session_loop_mt(se, config); fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } fuse-3.18.3/example/meson.build0000644000175000017500000000301115250106036015304 0ustar berndberndexamples = [ 'passthrough', 'passthrough_fh', 'hello', 'hello_ll', 'printcap', 'ioctl_client', 'poll_client', 'ioctl', 'cuse', 'cuse_client' ] if not platform.endswith('bsd') and platform != 'dragonfly' examples += [ 'passthrough_ll' ] if private_cfg.get('HAVE_CUSTOM_IO', false) examples += [ 'hello_ll_uds' ] endif # According to Conrad Meyer , FreeBSD doesn't # support mounting files, This is enforced in vfs_domount_first() # with the v_type != VDIR check. examples += [ 'null' ] endif threaded_examples = [ 'notify_inval_inode', 'invalidate_path', 'notify_store_retrieve', 'notify_inval_entry', 'poll' ] foreach ex : examples executable(ex, ex + '.c', dependencies: [ libfuse_dep ], install: false) endforeach foreach ex : threaded_examples executable(ex, ex + '.c', dependencies: [ thread_dep, libfuse_dep ], install: false) endforeach if platform != 'dragonfly' and add_languages('cpp', required : false) executable('passthrough_hp', 'passthrough_hp.cc', dependencies: [ thread_dep, libfuse_dep ], install: false) executable('memfs_ll', 'memfs_ll.cc', dependencies: [ thread_dep, libfuse_dep ], cpp_args : '-std=c++20', install: false) endif # TODO: Link passthrough_fh with ulockmgr if available fuse-3.18.3/example/notify_inval_entry.c0000644000175000017500000002623015250106036017240 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * This example implements a file system with a single file whose * file name changes dynamically to reflect the current time. * * It illustrates the use of the fuse_lowlevel_notify_inval_entry() and * fuse_lowlevel_notify_expire_entry() functions. * * To see the effect, first start the file system with the * ``--no-notify`` * * $ notify_inval_entry --update-interval=1 --timeout=30 --no-notify mnt/ * * Observe that `ls` always prints the correct directory contents * (since `readdir` output is not cached):: * * $ ls mnt; sleep 1; ls mnt; sleep 1; ls mnt * Time_is_15h_48m_33s current_time * Time_is_15h_48m_34s current_time * Time_is_15h_48m_35s current_time * * However, if you try to access a file by name the kernel will * report that it still exists: * * $ file=$(ls mnt/); echo $file * Time_is_15h_50m_09s * $ sleep 5; stat mnt/$file * File: ‘mnt/Time_is_15h_50m_09s’ * Size: 32 Blocks: 0 IO Block: 4096 regular file * Device: 2ah/42d Inode: 3 Links: 1 * Access: (0444/-r--r--r--) Uid: ( 0/ root) Gid: ( 0/ root) * Access: 1969-12-31 16:00:00.000000000 -0800 * Modify: 1969-12-31 16:00:00.000000000 -0800 * Change: 1969-12-31 16:00:00.000000000 -0800 * Birth: - * * Only once the kernel cache timeout has been reached will the stat * call fail: * * $ sleep 30; stat mnt/$file * stat: cannot stat ‘mnt/Time_is_15h_50m_09s’: No such file or directory * * In contrast, if you enable notifications you will be unable to stat * the file as soon as the file system updates its name: * * $ notify_inval_entry --update-interval=1 --timeout=30 mnt/ * $ file=$(ls mnt/); stat mnt/$file * File: ‘mnt/Time_is_20h_42m_11s’ * Size: 0 Blocks: 0 IO Block: 4096 regular empty file * Device: 2ah/42d Inode: 2 Links: 1 * Access: (0000/----------) Uid: ( 0/ root) Gid: ( 0/ root) * Access: 1969-12-31 16:00:00.000000000 -0800 * Modify: 1969-12-31 16:00:00.000000000 -0800 * Change: 1969-12-31 16:00:00.000000000 -0800 * Birth: - * $ sleep 1; stat mnt/$file * stat: cannot stat ‘mnt/Time_is_20h_42m_11s’: No such file or directory * * To use the function fuse_lowlevel_notify_expire_entry() instead of * fuse_lowlevel_notify_inval_entry(), use the command line option --only-expire * * Another possible command-line option is --inc-epoch, which will use the FUSE * low-level function fuse_lowlevel_notify_increment_epoch() instead. This will * function will force the invalidation of all dentries next time they are * revalidated. Note that --inc-epoch and --only-expire options are mutually * exclusive. * * ## Compilation ## * * gcc -Wall notify_inval_entry.c `pkg-config fuse3 --cflags --libs` -o notify_inval_entry * * ## Source code ## * \include notify_inval_entry.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12) #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_STR_LEN 128 static char file_name[MAX_STR_LEN]; static fuse_ino_t file_ino = 2; static int lookup_cnt = 0; static pthread_t main_thread; /* Command line parsing */ struct options { int no_notify; float timeout; int update_interval; int only_expire; int inc_epoch; }; static struct options options = { .timeout = 5, .no_notify = 0, .update_interval = 1, .only_expire = 0, .inc_epoch = 0, }; #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), OPTION("--timeout=%f", timeout), OPTION("--only-expire", only_expire), OPTION("--inc-epoch", inc_epoch), FUSE_OPT_END }; 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 | 0000; stbuf->st_nlink = 1; stbuf->st_size = 0; } else return -1; return 0; } static void tfs_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } 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 = options.timeout; e.entry_timeout = options.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); fuse_reply_none(req); } 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, options.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 const struct fuse_lowlevel_ops tfs_oper = { .init = tfs_init, .lookup = tfs_lookup, .getattr = tfs_getattr, .readdir = tfs_readdir, .forget = tfs_forget, }; static void update_fs(void) { time_t t; struct tm tmbuf; struct tm *now; ssize_t ret; t = time(NULL); now = localtime_r(&t, &tmbuf); assert(now != NULL); ret = strftime(file_name, MAX_STR_LEN, "Time_is_%Hh_%Mm_%Ss", now); assert(ret != 0); } static void *update_fs_loop(void *data) { struct fuse_session *se = (struct fuse_session *)data; char *old_name; int ret = 0; while (!fuse_session_exited(se)) { old_name = strdup(file_name); update_fs(); if (!options.no_notify && lookup_cnt) { if (options.only_expire) { // expire entry ret = fuse_lowlevel_notify_expire_entry( se, FUSE_ROOT_ID, old_name, strlen(old_name)); // no kernel support if (ret == -ENOSYS) { printf("%s not supported by kernel\n", "fuse_lowlevel_notify_expire_entry"); break; } // 1) ret == 0: successful expire of an existing entry // 2) ret == -ENOENT: kernel has already expired the entry / // entry does not exist anymore in the kernel assert(ret == 0 || ret == -ENOENT); } else if (options.inc_epoch) { // increment epoch ret = fuse_lowlevel_notify_increment_epoch(se); if (ret == -ENOSYS) { printf("%s not supported by kernel\n", "fuse_lowlevel_notify_increment_epoch"); break; } assert(ret == 0); } else { // invalidate entry assert(fuse_lowlevel_notify_inval_entry( se, FUSE_ROOT_ID, old_name, strlen(old_name)) == 0); } } free(old_name); sleep(options.update_interval); } if (ret == -ENOSYS) { printf("Exiting...\n"); fuse_session_exit(se); // Make sure to exit now, rather than on next request from userspace pthread_kill(main_thread, SIGPIPE); } return NULL; } static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --timeout= Timeout for kernel caches\n" " --update-interval= Update-rate of file system contents\n" " --no-notify Disable kernel notifications\n" " --only-expire Expire entries instead of invalidating them\n" " --inc-epoch Increment epoch, invalidating all dentries\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; struct fuse_loop_config *config; 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) return 1; if (opts.show_help) { show_help(argv[0]); fuse_cmdline_help(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); ret = 0; goto err_out1; } if (options.only_expire && options.inc_epoch) { printf("'only-expire' and 'inc-epoch' options are exclusive\n"); ret = 0; goto err_out1; } /* Initial contents */ update_fs(); se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), &se); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) goto err_out2; if (fuse_session_mount(se, opts.mountpoint) != 0) goto err_out3; fuse_daemonize(opts.foreground); // Needed to ensure that the main thread continues/restarts processing as soon // as the fuse session ends (immediately after calling fuse_session_exit() ) // and not only on the next request from userspace main_thread = pthread_self(); /* 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 { config = fuse_loop_cfg_create(); fuse_loop_cfg_set_clone_fd(config, opts.clone_fd); fuse_loop_cfg_set_max_threads(config, opts.max_threads); ret = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); config = NULL; } fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } /** * Local Variables: * mode: c * indent-tabs-mode: nil * c-basic-offset: 4 * End: */ fuse-3.18.3/example/notify_inval_inode.c0000644000175000017500000002276315250106036017204 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * 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 ## * \include notify_inval_inode.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12) #include #include #include #include #include #include #include #include #include #include #include #include /* We can't actually tell the kernel that there is no timeout, so we just send a big value */ #define NO_TIMEOUT 500000 #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; static _Atomic bool is_stop = false; /* 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), FUSE_OPT_END }; 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_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } static void tfs_destroy(void *userarg) { (void)userarg; is_stop = true; } 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); fuse_reply_none(req); } 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 & O_ACCMODE) != 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 const struct fuse_lowlevel_ops tfs_oper = { .init = tfs_init, .destroy = tfs_destroy, .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 tmbuf; struct tm *now; time_t t; t = time(NULL); now = localtime_r(&t, &tmbuf); 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 (!is_stop) { update_fs(); if (!options.no_notify && lookup_cnt) { /* Only send notification if the kernel is aware of the inode */ /* Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they * might come up during umount, when kernel side already releases * all inodes, but does not send FUSE_DESTROY yet. */ int ret = fuse_lowlevel_notify_inval_inode(se, FILE_INO, 0, 0); if ((ret != 0 && !is_stop) && ret != -ENOENT && ret != -EBADF && ret != -ENODEV) { fprintf(stderr, "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n", strerror(-ret), -ret); abort(); } } sleep(options.update_interval); } return NULL; } static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --update-interval= 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; struct fuse_loop_config *config; 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]); fuse_cmdline_help(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); 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; if (fuse_set_signal_handlers(se) != 0) 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 { config = fuse_loop_cfg_create(); fuse_loop_cfg_set_clone_fd(config, opts.clone_fd); fuse_loop_cfg_set_max_threads(config, opts.max_threads); ret = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); config = NULL; } fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: fuse_opt_free_args(&args); free(opts.mountpoint); return ret ? 1 : 0; } /** * Local Variables: * mode: c * indent-tabs-mode: nil * c-basic-offset: 4 * End: */ fuse-3.18.3/example/notify_store_retrieve.c0000644000175000017500000002653615250106036017760 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * This example implements a file system with a single file whose * contents change dynamically: it always contains the current time. * * While notify_inval_inode.c uses fuse_lowlevel_notify_inval_inode() * to let the kernel know that it has to invalidate the cache, this * example actively pushes the updated data into the kernel cache * using fuse_lowlevel_notify_store(). * * To see the effect, first start the file system with the * ``--no-notify`` option: * * $ notify_store_retrieve --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_store_retrieve --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_store_retrieve.c `pkg-config fuse3 --cflags --libs` -o notify_store_retrieve * * ## Source code ## * \include notify_store_retrieve.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12) #include #include #include #include #include #include #include #include #include #include #include /* We can't actually tell the kernel that there is no timeout, so we just send a big value */ #define NO_TIMEOUT 500000 #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 int open_cnt = 0; static size_t file_size; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; /* Keep track if we ever stored data (==1), and received it back correctly (==2) */ static int retrieve_status = 0; static bool is_umount = false; /* updater thread tid */ static pthread_t updater; /* 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), FUSE_OPT_END }; 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_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } 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; 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); /* * must only be set when the kernel knows about the entry, * otherwise update_fs_loop() might see a positive count, but kernel * would not have the entry yet */ if (e.ino == FILE_INO) { pthread_mutex_lock(&lock); lookup_cnt++; pthread_mutex_unlock(&lock); } 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) { pthread_mutex_lock(&lock); lookup_cnt -= nlookup; pthread_mutex_unlock(&lock); } else assert(ino == FUSE_ROOT_ID); fuse_reply_none(req); } 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 & O_ACCMODE) != O_RDONLY) fuse_reply_err(req, EACCES); else if (ino == FILE_INO) { fuse_reply_open(req, fi); pthread_mutex_lock(&lock); open_cnt++; pthread_mutex_unlock(&lock); } 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 void tfs_retrieve_reply(fuse_req_t req, void *cookie, fuse_ino_t ino, off_t offset, struct fuse_bufvec *data) { struct fuse_bufvec bufv; char buf[MAX_STR_LEN]; char *expected; ssize_t ret; assert(ino == FILE_INO); assert(offset == 0); expected = (char *)cookie; bufv.count = 1; bufv.idx = 0; bufv.off = 0; bufv.buf[0].size = MAX_STR_LEN; bufv.buf[0].mem = buf; bufv.buf[0].flags = 0; ret = fuse_buf_copy(&bufv, data, 0); assert(ret > 0); assert(strncmp(buf, expected, ret) == 0); free(expected); retrieve_status = 2; fuse_reply_none(req); } static void tfs_destroy(void *userdata) { (void)userdata; is_umount = true; pthread_join(updater, NULL); } static const struct fuse_lowlevel_ops tfs_oper = { .init = tfs_init, .lookup = tfs_lookup, .getattr = tfs_getattr, .readdir = tfs_readdir, .open = tfs_open, .read = tfs_read, .forget = tfs_forget, .retrieve_reply = tfs_retrieve_reply, .destroy = tfs_destroy, }; static void update_fs(void) { struct tm tmbuf; struct tm *now; time_t t; t = time(NULL); now = localtime_r(&t, &tmbuf); 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; struct fuse_bufvec bufv; int ret; while (!is_umount) { update_fs(); pthread_mutex_lock(&lock); if (!options.no_notify && open_cnt && lookup_cnt) { /* Only send notification if the kernel is aware of the inode */ bufv.count = 1; bufv.idx = 0; bufv.off = 0; bufv.buf[0].size = file_size; bufv.buf[0].mem = file_contents; bufv.buf[0].flags = 0; /* * Some errors (ENOENT, EBADF, ENODEV) have to be accepted as they * might come up during umount, when kernel side already releases * all inodes, but does not send FUSE_DESTROY yet. */ ret = fuse_lowlevel_notify_store(se, FILE_INO, 0, &bufv, 0); if ((ret != 0 && !is_umount) && ret != -ENOENT && ret != -EBADF && ret != -ENODEV) { fprintf(stderr, "ERROR: fuse_lowlevel_notify_store() failed with %s (%d)\n", strerror(-ret), -ret); abort(); } /* To make sure that everything worked correctly, ask the kernel to send us back the stored data */ ret = fuse_lowlevel_notify_retrieve( se, FILE_INO, MAX_STR_LEN, 0, (void *)strdup(file_contents)); assert((ret == 0 || is_umount) || ret == -ENOENT || ret == -EBADF || ret != -ENODEV); if (retrieve_status == 0) retrieve_status = 1; } pthread_mutex_unlock(&lock); sleep(options.update_interval); } return NULL; } static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --update-interval= 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; struct fuse_loop_config *config; int ret = -1; if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) return 1; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_help) { show_help(argv[0]); fuse_cmdline_help(); fuse_lowlevel_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); 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; if (fuse_set_signal_handlers(se) != 0) 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 { config = fuse_loop_cfg_create(); fuse_loop_cfg_set_clone_fd(config, opts.clone_fd); fuse_loop_cfg_set_max_threads(config, opts.max_threads); ret = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); config = NULL; } assert(retrieve_status != 1); fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } /** * Local Variables: * mode: c * indent-tabs-mode: nil * c-basic-offset: 4 * End: */ fuse-3.18.3/example/null.c0000644000175000017500000000543015250106036014267 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * This "filesystem" provides only a single file. The mountpoint * needs to be a file rather than a directory. All writes to the * file will be discarded, and reading the file always returns * \0. * * Compile with: * * gcc -Wall null.c `pkg-config fuse3 --cflags --libs` -o null * * ## Source code ## * \include passthrough_fh.c */ #define FUSE_USE_VERSION 31 #include #include #include #include #include #include #include #include static int null_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void) fi; 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, struct fuse_file_info *fi) { (void) size; (void) fi; 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; memset(buf, 0, size); 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 const 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[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_cmdline_opts opts; struct stat stbuf; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; fuse_opt_free_args(&args); if (!opts.mountpoint) { fprintf(stderr, "missing mountpoint parameter\n"); return 1; } if (stat(opts.mountpoint, &stbuf) == -1) { fprintf(stderr ,"failed to access mountpoint %s: %s\n", opts.mountpoint, strerror(errno)); free(opts.mountpoint); return 1; } free(opts.mountpoint); if (!S_ISREG(stbuf.st_mode)) { fprintf(stderr, "mountpoint is not a regular file\n"); return 1; } return fuse_main(argc, argv, &null_oper, NULL); } fuse-3.18.3/example/passthrough.c0000644000175000017500000002575715250106036015702 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * 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 ## * \include passthrough.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18) #define _GNU_SOURCE #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 #include "passthrough_helpers.h" static int fill_dir_plus = 0; static int readdir_zero_ino; static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void) conn; cfg->use_ino = !readdir_zero_ino; /* parallel_direct_writes feature depends on direct_io features. To make parallel_direct_writes valid, need either set cfg->direct_io in current function (recommended in high level API) or set fi->direct_io in xmp_create() or xmp_open(). */ // cfg->direct_io = 1; cfg->parallel_direct_writes = 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. */ if (!cfg->auto_cache) { 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; if (fill_dir_plus) { fstatat(dirfd(dp), de->d_name, &st, AT_SYMLINK_NOFOLLOW); } else { memset(&st, 0, sizeof(st)); st.st_ino = de->d_ino; st.st_mode = de->d_type << 12; } if (readdir_zero_ino) st.st_ino = 0; if (filler(buf, de->d_name, &st, 0, fill_dir_plus)) break; } closedir(dp); return 0; } static int xmp_mknod(const char *path, mode_t mode, dev_t rdev) { int res; res = mknod_wrapper(AT_FDCWD, path, NULL, 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; /* Enable direct_io when open has flags O_DIRECT to enjoy the feature parallel_direct_writes (i.e., to get a shared lock, not exclusive lock, for writes to the same file). */ if (fi->flags & O_DIRECT) { fi->direct_io = 1; fi->parallel_direct_writes = 1; } 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; } 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(fi == NULL) fd = open(path, O_WRONLY); else fd = fi->fh; if (fd == -1) return -errno; res = do_fallocate(fd, mode, offset, length); if(fi == NULL) close(fd); return res; } #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; if (fi_out == NULL) close(fd_out); if (fi_in == NULL) close(fd_in); return res; } #endif static off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi) { int fd; off_t res; if (fi == NULL) fd = open(path, O_RDONLY); else fd = fi->fh; if (fd == -1) return -errno; res = lseek(fd, off, whence); if (res == -1) res = -errno; if (fi == NULL) close(fd); return res; } #ifdef HAVE_STATX static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { int fd = -1; int res; if (fi) fd = fi->fh; res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf); if (res == -1) return -errno; return 0; } #endif static const 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, .fallocate = xmp_fallocate, #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 .lseek = xmp_lseek, #ifdef HAVE_STATX .statx = xmp_statx, #endif }; int main(int argc, char *argv[]) { enum { MAX_ARGS = 10 }; int i,new_argc; char *new_argv[MAX_ARGS]; umask(0); /* Process the "--plus" option apart */ for (i=0, new_argc=0; (i Copyright (C) 2011 Sebastian Pipping This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * 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 ## * \include passthrough_fh.c */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18) #define _GNU_SOURCE #include #ifdef HAVE_LIBULOCKMGR #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_SETXATTR #include #endif #include /* flock(2) */ #include "passthrough_helpers.h" static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void) conn; cfg->use_ino = 1; cfg->nullpath_ok = 1; /* parallel_direct_writes feature depends on direct_io features. To make parallel_direct_writes valid, need either set cfg->direct_io in current function (recommended in high level API) or set fi->direct_io in xmp_create() or xmp_open(). */ // cfg->direct_io = 1; cfg->parallel_direct_writes = 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 = FUSE_FILL_DIR_DEFAULTS; 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; /* Enable direct_io when open has flags O_DIRECT to enjoy the feature parallel_direct_writes (i.e., to get a shared lock, not exclusive lock, for writes to the same file). */ if (fi->flags & O_DIRECT) { fi->direct_io = 1; fi->parallel_direct_writes = 1; } 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; } static int xmp_fallocate(const char *path, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { (void) path; return do_fallocate(fi->fh, mode, offset, length); } #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 off_t xmp_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi) { off_t res; (void) path; res = lseek(fi->fh, off, whence); if (res == -1) return -errno; return res; } #ifdef HAVE_STATX static int xmp_statx(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { int fd = -1; int res; if (fi) fd = fi->fh; res = statx(fd, path, flags | AT_SYMLINK_NOFOLLOW, mask, stxbuf); if (res == -1) return -errno; return 0; } #endif static const 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, .fallocate = xmp_fallocate, #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 .lseek = xmp_lseek, #ifdef HAVE_STATX .statx = xmp_statx, #endif }; int main(int argc, char *argv[]) { umask(0); return fuse_main(argc, argv, &xmp_oper, NULL); } fuse-3.18.3/example/passthrough_helpers.h0000644000175000017500000000661715250106036017423 0ustar berndbernd/* * FUSE: Filesystem in Userspace * * 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 THE 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 THE 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 */ #ifndef FUSE_EXAMPLE_PASSTHROUGH_HELPERS_H_ #define FUSE_EXAMPLE_PASSTHROUGH_HELPERS_H_ #include #include #include #include #include #ifdef __FreeBSD__ #include #include #endif static inline int do_fallocate(int fd, int mode, off_t offset, off_t length) { #ifdef HAVE_FALLOCATE if (fallocate(fd, mode, offset, length) == -1) return -errno; return 0; #else // HAVE_FALLOCATE #ifdef HAVE_POSIX_FALLOCATE if (mode == 0) return -posix_fallocate(fd, offset, length); #endif #ifdef HAVE_FSPACECTL // 0x3 == FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE if (mode == 0x3) { struct spacectl_range sr; sr.r_offset = offset; sr.r_len = length; if (fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, NULL) == -1) return -errno; return 0; } #endif return -EOPNOTSUPP; #endif // HAVE_FALLOCATE } /* * Creates files on the underlying file system in response to a FUSE_MKNOD * operation */ static inline int mknod_wrapper(int dirfd, const char *path, const char *link, int mode, dev_t rdev) { int res; if (S_ISREG(mode)) { res = openat(dirfd, path, O_CREAT | O_EXCL | O_WRONLY, mode); if (res >= 0) res = close(res); } else if (S_ISDIR(mode)) { res = mkdirat(dirfd, path, mode); } else if (S_ISLNK(mode) && link != NULL) { res = symlinkat(link, dirfd, path); } else if (S_ISFIFO(mode)) { res = mkfifoat(dirfd, path, mode); #ifdef __FreeBSD__ } else if (S_ISSOCK(mode)) { struct sockaddr_un su; int fd; if (strlen(path) >= sizeof(su.sun_path)) { errno = ENAMETOOLONG; return -1; } fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd >= 0) { /* * We must bind the socket to the underlying file * system to create the socket file, even though * we'll never listen on this socket. */ su.sun_family = AF_UNIX; strncpy(su.sun_path, path, sizeof(su.sun_path)); res = bindat(dirfd, fd, (struct sockaddr*)&su, sizeof(su)); if (res == 0) close(fd); } else { res = -1; } #endif } else { res = mknodat(dirfd, path, mode, rdev); } return res; } #endif // FUSE_PASSTHROUGH_HELPERS_H_ fuse-3.18.3/example/passthrough_hp.cc0000644000175000017500000012553715250106036016531 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Copyright (C) 2017 Nikolaus Rath Copyright (C) 2018 Valve, Inc This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * This is a "high-performance" version of passthrough_ll.c. While * passthrough_ll.c is designed to be as simple as possible, this * example intended to be as efficient and correct as possible. * * passthrough_hp.cc mirrors a specified "source" directory under a * specified the mountpoint with as much fidelity and performance as * possible. * * If --nocache is specified, the source directory may be changed * directly even while mounted and the filesystem will continue * to work correctly. * * Without --nocache, the source directory is assumed to be modified * only through the passthrough filesystem. This enables much better * performance, but if changes are made directly to the source, they * may not be immediately visible under the mountpoint and further * access to the mountpoint may result in incorrect behavior, * including data-loss. * * On its own, this filesystem fulfills no practical purpose. It is * intended as a template upon which additional functionality can be * built. * * Unless --nocache is specified, 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). * * ## Source code ## * \include passthrough_hp.cc */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 12) #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif // C includes #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_XATTR_H #include #endif #include #include #include #include #ifdef __FreeBSD__ #include #include #endif // C++ includes #include #include #include #include "cxxopts.hpp" #include #include #include #include "passthrough_helpers.h" using namespace std; #define SFS_DEFAULT_THREADS "-1" // take libfuse value as default #define SFS_DEFAULT_CLONE_FD "0" /* We are re-using pointers to our `struct sfs_inode` and `struct sfs_dirp` elements as inodes and file handles. This means that we must be able to store pointer a pointer in both a fuse_ino_t variable and a uint64_t variable (used for file handles). */ static_assert(sizeof(fuse_ino_t) >= sizeof(void *), "void* must fit into fuse_ino_t"); static_assert(sizeof(fuse_ino_t) >= sizeof(uint64_t), "fuse_ino_t must be at least 64 bits"); /* Forward declarations */ struct Inode; static Inode &get_inode(fuse_ino_t ino); static void forget_one(fuse_ino_t ino, uint64_t n); // Uniquely identifies a file in the source directory tree. This could // be simplified to just ino_t since we require the source directory // not to contain any mountpoints. This hasn't been done yet in case // we need to reconsider this constraint (but relaxing this would have // the drawback that we can no longer reuse inode numbers, and thus // readdir() would need to do a full lookup() in order to report the // right inode number). typedef std::pair SrcId; // Define a hash function for SrcId namespace std { template <> struct hash { size_t operator()(const SrcId &id) const { return hash{}(id.first) ^ hash{}(id.second); } }; } // Maps files in the source directory tree to inodes typedef std::unordered_map InodeMap; struct Inode { int fd{ -1 }; dev_t src_dev{ 0 }; ino_t src_ino{ 0 }; int generation{ 0 }; int backing_id{ 0 }; uint64_t nopen{ 0 }; std::atomic nlookup{ 0 }; /* Drop before fuse_reply_*: the reply may be the kernel's last * reference, so forget_one() can erase the inode right after */ std::mutex m; // Delete copy constructor and assignments. We could implement // move if we need it. Inode() = default; Inode(const Inode &) = delete; Inode(Inode &&inode) = delete; Inode &operator=(Inode &&inode) = delete; Inode &operator=(const Inode &) = delete; ~Inode() { if (fd > 0) close(fd); } }; struct Fs { // Must be acquired *before* any Inode.m locks. std::mutex mutex; InodeMap inodes; // protected by mutex Inode root; double timeout; bool debug; bool debug_fuse; bool foreground; std::string source; size_t blocksize; dev_t src_dev; bool nosplice; bool nocache; size_t num_threads; bool clone_fd; std::string fuse_mount_options; bool direct_io; bool passthrough; }; static Fs fs{}; #define FUSE_BUF_COPY_FLAGS \ (fs.nosplice ? FUSE_BUF_NO_SPLICE : \ static_cast(FUSE_BUF_SPLICE_MOVE)) static Inode &get_inode(fuse_ino_t ino) { if (ino == FUSE_ROOT_ID) return fs.root; Inode *inode = reinterpret_cast(ino); if (inode->fd == -1) { cerr << "INTERNAL ERROR: Unknown inode " << ino << endl; abort(); } return *inode; } static int get_fs_fd(fuse_ino_t ino) { int fd = get_inode(ino).fd; return fd; } static void sfs_init(void *userdata, fuse_conn_info *conn) { (void)userdata; if (!fuse_set_feature_flag(conn, FUSE_CAP_PASSTHROUGH)) fs.passthrough = false; /* Passthrough and writeback cache are conflicting modes */ if (fs.timeout && !fs.passthrough) fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE); fuse_set_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); if (fs.nosplice) { // FUSE_CAP_SPLICE_READ is enabled in libfuse3 by default, // see do_init() in fuse_lowlevel.c // Just unset all, in case FUSE_CAP_SPLICE_WRITE or // FUSE_CAP_SPLICE_MOVE would also get enabled by default. fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ); fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_WRITE); fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_MOVE); } else { fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_WRITE); fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_READ); fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_MOVE); } /* This is a local file system - no network coherency needed */ fuse_set_feature_flag(conn, FUSE_CAP_DIRECT_IO_ALLOW_MMAP); /* Disable NFS export support, which also disabled name_to_handle_at. * Goal is to make xfstests that test name_to_handle_at to fail with * the right error code (EOPNOTSUPP) than to open_by_handle_at to fail with * ESTALE and let those test fail. * Perfect NFS export support is not possible with this FUSE filesystem needs * more kernel work, in order to passthrough nfs handle encode/decode to * fuse-server/daemon. */ fuse_set_feature_flag(conn, FUSE_CAP_NO_EXPORT_SUPPORT); /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; /* Try a large IO by default */ conn->max_write = 4 * 1024 * 1024; } static void sfs_getattr(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { struct stat attr; int fd = fi ? fi->fh : get_inode(ino).fd; auto res = fstatat(fd, "", &attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); if (res == -1) { fuse_reply_err(req, errno); return; } fuse_reply_attr(req, &attr, fs.timeout); } static int with_fd_path(int fd, const std::function &f) { #ifdef __FreeBSD__ struct kinfo_file kf; kf.kf_structsize = sizeof(kf); int ret = fcntl(fd, F_KINFO, &kf); if (ret == -1) return ret; return f(kf.kf_path); #else // Linux char procname[64]; sprintf(procname, "/proc/self/fd/%i", fd); return f(procname); #endif } static void do_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int valid, struct fuse_file_info *fi) { Inode &inode = get_inode(ino); int ifd = inode.fd; int res; if (valid & FUSE_SET_ATTR_MODE) { if (fi) { res = fchmod(fi->fh, attr->st_mode); } else { res = with_fd_path(ifd, [attr](const char *procname) { return 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 : static_cast(-1); gid_t gid = (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : static_cast(-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 { res = with_fd_path(ifd, [attr](const char *procname) { return 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 { #ifdef HAVE_UTIMENSAT res = with_fd_path(ifd, [&tv](const char *procname) { return utimensat(AT_FDCWD, procname, tv, 0); }); #else res = -1; errno = EOPNOTSUPP; #endif } if (res == -1) goto out_err; } return sfs_getattr(req, ino, fi); out_err: fuse_reply_err(req, errno); } static void sfs_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int valid, fuse_file_info *fi) { (void)ino; do_setattr(req, ino, attr, valid, fi); } static int do_lookup(fuse_ino_t parent, const char *name, fuse_entry_param *e) { if (fs.debug) cerr << "DEBUG: lookup(): name=" << name << ", parent=" << parent << endl; memset(e, 0, sizeof(*e)); e->attr_timeout = fs.timeout; e->entry_timeout = fs.timeout; auto newfd = openat(get_fs_fd(parent), name, O_PATH | O_NOFOLLOW); if (newfd == -1) return errno; auto res = fstatat(newfd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); if (res == -1) { auto saveerr = errno; close(newfd); if (fs.debug) cerr << "DEBUG: lookup(): fstatat failed" << endl; return saveerr; } if (e->attr.st_dev != fs.src_dev) { cerr << "WARNING: Mountpoints in the source directory tree will be hidden." << endl; return ENOTSUP; } else if (e->attr.st_ino == FUSE_ROOT_ID) { cerr << "ERROR: Source directory tree must not include inode " << FUSE_ROOT_ID << endl; return EIO; } SrcId id{ e->attr.st_ino, e->attr.st_dev }; unique_lock fs_lock{ fs.mutex }; Inode *inode_p; try { inode_p = &fs.inodes[id]; } catch (std::bad_alloc &) { return ENOMEM; } e->ino = reinterpret_cast(inode_p); Inode &inode{ *inode_p }; e->generation = inode.generation; if (inode.fd == -ENOENT) { // found unlinked inode if (fs.debug) cerr << "DEBUG: lookup(): inode " << e->attr.st_ino << " recycled; generation=" << inode.generation << endl; /* fallthrough to new inode but keep existing inode.nlookup */ } if (inode.fd > 0) { // found existing inode if (fs.debug) cerr << "DEBUG: lookup(): inode " << e->attr.st_ino << " (userspace) already known; fd = " << inode.fd << endl; inode.nlookup++; if (fs.debug) cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " << "inode " << inode.src_ino << " count " << inode.nlookup << endl; fs_lock.unlock(); close(newfd); } else { // no existing inode /* An unlinked inode (fd == -ENOENT) stays in fs.inodes and is * reachable by other threads, so this is a real lock */ lock_guard g{ inode.m }; inode.src_ino = e->attr.st_ino; inode.src_dev = e->attr.st_dev; inode.nlookup++; if (fs.debug) cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " << "inode " << inode.src_ino << " count " << inode.nlookup << endl; inode.fd = newfd; fs_lock.unlock(); if (fs.debug) cerr << "DEBUG: lookup(): created userspace inode " << e->attr.st_ino << "; fd = " << inode.fd << endl; } return 0; } static void sfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { fuse_entry_param e{}; auto err = do_lookup(parent, name, &e); if (err == ENOENT) { e.attr_timeout = fs.timeout; e.entry_timeout = fs.timeout; e.ino = e.attr.st_ino = 0; fuse_reply_entry(req, &e); } else if (err) { if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, err); } else { fuse_reply_entry(req, &e); } } static void mknod_symlink(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev, const char *link) { int res; Inode &inode_p = get_inode(parent); auto saverr = ENOMEM; if (S_ISDIR(mode)) res = mkdirat(inode_p.fd, name, mode); else if (S_ISLNK(mode)) res = symlinkat(link, inode_p.fd, name); else res = mknodat(inode_p.fd, name, mode, rdev); saverr = errno; if (res == -1) goto out; fuse_entry_param e; saverr = do_lookup(parent, name, &e); if (saverr) goto out; fuse_reply_entry(req, &e); return; out: if (saverr == ENFILE || saverr == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, saverr); } static void sfs_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { mknod_symlink(req, parent, name, mode, rdev, nullptr); } static void sfs_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { mknod_symlink(req, parent, name, S_IFDIR | mode, 0, nullptr); } static void sfs_symlink(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name) { mknod_symlink(req, parent, name, S_IFLNK, 0, link); } static void sfs_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t parent, const char *name) { Inode &inode = get_inode(ino); Inode &inode_p = get_inode(parent); fuse_entry_param e{}; e.attr_timeout = fs.timeout; e.entry_timeout = fs.timeout; char procname[64]; sprintf(procname, "/proc/self/fd/%i", inode.fd); auto res = linkat(AT_FDCWD, procname, inode_p.fd, name, AT_SYMLINK_FOLLOW); if (res == -1) { fuse_reply_err(req, errno); return; } res = fstatat(inode.fd, "", &e.attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); if (res == -1) { fuse_reply_err(req, errno); return; } e.ino = reinterpret_cast(&inode); { /* forget_one() reads the count under fs.mutex to decide that * an inode is unreferenced, so raise it under fs.mutex too */ lock_guard g_fs{ fs.mutex }; inode.nlookup++; if (fs.debug) cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " << "inode " << inode.src_ino << " count " << inode.nlookup << endl; } fuse_reply_entry(req, &e); return; } static void sfs_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { Inode &inode_p = get_inode(parent); auto res = unlinkat(inode_p.fd, name, AT_REMOVEDIR); fuse_reply_err(req, res == -1 ? errno : 0); } static void sfs_rename(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags) { Inode &inode_p = get_inode(parent); Inode &inode_np = get_inode(newparent); if (flags) { fuse_reply_err(req, EINVAL); return; } auto res = renameat(inode_p.fd, name, inode_np.fd, newname); fuse_reply_err(req, res == -1 ? errno : 0); } static void sfs_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { Inode &inode_p = get_inode(parent); // Release inode.fd before last unlink like nfsd EXPORT_OP_CLOSE_BEFORE_UNLINK // to test reused inode numbers. // Skip this when inode has an open file and when writeback cache is enabled. if (!fs.timeout) { fuse_entry_param e; auto err = do_lookup(parent, name, &e); if (err) { fuse_reply_err(req, err); return; } if (e.attr.st_nlink == 1) { Inode &inode = get_inode(e.ino); int release_fd = -1; { lock_guard g_fs{ fs.mutex }; lock_guard g{ inode.m }; if (inode.fd > 0 && !inode.nopen) { if (fs.debug) cerr << "DEBUG: unlink: release inode " << e.attr.st_ino << "; fd=" << inode.fd << endl; release_fd = inode.fd; inode.fd = -ENOENT; inode.generation++; } } /* closed only after the fd is unpublished, so no other * thread can hand it to a syscall once it is reused */ if (release_fd != -1) close(release_fd); } // decrease the ref which lookup above had increased forget_one(e.ino, 1); } auto res = unlinkat(inode_p.fd, name, 0); fuse_reply_err(req, res == -1 ? errno : 0); } static void forget_one(fuse_ino_t ino, uint64_t n) { Inode &inode = get_inode(ino); SrcId id; { lock_guard l{ inode.m }; if (n > inode.nlookup) { cerr << "INTERNAL ERROR: Negative lookup count for inode " << inode.src_ino << endl; abort(); } inode.nlookup -= n; if (fs.debug) cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " << "inode " << inode.src_ino << " count " << inode.nlookup << endl; if (inode.nlookup) return; id = { inode.src_ino, inode.src_dev }; } /* The inode may be erased and re-created between the two locks, so * look it up by key instead of reusing the reference and let a * resurrecting do_lookup() win the count check */ lock_guard g_fs{ fs.mutex }; auto it = fs.inodes.find(id); if (it == fs.inodes.end() || it->second.nlookup) return; if (fs.debug) cerr << "DEBUG: forget: cleaning up inode " << id.first << endl; fs.inodes.erase(it); } static void sfs_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { forget_one(ino, nlookup); fuse_reply_none(req); } static void sfs_forget_multi(fuse_req_t req, size_t count, fuse_forget_data *forgets) { for (int i = 0; i < count; i++) forget_one(forgets[i].ino, forgets[i].nlookup); fuse_reply_none(req); } static void sfs_readlink(fuse_req_t req, fuse_ino_t ino) { Inode &inode = get_inode(ino); char buf[PATH_MAX + 1]; auto res = readlinkat(inode.fd, "", buf, sizeof(buf)); if (res == -1) fuse_reply_err(req, errno); else if (res == sizeof(buf)) fuse_reply_err(req, ENAMETOOLONG); else { buf[res] = '\0'; fuse_reply_readlink(req, buf); } } struct DirHandle { DIR *dp{ nullptr }; off_t offset; // serialises readdir(); drop before fuse_reply_*, the reply may let // RELEASEDIR delete this handle std::mutex m; DirHandle() = default; DirHandle(const DirHandle &) = delete; DirHandle &operator=(const DirHandle &) = delete; ~DirHandle() { if (dp) closedir(dp); } }; static DirHandle *get_dir_handle(fuse_file_info *fi) { return reinterpret_cast(fi->fh); } static void sfs_opendir(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { Inode &inode = get_inode(ino); DIR *dp = nullptr; int fd; auto d = new (nothrow) DirHandle; if (d == nullptr) { fuse_reply_err(req, ENOMEM); return; } fd = openat(inode.fd, ".", O_RDONLY); if (fd == -1) goto out_errno; // On success, dir stream takes ownership of fd, so we // do not have to close it. dp = fdopendir(fd); if (dp == nullptr) goto out_errno; { // Make Helgrind happy - it can't know that there's an implicit // synchronization due to the fact that other threads cannot // access d until we've called fuse_reply_*. lock_guard g{ d->m }; d->dp = dp; d->offset = 0; } fi->fh = reinterpret_cast(d); if (fs.timeout) { fi->keep_cache = 1; fi->cache_readdir = 1; } fuse_reply_open(req, fi); return; out_errno: auto error = errno; delete d; if (error == ENFILE || error == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, error); } static bool is_dot_or_dotdot(const char *name) { return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); } static void do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, fuse_file_info *fi, const int plus) { auto d = get_dir_handle(fi); char *p; auto rem = size; int err = 0, count = 0; if (fs.debug) cerr << "DEBUG: readdir(): started with offset " << offset << endl; auto buf = new (nothrow) char[size]; if (!buf) { fuse_reply_err(req, ENOMEM); return; } p = buf; unique_lock l{ d->m }; if (offset != d->offset) { if (fs.debug) cerr << "DEBUG: readdir(): seeking to " << offset << endl; seekdir(d->dp, offset); d->offset = offset; } while (1) { bool did_lookup = false; struct dirent *entry; errno = 0; entry = readdir(d->dp); if (!entry) { if (errno) { err = errno; if (fs.debug) warn("DEBUG: readdir(): readdir failed with"); goto error; } break; // End of stream } d->offset = entry->d_off; fuse_entry_param e{}; size_t entsize; if (plus) { if (is_dot_or_dotdot(entry->d_name)) { /* fuse kernel ignores attributes for these and also does * not increase lookup count (see fuse_direntplus_link) */ e.attr.st_ino = entry->d_ino; e.attr.st_mode = entry->d_type << 12; } else { err = do_lookup(ino, entry->d_name, &e); if (err) goto error; did_lookup = true; } entsize = fuse_add_direntry_plus( req, p, rem, entry->d_name, &e, entry->d_off); } else { e.attr.st_ino = entry->d_ino; e.attr.st_mode = entry->d_type << 12; entsize = fuse_add_direntry(req, p, rem, entry->d_name, &e.attr, entry->d_off); } if (entsize > rem) { if (fs.debug) cerr << "DEBUG: readdir(): buffer full, returning data. " << endl; if (did_lookup) forget_one(e.ino, 1); break; } p += entsize; rem -= entsize; count++; if (fs.debug) { cerr << "DEBUG: readdir(): added to buffer: " << entry->d_name << ", ino " << e.attr.st_ino << ", offset " << entry->d_off << endl; } } 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) { if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; l.unlock(); fuse_reply_err(req, err); } else { if (fs.debug) cerr << "DEBUG: readdir(): returning " << count << " entries, curr offset " << d->offset << endl; l.unlock(); fuse_reply_buf(req, buf, size - rem); } delete[] buf; return; } static void sfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, fuse_file_info *fi) { // operation logging is done in readdir to reduce code duplication do_readdir(req, ino, size, offset, fi, 0); } static void sfs_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, fuse_file_info *fi) { // operation logging is done in readdir to reduce code duplication do_readdir(req, ino, size, offset, fi, 1); } static void sfs_releasedir(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { (void)ino; auto d = get_dir_handle(fi); delete d; fuse_reply_err(req, 0); } static void do_passthrough_open(fuse_req_t req, fuse_ino_t ino, int fd, fuse_file_info *fi) { Inode &inode = get_inode(ino); /* Setup a shared backing file on first open of an inode */ if (inode.backing_id) { if (fs.debug) cerr << "DEBUG: reusing shared backing file " << inode.backing_id << " for inode " << ino << endl; fi->backing_id = inode.backing_id; } else if (!(inode.backing_id = fuse_passthrough_open(req, fd))) { cerr << "DEBUG: fuse_passthrough_open failed for inode " << ino << ", disabling rw passthrough." << endl; fs.passthrough = false; } else { if (fs.debug) cerr << "DEBUG: setup shared backing file " << inode.backing_id << " for inode " << ino << endl; fi->backing_id = inode.backing_id; } /* open in passthrough mode must drop old page cache */ if (fi->backing_id) fi->keep_cache = false; } static void sfs_create_open_flags(fuse_file_info *fi) { if (fs.direct_io) fi->direct_io = 1; /* * fi->direct_io (FOPEN_DIRECT_IO) is set to benefit from * parallel_direct_writes, which kernel cannot do for plain O_DIRECT. * However, passthrough is preferred, but which is not possible when * FOPEN_DIRECT_IO is set. */ if (!fs.passthrough) { if (fi->flags & O_DIRECT) fi->direct_io = 1; } /* parallel_direct_writes feature depends on direct_io features. * To make parallel_direct_writes valid, need set fi->direct_io * in current function. */ fi->parallel_direct_writes = 1; fi->keep_cache = (fs.timeout != 0); fi->noflush = (fs.timeout == 0 && (fi->flags & O_ACCMODE) == O_RDONLY); } static void sfs_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, fuse_file_info *fi) { Inode &inode_p = get_inode(parent); auto fd = openat(inode_p.fd, name, (fi->flags | O_CREAT) & ~O_NOFOLLOW, mode); if (fd == -1) { auto err = errno; if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, err); return; } fi->fh = fd; fuse_entry_param e; auto err = do_lookup(parent, name, &e); if (err) { if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, err); return; } Inode &inode = get_inode(e.ino); { lock_guard g{ inode.m }; inode.nopen++; sfs_create_open_flags(fi); if (fs.passthrough) do_passthrough_open(req, e.ino, fd, fi); } fuse_reply_create(req, &e, fi); } #ifdef O_TMPFILE static Inode *create_new_inode(int fd, fuse_entry_param *e) { memset(e, 0, sizeof(*e)); e->attr_timeout = fs.timeout; e->entry_timeout = fs.timeout; auto res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); if (res == -1) { if (fs.debug) cerr << "DEBUG: lookup(): fstatat failed" << endl; return NULL; } SrcId id{ e->attr.st_ino, e->attr.st_dev }; unique_lock fs_lock{ fs.mutex }; Inode *p_inode; try { p_inode = &fs.inodes[id]; } catch (std::bad_alloc &) { return NULL; } e->ino = reinterpret_cast(p_inode); e->generation = p_inode->generation; lock_guard g{ p_inode->m }; p_inode->src_ino = e->attr.st_ino; p_inode->src_dev = e->attr.st_dev; p_inode->nlookup++; if (fs.debug) cerr << "DEBUG:" << __func__ << ":" << __LINE__ << " " << "inode " << p_inode->src_ino << " count " << p_inode->nlookup << endl; p_inode->fd = fd; fs_lock.unlock(); if (fs.debug) cerr << "DEBUG: lookup(): created userspace inode " << e->attr.st_ino << "; fd = " << p_inode->fd << endl; return p_inode; } static void sfs_tmpfile(fuse_req_t req, fuse_ino_t parent, mode_t mode, fuse_file_info *fi) { Inode &parent_inode = get_inode(parent); auto fd = openat(parent_inode.fd, ".", (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode); if (fd == -1) { auto err = errno; if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, err); return; } fi->fh = fd; fuse_entry_param e; Inode *inode = create_new_inode(dup(fd), &e); if (inode == NULL) { auto err = errno; cerr << "ERROR: could not create new inode." << endl; close(fd); fuse_reply_err(req, err); return; } { lock_guard g{ inode->m }; sfs_create_open_flags(fi); if (fs.passthrough) do_passthrough_open(req, e.ino, fd, fi); } fuse_reply_create(req, &e, fi); } #endif static void sfs_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, fuse_file_info *fi) { (void)ino; int res; int fd = dirfd(get_dir_handle(fi)->dp); if (datasync) res = fdatasync(fd); else res = fsync(fd); fuse_reply_err(req, res == -1 ? errno : 0); } static void sfs_open(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { Inode &inode = get_inode(ino); /* With writeback cache, kernel may send read requests even when userspace opened write-only */ if (fs.timeout && (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). However, no process should modify the * file in the underlying filesystem once it has been read, so * this is not a problem. */ if (fs.timeout && fi->flags & O_APPEND) fi->flags &= ~O_APPEND; /* Unfortunately we cannot use inode.fd, because this was opened with O_PATH (so it doesn't allow read/write access). */ auto fd = with_fd_path(inode.fd, [fi](const char *buf) { return open(buf, fi->flags & ~O_NOFOLLOW); }); if (fd == -1) { auto err = errno; if (err == ENFILE || err == EMFILE) cerr << "ERROR: Reached maximum number of file descriptors." << endl; fuse_reply_err(req, err); return; } { lock_guard g{ inode.m }; inode.nopen++; sfs_create_open_flags(fi); fi->fh = fd; if (fs.passthrough) do_passthrough_open(req, ino, fd, fi); } fuse_reply_open(req, fi); } static void sfs_release(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { Inode &inode = get_inode(ino); int backing_id = 0; { lock_guard g{ inode.m }; inode.nopen--; /* Close the shared backing file on last file close of an inode */ if (inode.backing_id && !inode.nopen) { backing_id = inode.backing_id; inode.backing_id = 0; } } if (backing_id) { if (fuse_passthrough_close(req, backing_id) < 0) { cerr << "DEBUG: fuse_passthrough_close failed for inode " << ino << " backing file " << backing_id << endl; } else if (fs.debug) { cerr << "DEBUG: closed backing file " << backing_id << " for inode " << ino << endl; } } close(fi->fh); fuse_reply_err(req, 0); } static void sfs_flush(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi) { (void)ino; auto res = close(dup(fi->fh)); fuse_reply_err(req, res == -1 ? errno : 0); } static void sfs_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, fuse_file_info *fi) { (void)ino; int res; if (datasync) res = fdatasync(fi->fh); else res = fsync(fi->fh); fuse_reply_err(req, res == -1 ? errno : 0); } static void do_read(fuse_req_t req, size_t size, off_t off, fuse_file_info *fi) { fuse_bufvec buf = FUSE_BUFVEC_INIT(size); char *payload = NULL; size_t payload_size = 0; int res = fuse_req_get_payload(req, &payload, &payload_size, NULL); /* * This is a demonstration how to use io-uring payload. For FUSE_BUF_IS_FD * it shouldn't make much of a difference because fuse_reply_data() -> * fuse_reply_data_uring() also has access to the payload and will * read directly from the FD into the payload. * It is more useful for file systems that need a buffer for decryption, * decompression, etc. */ if (res == 0) { /* This is an io-uring request - write directly to the payload */ assert(payload_size >= size); buf.buf[0].mem = payload; buf.buf[0].size = payload_size; res = pread(fi->fh, payload, size, off); if (res < 0) { fuse_reply_err(req, errno); return; } buf.buf[0].size = res; } else { buf.buf[0].flags = static_cast( FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK); buf.buf[0].fd = fi->fh; buf.buf[0].pos = off; } fuse_reply_data(req, &buf, FUSE_BUF_COPY_FLAGS); } static void sfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, fuse_file_info *fi) { (void)ino; if (fs.passthrough && !fs.direct_io) { cerr << "ERROR: fuse_passthrough read failed." << endl; fuse_reply_err(req, EIO); return; } do_read(req, size, off, fi); } static void do_write_buf(fuse_req_t req, size_t size, off_t off, fuse_bufvec *in_buf, fuse_file_info *fi) { fuse_bufvec out_buf = FUSE_BUFVEC_INIT(size); out_buf.buf[0].flags = static_cast(FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK); out_buf.buf[0].fd = fi->fh; out_buf.buf[0].pos = off; auto res = fuse_buf_copy(&out_buf, in_buf, FUSE_BUF_COPY_FLAGS); if (res < 0) fuse_reply_err(req, -res); else fuse_reply_write(req, (size_t)res); } static void sfs_write_buf(fuse_req_t req, fuse_ino_t ino, fuse_bufvec *in_buf, off_t off, fuse_file_info *fi) { (void)ino; if (fs.passthrough && !fs.direct_io) { cerr << "ERROR: fuse_passthrough write failed." << endl; fuse_reply_err(req, EIO); return; } auto size{ fuse_buf_size(in_buf) }; do_write_buf(req, size, off, in_buf, fi); } static void sfs_statfs(fuse_req_t req, fuse_ino_t ino) { struct statvfs stbuf; auto res = fstatvfs(get_fs_fd(ino), &stbuf); if (res == -1) fuse_reply_err(req, errno); else fuse_reply_statfs(req, &stbuf); } static void sfs_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, fuse_file_info *fi) { (void)ino; auto err = -do_fallocate(fi->fh, mode, offset, length); fuse_reply_err(req, err); } static void sfs_flock(fuse_req_t req, fuse_ino_t ino, fuse_file_info *fi, int op) { (void)ino; auto res = flock(fi->fh, op); fuse_reply_err(req, res == -1 ? errno : 0); } #ifdef HAVE_SETXATTR static void sfs_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { char *value = nullptr; Inode &inode = get_inode(ino); ssize_t ret; int saverr; char procname[64]; sprintf(procname, "/proc/self/fd/%i", inode.fd); if (size) { value = new (nothrow) char[size]; if (value == nullptr) { saverr = ENOMEM; goto out; } 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, nullptr, 0); if (ret == -1) goto out_err; fuse_reply_xattr(req, ret); } out_free: delete[] value; return; out_err: saverr = errno; out: fuse_reply_err(req, saverr); goto out_free; } static void sfs_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { char *value = nullptr; Inode &inode = get_inode(ino); ssize_t ret; int saverr; char procname[64]; sprintf(procname, "/proc/self/fd/%i", inode.fd); if (size) { value = new (nothrow) char[size]; if (value == nullptr) { saverr = ENOMEM; goto out; } 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, nullptr, 0); if (ret == -1) goto out_err; fuse_reply_xattr(req, ret); } out_free: delete[] value; return; out_err: saverr = errno; out: fuse_reply_err(req, saverr); goto out_free; } static void sfs_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { Inode &inode = get_inode(ino); ssize_t ret; int saverr; char procname[64]; sprintf(procname, "/proc/self/fd/%i", inode.fd); ret = setxattr(procname, name, value, size, flags); saverr = ret == -1 ? errno : 0; fuse_reply_err(req, saverr); } static void sfs_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { char procname[64]; Inode &inode = get_inode(ino); ssize_t ret; int saverr; sprintf(procname, "/proc/self/fd/%i", inode.fd); ret = removexattr(procname, name); saverr = ret == -1 ? errno : 0; fuse_reply_err(req, saverr); } #endif static void assign_operations(fuse_lowlevel_ops &sfs_oper) { sfs_oper.init = sfs_init; sfs_oper.lookup = sfs_lookup; sfs_oper.mkdir = sfs_mkdir; sfs_oper.mknod = sfs_mknod; sfs_oper.symlink = sfs_symlink; sfs_oper.link = sfs_link; sfs_oper.unlink = sfs_unlink; sfs_oper.rmdir = sfs_rmdir; sfs_oper.rename = sfs_rename; sfs_oper.forget = sfs_forget; sfs_oper.forget_multi = sfs_forget_multi; sfs_oper.getattr = sfs_getattr; sfs_oper.setattr = sfs_setattr; sfs_oper.readlink = sfs_readlink; sfs_oper.opendir = sfs_opendir; sfs_oper.readdir = sfs_readdir; sfs_oper.readdirplus = sfs_readdirplus; sfs_oper.releasedir = sfs_releasedir; sfs_oper.fsyncdir = sfs_fsyncdir; sfs_oper.create = sfs_create; #ifdef O_TMPFILE sfs_oper.tmpfile = sfs_tmpfile; #endif sfs_oper.open = sfs_open; sfs_oper.release = sfs_release; sfs_oper.flush = sfs_flush; sfs_oper.fsync = sfs_fsync; sfs_oper.read = sfs_read; sfs_oper.write_buf = sfs_write_buf; sfs_oper.statfs = sfs_statfs; sfs_oper.fallocate = sfs_fallocate; sfs_oper.flock = sfs_flock; #ifdef HAVE_SETXATTR sfs_oper.setxattr = sfs_setxattr; sfs_oper.getxattr = sfs_getxattr; sfs_oper.listxattr = sfs_listxattr; sfs_oper.removexattr = sfs_removexattr; #endif } static void print_usage(char *prog_name) { cout << "Usage: " << prog_name << " --help\n" << " " << prog_name << " [options] \n"; } static cxxopts::ParseResult parse_wrapper(cxxopts::Options &parser, int &argc, char **&argv) { try { return parser.parse(argc, argv); } catch (cxxopts::option_not_exists_exception &exc) { std::cout << argv[0] << ": " << exc.what() << std::endl; print_usage(argv[0]); exit(2); } } static void string_split(std::string s, std::vector &out, std::string delimiter) { size_t pos_start = 0, pos_end, delim_len = delimiter.length(); std::string token; while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { token = s.substr(pos_start, pos_end - pos_start); pos_start = pos_end + delim_len; out.push_back(token); } out.push_back(s.substr(pos_start)); } static std::string string_join(const std::vector &elems, char delim) { std::ostringstream out; for (auto ii = elems.begin(); ii != elems.end(); ++ii) { out << (*ii); if (ii + 1 != elems.end()) { out << delim; } } return out.str(); } static cxxopts::ParseResult parse_options(int argc, char **argv) { cxxopts::Options opt_parser(argv[0]); std::vector mount_options; opt_parser.add_options()("debug", "Enable filesystem debug messages")( "debug-fuse", "Enable libfuse debug messages")( "foreground", "Run in foreground")("help", "Print help")( "nocache", "Disable attribute all caching")( "nosplice", "Do not use splice(2) to transfer data")( "nopassthrough", "Do not use pass-through mode for read/write")( "single", "Run single-threaded")( "o", "Mount options (see mount.fuse(5) - only use if you know what " "you are doing)", cxxopts::value(mount_options))( "num-threads", "Number of libfuse worker threads", cxxopts::value()->default_value(SFS_DEFAULT_THREADS))( "clone-fd", "use separate fuse device fd for each thread")( "direct-io", "enable fuse kernel internal direct-io"); // FIXME: Find a better way to limit the try clause to just // opt_parser.parse() (cf. https://github.com/jarro2783/cxxopts/issues/146) auto options = parse_wrapper(opt_parser, argc, argv); if (options.count("help")) { print_usage(argv[0]); // Strip everything before the option list from the // default help string. auto help = opt_parser.help(); std::cout << std::endl << "options:" << help.substr(help.find("\n\n") + 1, string::npos); std::cout << "\nFuse lowlevel options:\n"; fuse_lowlevel_help(); exit(0); } else if (argc != 3) { std::cout << argv[0] << ": invalid number of arguments\n"; print_usage(argv[0]); exit(2); } fs.debug = options.count("debug") != 0; fs.debug_fuse = options.count("debug-fuse") != 0; fs.foreground = options.count("foreground") != 0; if (fs.debug || fs.debug_fuse) fs.foreground = true; fs.nosplice = options.count("nosplice") != 0; fs.passthrough = options.count("nopassthrough") == 0; fs.num_threads = options["num-threads"].as(); fs.clone_fd = options.count("clone-fd"); fs.direct_io = options.count("direct-io"); char *resolved_path = realpath(argv[1], NULL); if (resolved_path == NULL) warn("WARNING: realpath() failed with"); fs.source = std::string{ resolved_path }; free(resolved_path); std::vector flattened_mount_opts; for (auto opt : mount_options) { string_split(opt, flattened_mount_opts, ","); } bool found_fsname = false; for (auto opt : flattened_mount_opts) { if (opt.find("fsname=") == 0) { found_fsname = true; continue; } /* Filter out some obviously incorrect options. */ if (opt == "fd") { std::cout << argv[0] << ": Unsupported mount option: " << opt << "\n"; print_usage(argv[0]); exit(2); } } if (!found_fsname) { flattened_mount_opts.push_back("fsname=" + fs.source); } flattened_mount_opts.push_back("default_permissions"); fs.fuse_mount_options = string_join(flattened_mount_opts, ','); return options; } static void maximize_fd_limit() { struct rlimit lim {}; auto res = getrlimit(RLIMIT_NOFILE, &lim); if (res != 0) { warn("WARNING: getrlimit() failed with"); return; } lim.rlim_cur = lim.rlim_max; res = setrlimit(RLIMIT_NOFILE, &lim); if (res != 0) warn("WARNING: setrlimit() failed with"); } int main(int argc, char *argv[]) { struct fuse_loop_config *loop_config = NULL; // Parse command line options auto options{ parse_options(argc, argv) }; // We need an fd for every dentry in our the filesystem that the // kernel knows about. This is way more than most processes need, // so try to get rid of any resource softlimit. maximize_fd_limit(); // Initialize filesystem root fs.root.fd = -1; fs.root.nlookup = 9999; fs.timeout = options.count("nocache") ? 0 : 86400.0; struct stat stat; auto ret = lstat(fs.source.c_str(), &stat); if (ret == -1) err(1, "ERROR: failed to stat source (\"%s\")", fs.source.c_str()); if (!S_ISDIR(stat.st_mode)) errx(1, "ERROR: source is not a directory"); fs.src_dev = stat.st_dev; fs.root.fd = open(fs.source.c_str(), O_PATH); if (fs.root.fd == -1) err(1, "ERROR: open(\"%s\", O_PATH)", fs.source.c_str()); // Initialize fuse fuse_args args = FUSE_ARGS_INIT(0, nullptr); if (fuse_opt_add_arg(&args, argv[0]) || fuse_opt_add_arg(&args, "-o") || fuse_opt_add_arg(&args, fs.fuse_mount_options.c_str()) || (fs.debug_fuse && fuse_opt_add_arg(&args, "-odebug"))) errx(3, "ERROR: Out of memory adding arguments"); ret = -1; fuse_lowlevel_ops sfs_oper{}; assign_operations(sfs_oper); auto se = fuse_session_new(&args, &sfs_oper, sizeof(sfs_oper), &fs); if (se == nullptr) goto err_out1; if (fuse_set_signal_handlers(se) != 0) goto err_out2; if (fuse_set_fail_signal_handlers(se) != 0) goto err_out2; // Don't apply umask, use modes exactly as specified umask(0); // Mount and run main loop loop_config = fuse_loop_cfg_create(); if (fs.num_threads != -1) fuse_loop_cfg_set_max_threads(loop_config, fs.num_threads); fuse_loop_cfg_set_clone_fd(loop_config, fs.clone_fd); if (fuse_session_mount(se, argv[2]) != 0) goto err_out3; fuse_daemonize(fs.foreground); if (!fs.foreground) fuse_log_enable_syslog("passthrough-hp", LOG_PID | LOG_CONS, LOG_DAEMON); if (options.count("single")) ret = fuse_session_loop(se); else ret = fuse_session_loop_mt(se, loop_config); fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: fuse_loop_cfg_destroy(loop_config); fuse_opt_free_args(&args); if (!fs.foreground) fuse_log_close_syslog(); return ret ? 1 : 0; } fuse-3.18.3/example/passthrough_ll.c0000644000175000017500000007760315250106036016366 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * 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. * * 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 ## * \include passthrough_ll.c */ #define _GNU_SOURCE #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 18) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "passthrough_helpers.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; 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; 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 }, FUSE_OPT_END }; static void passthrough_ll_help(void) { printf( " -o writeback Enable writeback\n" " -o no_writeback Disable write back\n" " -o source=/home/dir Source directory to be mounted\n" " -o flock Enable flock\n" " -o no_flock Disable flock\n" " -o xattr Enable xattr\n" " -o no_xattr Disable xattr\n" " -o timeout=1.0 Caching timeout\n" " -o timeout=0/1 Timeout is set\n" " -o cache=never Disable cache\n" " -o cache=auto Auto enable cache\n" " -o cache=always Cache always\n"); } 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; bool has_flag; if (lo->writeback) { has_flag = fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE); if (lo->debug && has_flag) fuse_log(FUSE_LOG_DEBUG, "lo_init: activating writeback\n"); } if (lo->flock && conn->capable & FUSE_CAP_FLOCK_LOCKS) { has_flag = fuse_set_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); if (lo->debug && has_flag) fuse_log(FUSE_LOG_DEBUG, "lo_init: activating flock locks\n"); } /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } static void lo_destroy(void *userdata) { struct lo_data *lo = (struct lo_data*) userdata; while (lo->root.next != &lo->root) { struct lo_inode* next = lo->root.next; lo->root.next = next->next; close(next->fd); free(next); } } 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); int fd = fi ? fi->fh : lo_fd(req, ino); (void) fi; res = fstatat(fd, "", &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 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 { sprintf(procname, "/proc/self/fd/%i", ifd); res = utimensat(AT_FDCWD, procname, tv, 0); } 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 struct lo_inode *create_new_inode(int fd, struct fuse_entry_param *e, struct lo_data* lo) { struct lo_inode *inode = NULL; struct lo_inode *prev, *next; inode = calloc(1, sizeof(struct lo_inode)); if (!inode) return NULL; inode->refcount = 1; inode->fd = fd; 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); return inode; } static int fill_entry_param_new_inode(fuse_req_t req, fuse_ino_t parent, int fd, struct fuse_entry_param *e) { int res; struct lo_data *lo = lo_data(req); memset(e, 0, sizeof(*e)); e->attr_timeout = lo->timeout; e->entry_timeout = lo->timeout; res = fstatat(fd, "", &e->attr, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW); if (res == -1) return errno; e->ino = (uintptr_t) create_new_inode(dup(fd), e, lo); if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, " %lli/%d -> %lli\n", (unsigned long long) parent, fd, (unsigned long long) e->ino); return 0; } 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 { inode = create_new_inode(newfd, e, lo); if (!inode) goto out_err; } e->ino = (uintptr_t) inode; if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, " %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)) fuse_log(FUSE_LOG_DEBUG, "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 res; int saverr; struct lo_inode *dir = lo_inode(req, parent); struct fuse_entry_param e; res = mknod_wrapper(dir->fd, name, link, 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)) fuse_log(FUSE_LOG_DEBUG, " %lli/%s -> %lli\n", (unsigned long long) parent, name, (unsigned long long) e.ino); fuse_reply_entry(req, &e); return; out: 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 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; char procname[64]; int saverr; memset(&e, 0, sizeof(struct fuse_entry_param)); e.attr_timeout = lo->timeout; e.entry_timeout = lo->timeout; sprintf(procname, "/proc/self/fd/%i", inode->fd); res = linkat(AT_FDCWD, procname, lo_fd(req, parent), name, AT_SYMLINK_FOLLOW); 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)) fuse_log(FUSE_LOG_DEBUG, " %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)) { fuse_log(FUSE_LOG_DEBUG, " 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); fuse_reply_none(req); } 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); fuse_reply_none(req); } 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'; fuse_reply_readlink(req, buf); } struct lo_dirp { 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; int fd = -1; d = calloc(1, sizeof(struct lo_dirp)); if (d == NULL) goto out_err; fd = openat(lo_fd(req, ino), ".", O_RDONLY); if (fd == -1) goto out_errno; d->dp = fdopendir(fd); if (d->dp == NULL) goto out_errno; d->offset = 0; d->entry = NULL; fi->fh = (uintptr_t) d; if (lo->cache != CACHE_NEVER) fi->cache_readdir = 1; if (lo->cache == CACHE_ALWAYS) fi->keep_cache = 1; fuse_reply_open(req, fi); return; out_errno: error = errno; out_err: if (d) { if (fd != -1) close(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_tmpfile(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi) { int fd; struct lo_data *lo = lo_data(req); struct fuse_entry_param e; int err; if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, "lo_tmpfile(parent=%" PRIu64 ")\n", parent); fd = openat(lo_fd(req, parent), ".", (fi->flags | O_TMPFILE) & ~O_NOFOLLOW, mode); 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; /* parallel_direct_writes feature depends on direct_io features. To make parallel_direct_writes valid, need set fi->direct_io in current function. */ fi->parallel_direct_writes = 1; err = fill_entry_param_new_inode(req, parent, fd, &e); if (err) fuse_reply_err(req, err); else fuse_reply_create(req, &e, fi); } 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 lo_data *lo = lo_data(req); struct fuse_entry_param e; int err; if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, "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; if (lo->cache == CACHE_NEVER) fi->direct_io = 1; else if (lo->cache == CACHE_ALWAYS) fi->keep_cache = 1; /* parallel_direct_writes feature depends on direct_io features. To make parallel_direct_writes valid, need set fi->direct_io in current function. */ fi->parallel_direct_writes = 1; 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)) fuse_log(FUSE_LOG_DEBUG, "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; /* Enable direct_io when open has flags O_DIRECT to enjoy the feature parallel_direct_writes (i.e., to get a shared lock, not exclusive lock, for writes to the same file in the kernel). */ if (fi->flags & O_DIRECT) fi->direct_io = 1; /* parallel_direct_writes feature depends on direct_io features. To make parallel_direct_writes valid, need set fi->direct_io in current function. */ fi->parallel_direct_writes = 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)) fuse_log(FUSE_LOG_DEBUG, "lo_read(ino=%" PRIu64 ", size=%zd, " "off=%lu)\n", ino, size, (unsigned long) offset); buf.buf[0].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; buf.buf[0].fd = fi->fh; buf.buf[0].pos = offset; fuse_reply_data(req, &buf, FUSE_BUF_SPLICE_MOVE); } 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].flags = FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK; out_buf.buf[0].fd = fi->fh; out_buf.buf[0].pos = off; if (lo_debug(req)) fuse_log(FUSE_LOG_DEBUG, "lo_write(ino=%" PRIu64 ", size=%zd, off=%jd)\n", ino, out_buf.buf[0].size, (intmax_t) 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; err = -do_fallocate(fi->fh, mode, 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)) { fuse_log(FUSE_LOG_DEBUG, "lo_getxattr(ino=%" PRIu64 ", name=%s size=%zd)\n", ino, name, size); } 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)) { fuse_log(FUSE_LOG_DEBUG, "lo_listxattr(ino=%" PRIu64 ", size=%zd)\n", ino, size); } 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)) { fuse_log(FUSE_LOG_DEBUG, "lo_setxattr(ino=%" PRIu64 ", name=%s value=%s size=%zd)\n", ino, name, value, size); } 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)) { fuse_log(FUSE_LOG_DEBUG, "lo_removexattr(ino=%" PRIu64 ", name=%s)\n", ino, name); } 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)) fuse_log(FUSE_LOG_DEBUG, "%s(ino=%lld fd=%lld off=%jd ino=%lld fd=%lld off=%jd, size=%zd, flags=0x%x)\n", __func__, (unsigned long long)ino_in, (unsigned long long)fi_in->fh, (intmax_t) off_in, (unsigned long long)ino_out, (unsigned long long)fi_out->fh, (intmax_t) 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 void lo_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi) { off_t res; (void)ino; res = lseek(fi->fh, off, whence); if (res != -1) fuse_reply_lseek(req, res); else fuse_reply_err(req, errno); } #ifdef HAVE_STATX static void lo_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi) { struct lo_data *lo = lo_data(req); struct statx buf; int res; int fd; if (fi) fd = fi->fh; else fd = lo_fd(req, ino); res = statx(fd, "", flags | AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW, mask, &buf); if (res == -1) fuse_reply_err(req, errno); else fuse_reply_statx(req, 0, &buf, lo->timeout); } #endif static const struct fuse_lowlevel_ops lo_oper = { .init = lo_init, .destroy = lo_destroy, .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, .tmpfile = lo_tmpfile, .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 .lseek = lo_lseek, #ifdef HAVE_STATX .statx = lo_statx, #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 fuse_loop_config *config; 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] \n\n", argv[0]); fuse_cmdline_help(); fuse_lowlevel_help(); passthrough_ll_help(); ret = 0; goto err_out1; } else if (opts.show_version) { printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); ret = 0; goto err_out1; } if(opts.mountpoint == NULL) { printf("usage: %s [options] \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) { fuse_log(FUSE_LOG_ERR, "failed to stat source (\"%s\"): %m\n", lo.source); exit(1); } if (!S_ISDIR(stat.st_mode)) { fuse_log(FUSE_LOG_ERR, "source is not a directory\n"); exit(1); } } else { lo.source = strdup("/"); if(!lo.source) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); exit(1); } } 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) { fuse_log(FUSE_LOG_ERR, "timeout is negative (%lf)\n", lo.timeout); exit(1); } lo.root.fd = open(lo.source, O_PATH); if (lo.root.fd == -1) { fuse_log(FUSE_LOG_ERR, "open(\"%s\", O_PATH): %m\n", lo.source); exit(1); } se = fuse_session_new(&args, &lo_oper, sizeof(lo_oper), &lo); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) 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 { config = fuse_loop_cfg_create(); fuse_loop_cfg_set_clone_fd(config, opts.clone_fd); fuse_loop_cfg_set_max_threads(config, opts.max_threads); ret = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); config = NULL; } fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: free(opts.mountpoint); fuse_opt_free_args(&args); if (lo.root.fd >= 0) close(lo.root.fd); free(lo.source); return ret ? 1 : 0; } fuse-3.18.3/example/poll.c0000644000175000017500000001502215250106036014261 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * This example illustrates how to write a FUSE file system that * supports polling for changes that don't come through the kernel. It * can be tested with the poll_client.c program. * * Compile with: * * gcc -Wall poll.c `pkg-config fuse3 --cflags --libs` -o poll * * ## Source code ## * \include poll.c */ #define FUSE_USE_VERSION 31 #include #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 up to 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 _Atomic bool fsel_stop = false; static pthread_t fsel_producer_thread; 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 void fsel_destroy(void *private_data) { (void)private_data; fsel_stop = true; pthread_join(fsel_producer_thread, NULL); } static int fsel_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void) fi; 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, enum fuse_readdir_flags flags) { char name[2] = { }; int i; (void) offset; (void) fi; (void) flags; if (strcmp(path, "/") != 0) return -ENOENT; for (i = 0; i < FSEL_FILES; i++) { name[0] = fsel_hex_map[i]; filler(buf, name, NULL, 0, FUSE_FILL_DIR_DEFAULTS); } 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 & O_ACCMODE) != 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 const struct fuse_operations fsel_oper = { .destroy = fsel_destroy, .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 (!fsel_stop) { 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_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(&fsel_producer_thread, &attr, fsel_producer, NULL); if (errno) { perror("pthread_create"); return 1; } ret = fuse_main(argc, argv, &fsel_oper, NULL); return ret; } fuse-3.18.3/example/poll_client.c0000644000175000017500000000310215250106036015613 0ustar berndbernd/* 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 GPLv2. See the file GPL2.txt. */ /** @file * * This program tests the poll.c example file systsem. * * Compile with: * * gcc -Wall poll_client.c -o poll_client * * ## Source code ## * \include poll_client.c */ #include #include #include #include #include #include #include #include #include #include int main(void) { static const char hex_map[] = "0123456789ABCDEF"; const size_t fsel_files = sizeof(hex_map) - 1; int fds[sizeof(hex_map) - 1]; size_t i, tries; int 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; for (tries = 0; tries < fsel_files; tries++) { 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("%zX:", i); rc = read(fds[i], buf, sizeof(buf)); if (rc < 0) { perror("read"); return 1; } printf("%02d ", rc); } printf("\n"); } return 0; } fuse-3.18.3/example/printcap.c0000644000175000017500000000745215250106036015143 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2017 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /** @file * * minimal example filesystem that prints out all capabilities * supported by the kernel and then exits. * * Compile with: * * gcc -Wall printcap.c `pkg-config fuse3 --cflags --libs` -o printcap * * ## Source code ## * \include printcap.c */ #define FUSE_USE_VERSION 31 #include #include #include #include #include struct fuse_session *se; // Define a structure to hold capability information struct cap_info { uint64_t flag; const char *name; }; // Define an array of all capabilities static const struct cap_info capabilities[] = { {FUSE_CAP_ASYNC_READ, "FUSE_CAP_ASYNC_READ"}, {FUSE_CAP_POSIX_LOCKS, "FUSE_CAP_POSIX_LOCKS"}, {FUSE_CAP_ATOMIC_O_TRUNC, "FUSE_CAP_ATOMIC_O_TRUNC"}, {FUSE_CAP_EXPORT_SUPPORT, "FUSE_CAP_EXPORT_SUPPORT"}, {FUSE_CAP_DONT_MASK, "FUSE_CAP_DONT_MASK"}, {FUSE_CAP_SPLICE_MOVE, "FUSE_CAP_SPLICE_MOVE"}, {FUSE_CAP_SPLICE_READ, "FUSE_CAP_SPLICE_READ"}, {FUSE_CAP_SPLICE_WRITE, "FUSE_CAP_SPLICE_WRITE"}, {FUSE_CAP_FLOCK_LOCKS, "FUSE_CAP_FLOCK_LOCKS"}, {FUSE_CAP_IOCTL_DIR, "FUSE_CAP_IOCTL_DIR"}, {FUSE_CAP_AUTO_INVAL_DATA, "FUSE_CAP_AUTO_INVAL_DATA"}, {FUSE_CAP_READDIRPLUS, "FUSE_CAP_READDIRPLUS"}, {FUSE_CAP_READDIRPLUS_AUTO, "FUSE_CAP_READDIRPLUS_AUTO"}, {FUSE_CAP_ASYNC_DIO, "FUSE_CAP_ASYNC_DIO"}, {FUSE_CAP_WRITEBACK_CACHE, "FUSE_CAP_WRITEBACK_CACHE"}, {FUSE_CAP_NO_OPEN_SUPPORT, "FUSE_CAP_NO_OPEN_SUPPORT"}, {FUSE_CAP_PARALLEL_DIROPS, "FUSE_CAP_PARALLEL_DIROPS"}, {FUSE_CAP_POSIX_ACL, "FUSE_CAP_POSIX_ACL"}, {FUSE_CAP_CACHE_SYMLINKS, "FUSE_CAP_CACHE_SYMLINKS"}, {FUSE_CAP_NO_OPENDIR_SUPPORT, "FUSE_CAP_NO_OPENDIR_SUPPORT"}, {FUSE_CAP_EXPLICIT_INVAL_DATA, "FUSE_CAP_EXPLICIT_INVAL_DATA"}, {FUSE_CAP_EXPIRE_ONLY, "FUSE_CAP_EXPIRE_ONLY"}, {FUSE_CAP_SETXATTR_EXT, "FUSE_CAP_SETXATTR_EXT"}, {FUSE_CAP_HANDLE_KILLPRIV, "FUSE_CAP_HANDLE_KILLPRIV"}, {FUSE_CAP_HANDLE_KILLPRIV_V2, "FUSE_CAP_HANDLE_KILLPRIV_V2"}, {FUSE_CAP_DIRECT_IO_ALLOW_MMAP, "FUSE_CAP_DIRECT_IO_ALLOW_MMAP"}, {FUSE_CAP_NO_EXPORT_SUPPORT, "FUSE_CAP_NO_EXPORT_SUPPORT"}, {FUSE_CAP_PASSTHROUGH, "FUSE_CAP_PASSTHROUGH"}, // Add any new capabilities here {0, NULL} // Sentinel to mark the end of the array }; static void print_capabilities(struct fuse_conn_info *conn) { printf("Capabilities:\n"); for (const struct cap_info *cap = capabilities; cap->name != NULL; cap++) { if (fuse_get_feature_flag(conn, cap->flag)) { printf("\t%s\n", cap->name); } } } static void pc_init(void *userdata, struct fuse_conn_info *conn) { (void) userdata; printf("Protocol version: %d.%d\n", conn->proto_major, conn->proto_minor); print_capabilities(conn); fuse_session_exit(se); } static const struct fuse_lowlevel_ops pc_oper = { .init = pc_init, }; int main(int argc, char **argv) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); char *mountpoint; int ret = -1; mountpoint = strdup("/tmp/fuse_printcap_XXXXXX"); if(mkdtemp(mountpoint) == NULL) { perror("mkdtemp"); return 1; } printf("FUSE library version %s\n", fuse_pkgversion()); fuse_lowlevel_version(); se = fuse_session_new(&args, &pc_oper, sizeof(pc_oper), NULL); if (se == NULL) goto err_out1; if (fuse_set_signal_handlers(se) != 0) goto err_out2; if (fuse_session_mount(se, mountpoint) != 0) goto err_out3; ret = fuse_session_loop(se); fuse_session_unmount(se); err_out3: fuse_remove_signal_handlers(se); err_out2: fuse_session_destroy(se); err_out1: rmdir(mountpoint); free(mountpoint); fuse_opt_free_args(&args); return ret ? 1 : 0; } fuse-3.18.3/example/usdt.bt0000644000175000017500000000075215250106036014461 0ustar berndbernd#!/usr/bin/env bpftrace // To run, do `sudo bpftrace usdt.bt` usdt:../build/lib/libfuse3.so:libfuse:request_receive { printf("libfuse:request_receive hit, err=%d\n", arg0); } usdt:../build/lib/libfuse3.so:libfuse:request_process { printf("libfuse:request_process hit, opcode=%u, unique=%u\n", arg0, arg1); } usdt:../build/lib/libfuse3.so:libfuse:request_reply { printf("libfuse:request_reply hit, unique=%lu, len=%u, err=%u, reply_err=%d\n", arg0, arg1, arg2, arg3); } fuse-3.18.3/include/0000755000175000017500000000000015250106036013137 5ustar berndberndfuse-3.18.3/include/cuse_lowlevel.h0000644000175000017500000000501315250106036016157 0ustar berndbernd/* 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 LGPL2.txt. 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-3.18.3/include/fuse.h0000644000175000017500000014074215250106036014262 0ustar berndbernd/* 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 LGPL2.txt. */ #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. */ #include "fuse_common.h" #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* ----------------------------------------------------------- * * Basic FUSE API * * ----------------------------------------------------------- */ /* Forward declaration */ struct statx; /** Handle for a FUSE filesystem */ struct fuse; /** * Readdir flags, passed to ->readdir() */ enum fuse_readdir_flags { /** * "Plus" mode. * * The kernel wants to prefill the inode cache during readdir. The * filesystem may honour this by filling in the attributes and setting * FUSE_FILL_DIR_FLAGS for the filler function. The filesystem may also * just ignore this flag completely. */ FUSE_READDIR_DEFAULTS = 0, FUSE_READDIR_PLUS = (1 << 0) }; /** * Readdir flags, passed to fuse_fill_dir_t callback. */ enum fuse_fill_dir_flags { /** * "Plus" mode: file attributes are valid * * The attributes are used by the kernel to prefill the inode cache * during a readdir. * * It is okay to set FUSE_FILL_DIR_PLUS if FUSE_READDIR_PLUS is not set * and vice versa. * * This does not make libfuse honor the 'st_ino' field. That is * controlled by the 'use_ino' option instead. */ FUSE_FILL_DIR_DEFAULTS = 0, FUSE_FILL_DIR_PLUS = (1 << 1) }; /** Function to add an entry in a readdir() operation * * The *off* parameter can be any non-zero value that enables the * filesystem to identify the current point in the directory * stream. It does not need to be the actual physical position. A * value of zero is reserved to indicate that seeking in directories * is not supported. * * @param buf the buffer passed to the readdir() operation * @param name the file name of the directory entry * @param stbuf file attributes, can be NULL * @param off offset of the next entry or zero * @param flags fill flags * @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, enum fuse_fill_dir_flags flags); /** * Configuration of the high-level API * * This structure is initialized from the arguments passed to * fuse_new(), and then passed to the file system's init() handler * which should ensure that the configuration is compatible with the * file system implementation. * * Note: this data structure is ABI sensitive, new options have to be * appended at the end of the structure */ struct fuse_config { /** * If `set_gid` is non-zero, the st_gid attribute of each file * is overwritten with the value of `gid`. */ int32_t set_gid; uint32_t gid; /** * If `set_uid` is non-zero, the st_uid attribute of each file * is overwritten with the value of `uid`. */ int32_t set_uid; uint32_t uid; /** * If `set_mode` is non-zero, the any permissions bits set in * `umask` are unset in the st_mode attribute of each file. */ int32_t set_mode; uint32_t umask; /** * The timeout in seconds for which name lookups will be * cached. */ double entry_timeout; /** * The timeout in seconds for which a negative lookup will be * cached. This means, that if file did not exist (lookup * returned ENOENT), the lookup will only be redone after the * timeout, and the file/directory will be assumed to not * exist until then. A value of zero means that negative * lookups are not cached. */ double negative_timeout; /** * The timeout in seconds for which file/directory attributes * (as returned by e.g. the `getattr` handler) are cached. */ double attr_timeout; /** * Allow requests to be interrupted */ int32_t intr; /** * Specify which signal number to send to the filesystem when * a request is interrupted. The default is hardcoded to * USR1. */ int32_t intr_signal; /** * Normally, FUSE assigns inodes to paths only for as long as * the kernel is aware of them. With this option inodes are * instead remembered for at least this many seconds. This * will require more memory, but may be necessary when using * applications that make use of inode numbers. * * A number of -1 means that inodes will be remembered for the * entire life-time of the file-system process. */ int32_t remember; /** * The default behavior is that if an open file is deleted, * the file is renamed to a hidden file (.fuse_hiddenXXX), and * only removed when the file is finally released. This * relieves the filesystem implementation of having to deal * with this problem. This option disables the hiding * behavior, and files are removed immediately in an unlink * operation (or in a rename operation which overwrites an * existing file). * * It is recommended that you not use the hard_remove * option. When hard_remove is set, the following libc * functions fail on unlinked files (returning errno of * ENOENT): read(2), write(2), fsync(2), close(2), f*xattr(2), * ftruncate(2), fstat(2), fchmod(2), fchown(2) */ int32_t hard_remove; /** * Honor the st_ino field in the functions getattr() and * fill_dir(). This value is used to fill in the st_ino field * in the stat(2), lstat(2), fstat(2) functions and the d_ino * field in the readdir(2) function. The filesystem does not * have to guarantee uniqueness, however some applications * rely on this value being unique for the whole filesystem. * * Note that this does *not* affect the inode that libfuse * and the kernel use internally (also called the "nodeid"). */ int32_t use_ino; /** * If use_ino option is not given, still try to fill in the * d_ino field in readdir(2). If the name was previously * looked up, and is still in the cache, the inode number * found there will be used. Otherwise it will be set to -1. * If use_ino option is given, this option is ignored. */ int32_t readdir_ino; /** * This option disables the use of page cache (file content cache) * in the kernel for this filesystem. This has several affects: * * 1. Each read(2) or write(2) system call will initiate one * or more read or write operations, data will not be * cached in the kernel. * * 2. The return value of the read() and write() system calls * will correspond to the return values of the read and * write operations. This is useful for example if the * file size is not known in advance (before reading it). * * Internally, enabling this option causes fuse to set the * `direct_io` field of `struct fuse_file_info` - overwriting * any value that was put there by the file system. */ int32_t direct_io; /** * This option disables flushing the cache of the file * contents on every open(2). This should only be enabled on * filesystems where the file data is never changed * externally (not through the mounted FUSE filesystem). Thus * it is not suitable for network filesystems and other * intermediate filesystems. * * NOTE: if this option is not specified (and neither * direct_io) data is still cached after the open(2), so a * read(2) system call will not always initiate a read * operation. * * Internally, enabling this option causes fuse to set the * `keep_cache` field of `struct fuse_file_info` - overwriting * any value that was put there by the file system. */ int32_t kernel_cache; /** * This option is an alternative to `kernel_cache`. Instead of * unconditionally keeping cached data, the cached data is * invalidated on open(2) if if the modification time or the * size of the file has changed since it was last opened. */ int32_t auto_cache; /* * The timeout in seconds for which file attributes are cached * for the purpose of checking if auto_cache should flush the * file data on open. */ int32_t ac_attr_timeout_set; double ac_attr_timeout; /** * If this option is given the file-system handlers for the * following operations will not receive path information: * read, write, flush, release, fallocate, fsync, readdir, * releasedir, fsyncdir, lock, ioctl and poll. * * For the truncate, getattr, chmod, chown and utimens * operations the path will be provided only if the struct * fuse_file_info argument is NULL. */ int32_t nullpath_ok; /** * These 3 options are used by libfuse internally and * should not be touched. */ int32_t show_help; char *modules; int32_t debug; /** * `fmask` and `dmask` function the same way as `umask`, but apply * to files and directories separately. If non-zero, `fmask` and * `dmask` take precedence over the `umask` setting. */ uint32_t fmask; uint32_t dmask; /** * By default, fuse waits for all pending writes to complete * and calls the FLUSH operation on close(2) of every fuse fd. * With this option, wait and FLUSH are not done for read-only * fuse fd, similar to the behavior of NFS/SMB clients. */ int32_t no_rofd_flush; /** * Allow parallel direct-io writes to operate on the same file. * * FUSE implementations which do not handle parallel writes on * same file/region should NOT enable this option at all as it * might lead to data inconsistencies. * * For the FUSE implementations which have their own mechanism * of cache/data integrity are beneficiaries of this setting as * it now open doors to parallel writes on the same file (without * enabling this setting, all direct writes on the same file are * serialized, resulting in huge data bandwidth loss). */ int32_t parallel_direct_writes; /** * Reserved for future use. */ uint32_t flags; /** * Reserved for future use. */ uint64_t reserved[48]; }; /** * 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. */ 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. 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. */ int (*getattr) (const char *, struct stat *, struct fuse_file_info *fi); /** Read the target of a symbolic link * * The buffer should be filled with a null terminated string. The * buffer size argument includes the space for the terminating * null character. If the linkname is too long to fit in the * buffer, it should be truncated. The return value should be 0 * for success. */ int (*readlink) (const char *, char *, size_t); /** Create a file node * * This is called for creation of all non-directory, non-symlink * nodes. If the filesystem defines a create() method, then for * regular files that will be called instead. */ int (*mknod) (const char *, mode_t, dev_t); /** Create a directory * * Note that the mode argument may not have the type specification * bits set, i.e. S_ISDIR(mode) can be false. To obtain the * correct directory type bits use mode|S_IFDIR * */ int (*mkdir) (const char *, mode_t); /** 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 * * *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. */ int (*rename) (const char *, const char *, unsigned int flags); /** Create a hard link to a file */ int (*link) (const char *, const char *); /** Change the permission bits of a file * * `fi` will always be NULL if the file is not currently open, but * may also be NULL if the file is open. */ int (*chmod) (const char *, mode_t, struct fuse_file_info *fi); /** Change the owner and group of a file * * `fi` will always be NULL if the file is not currently 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. */ int (*chown) (const char *, uid_t, gid_t, struct fuse_file_info *fi); /** Change the size of a file * * `fi` will always be NULL if the file is not currently 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. */ int (*truncate) (const char *, off_t, struct fuse_file_info *fi); /** 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, O_EXEC, O_SEARCH) * 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 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 sent * to the filesystem process. * */ 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. */ 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). * * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is * expected to reset the setuid and setgid bits. */ int (*write) (const char *, const char *, size_t, off_t, struct fuse_file_info *); /** Get file system statistics * * The 'f_favail', 'f_fsid' and 'f_flag' fields are ignored */ 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, as opposed to * release which is called on the close of the last file descriptor for * a file. Under Linux, errors returned by flush() will be passed to * userspace as errors from close(), so flush() is a good place to write * back any cached dirty data. However, many applications ignore errors * on close(), and on non-Linux systems, close() may succeed even if flush() * returns an error. For these reasons, filesystems should not assume * that errors returned by flush will ever be noticed or even * delivered. * * NOTE: The flush() method may be called more than once for each * open(). This happens if more than one file descriptor refers to an * open file handle, e.g. 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 be called at any * particular point. It may be called more times than expected, or not * at all. * * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html */ 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 handle. 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. */ 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. */ 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. */ int (*opendir) (const char *, struct fuse_file_info *); /** 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'. * * When FUSE_READDIR_PLUS is not set, only some parameters of the * fill function (the fuse_fill_dir_t parameter) are actually used: * The file type (which is part of stat::st_mode) is used. And if * fuse_config::use_ino is set, the inode (stat::st_ino) is also * used. The other fields are ignored when FUSE_READDIR_PLUS is not * set. */ int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *, enum fuse_readdir_flags); /** Release directory * * If the directory has been removed after the call to opendir, the * path parameter will be NULL. */ int (*releasedir) (const char *, struct fuse_file_info *); /** Synchronize directory contents * * If the directory has been removed after the call to opendir, the * path parameter will be NULL. * * If the datasync parameter is non-zero, then only the user data * should be flushed, not the meta data */ int (*fsyncdir) (const char *, int, struct fuse_file_info *); /** * 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(). */ void *(*init) (struct fuse_conn_info *conn, struct fuse_config *cfg); /** * Clean up filesystem * * Called on filesystem exit. */ void (*destroy) (void *private_data); /** * 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 */ 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. */ int (*create) (const char *, mode_t, 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. */ 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. * * `fi` will always be NULL if the file is not currently open, but * may also be NULL if the file is open. * * See the utimensat(2) man page for details. */ int (*utimens) (const char *, const struct timespec tv[2], struct fuse_file_info *fi); /** * 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 */ int (*bmap) (const char *, size_t blocksize, uint64_t *idx); #if FUSE_USE_VERSION < 35 int (*ioctl) (const char *, int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); #else /** * 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. * * Note : the unsigned long request submitted by the application * is truncated to 32 bits. */ int (*ioctl) (const char *, unsigned int cmd, void *arg, struct fuse_file_info *, unsigned int flags, void *data); #endif /** * 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. */ 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. * * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is * expected to reset the setuid and setgid bits. */ 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. */ 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. */ 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. */ int (*fallocate) (const char *, int, off_t, off_t, struct fuse_file_info *); /** * Copy a range of data from one file to another * * Performs an optimized copy between two file descriptors without the * additional cost of transferring data through the FUSE kernel module * to user space (glibc) and then back into the FUSE filesystem again. * * In case this method is not implemented, applications are expected to * fall back to a regular file copy. (Some glibc versions did this * emulation automatically, but the emulation has been removed from all * glibc release branches.) */ 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); /** * Find next data or hole after the specified offset */ off_t (*lseek) (const char *, off_t off, int whence, struct fuse_file_info *); /** * Get extended file attributes. * * fi may be NULL. * * If path is NULL, then the AT_EMPTY_PATH bit in flags will be * already set. */ int (*statx)(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi); }; /** 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; /** Process ID of the calling thread */ pid_t pid; /** Private filesystem data */ void *private_data; /** Umask of the calling process */ mode_t umask; }; /** * The real main function * * Do not call this directly, use fuse_main() */ int fuse_main_real_versioned(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data); static inline int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { struct libfuse_version version = { .major = FUSE_MAJOR_VERSION, .minor = FUSE_MINOR_VERSION, .hotfix = FUSE_HOTFIX_VERSION, .padding = 0 }; fuse_log(FUSE_LOG_ERR, "%s is a libfuse internal function, please use fuse_main()\n", __func__); return fuse_main_real_versioned(argc, argv, op, op_size, &version, user_data); } /** * Main function of FUSE. * * This is for the lazy. This is all that has to be called from the * main() function. * * This function does the following: * - parses command line options, and handles --help and * --version * - installs signal handlers for INT, HUP, TERM and PIPE * - registers an exit handler to unmount the filesystem on program exit * - creates a fuse handle * - registers the operations * - calls either the single-threaded or the multi-threaded event loop * * Most file systems will have to parse some file-system specific * arguments before calling this function. It is recommended to do * this with fuse_opt_parse() and a processing function that passes * through any unknown options (this can also be achieved by just * passing NULL as the processing function). That way, the remaining * options can be passed directly to fuse_main(). * * fuse_main() accepts all options that can be passed to * fuse_parse_cmdline(), fuse_new(), or fuse_session_new(). * * Option parsing skips argv[0], which is assumed to contain the * program name. This element must always be present and is used to * construct a basic ``usage: `` message for the --help * output. argv[0] may also be set to the empty string. In this case * the usage message is suppressed. This can be used by file systems * to print their own usage line first. See hello.c for an example of * how to do this. * * Note: this is currently implemented as a macro. * * The following error codes may be returned from fuse_main(): * 1: Invalid option arguments * 2: No mount point specified * 3: FUSE setup failed * 4: Mounting failed * 5: Failed to daemonize (detach from session) * 6: Failed to set up signal handlers * 7: An error occurred during the life of the file system * * @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 private_data Initial value for the `private_data` * field of `struct fuse_context`. May be overridden by the * `struct fuse_operations.init` handler. * @return 0 on success, nonzero on failure * * Example usage, see hello.c */ static inline int fuse_main_fn(int argc, char *argv[], const struct fuse_operations *op, void *user_data) { struct libfuse_version version = { .major = FUSE_MAJOR_VERSION, .minor = FUSE_MINOR_VERSION, .hotfix = FUSE_HOTFIX_VERSION, .padding = 0 }; return fuse_main_real_versioned(argc, argv, op, sizeof(*(op)), &version, user_data); } #define fuse_main(argc, argv, op, user_data) \ fuse_main_fn(argc, argv, op, user_data) /* ----------------------------------------------------------- * * More detailed API * * ----------------------------------------------------------- */ /** * Print available options (high- and low-level) to stdout. This is * not an exhaustive list, but includes only those options that may be * of interest to an end-user of a file system. * * The function looks at the argument vector only to determine if * there are additional modules to be loaded (module=foo option), * and attempts to call their help functions as well. * * @param args the argument vector. */ void fuse_lib_help(struct fuse_args *args); /* Do not call this directly, use fuse_new() instead */ struct fuse *_fuse_new_30(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data); struct fuse *_fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data); /** * Create a new FUSE filesystem. * * This function accepts most file-system independent mount options * (like context, nodev, ro - see mount(8)), as well as the * FUSE-specific mount options from mount.fuse(8). * * If the --help option is specified, the function writes a help text * to stdout and returns NULL. * * Option parsing skips argv[0], which is assumed to contain the * program name. This element must always be present and is used to * construct a basic ``usage: `` message for the --help output. If * argv[0] is set to the empty string, no usage message is included in * the --help output. * * If an unknown option is passed in, an error message is written to * stderr and the function returns NULL. * * @param args argument vector * @param op the filesystem operations * @param op_size the size of the fuse_operations structure * @param private_data Initial value for the `private_data` * field of `struct fuse_context`. May be overridden by the * `struct fuse_operations.init` handler. * @return the created FUSE handle */ #if FUSE_USE_VERSION == 30 static inline struct fuse *fuse_new_fn(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { struct libfuse_version version = { .major = FUSE_MAJOR_VERSION, .minor = FUSE_MINOR_VERSION, .hotfix = FUSE_HOTFIX_VERSION, .padding = 0 }; return _fuse_new_30(args, op, op_size, &version, user_data); } #else /* FUSE_USE_VERSION */ static inline struct fuse *fuse_new_fn(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { struct libfuse_version version = { .major = FUSE_MAJOR_VERSION, .minor = FUSE_MINOR_VERSION, .hotfix = FUSE_HOTFIX_VERSION, .padding = 0 }; return _fuse_new_31(args, op, op_size, &version, user_data); } #endif #define fuse_new(args, op, size, data) fuse_new_fn(args, op, size, data) /** * Mount a FUSE file system. * * @param mountpoint the mount point path * @param f the FUSE handle * * @return 0 on success, -1 on failure. **/ int fuse_mount(struct fuse *f, const char *mountpoint); /** * Unmount a FUSE file system. * * See fuse_session_unmount() for additional information. * * @param f the FUSE handle **/ void fuse_unmount(struct fuse *f); /** * Destroy the FUSE handle. * * 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. * * For a description of the return value and the conditions when the * event loop exits, refer to the documentation of * fuse_session_loop(). * * @param f the FUSE handle * @return see fuse_session_loop() * * See also: fuse_loop_mt() */ int fuse_loop(struct fuse *f); /** * Flag session as terminated * * This function will cause any running event loops to exit on * the next opportunity. * * @param f the FUSE handle */ void fuse_exit(struct fuse *f); #if FUSE_USE_VERSION < 32 int fuse_loop_mt_31(struct fuse *f, int clone_fd); #define fuse_loop_mt(f, clone_fd) fuse_loop_mt_31(f, clone_fd) #elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config *config); #define fuse_loop_mt(f, config) fuse_loop_mt_32(f, config) #else /** * FUSE event loop with multiple threads * * Requests from the kernel are processed, and the appropriate * operations are called. Request are processed in parallel by * distributing them between multiple threads. * * For a description of the return value and the conditions when the * event loop exits, refer to the documentation of * fuse_session_loop(). * * Note: using fuse_loop() instead of fuse_loop_mt() means you are running in * single-threaded mode, and that you will not have to worry about reentrancy, * though you will have to worry about recursive lookups. In single-threaded * mode, FUSE will wait for one callback to return before calling another. * * Enabling multiple threads, by using fuse_loop_mt(), will cause FUSE to make * multiple simultaneous calls into the various callback functions given by your * fuse_operations record. * * If you are using multiple threads, you can enjoy all the parallel execution * and interactive response benefits of threads, and you get to enjoy all the * benefits of race conditions and locking bugs, too. Ensure that any code used * in the callback function of fuse_operations is also thread-safe. * * @param f the FUSE handle * @param config loop configuration, may be NULL and defaults will be used then * @return see fuse_session_loop() * * See also: fuse_loop() */ #if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS)) int fuse_loop_mt(struct fuse *f, struct fuse_loop_config *config); #else int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config); #define fuse_loop_mt(f, config) fuse_loop_mt_312(f, config) #endif /* LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS */ #endif /** * 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); /** * Invalidates cache for the given path. * * This calls fuse_lowlevel_notify_inval_inode internally. * * @return 0 on successful invalidation, negative error value otherwise. * This routine may return -ENOENT to indicate that there was * no entry to be invalidated, e.g., because the path has not * been seen before or has been forgotten; this should not be * considered to be an error. */ int fuse_invalidate_path(struct fuse *f, const char *path); /** * Start the cleanup thread when using option "remember". * * This is done automatically by fuse_loop_mt() * @param fuse struct fuse pointer for fuse instance * @return 0 on success and -1 on error */ int fuse_start_cleanup_thread(struct fuse *fuse); /** * 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, struct fuse_file_info *fi); int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, const char *newpath, unsigned int flags); 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, enum fuse_readdir_flags flags); 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, struct fuse_file_info *fi); int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi); int fuse_fs_truncate(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], struct fuse_file_info *fi); 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); #if FUSE_USE_VERSION < 35 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); #else int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data); #endif 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); ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, 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); off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence, struct fuse_file_info *fi); int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi); void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn, struct fuse_config *cfg); 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 private_data Initial value for the `private_data` * field of `struct fuse_context`. May be overridden by the * `struct fuse_operations.init` handler. * @return a new filesystem object */ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *private_data); /** * 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 */ typedef struct fuse_fs *(*fuse_module_factory_t)(struct fuse_args *args, struct fuse_fs *fs[]); /** * Register filesystem module * * If the "-omodules=*name*_:..." option is present, filesystem * objects are created and pushed onto the stack with the *factory_* * function. * * @param name_ the name of this filesystem module * @param factory_ the factory function for this filesystem module */ #define FUSE_REGISTER_MODULE(name_, factory_) \ fuse_module_factory_t fuse_module_ ## name_ ## _factory = factory_ /** Get session from fuse object */ struct fuse_session *fuse_get_session(struct fuse *f); /** * Open a FUSE file descriptor and set up the mount for the given * mountpoint and flags. * * @param mountpoint reference to the mount in the file system * @param options mount options * @return the FUSE file descriptor or -1 upon error */ int fuse_open_channel(const char *mountpoint, const char *options); #ifdef __cplusplus } #endif #endif /* FUSE_H_ */ fuse-3.18.3/include/fuse_common.h0000644000175000017500000011141315250106036015623 0ustar berndbernd/* 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 LGPL2.txt. */ /** @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_ #ifdef HAVE_LIBFUSE_PRIVATE_CONFIG_H #include "fuse_config.h" #endif #include "libfuse_config.h" #include "fuse_opt.h" #include "fuse_log.h" #include #include #include #include #define FUSE_MAKE_VERSION(maj, min) ((maj) * 100 + (min)) #define FUSE_VERSION FUSE_MAKE_VERSION(FUSE_MAJOR_VERSION, FUSE_MINOR_VERSION) #ifdef __cplusplus extern "C" { #endif /** * Information about an open file. * * File Handles are created by the open, opendir, and create methods and closed * by the release and releasedir methods. Multiple file handles may be * concurrently open for the same file. Generally, a client will create one * file handle per file descriptor, though in some cases multiple file * descriptors can share a single file handle. * * Note: This data structure is ABI sensitive, new parameters have to be * added within padding/padding2 bits and always below existing * parameters. */ struct fuse_file_info { /** Open flags. Available in open(), release() and create() */ int32_t flags; /** In case of a write operation indicates if this was caused by a delayed write from the page cache. If so, then the context's pid, uid, and gid fields will not be valid, and the *fh* value may not match the *fh* value that would have been sent with the corresponding individual write requests if write caching had been disabled. */ uint32_t writepage : 1; /** Can be filled in by open/create, to use direct I/O on this file. */ uint32_t direct_io : 1; /** Can be filled in by open and opendir. It signals the kernel that any currently cached data (ie., data that the filesystem provided the last time the file/directory was open) need not be invalidated when the file/directory is closed. */ uint32_t keep_cache : 1; /** Indicates a flush operation. Set in flush operation, also maybe set in highlevel lock operation and lowlevel release operation. */ uint32_t flush : 1; /** Can be filled in by open, to indicate that the file is not seekable. */ uint32_t nonseekable : 1; /* Indicates that flock locks for this file should be released. If set, lock_owner shall contain a valid value. May only be set in ->release(). */ uint32_t flock_release : 1; /** Can be filled in by opendir. It signals the kernel to enable caching of entries returned by readdir(). Has no effect when set in other contexts (in particular it does nothing when set by open()). */ uint32_t cache_readdir : 1; /** Can be filled in by open, to indicate that flush is not needed on close. */ uint32_t noflush : 1; /** Can be filled by open/create, to allow parallel direct writes on this file */ uint32_t parallel_direct_writes : 1; /** * Set in open, create and write when KILLPRIV_V2 was negotiated and * the application issuing the syscall lacks CAP_FSETID; the * filesystem's own privileges do not matter. The filesystem then * has to remove setuid/setgid bits. */ uint32_t kill_suidgid : 1; /** Padding. Reserved for future use*/ uint32_t padding : 22; uint32_t padding2 : 32; uint32_t padding3 : 32; /** File handle id. May be filled in by filesystem in create, * open, and opendir(). Available in most other file operations on the * same file handle. */ uint64_t fh; /** Lock owner id. Available in locking operations and flush */ uint64_t lock_owner; /** Requested poll events. Available in ->poll. Only set on kernels which support it. If unsupported, this field is set to zero. */ uint32_t poll_events; /** Passthrough backing file id. May be filled in by filesystem in * create and open. It is used to create a passthrough connection * between FUSE file and backing file. */ int32_t backing_id; /** struct fuse_file_info api and abi flags */ uint64_t compat_flags; uint64_t reserved[2]; }; /** * Configuration parameters passed to fuse_session_loop_mt() and * fuse_loop_mt(). * For FUSE API versions less than 312, use a public struct * fuse_loop_config in applications and struct fuse_loop_config_v1 * is used in library (i.e., libfuse.so). These two structs are binary * compatible in earlier API versions and can be linked. * Deprecated and replaced by a newer private struct in FUSE API * version 312 (FUSE_MAKE_VERSION(3, 12)). */ #if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) struct fuse_loop_config_v1; /* forward declaration */ struct fuse_loop_config { #else struct fuse_loop_config_v1 { #endif /** * whether to use separate device fds for each thread * (may increase performance) */ int clone_fd; /** * 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. */ unsigned int max_idle_threads; }; /************************************************************************** * Capability bits for 'fuse_conn_info.capable' and 'fuse_conn_info.want' * **************************************************************************/ /** * Indicates that the filesystem supports asynchronous read requests. * * If this capability is not requested/available, the kernel will * ensure that there is at most one pending read request per * file-handle at any time, and will attempt to order read requests by * increasing offset. * * This feature is enabled by default when supported by the kernel. */ #define FUSE_CAP_ASYNC_READ (1UL << 0) /** * Indicates that the filesystem supports "remote" locking. * * This feature is enabled by default when supported by the kernel, * and if getlk() and setlk() handlers are implemented. */ #define FUSE_CAP_POSIX_LOCKS (1UL << 1) /** * Indicates that the filesystem supports the O_TRUNC open flag. If * disabled, and an application specifies O_TRUNC, fuse first calls * truncate() and then open() with O_TRUNC filtered out. * * This feature is enabled by default when supported by the kernel. */ #define FUSE_CAP_ATOMIC_O_TRUNC (1UL << 3) /** * Indicates that the filesystem supports lookups of "." and "..". * * When this flag is set, the filesystem must be prepared to receive requests * for invalid inodes (i.e., for which a FORGET request was received or * which have been used in a previous instance of the filesystem daemon) and * must not reuse node-ids (even when setting generation numbers). * * This feature is disabled by default. */ #define FUSE_CAP_EXPORT_SUPPORT (1UL << 4) /** * Indicates that the kernel should not apply the umask to the * file mode on create operations. * * This feature is disabled by default. */ #define FUSE_CAP_DONT_MASK (1UL << 6) /** * Indicates that libfuse should try to use splice() when writing to * the fuse device. This may improve performance. * * This feature is disabled by default. */ #define FUSE_CAP_SPLICE_WRITE (1UL << 7) /** * Indicates that libfuse should try to move pages instead of copying when * writing to / reading from the fuse device. This may improve performance. * * This feature is disabled by default. */ #define FUSE_CAP_SPLICE_MOVE (1UL << 8) /** * Indicates that libfuse should try to use splice() when reading from * the fuse device. This may improve performance. * * This feature is enabled by default when supported by the kernel and * if the filesystem implements a write_buf() handler. */ #define FUSE_CAP_SPLICE_READ (1UL << 9) /** * If set, the calls to flock(2) will be emulated using POSIX locks and must * then be handled by the filesystem's setlock() handler. * * If not set, flock(2) calls will be handled by the FUSE kernel module * internally (so any access that does not go through the kernel cannot be taken * into account). * * This feature is enabled by default when supported by the kernel and * if the filesystem implements a flock() handler. */ #define FUSE_CAP_FLOCK_LOCKS (1UL << 10) /** * Indicates that the filesystem supports ioctl's on directories. * * This feature is enabled by default when supported by the kernel. */ #define FUSE_CAP_IOCTL_DIR (1UL << 11) /** * Traditionally, while a file is open the FUSE kernel module only * asks the filesystem for an update of the file's attributes when a * client attempts to read beyond EOF. This is unsuitable for * e.g. network filesystems, where the file contents may change * without the kernel knowing about it. * * If this flag is set, FUSE will check the validity of the attributes * on every read. If the attributes are no longer valid (i.e., if the * *attr_timeout* passed to fuse_reply_attr() or set in `struct * fuse_entry_param` has passed), it will first issue a `getattr` * request. If the new mtime differs from the previous value, any * cached file *contents* will be invalidated as well. * * This flag should always be set when available. If all file changes * go through the kernel, *attr_timeout* should be set to a very large * number to avoid unnecessary getattr() calls. * * This feature is enabled by default when supported by the kernel. */ #define FUSE_CAP_AUTO_INVAL_DATA (1UL << 12) /** * Indicates that the filesystem supports readdirplus. * * This feature is enabled by default when supported by the kernel and if the * filesystem implements a readdirplus() handler. */ #define FUSE_CAP_READDIRPLUS (1UL << 13) /** * Indicates that the filesystem supports adaptive readdirplus. * * If FUSE_CAP_READDIRPLUS is not set, this flag has no effect. * * If FUSE_CAP_READDIRPLUS is set and this flag is not set, the kernel * will always issue readdirplus() requests to retrieve directory * contents. * * If FUSE_CAP_READDIRPLUS is set and this flag is set, the kernel * will issue both readdir() and readdirplus() requests, depending on * how much information is expected to be required. * * As of Linux 4.20, the algorithm is as follows: when userspace * starts to read directory entries, issue a READDIRPLUS request to * the filesystem. If any entry attributes have been looked up by the * time userspace requests the next batch of entries continue with * READDIRPLUS, otherwise switch to plain READDIR. This will reasult * in eg plain "ls" triggering READDIRPLUS first then READDIR after * that because it doesn't do lookups. "ls -l" should result in all * READDIRPLUS, except if dentries are already cached. * * This feature is enabled by default when supported by the kernel and * if the filesystem implements both a readdirplus() and a readdir() * handler. */ #define FUSE_CAP_READDIRPLUS_AUTO (1UL << 14) /** * Indicates that the filesystem supports asynchronous direct I/O submission. * * If this capability is not requested/available, the kernel will ensure that * there is at most one pending read and one pending write request per direct * I/O file-handle at any time. * * This feature is enabled by default when supported by the kernel. */ #define FUSE_CAP_ASYNC_DIO (1UL << 15) /** * Indicates that writeback caching should be enabled. This means that * individual write request may be buffered and merged in the kernel * before they are send to the filesystem. * * This feature is disabled by default. */ #define FUSE_CAP_WRITEBACK_CACHE (1UL << 16) /** * Indicates support for zero-message opens. If this flag is set in * the `capable` field of the `fuse_conn_info` structure, then the * filesystem may return `ENOSYS` from the open() handler to indicate * success. Further attempts to open files will be handled in the * kernel. (If this flag is not set, returning ENOSYS will be treated * as an error and signaled to the caller). * * Setting this flag in the `want` field enables this behavior automatically * within libfuse for low level API users. If non-low level users wish to have * this behavior you must return `ENOSYS` from the open() handler on supporting * kernels. */ #define FUSE_CAP_NO_OPEN_SUPPORT (1UL << 17) /** * Indicates support for parallel directory operations. If this flag * is unset, the FUSE kernel module will ensure that lookup() and * readdir() requests are never issued concurrently for the same * directory. */ #define FUSE_CAP_PARALLEL_DIROPS (1UL << 18) /** * Indicates support for POSIX ACLs. * * If this feature is enabled, the kernel will cache and have * responsibility for enforcing ACLs. ACL will be stored as xattrs and * passed to userspace, which is responsible for updating the ACLs in * the filesystem, keeping the file mode in sync with the ACL, and * ensuring inheritance of default ACLs when new filesystem nodes are * created. Note that this requires that the file system is able to * parse and interpret the xattr representation of ACLs. * * Enabling this feature implicitly turns on the * ``default_permissions`` mount option (even if it was not passed to * mount(2)). * * This feature is disabled by default. */ #define FUSE_CAP_POSIX_ACL (1UL << 19) /** * Indicates that the filesystem is responsible for unsetting * setuid and setgid bits when a file is written, truncated, or * its owner is changed. * * This feature is disabled by default. */ #define FUSE_CAP_HANDLE_KILLPRIV (1UL << 20) /** * Indicates that the filesystem is responsible for unsetting * setuid and setgid bit and additionally cap (stored as xattr) when a * file is written, truncated, or its owner is changed. * Upon write/truncate suid/sgid is only killed if caller * does not have CAP_FSETID. Additionally upon * write/truncate sgid is killed only if file has group * execute permission. (Same as Linux VFS behavior). * KILLPRIV_V2 requires handling of * - FUSE_OPEN_KILL_SUIDGID (set in struct fuse_create_in::open_flags) * - FATTR_KILL_SUIDGID (set in struct fuse_setattr_in::valid) * - FUSE_WRITE_KILL_SUIDGID (set in struct fuse_write_in::write_flags) * * This feature is disabled by default. */ #define FUSE_CAP_HANDLE_KILLPRIV_V2 (1UL << 21) /** * Indicates that the kernel supports caching symlinks in its page cache. * * When this feature is enabled, symlink targets are saved in the page cache. * You can invalidate a cached link by calling: * `fuse_lowlevel_notify_inval_inode(se, ino, 0, 0);` * * This feature is disabled by default. * If the kernel supports it (>= 4.20), you can enable this feature by * setting this flag in the `want` field of the `fuse_conn_info` structure. */ #define FUSE_CAP_CACHE_SYMLINKS (1UL << 23) /** * Indicates support for zero-message opendirs. If this flag is set in * the `capable` field of the `fuse_conn_info` structure, then the filesystem * may return `ENOSYS` from the opendir() handler to indicate success. Further * opendir and releasedir messages will be handled in the kernel. (If this * flag is not set, returning ENOSYS will be treated as an error and signalled * to the caller.) * * Setting this flag in the `want` field enables this behavior automatically * within libfuse for low level API users. If non-low level users with to have * this behavior you must return `ENOSYS` from the opendir() handler on * supporting kernels. */ #define FUSE_CAP_NO_OPENDIR_SUPPORT (1UL << 24) /** * Indicates support for invalidating cached pages only on explicit request. * * If this flag is set in the `capable` field of the `fuse_conn_info` structure, * then the FUSE kernel module supports invalidating cached pages only on * explicit request by the filesystem through fuse_lowlevel_notify_inval_inode() * or fuse_invalidate_path(). * * By setting this flag in the `want` field of the `fuse_conn_info` structure, * the filesystem is responsible for invalidating cached pages through explicit * requests to the kernel. * * Note that setting this flag does not prevent the cached pages from being * flushed by OS itself and/or through user actions. * * Note that if both FUSE_CAP_EXPLICIT_INVAL_DATA and FUSE_CAP_AUTO_INVAL_DATA * are set in the `capable` field of the `fuse_conn_info` structure then * FUSE_CAP_AUTO_INVAL_DATA takes precedence. * * This feature is disabled by default. */ #define FUSE_CAP_EXPLICIT_INVAL_DATA (1UL << 25) /** * Indicates support that dentries can be expired. * * Expiring dentries, instead of invalidating them, makes a difference for * overmounted dentries, where plain invalidation would detach all submounts * before dropping the dentry from the cache. If only expiry is set on the * dentry, then any overmounts are left alone and until ->d_revalidate() * is called. * * Note: ->d_revalidate() is not called for the case of following a submount, * so invalidation will only be triggered for the non-overmounted case. * The dentry could also be mounted in a different mount instance, in which case * any submounts will still be detached. */ #define FUSE_CAP_EXPIRE_ONLY (1UL << 26) /** * Indicates that an extended 'struct fuse_setxattr' is used by the kernel * side - extra_flags are passed, which are used (as of now by acl) processing. * For example FUSE_SETXATTR_ACL_KILL_SGID might be set. */ #define FUSE_CAP_SETXATTR_EXT (1UL << 27) /** * Files opened with FUSE_DIRECT_IO do not support MAP_SHARED mmap. This restriction * is relaxed through FUSE_CAP_DIRECT_IO_RELAX (kernel flag: FUSE_DIRECT_IO_RELAX). * MAP_SHARED is disabled by default for FUSE_DIRECT_IO, as this flag can be used to * ensure coherency between mount points (or network clients) and with kernel page * cache as enforced by mmap that cannot be guaranteed anymore. */ #define FUSE_CAP_DIRECT_IO_ALLOW_MMAP (1UL << 28) /** * Indicates support for passthrough mode access for read/write operations. * * If this flag is set in the `capable` field of the `fuse_conn_info` * structure, then the FUSE kernel module supports redirecting read/write * operations to the backing file instead of letting them to be handled * by the FUSE daemon. * * This feature is disabled by default. */ #define FUSE_CAP_PASSTHROUGH (1UL << 29) /** * Indicates that the file system cannot handle NFS export * * If this flag is set NFS export and name_to_handle_at * is not going to work at all and will fail with EOPNOTSUPP. */ #define FUSE_CAP_NO_EXPORT_SUPPORT (1UL << 30) /** * Indicates support for io-uring between fuse-server and fuse-client */ #define FUSE_CAP_OVER_IO_URING (1UL << 31) /** * 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. * * Note: The `capable` and `want` fields are limited to 32 bits for * ABI compatibility. For full 64-bit capability support, use the * `capable_ext` and `want_ext` fields instead. */ struct fuse_conn_info { /** * Major version of the protocol (read-only) */ uint32_t proto_major; /** * Minor version of the protocol (read-only) */ uint32_t proto_minor; /** * Maximum size of the write buffer */ uint32_t max_write; /** * Maximum size of read requests. A value of zero indicates no * limit. However, even if the filesystem does not specify a * limit, the maximum size of read requests will still be * limited by the kernel. * * NOTE: For the time being, the maximum size of read requests * must be set both here *and* passed to fuse_session_new() * using the ``-o max_read=`` mount option. At some point * in the future, specifying the mount option will no longer * be necessary. */ uint32_t max_read; /** * Maximum readahead */ uint32_t max_readahead; /** * Capability flags that the kernel supports (read-only) * * Deprecated left over for ABI compatibility, use capable_ext */ uint32_t capable; /** * Capability flags that the filesystem wants to enable. * * libfuse attempts to initialize this field with * reasonable default values before calling the init() handler. * * Deprecated left over for ABI compatibility. * Use want_ext with the helper functions * fuse_set_feature_flag() / fuse_unset_feature_flag() */ uint32_t want; /** * Maximum number of pending "background" requests. A * background request is any type of request for which the * total number is not limited by other means. As of kernel * 4.8, only two types of requests fall into this category: * * 1. Read-ahead requests * 2. Asynchronous direct I/O requests * * Read-ahead requests are generated (if max_readahead is * non-zero) by the kernel to preemptively fill its caches * when it anticipates that userspace will soon read more * data. * * Asynchronous direct I/O requests are generated if * FUSE_CAP_ASYNC_DIO is enabled and userspace submits a large * direct I/O request. In this case the kernel will internally * split it up into multiple smaller requests and submit them * to the filesystem concurrently. * * Note that the following requests are *not* background * requests: writeback requests (limited by the kernel's * flusher algorithm), regular (i.e., synchronous and * buffered) userspace read/write requests (limited to one per * thread), asynchronous read requests (Linux's io_submit(2) * call actually blocks, so these are also limited to one per * thread). */ uint32_t max_background; /** * Kernel congestion threshold parameter. If the number of pending * background requests exceeds this number, the FUSE kernel module will * mark the filesystem as "congested". This instructs the kernel to * expect that queued requests will take some time to complete, and to * adjust its algorithms accordingly (e.g. by putting a waiting thread * to sleep instead of using a busy-loop). */ uint32_t congestion_threshold; /** * When FUSE_CAP_WRITEBACK_CACHE is enabled, the kernel is responsible * for updating mtime and ctime when write requests are received. The * updated values are passed to the filesystem with setattr() requests. * However, if the filesystem does not support the full resolution of * the kernel timestamps (nanoseconds), the mtime and ctime values used * by kernel and filesystem will differ (and result in an apparent * change of times after a cache flush). * * To prevent this problem, this variable can be used to inform the * kernel about the timestamp granularity supported by the file-system. * The value should be power of 10. The default is 1, i.e. full * nano-second resolution. Filesystems supporting only second resolution * should set this to 1000000000. */ uint32_t time_gran; /** * When FUSE_CAP_PASSTHROUGH is enabled, this is the maximum allowed * stacking depth of the backing files. In current kernel, the maximum * allowed stack depth if FILESYSTEM_MAX_STACK_DEPTH (2), which includes * the FUSE passthrough layer, so the maximum stacking depth for backing * files is 1. * * The default is FUSE_BACKING_STACKED_UNDER (0), meaning that the * backing files cannot be on a stacked filesystem, but another stacked * filesystem can be stacked over this FUSE passthrough filesystem. * * Set this to FUSE_BACKING_STACKED_OVER (1) if backing files may be on * a stacked filesystem, such as overlayfs or another FUSE passthrough. * In this configuration, another stacked filesystem cannot be stacked * over this FUSE passthrough filesystem. */ #define FUSE_BACKING_STACKED_UNDER (0) #define FUSE_BACKING_STACKED_OVER (1) uint32_t max_backing_stack_depth; /** * Disable FUSE_INTERRUPT requests. * * Enable `no_interrupt` option to: * 1) Avoid unnecessary locking operations and list operations, * 2) Return ENOSYS for the reply of FUSE_INTERRUPT request to * inform the kernel not to send the FUSE_INTERRUPT request. */ uint32_t no_interrupt : 1; /* reserved bits for future use */ uint32_t padding : 31; /** * Extended capability flags that the kernel supports (read-only) * This field provides full 64-bit capability support. */ uint64_t capable_ext; /** * Extended capability flags that the filesystem wants to enable. * This field provides full 64-bit capability support. * * Don't set this field directly, but use the helper functions * fuse_set_feature_flag() / fuse_unset_feature_flag() * */ uint64_t want_ext; /** * Request timeout (in seconds). If the request is not answered by * this timeout, the connection will be aborted by the kernel. */ uint16_t request_timeout; /** * For future use. */ uint16_t reserved[31]; }; struct fuse_session; struct fuse_pollhandle; struct fuse_conn_info_opts; /** * This function parses several command-line options that can be used * to override elements of struct fuse_conn_info. The pointer returned * by this function should be passed to the * fuse_apply_conn_info_opts() method by the file system's init() * handler. * * Before using this function, think twice if you really want these * parameters to be adjustable from the command line. In most cases, * they should be determined by the file system internally. * * The following options are recognized: * * -o max_write=N sets conn->max_write * -o max_readahead=N sets conn->max_readahead * -o max_background=N sets conn->max_background * -o congestion_threshold=N sets conn->congestion_threshold * -o async_read sets FUSE_CAP_ASYNC_READ in conn->want * -o sync_read unsets FUSE_CAP_ASYNC_READ in conn->want * -o atomic_o_trunc sets FUSE_CAP_ATOMIC_O_TRUNC in conn->want * -o no_remote_lock Equivalent to -o no_remote_flock,no_remote_posix_lock * -o no_remote_flock Unsets FUSE_CAP_FLOCK_LOCKS in conn->want * -o no_remote_posix_lock Unsets FUSE_CAP_POSIX_LOCKS in conn->want * -o [no_]splice_write (un-)sets FUSE_CAP_SPLICE_WRITE in conn->want * -o [no_]splice_move (un-)sets FUSE_CAP_SPLICE_MOVE in conn->want * -o [no_]splice_read (un-)sets FUSE_CAP_SPLICE_READ in conn->want * -o [no_]auto_inval_data (un-)sets FUSE_CAP_AUTO_INVAL_DATA in conn->want * -o readdirplus=no unsets FUSE_CAP_READDIRPLUS in conn->want * -o readdirplus=yes sets FUSE_CAP_READDIRPLUS and unsets * FUSE_CAP_READDIRPLUS_AUTO in conn->want * -o readdirplus=auto sets FUSE_CAP_READDIRPLUS and * FUSE_CAP_READDIRPLUS_AUTO in conn->want * -o [no_]async_dio (un-)sets FUSE_CAP_ASYNC_DIO in conn->want * -o [no_]writeback_cache (un-)sets FUSE_CAP_WRITEBACK_CACHE in conn->want * -o time_gran=N sets conn->time_gran * * Known options will be removed from *args*, unknown options will be * passed through unchanged. * * @param args argument vector (input+output) * @return parsed options **/ struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args); /** * This function applies the (parsed) parameters in *opts* to the * *conn* pointer. It may modify the following fields: wants, * max_write, max_readahead, congestion_threshold, max_background, * time_gran. A field is only set (or unset) if the corresponding * option has been explicitly set. */ void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn); /** * 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); /** * Get the full package version string of the library * * @return the package version */ const char *fuse_pkgversion(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; /** * Size of memory pointer * * Used only if mem was internally allocated. * Not used if mem was user-provided. */ size_t mem_size; }; /** * 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]; }; /** * libfuse version a file system was compiled with. Should be filled in from * defines in 'libfuse_config.h' */ struct libfuse_version { uint32_t major; uint32_t minor; uint32_t hotfix; uint32_t padding; }; /* 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, \ /* .mem_size = */ 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. * * Once either of the POSIX signals arrives, the signal handler calls * fuse_session_exit(). * * @param se the session to exit * @return 0 on success, -1 on failure * * See also: * fuse_remove_signal_handlers() */ int fuse_set_signal_handlers(struct fuse_session *se); /** * Print a stack backtrace diagnostic on critical signals () * * Stores session in a global variable. May only be called once per * process until fuse_remove_signal_handlers() is called. * * Once either of the POSIX signals arrives, the signal handler calls * fuse_session_exit(). * * @param se the session to exit * @return 0 on success, -1 on failure * * See also: * fuse_remove_signal_handlers() */ int fuse_set_fail_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() * * See also: * fuse_set_signal_handlers() */ void fuse_remove_signal_handlers(struct fuse_session *se); /** * Config operations. * These APIs are introduced in version 312 (FUSE_MAKE_VERSION(3, 12)). * Using them in earlier versions will result in errors. */ #if FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 12) /** * Create and set default config for fuse_session_loop_mt and fuse_loop_mt. * * @return anonymous config struct */ struct fuse_loop_config *fuse_loop_cfg_create(void); /** * Free the config data structure */ void fuse_loop_cfg_destroy(struct fuse_loop_config *config); /** * fuse_loop_config setter to set the number of max idle threads. */ void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, unsigned int value); /** * fuse_loop_config setter to set the number of max threads. */ void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config, unsigned int value); /** * fuse_loop_config setter to enable the clone_fd feature */ void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, unsigned int value); /** * Convert old config to more recernt fuse_loop_config2 * * @param config current config2 type * @param v1_conf older config1 type (below FUSE API 312) */ void fuse_loop_cfg_convert(struct fuse_loop_config *config, struct fuse_loop_config_v1 *v1_conf); #endif /** * Set a feature flag in the want_ext field of fuse_conn_info. * * @param conn connection information * @param flag feature flag to be set * @return true if the flag was set, false if the flag is not supported */ bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag); /** * Unset a feature flag in the want_ext field of fuse_conn_info. * * @param conn connection information * @param flag feature flag to be unset */ void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag); /** * Get the value of a feature flag in the want_ext field of fuse_conn_info. * * @param conn connection information * @param flag feature flag to be checked * @return true if the flag is set, false otherwise */ bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag); /* * DO NOT USE: Not part of public API, for internal test use only. * The function signature or any use of it is not guaranteeed to * remain stable. And neither are results of what this function does. */ int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn); /* ----------------------------------------------------------- * * Compatibility stuff * * ----------------------------------------------------------- */ #if !defined(FUSE_USE_VERSION) || FUSE_USE_VERSION < 30 # error only API version 30 or greater is supported #endif #ifdef __cplusplus } #endif /* * This interface uses 64 bit off_t. * * On 32bit systems please add -D_FILE_OFFSET_BITS=64 to your compile flags! */ #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) _Static_assert(sizeof(off_t) == 8, "fuse: off_t must be 64bit"); #else struct _fuse_off_t_must_be_64bit_dummy_struct \ { unsigned _fuse_off_t_must_be_64bit:((sizeof(off_t) == 8) ? 1 : -1); }; #endif #endif /* FUSE_COMMON_H_ */ fuse-3.18.3/include/fuse_kernel.h0000644000175000017500000007601215250106036015620 0ustar berndbernd/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */ /* 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.1: * - add the following messages: * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK, * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE, * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR, * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR, * FUSE_RELEASEDIR * - add padding to messages to accommodate 32-bit servers on 64-bit kernels * * 7.2: * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags * - add FUSE_FSYNCDIR message * * 7.3: * - add FUSE_ACCESS message * - add FUSE_CREATE message * - add filehandle to fuse_setattr_in * * 7.4: * - add frsize to fuse_kstatfs * - clean up request size limit checking * * 7.5: * - add flags and max_write to fuse_init_out * * 7.6: * - add max_readahead to fuse_init_in and fuse_init_out * * 7.7: * - add FUSE_INTERRUPT message * - add POSIX file lock support * * 7.8: * - add lock_owner and flags fields to fuse_release_in * - add FUSE_BMAP message * - add FUSE_DESTROY message * * 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 * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_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 create, 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 * * 7.20 * - add FUSE_AUTO_INVAL_DATA * * 7.21 * - add FUSE_READDIRPLUS * - send the requested events in POLL request * * 7.22 * - add FUSE_ASYNC_DIO * * 7.23 * - add FUSE_WRITEBACK_CACHE * - add time_gran to fuse_init_out * - add reserved space to fuse_init_out * - add FATTR_CTIME * - add ctime and ctimensec to fuse_setattr_in * - add FUSE_RENAME2 request * - add FUSE_NO_OPEN_SUPPORT flag * * 7.24 * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support * * 7.25 * - add FUSE_PARALLEL_DIROPS * * 7.26 * - add FUSE_HANDLE_KILLPRIV * - add FUSE_POSIX_ACL * * 7.27 * - add FUSE_ABORT_ERROR * * 7.28 * - add FUSE_COPY_FILE_RANGE * - add FOPEN_CACHE_DIR * - add FUSE_MAX_PAGES, add max_pages to init_out * - add FUSE_CACHE_SYMLINKS * * 7.29 * - add FUSE_NO_OPENDIR_SUPPORT flag * * 7.30 * - add FUSE_EXPLICIT_INVAL_DATA * - add FUSE_IOCTL_COMPAT_X32 * * 7.31 * - add FUSE_WRITE_KILL_PRIV flag * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag * * 7.32 * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS * * 7.33 * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID * - add FUSE_OPEN_KILL_SUIDGID * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT * - add FUSE_SETXATTR_ACL_KILL_SGID * * 7.34 * - add FUSE_SYNCFS * * 7.35 * - add FOPEN_NOFLUSH * * 7.36 * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag * - add flags2 to fuse_init_in and fuse_init_out * - add FUSE_SECURITY_CTX init flag * - add security context to create, mkdir, symlink, and mknod requests * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX * * 7.37 * - add FUSE_TMPFILE * * 7.38 * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry * - add FOPEN_PARALLEL_DIRECT_WRITES * - add total_extlen to fuse_in_header * - add FUSE_MAX_NR_SECCTX * - add extension header * - add FUSE_EXT_GROUPS * - add FUSE_CREATE_SUPP_GROUP * - add FUSE_HAS_EXPIRE_ONLY * * 7.39 * - add FUSE_DIRECT_IO_ALLOW_MMAP * - add FUSE_STATX and related structures * * 7.40 * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag * - add FUSE_NO_EXPORT_SUPPORT init flag * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag * * 7.41 * - add FUSE_ALLOW_IDMAP * 7.42 * - Add FUSE_OVER_IO_URING and all other io-uring related flags and data * structures: * - struct fuse_uring_ent_in_out * - struct fuse_uring_req_header * - struct fuse_uring_cmd_req * - FUSE_URING_IN_OUT_HEADER_SZ * - FUSE_URING_OP_IN_OUT_SZ * - enum fuse_uring_cmd * * 7.43 * - add FUSE_REQUEST_TIMEOUT * * 7.44 * - add FUSE_NOTIFY_INC_EPOCH * * 7.45 * - add FUSE_COPY_FILE_RANGE_64 * - add struct fuse_copy_file_range_out */ #ifndef _LINUX_FUSE_H #define _LINUX_FUSE_H #ifdef __KERNEL__ #include #else #include #endif /* * 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 45 /** 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 { uint64_t ino; uint64_t size; uint64_t blocks; uint64_t atime; uint64_t mtime; uint64_t ctime; uint32_t atimensec; uint32_t mtimensec; uint32_t ctimensec; uint32_t mode; uint32_t nlink; uint32_t uid; uint32_t gid; uint32_t rdev; uint32_t blksize; uint32_t flags; }; /* * The following structures are bit-for-bit compatible with the statx(2) ABI in * Linux. */ struct fuse_sx_time { int64_t tv_sec; uint32_t tv_nsec; int32_t __reserved; }; struct fuse_statx { uint32_t mask; uint32_t blksize; uint64_t attributes; uint32_t nlink; uint32_t uid; uint32_t gid; uint16_t mode; uint16_t __spare0[1]; uint64_t ino; uint64_t size; uint64_t blocks; uint64_t attributes_mask; struct fuse_sx_time atime; struct fuse_sx_time btime; struct fuse_sx_time ctime; struct fuse_sx_time mtime; uint32_t rdev_major; uint32_t rdev_minor; uint32_t dev_major; uint32_t dev_minor; uint64_t __spare2[14]; }; struct fuse_kstatfs { uint64_t blocks; uint64_t bfree; uint64_t bavail; uint64_t files; uint64_t ffree; uint32_t bsize; uint32_t namelen; uint32_t frsize; uint32_t padding; uint32_t spare[6]; }; struct fuse_file_lock { uint64_t start; uint64_t end; uint32_t type; uint32_t 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) #define FATTR_CTIME (1 << 10) #define FATTR_KILL_SUIDGID (1 << 11) /** * 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 * FOPEN_CACHE_DIR: allow caching this directory * FOPEN_STREAM: the file is stream-like (no file position at all) * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode * FOPEN_PASSTHROUGH: passthrough read/write io for this open file */ #define FOPEN_DIRECT_IO (1 << 0) #define FOPEN_KEEP_CACHE (1 << 1) #define FOPEN_NONSEEKABLE (1 << 2) #define FOPEN_CACHE_DIR (1 << 3) #define FOPEN_STREAM (1 << 4) #define FOPEN_NOFLUSH (1 << 5) #define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6) #define FOPEN_PASSTHROUGH (1 << 7) /** * INIT request/reply flags * * FUSE_ASYNC_READ: asynchronous read requests * FUSE_POSIX_LOCKS: remote locking for POSIX file locks * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB * FUSE_DONT_MASK: don't apply umask to file mode on create operations * FUSE_SPLICE_WRITE: kernel supports splice write on the device * FUSE_SPLICE_MOVE: kernel supports splice move on the device * FUSE_SPLICE_READ: kernel supports splice read on the device * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) * FUSE_READDIRPLUS_AUTO: adaptive readdirplus * FUSE_ASYNC_DIO: asynchronous direct I/O submission * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc * FUSE_POSIX_ACL: filesystem supports posix acls * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages * FUSE_CACHE_SYMLINKS: cache READLINK responses * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request * FUSE_MAP_ALIGNMENT: init_out.map_alignment contains log2(byte alignment) for * foffset and moffset fields in struct * fuse_setupmapping_out and fuse_removemapping_one. * FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts * FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc. * Upon write/truncate suid/sgid is only killed if caller * does not have CAP_FSETID. Additionally upon * write/truncate sgid is killed only if file has group * execute permission. (Same as Linux VFS behavior). * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in * FUSE_INIT_EXT: extended fuse_init_in request * FUSE_INIT_RESERVED: reserved, do not use * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and * mknod * FUSE_HAS_INODE_DAX: use per inode DAX * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, * symlink and mknod (single group that matches parent) * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation * FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode. * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit * of the request ID indicates resend requests * FUSE_ALLOW_IDMAP: allow creation of idmapped mounts * FUSE_OVER_IO_URING: Indicate that client supports io-uring * FUSE_REQUEST_TIMEOUT: kernel supports timing out requests. * init_out.request_timeout contains the timeout (in secs) */ #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_SPLICE_WRITE (1 << 7) #define FUSE_SPLICE_MOVE (1 << 8) #define FUSE_SPLICE_READ (1 << 9) #define FUSE_FLOCK_LOCKS (1 << 10) #define FUSE_HAS_IOCTL_DIR (1 << 11) #define FUSE_AUTO_INVAL_DATA (1 << 12) #define FUSE_DO_READDIRPLUS (1 << 13) #define FUSE_READDIRPLUS_AUTO (1 << 14) #define FUSE_ASYNC_DIO (1 << 15) #define FUSE_WRITEBACK_CACHE (1 << 16) #define FUSE_NO_OPEN_SUPPORT (1 << 17) #define FUSE_PARALLEL_DIROPS (1 << 18) #define FUSE_HANDLE_KILLPRIV (1 << 19) #define FUSE_POSIX_ACL (1 << 20) #define FUSE_ABORT_ERROR (1 << 21) #define FUSE_MAX_PAGES (1 << 22) #define FUSE_CACHE_SYMLINKS (1 << 23) #define FUSE_NO_OPENDIR_SUPPORT (1 << 24) #define FUSE_EXPLICIT_INVAL_DATA (1 << 25) #define FUSE_MAP_ALIGNMENT (1 << 26) #define FUSE_SUBMOUNTS (1 << 27) #define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) #define FUSE_SETXATTR_EXT (1 << 29) #define FUSE_INIT_EXT (1 << 30) #define FUSE_INIT_RESERVED (1 << 31) /* bits 32..63 get shifted down 32 bits into the flags2 field */ #define FUSE_SECURITY_CTX (1ULL << 32) #define FUSE_HAS_INODE_DAX (1ULL << 33) #define FUSE_CREATE_SUPP_GROUP (1ULL << 34) #define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) #define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36) #define FUSE_PASSTHROUGH (1ULL << 37) #define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) #define FUSE_HAS_RESEND (1ULL << 39) /* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ #define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP #define FUSE_ALLOW_IDMAP (1ULL << 40) #define FUSE_OVER_IO_URING (1ULL << 41) #define FUSE_REQUEST_TIMEOUT (1ULL << 42) /** * 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 * FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits */ #define FUSE_WRITE_CACHE (1 << 0) #define FUSE_WRITE_LOCKOWNER (1 << 1) #define FUSE_WRITE_KILL_SUIDGID (1 << 2) /* Obsolete alias; this flag implies killing suid/sgid only. */ #define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID /** * 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_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t) * * 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_COMPAT_X32 (1 << 5) #define FUSE_IOCTL_MAX_IOV 256 /** * Poll flags * * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify */ #define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) /** * Fsync flags * * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata */ #define FUSE_FSYNC_FDATASYNC (1 << 0) /** * fuse_attr flags * * FUSE_ATTR_SUBMOUNT: Object is a submount root * FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode */ #define FUSE_ATTR_SUBMOUNT (1 << 0) #define FUSE_ATTR_DAX (1 << 1) /** * Open flags * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable */ #define FUSE_OPEN_KILL_SUIDGID (1 << 0) /** * setxattr flags * FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set */ #define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) /** * notify_inval_entry flags * FUSE_EXPIRE_ONLY */ #define FUSE_EXPIRE_ONLY (1 << 0) /** * extension type * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx * FUSE_EXT_GROUPS: &fuse_supp_groups extension */ enum fuse_ext_type { /* Types 0..31 are reserved for fuse_secctx_header */ FUSE_MAX_NR_SECCTX = 31, FUSE_EXT_GROUPS = 32, }; 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, FUSE_READDIRPLUS = 44, FUSE_RENAME2 = 45, FUSE_LSEEK = 46, FUSE_COPY_FILE_RANGE = 47, FUSE_SETUPMAPPING = 48, FUSE_REMOVEMAPPING = 49, FUSE_SYNCFS = 50, FUSE_TMPFILE = 51, FUSE_STATX = 52, FUSE_COPY_FILE_RANGE_64 = 53, /* CUSE specific operations */ CUSE_INIT = 4096, /* Reserved opcodes: helpful to detect structure endian-ness */ CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */ }; 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_RESEND = 7, FUSE_NOTIFY_INC_EPOCH = 8, 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 { uint64_t nodeid; /* Inode ID */ uint64_t generation; /* Inode generation: nodeid:gen must be unique for the fs's lifetime */ uint64_t entry_valid; /* Cache timeout for the name */ uint64_t attr_valid; /* Cache timeout for the attributes */ uint32_t entry_valid_nsec; uint32_t attr_valid_nsec; struct fuse_attr attr; }; struct fuse_forget_in { uint64_t nlookup; }; struct fuse_forget_one { uint64_t nodeid; uint64_t nlookup; }; struct fuse_batch_forget_in { uint32_t count; uint32_t dummy; }; struct fuse_getattr_in { uint32_t getattr_flags; uint32_t dummy; uint64_t fh; }; #define FUSE_COMPAT_ATTR_OUT_SIZE 96 struct fuse_attr_out { uint64_t attr_valid; /* Cache timeout for the attributes */ uint32_t attr_valid_nsec; uint32_t dummy; struct fuse_attr attr; }; struct fuse_statx_in { uint32_t getattr_flags; uint32_t reserved; uint64_t fh; uint32_t sx_flags; uint32_t sx_mask; }; struct fuse_statx_out { uint64_t attr_valid; /* Cache timeout for the attributes */ uint32_t attr_valid_nsec; uint32_t flags; uint64_t spare[2]; struct fuse_statx stat; }; #define FUSE_COMPAT_MKNOD_IN_SIZE 8 struct fuse_mknod_in { uint32_t mode; uint32_t rdev; uint32_t umask; uint32_t padding; }; struct fuse_mkdir_in { uint32_t mode; uint32_t umask; }; struct fuse_rename_in { uint64_t newdir; }; struct fuse_rename2_in { uint64_t newdir; uint32_t flags; uint32_t padding; }; struct fuse_link_in { uint64_t oldnodeid; }; struct fuse_setattr_in { uint32_t valid; uint32_t padding; uint64_t fh; uint64_t size; uint64_t lock_owner; uint64_t atime; uint64_t mtime; uint64_t ctime; uint32_t atimensec; uint32_t mtimensec; uint32_t ctimensec; uint32_t mode; uint32_t unused4; uint32_t uid; uint32_t gid; uint32_t unused5; }; struct fuse_open_in { uint32_t flags; uint32_t open_flags; /* FUSE_OPEN_... */ }; struct fuse_create_in { uint32_t flags; uint32_t mode; uint32_t umask; uint32_t open_flags; /* FUSE_OPEN_... */ }; struct fuse_open_out { uint64_t fh; uint32_t open_flags; int32_t backing_id; }; struct fuse_release_in { uint64_t fh; uint32_t flags; uint32_t release_flags; uint64_t lock_owner; }; struct fuse_flush_in { uint64_t fh; uint32_t unused; uint32_t padding; uint64_t lock_owner; }; struct fuse_read_in { uint64_t fh; uint64_t offset; uint32_t size; uint32_t read_flags; uint64_t lock_owner; uint32_t flags; uint32_t padding; }; #define FUSE_COMPAT_WRITE_IN_SIZE 24 struct fuse_write_in { uint64_t fh; uint64_t offset; uint32_t size; uint32_t write_flags; uint64_t lock_owner; uint32_t flags; uint32_t padding; }; struct fuse_write_out { uint32_t size; uint32_t padding; }; #define FUSE_COMPAT_STATFS_SIZE 48 struct fuse_statfs_out { struct fuse_kstatfs st; }; struct fuse_fsync_in { uint64_t fh; uint32_t fsync_flags; uint32_t padding; }; #define FUSE_COMPAT_SETXATTR_IN_SIZE 8 struct fuse_setxattr_in { uint32_t size; uint32_t flags; uint32_t setxattr_flags; uint32_t padding; }; struct fuse_getxattr_in { uint32_t size; uint32_t padding; }; struct fuse_getxattr_out { uint32_t size; uint32_t padding; }; struct fuse_lk_in { uint64_t fh; uint64_t owner; struct fuse_file_lock lk; uint32_t lk_flags; uint32_t padding; }; struct fuse_lk_out { struct fuse_file_lock lk; }; struct fuse_access_in { uint32_t mask; uint32_t padding; }; struct fuse_init_in { uint32_t major; uint32_t minor; uint32_t max_readahead; uint32_t flags; uint32_t flags2; uint32_t unused[11]; }; #define FUSE_COMPAT_INIT_OUT_SIZE 8 #define FUSE_COMPAT_22_INIT_OUT_SIZE 24 struct fuse_init_out { uint32_t major; uint32_t minor; uint32_t max_readahead; uint32_t flags; uint16_t max_background; uint16_t congestion_threshold; uint32_t max_write; uint32_t time_gran; uint16_t max_pages; uint16_t map_alignment; uint32_t flags2; uint32_t max_stack_depth; uint16_t request_timeout; uint16_t unused[11]; }; #define CUSE_INIT_INFO_MAX 4096 struct cuse_init_in { uint32_t major; uint32_t minor; uint32_t unused; uint32_t flags; }; struct cuse_init_out { uint32_t major; uint32_t minor; uint32_t unused; uint32_t flags; uint32_t max_read; uint32_t max_write; uint32_t dev_major; /* chardev major */ uint32_t dev_minor; /* chardev minor */ uint32_t spare[10]; }; struct fuse_interrupt_in { uint64_t unique; }; struct fuse_bmap_in { uint64_t block; uint32_t blocksize; uint32_t padding; }; struct fuse_bmap_out { uint64_t block; }; struct fuse_ioctl_in { uint64_t fh; uint32_t flags; uint32_t cmd; uint64_t arg; uint32_t in_size; uint32_t out_size; }; struct fuse_ioctl_iovec { uint64_t base; uint64_t len; }; struct fuse_ioctl_out { int32_t result; uint32_t flags; uint32_t in_iovs; uint32_t out_iovs; }; struct fuse_poll_in { uint64_t fh; uint64_t kh; uint32_t flags; uint32_t events; }; struct fuse_poll_out { uint32_t revents; uint32_t padding; }; struct fuse_notify_poll_wakeup_out { uint64_t kh; }; struct fuse_fallocate_in { uint64_t fh; uint64_t offset; uint64_t length; uint32_t mode; uint32_t padding; }; /** * FUSE request unique ID flag * * Indicates whether this is a resend request. The receiver should handle this * request accordingly. */ #define FUSE_UNIQUE_RESEND (1ULL << 63) /** * This value will be set by the kernel to * (struct fuse_in_header).{uid,gid} fields in * case when: * - fuse daemon enabled FUSE_ALLOW_IDMAP * - idmapping information is not available and uid/gid * can not be mapped in accordance with an idmapping. * * Note: an idmapping information always available * for inode creation operations like: * FUSE_MKNOD, FUSE_SYMLINK, FUSE_MKDIR, FUSE_TMPFILE, * FUSE_CREATE and FUSE_RENAME2 (with RENAME_WHITEOUT). */ #define FUSE_INVALID_UIDGID ((uint32_t)(-1)) struct fuse_in_header { uint32_t len; uint32_t opcode; uint64_t unique; uint64_t nodeid; uint32_t uid; uint32_t gid; uint32_t pid; uint16_t total_extlen; /* length of extensions in 8byte units */ uint16_t padding; }; struct fuse_out_header { uint32_t len; int32_t error; uint64_t unique; }; struct fuse_dirent { uint64_t ino; uint64_t off; uint32_t namelen; uint32_t type; char name[]; }; /* Align variable length records to 64bit boundary */ #define FUSE_REC_ALIGN(x) \ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) #define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) #define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x) #define FUSE_DIRENT_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) struct fuse_direntplus { struct fuse_entry_out entry_out; struct fuse_dirent dirent; }; #define FUSE_NAME_OFFSET_DIRENTPLUS \ offsetof(struct fuse_direntplus, dirent.name) #define FUSE_DIRENTPLUS_SIZE(d) \ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) struct fuse_notify_inval_inode_out { uint64_t ino; int64_t off; int64_t len; }; struct fuse_notify_inval_entry_out { uint64_t parent; uint32_t namelen; uint32_t flags; }; struct fuse_notify_delete_out { uint64_t parent; uint64_t child; uint32_t namelen; uint32_t padding; }; struct fuse_notify_store_out { uint64_t nodeid; uint64_t offset; uint32_t size; uint32_t padding; }; struct fuse_notify_retrieve_out { uint64_t notify_unique; uint64_t nodeid; uint64_t offset; uint32_t size; uint32_t padding; }; /* Matches the size of fuse_write_in */ struct fuse_notify_retrieve_in { uint64_t dummy1; uint64_t offset; uint32_t size; uint32_t dummy2; uint64_t dummy3; uint64_t dummy4; }; struct fuse_backing_map { int32_t fd; uint32_t flags; uint64_t padding; }; /* Device ioctls: */ #define FUSE_DEV_IOC_MAGIC 229 #define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) #define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ struct fuse_backing_map) #define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) struct fuse_lseek_in { uint64_t fh; uint64_t offset; uint32_t whence; uint32_t padding; }; struct fuse_lseek_out { uint64_t offset; }; struct fuse_copy_file_range_in { uint64_t fh_in; uint64_t off_in; uint64_t nodeid_out; uint64_t fh_out; uint64_t off_out; uint64_t len; uint64_t flags; }; /* For FUSE_COPY_FILE_RANGE_64 */ struct fuse_copy_file_range_out { uint64_t bytes_copied; }; #define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0) #define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1) struct fuse_setupmapping_in { /* An already open handle */ uint64_t fh; /* Offset into the file to start the mapping */ uint64_t foffset; /* Length of mapping required */ uint64_t len; /* Flags, FUSE_SETUPMAPPING_FLAG_* */ uint64_t flags; /* Offset in Memory Window */ uint64_t moffset; }; struct fuse_removemapping_in { /* number of fuse_removemapping_one follows */ uint32_t count; }; struct fuse_removemapping_one { /* Offset into the dax window start the unmapping */ uint64_t moffset; /* Length of mapping required */ uint64_t len; }; #define FUSE_REMOVEMAPPING_MAX_ENTRY \ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) struct fuse_syncfs_in { uint64_t padding; }; /* * For each security context, send fuse_secctx with size of security context * fuse_secctx will be followed by security context name and this in turn * will be followed by actual context label. * fuse_secctx, name, context */ struct fuse_secctx { uint32_t size; uint32_t padding; }; /* * Contains the information about how many fuse_secctx structures are being * sent and what's the total size of all security contexts (including * size of fuse_secctx_header). * */ struct fuse_secctx_header { uint32_t size; uint32_t nr_secctx; }; /** * struct fuse_ext_header - extension header * @size: total size of this extension including this header * @type: type of extension * * This is made compatible with fuse_secctx_header by using type values > * FUSE_MAX_NR_SECCTX */ struct fuse_ext_header { uint32_t size; uint32_t type; }; /** * struct fuse_supp_groups - Supplementary group extension * @nr_groups: number of supplementary groups * @groups: flexible array of group IDs */ struct fuse_supp_groups { uint32_t nr_groups; uint32_t groups[]; }; /** * Size of the ring buffer header */ #define FUSE_URING_IN_OUT_HEADER_SZ 128 #define FUSE_URING_OP_IN_OUT_SZ 128 /* Used as part of the fuse_uring_req_header */ struct fuse_uring_ent_in_out { uint64_t flags; /* * commit ID to be used in a reply to a ring request (see also * struct fuse_uring_cmd_req) */ uint64_t commit_id; /* size of user payload buffer */ uint32_t payload_sz; uint32_t padding; uint64_t reserved; }; /** * Header for all fuse-io-uring requests */ struct fuse_uring_req_header { /* struct fuse_in_header / struct fuse_out_header */ char in_out[FUSE_URING_IN_OUT_HEADER_SZ]; /* per op code header */ char op_in[FUSE_URING_OP_IN_OUT_SZ]; struct fuse_uring_ent_in_out ring_ent_in_out; }; /** * sqe commands to the kernel */ enum fuse_uring_cmd { FUSE_IO_URING_CMD_INVALID = 0, /* register the request buffer and fetch a fuse request */ FUSE_IO_URING_CMD_REGISTER = 1, /* commit fuse request result and fetch next request */ FUSE_IO_URING_CMD_COMMIT_AND_FETCH = 2, }; /** * In the 80B command area of the SQE. */ struct fuse_uring_cmd_req { uint64_t flags; /* entry identifier for commits */ uint64_t commit_id; /* queue the command is for (queue index) */ uint16_t qid; uint8_t padding[6]; }; #endif /* _LINUX_FUSE_H */ fuse-3.18.3/include/fuse_log.h0000644000175000017500000000435115250106036015116 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2019 Red Hat, Inc. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #ifndef FUSE_LOG_H_ #define FUSE_LOG_H_ /** @file * * This file defines the logging interface of FUSE */ #include #ifdef __cplusplus extern "C" { #endif /** * Log severity level * * These levels correspond to syslog(2) log levels since they are widely used. */ enum fuse_log_level { FUSE_LOG_EMERG, FUSE_LOG_ALERT, FUSE_LOG_CRIT, FUSE_LOG_ERR, FUSE_LOG_WARNING, FUSE_LOG_NOTICE, FUSE_LOG_INFO, FUSE_LOG_DEBUG }; /** * Log message handler function. * * This function must be thread-safe. It may be called from any libfuse * function, including fuse_parse_cmdline() and other functions invoked before * a FUSE filesystem is created. * * Install a custom log message handler function using fuse_set_log_func(). * * @param level log severity level * @param fmt sprintf-style format string including newline * @param ap format string arguments */ typedef void (*fuse_log_func_t)(enum fuse_log_level level, const char *fmt, va_list ap); /** * Install a custom log handler function. * * Log messages are emitted by libfuse functions to report errors and debug * information. Messages are printed to stderr by default but this can be * overridden by installing a custom log message handler function. * * The log message handler function is global and affects all FUSE filesystems * created within this process. * * @param func a custom log message handler function or NULL to revert to * the default */ void fuse_set_log_func(fuse_log_func_t func); /** * Emit a log message * * @param level severity level (FUSE_LOG_ERR, FUSE_LOG_DEBUG, etc) * @param fmt sprintf-style format string including newline */ void fuse_log(enum fuse_log_level level, const char *fmt, ...) __attribute__((format(printf, 2, 3))); /** * Switch default log handler from stderr to syslog * * Passed options are according to 'man 3 openlog' */ void fuse_log_enable_syslog(const char *ident, int option, int facility); /** * To be called at teardown to close syslog. */ void fuse_log_close_syslog(void); #ifdef __cplusplus } #endif #endif /* FUSE_LOG_H_ */ fuse-3.18.3/include/fuse_lowlevel.h0000644000175000017500000023330415250106036016170 0ustar berndbernd/* 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 LGPL2.txt. */ #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 35 (recommended for any * new application). */ #ifndef FUSE_USE_VERSION #error FUSE_USE_VERSION not defined #endif #include "fuse_common.h" #include #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 uint64_t fuse_ino_t; /** Request pointer type */ typedef struct fuse_req *fuse_req_t; /* Forward declaration */ struct statx; /** * Session * * This provides hooks for processing requests, and exiting */ struct fuse_session; /** 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. * */ uint64_t generation; /** Inode attributes. * * Even if attr_timeout == 0, attr must be correct. For example, * for open(), FUSE uses attr.st_size from lookup() to determine * how many bytes to request. If this value is not correct, * incorrect data will be returned. */ struct stat attr; /** Validity timeout (in seconds) for inode attributes. If attributes only change as a result of requests that come through the kernel, this should be set to a very large value. */ double attr_timeout; /** Validity timeout (in seconds) for the name. If directory entries are changed/deleted only as a result of requests that come through the kernel, this should be set to a very large value. */ 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 */ mode_t umask; }; struct fuse_forget_data { fuse_ino_t ino; uint64_t nlookup; }; struct fuse_custom_io { ssize_t (*writev)(int fd, struct iovec *iov, int count, void *userdata); ssize_t (*read)(int fd, void *buf, size_t buf_len, void *userdata); ssize_t (*splice_receive)(int fdin, off_t *offin, int fdout, off_t *offout, size_t len, unsigned int flags, void *userdata); ssize_t (*splice_send)(int fdin, off_t *offin, int fdout, off_t *offout, size_t len, unsigned int flags, void *userdata); int (*clone_fd)(int master_fd); }; /** * Flags for fuse_lowlevel_notify_entry() * 0 = invalidate entry * FUSE_LL_EXPIRE_ONLY = expire entry */ enum fuse_notify_entry_flags { FUSE_LL_INVALIDATE = 0, FUSE_LL_EXPIRE_ONLY = (1 << 0), }; /* '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) #define FUSE_SET_ATTR_FORCE (1 << 9) #define FUSE_SET_ATTR_CTIME (1 << 10) #define FUSE_SET_ATTR_KILL_SUID (1 << 11) #define FUSE_SET_ATTR_KILL_SGID (1 << 12) #define FUSE_SET_ATTR_FILE (1 << 13) #define FUSE_SET_ATTR_KILL_PRIV (1 << 14) #define FUSE_SET_ATTR_OPEN (1 << 15) #define FUSE_SET_ATTR_TIMES_SET (1 << 16) #define FUSE_SET_ATTR_TOUCH (1 << 17) /* ----------------------------------------------------------- * * 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. * * 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_session_new()`. In this case, methods will only be called if * the kernel's permission check has succeeded. * * It is generally not really necessary to check the fuse_reply_* return * values for errors, as any error in sending a reply indicates an * unrecoverable problem with the kernel fuse connection, which will also * terminate the session loop anyway. * * This data structure is ABI sensitive, on adding new functions these need to * be appended at the end of the struct */ struct fuse_lowlevel_ops { /** * Initialize filesystem * * This function is called when libfuse establishes * communication with the FUSE kernel module. The file system * should use this module to inspect and/or modify the * connection parameters provided in the `conn` structure. * * Note that some parameters may be overwritten by options * passed to fuse_session_new() which take precedence over the * values set in this handler. * * There's no reply to this function * * @param userdata the user data passed to fuse_session_new() */ void (*init) (void *userdata, struct fuse_conn_info *conn); /** * Clean up filesystem. * * Called on filesystem exit. When this method is called, the * connection to the kernel may be gone already, so that eg. calls * to fuse_lowlevel_notify_* will fail. * * There's no reply to this function * * @param userdata the user data passed to fuse_session_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, rmdir or rename will be followed closely by forget * unless the file or directory is open, in which case the * kernel issues forget only after the release or releasedir * calls. * * Note that if a file system will be exported over NFS the * inodes lifetime must extend even beyond forget. See the * generation field in struct fuse_entry_param above. * * On unmount the lookup count for all inodes implicitly drops * to zero. It is not guaranteed that the file system will * receive corresponding forget messages for the affected * inodes. * * Valid replies: * fuse_reply_none * * @param req request handle * @param ino the inode number * @param nlookup the number of lookups to forget */ void (*forget) (fuse_req_t req, fuse_ino_t ino, uint64_t nlookup); /** * Get file attributes. * * If writeback caching is enabled, the kernel may have a * better idea of a file's length than the FUSE file system * (eg if there has been a write that extended the file size, * but that has not yet been passed to the filesystem. * * In this case, the st_size value provided by the file system * will be ignored. * * Valid replies: * fuse_reply_attr * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information, or 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. * * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is * expected to reset the setuid and setgid bits if the file * size or owner is being changed. * * This method will not be called to update st_atime or st_ctime implicitly * (eg. after a read() request), and only be called to implicitly update st_mtime * if writeback caching is active. It is the filesystem's responsibility to update * these timestamps when needed, and (if desired) to implement mount options like * `noatime` or `relatime`. * * 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 */ 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). * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EINVAL, i.e. all * future rename requests will fail with EINVAL without being * send to the filesystem process. * * *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. * * 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, unsigned int flags); /** * 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 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 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 and release will also succeed without being * sent to the filesystem process. * * To get this behavior without providing an opendir handler, you may * set FUSE_CAP_NO_OPEN_SUPPORT in `fuse_conn_info.want` on supported * kernels to automatically get the zero message open(). * * If this callback is not provided and FUSE_CAP_NO_OPEN_SUPPORT is not * set in `fuse_conn_info.want` then an empty reply will be sent. * * 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. * * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is * expected to reset the setuid and setgid bits. * * 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 during close. However, such use is non-portable * because POSIX does not require [close] to wait for delayed I/O to * complete. * * If the filesystem supports file locking operations (setlk, * getlk) it should remove all locks belonging to 'fi->owner'. * * If this request is answered with an error code of ENOSYS, * this is treated as success and future calls to flush() will * succeed automatically without being send to the filesystem * process. * * Valid replies: * fuse_reply_err * * @param req request handle * @param ino the inode number * @param fi file information * * [close]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html */ 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 (unless * the filesystem is force-unmounted). * * 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. * * If this request is answered with an error code of ENOSYS, * this is treated as success and future calls to fsync() will * succeed automatically without being send to the filesystem * process. * * 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). * * If this request is answered with an error code of ENOSYS and * FUSE_CAP_NO_OPENDIR_SUPPORT is set in `fuse_conn_info.capable`, * this is treated as success and future calls to opendir and * releasedir will also succeed without being sent to the filesystem * process. In addition, the kernel will cache readdir results * as if opendir returned FOPEN_KEEP_CACHE | FOPEN_CACHE_DIR. * * To get this behavior without providing an opendir handler, you may * set FUSE_CAP_NO_OPENDIR_SUPPORT in `fuse_conn_info.want` on supported * kernels to automatically get the zero message opendir(). * * If this callback is not provided and FUSE_CAP_NO_OPENDIR_SUPPORT is * not set in `fuse_conn_info.want` then an empty reply will be sent. * * 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. * * Returning a directory entry from readdir() does not affect * its lookup count. * * If off_t is non-zero, then it will correspond to one of the off_t * values that was previously returned by readdir() for the same * directory handle. In this case, readdir() should skip over entries * coming before the position defined by the off_t value. If entries * are added or removed while the directory handle is open, the filesystem * may still include the entries that have been removed, and may not * report the entries that have been created. However, addition or * removal of entries must never cause readdir() to skip over unrelated * entries or to report them more than once. This means * that off_t can not be a simple index that enumerates the entries * that have been returned but must contain sufficient information to * uniquely determine the next directory entry to return even when the * set of entries is changing. * * The function does not have to report the '.' and '..' * entries, but is allowed to do so. Note that, if readdir does * not return '.' or '..', they will not be implicitly returned, * and this behavior is observable by the caller. * * 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 (unless the filesystem is force-unmounted). * * 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. * * If this request is answered with an error code of ENOSYS, * this is treated as success and future calls to fsyncdir() will * succeed automatically without being send to the filesystem * process. * * 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 * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future setxattr() requests will fail with EOPNOTSUPP without being * send to the filesystem process. * * 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. * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future getxattr() requests will fail with EOPNOTSUPP without being * send to the filesystem process. * * 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. * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future listxattr() requests will fail with EOPNOTSUPP without being * send to the filesystem process. * * 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 * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future removexattr() requests will fail with EOPNOTSUPP without being * send to the filesystem process. * * 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() and chdir() system * calls. 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 * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent success, i.e. this and all future access() * requests will succeed without being send to the filesystem process. * * 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. * * See the description of the open handler for more * information. * * 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. * * If this request is answered with an error code of ENOSYS, the handler * is treated as not implemented (i.e., for this and future requests the * mknod() and open() handlers will be called instead). * * 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 * * 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. * * 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 * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure, i.e. all future bmap() requests will * fail with the same error code without being send to the filesystem * process. * * 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); #if FUSE_USE_VERSION < 35 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); #else /** * 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. * * 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 * * Note : the unsigned long request submitted by the application * is truncated to 32 bits. */ void (*ioctl) (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz); #endif /** * Poll for IO readiness * * The client should immediately respond with fuse_reply_poll(), * setting revents appropriately according to which events are ready. * * Additionally, if ph is non-NULL, the client must retain it and * notify when all future IO readiness events occur by calling * fuse_lowlevel_notify_poll() with the specified ph. * * Regardless of the number of times poll with a non-NULL ph is * received, a single notify_poll is enough to service all. (Notifying * more times incurs overhead but doesn't harm correctness.) Any * additional received handles can be immediately destroyed. * * The callee is responsible for destroying ph with * fuse_pollhandle_destroy() when no longer in use. * * If this request is answered with an error code of ENOSYS, this is * treated as success (with a kernel-defined default poll-mask) and * future calls to poll() will succeed the same way without being send * to the filesystem process. * * 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]). * * Unless FUSE_CAP_HANDLE_KILLPRIV is disabled, this method is * expected to reset the setuid and setgid bits. * * 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 * * 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. * * 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. * * 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. * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future fallocate() requests will fail with EOPNOTSUPP without being * send to the filesystem process. * * 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); /** * Read directory with attributes * * Send a buffer filled using fuse_add_direntry_plus(), with size not * exceeding the requested size. Send an empty buffer on end of * stream. * * fi->fh will contain the value set by the opendir method, or * will be undefined if the opendir method didn't set any value. * * In contrast to readdir() (which does not affect the lookup counts), * the lookup count of every entry returned by readdirplus(), except "." * and "..", is incremented by one. * * Valid replies: * fuse_reply_buf * fuse_reply_data * fuse_reply_err * * @param req request handle * @param ino the inode number * @param size maximum number of bytes to send * @param off offset to continue reading the directory stream * @param fi file information */ void (*readdirplus) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi); /** * Copy a range of data from one file to another * * Performs an optimized copy between two file descriptors without the * additional cost of transferring data through the FUSE kernel module * to user space (glibc) and then back into the FUSE filesystem again. * * In case this method is not implemented, glibc falls back to reading * data from the source and writing to the destination. Effectively * doing an inefficient copy of the data. * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure with error code EOPNOTSUPP, i.e. all * future copy_file_range() requests will fail with EOPNOTSUPP without * being send to the filesystem process. * * Valid replies: * fuse_reply_write * fuse_reply_err * * @param req request handle * @param ino_in the inode number or the source file * @param off_in starting point from were the data should be read * @param fi_in file information of the source file * @param ino_out the inode number or the destination file * @param off_out starting point where the data should be written * @param fi_out file information of the destination file * @param len maximum size of the data to copy * @param flags passed along with the copy_file_range() syscall */ void (*copy_file_range) (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags); /** * Find next data or hole after the specified offset * * If this request is answered with an error code of ENOSYS, this is * treated as a permanent failure, i.e. all future lseek() requests will * fail with the same error code without being send to the filesystem * process. * * Valid replies: * fuse_reply_lseek * fuse_reply_err * * @param req request handle * @param ino the inode number * @param off offset to start search from * @param whence either SEEK_DATA or SEEK_HOLE * @param fi file information */ void (*lseek) (fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi); /** * Create a tempfile * * Tempfile means an anonymous file. It can be made into a normal file later * by using linkat or such. * * If this is answered with an error ENOSYS this is treated by the kernel as * a permanent failure and it will disable the feature and not ask again. * * Valid replies: * fuse_reply_create * fuse_reply_err * * @param req request handle * @param parent inode number of the parent directory * @param mode file type and mode with which to create the new file * @param fi file information */ void (*tmpfile) (fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi); /** * Get extended file attributes. * * Valid replies: * fuse_reply_statx * fuse_reply_err * * @param req request handle * @param ino the inode number * @param flags bitmask of requested flags * @param mask bitmask of requested fields * @param fi file information (may be NULL) */ void (*statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi); }; /** * Reply with an error code or success. * * Possible requests: * all except forget, forget_multi, retrieve_reply * * Wherever possible, error codes should be chosen from the list of * documented error conditions in the corresponding system calls * manpage. * * An error code of ENOSYS is sometimes treated specially. This is * indicated in the documentation of the affected handler functions. * * The following requests may be answered with a zero error code: * unlink, rmdir, rename, flush, release, fsync, fsyncdir, setxattr, * removexattr, setlk. * * @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 * forget_multi * retrieve_reply * * @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, cache_readdir, nonseekable, noflush, * parallel_direct_writes * * 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); /** * Setup passthrough backing file for open reply * * Currently there should be only one backing id per node / backing file. * * Possible requests: * open, opendir, create * * @param req request handle * @param fd backing file descriptor * @return positive backing id for success, 0 for failure */ int fuse_passthrough_open(fuse_req_t req, int fd); int fuse_passthrough_close(fuse_req_t req, int backing_id); /** * Reply with open parameters * * currently the following members of 'fi' are used: * fh, direct_io, keep_cache, cache_readdir, nonseekable, noflush, * parallel_direct_writes, * * 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) * * Zero copy data transfer ("splicing") will be used under * the following circumstances: * * 1. FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.want, and * 2. the kernel supports splicing from the fuse device * (FUSE_CAP_SPLICE_WRITE is set in fuse_conn_info.capable), and * 3. *flags* does not contain FUSE_BUF_NO_SPLICE * 4. The amount of data that is provided in file-descriptor backed * buffers (i.e., buffers for which bufv[n].flags == FUSE_BUF_FD) * is at least twice the page size. * * In order for SPLICE_F_MOVE to be used, the following additional * conditions have to be fulfilled: * * 1. FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.want, and * 2. the kernel supports it (i.e, FUSE_CAP_SPLICE_MOVE is set in fuse_conn_info.capable), and * 3. *flags* contains FUSE_BUF_SPLICE_MOVE * * Note that, if splice is used, the data is actually spliced twice: * once into a temporary pipe (to prepend header data), and then again * into the kernel. If some of the provided buffers are memory-backed, * the data in them is copied in step one and spliced in step two. * * The FUSE_BUF_SPLICE_FORCE_SPLICE and FUSE_BUF_SPLICE_NONBLOCK flags * are silently ignored. * * Possible requests: * read, readdir, getxattr, listxattr * * Side effects: * when used to return data from a readdirplus() (but not readdir()) * call, increments the lookup count of each returned entry by one * on success. * * @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. * * *off* should be any non-zero value that the filesystem can use to * identify the current point in the directory stream. It does not * need to be the actual physical position. A value of zero is * reserved to mean "from the beginning", and should therefore never * be used (the first call to fuse_add_direntry should be passed the * offset of the second directory entry). * * @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); /** * Add a directory entry to the buffer with the attributes * * See documentation of `fuse_add_direntry()` for more details. * * @param req request handle * @param buf the point where the new entry will be added to the buffer * @param bufsize remaining size of the buffer * @param name the name of the entry * @param e the directory entry * @param off the offset of the next entry * @return the space needed for the entry */ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct fuse_entry_param *e, off_t off); /** * Reply to ask for data fetch and output buffer preparation. ioctl * will be retried with the specified input data fetched and output * buffer prepared. * * 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); /** * Reply with offset * * Possible requests: * lseek * * @param req request handle * @param off offset of next data or hole * @return zero for success, -errno for failure to send reply */ int fuse_reply_lseek(fuse_req_t req, off_t off); /** * Reply with extended file attributes. * * Possible requests: * statx * * @param req request handle * @param flags statx flags * @param statx 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_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout); /* ----------------------------------------------------------- * * 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. * * Added in FUSE protocol version 7.12. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do * nothing. * * If the filesystem has writeback caching enabled, invalidating an * inode will first trigger a writeback of all dirty pages. The call * will block until all writeback requests have completed and the * inode has been invalidated. It will, however, not wait for * completion of pending writeback requests that have been issued * before. * * If there are no dirty pages, this function will never block. * * @param se the session object * @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_session *se, fuse_ino_t ino, off_t off, off_t len); /** * Notify to increment the epoch for the current * * Each fuse connection has an 'epoch', which is initialized during INIT. * Caching will then be validated against the epoch value: if the current epoch * is higher than an object being revalidated, the object is invalid. * * This function simply increment the current epoch value. * * @param se the session object * @return zero for success, -errno for failure */ int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se); /** * Notify to invalidate parent attributes and the dentry matching parent/name * * To avoid a deadlock this function must not be called in the * execution path of a related filesystem operation or within any code * that could hold a lock that could be needed to execute such an * operation. As of kernel 4.18, a "related operation" is a lookup(), * symlink(), mknod(), mkdir(), unlink(), rename(), link() or create() * request for the parent, and a setattr(), unlink(), rmdir(), * rename(), setxattr(), removexattr(), readdir() or readdirplus() * request for the inode itself. * * When called correctly, this function will never block. * * Added in FUSE protocol version 7.12. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do * nothing. * * @param se the session object * @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_session *se, fuse_ino_t parent, const char *name, size_t namelen); /** * Notify to expire parent attributes and the dentry matching parent/name * * Same restrictions apply as for fuse_lowlevel_notify_inval_entry() * * Compared to invalidating an entry, expiring the entry results not in a * forceful removal of that entry from kernel cache but instead the next access * to it forces a lookup from the filesystem. * * This makes a difference for overmounted dentries, where plain invalidation * would detach all submounts before dropping the dentry from the cache. * If only expiry is set on the dentry, then any overmounts are left alone and * until ->d_revalidate() is called. * * Note: ->d_revalidate() is not called for the case of following a submount, * so invalidation will only be triggered for the non-overmounted case. * The dentry could also be mounted in a different mount instance, in which case * any submounts will still be detached. * * Added in FUSE protocol version 7.38. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do nothing. * * @param se the session object * @param parent inode number * @param name file name * @param namelen strlen() of file name * @return zero for success, -errno for failure, -enosys if no kernel support */ int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen); /** * This function behaves like fuse_lowlevel_notify_inval_entry() with * the following additional effect (at least as of Linux kernel 4.8): * * If the provided *child* inode matches the inode that is currently * associated with the cached dentry, and if there are any inotify * watches registered for the dentry, then the watchers are informed * that the dentry has been deleted. * * To avoid a deadlock this function must not be called while * executing a related filesystem operation or while holding a lock * that could be needed to execute such an operation (see the * description of fuse_lowlevel_notify_inval_entry() for more * details). * * When called correctly, this function will never block. * * Added in FUSE protocol version 7.18. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do * nothing. * * @param se the session object * @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_session *se, 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. * * Added in FUSE protocol version 7.15. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do * nothing. * * @param se the session object * @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_session *se, 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. * * Added in FUSE protocol version 7.15. If the kernel does not support * this (or a newer) version, the function will return -ENOSYS and do * nothing. * * @param se the session object * @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_session *se, 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_session_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); /* ----------------------------------------------------------- * * Inquiry functions * * ----------------------------------------------------------- */ /** * Print low-level version information to stdout. */ void fuse_lowlevel_version(void); /** * Print available low-level options to stdout. This is not an * exhaustive list, but includes only those options that may be of * interest to an end-user of a file system. */ void fuse_lowlevel_help(void); /** * Print available options for `fuse_parse_cmdline()`. */ void fuse_cmdline_help(void); /* ----------------------------------------------------------- * * Filesystem setup & teardown * * ----------------------------------------------------------- */ /** * Note: Any addition to this struct needs to create a compatibility symbol * for fuse_parse_cmdline(). For ABI compatibility reasons it is also * not possible to remove struct members. */ struct fuse_cmdline_opts { int singlethread; int foreground; int debug; int nodefault_subtype; char *mountpoint; int show_version; int show_help; int clone_fd; unsigned int max_idle_threads; /* discouraged, due to thread * destruct overhead */ /* Added in libfuse-3.12 */ unsigned int max_threads; }; /** * Utility function to parse common options for simple file systems * using the low-level API. A help text that describes the available * options can be printed with `fuse_cmdline_help`. A single * non-option argument is treated as the mountpoint. Multiple * non-option arguments will result in an error. * * If neither -o subtype= or -o fsname= options are given, a new * subtype option will be added and set to the basename of the program * (the fsname will remain unset, and then defaults to "fuse"). * * Known options will be removed from *args*, unknown options will * remain. * * @param args argument vector (input+output) * @param opts output argument for parsed options * @return 0 on success, -1 on failure */ #if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS)) int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts); #else #if FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts); #define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_30(args, opts) #else int fuse_parse_cmdline_312(struct fuse_args *args, struct fuse_cmdline_opts *opts); #define fuse_parse_cmdline(args, opts) fuse_parse_cmdline_312(args, opts) #endif #endif /* Do not call this directly, use fuse_session_new() instead */ struct fuse_session * fuse_session_new_versioned(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, struct libfuse_version *version, void *userdata); /** * Create a low level session. * * Returns a session structure suitable for passing to * fuse_session_mount() and fuse_session_loop(). * * This function accepts most file-system independent mount options * (like context, nodev, ro - see mount(8)), as well as the general * fuse mount options listed in mount.fuse(8) (e.g. -o allow_root and * -o default_permissions, but not ``-o use_ino``). Instead of `-o * debug`, debugging may also enabled with `-d` or `--debug`. * * If not all options are known, an error message is written to stderr * and the function returns NULL. * * To create a no-op session just for mounting pass op as NULL. * * Option parsing skips argv[0], which is assumed to contain the * program name. To prevent accidentally passing an option in * argv[0], this element must always be present (even if no options * are specified). It may be set to the empty string ('\0') if no * reasonable value can be provided. * * @param args argument vector * @param op the (low-level) filesystem operations * @param op_size sizeof(struct fuse_lowlevel_ops) * @param version the libfuse version a file system server was compiled against * @param userdata user data * @return the fuse session on success, NULL on failure **/ static inline struct fuse_session * fuse_session_new_fn(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { struct libfuse_version version = { .major = FUSE_MAJOR_VERSION, .minor = FUSE_MINOR_VERSION, .hotfix = FUSE_HOTFIX_VERSION, .padding = 0 }; return fuse_session_new_versioned(args, op, op_size, &version, userdata); } #define fuse_session_new(args, op, op_size, userdata) \ fuse_session_new_fn(args, op, op_size, userdata) /* * This should mostly not be called directly, but instead the * fuse_session_custom_io() should be used. */ int fuse_session_custom_io_317(struct fuse_session *se, const struct fuse_custom_io *io, size_t op_size, int fd); /** * Set a file descriptor for the session. * * This function can be used if you want to have a custom communication * interface instead of using a mountpoint. In practice, this means that instead * of calling fuse_session_mount() and fuse_session_unmount(), one could call * fuse_session_custom_io() where fuse_session_mount() would have otherwise been * called. * * In `io`, implementations for read and writev MUST be provided. Otherwise -1 * will be returned and `fd` will not be used. Implementations for `splice_send` * and `splice_receive` are optional. If they are not provided splice will not * be used for send or receive respectively. * * The provided file descriptor `fd` will be closed when fuse_session_destroy() * is called. * * Requires a library built with -Denable-custom-io=true. The peer at the other * end of `fd` takes the place of the kernel as the sender of requests, so it * owes the session the validation the kernel would have done -- libfuse does * not repeat it. A request whose length or count field exceeds the bytes that * actually arrived makes the handlers read past the receive buffer and crash * the filesystem process. * * @param se session object * @param io Custom io to use when retrieving/sending requests/responses * @param fd file descriptor for the session * * @return 0 on success * @return -EINVAL if `io`, `io->read` or `ìo->writev` are NULL * @return -EBADF if `fd` was smaller than 0 * @return -errno if failed to allocate memory to store `io` * @return -ENOTSUP if the library was built without custom io * **/ #if FUSE_MAKE_VERSION(3, 17) <= FUSE_USE_VERSION static inline int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, size_t op_size, int fd) { return fuse_session_custom_io_317(se, io, op_size, fd); } #else static inline int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, int fd) { return fuse_session_custom_io_317(se, io, offsetof(struct fuse_custom_io, clone_fd), fd); } #endif /** * Mount a FUSE file system. * * @param mountpoint the mount point path * @param se session object * * @return 0 on success, -1 on failure. **/ int fuse_session_mount(struct fuse_session *se, const char *mountpoint); /** * Enter a single threaded, blocking event loop. * * When the event loop terminates because the connection to the FUSE * kernel module has been closed, this function returns zero. This * happens when the filesystem is unmounted regularly (by the * filesystem owner or root running the umount(8) or fusermount(1) * command), or if connection is explicitly severed by writing ``1`` * to the``abort`` file in ``/sys/fs/fuse/connections/NNN``. The only * way to distinguish between these two conditions is to check if the * filesystem is still mounted after the session loop returns. * * When some error occurs during request processing, the function * returns a negated errno(3) value. * * If the loop has been terminated because of a signal handler * installed by fuse_set_signal_handlers(), this function returns the * (positive) signal value that triggered the exit. * * @param se the session * @return 0, -errno, or a signal value */ int fuse_session_loop(struct fuse_session *se); #if FUSE_USE_VERSION < 32 int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); #define fuse_session_loop_mt(se, clone_fd) fuse_session_loop_mt_31(se, clone_fd) #elif FUSE_USE_VERSION < FUSE_MAKE_VERSION(3, 12) int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config *config); #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_32(se, config) #else #if (defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS)) /** * Enter a multi-threaded event loop. * * For a description of the return value and the conditions when the * event loop exits, refer to the documentation of * fuse_session_loop(). * * @param se the session * @param config session loop configuration * @return see fuse_session_loop() */ int fuse_session_loop_mt(struct fuse_session *se, struct fuse_loop_config *config); #else int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); #define fuse_session_loop_mt(se, config) fuse_session_loop_mt_312(se, config) #endif #endif /** * Flag a session as terminated. * * This will cause any running event loop to terminate on the next opportunity. * fuse_session_loop_mt(), and fuse_session_loop() from FUSE_USE_VERSION 3.19 * on, are woken up directly and return without waiting for a request, no * matter which thread calls this. * * The deprecated fuse_session_loop() below FUSE_USE_VERSION 3.19 is not woken * up and only notices the flag once the next request is received, which may be * far in the future if the filesystem is not currently being used by any * clients. Sending a signal to its thread afterwards avoids that delay - if * fuse_set_signal_handlers() is used, SIGPIPE will cause the thread to wake-up * but otherwise be ignored. * * @param se the session */ void fuse_session_exit(struct fuse_session *se); /** * Reset the terminated flag of a session * * @param se the session */ void fuse_session_reset(struct fuse_session *se); /** * Query the terminated flag of a session * * @param se the session * @return 1 if exited, 0 if not exited */ int fuse_session_exited(struct fuse_session *se); /** * Ensure that file system is unmounted. * * In regular operation, the file system is typically unmounted by the * user calling umount(8) or fusermount(1), which then terminates the * FUSE session loop. However, the session loop may also terminate as * a result of an explicit call to fuse_session_exit() (e.g. by a * signal handler installed by fuse_set_signal_handler()). In this * case the filesystem remains mounted, but any attempt to access it * will block (while the filesystem process is still running) or give * an ESHUTDOWN error (after the filesystem process has terminated). * * If the communication channel with the FUSE kernel module is still * open (i.e., if the session loop was terminated by an explicit call * to fuse_session_exit()), this function will close it and unmount * the filesystem. If the communication channel has been closed by the * kernel, this method will do (almost) nothing. * * NOTE: The above semantics mean that if the connection to the kernel * is terminated via the ``/sys/fs/fuse/connections/NNN/abort`` file, * this method will *not* unmount the filesystem. * * @param se the session */ void fuse_session_unmount(struct fuse_session *se); /** * Destroy a session * * @param se the session */ void fuse_session_destroy(struct fuse_session *se); /* ----------------------------------------------------------- * * Custom event loop support * * ----------------------------------------------------------- */ /** * Return file descriptor for communication with kernel. * * The file selector can be used to integrate FUSE with a custom event * loop. Whenever data is available for reading on the provided fd, * the event loop should call `fuse_session_receive_buf` followed by * `fuse_session_process_buf` to process the request. * * The returned file descriptor is valid until `fuse_session_unmount` * is called. * * @param se the session * @return a file descriptor */ int fuse_session_fd(struct fuse_session *se); /** * Process a raw request supplied in a generic buffer * * 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 */ void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf); /** * Read a raw request from the kernel into the supplied buffer. * * Depending on file system options, system capabilities, and request * size the request is either read into a memory buffer or spliced * into a temporary pipe. * * @param se the session * @param buf the fuse_buf to store the request in * @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); /** * Check if the request is submitted through fuse-io-uring */ bool fuse_req_is_uring(fuse_req_t req); /** * Get the payload of a request * (for requests submitted through fuse-io-uring only) * * This is useful for a file system that wants to write data directly * to the request buffer. With io-uring the req is the buffer owner * and the file system can write directly to the buffer and avoid * extra copying. For example useful for network file systems. * * @param req the request * @param payload pointer to the payload * @param payload_sz size of the payload * @param mr memory registration handle, currently unused * @return 0 on success, -errno on failure */ int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr); #ifdef __cplusplus } #endif #endif /* FUSE_LOWLEVEL_H_ */ fuse-3.18.3/include/fuse_mount_compat.h0000644000175000017500000000204615250106036017041 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2023 Giulio Benetti Logging API. This program can be distributed under the terms of the GNU LGPLv2. See the file LICENSE */ #ifndef FUSE_MOUNT_COMPAT_H_ #define FUSE_MOUNT_COMPAT_H_ #include /* Some libc don't define MS_*, so define them manually * (values taken from https://elixir.bootlin.com/linux/v6.10/source/include/uapi/linux/mount.h#L13 on) */ #ifndef MS_DIRSYNC #define MS_DIRSYNC 128 #endif #ifndef MS_NOSYMFOLLOW #define MS_NOSYMFOLLOW 256 #endif #ifndef MS_REC #define MS_REC 16384 #endif #ifndef MS_PRIVATE #define MS_PRIVATE (1<<18) #endif #ifndef MS_LAZYTIME #define MS_LAZYTIME (1<<25) #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 #endif /* FUSE_MOUNT_COMPAT_H_ */ fuse-3.18.3/include/fuse_opt.h0000644000175000017500000001657315250106036015150 0ustar berndbernd/* 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 LGPL2.txt. */ #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(). The previous value (if non-NULL) stored at the this location is * freed. */ 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-3.18.3/include/meson.build0000644000175000017500000000026215250106036015301 0ustar berndberndlibfuse_headers = [ 'fuse.h', 'fuse_common.h', 'fuse_lowlevel.h', 'fuse_opt.h', 'cuse_lowlevel.h', 'fuse_log.h' ] install_headers(libfuse_headers, subdir: 'fuse3') fuse-3.18.3/lib/0000755000175000017500000000000015250106036012262 5ustar berndberndfuse-3.18.3/lib/buffer.c0000644000175000017500000001471415250106036013706 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2010 Miklos Szeredi Functions for dealing with `struct fuse_buf` and `struct fuse_bufvec`. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #define _GNU_SOURCE #include "fuse_config.h" #include "fuse_i.h" #include "fuse_lowlevel.h" #include #include #include #include size_t fuse_buf_size(const struct fuse_bufvec *bufv) { size_t i; size_t size = 0; for (i = 0; i < bufv->count; i++) { if (bufv->buf[i].size >= SIZE_MAX - size) return SIZE_MAX; size += bufv->buf[i].size; } return size; } static size_t min_size(size_t s1, size_t s2) { return s1 < s2 ? s1 : s2; } static ssize_t fuse_buf_write(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { ssize_t res = 0; size_t copied = 0; while (len) { if (dst->flags & FUSE_BUF_FD_SEEK) { res = pwrite(dst->fd, (char *)src->mem + src_off, len, dst->pos + dst_off); } else { res = write(dst->fd, (char *)src->mem + src_off, len); } if (res == -1) { if (!copied) return -errno; break; } if (res == 0) break; copied += res; if (!(dst->flags & FUSE_BUF_FD_RETRY)) break; src_off += res; dst_off += res; len -= res; } return copied; } static ssize_t fuse_buf_read(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { ssize_t res = 0; size_t copied = 0; while (len) { if (src->flags & FUSE_BUF_FD_SEEK) { res = pread(src->fd, (char *)dst->mem + dst_off, len, src->pos + src_off); } else { res = read(src->fd, (char *)dst->mem + dst_off, len); } if (res == -1) { if (!copied) return -errno; break; } if (res == 0) break; copied += res; if (!(src->flags & FUSE_BUF_FD_RETRY)) break; dst_off += res; src_off += res; len -= res; } return copied; } static ssize_t fuse_buf_fd_to_fd(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len) { char buf[4096]; struct fuse_buf tmp = { .size = sizeof(buf), .flags = 0, }; ssize_t res; size_t copied = 0; tmp.mem = buf; while (len) { size_t this_len = min_size(tmp.size, len); size_t read_len; res = fuse_buf_read(&tmp, 0, src, src_off, this_len); if (res < 0) { if (!copied) return res; break; } if (res == 0) break; read_len = res; res = fuse_buf_write(dst, dst_off, &tmp, 0, read_len); if (res < 0) { if (!copied) return res; break; } if (res == 0) break; copied += res; if (res < this_len) break; dst_off += res; src_off += res; len -= res; } return copied; } #ifdef HAVE_SPLICE static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { int splice_flags = 0; off_t *srcpos = NULL; off_t *dstpos = NULL; off_t srcpos_val; off_t dstpos_val; ssize_t res; size_t copied = 0; if (flags & FUSE_BUF_SPLICE_MOVE) splice_flags |= SPLICE_F_MOVE; if (flags & FUSE_BUF_SPLICE_NONBLOCK) splice_flags |= SPLICE_F_NONBLOCK; if (src->flags & FUSE_BUF_FD_SEEK) { srcpos_val = src->pos + src_off; srcpos = &srcpos_val; } if (dst->flags & FUSE_BUF_FD_SEEK) { dstpos_val = dst->pos + dst_off; dstpos = &dstpos_val; } while (len) { res = splice(src->fd, srcpos, dst->fd, dstpos, len, splice_flags); if (res == -1) { if (copied) break; if (errno != EINVAL || (flags & FUSE_BUF_FORCE_SPLICE)) return -errno; /* Maybe splice is not supported for this combination */ return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); } if (res == 0) break; copied += res; if (!(src->flags & FUSE_BUF_FD_RETRY) && !(dst->flags & FUSE_BUF_FD_RETRY)) { break; } len -= res; } return copied; } #else static ssize_t fuse_buf_splice(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { (void) flags; return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); } #endif static ssize_t fuse_buf_copy_one(const struct fuse_buf *dst, size_t dst_off, const struct fuse_buf *src, size_t src_off, size_t len, enum fuse_buf_copy_flags flags) { int src_is_fd = src->flags & FUSE_BUF_IS_FD; int dst_is_fd = dst->flags & FUSE_BUF_IS_FD; if (!src_is_fd && !dst_is_fd) { char *dstmem = (char *)dst->mem + dst_off; char *srcmem = (char *)src->mem + src_off; if (dstmem != srcmem) { if (dstmem + len <= srcmem || srcmem + len <= dstmem) memcpy(dstmem, srcmem, len); else memmove(dstmem, srcmem, len); } return len; } else if (!src_is_fd) { return fuse_buf_write(dst, dst_off, src, src_off, len); } else if (!dst_is_fd) { return fuse_buf_read(dst, dst_off, src, src_off, len); } else if (flags & FUSE_BUF_NO_SPLICE) { return fuse_buf_fd_to_fd(dst, dst_off, src, src_off, len); } else { return fuse_buf_splice(dst, dst_off, src, src_off, len, flags); } } static const struct fuse_buf *fuse_bufvec_current(struct fuse_bufvec *bufv) { if (bufv->idx < bufv->count) return &bufv->buf[bufv->idx]; else return NULL; } static int fuse_bufvec_advance(struct fuse_bufvec *bufv, size_t len) { const struct fuse_buf *buf = fuse_bufvec_current(bufv); if (!buf) return 0; bufv->off += len; assert(bufv->off <= buf->size); if (bufv->off == buf->size) { assert(bufv->idx < bufv->count); bufv->idx++; if (bufv->idx == bufv->count) return 0; bufv->off = 0; } return 1; } ssize_t fuse_buf_copy(struct fuse_bufvec *dstv, struct fuse_bufvec *srcv, enum fuse_buf_copy_flags flags) { size_t copied = 0; if (dstv == srcv) return fuse_buf_size(dstv); for (;;) { const struct fuse_buf *src = fuse_bufvec_current(srcv); const struct fuse_buf *dst = fuse_bufvec_current(dstv); size_t src_len; size_t dst_len; size_t len; ssize_t res; if (src == NULL || dst == NULL) break; src_len = src->size - srcv->off; dst_len = dst->size - dstv->off; len = min_size(src_len, dst_len); res = fuse_buf_copy_one(dst, dstv->off, src, srcv->off, len, flags); if (res < 0) { if (!copied) return res; break; } copied += res; if (!fuse_bufvec_advance(srcv, res) || !fuse_bufvec_advance(dstv, res)) break; if (res < len) break; } return copied; } fuse-3.18.3/lib/compat.c0000644000175000017500000000533615250106036013720 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Helper functions to create (simple) standalone programs. With the aid of these functions it should be possible to create full FUSE file system by implementing nothing but the request handlers. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ /* Description: This file has compatibility symbols for platforms that do not support version symboling */ #include "libfuse_config.h" #include #include struct fuse_args; struct fuse_cmdline_opts; struct fuse_cmdline_opts; struct fuse_session; struct fuse_custom_io; struct fuse_operations; struct fuse_lowlevel_ops; /** * Compatibility ABI symbol for systems that do not support version symboling */ #if (!defined(LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS)) /* With current libfuse fuse_parse_cmdline is a macro pointing to the * versioned function. Here in this file we need to provide the ABI symbol * and the redirecting macro is conflicting. */ #ifdef fuse_parse_cmdline #undef fuse_parse_cmdline #endif int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts); int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts); int fuse_parse_cmdline(struct fuse_args *args, struct fuse_cmdline_opts *opts) { return fuse_parse_cmdline_30(args, opts); } int fuse_session_custom_io_30(struct fuse_session *se, const struct fuse_custom_io *io, int fd); int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, int fd); int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, int fd) { return fuse_session_custom_io_30(se, io, fd); } #endif /* LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS */ int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data); int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data); int fuse_main_real(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { return fuse_main_real_30(argc, argv, op, op_size, user_data); } struct fuse_session *fuse_session_new_30(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); struct fuse_session *fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); struct fuse_session *fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { return fuse_session_new_30(args, op, op_size, userdata); } fuse-3.18.3/lib/cuse_lowlevel.c0000644000175000017500000002172315250106036015303 0ustar berndbernd/* CUSE: Character device in Userspace Copyright (C) 2008 SUSE Linux Products GmbH Copyright (C) 2008 Tejun Heo This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #include "fuse_config.h" #include "cuse_lowlevel.h" #include "fuse_kernel.h" #include "fuse_i.h" #include "fuse_opt.h" #include #include #include #include #include #include struct cuse_data { struct cuse_lowlevel_ops clop; unsigned max_read; unsigned dev_major; unsigned dev_minor; unsigned flags; unsigned dev_info_len; char dev_info[]; }; static struct cuse_lowlevel_ops *req_clop(fuse_req_t req) { return &req->se->cuse_data->clop; } static void cuse_fll_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { (void)ino; req_clop(req)->open(req, fi); } static void cuse_fll_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { (void)ino; req_clop(req)->read(req, size, off, fi); } static void cuse_fll_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { (void)ino; req_clop(req)->write(req, buf, size, off, fi); } static void cuse_fll_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { (void)ino; req_clop(req)->flush(req, fi); } static void cuse_fll_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { (void)ino; req_clop(req)->release(req, fi); } static void cuse_fll_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { (void)ino; req_clop(req)->fsync(req, datasync, fi); } static void cuse_fll_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { (void)ino; req_clop(req)->ioctl(req, cmd, arg, fi, flags, in_buf, in_bufsz, out_bufsz); } static void cuse_fll_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph) { (void)ino; req_clop(req)->poll(req, fi, ph); } static size_t cuse_pack_info(int argc, const char **argv, char *buf) { size_t size = 0; int i; for (i = 0; i < argc; i++) { size_t len; len = strlen(argv[i]) + 1; size += len; if (buf) { memcpy(buf, argv[i], len); buf += len; } } return size; } static struct cuse_data *cuse_prep_data(const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop) { struct cuse_data *cd; size_t dev_info_len; dev_info_len = cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, NULL); if (dev_info_len > CUSE_INIT_INFO_MAX) { fuse_log(FUSE_LOG_ERR, "cuse: dev_info (%zu) too large, limit=%u\n", dev_info_len, CUSE_INIT_INFO_MAX); return NULL; } cd = calloc(1, sizeof(*cd) + dev_info_len); if (!cd) { fuse_log(FUSE_LOG_ERR, "cuse: failed to allocate cuse_data\n"); return NULL; } memcpy(&cd->clop, clop, sizeof(cd->clop)); cd->max_read = 131072; cd->dev_major = ci->dev_major; cd->dev_minor = ci->dev_minor; cd->dev_info_len = dev_info_len; cd->flags = ci->flags; cuse_pack_info(ci->dev_info_argc, ci->dev_info_argv, cd->dev_info); return cd; } struct fuse_session *cuse_lowlevel_new(struct fuse_args *args, const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata) { struct fuse_lowlevel_ops lop; struct cuse_data *cd; struct fuse_session *se; cd = cuse_prep_data(ci, clop); if (!cd) return NULL; memset(&lop, 0, sizeof(lop)); lop.init = clop->init; lop.destroy = clop->destroy; lop.open = clop->open ? cuse_fll_open : NULL; lop.read = clop->read ? cuse_fll_read : NULL; lop.write = clop->write ? cuse_fll_write : NULL; lop.flush = clop->flush ? cuse_fll_flush : NULL; lop.release = clop->release ? cuse_fll_release : NULL; lop.fsync = clop->fsync ? cuse_fll_fsync : NULL; lop.ioctl = clop->ioctl ? cuse_fll_ioctl : NULL; lop.poll = clop->poll ? cuse_fll_poll : NULL; se = fuse_session_new(args, &lop, sizeof(lop), userdata); if (!se) { free(cd); return NULL; } se->cuse_data = cd; return se; } static int cuse_reply_init(fuse_req_t req, struct cuse_init_out *arg, char *dev_info, unsigned dev_info_len) { struct iovec iov[3]; iov[1].iov_base = arg; iov[1].iov_len = sizeof(struct cuse_init_out); iov[2].iov_base = dev_info; iov[2].iov_len = dev_info_len; return fuse_send_reply_iov_nofree(req, 0, iov, 3); } void _cuse_lowlevel_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *req_payload) { const struct fuse_init_in *arg = op_in; (void)req_payload; struct cuse_init_out outarg; struct fuse_session *se = req->se; struct cuse_data *cd = se->cuse_data; size_t bufsize = se->bufsize; struct cuse_lowlevel_ops *clop = req_clop(req); (void) nodeid; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, "CUSE_INIT: %u.%u\n", arg->major, arg->minor); fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags); } se->conn.proto_major = arg->major; se->conn.proto_minor = arg->minor; /* XXX This is not right.*/ se->conn.capable_ext = 0; se->conn.want_ext = 0; if (arg->major < 7) { fuse_log(FUSE_LOG_ERR, "cuse: unsupported protocol version: %u.%u\n", arg->major, arg->minor); fuse_reply_err(req, EPROTO); return; } if (bufsize < FUSE_MIN_READ_BUFFER) { fuse_log(FUSE_LOG_ERR, "cuse: warning: buffer size too small: %zu\n", bufsize); bufsize = FUSE_MIN_READ_BUFFER; } bufsize -= 4096; if (bufsize < se->conn.max_write) se->conn.max_write = bufsize; se->got_init = 1; if (se->op.init) se->op.init(se->userdata, &se->conn); memset(&outarg, 0, sizeof(outarg)); outarg.major = FUSE_KERNEL_VERSION; outarg.minor = FUSE_KERNEL_MINOR_VERSION; outarg.flags = cd->flags; outarg.max_read = cd->max_read; outarg.max_write = se->conn.max_write; outarg.dev_major = cd->dev_major; outarg.dev_minor = cd->dev_minor; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, " CUSE_INIT: %u.%u\n", outarg.major, outarg.minor); fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags); fuse_log(FUSE_LOG_DEBUG, " max_read=0x%08x\n", outarg.max_read); fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write); fuse_log(FUSE_LOG_DEBUG, " dev_major=%u\n", outarg.dev_major); fuse_log(FUSE_LOG_DEBUG, " dev_minor=%u\n", outarg.dev_minor); fuse_log(FUSE_LOG_DEBUG, " dev_info: %.*s\n", cd->dev_info_len, cd->dev_info); } cuse_reply_init(req, &outarg, cd->dev_info, cd->dev_info_len); if (clop->init_done) clop->init_done(se->userdata); fuse_free_req(req); } void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _cuse_lowlevel_init(req, nodeid, inarg, NULL); } struct fuse_session *cuse_lowlevel_setup(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, int *multithreaded, void *userdata) { const char *devname = "/dev/cuse"; static const struct fuse_opt kill_subtype_opts[] = { FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_DISCARD), FUSE_OPT_END }; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts opts; int fd; int res; if (fuse_parse_cmdline(&args, &opts) == -1) return NULL; *multithreaded = !opts.singlethread; /* Remove subtype= option */ res = fuse_opt_parse(&args, NULL, kill_subtype_opts, NULL); if (res == -1) goto out1; /* * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos * would ensue. */ do { fd = open("/dev/null", O_RDWR); if (fd > 2) close(fd); } while (fd >= 0 && fd <= 2); se = cuse_lowlevel_new(&args, ci, clop, userdata); if (se == NULL) goto out1; fd = open(devname, O_RDWR); if (fd == -1) { if (errno == ENODEV || errno == ENOENT) fuse_log(FUSE_LOG_ERR, "cuse: device not found, try 'modprobe cuse' first\n"); else fuse_log(FUSE_LOG_ERR, "cuse: failed to open %s: %s\n", devname, strerror(errno)); goto err_se; } se->fd = fd; res = fuse_set_signal_handlers(se); if (res == -1) goto err_se; res = fuse_daemonize(opts.foreground); if (res == -1) goto err_sig; fuse_opt_free_args(&args); return se; err_sig: fuse_remove_signal_handlers(se); err_se: fuse_session_destroy(se); out1: free(opts.mountpoint); fuse_opt_free_args(&args); return NULL; } void cuse_lowlevel_teardown(struct fuse_session *se) { fuse_remove_signal_handlers(se); fuse_session_destroy(se); } int cuse_lowlevel_main(int argc, char *argv[], const struct cuse_info *ci, const struct cuse_lowlevel_ops *clop, void *userdata) { struct fuse_session *se; int multithreaded; int res; se = cuse_lowlevel_setup(argc, argv, ci, clop, &multithreaded, userdata); if (se == NULL) return 1; if (multithreaded) { struct fuse_loop_config *config = fuse_loop_cfg_create(); res = fuse_session_loop_mt(se, config); fuse_loop_cfg_destroy(config); } else res = fuse_session_loop(se); cuse_lowlevel_teardown(se); if (res == -1) return 1; return 0; } fuse-3.18.3/lib/fuse.c0000644000175000017500000035447415250106036013411 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Implementation of the high-level FUSE API on top of the low-level API. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #define _GNU_SOURCE #include "fuse.h" #include #include "fuse_config.h" #include "fuse_i.h" #include "fuse_lowlevel.h" #include "fuse_opt.h" #include "fuse_misc.h" #include "fuse_kernel.h" #include "util.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FUSE_NODE_SLAB 1 #ifndef MAP_ANONYMOUS #undef FUSE_NODE_SLAB #endif #ifndef RENAME_EXCHANGE #define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */ #endif #define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1 #define FUSE_UNKNOWN_INO 0xffffffff #define OFFSET_MAX 0x7fffffffffffffffLL #define NODE_TABLE_MIN_SIZE 8192 struct fuse_fs { struct fuse_operations op; void *user_data; int debug; }; struct fusemod_so { void *handle; int ctr; }; struct lock_queue_element { struct lock_queue_element *next; pthread_cond_t cond; fuse_ino_t nodeid1; const char *name1; char **path1; struct node **wnode1; fuse_ino_t nodeid2; const char *name2; char **path2; struct node **wnode2; int err; bool done : 1; }; struct node_table { struct node **array; size_t use; size_t size; size_t split; }; #define list_entry(ptr, type, member) \ container_of(ptr, type, member) struct list_head { struct list_head *next; struct list_head *prev; }; struct node_slab { struct list_head list; /* must be the first member */ struct list_head freelist; int used; }; struct fuse { struct fuse_session *se; struct node_table name_table; struct node_table id_table; struct list_head lru_table; fuse_ino_t ctr; unsigned int generation; unsigned int hidectr; pthread_mutex_t lock; struct fuse_config conf; int intr_installed; struct fuse_fs *fs; struct lock_queue_element *lockq; int pagesize; struct list_head partial_slabs; struct list_head full_slabs; pthread_t prune_thread; }; struct lock { int type; off_t start; off_t end; pid_t pid; uint64_t owner; struct lock *next; }; struct node { struct node *name_next; struct node *id_next; fuse_ino_t nodeid; unsigned int generation; int refctr; struct node *parent; char *name; uint64_t nlookup; int open_count; struct timespec stat_updated; struct timespec mtime; off_t size; struct lock *locks; unsigned int is_hidden : 1; unsigned int cache_valid : 1; int treelock; char inline_name[32]; }; #define TREELOCK_WRITE -1 #define TREELOCK_WAIT_OFFSET INT_MIN struct node_lru { struct node node; struct list_head lru; struct timespec forget_time; }; struct fuse_direntry { struct stat stat; enum fuse_fill_dir_flags flags; char *name; struct fuse_direntry *next; }; struct fuse_dh { pthread_mutex_t lock; struct fuse *fuse; fuse_req_t req; char *contents; struct fuse_direntry *first; struct fuse_direntry **last; unsigned len; unsigned size; unsigned needlen; int filled; uint64_t fh; int error; fuse_ino_t nodeid; }; struct fuse_context_i { struct fuse_context ctx; fuse_req_t req; }; /* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */ extern fuse_module_factory_t fuse_module_subdir_factory; #ifdef HAVE_ICONV extern fuse_module_factory_t fuse_module_iconv_factory; #endif static pthread_key_t fuse_context_key; static pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER; static int fuse_context_ref; static struct fuse_module *fuse_modules = NULL; static int fuse_register_module(const char *name, fuse_module_factory_t factory, struct fusemod_so *so) { struct fuse_module *mod; mod = calloc(1, sizeof(struct fuse_module)); if (!mod) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module\n"); return -1; } mod->name = strdup(name); if (!mod->name) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module name\n"); free(mod); return -1; } mod->factory = factory; mod->ctr = 0; mod->so = so; if (mod->so) mod->so->ctr++; mod->next = fuse_modules; fuse_modules = mod; return 0; } static void fuse_unregister_module(struct fuse_module *m) { struct fuse_module **mp; for (mp = &fuse_modules; *mp; mp = &(*mp)->next) { if (*mp == m) { *mp = (*mp)->next; break; } } free(m->name); free(m); } static int fuse_load_so_module(const char *module) { int ret = -1; char *tmp; struct fusemod_so *so; fuse_module_factory_t *factory; tmp = malloc(strlen(module) + 64); if (!tmp) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); return -1; } sprintf(tmp, "libfusemod_%s.so", module); so = calloc(1, sizeof(struct fusemod_so)); if (!so) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate module so\n"); goto out; } so->handle = dlopen(tmp, RTLD_NOW); if (so->handle == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: dlopen(%s) failed: %s\n", tmp, dlerror()); goto out_free_so; } sprintf(tmp, "fuse_module_%s_factory", module); factory = (fuse_module_factory_t*)dlsym(so->handle, tmp); if (factory == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: symbol <%s> not found in module: %s\n", tmp, dlerror()); goto out_dlclose; } ret = fuse_register_module(module, *factory, so); if (ret) goto out_dlclose; out: free(tmp); return ret; out_dlclose: dlclose(so->handle); out_free_so: free(so); goto out; } static struct fuse_module *fuse_find_module(const char *module) { struct fuse_module *m; for (m = fuse_modules; m; m = m->next) { if (strcmp(module, m->name) == 0) { m->ctr++; break; } } return m; } static struct fuse_module *fuse_get_module(const char *module) { struct fuse_module *m; pthread_mutex_lock(&fuse_context_lock); m = fuse_find_module(module); if (!m) { int err = fuse_load_so_module(module); if (!err) m = fuse_find_module(module); } pthread_mutex_unlock(&fuse_context_lock); return m; } static void fuse_put_module(struct fuse_module *m) { pthread_mutex_lock(&fuse_context_lock); if (m->so) assert(m->ctr > 0); /* Builtin modules may already have m->ctr == 0 */ if (m->ctr > 0) m->ctr--; if (!m->ctr && m->so) { struct fusemod_so *so = m->so; assert(so->ctr > 0); so->ctr--; if (!so->ctr) { struct fuse_module **mp; for (mp = &fuse_modules; *mp;) { if ((*mp)->so == so) fuse_unregister_module(*mp); else mp = &(*mp)->next; } dlclose(so->handle); free(so); } } else if (!m->ctr) { fuse_unregister_module(m); } pthread_mutex_unlock(&fuse_context_lock); } static void init_list_head(struct list_head *list) { list->next = list; list->prev = list; } static int list_empty(const struct list_head *head) { return head->next == head; } static void list_add(struct list_head *new, struct list_head *prev, struct list_head *next) { next->prev = new; new->next = next; new->prev = prev; prev->next = new; } static inline void list_add_head(struct list_head *new, struct list_head *head) { list_add(new, head, head->next); } static inline void list_add_tail(struct list_head *new, struct list_head *head) { list_add(new, head->prev, head); } static inline void list_del(struct list_head *entry) { struct list_head *prev = entry->prev; struct list_head *next = entry->next; next->prev = prev; prev->next = next; } static inline int lru_enabled(struct fuse *f) { return f->conf.remember > 0; } static struct node_lru *node_lru(struct node *node) { return (struct node_lru *) node; } static size_t get_node_size(struct fuse *f) { if (lru_enabled(f)) return sizeof(struct node_lru); else return sizeof(struct node); } #ifdef FUSE_NODE_SLAB static struct node_slab *list_to_slab(struct list_head *head) { return (struct node_slab *) head; } static struct node_slab *node_to_slab(struct fuse *f, struct node *node) { return (struct node_slab *) (((uintptr_t) node) & ~((uintptr_t) f->pagesize - 1)); } static int alloc_slab(struct fuse *f) { void *mem; struct node_slab *slab; char *start; size_t num; size_t i; size_t node_size = get_node_size(f); mem = mmap(NULL, f->pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mem == MAP_FAILED) return -1; slab = mem; init_list_head(&slab->freelist); slab->used = 0; num = (f->pagesize - sizeof(struct node_slab)) / node_size; start = (char *) mem + f->pagesize - num * node_size; for (i = 0; i < num; i++) { struct list_head *n; n = (struct list_head *) (start + i * node_size); list_add_tail(n, &slab->freelist); } list_add_tail(&slab->list, &f->partial_slabs); return 0; } static struct node *alloc_node(struct fuse *f) { struct node_slab *slab; struct list_head *node; if (list_empty(&f->partial_slabs)) { int res = alloc_slab(f); if (res != 0) return NULL; } slab = list_to_slab(f->partial_slabs.next); slab->used++; node = slab->freelist.next; list_del(node); if (list_empty(&slab->freelist)) { list_del(&slab->list); list_add_tail(&slab->list, &f->full_slabs); } memset(node, 0, sizeof(struct node)); return (struct node *) node; } static void free_slab(struct fuse *f, struct node_slab *slab) { int res; list_del(&slab->list); res = munmap(slab, f->pagesize); if (res == -1) fuse_log(FUSE_LOG_WARNING, "fuse warning: munmap(%p) failed\n", slab); } static void free_node_mem(struct fuse *f, struct node *node) { struct node_slab *slab = node_to_slab(f, node); struct list_head *n = (struct list_head *) node; slab->used--; if (slab->used) { if (list_empty(&slab->freelist)) { list_del(&slab->list); list_add_tail(&slab->list, &f->partial_slabs); } list_add_head(n, &slab->freelist); } else { free_slab(f, slab); } } #else static struct node *alloc_node(struct fuse *f) { return (struct node *) calloc(1, get_node_size(f)); } static void free_node_mem(struct fuse *f, struct node *node) { (void) f; free(node); } #endif static size_t id_hash(struct fuse *f, fuse_ino_t ino) { uint64_t hash = ((uint32_t) ino * 2654435761U) % f->id_table.size; uint64_t oldhash = hash % (f->id_table.size / 2); if (oldhash >= f->id_table.split) return oldhash; else return hash; } static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid) { size_t hash = id_hash(f, nodeid); struct node *node; for (node = f->id_table.array[hash]; node != NULL; node = node->id_next) if (node->nodeid == nodeid) return node; return NULL; } static struct node *get_node(struct fuse *f, fuse_ino_t nodeid) { struct node *node = get_node_nocheck(f, nodeid); if (!node) { fuse_log(FUSE_LOG_ERR, "fuse internal error: node %llu not found\n", (unsigned long long) nodeid); abort(); } return node; } static void curr_time(struct timespec *now); static double diff_timespec(const struct timespec *t1, const struct timespec *t2); static void remove_node_lru(struct node *node) { struct node_lru *lnode = node_lru(node); list_del(&lnode->lru); init_list_head(&lnode->lru); } static void set_forget_time(struct fuse *f, struct node *node) { struct node_lru *lnode = node_lru(node); list_del(&lnode->lru); list_add_tail(&lnode->lru, &f->lru_table); curr_time(&lnode->forget_time); } static void free_node(struct fuse *f, struct node *node) { if (node->name != node->inline_name) free(node->name); free_node_mem(f, node); } static void node_table_reduce(struct node_table *t) { size_t newsize = t->size / 2; void *newarray; if (newsize < NODE_TABLE_MIN_SIZE) return; newarray = realloc(t->array, sizeof(struct node *) * newsize); if (newarray != NULL) t->array = newarray; t->size = newsize; t->split = t->size / 2; } static void remerge_id(struct fuse *f) { struct node_table *t = &f->id_table; int iter; if (t->split == 0) node_table_reduce(t); for (iter = 8; t->split > 0 && iter; iter--) { struct node **upper; t->split--; upper = &t->array[t->split + t->size / 2]; if (*upper) { struct node **nodep; for (nodep = &t->array[t->split]; *nodep; nodep = &(*nodep)->id_next); *nodep = *upper; *upper = NULL; break; } } } static void unhash_id(struct fuse *f, struct node *node) { struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)]; for (; *nodep != NULL; nodep = &(*nodep)->id_next) if (*nodep == node) { *nodep = node->id_next; f->id_table.use--; if(f->id_table.use < f->id_table.size / 4) remerge_id(f); return; } } static int node_table_resize(struct node_table *t) { size_t newsize = t->size * 2; void *newarray; newarray = realloc(t->array, sizeof(struct node *) * newsize); if (newarray == NULL) return -1; t->array = newarray; memset(t->array + t->size, 0, t->size * sizeof(struct node *)); t->size = newsize; t->split = 0; return 0; } static void rehash_id(struct fuse *f) { struct node_table *t = &f->id_table; struct node **nodep; struct node **next; size_t hash; if (t->split == t->size / 2) return; hash = t->split; t->split++; for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { struct node *node = *nodep; size_t newhash = id_hash(f, node->nodeid); if (newhash != hash) { next = nodep; *nodep = node->id_next; node->id_next = t->array[newhash]; t->array[newhash] = node; } else { next = &node->id_next; } } if (t->split == t->size / 2) node_table_resize(t); } static void hash_id(struct fuse *f, struct node *node) { size_t hash = id_hash(f, node->nodeid); node->id_next = f->id_table.array[hash]; f->id_table.array[hash] = node; f->id_table.use++; if (f->id_table.use >= f->id_table.size / 2) rehash_id(f); } static size_t name_hash(struct fuse *f, fuse_ino_t parent, const char *name) { uint64_t hash = parent; uint64_t oldhash; for (; *name; name++) hash = hash * 31 + (unsigned char) *name; hash %= f->name_table.size; oldhash = hash % (f->name_table.size / 2); if (oldhash >= f->name_table.split) return oldhash; else return hash; } static void unref_node(struct fuse *f, struct node *node); static void remerge_name(struct fuse *f) { struct node_table *t = &f->name_table; int iter; if (t->split == 0) node_table_reduce(t); for (iter = 8; t->split > 0 && iter; iter--) { struct node **upper; t->split--; upper = &t->array[t->split + t->size / 2]; if (*upper) { struct node **nodep; for (nodep = &t->array[t->split]; *nodep; nodep = &(*nodep)->name_next); *nodep = *upper; *upper = NULL; break; } } } static void unhash_name(struct fuse *f, struct node *node) { if (node->name) { size_t hash = name_hash(f, node->parent->nodeid, node->name); struct node **nodep = &f->name_table.array[hash]; for (; *nodep != NULL; nodep = &(*nodep)->name_next) if (*nodep == node) { *nodep = node->name_next; node->name_next = NULL; unref_node(f, node->parent); if (node->name != node->inline_name) free(node->name); node->name = NULL; node->parent = NULL; f->name_table.use--; if (f->name_table.use < f->name_table.size / 4) remerge_name(f); return; } fuse_log(FUSE_LOG_ERR, "fuse internal error: unable to unhash node: %llu\n", (unsigned long long) node->nodeid); abort(); } } static void rehash_name(struct fuse *f) { struct node_table *t = &f->name_table; struct node **nodep; struct node **next; size_t hash; if (t->split == t->size / 2) return; hash = t->split; t->split++; for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) { struct node *node = *nodep; size_t newhash = name_hash(f, node->parent->nodeid, node->name); if (newhash != hash) { next = nodep; *nodep = node->name_next; node->name_next = t->array[newhash]; t->array[newhash] = node; } else { next = &node->name_next; } } if (t->split == t->size / 2) node_table_resize(t); } static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid, const char *name) { size_t hash = name_hash(f, parentid, name); struct node *parent = get_node(f, parentid); if (strlen(name) < sizeof(node->inline_name)) { strcpy(node->inline_name, name); node->name = node->inline_name; } else { node->name = strdup(name); if (node->name == NULL) return -1; } parent->refctr ++; node->parent = parent; node->name_next = f->name_table.array[hash]; f->name_table.array[hash] = node; f->name_table.use++; if (f->name_table.use >= f->name_table.size / 2) rehash_name(f); return 0; } static void delete_node(struct fuse *f, struct node *node) { if (f->conf.debug) fuse_log(FUSE_LOG_DEBUG, "DELETE: %llu\n", (unsigned long long) node->nodeid); assert(node->treelock == 0); unhash_name(f, node); if (lru_enabled(f)) remove_node_lru(node); unhash_id(f, node); free_node(f, node); } static void unref_node(struct fuse *f, struct node *node) { assert(node->refctr > 0); node->refctr --; if (!node->refctr) delete_node(f, node); } static fuse_ino_t next_id(struct fuse *f) { do { f->ctr = (f->ctr + 1) & 0xffffffff; if (!f->ctr) f->generation ++; } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO || get_node_nocheck(f, f->ctr) != NULL); return f->ctr; } static struct node *lookup_node(struct fuse *f, fuse_ino_t parent, const char *name) { size_t hash = name_hash(f, parent, name); struct node *node; for (node = f->name_table.array[hash]; node != NULL; node = node->name_next) if (node->parent->nodeid == parent && strcmp(node->name, name) == 0) return node; return NULL; } static void inc_nlookup(struct node *node) { if (!node->nlookup) node->refctr++; node->nlookup++; } static struct node *find_node(struct fuse *f, fuse_ino_t parent, const char *name) { struct node *node; pthread_mutex_lock(&f->lock); if (!name) node = get_node(f, parent); else node = lookup_node(f, parent, name); if (node == NULL) { node = alloc_node(f); if (node == NULL) goto out_err; node->nodeid = next_id(f); node->generation = f->generation; if (f->conf.remember) inc_nlookup(node); if (hash_name(f, node, parent, name) == -1) { free_node(f, node); node = NULL; goto out_err; } hash_id(f, node); if (lru_enabled(f)) { struct node_lru *lnode = node_lru(node); init_list_head(&lnode->lru); } } else if (lru_enabled(f) && node->nlookup == 1) { remove_node_lru(node); } inc_nlookup(node); out_err: pthread_mutex_unlock(&f->lock); return node; } static int lookup_path_in_cache(struct fuse *f, const char *path, fuse_ino_t *inop) { char *tmp = strdup(path); if (!tmp) return -ENOMEM; pthread_mutex_lock(&f->lock); fuse_ino_t ino = FUSE_ROOT_ID; int err = 0; char *save_ptr; char *path_element = strtok_r(tmp, "/", &save_ptr); while (path_element != NULL) { struct node *node = lookup_node(f, ino, path_element); if (node == NULL) { err = -ENOENT; break; } ino = node->nodeid; path_element = strtok_r(NULL, "/", &save_ptr); } pthread_mutex_unlock(&f->lock); free(tmp); if (!err) *inop = ino; return err; } static char *add_name(char **buf, unsigned *bufsize, char *s, const char *name) { size_t len = strlen(name); if (s - len <= *buf) { unsigned pathlen = *bufsize - (s - *buf); unsigned newbufsize = *bufsize; char *newbuf; while (newbufsize < pathlen + len + 1) { if (newbufsize >= 0x80000000) newbufsize = 0xffffffff; else newbufsize *= 2; } newbuf = realloc(*buf, newbufsize); if (newbuf == NULL) return NULL; *buf = newbuf; s = newbuf + newbufsize - pathlen; memmove(s, newbuf + *bufsize - pathlen, pathlen); *bufsize = newbufsize; } s -= len; memcpy(s, name, len); s--; *s = '/'; return s; } static void unlock_path(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, struct node *end) { struct node *node; if (wnode) { assert(wnode->treelock == TREELOCK_WRITE); wnode->treelock = 0; } for (node = get_node(f, nodeid); node != end && node->nodeid != FUSE_ROOT_ID; node = node->parent) { assert(node->treelock != 0); assert(node->treelock != TREELOCK_WAIT_OFFSET); assert(node->treelock != TREELOCK_WRITE); node->treelock--; if (node->treelock == TREELOCK_WAIT_OFFSET) node->treelock = 0; } } static int try_get_path(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnodep, bool need_lock) { unsigned bufsize = 256; char *buf; char *s; struct node *node; struct node *wnode = NULL; int err; *path = NULL; err = -ENOMEM; buf = malloc(bufsize); if (buf == NULL) goto out_err; s = buf + bufsize - 1; *s = '\0'; if (name != NULL) { s = add_name(&buf, &bufsize, s, name); err = -ENOMEM; if (s == NULL) goto out_free; } if (wnodep) { assert(need_lock); assert(name != NULL); wnode = lookup_node(f, nodeid, name); if (wnode) { if (wnode->treelock != 0) { if (wnode->treelock > 0) wnode->treelock += TREELOCK_WAIT_OFFSET; err = -EAGAIN; goto out_free; } wnode->treelock = TREELOCK_WRITE; } } for (node = get_node(f, nodeid); node->nodeid != FUSE_ROOT_ID; node = node->parent) { err = -ESTALE; if (node->name == NULL || node->parent == NULL) goto out_unlock; err = -ENOMEM; s = add_name(&buf, &bufsize, s, node->name); if (s == NULL) goto out_unlock; if (need_lock) { err = -EAGAIN; if (node->treelock < 0) goto out_unlock; node->treelock++; } } if (s[0]) memmove(buf, s, bufsize - (s - buf)); else strcpy(buf, "/"); *path = buf; if (wnodep) *wnodep = wnode; return 0; out_unlock: if (need_lock) unlock_path(f, nodeid, wnode, node); out_free: free(buf); out_err: return err; } static int try_get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, fuse_ino_t nodeid2, const char *name2, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { int err; /* FIXME: locking two paths needs deadlock checking */ err = try_get_path(f, nodeid1, name1, path1, wnode1, true); if (!err) { err = try_get_path(f, nodeid2, name2, path2, wnode2, true); if (err) { struct node *wn1 = wnode1 ? *wnode1 : NULL; unlock_path(f, nodeid1, wn1, NULL); free(*path1); } } return err; } static void queue_element_wakeup(struct fuse *f, struct lock_queue_element *qe) { int err; if (!qe->path1) { /* Just waiting for it to be unlocked */ if (get_node(f, qe->nodeid1)->treelock == 0) pthread_cond_signal(&qe->cond); return; } if (qe->done) return; // Don't try to double-lock the element if (!qe->path2) { err = try_get_path(f, qe->nodeid1, qe->name1, qe->path1, qe->wnode1, true); } else { err = try_get_path2(f, qe->nodeid1, qe->name1, qe->nodeid2, qe->name2, qe->path1, qe->path2, qe->wnode1, qe->wnode2); } if (err == -EAGAIN) return; /* keep trying */ qe->err = err; qe->done = true; pthread_cond_signal(&qe->cond); } static void wake_up_queued(struct fuse *f) { struct lock_queue_element *qe; for (qe = f->lockq; qe != NULL; qe = qe->next) queue_element_wakeup(f, qe); } static void debug_path(struct fuse *f, const char *msg, fuse_ino_t nodeid, const char *name, bool wr) { if (f->conf.debug) { struct node *wnode = NULL; if (wr) wnode = lookup_node(f, nodeid, name); if (wnode) { fuse_log(FUSE_LOG_DEBUG, "%s %llu (w)\n", msg, (unsigned long long) wnode->nodeid); } else { fuse_log(FUSE_LOG_DEBUG, "%s %llu\n", msg, (unsigned long long) nodeid); } } } static void queue_path(struct fuse *f, struct lock_queue_element *qe) { struct lock_queue_element **qp; qe->done = false; pthread_cond_init(&qe->cond, NULL); qe->next = NULL; for (qp = &f->lockq; *qp != NULL; qp = &(*qp)->next); *qp = qe; } static void dequeue_path(struct fuse *f, struct lock_queue_element *qe) { struct lock_queue_element **qp; pthread_cond_destroy(&qe->cond); for (qp = &f->lockq; *qp != qe; qp = &(*qp)->next); *qp = qe->next; } static int wait_path(struct fuse *f, struct lock_queue_element *qe) { queue_path(f, qe); do { pthread_cond_wait(&qe->cond, &f->lock); } while (!qe->done); dequeue_path(f, qe); return qe->err; } static int get_path_common(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { int err; pthread_mutex_lock(&f->lock); err = try_get_path(f, nodeid, name, path, wnode, true); if (err == -EAGAIN) { struct lock_queue_element qe = { .nodeid1 = nodeid, .name1 = name, .path1 = path, .wnode1 = wnode, }; debug_path(f, "QUEUE PATH", nodeid, name, !!wnode); err = wait_path(f, &qe); debug_path(f, "DEQUEUE PATH", nodeid, name, !!wnode); } pthread_mutex_unlock(&f->lock); return err; } static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path) { return get_path_common(f, nodeid, NULL, path, NULL); } static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path) { int err = 0; if (f->conf.nullpath_ok) { *path = NULL; } else { err = get_path_common(f, nodeid, NULL, path, NULL); if (err == -ESTALE) err = 0; } return err; } static int get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path) { return get_path_common(f, nodeid, name, path, NULL); } static int get_path_wrlock(struct fuse *f, fuse_ino_t nodeid, const char *name, char **path, struct node **wnode) { return get_path_common(f, nodeid, name, path, wnode); } #if defined(__FreeBSD__) #define CHECK_DIR_LOOP #endif #if defined(CHECK_DIR_LOOP) static int check_dir_loop(struct fuse *f, fuse_ino_t nodeid1, const char *name1, fuse_ino_t nodeid2, const char *name2) { struct node *node, *node1, *node2; fuse_ino_t id1, id2; node1 = lookup_node(f, nodeid1, name1); id1 = node1 ? node1->nodeid : nodeid1; node2 = lookup_node(f, nodeid2, name2); id2 = node2 ? node2->nodeid : nodeid2; for (node = get_node(f, id2); node->nodeid != FUSE_ROOT_ID; node = node->parent) { if (node->name == NULL || node->parent == NULL) break; if (node->nodeid != id2 && node->nodeid == id1) return -EINVAL; } if (node2) { for (node = get_node(f, id1); node->nodeid != FUSE_ROOT_ID; node = node->parent) { if (node->name == NULL || node->parent == NULL) break; if (node->nodeid != id1 && node->nodeid == id2) return -ENOTEMPTY; } } return 0; } #endif static int get_path2(struct fuse *f, fuse_ino_t nodeid1, const char *name1, fuse_ino_t nodeid2, const char *name2, char **path1, char **path2, struct node **wnode1, struct node **wnode2) { int err; pthread_mutex_lock(&f->lock); #if defined(CHECK_DIR_LOOP) if (name1) { // called during rename; perform dir loop check err = check_dir_loop(f, nodeid1, name1, nodeid2, name2); if (err) goto out_unlock; } #endif err = try_get_path2(f, nodeid1, name1, nodeid2, name2, path1, path2, wnode1, wnode2); if (err == -EAGAIN) { struct lock_queue_element qe = { .nodeid1 = nodeid1, .name1 = name1, .path1 = path1, .wnode1 = wnode1, .nodeid2 = nodeid2, .name2 = name2, .path2 = path2, .wnode2 = wnode2, }; debug_path(f, "QUEUE PATH1", nodeid1, name1, !!wnode1); debug_path(f, " PATH2", nodeid2, name2, !!wnode2); err = wait_path(f, &qe); debug_path(f, "DEQUEUE PATH1", nodeid1, name1, !!wnode1); debug_path(f, " PATH2", nodeid2, name2, !!wnode2); } #if defined(CHECK_DIR_LOOP) out_unlock: #endif pthread_mutex_unlock(&f->lock); return err; } static void free_path_wrlock(struct fuse *f, fuse_ino_t nodeid, struct node *wnode, char *path) { pthread_mutex_lock(&f->lock); unlock_path(f, nodeid, wnode, NULL); if (f->lockq) wake_up_queued(f); pthread_mutex_unlock(&f->lock); free(path); } static void free_path(struct fuse *f, fuse_ino_t nodeid, char *path) { if (path) free_path_wrlock(f, nodeid, NULL, path); } static void free_path2(struct fuse *f, fuse_ino_t nodeid1, fuse_ino_t nodeid2, struct node *wnode1, struct node *wnode2, char *path1, char *path2) { pthread_mutex_lock(&f->lock); unlock_path(f, nodeid1, wnode1, NULL); unlock_path(f, nodeid2, wnode2, NULL); wake_up_queued(f); pthread_mutex_unlock(&f->lock); free(path1); free(path2); } static void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup) { struct node *node; if (nodeid == FUSE_ROOT_ID) return; pthread_mutex_lock(&f->lock); node = get_node(f, nodeid); /* * Node may still be locked due to interrupt idiocy in open, * create and opendir */ while (node->nlookup == nlookup && node->treelock) { struct lock_queue_element qe = { .nodeid1 = nodeid, }; debug_path(f, "QUEUE PATH (forget)", nodeid, NULL, false); queue_path(f, &qe); do { pthread_cond_wait(&qe.cond, &f->lock); } while (node->nlookup == nlookup && node->treelock); dequeue_path(f, &qe); debug_path(f, "DEQUEUE_PATH (forget)", nodeid, NULL, false); } assert(node->nlookup >= nlookup); node->nlookup -= nlookup; if (!node->nlookup) { unref_node(f, node); } else if (lru_enabled(f) && node->nlookup == 1) { set_forget_time(f, node); } pthread_mutex_unlock(&f->lock); } static void unlink_node(struct fuse *f, struct node *node) { if (f->conf.remember) { assert(node->nlookup > 1); node->nlookup--; } unhash_name(f, node); } static void remove_node(struct fuse *f, fuse_ino_t dir, const char *name) { struct node *node; pthread_mutex_lock(&f->lock); node = lookup_node(f, dir, name); if (node != NULL) unlink_node(f, node); pthread_mutex_unlock(&f->lock); } static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, fuse_ino_t newdir, const char *newname, int hide) { struct node *node; struct node *newnode; int err = 0; pthread_mutex_lock(&f->lock); node = lookup_node(f, olddir, oldname); newnode = lookup_node(f, newdir, newname); if (node == NULL) goto out; if (newnode != NULL) { if (hide) { fuse_log(FUSE_LOG_ERR, "fuse: hidden file got created during hiding\n"); err = -EBUSY; goto out; } unlink_node(f, newnode); } unhash_name(f, node); if (hash_name(f, node, newdir, newname) == -1) { err = -ENOMEM; goto out; } if (hide) node->is_hidden = 1; out: pthread_mutex_unlock(&f->lock); return err; } static int exchange_node(struct fuse *f, fuse_ino_t olddir, const char *oldname, fuse_ino_t newdir, const char *newname) { struct node *oldnode; struct node *newnode; int err; pthread_mutex_lock(&f->lock); oldnode = lookup_node(f, olddir, oldname); newnode = lookup_node(f, newdir, newname); if (oldnode) unhash_name(f, oldnode); if (newnode) unhash_name(f, newnode); err = -ENOMEM; if (oldnode) { if (hash_name(f, oldnode, newdir, newname) == -1) goto out; } if (newnode) { if (hash_name(f, newnode, olddir, oldname) == -1) goto out; } err = 0; out: pthread_mutex_unlock(&f->lock); return err; } static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf) { if (!f->conf.use_ino) stbuf->st_ino = nodeid; if (f->conf.set_mode) { if (f->conf.dmask && S_ISDIR(stbuf->st_mode)) stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.dmask); else if (f->conf.fmask) stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.fmask); else stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask); } if (f->conf.set_uid) stbuf->st_uid = f->conf.uid; if (f->conf.set_gid) stbuf->st_gid = f->conf.gid; } #ifdef HAVE_STATX static void set_statx(struct fuse *f, fuse_ino_t nodeid, struct statx *stxbuf) { if (!f->conf.use_ino) stxbuf->stx_ino = nodeid; if (f->conf.set_mode) { if (f->conf.dmask && S_ISDIR(stxbuf->stx_mode)) stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) | (0777 & ~f->conf.dmask); else if (f->conf.fmask) stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) | (0777 & ~f->conf.fmask); else stxbuf->stx_mode = (stxbuf->stx_mode & S_IFMT) | (0777 & ~f->conf.umask); } if (f->conf.set_uid) stxbuf->stx_uid = f->conf.uid; if (f->conf.set_gid) stxbuf->stx_gid = f->conf.gid; } #endif static struct fuse *req_fuse(fuse_req_t req) { return (struct fuse *) fuse_req_userdata(req); } static void fuse_intr_sighandler(int sig) { (void) sig; /* Nothing to do */ } struct fuse_intr_data { pthread_t id; pthread_cond_t cond; int finished; }; static void fuse_interrupt(fuse_req_t req, void *d_) { struct fuse_intr_data *d = d_; struct fuse *f = req_fuse(req); if (d->id == pthread_self()) return; pthread_mutex_lock(&f->lock); while (!d->finished) { struct timeval now; struct timespec timeout; pthread_kill(d->id, f->conf.intr_signal); gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec + 1; timeout.tv_nsec = now.tv_usec * 1000; pthread_cond_timedwait(&d->cond, &f->lock, &timeout); } pthread_mutex_unlock(&f->lock); } static void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { pthread_mutex_lock(&f->lock); d->finished = 1; pthread_cond_broadcast(&d->cond); pthread_mutex_unlock(&f->lock); fuse_req_interrupt_func(req, NULL, NULL); pthread_cond_destroy(&d->cond); } static void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d) { d->id = pthread_self(); pthread_cond_init(&d->cond, NULL); d->finished = 0; fuse_req_interrupt_func(req, fuse_interrupt, d); } static inline void fuse_finish_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { if (f->conf.intr) fuse_do_finish_interrupt(f, req, d); } static inline void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req, struct fuse_intr_data *d) { if (f->conf.intr) fuse_do_prepare_interrupt(req, d); } static const char* file_info_string(struct fuse_file_info *fi, char* buf, size_t len) { if(fi == NULL) return "NULL"; snprintf(buf, len, "%llu", (unsigned long long) fi->fh); return buf; } int fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.getattr) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "getattr[%s] %s\n", file_info_string(fi, buf, sizeof(buf)), path); } return fs->op.getattr(path, buf, fi); } int fuse_fs_rename(struct fuse_fs *fs, const char *oldpath, const char *newpath, unsigned int flags) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.rename) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "rename %s %s 0x%x\n", oldpath, newpath, flags); return fs->op.rename(oldpath, newpath, flags); } int fuse_fs_unlink(struct fuse_fs *fs, const char *path) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.unlink) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "unlink %s\n", path); return fs->op.unlink(path); } int fuse_fs_rmdir(struct fuse_fs *fs, const char *path) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.rmdir) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "rmdir %s\n", path); return fs->op.rmdir(path); } int fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.symlink) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "symlink %s %s\n", linkname, path); return fs->op.symlink(linkname, path); } int fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.link) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "link %s %s\n", oldpath, newpath); return fs->op.link(oldpath, newpath); } int fuse_fs_release(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.release) return 0; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "release%s[%llu] flags: 0x%x\n", fi->flush ? "+flush" : "", (unsigned long long) fi->fh, fi->flags); return fs->op.release(path, fi); } int fuse_fs_opendir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { int err; fuse_get_context()->private_data = fs->user_data; if (!fs->op.opendir) return 0; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "opendir flags: 0x%x %s\n", fi->flags, path); err = fs->op.opendir(path, fi); if (fs->debug && !err) fuse_log(FUSE_LOG_DEBUG, " opendir[%llu] flags: 0x%x %s\n", (unsigned long long) fi->fh, fi->flags, path); return err; } int fuse_fs_open(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { int err; fuse_get_context()->private_data = fs->user_data; if (!fs->op.open) return 0; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "open flags: 0x%x %s\n", fi->flags, path); err = fs->op.open(path, fi); if (fs->debug && !err) fuse_log(FUSE_LOG_DEBUG, " open[%llu] flags: 0x%x %s\n", (unsigned long long) fi->fh, fi->flags, path); return err; } static void fuse_free_buf(struct fuse_bufvec *buf) { if (buf != NULL) { size_t i; for (i = 0; i < buf->count; i++) if (!(buf->buf[i].flags & FUSE_BUF_IS_FD)) free(buf->buf[i].mem); free(buf); } } int fuse_fs_read_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec **bufp, size_t size, off_t off, struct fuse_file_info *fi) { int res; fuse_get_context()->private_data = fs->user_data; if (!fs->op.read && !fs->op.read_buf) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "read[%llu] %zu bytes from %llu flags: 0x%x\n", (unsigned long long) fi->fh, size, (unsigned long long) off, fi->flags); if (fs->op.read_buf) { res = fs->op.read_buf(path, bufp, size, off, fi); } else { struct fuse_bufvec *buf; void *mem; buf = malloc(sizeof(struct fuse_bufvec)); if (buf == NULL) return -ENOMEM; mem = malloc(size); if (mem == NULL) { free(buf); return -ENOMEM; } *buf = FUSE_BUFVEC_INIT(size); buf->buf[0].mem = mem; *bufp = buf; res = fs->op.read(path, mem, size, off, fi); if (res >= 0) buf->buf[0].size = res; } if (fs->debug && res >= 0) fuse_log(FUSE_LOG_DEBUG, " read[%llu] %zu bytes from %llu\n", (unsigned long long) fi->fh, fuse_buf_size(*bufp), (unsigned long long) off); if (res >= 0 && fuse_buf_size(*bufp) > size) fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n"); if (res < 0) return res; return 0; } int fuse_fs_read(struct fuse_fs *fs, const char *path, char *mem, size_t size, off_t off, struct fuse_file_info *fi) { int res; fuse_get_context()->private_data = fs->user_data; if (!fs->op.read && !fs->op.read_buf) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "read[%llu] %zu bytes from %llu flags: 0x%x\n", (unsigned long long) fi->fh, size, (unsigned long long) off, fi->flags); if (fs->op.read_buf) { struct fuse_bufvec *buf = NULL; res = fs->op.read_buf(path, &buf, size, off, fi); if (res == 0) { struct fuse_bufvec dst = FUSE_BUFVEC_INIT(size); dst.buf[0].mem = mem; res = fuse_buf_copy(&dst, buf, 0); } fuse_free_buf(buf); } else { res = fs->op.read(path, mem, size, off, fi); } if (fs->debug && res >= 0) fuse_log(FUSE_LOG_DEBUG, " read[%llu] %u bytes from %llu\n", (unsigned long long) fi->fh, res, (unsigned long long) off); if (res >= 0 && res > (int) size) fuse_log(FUSE_LOG_ERR, "fuse: read too many bytes\n"); return res; } int fuse_fs_write_buf(struct fuse_fs *fs, const char *path, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { int res; size_t size; fuse_get_context()->private_data = fs->user_data; if (!fs->op.write_buf && !fs->op.write) return -ENOSYS; size = fuse_buf_size(buf); assert(buf->idx == 0 && buf->off == 0); if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "write%s[%llu] %zu bytes to %llu flags: 0x%x\n", fi->writepage ? "page" : "", (unsigned long long) fi->fh, size, (unsigned long long) off, fi->flags); if (fs->op.write_buf) { res = fs->op.write_buf(path, buf, off, fi); } else { void *mem = NULL; struct fuse_buf *flatbuf; struct fuse_bufvec tmp = FUSE_BUFVEC_INIT(size); if (buf->count == 1 && !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { flatbuf = &buf->buf[0]; } else { res = -ENOMEM; mem = malloc(size); if (mem == NULL) goto out; tmp.buf[0].mem = mem; res = fuse_buf_copy(&tmp, buf, 0); if (res <= 0) goto out_free; tmp.buf[0].size = res; flatbuf = &tmp.buf[0]; } res = fs->op.write(path, flatbuf->mem, flatbuf->size, off, fi); out_free: free(mem); } out: if (fs->debug && res >= 0) fuse_log(FUSE_LOG_DEBUG, " write%s[%llu] %u bytes to %llu\n", fi->writepage ? "page" : "", (unsigned long long) fi->fh, res, (unsigned long long) off); if (res > (int) size) fuse_log(FUSE_LOG_ERR, "fuse: wrote too many bytes\n"); return res; } int fuse_fs_write(struct fuse_fs *fs, const char *path, const char *mem, size_t size, off_t off, struct fuse_file_info *fi) { struct fuse_bufvec bufv = FUSE_BUFVEC_INIT(size); bufv.buf[0].mem = (void *) mem; return fuse_fs_write_buf(fs, path, &bufv, off, fi); } int fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.fsync) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "fsync[%llu] datasync: %i\n", (unsigned long long) fi->fh, datasync); return fs->op.fsync(path, datasync, fi); } int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.fsyncdir) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "fsyncdir[%llu] datasync: %i\n", (unsigned long long) fi->fh, datasync); return fs->op.fsyncdir(path, datasync, fi); } int fuse_fs_flush(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.flush) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "flush[%llu]\n", (unsigned long long) fi->fh); return fs->op.flush(path, fi); } int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf) { fuse_get_context()->private_data = fs->user_data; if (fs->op.statfs) { if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "statfs %s\n", path); return fs->op.statfs(path, buf); } else { buf->f_namemax = 255; buf->f_bsize = 512; return 0; } } int fuse_fs_releasedir(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.releasedir) return 0; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "releasedir[%llu] flags: 0x%x\n", (unsigned long long) fi->fh, fi->flags); return fs->op.releasedir(path, 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, enum fuse_readdir_flags flags) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.readdir) return -ENOSYS; if (fs->debug) { fuse_log(FUSE_LOG_DEBUG, "readdir%s[%llu] from %llu\n", (flags & FUSE_READDIR_PLUS) ? "plus" : "", (unsigned long long) fi->fh, (unsigned long long) off); } return fs->op.readdir(path, buf, filler, off, fi, flags); } int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi) { int err; fuse_get_context()->private_data = fs->user_data; if (!fs->op.create) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "create flags: 0x%x %s 0%o umask=0%03o\n", fi->flags, path, mode, fuse_get_context()->umask); err = fs->op.create(path, mode, fi); if (fs->debug && !err) fuse_log(FUSE_LOG_DEBUG, " create[%llu] flags: 0x%x %s\n", (unsigned long long) fi->fh, fi->flags, path); return err; } int fuse_fs_lock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.lock) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s %s start: %llu len: %llu pid: %llu\n", (unsigned long long) fi->fh, (cmd == F_GETLK ? "F_GETLK" : (cmd == F_SETLK ? "F_SETLK" : (cmd == F_SETLKW ? "F_SETLKW" : "???"))), (lock->l_type == F_RDLCK ? "F_RDLCK" : (lock->l_type == F_WRLCK ? "F_WRLCK" : (lock->l_type == F_UNLCK ? "F_UNLCK" : "???"))), (unsigned long long) lock->l_start, (unsigned long long) lock->l_len, (unsigned long long) lock->l_pid); return fs->op.lock(path, fi, cmd, lock); } int fuse_fs_flock(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, int op) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.flock) return -ENOSYS; if (fs->debug) { int xop = op & ~LOCK_NB; fuse_log(FUSE_LOG_DEBUG, "lock[%llu] %s%s\n", (unsigned long long) fi->fh, xop == LOCK_SH ? "LOCK_SH" : (xop == LOCK_EX ? "LOCK_EX" : (xop == LOCK_UN ? "LOCK_UN" : "???")), (op & LOCK_NB) ? "|LOCK_NB" : ""); } return fs->op.flock(path, fi, op); } int fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.chown) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "chown[%s] %s %lu %lu\n", file_info_string(fi, buf, sizeof(buf)), path, (unsigned long) uid, (unsigned long) gid); } return fs->op.chown(path, uid, gid, fi); } int fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.truncate) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "truncate[%s] %llu\n", file_info_string(fi, buf, sizeof(buf)), (unsigned long long) size); } return fs->op.truncate(path, size, fi); } int fuse_fs_utimens(struct fuse_fs *fs, const char *path, const struct timespec tv[2], struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.utimens) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "utimens[%s] %s %jd.%09ld %jd.%09ld\n", file_info_string(fi, buf, sizeof(buf)), path, (intmax_t)tv[0].tv_sec, tv[0].tv_nsec, (intmax_t)tv[1].tv_sec, tv[1].tv_nsec); } return fs->op.utimens(path, tv, fi); } int fuse_fs_access(struct fuse_fs *fs, const char *path, int mask) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.access) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "access %s 0%o\n", path, mask); return fs->op.access(path, mask); } int fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf, size_t len) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.readlink) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "readlink %s %lu\n", path, (unsigned long) len); return fs->op.readlink(path, buf, len); } int fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode, dev_t rdev) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.mknod) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "mknod %s 0%o 0x%llx umask=0%03o\n", path, mode, (unsigned long long) rdev, fuse_get_context()->umask); return fs->op.mknod(path, mode, rdev); } int fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.mkdir) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "mkdir %s 0%o umask=0%03o\n", path, mode, fuse_get_context()->umask); return fs->op.mkdir(path, mode); } int fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name, const char *value, size_t size, int flags) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.setxattr) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "setxattr %s %s %lu 0x%x\n", path, name, (unsigned long) size, flags); return fs->op.setxattr(path, name, value, size, flags); } int fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name, char *value, size_t size) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.getxattr) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "getxattr %s %s %lu\n", path, name, (unsigned long) size); return fs->op.getxattr(path, name, value, size); } int fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list, size_t size) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.listxattr) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "listxattr %s %lu\n", path, (unsigned long) size); return fs->op.listxattr(path, list, size); } int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize, uint64_t *idx) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.bmap) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "bmap %s blocksize: %lu index: %llu\n", path, (unsigned long) blocksize, (unsigned long long) *idx); return fs->op.bmap(path, blocksize, idx); } int fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.removexattr) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "removexattr %s %s\n", path, name); return fs->op.removexattr(path, name); } int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, void *data) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.ioctl) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "ioctl[%llu] 0x%x flags: 0x%x\n", (unsigned long long) fi->fh, cmd, flags); return fs->op.ioctl(path, cmd, arg, fi, flags, data); } int fuse_fs_poll(struct fuse_fs *fs, const char *path, struct fuse_file_info *fi, struct fuse_pollhandle *ph, unsigned *reventsp) { int res; fuse_get_context()->private_data = fs->user_data; if (!fs->op.poll) { fuse_pollhandle_destroy(ph); return -ENOSYS; } if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "poll[%llu] ph: %p, events 0x%x\n", (unsigned long long) fi->fh, ph, fi->poll_events); res = fs->op.poll(path, fi, ph, reventsp); if (fs->debug && !res) fuse_log(FUSE_LOG_DEBUG, " poll[%llu] revents: 0x%x\n", (unsigned long long) fi->fh, *reventsp); return res; } int fuse_fs_fallocate(struct fuse_fs *fs, const char *path, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.fallocate) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "fallocate %s mode %x, offset: %llu, length: %llu\n", path, mode, (unsigned long long) offset, (unsigned long long) length); return fs->op.fallocate(path, mode, offset, length, fi); } ssize_t fuse_fs_copy_file_range(struct fuse_fs *fs, 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) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.copy_file_range) return -ENOSYS; if (fs->debug) fuse_log(FUSE_LOG_DEBUG, "copy_file_range from %s:%llu to " "%s:%llu, length: %llu\n", path_in, (unsigned long long) off_in, path_out, (unsigned long long) off_out, (unsigned long long) len); return fs->op.copy_file_range(path_in, fi_in, off_in, path_out, fi_out, off_out, len, flags); } off_t fuse_fs_lseek(struct fuse_fs *fs, const char *path, off_t off, int whence, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.lseek) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "lseek[%s] %llu %d\n", file_info_string(fi, buf, sizeof(buf)), (unsigned long long) off, whence); } return fs->op.lseek(path, off, whence, fi); } #ifdef HAVE_STATX int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (fs->op.statx) { if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "statx[%s] %s %d %d\n", file_info_string(fi, buf, sizeof(buf)), path, flags, mask); } return fs->op.statx(path, flags, mask, stxbuf, fi); } return -ENOSYS; } #else int fuse_fs_statx(struct fuse_fs *fs, const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { (void)fs; (void)path; (void)flags; (void)mask; (void)stxbuf; (void)fi; return -ENOSYS; } #endif static int is_open(struct fuse *f, fuse_ino_t dir, const char *name) { struct node *node; int isopen = 0; pthread_mutex_lock(&f->lock); node = lookup_node(f, dir, name); if (node && node->open_count > 0) isopen = 1; pthread_mutex_unlock(&f->lock); return isopen; } static char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname, char *newname, size_t bufsize) { struct stat buf; struct node *node; struct node *newnode; char *newpath; int res; int failctr = 10; do { pthread_mutex_lock(&f->lock); node = lookup_node(f, dir, oldname); if (node == NULL) { pthread_mutex_unlock(&f->lock); return NULL; } do { f->hidectr ++; snprintf(newname, bufsize, ".fuse_hidden%08x%08x", (unsigned int) node->nodeid, f->hidectr); newnode = lookup_node(f, dir, newname); } while(newnode); res = try_get_path(f, dir, newname, &newpath, NULL, false); pthread_mutex_unlock(&f->lock); if (res) break; memset(&buf, 0, sizeof(buf)); res = fuse_fs_getattr(f->fs, newpath, &buf, NULL); if (res == -ENOENT) break; free(newpath); newpath = NULL; } while(res == 0 && --failctr); return newpath; } static int hide_node(struct fuse *f, const char *oldpath, fuse_ino_t dir, const char *oldname) { char newname[64]; char *newpath; int err = -EBUSY; newpath = hidden_name(f, dir, oldname, newname, sizeof(newname)); if (newpath) { err = fuse_fs_rename(f->fs, oldpath, newpath, 0); if (!err) err = rename_node(f, dir, oldname, dir, newname, 1); free(newpath); } return err; } static int mtime_eq(const struct stat *stbuf, const struct timespec *ts) { return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec; } #ifndef CLOCK_MONOTONIC #define CLOCK_MONOTONIC CLOCK_REALTIME #endif static void curr_time(struct timespec *now) { static clockid_t clockid = CLOCK_MONOTONIC; int res = clock_gettime(clockid, now); if (res == -1 && errno == EINVAL) { clockid = CLOCK_REALTIME; res = clock_gettime(clockid, now); } if (res == -1) { perror("fuse: clock_gettime"); abort(); } } static void update_stat(struct node *node, const struct stat *stbuf) { if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) || stbuf->st_size != node->size)) node->cache_valid = 0; node->mtime.tv_sec = stbuf->st_mtime; node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf); node->size = stbuf->st_size; curr_time(&node->stat_updated); } static int do_lookup(struct fuse *f, fuse_ino_t nodeid, const char *name, struct fuse_entry_param *e) { struct node *node; node = find_node(f, nodeid, name); if (node == NULL) return -ENOMEM; e->ino = node->nodeid; e->generation = node->generation; e->entry_timeout = f->conf.entry_timeout; e->attr_timeout = f->conf.attr_timeout; if (f->conf.auto_cache) { pthread_mutex_lock(&f->lock); update_stat(node, &e->attr); pthread_mutex_unlock(&f->lock); } set_stat(f, e->ino, &e->attr); return 0; } static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name, const char *path, struct fuse_entry_param *e, struct fuse_file_info *fi) { int res; memset(e, 0, sizeof(struct fuse_entry_param)); res = fuse_fs_getattr(f->fs, path, &e->attr, fi); if (res == 0) { res = do_lookup(f, nodeid, name, e); if (res == 0 && f->conf.debug) { fuse_log(FUSE_LOG_DEBUG, " NODEID: %llu\n", (unsigned long long) e->ino); } } return res; } static struct fuse_context_i *fuse_get_context_internal(void) { return (struct fuse_context_i *) pthread_getspecific(fuse_context_key); } static struct fuse_context_i *fuse_create_context(struct fuse *f) { struct fuse_context_i *c = fuse_get_context_internal(); if (c == NULL) { c = (struct fuse_context_i *) calloc(1, sizeof(struct fuse_context_i)); if (c == NULL) { /* This is hard to deal with properly, so just abort. If memory is so low that the context cannot be allocated, there's not much hope for the filesystem anyway */ fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate thread specific data\n"); abort(); } if (pthread_setspecific(fuse_context_key, c) != 0) { fuse_log(FUSE_LOG_ERR, "fuse: failed to set thread specific data\n"); free(c); abort(); } } else { memset(c, 0, sizeof(*c)); } c->ctx.fuse = f; return c; } static void fuse_freecontext(void *data) { free(data); } static int fuse_create_context_key(void) { int err = 0; pthread_mutex_lock(&fuse_context_lock); if (!fuse_context_ref) { err = pthread_key_create(&fuse_context_key, fuse_freecontext); if (err) { fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n", strerror(err)); pthread_mutex_unlock(&fuse_context_lock); return -1; } } fuse_context_ref++; pthread_mutex_unlock(&fuse_context_lock); return 0; } static void fuse_delete_context_key(void) { pthread_mutex_lock(&fuse_context_lock); fuse_context_ref--; if (!fuse_context_ref) { free(pthread_getspecific(fuse_context_key)); pthread_key_delete(fuse_context_key); } pthread_mutex_unlock(&fuse_context_lock); } static struct fuse *req_fuse_prepare(fuse_req_t req) { struct fuse_context_i *c = fuse_create_context(req_fuse(req)); const struct fuse_ctx *ctx = fuse_req_ctx(req); c->req = req; c->ctx.uid = ctx->uid; c->ctx.gid = ctx->gid; c->ctx.pid = ctx->pid; c->ctx.umask = ctx->umask; return c->ctx.fuse; } static inline void reply_err(fuse_req_t req, int err) { /* fuse_reply_err() uses non-negated errno values */ fuse_reply_err(req, -err); } static void reply_entry(fuse_req_t req, const struct fuse_entry_param *e, int err) { if (!err) { struct fuse *f = req_fuse(req); if (fuse_reply_entry(req, e) == -ENOENT) { /* Skip forget for negative result */ if (e->ino != 0) forget_node(f, e->ino, 1); } } else reply_err(req, err); } void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn, struct fuse_config *cfg) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.write_buf) fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ); if (!fs->op.lock) fuse_unset_feature_flag(conn, FUSE_CAP_POSIX_LOCKS); if (!fs->op.flock) fuse_unset_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); if (fs->op.init) fs->user_data = fs->op.init(conn, cfg); } static int fuse_init_intr_signal(int signum, int *installed); static void fuse_lib_init(void *data, struct fuse_conn_info *conn) { struct fuse *f = (struct fuse *) data; fuse_create_context(f); fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT); fuse_fs_init(f->fs, conn, &f->conf); if (f->conf.intr) { if (fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1) fuse_log(FUSE_LOG_ERR, "fuse: failed to init interrupt signal\n"); } else { /* Disable the receiving and processing of FUSE_INTERRUPT requests */ conn->no_interrupt = 1; } } void fuse_fs_destroy(struct fuse_fs *fs) { fuse_get_context()->private_data = fs->user_data; if (fs->op.destroy) fs->op.destroy(fs->user_data); } static void fuse_lib_destroy(void *data) { struct fuse *f = (struct fuse *) data; fuse_create_context(f); fuse_fs_destroy(f->fs); } static void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse *f = req_fuse_prepare(req); struct fuse_entry_param e = { .ino = 0 }; /* invalid ino */ char *path; int err; struct node *dot = NULL; if (name[0] == '.') { int len = strlen(name); if (len == 1 || (name[1] == '.' && len == 2)) { pthread_mutex_lock(&f->lock); if (len == 1) { if (f->conf.debug) fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOT\n"); dot = get_node_nocheck(f, parent); if (dot == NULL) { pthread_mutex_unlock(&f->lock); reply_entry(req, &e, -ESTALE); return; } dot->refctr++; } else { if (f->conf.debug) fuse_log(FUSE_LOG_DEBUG, "LOOKUP-DOTDOT\n"); parent = get_node(f, parent)->parent->nodeid; } pthread_mutex_unlock(&f->lock); name = NULL; } } err = get_path_name(f, parent, name, &path); if (!err) { struct fuse_intr_data d; if (f->conf.debug) fuse_log(FUSE_LOG_DEBUG, "LOOKUP %s\n", path); fuse_prepare_interrupt(f, req, &d); err = lookup_path(f, parent, name, path, &e, NULL); if (err == -ENOENT && f->conf.negative_timeout != 0.0) { e.ino = 0; e.entry_timeout = f->conf.negative_timeout; err = 0; } fuse_finish_interrupt(f, req, &d); free_path(f, parent, path); } if (dot) { pthread_mutex_lock(&f->lock); unref_node(f, dot); pthread_mutex_unlock(&f->lock); } reply_entry(req, &e, err); } static void do_forget(struct fuse *f, fuse_ino_t ino, uint64_t nlookup) { if (f->conf.debug) fuse_log(FUSE_LOG_DEBUG, "FORGET %llu/%llu\n", (unsigned long long)ino, (unsigned long long) nlookup); forget_node(f, ino, nlookup); } static void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup) { do_forget(req_fuse(req), ino, nlookup); fuse_reply_none(req); } static void fuse_lib_forget_multi(fuse_req_t req, size_t count, struct fuse_forget_data *forgets) { struct fuse *f = req_fuse(req); size_t i; for (i = 0; i < count; i++) do_forget(f, forgets[i].ino, forgets[i].nlookup); fuse_reply_none(req); } static void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct stat buf; char *path; int err; memset(&buf, 0, sizeof(buf)); if (fi != NULL) err = get_path_nullok(f, ino, &path); else err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_getattr(f->fs, path, &buf, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) { struct node *node; pthread_mutex_lock(&f->lock); node = get_node(f, ino); if (node->is_hidden && buf.st_nlink > 0) buf.st_nlink--; if (f->conf.auto_cache) update_stat(node, &buf); pthread_mutex_unlock(&f->lock); set_stat(f, ino, &buf); fuse_reply_attr(req, &buf, f->conf.attr_timeout); } else reply_err(req, err); } int fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode, struct fuse_file_info *fi) { fuse_get_context()->private_data = fs->user_data; if (!fs->op.chmod) return -ENOSYS; if (fs->debug) { char buf[10]; fuse_log(FUSE_LOG_DEBUG, "chmod[%s] %s %llo\n", file_info_string(fi, buf, sizeof(buf)), path, (unsigned long long) mode); } return fs->op.chmod(path, mode, fi); } static void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int valid, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct stat buf; char *path; int err; memset(&buf, 0, sizeof(buf)); if (fi != NULL) err = get_path_nullok(f, ino, &path); else err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = 0; if (!err && (valid & FUSE_SET_ATTR_MODE)) err = fuse_fs_chmod(f->fs, path, attr->st_mode, fi); if (!err && (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; err = fuse_fs_chown(f->fs, path, uid, gid, fi); } if (!err && (valid & FUSE_SET_ATTR_SIZE)) { err = fuse_fs_truncate(f->fs, path, attr->st_size, fi); } #ifdef HAVE_UTIMENSAT if (!err && (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; err = fuse_fs_utimens(f->fs, path, tv, fi); } else #endif if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) == (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) { struct timespec tv[2]; tv[0].tv_sec = attr->st_atime; tv[0].tv_nsec = ST_ATIM_NSEC(attr); tv[1].tv_sec = attr->st_mtime; tv[1].tv_nsec = ST_MTIM_NSEC(attr); err = fuse_fs_utimens(f->fs, path, tv, fi); } if (!err) { err = fuse_fs_getattr(f->fs, path, &buf, fi); } fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) { if (f->conf.auto_cache) { pthread_mutex_lock(&f->lock); update_stat(get_node(f, ino), &buf); pthread_mutex_unlock(&f->lock); } set_stat(f, ino, &buf); fuse_reply_attr(req, &buf, f->conf.attr_timeout); } else reply_err(req, err); } static void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_access(f->fs, path, mask); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino) { struct fuse *f = req_fuse_prepare(req); char linkname[PATH_MAX + 1]; char *path; int err; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname)); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) { linkname[PATH_MAX] = '\0'; fuse_reply_readlink(req, linkname); } else reply_err(req, err); } static void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev) { struct fuse *f = req_fuse_prepare(req); struct fuse_entry_param e; char *path; int err; err = get_path_name(f, parent, name, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = -ENOSYS; if (S_ISREG(mode)) { struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = O_CREAT | O_EXCL | O_WRONLY; err = fuse_fs_create(f->fs, path, mode, &fi); if (!err) { err = lookup_path(f, parent, name, path, &e, &fi); fuse_fs_release(f->fs, path, &fi); } } if (err == -ENOSYS) { err = fuse_fs_mknod(f->fs, path, mode, rdev); if (!err) err = lookup_path(f, parent, name, path, &e, NULL); } fuse_finish_interrupt(f, req, &d); free_path(f, parent, path); } reply_entry(req, &e, err); } static void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode) { struct fuse *f = req_fuse_prepare(req); struct fuse_entry_param e; char *path; int err; err = get_path_name(f, parent, name, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_mkdir(f->fs, path, mode); if (!err) err = lookup_path(f, parent, name, path, &e, NULL); fuse_finish_interrupt(f, req, &d); free_path(f, parent, path); } reply_entry(req, &e, err); } static void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse *f = req_fuse_prepare(req); struct node *wnode; char *path; int err; err = get_path_wrlock(f, parent, name, &path, &wnode); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); if (!f->conf.hard_remove && is_open(f, parent, name)) { err = hide_node(f, path, parent, name); if (!err) { /* we have hidden the node so now check again under a lock in case it is not used any more */ if (!is_open(f, parent, wnode->name)) { char *unlinkpath; /* get the hidden file path, to unlink it */ if (try_get_path(f, wnode->nodeid, NULL, &unlinkpath, NULL, false) == 0) { err = fuse_fs_unlink(f->fs, unlinkpath); if (!err) remove_node(f, parent, wnode->name); free(unlinkpath); } } } } else { err = fuse_fs_unlink(f->fs, path); if (!err) remove_node(f, parent, name); } fuse_finish_interrupt(f, req, &d); free_path_wrlock(f, parent, wnode, path); } reply_err(req, err); } static void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse *f = req_fuse_prepare(req); struct node *wnode; char *path; int err; err = get_path_wrlock(f, parent, name, &path, &wnode); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_rmdir(f->fs, path); fuse_finish_interrupt(f, req, &d); if (!err) remove_node(f, parent, name); free_path_wrlock(f, parent, wnode, path); } reply_err(req, err); } static void fuse_lib_symlink(fuse_req_t req, const char *linkname, fuse_ino_t parent, const char *name) { struct fuse *f = req_fuse_prepare(req); struct fuse_entry_param e; char *path; int err; err = get_path_name(f, parent, name, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_symlink(f->fs, linkname, path); if (!err) err = lookup_path(f, parent, name, path, &e, NULL); fuse_finish_interrupt(f, req, &d); free_path(f, parent, path); } reply_entry(req, &e, err); } static void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname, fuse_ino_t newdir, const char *newname, unsigned int flags) { struct fuse *f = req_fuse_prepare(req); char *oldpath; char *newpath; struct node *wnode1; struct node *wnode2; int err; err = get_path2(f, olddir, oldname, newdir, newname, &oldpath, &newpath, &wnode1, &wnode2); if (!err) { struct fuse_intr_data d; err = 0; fuse_prepare_interrupt(f, req, &d); if (!f->conf.hard_remove && !(flags & RENAME_EXCHANGE) && is_open(f, newdir, newname)) err = hide_node(f, newpath, newdir, newname); if (!err) { err = fuse_fs_rename(f->fs, oldpath, newpath, flags); if (!err) { if (flags & RENAME_EXCHANGE) { err = exchange_node(f, olddir, oldname, newdir, newname); } else { err = rename_node(f, olddir, oldname, newdir, newname, 0); } } } fuse_finish_interrupt(f, req, &d); free_path2(f, olddir, newdir, wnode1, wnode2, oldpath, newpath); } reply_err(req, err); } static void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) { struct fuse *f = req_fuse_prepare(req); struct fuse_entry_param e; char *oldpath; char *newpath; int err; err = get_path2(f, ino, NULL, newparent, newname, &oldpath, &newpath, NULL, NULL); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_link(f->fs, oldpath, newpath); if (!err) err = lookup_path(f, newparent, newname, newpath, &e, NULL); fuse_finish_interrupt(f, req, &d); free_path2(f, ino, newparent, NULL, NULL, oldpath, newpath); } reply_entry(req, &e, err); } static void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path, struct fuse_file_info *fi) { struct node *node; int unlink_hidden = 0; fuse_fs_release(f->fs, path, fi); pthread_mutex_lock(&f->lock); node = get_node(f, ino); assert(node->open_count > 0); --node->open_count; if (node->is_hidden && !node->open_count) { unlink_hidden = 1; node->is_hidden = 0; } pthread_mutex_unlock(&f->lock); if(unlink_hidden) { if (path) { fuse_fs_unlink(f->fs, path); } else if (f->conf.nullpath_ok) { char *unlinkpath; if (get_path(f, ino, &unlinkpath) == 0) fuse_fs_unlink(f->fs, unlinkpath); free_path(f, ino, unlinkpath); } } } static void fuse_lib_create(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; struct fuse_entry_param e; char *path; int err; err = get_path_name(f, parent, name, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_create(f->fs, path, mode, fi); if (!err) { err = lookup_path(f, parent, name, path, &e, fi); if (err) fuse_fs_release(f->fs, path, fi); else if (!S_ISREG(e.attr.st_mode)) { err = -EIO; fuse_fs_release(f->fs, path, fi); forget_node(f, e.ino, 1); } else { if (f->conf.direct_io) fi->direct_io = 1; if (f->conf.kernel_cache) fi->keep_cache = 1; if (fi->direct_io && f->conf.parallel_direct_writes) fi->parallel_direct_writes = 1; } } fuse_finish_interrupt(f, req, &d); } if (!err) { pthread_mutex_lock(&f->lock); get_node(f, e.ino)->open_count++; pthread_mutex_unlock(&f->lock); if (fuse_reply_create(req, &e, fi) == -ENOENT) { /* The open syscall was interrupted, so it must be cancelled */ fuse_do_release(f, e.ino, path, fi); forget_node(f, e.ino, 1); } } else { reply_err(req, err); } free_path(f, parent, path); } static double diff_timespec(const struct timespec *t1, const struct timespec *t2) { return (t1->tv_sec - t2->tv_sec) + ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0; } static void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path, struct fuse_file_info *fi) { struct node *node; pthread_mutex_lock(&f->lock); node = get_node(f, ino); if (node->cache_valid) { struct timespec now; curr_time(&now); if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) { struct stat stbuf; int err; pthread_mutex_unlock(&f->lock); err = fuse_fs_getattr(f->fs, path, &stbuf, fi); pthread_mutex_lock(&f->lock); if (!err) update_stat(node, &stbuf); else node->cache_valid = 0; } } if (node->cache_valid) fi->keep_cache = 1; node->cache_valid = 1; pthread_mutex_unlock(&f->lock); } static void fuse_lib_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err; err = get_path(f, ino, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_open(f->fs, path, fi); if (!err) { if (f->conf.direct_io) fi->direct_io = 1; if (f->conf.kernel_cache) fi->keep_cache = 1; if (f->conf.auto_cache) open_auto_cache(f, ino, path, fi); if (f->conf.no_rofd_flush && (fi->flags & O_ACCMODE) == O_RDONLY) fi->noflush = 1; if (fi->direct_io && f->conf.parallel_direct_writes) fi->parallel_direct_writes = 1; } fuse_finish_interrupt(f, req, &d); } if (!err) { pthread_mutex_lock(&f->lock); get_node(f, ino)->open_count++; pthread_mutex_unlock(&f->lock); if (fuse_reply_open(req, fi) == -ENOENT) { /* The open syscall was interrupted, so it must be cancelled */ fuse_do_release(f, ino, path, fi); } } else reply_err(req, err); free_path(f, ino, path); } static void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_bufvec *buf = NULL; char *path; int res; res = get_path_nullok(f, ino, &path); if (res == 0) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = fuse_fs_read_buf(f->fs, path, &buf, size, off, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (res == 0) fuse_reply_data(req, buf, FUSE_BUF_SPLICE_MOVE); else reply_err(req, res); fuse_free_buf(buf); } static void fuse_lib_write_buf(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *buf, off_t off, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); char *path; int res; res = get_path_nullok(f, ino, &path); if (res == 0) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); res = fuse_fs_write_buf(f->fs, path, buf, off, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (res >= 0) fuse_reply_write(req, res); else reply_err(req, res); } static void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path_nullok(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_fsync(f->fs, path, datasync, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi, struct fuse_file_info *fi) { struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh; memset(fi, 0, sizeof(struct fuse_file_info)); fi->fh = dh->fh; return dh; } static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *llfi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; struct fuse_dh *dh; struct fuse_file_info fi; char *path; int err; dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh)); if (dh == NULL) { reply_err(req, -ENOMEM); return; } memset(dh, 0, sizeof(struct fuse_dh)); dh->fuse = f; dh->contents = NULL; dh->first = NULL; dh->len = 0; dh->filled = 0; dh->nodeid = ino; pthread_mutex_init(&dh->lock, NULL); llfi->fh = (uintptr_t) dh; memset(&fi, 0, sizeof(fi)); fi.flags = llfi->flags; err = get_path(f, ino, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_opendir(f->fs, path, &fi); fuse_finish_interrupt(f, req, &d); dh->fh = fi.fh; llfi->cache_readdir = fi.cache_readdir; llfi->keep_cache = fi.keep_cache; } if (!err) { if (fuse_reply_open(req, llfi) == -ENOENT) { /* The opendir syscall was interrupted, so it must be cancelled */ fuse_fs_releasedir(f->fs, path, &fi); pthread_mutex_destroy(&dh->lock); free(dh); } } else { reply_err(req, err); pthread_mutex_destroy(&dh->lock); free(dh); } free_path(f, ino, path); } static int extend_contents(struct fuse_dh *dh, unsigned minsize) { if (minsize > dh->size) { char *newptr; unsigned newsize = dh->size; if (!newsize) newsize = 1024; while (newsize < minsize) { if (newsize >= 0x80000000) newsize = 0xffffffff; else newsize *= 2; } newptr = (char *) realloc(dh->contents, newsize); if (!newptr) { dh->error = -ENOMEM; return -1; } dh->contents = newptr; dh->size = newsize; } return 0; } static int fuse_add_direntry_to_dh(struct fuse_dh *dh, const char *name, struct stat *st, enum fuse_fill_dir_flags flags) { struct fuse_direntry *de; de = malloc(sizeof(struct fuse_direntry)); if (!de) { dh->error = -ENOMEM; return -1; } de->name = strdup(name); if (!de->name) { dh->error = -ENOMEM; free(de); return -1; } de->flags = flags; de->stat = *st; de->next = NULL; *dh->last = de; dh->last = &de->next; return 0; } static fuse_ino_t lookup_nodeid(struct fuse *f, fuse_ino_t parent, const char *name) { struct node *node; fuse_ino_t res = FUSE_UNKNOWN_INO; pthread_mutex_lock(&f->lock); node = lookup_node(f, parent, name); if (node) res = node->nodeid; pthread_mutex_unlock(&f->lock); return res; } static int fill_dir(void *dh_, const char *name, const struct stat *statp, off_t off, enum fuse_fill_dir_flags flags) { struct fuse_dh *dh = (struct fuse_dh *) dh_; struct stat stbuf; if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) { dh->error = -EIO; return 1; } if (statp) stbuf = *statp; else { memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = FUSE_UNKNOWN_INO; } if (!dh->fuse->conf.use_ino) { stbuf.st_ino = FUSE_UNKNOWN_INO; if (dh->fuse->conf.readdir_ino) { stbuf.st_ino = (ino_t) lookup_nodeid(dh->fuse, dh->nodeid, name); } } if (off) { size_t newlen; if (dh->filled) { dh->error = -EIO; return 1; } if (dh->first) { dh->error = -EIO; return 1; } if (extend_contents(dh, dh->needlen) == -1) return 1; newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len, dh->needlen - dh->len, name, &stbuf, off); if (newlen > dh->needlen) return 1; dh->len = newlen; } else { dh->filled = 1; if (fuse_add_direntry_to_dh(dh, name, &stbuf, flags) == -1) return 1; } return 0; } static int is_dot_or_dotdot(const char *name) { return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); } static int fill_dir_plus(void *dh_, const char *name, const struct stat *statp, off_t off, enum fuse_fill_dir_flags flags) { struct fuse_dh *dh = (struct fuse_dh *) dh_; struct fuse_entry_param e = { /* ino=0 tells the kernel to ignore readdirplus stat info */ .ino = 0, }; struct fuse *f = dh->fuse; int res; if ((flags & ~FUSE_FILL_DIR_PLUS) != 0) { dh->error = -EIO; return 1; } if (statp && (flags & FUSE_FILL_DIR_PLUS)) { e.attr = *statp; } e.attr.st_ino = FUSE_UNKNOWN_INO; if (statp) { e.attr.st_mode = statp->st_mode; if (f->conf.use_ino) e.attr.st_ino = statp->st_ino; } if (!f->conf.use_ino && f->conf.readdir_ino) { e.attr.st_ino = (ino_t) lookup_nodeid(f, dh->nodeid, name); } if (off) { size_t newlen; if (dh->filled) { dh->error = -EIO; return 1; } if (dh->first) { dh->error = -EIO; return 1; } if (extend_contents(dh, dh->needlen) == -1) return 1; if (statp && (flags & FUSE_FILL_DIR_PLUS)) { if (!is_dot_or_dotdot(name)) { res = do_lookup(f, dh->nodeid, name, &e); if (res) { dh->error = res; return 1; } } } newlen = dh->len + fuse_add_direntry_plus(dh->req, dh->contents + dh->len, dh->needlen - dh->len, name, &e, off); if (newlen > dh->needlen) return 1; dh->len = newlen; } else { dh->filled = 1; if (fuse_add_direntry_to_dh(dh, name, &e.attr, flags) == -1) return 1; } return 0; } static void free_direntries(struct fuse_direntry *de) { while (de) { struct fuse_direntry *next = de->next; free(de->name); free(de); de = next; } } static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_dh *dh, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { char *path; int err; if (f->fs->op.readdir) err = get_path_nullok(f, ino, &path); else err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_fill_dir_t filler = fill_dir; if (flags & FUSE_READDIR_PLUS) filler = fill_dir_plus; free_direntries(dh->first); dh->first = NULL; dh->last = &dh->first; dh->len = 0; dh->error = 0; dh->needlen = size; dh->filled = 0; dh->req = req; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_readdir(f->fs, path, dh, filler, off, fi, flags); fuse_finish_interrupt(f, req, &d); dh->req = NULL; if (!err) err = dh->error; if (err) dh->filled = 0; free_path(f, ino, path); } return err; } static int readdir_fill_from_list(fuse_req_t req, struct fuse_dh *dh, off_t off, enum fuse_readdir_flags flags) { off_t pos; struct fuse_direntry *de = dh->first; int res; dh->len = 0; if (extend_contents(dh, dh->needlen) == -1) return dh->error; for (pos = 0; pos < off; pos++) { if (!de) break; de = de->next; } while (de) { char *p = dh->contents + dh->len; unsigned rem = dh->needlen - dh->len; unsigned thislen; unsigned newlen; pos++; if (flags & FUSE_READDIR_PLUS) { struct fuse_entry_param e = { .ino = 0, .attr = de->stat, }; if (de->flags & FUSE_FILL_DIR_PLUS && !is_dot_or_dotdot(de->name)) { res = do_lookup(dh->fuse, dh->nodeid, de->name, &e); if (res) { dh->error = res; return 1; } } thislen = fuse_add_direntry_plus(req, p, rem, de->name, &e, pos); } else { thislen = fuse_add_direntry(req, p, rem, de->name, &de->stat, pos); } newlen = dh->len + thislen; if (newlen > dh->needlen) break; dh->len = newlen; de = de->next; } return 0; } static void fuse_readdir_common(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *llfi, enum fuse_readdir_flags flags) { struct fuse *f = req_fuse_prepare(req); struct fuse_file_info fi; struct fuse_dh *dh = get_dirhandle(llfi, &fi); int err; pthread_mutex_lock(&dh->lock); /* According to SUS, directory contents need to be refreshed on rewinddir() */ if (!off) dh->filled = 0; if (!dh->filled) { err = readdir_fill(f, req, ino, size, off, dh, &fi, flags); if (err) { reply_err(req, err); goto out; } } if (dh->filled) { dh->needlen = size; err = readdir_fill_from_list(req, dh, off, flags); if (err) { reply_err(req, err); goto out; } } fuse_reply_buf(req, dh->contents, dh->len); out: pthread_mutex_unlock(&dh->lock); } static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *llfi) { fuse_readdir_common(req, ino, size, off, llfi, 0); } static void fuse_lib_readdirplus(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *llfi) { fuse_readdir_common(req, ino, size, off, llfi, FUSE_READDIR_PLUS); } static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *llfi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; struct fuse_file_info fi; struct fuse_dh *dh = get_dirhandle(llfi, &fi); char *path; get_path_nullok(f, ino, &path); fuse_prepare_interrupt(f, req, &d); fuse_fs_releasedir(f->fs, path, &fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); pthread_mutex_lock(&dh->lock); pthread_mutex_unlock(&dh->lock); pthread_mutex_destroy(&dh->lock); free_direntries(dh->first); free(dh->contents); free(dh); reply_err(req, 0); } static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *llfi) { struct fuse *f = req_fuse_prepare(req); struct fuse_file_info fi; char *path; int err; get_dirhandle(llfi, &fi); err = get_path_nullok(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino) { struct fuse *f = req_fuse_prepare(req); struct statvfs buf; char *path = NULL; int err = 0; memset(&buf, 0, sizeof(buf)); if (ino) err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_statfs(f->fs, path ? path : "/", &buf); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) fuse_reply_statfs(req, &buf); else reply_err(req, err); } static void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_setxattr(f->fs, path, name, value, size, flags); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, const char *name, char *value, size_t size) { int err; char *path; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_getxattr(f->fs, path, name, value, size); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } return err; } static void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { struct fuse *f = req_fuse_prepare(req); int res; if (size) { char *value = (char *) malloc(size); if (value == NULL) { reply_err(req, -ENOMEM); return; } res = common_getxattr(f, req, ino, name, value, size); if (res > 0) fuse_reply_buf(req, value, res); else reply_err(req, res); free(value); } else { res = common_getxattr(f, req, ino, name, NULL, 0); if (res >= 0) fuse_reply_xattr(req, res); else reply_err(req, res); } } static int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino, char *list, size_t size) { char *path; int err; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_listxattr(f->fs, path, list, size); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } return err; } static void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { struct fuse *f = req_fuse_prepare(req); int res; if (size) { char *list = (char *) malloc(size); if (list == NULL) { reply_err(req, -ENOMEM); return; } res = common_listxattr(f, req, ino, list, size); if (res > 0) fuse_reply_buf(req, list, res); else reply_err(req, res); free(list); } else { res = common_listxattr(f, req, ino, NULL, 0); if (res >= 0) fuse_reply_xattr(req, res); else reply_err(req, res); } } static void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_removexattr(f->fs, path, name); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static struct lock *locks_conflict(struct node *node, const struct lock *lock) { struct lock *l; for (l = node->locks; l; l = l->next) if (l->owner != lock->owner && lock->start <= l->end && l->start <= lock->end && (l->type == F_WRLCK || lock->type == F_WRLCK)) break; return l; } static void delete_lock(struct lock **lockp) { struct lock *l = *lockp; *lockp = l->next; free(l); } static void insert_lock(struct lock **pos, struct lock *lock) { lock->next = *pos; *pos = lock; } static int locks_insert(struct node *node, struct lock *lock) { struct lock **lp; struct lock *newl1 = NULL; struct lock *newl2 = NULL; if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) { newl1 = malloc(sizeof(struct lock)); newl2 = malloc(sizeof(struct lock)); if (!newl1 || !newl2) { free(newl1); free(newl2); return -ENOLCK; } } for (lp = &node->locks; *lp;) { struct lock *l = *lp; if (l->owner != lock->owner) goto skip; if (lock->type == l->type) { if (l->end < lock->start - 1) goto skip; if (lock->end < l->start - 1) break; if (l->start <= lock->start && lock->end <= l->end) goto out; if (l->start < lock->start) lock->start = l->start; if (lock->end < l->end) lock->end = l->end; goto delete; } else { if (l->end < lock->start) goto skip; if (lock->end < l->start) break; if (lock->start <= l->start && l->end <= lock->end) goto delete; if (l->end <= lock->end) { l->end = lock->start - 1; goto skip; } if (lock->start <= l->start) { l->start = lock->end + 1; break; } *newl2 = *l; newl2->start = lock->end + 1; l->end = lock->start - 1; insert_lock(&l->next, newl2); newl2 = NULL; } skip: lp = &l->next; continue; delete: delete_lock(lp); } if (lock->type != F_UNLCK) { *newl1 = *lock; insert_lock(lp, newl1); newl1 = NULL; } out: free(newl1); free(newl2); return 0; } static void flock_to_lock(struct flock *flock, struct lock *lock) { memset(lock, 0, sizeof(struct lock)); lock->type = flock->l_type; lock->start = flock->l_start; lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX; lock->pid = flock->l_pid; } static void lock_to_flock(struct lock *lock, struct flock *flock) { flock->l_type = lock->type; flock->l_start = lock->start; flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1; flock->l_pid = lock->pid; } static int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino, const char *path, struct fuse_file_info *fi) { struct fuse_intr_data d; struct flock lock; struct lock l; int err; int errlock; fuse_prepare_interrupt(f, req, &d); memset(&lock, 0, sizeof(lock)); lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; err = fuse_fs_flush(f->fs, path, fi); errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock); fuse_finish_interrupt(f, req, &d); if (errlock != -ENOSYS) { flock_to_lock(&lock, &l); l.owner = fi->lock_owner; pthread_mutex_lock(&f->lock); locks_insert(get_node(f, ino), &l); pthread_mutex_unlock(&f->lock); /* if op.lock() is defined FLUSH is needed regardless of op.flush() */ if (err == -ENOSYS) err = 0; } return err; } static void fuse_lib_release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err = 0; get_path_nullok(f, ino, &path); if (fi->flush) { err = fuse_flush_common(f, req, ino, path, fi); if (err == -ENOSYS) err = 0; } fuse_prepare_interrupt(f, req, &d); fuse_do_release(f, ino, path, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); reply_err(req, err); } static void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); char *path; int err; get_path_nullok(f, ino, &path); err = fuse_flush_common(f, req, ino, path, fi); free_path(f, ino, path); reply_err(req, err); } static int fuse_lock_common(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int cmd) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path_nullok(f, ino, &path); if (!err) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_lock(f->fs, path, fi, cmd, lock); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } return err; } static void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock) { int err; struct lock l; struct lock *conflict; struct fuse *f = req_fuse(req); flock_to_lock(lock, &l); l.owner = fi->lock_owner; pthread_mutex_lock(&f->lock); conflict = locks_conflict(get_node(f, ino), &l); if (conflict) lock_to_flock(conflict, lock); pthread_mutex_unlock(&f->lock); if (!conflict) err = fuse_lock_common(req, ino, fi, lock, F_GETLK); else err = 0; if (!err) fuse_reply_lock(req, lock); else reply_err(req, err); } static void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep) { int err = fuse_lock_common(req, ino, fi, lock, sleep ? F_SETLKW : F_SETLK); if (!err) { struct fuse *f = req_fuse(req); struct lock l; flock_to_lock(lock, &l); l.owner = fi->lock_owner; pthread_mutex_lock(&f->lock); locks_insert(get_node(f, ino), &l); pthread_mutex_unlock(&f->lock); } reply_err(req, err); } static void fuse_lib_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op) { struct fuse *f = req_fuse_prepare(req); char *path; int err; err = get_path_nullok(f, ino, &path); if (err == 0) { struct fuse_intr_data d; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_flock(f->fs, path, fi, op); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err; err = get_path(f, ino, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_bmap(f->fs, path, blocksize, &idx); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) fuse_reply_bmap(req, idx); else reply_err(req, err); } static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *llfi, unsigned int flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; struct fuse_file_info fi; char *path, *out_buf = NULL; int err; err = -EPERM; if (flags & FUSE_IOCTL_UNRESTRICTED) goto err; if (flags & FUSE_IOCTL_DIR) get_dirhandle(llfi, &fi); else fi = *llfi; if (out_bufsz) { err = -ENOMEM; out_buf = malloc(out_bufsz); if (!out_buf) goto err; } assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz); if (out_buf && in_bufsz) memcpy(out_buf, in_buf, in_bufsz); err = get_path_nullok(f, ino, &path); if (err) goto err; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags, out_buf ? out_buf : (void *)in_buf); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); if (err < 0) goto err; fuse_reply_ioctl(req, err, out_buf, out_bufsz); goto out; err: reply_err(req, err); out: free(out_buf); } static void fuse_lib_poll(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err; unsigned revents = 0; err = get_path_nullok(f, ino, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_poll(f->fs, path, fi, ph, &revents); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } else { fuse_pollhandle_destroy(ph); } if (!err) fuse_reply_poll(req, revents); else reply_err(req, err); } static void fuse_lib_fallocate(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err; err = get_path_nullok(f, ino, &path); if (!err) { fuse_prepare_interrupt(f, req, &d); err = fuse_fs_fallocate(f->fs, path, mode, offset, length, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } reply_err(req, err); } static void fuse_lib_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t nodeid_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path_in, *path_out; int err; ssize_t res; err = get_path_nullok(f, nodeid_in, &path_in); if (err) { reply_err(req, err); return; } err = get_path_nullok(f, nodeid_out, &path_out); if (err) { free_path(f, nodeid_in, path_in); reply_err(req, err); return; } fuse_prepare_interrupt(f, req, &d); res = fuse_fs_copy_file_range(f->fs, path_in, fi_in, off_in, path_out, fi_out, off_out, len, flags); fuse_finish_interrupt(f, req, &d); if (res >= 0) fuse_reply_write(req, res); else reply_err(req, res); free_path(f, nodeid_in, path_in); free_path(f, nodeid_out, path_out); } static void fuse_lib_lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct fuse_intr_data d; char *path; int err; off_t res; err = get_path(f, ino, &path); if (err) { reply_err(req, err); return; } fuse_prepare_interrupt(f, req, &d); res = fuse_fs_lseek(f->fs, path, off, whence, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); if (res >= 0) fuse_reply_lseek(req, res); else reply_err(req, res); } #ifdef HAVE_STATX static void fuse_lib_statx(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi) { struct fuse *f = req_fuse_prepare(req); struct statx stxbuf; char *path; int err; memset(&stxbuf, 0, sizeof(stxbuf)); if (fi != NULL) err = get_path_nullok(f, ino, &path); else err = get_path(f, ino, &path); if (!err) { struct fuse_intr_data d; if (!path) flags |= AT_EMPTY_PATH; fuse_prepare_interrupt(f, req, &d); err = fuse_fs_statx(f->fs, path, flags, mask, &stxbuf, fi); fuse_finish_interrupt(f, req, &d); free_path(f, ino, path); } if (!err) { struct node *node; pthread_mutex_lock(&f->lock); node = get_node(f, ino); if (node->is_hidden && stxbuf.stx_nlink > 0) stxbuf.stx_nlink--; if (f->conf.auto_cache) { struct stat stbuf; stbuf.st_mtime = stxbuf.stx_mtime.tv_sec; ST_MTIM_NSEC_SET(&stbuf, stxbuf.stx_mtime.tv_nsec); stbuf.st_size = stxbuf.stx_size; update_stat(node, &stbuf); } pthread_mutex_unlock(&f->lock); set_statx(f, ino, &stxbuf); fuse_reply_statx(req, 0, &stxbuf, f->conf.attr_timeout); } else reply_err(req, err); } #endif static int clean_delay(struct fuse *f) { /* * This is calculating the delay between clean runs. To * reduce the number of cleans we are doing them 10 times * within the remember window. */ int min_sleep = 60; int max_sleep = 3600; int sleep_time = f->conf.remember / 10; if (sleep_time > max_sleep) return max_sleep; if (sleep_time < min_sleep) return min_sleep; return sleep_time; } int fuse_clean_cache(struct fuse *f) { struct node_lru *lnode; struct list_head *curr, *next; struct node *node; struct timespec now; pthread_mutex_lock(&f->lock); curr_time(&now); for (curr = f->lru_table.next; curr != &f->lru_table; curr = next) { double age; next = curr->next; lnode = list_entry(curr, struct node_lru, lru); node = &lnode->node; age = diff_timespec(&now, &lnode->forget_time); if (age <= f->conf.remember) break; assert(node->nlookup == 1); /* Don't forget active directories */ if (node->refctr > 1) continue; node->nlookup = 0; unhash_name(f, node); unref_node(f, node); } pthread_mutex_unlock(&f->lock); return clean_delay(f); } static struct fuse_lowlevel_ops fuse_path_ops = { .init = fuse_lib_init, .destroy = fuse_lib_destroy, .lookup = fuse_lib_lookup, .forget = fuse_lib_forget, .forget_multi = fuse_lib_forget_multi, .getattr = fuse_lib_getattr, .setattr = fuse_lib_setattr, .access = fuse_lib_access, .readlink = fuse_lib_readlink, .mknod = fuse_lib_mknod, .mkdir = fuse_lib_mkdir, .unlink = fuse_lib_unlink, .rmdir = fuse_lib_rmdir, .symlink = fuse_lib_symlink, .rename = fuse_lib_rename, .link = fuse_lib_link, .create = fuse_lib_create, .open = fuse_lib_open, .read = fuse_lib_read, .write_buf = fuse_lib_write_buf, .flush = fuse_lib_flush, .release = fuse_lib_release, .fsync = fuse_lib_fsync, .opendir = fuse_lib_opendir, .readdir = fuse_lib_readdir, .readdirplus = fuse_lib_readdirplus, .releasedir = fuse_lib_releasedir, .fsyncdir = fuse_lib_fsyncdir, .statfs = fuse_lib_statfs, .setxattr = fuse_lib_setxattr, .getxattr = fuse_lib_getxattr, .listxattr = fuse_lib_listxattr, .removexattr = fuse_lib_removexattr, .getlk = fuse_lib_getlk, .setlk = fuse_lib_setlk, .flock = fuse_lib_flock, .bmap = fuse_lib_bmap, .ioctl = fuse_lib_ioctl, .poll = fuse_lib_poll, .fallocate = fuse_lib_fallocate, .copy_file_range = fuse_lib_copy_file_range, .lseek = fuse_lib_lseek, #ifdef HAVE_STATX .statx = fuse_lib_statx, #endif }; int fuse_notify_poll(struct fuse_pollhandle *ph) { return fuse_lowlevel_notify_poll(ph); } struct fuse_session *fuse_get_session(struct fuse *f) { return f->se; } static int fuse_session_loop_remember(struct fuse *f) { struct fuse_session *se = f->se; int res = 0; struct timespec now; time_t next_clean; struct pollfd fds = { .fd = se->fd, .events = POLLIN }; struct fuse_buf fbuf = { .mem = NULL, }; curr_time(&now); next_clean = now.tv_sec; while (!fuse_session_exited(se)) { unsigned timeout; curr_time(&now); if (now.tv_sec < next_clean) timeout = next_clean - now.tv_sec; else timeout = 0; res = poll(&fds, 1, timeout * 1000); if (res == -1) { if (errno == EINTR) continue; else break; } else if (res > 0) { res = fuse_session_receive_buf_internal(se, &fbuf, NULL); if (res == -EINTR) continue; if (res <= 0) break; fuse_session_process_buf_internal(se, &fbuf, NULL); } else { timeout = fuse_clean_cache(f); curr_time(&now); next_clean = now.tv_sec + timeout; } } fuse_buf_free(&fbuf); return res < 0 ? -1 : 0; } int fuse_loop(struct fuse *f) { if (!f) return -1; if (lru_enabled(f)) return fuse_session_loop_remember(f); return fuse_session_loop(f->se); } FUSE_SYMVER("fuse_loop_mt_312", "fuse_loop_mt@@FUSE_3.12") int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config) { if (f == NULL) return -1; int res = fuse_start_cleanup_thread(f); if (res) return -1; res = fuse_session_loop_mt_312(fuse_get_session(f), config); fuse_stop_cleanup_thread(f); return res; } int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1); FUSE_SYMVER("fuse_loop_mt_32", "fuse_loop_mt@FUSE_3.2") int fuse_loop_mt_32(struct fuse *f, struct fuse_loop_config_v1 *config_v1) { struct fuse_loop_config *config = fuse_loop_cfg_create(); if (config == NULL) return ENOMEM; fuse_loop_cfg_convert(config, config_v1); int res = fuse_loop_mt_312(f, config); fuse_loop_cfg_destroy(config); return res; } int fuse_loop_mt_31(struct fuse *f, int clone_fd); FUSE_SYMVER("fuse_loop_mt_31", "fuse_loop_mt@FUSE_3.0") int fuse_loop_mt_31(struct fuse *f, int clone_fd) { int err; struct fuse_loop_config *config = fuse_loop_cfg_create(); if (config == NULL) return ENOMEM; fuse_loop_cfg_set_clone_fd(config, clone_fd); err = fuse_loop_mt_312(f, config); fuse_loop_cfg_destroy(config); return err; } void fuse_exit(struct fuse *f) { fuse_session_exit(f->se); } struct fuse_context *fuse_get_context(void) { struct fuse_context_i *c = fuse_get_context_internal(); if (c) return &c->ctx; else return NULL; } int fuse_getgroups(int size, gid_t list[]) { struct fuse_context_i *c = fuse_get_context_internal(); if (!c) return -EINVAL; return fuse_req_getgroups(c->req, size, list); } int fuse_interrupted(void) { struct fuse_context_i *c = fuse_get_context_internal(); if (c) return fuse_req_interrupted(c->req); else return 0; } int fuse_invalidate_path(struct fuse *f, const char *path) { fuse_ino_t ino; int err = lookup_path_in_cache(f, path, &ino); if (err) { return err; } return fuse_lowlevel_notify_inval_inode(f->se, ino, 0, 0); } #define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v } static const struct fuse_opt fuse_lib_opts[] = { FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), FUSE_LIB_OPT("debug", debug, 1), FUSE_LIB_OPT("-d", debug, 1), FUSE_LIB_OPT("kernel_cache", kernel_cache, 1), FUSE_LIB_OPT("auto_cache", auto_cache, 1), FUSE_LIB_OPT("noauto_cache", auto_cache, 0), FUSE_LIB_OPT("no_rofd_flush", no_rofd_flush, 1), FUSE_LIB_OPT("umask=", set_mode, 1), FUSE_LIB_OPT("umask=%o", umask, 0), FUSE_LIB_OPT("fmask=", set_mode, 1), FUSE_LIB_OPT("fmask=%o", fmask, 0), FUSE_LIB_OPT("dmask=", set_mode, 1), FUSE_LIB_OPT("dmask=%o", dmask, 0), FUSE_LIB_OPT("uid=", set_uid, 1), FUSE_LIB_OPT("uid=%d", uid, 0), FUSE_LIB_OPT("gid=", set_gid, 1), FUSE_LIB_OPT("gid=%d", gid, 0), FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0), FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0), FUSE_LIB_OPT("ac_attr_timeout=%lf", ac_attr_timeout, 0), FUSE_LIB_OPT("ac_attr_timeout=", ac_attr_timeout_set, 1), FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0), FUSE_LIB_OPT("noforget", remember, -1), FUSE_LIB_OPT("remember=%u", remember, 0), FUSE_LIB_OPT("modules=%s", modules, 0), FUSE_LIB_OPT("parallel_direct_write=%d", parallel_direct_writes, 0), FUSE_OPT_END }; static int fuse_lib_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) arg; (void) outargs; (void) data; (void) key; /* Pass through unknown options */ return 1; } static const struct fuse_opt fuse_help_opts[] = { FUSE_LIB_OPT("modules=%s", modules, 1), FUSE_OPT_KEY("modules=%s", FUSE_OPT_KEY_KEEP), FUSE_OPT_END }; static void print_module_help(const char *name, fuse_module_factory_t *fac) { struct fuse_args a = FUSE_ARGS_INIT(0, NULL); if (fuse_opt_add_arg(&a, "") == -1 || fuse_opt_add_arg(&a, "-h") == -1) { fuse_opt_free_args(&a); return; } printf("\nOptions for %s module:\n", name); (*fac)(&a, NULL); fuse_opt_free_args(&a); } void fuse_lib_help(struct fuse_args *args) { /* These are not all options, but only the ones that may be of interest to an end-user */ printf( " -o kernel_cache cache files in kernel\n" " -o [no]auto_cache enable caching based on modification times (off)\n" " -o no_rofd_flush disable flushing of read-only fd on close (off)\n" " -o umask=M set file permissions (octal)\n" " -o fmask=M set file permissions (octal)\n" " -o dmask=M set dir permissions (octal)\n" " -o uid=N set file owner\n" " -o gid=N set file group\n" " -o entry_timeout=T cache timeout for names (1.0s)\n" " -o negative_timeout=T cache timeout for deleted names (0.0s)\n" " -o attr_timeout=T cache timeout for attributes (1.0s)\n" " -o ac_attr_timeout=T auto cache timeout for attributes (attr_timeout)\n" " -o noforget never forget cached inodes\n" " -o remember=T remember cached inodes for T seconds (0s)\n" " -o modules=M1[:M2...] names of modules to push onto filesystem stack\n"); /* Print low-level help */ fuse_lowlevel_help(); /* Print help for builtin modules */ print_module_help("subdir", &fuse_module_subdir_factory); #ifdef HAVE_ICONV print_module_help("iconv", &fuse_module_iconv_factory); #endif /* Parse command line options in case we need to activate more modules */ struct fuse_config conf = { .modules = NULL }; if (fuse_opt_parse(args, &conf, fuse_help_opts, fuse_lib_opt_proc) == -1 || !conf.modules) return; char *module; char *next; struct fuse_module *m; // Iterate over all modules for (module = conf.modules; module; module = next) { char *p; for (p = module; *p && *p != ':'; p++); next = *p ? p + 1 : NULL; *p = '\0'; m = fuse_get_module(module); if (m) print_module_help(module, &m->factory); } } static int fuse_init_intr_signal(int signum, int *installed) { struct sigaction old_sa; if (sigaction(signum, NULL, &old_sa) == -1) { perror("fuse: cannot get old signal handler"); return -1; } if (old_sa.sa_handler == SIG_DFL) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = fuse_intr_sighandler; sigemptyset(&sa.sa_mask); if (sigaction(signum, &sa, NULL) == -1) { perror("fuse: cannot set interrupt signal handler"); return -1; } *installed = 1; } return 0; } static void fuse_restore_intr_signal(int signum) { struct sigaction sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = SIG_DFL; sigaction(signum, &sa, NULL); } static int fuse_push_module(struct fuse *f, const char *module, struct fuse_args *args) { struct fuse_fs *fs[2] = { f->fs, NULL }; struct fuse_fs *newfs; struct fuse_module *m = fuse_get_module(module); if (!m) return -1; newfs = m->factory(args, fs); if (!newfs) { fuse_put_module(m); return -1; } f->fs = newfs; return 0; } struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size, void *user_data) { struct fuse_fs *fs; if (sizeof(struct fuse_operations) < op_size) { fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not not work\n"); op_size = sizeof(struct fuse_operations); } fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs)); if (!fs) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse_fs object\n"); return NULL; } fs->user_data = user_data; if (op) memcpy(&fs->op, op, op_size); return fs; } static int node_table_init(struct node_table *t) { t->size = NODE_TABLE_MIN_SIZE; t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size); if (t->array == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); return -1; } t->use = 0; t->split = 0; return 0; } static void *fuse_prune_nodes(void *fuse) { struct fuse *f = fuse; int sleep_time; fuse_set_thread_name("fuse_prune_nodes"); while(1) { sleep_time = fuse_clean_cache(f); sleep(sleep_time); } return NULL; } int fuse_start_cleanup_thread(struct fuse *f) { if (lru_enabled(f)) return fuse_start_thread(&f->prune_thread, fuse_prune_nodes, f); return 0; } void fuse_stop_cleanup_thread(struct fuse *f) { if (lru_enabled(f)) { pthread_mutex_lock(&f->lock); pthread_cancel(f->prune_thread); pthread_mutex_unlock(&f->lock); pthread_join(f->prune_thread, NULL); } } /* * Not supposed to be called directly, but supposed to be called * through the fuse_new macro */ struct fuse *_fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data) { struct fuse *f; struct node *root; struct fuse_fs *fs; struct fuse_lowlevel_ops llop = fuse_path_ops; f = (struct fuse *) calloc(1, sizeof(struct fuse)); if (f == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n"); goto out; } f->conf.entry_timeout = 1.0; f->conf.attr_timeout = 1.0; f->conf.negative_timeout = 0.0; f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL; /* Parse options */ if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1) goto out_free; pthread_mutex_lock(&fuse_context_lock); static int builtin_modules_registered = 0; /* Have the builtin modules already been registered? */ if (builtin_modules_registered == 0) { /* If not, register them. */ fuse_register_module("subdir", fuse_module_subdir_factory, NULL); #ifdef HAVE_ICONV fuse_register_module("iconv", fuse_module_iconv_factory, NULL); #endif builtin_modules_registered= 1; } pthread_mutex_unlock(&fuse_context_lock); if (fuse_create_context_key() == -1) goto out_free; fs = fuse_fs_new(op, op_size, user_data); if (!fs) goto out_delete_context_key; f->fs = fs; /* Oh f**k, this is ugly! */ if (!fs->op.lock) { llop.getlk = NULL; llop.setlk = NULL; } f->pagesize = getpagesize(); init_list_head(&f->partial_slabs); init_list_head(&f->full_slabs); init_list_head(&f->lru_table); if (f->conf.modules) { char *module; char *next; for (module = f->conf.modules; module; module = next) { char *p; for (p = module; *p && *p != ':'; p++); next = *p ? p + 1 : NULL; *p = '\0'; if (module[0] && fuse_push_module(f, module, args) == -1) goto out_free_fs; } } if (!f->conf.ac_attr_timeout_set) f->conf.ac_attr_timeout = f->conf.attr_timeout; #if defined(__FreeBSD__) || defined(__NetBSD__) /* * In FreeBSD, we always use these settings as inode numbers * are needed to make getcwd(3) work. */ f->conf.readdir_ino = 1; #endif /* not declared globally, to restrict usage of this function */ struct fuse_session *fuse_session_new_versioned( struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, struct libfuse_version *version, void *userdata); f->se = fuse_session_new_versioned(args, &llop, sizeof(llop), version, f); if (f->se == NULL) goto out_free_fs; /* Trace topmost layer by default */ f->fs->debug = f->conf.debug; f->ctr = 0; f->generation = 0; if (node_table_init(&f->name_table) == -1) goto out_free_session; if (node_table_init(&f->id_table) == -1) goto out_free_name_table; pthread_mutex_init(&f->lock, NULL); root = alloc_node(f); if (root == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); goto out_free_id_table; } if (lru_enabled(f)) { struct node_lru *lnode = node_lru(root); init_list_head(&lnode->lru); } strcpy(root->inline_name, "/"); root->name = root->inline_name; root->parent = NULL; root->nodeid = FUSE_ROOT_ID; inc_nlookup(root); hash_id(f, root); return f; out_free_id_table: free(f->id_table.array); out_free_name_table: free(f->name_table.array); out_free_session: fuse_session_destroy(f->se); out_free_fs: free(f->fs); free(f->conf.modules); out_delete_context_key: fuse_delete_context_key(); out_free: free(f); out: return NULL; } /* Emulates 3.0-style fuse_new(), which processes --help */ FUSE_SYMVER("_fuse_new_30", "_fuse_new@FUSE_3.0") struct fuse *_fuse_new_30(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data) { struct fuse_config conf = {0}; const struct fuse_opt opts[] = { FUSE_LIB_OPT("-h", show_help, 1), FUSE_LIB_OPT("--help", show_help, 1), FUSE_OPT_END }; if (fuse_opt_parse(args, &conf, opts, fuse_lib_opt_proc) == -1) return NULL; if (conf.show_help) { fuse_lib_help(args); return NULL; } else return _fuse_new_31(args, op, op_size, version, user_data); } /* ABI compat version */ struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data); FUSE_SYMVER("fuse_new_31", "fuse_new@FUSE_3.1") struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { /* unknown version */ struct libfuse_version version = { 0 }; return _fuse_new_31(args, op, op_size, &version, user_data); } /* * ABI compat version * Emulates 3.0-style fuse_new(), which processes --help */ struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data); FUSE_SYMVER("fuse_new_30", "fuse_new@FUSE_3.0") struct fuse *fuse_new_30(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *user_data) { struct fuse_config conf = {0}; const struct fuse_opt opts[] = { FUSE_LIB_OPT("-h", show_help, 1), FUSE_LIB_OPT("--help", show_help, 1), FUSE_OPT_END }; if (fuse_opt_parse(args, &conf, opts, fuse_lib_opt_proc) == -1) return NULL; if (conf.show_help) { fuse_lib_help(args); return NULL; } else return fuse_new_31(args, op, op_size, user_data); } void fuse_destroy(struct fuse *f) { size_t i; if (f->conf.intr && f->intr_installed) fuse_restore_intr_signal(f->conf.intr_signal); if (f->fs) { fuse_create_context(f); for (i = 0; i < f->id_table.size; i++) { struct node *node; for (node = f->id_table.array[i]; node != NULL; node = node->id_next) { if (node->is_hidden) { char *path; if (try_get_path(f, node->nodeid, NULL, &path, NULL, false) == 0) { fuse_fs_unlink(f->fs, path); free(path); } } } } } for (i = 0; i < f->id_table.size; i++) { struct node *node; struct node *next; for (node = f->id_table.array[i]; node != NULL; node = next) { next = node->id_next; free_node(f, node); f->id_table.use--; } } assert(list_empty(&f->partial_slabs)); assert(list_empty(&f->full_slabs)); while (fuse_modules) { fuse_put_module(fuse_modules); } free(f->id_table.array); free(f->name_table.array); pthread_mutex_destroy(&f->lock); fuse_session_destroy(f->se); free(f->fs); free(f->conf.modules); free(f); fuse_delete_context_key(); } int fuse_mount(struct fuse *f, const char *mountpoint) { return fuse_session_mount(fuse_get_session(f), mountpoint); } void fuse_unmount(struct fuse *f) { fuse_session_unmount(fuse_get_session(f)); } int fuse_version(void) { return FUSE_VERSION; } const char *fuse_pkgversion(void) { return PACKAGE_VERSION; } fuse-3.18.3/lib/fuse_i.h0000644000175000017500000001536215250106036013714 0ustar berndbernd/* 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 LGPL2.txt */ #ifndef LIB_FUSE_I_H_ #define LIB_FUSE_I_H_ #include "fuse.h" #include "fuse_lowlevel.h" #include "util.h" #include #include #include #include #include #include #define MIN(a, b) \ ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ _a < _b ? _a : _b; \ }) struct mount_opts; struct fuse_ring_pool; struct fuse_req { struct fuse_session *se; uint64_t unique; _Atomic int ref_cnt; pthread_mutex_t lock; struct fuse_ctx ctx; struct fuse_chan *ch; int interrupted; struct { unsigned int ioctl_64bit : 1; unsigned int is_uring : 1; unsigned int is_copy_file_range_64 : 1; } flags; union { struct { uint64_t unique; } i; struct { fuse_interrupt_func_t func; void *data; } ni; } u; struct fuse_req *next; struct fuse_req *prev; }; struct fuse_notify_req { uint64_t unique; void (*reply)(struct fuse_notify_req *, fuse_req_t, fuse_ino_t, const void *, const struct fuse_buf *); struct fuse_notify_req *next; struct fuse_notify_req *prev; }; struct fuse_session_uring { bool enable; unsigned int q_depth; struct fuse_ring_pool *pool; }; struct fuse_session { _Atomic(char *)mountpoint; int fd; struct fuse_custom_io *io; struct mount_opts *mo; int debug; int deny_others; struct fuse_lowlevel_ops op; int got_init; struct cuse_data *cuse_data; void *userdata; uid_t owner; struct fuse_conn_info conn; struct fuse_req list; struct fuse_req interrupts; pthread_mutex_t lock; int got_destroy; pthread_key_t pipe_key; int broken_splice_nonblock; uint64_t notify_ctr; struct fuse_notify_req notify_list; _Atomic size_t bufsize; int error; /* * This is useful if any kind of ABI incompatibility is found at * a later version, to 'fix' it at run time. */ struct libfuse_version version; /* thread synchronization */ _Atomic bool mt_exited; pthread_mutex_t mt_lock; sem_t mt_finish; /* true if reading requests from /dev/fuse are handled internally */ bool buf_reallocable; /* io_uring */ struct fuse_session_uring uring; /* * conn->want and conn_want_ext options set by libfuse , needed * to correctly convert want to want_ext */ uint32_t conn_want; uint64_t conn_want_ext; }; struct fuse_chan { pthread_mutex_t lock; int ctr; int fd; }; /** * Filesystem module * * Filesystem modules are registered with the FUSE_REGISTER_MODULE() * macro. * */ struct fuse_module { char *name; fuse_module_factory_t factory; struct fuse_module *next; struct fusemod_so *so; int ctr; }; /** * Configuration parameters passed to fuse_session_loop_mt() and * fuse_loop_mt(). * * Internal API to avoid exposing the plain data structure and * causing compat issues after adding or removing struct members. * */ #if FUSE_USE_VERSION >= FUSE_MAKE_VERSION(3, 12) struct fuse_loop_config { /* verififier that a correct struct was was passed. This is especially * needed, as versions below (3, 12) were using a public struct * (now called fuse_loop_config_v1), which was hard to extend with * additional parameters, without risking that file system implementations * would not have noticed and might either pass uninitialized members * or even too small structs. * fuse_loop_config_v1 has clone_fd at this offset, which should be either 0 * or 1. v2 or even higher version just need to set a value here * which not conflicting and very unlikely as having been set by * file system implementation. */ int version_id; /** * whether to use separate device fds for each thread * (may increase performance) */ int clone_fd; /** * The maximum number of available worker threads before they * start to get deleted when they become idle. If not * specified, the default is -1. * * 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. * The special value of -1 means that this parameter is disabled. */ int max_idle_threads; /** * max number of threads taking and processing kernel requests * * As of now threads are created dynamically */ unsigned int max_threads; }; #endif /* ----------------------------------------------------------- * * Channel interface (when using -o clone_fd) * * ----------------------------------------------------------- */ /** * Obtain counted reference to the channel * * @param ch the channel * @return the channel */ struct fuse_chan *fuse_chan_get(struct fuse_chan *ch); /** * Drop counted reference to a channel * * @param ch the channel */ void fuse_chan_put(struct fuse_chan *ch); struct mount_opts *parse_mount_opts(struct fuse_args *args); void destroy_mount_opts(struct mount_opts *mo); void fuse_mount_version(void); unsigned get_max_read(struct mount_opts *o); void fuse_kern_unmount(const char *mountpoint, int fd); int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo); int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count); void fuse_free_req(fuse_req_t req); void list_init_req(struct fuse_req *req); void _cuse_lowlevel_init(fuse_req_t req, const fuse_ino_t nodeid, const void *req_header, const void *req_payload); void cuse_lowlevel_init(fuse_req_t req, fuse_ino_t nodeide, const void *inarg); int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg); void fuse_buf_free(struct fuse_buf *buf); int fuse_session_receive_buf_internal(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan *ch); void fuse_session_process_buf_internal(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch); struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, void *private_data); int fuse_loop_mt_312(struct fuse *f, struct fuse_loop_config *config); int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); /** * Internal verifier for the given config. * * @return negative standard error code or 0 on success */ int fuse_loop_cfg_verify(struct fuse_loop_config *config); /* * This can be changed dynamically on recent kernels through the * /proc/sys/fs/fuse/max_pages_limit interface. * * Older kernels will always use the default value. */ #define FUSE_DEFAULT_MAX_PAGES_LIMIT 256 #define FUSE_DEFAULT_MAX_PAGES_PER_REQ 32 /* room needed in buffer to accommodate header */ #define FUSE_BUFFER_HEADER_SIZE 0x1000 #endif /* LIB_FUSE_I_H_*/ fuse-3.18.3/lib/fuse_log.c0000644000175000017500000000176115250106036014236 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2019 Red Hat, Inc. Logging API. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include "fuse_log.h" #include #include #include #include #define MAX_SYSLOG_LINE_LEN 512 static bool to_syslog = false; static void default_log_func(enum fuse_log_level level, const char *fmt, va_list ap) { if (to_syslog) vsyslog(level, fmt, ap); else vfprintf(stderr, fmt, ap); } static fuse_log_func_t log_func = default_log_func; void fuse_set_log_func(fuse_log_func_t func) { if (!func) func = default_log_func; log_func = func; } void fuse_log(enum fuse_log_level level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); log_func(level, fmt, ap); va_end(ap); } void fuse_log_enable_syslog(const char *ident, int option, int facility) { to_syslog = true; openlog(ident, option, facility); } void fuse_log_close_syslog(void) { closelog(); } fuse-3.18.3/lib/fuse_loop.c0000644000175000017500000000165615250106036014431 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Implementation of the single-threaded FUSE session loop. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include "fuse_config.h" #include "fuse_lowlevel.h" #include "fuse_i.h" #include "fuse_uring_i.h" #include #include #include int fuse_session_loop(struct fuse_session *se) { int res = 0; struct fuse_buf fbuf = { .mem = NULL, }; while (!fuse_session_exited(se)) { res = fuse_session_receive_buf_internal(se, &fbuf, NULL); if (res == -EINTR) continue; if (res <= 0) break; fuse_session_process_buf(se, &fbuf); } fuse_buf_free(&fbuf); if(res > 0) /* No error, just the length of the most recently read request */ res = 0; if(se->error != 0) res = se->error; if (se->uring.pool) fuse_uring_stop(se); return res; } fuse-3.18.3/lib/fuse_loop_mt.c0000644000175000017500000003040515250106036015123 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Implementation of the multi-threaded FUSE session loop. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #define _GNU_SOURCE #include "fuse_config.h" #include "fuse_lowlevel.h" #include "fuse_misc.h" #include "fuse_kernel.h" #include "fuse_i.h" #include "fuse_uring_i.h" #include "util.h" #include #include #include #include #include #include #include #include #include #include #include /* Environment var controlling the thread stack size */ #define ENVNAME_THREAD_STACK "FUSE_THREAD_STACK" #define FUSE_LOOP_MT_V2_IDENTIFIER INT_MAX - 2 #define FUSE_LOOP_MT_DEF_CLONE_FD 0 #define FUSE_LOOP_MT_DEF_MAX_THREADS 10 #define FUSE_LOOP_MT_DEF_IDLE_THREADS -1 /* thread destruction is disabled * by default */ /* an arbitrary large value that cannot be valid */ #define FUSE_LOOP_MT_MAX_THREADS (100U * 1000) struct fuse_worker { struct fuse_worker *prev; struct fuse_worker *next; pthread_t thread_id; // We need to include fuse_buf so that we can properly free // it when a thread is terminated by pthread_cancel(). struct fuse_buf fbuf; struct fuse_chan *ch; struct fuse_mt *mt; }; /* synchronization via se->mt_lock */ struct fuse_mt { int numworker; int numavail; struct fuse_session *se; struct fuse_worker main; int error; int clone_fd; int max_idle; int max_threads; }; static struct fuse_chan *fuse_chan_new(int fd) { struct fuse_chan *ch = (struct fuse_chan *) malloc(sizeof(*ch)); if (ch == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate channel\n"); return NULL; } memset(ch, 0, sizeof(*ch)); ch->fd = fd; ch->ctr = 1; pthread_mutex_init(&ch->lock, NULL); return ch; } struct fuse_chan *fuse_chan_get(struct fuse_chan *ch) { assert(ch->ctr > 0); pthread_mutex_lock(&ch->lock); ch->ctr++; pthread_mutex_unlock(&ch->lock); return ch; } void fuse_chan_put(struct fuse_chan *ch) { if (ch == NULL) return; pthread_mutex_lock(&ch->lock); ch->ctr--; if (!ch->ctr) { pthread_mutex_unlock(&ch->lock); close(ch->fd); pthread_mutex_destroy(&ch->lock); free(ch); } else pthread_mutex_unlock(&ch->lock); } static void list_add_worker(struct fuse_worker *w, struct fuse_worker *next) { struct fuse_worker *prev = next->prev; w->next = next; w->prev = prev; prev->next = w; next->prev = w; } static void list_del_worker(struct fuse_worker *w) { struct fuse_worker *prev = w->prev; struct fuse_worker *next = w->next; prev->next = next; next->prev = prev; } static int fuse_loop_start_thread(struct fuse_mt *mt); static void *fuse_do_work(void *data) { struct fuse_worker *w = (struct fuse_worker *) data; struct fuse_mt *mt = w->mt; struct fuse_session *se = mt->se; fuse_set_thread_name("fuse_worker"); while (!fuse_session_exited(se)) { int isforget = 0; int res; pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); res = fuse_session_receive_buf_internal(se, &w->fbuf, w->ch); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); if (res == -EINTR) continue; if (res <= 0) { if (res < 0) { fuse_session_exit(se); mt->error = res; } break; } pthread_mutex_lock(&se->mt_lock); if (fuse_session_exited(se)) { pthread_mutex_unlock(&se->mt_lock); return NULL; } /* * This disgusting hack is needed so that zillions of threads * are not created on a burst of FORGET messages */ if (!(w->fbuf.flags & FUSE_BUF_IS_FD)) { struct fuse_in_header *in = w->fbuf.mem; if (in->opcode == FUSE_FORGET || in->opcode == FUSE_BATCH_FORGET) isforget = 1; } if (!isforget) mt->numavail--; if (mt->numavail == 0 && mt->numworker < mt->max_threads && likely(se->got_init)) fuse_loop_start_thread(mt); pthread_mutex_unlock(&se->mt_lock); fuse_session_process_buf_internal(se, &w->fbuf, w->ch); pthread_mutex_lock(&se->mt_lock); if (!isforget) mt->numavail++; /* creating and destroying threads is rather expensive - and there is * not much gain from destroying existing threads. It is therefore * discouraged to set max_idle to anything else than -1. If there * is indeed a good reason to destruct threads it should be done * delayed, a moving average might be useful for that. */ if (mt->max_idle != -1 && mt->numavail > mt->max_idle && mt->numworker > 1) { if (fuse_session_exited(se)) { pthread_mutex_unlock(&se->mt_lock); return NULL; } list_del_worker(w); mt->numavail--; mt->numworker--; pthread_mutex_unlock(&se->mt_lock); pthread_detach(w->thread_id); fuse_buf_free(&w->fbuf); fuse_chan_put(w->ch); free(w); return NULL; } pthread_mutex_unlock(&se->mt_lock); } sem_post(&se->mt_finish); return NULL; } int fuse_start_thread(pthread_t *thread_id, void *(*func)(void *), void *arg) { sigset_t oldset; sigset_t newset; int res; pthread_attr_t attr; char *stack_size; /* Override default stack size * XXX: This should ideally be a parameter option. It is rather * well hidden here. */ pthread_attr_init(&attr); stack_size = getenv(ENVNAME_THREAD_STACK); if (stack_size) { long size; res = libfuse_strtol(stack_size, &size); if (res) fuse_log(FUSE_LOG_ERR, "fuse: invalid stack size: %s\n", stack_size); else if (pthread_attr_setstacksize(&attr, size)) fuse_log(FUSE_LOG_ERR, "fuse: could not set stack size: %ld\n", size); } /* Disallow signal reception in worker threads */ sigemptyset(&newset); sigaddset(&newset, SIGTERM); sigaddset(&newset, SIGINT); sigaddset(&newset, SIGHUP); sigaddset(&newset, SIGQUIT); pthread_sigmask(SIG_BLOCK, &newset, &oldset); res = pthread_create(thread_id, &attr, func, arg); pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_attr_destroy(&attr); if (res != 0) { fuse_log(FUSE_LOG_ERR, "fuse: error creating thread: %s\n", strerror(res)); return -1; } return 0; } static int fuse_clone_chan_fd_default(struct fuse_session *se) { int res; int clonefd; uint32_t masterfd; const char *devname = "/dev/fuse"; #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif clonefd = open(devname, O_RDWR | O_CLOEXEC); if (clonefd == -1) { fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname, strerror(errno)); return -1; } if (!O_CLOEXEC) { res = fcntl(clonefd, F_SETFD, FD_CLOEXEC); if (res == -1) { fuse_log(FUSE_LOG_ERR, "fuse: failed to set CLOEXEC: %s\n", strerror(errno)); close(clonefd); return -1; } } masterfd = se->fd; res = ioctl(clonefd, FUSE_DEV_IOC_CLONE, &masterfd); if (res == -1) { fuse_log(FUSE_LOG_ERR, "fuse: failed to clone device fd: %s\n", strerror(errno)); close(clonefd); return -1; } return clonefd; } static struct fuse_chan *fuse_clone_chan(struct fuse_mt *mt) { int clonefd; struct fuse_session *se = mt->se; struct fuse_chan *newch; if (se->io != NULL) { if (se->io->clone_fd != NULL) clonefd = se->io->clone_fd(se->fd); else return NULL; } else { clonefd = fuse_clone_chan_fd_default(se); } if (clonefd < 0) return NULL; newch = fuse_chan_new(clonefd); if (newch == NULL) close(clonefd); return newch; } static int fuse_loop_start_thread(struct fuse_mt *mt) { int res; struct fuse_worker *w = malloc(sizeof(struct fuse_worker)); if (!w) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate worker structure\n"); return -1; } memset(w, 0, sizeof(struct fuse_worker)); w->fbuf.mem = NULL; w->mt = mt; w->ch = NULL; if (mt->clone_fd) { w->ch = fuse_clone_chan(mt); if(!w->ch) { /* Don't attempt this again */ fuse_log(FUSE_LOG_ERR, "fuse: trying to continue " "without -o clone_fd.\n"); mt->clone_fd = 0; } } res = fuse_start_thread(&w->thread_id, fuse_do_work, w); if (res == -1) { fuse_chan_put(w->ch); free(w); return -1; } list_add_worker(w, &mt->main); mt->numavail ++; mt->numworker ++; return 0; } static void fuse_join_worker(struct fuse_mt *mt, struct fuse_worker *w) { pthread_join(w->thread_id, NULL); pthread_mutex_lock(&mt->se->mt_lock); list_del_worker(w); pthread_mutex_unlock(&mt->se->mt_lock); fuse_buf_free(&w->fbuf); fuse_chan_put(w->ch); free(w); } int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config); FUSE_SYMVER("fuse_session_loop_mt_312", "fuse_session_loop_mt@@FUSE_3.12") int fuse_session_loop_mt_312(struct fuse_session *se, struct fuse_loop_config *config) { int err; struct fuse_mt mt; struct fuse_worker *w; int created_config = 0; if (config) { err = fuse_loop_cfg_verify(config); if (err) return err; } else { /* The caller does not care about parameters - use the default */ config = fuse_loop_cfg_create(); if (!config) return -ENOMEM; created_config = 1; } memset(&mt, 0, sizeof(struct fuse_mt)); mt.se = se; mt.clone_fd = config->clone_fd; mt.error = 0; mt.numworker = 0; mt.numavail = 0; mt.max_idle = config->max_idle_threads; mt.max_threads = config->max_threads; mt.main.thread_id = pthread_self(); mt.main.prev = mt.main.next = &mt.main; pthread_mutex_lock(&se->mt_lock); err = fuse_loop_start_thread(&mt); pthread_mutex_unlock(&se->mt_lock); if (!err) { while (!fuse_session_exited(se)) sem_wait(&se->mt_finish); if (se->debug) fuse_log(FUSE_LOG_DEBUG, "fuse: session exited, terminating workers\n"); pthread_mutex_lock(&se->mt_lock); for (w = mt.main.next; w != &mt.main; w = w->next) pthread_cancel(w->thread_id); pthread_mutex_unlock(&se->mt_lock); while (mt.main.next != &mt.main) fuse_join_worker(&mt, mt.main.next); err = mt.error; if (se->uring.pool) fuse_uring_stop(se); } if(se->error != 0) err = se->error; if (created_config) { fuse_loop_cfg_destroy(config); config = NULL; } return err; } int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1); FUSE_SYMVER("fuse_session_loop_mt_32", "fuse_session_loop_mt@FUSE_3.2") int fuse_session_loop_mt_32(struct fuse_session *se, struct fuse_loop_config_v1 *config_v1) { int err; struct fuse_loop_config *config = NULL; if (config_v1 != NULL) { /* convert the given v1 config */ config = fuse_loop_cfg_create(); if (config == NULL) return ENOMEM; fuse_loop_cfg_convert(config, config_v1); } err = fuse_session_loop_mt_312(se, config); fuse_loop_cfg_destroy(config); return err; } int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd); FUSE_SYMVER("fuse_session_loop_mt_31", "fuse_session_loop_mt@FUSE_3.0") int fuse_session_loop_mt_31(struct fuse_session *se, int clone_fd) { int err; struct fuse_loop_config *config = fuse_loop_cfg_create(); if (!config) return -ENOMEM; if (clone_fd > 0) fuse_loop_cfg_set_clone_fd(config, clone_fd); err = fuse_session_loop_mt_312(se, config); fuse_loop_cfg_destroy(config); return err; } struct fuse_loop_config *fuse_loop_cfg_create(void) { struct fuse_loop_config *config = calloc(1, sizeof(*config)); if (config == NULL) return NULL; config->version_id = FUSE_LOOP_MT_V2_IDENTIFIER; config->max_idle_threads = FUSE_LOOP_MT_DEF_IDLE_THREADS; config->max_threads = FUSE_LOOP_MT_DEF_MAX_THREADS; config->clone_fd = FUSE_LOOP_MT_DEF_CLONE_FD; return config; } void fuse_loop_cfg_destroy(struct fuse_loop_config *config) { free(config); } int fuse_loop_cfg_verify(struct fuse_loop_config *config) { if (config->version_id != FUSE_LOOP_MT_V2_IDENTIFIER) return -EINVAL; return 0; } void fuse_loop_cfg_convert(struct fuse_loop_config *config, struct fuse_loop_config_v1 *v1_conf) { fuse_loop_cfg_set_idle_threads(config, v1_conf->max_idle_threads); fuse_loop_cfg_set_clone_fd(config, v1_conf->clone_fd); } void fuse_loop_cfg_set_idle_threads(struct fuse_loop_config *config, unsigned int value) { if (value > FUSE_LOOP_MT_MAX_THREADS) { if (value != UINT_MAX) fuse_log(FUSE_LOG_ERR, "Ignoring invalid max threads value " "%u > max (%u).\n", value, FUSE_LOOP_MT_MAX_THREADS); return; } config->max_idle_threads = value; } void fuse_loop_cfg_set_max_threads(struct fuse_loop_config *config, unsigned int value) { config->max_threads = value; } void fuse_loop_cfg_set_clone_fd(struct fuse_loop_config *config, unsigned int value) { config->clone_fd = value; } fuse-3.18.3/lib/fuse_lowlevel.c0000644000175000017500000034127015250106036015310 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Implementation of (most of) the low-level FUSE API. The session loop functions are implemented in separate files. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #define _GNU_SOURCE #include "fuse_config.h" #include "fuse_i.h" #include "fuse_kernel.h" #include "fuse_opt.h" #include "fuse_misc.h" #include "mount_util.h" #include "util.h" #include "fuse_uring_i.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USDT_ENABLED #include "usdt.h" #endif #ifndef F_LINUX_SPECIFIC_BASE #define F_LINUX_SPECIFIC_BASE 1024 #endif #ifndef F_SETPIPE_SZ #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) #endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) #define OFFSET_MAX 0x7fffffffffffffffLL struct fuse_pollhandle { uint64_t kh; struct fuse_session *se; }; static size_t pagesize; static __attribute__((constructor)) void fuse_ll_init_pagesize(void) { pagesize = getpagesize(); } #ifdef USDT_ENABLED /* tracepoints */ static void trace_request_receive(int err) { USDT(libfuse, request_receive, err); } static void trace_request_process(unsigned int opcode, unsigned int unique) { USDT(libfuse, request_process, opcode, unique); } static void trace_request_reply(uint64_t unique, unsigned int len, int error, int reply_err) { USDT(libfuse, request_reply, unique, len, error, reply_err); } #else static void trace_request_receive(int err) { (void)err; } static void trace_request_process(unsigned int opcode, unsigned int unique) { (void)opcode; (void)unique; } static void trace_request_reply(uint64_t unique, unsigned int len, int error, int reply_err) { (void)unique; (void)len; (void)error; (void)reply_err; } #endif static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr) { attr->ino = stbuf->st_ino; attr->mode = stbuf->st_mode; attr->nlink = stbuf->st_nlink; attr->uid = stbuf->st_uid; attr->gid = stbuf->st_gid; attr->rdev = stbuf->st_rdev; attr->size = stbuf->st_size; attr->blksize = stbuf->st_blksize; attr->blocks = stbuf->st_blocks; attr->atime = stbuf->st_atime; attr->mtime = stbuf->st_mtime; attr->ctime = stbuf->st_ctime; attr->atimensec = ST_ATIM_NSEC(stbuf); attr->mtimensec = ST_MTIM_NSEC(stbuf); attr->ctimensec = ST_CTIM_NSEC(stbuf); } static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf) { stbuf->st_mode = attr->mode; stbuf->st_uid = attr->uid; stbuf->st_gid = attr->gid; stbuf->st_size = attr->size; stbuf->st_atime = attr->atime; stbuf->st_mtime = attr->mtime; stbuf->st_ctime = attr->ctime; ST_ATIM_NSEC_SET(stbuf, attr->atimensec); ST_MTIM_NSEC_SET(stbuf, attr->mtimensec); ST_CTIM_NSEC_SET(stbuf, attr->ctimensec); } static size_t iov_length(const struct iovec *iov, size_t count) { size_t seg; size_t ret = 0; for (seg = 0; seg < count; seg++) ret += iov[seg].iov_len; return ret; } void list_init_req(struct fuse_req *req) { req->next = req; req->prev = req; } static void list_del_req(struct fuse_req *req) { struct fuse_req *prev = req->prev; struct fuse_req *next = req->next; prev->next = next; next->prev = prev; } static void list_add_req(struct fuse_req *req, struct fuse_req *next) { struct fuse_req *prev = next->prev; req->next = next; req->prev = prev; prev->next = req; next->prev = req; } static void destroy_req(fuse_req_t req) { if (req->flags.is_uring) { fuse_log(FUSE_LOG_ERR, "Refusing to destruct uring req\n"); return; } assert(req->ch == NULL); pthread_mutex_destroy(&req->lock); free(req); } void fuse_free_req(fuse_req_t req) { int ctr; struct fuse_session *se = req->se; /* XXX: for now no support for interrupts with io-uring * It actually might work already, though. But then would add * a lock across ring queues. */ if (se->conn.no_interrupt || req->flags.is_uring) { ctr = --req->ref_cnt; fuse_chan_put(req->ch); req->ch = NULL; } else { pthread_mutex_lock(&se->lock); req->u.ni.func = NULL; req->u.ni.data = NULL; list_del_req(req); ctr = --req->ref_cnt; fuse_chan_put(req->ch); req->ch = NULL; pthread_mutex_unlock(&se->lock); } if (!ctr) destroy_req(req); } static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se) { struct fuse_req *req; req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req)); if (req == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n"); } else { req->se = se; req->ref_cnt = 1; list_init_req(req); pthread_mutex_init(&req->lock, NULL); } return req; } /* * Send data to fuse-kernel using an fd of the fuse device. */ static int fuse_write_msg_dev(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int count) { ssize_t res; int err; if (se->io != NULL) /* se->io->writev is never NULL if se->io is not NULL as * specified by fuse_session_custom_io() */ res = se->io->writev(ch ? ch->fd : se->fd, iov, count, se->userdata); else res = writev(ch ? ch->fd : se->fd, iov, count); if (res == -1) { /* ENOENT means the operation was interrupted */ err = errno; if (!fuse_session_exited(se) && err != ENOENT) perror("fuse: writing device"); return -err; } return 0; } static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int count, fuse_req_t req) { struct fuse_out_header *out = iov[0].iov_base; int err; bool is_uring = req && req->flags.is_uring ? true : false; if (!is_uring) assert(se != NULL); out->len = iov_length(iov, count); if (se->debug) { if (out->unique == 0) { fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error, out->len); } else if (out->error) { fuse_log(FUSE_LOG_DEBUG, " unique: %llu, error: %i (%s), outsize: %i\n", (unsigned long long) out->unique, out->error, strerror(-out->error), out->len); } else { fuse_log(FUSE_LOG_DEBUG, " unique: %llu, success, outsize: %i\n", (unsigned long long) out->unique, out->len); } } if (is_uring) err = fuse_send_msg_uring(req, iov, count); else err = fuse_write_msg_dev(se, ch, iov, count); trace_request_reply(out->unique, out->len, out->error, err); return err; } int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov, int count) { struct fuse_out_header out; #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32 const char *str = strerrordesc_np(error * -1); if ((str == NULL && error != 0) || error > 0) { #else if (error <= -1000 || error > 0) { #endif fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error); error = -ERANGE; } out.unique = req->unique; out.error = error; iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); return fuse_send_msg(req->se, req->ch, iov, count, req); } static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov, int count) { int res; res = fuse_send_reply_iov_nofree(req, error, iov, count); fuse_free_req(req); return res; } static int send_reply(fuse_req_t req, int error, const void *arg, size_t argsize) { if (req->flags.is_uring) return send_reply_uring(req, error, arg, argsize); struct iovec iov[2]; int count = 1; if (argsize) { iov[1].iov_base = (void *) arg; iov[1].iov_len = argsize; count++; } return send_reply_iov(req, error, iov, count); } int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count) { int res; struct iovec *padded_iov; padded_iov = malloc((count + 1) * sizeof(struct iovec)); if (padded_iov == NULL) return fuse_reply_err(req, ENOMEM); memcpy(padded_iov + 1, iov, count * sizeof(struct iovec)); count++; res = send_reply_iov(req, 0, padded_iov, count); free(padded_iov); return res; } /* `buf` is allowed to be empty so that the proper size may be allocated by the caller */ 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)req; size_t namelen; size_t entlen; size_t entlen_padded; struct fuse_dirent *dirent; namelen = strlen(name); entlen = FUSE_NAME_OFFSET + namelen; entlen_padded = FUSE_DIRENT_ALIGN(entlen); if ((buf == NULL) || (entlen_padded > bufsize)) return entlen_padded; dirent = (struct fuse_dirent*) buf; dirent->ino = stbuf->st_ino; dirent->off = off; dirent->namelen = namelen; dirent->type = (stbuf->st_mode & S_IFMT) >> 12; memcpy(dirent->name, name, namelen); memset(dirent->name + namelen, 0, entlen_padded - entlen); return entlen_padded; } static void convert_statfs(const struct statvfs *stbuf, struct fuse_kstatfs *kstatfs) { kstatfs->bsize = stbuf->f_bsize; kstatfs->frsize = stbuf->f_frsize; kstatfs->blocks = stbuf->f_blocks; kstatfs->bfree = stbuf->f_bfree; kstatfs->bavail = stbuf->f_bavail; kstatfs->files = stbuf->f_files; kstatfs->ffree = stbuf->f_ffree; kstatfs->namelen = stbuf->f_namemax; } static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize) { return send_reply(req, 0, arg, argsize); } int fuse_reply_err(fuse_req_t req, int err) { return send_reply(req, -err, NULL, 0); } void fuse_reply_none(fuse_req_t req) { if (req->flags.is_uring) { send_reply_uring(req, 0, NULL, 0); return; } fuse_free_req(req); } static unsigned long calc_timeout_sec(double t) { if (t > (double) ULONG_MAX) return ULONG_MAX; else if (t < 0.0) return 0; else return (unsigned long) t; } static unsigned int calc_timeout_nsec(double t) { double f = t - (double) calc_timeout_sec(t); if (f < 0.0) return 0; else if (f >= 0.999999999) return 999999999; else return (unsigned int) (f * 1.0e9); } static void fill_entry(struct fuse_entry_out *arg, const struct fuse_entry_param *e) { arg->nodeid = e->ino; arg->generation = e->generation; arg->entry_valid = calc_timeout_sec(e->entry_timeout); arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout); arg->attr_valid = calc_timeout_sec(e->attr_timeout); arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout); convert_stat(&e->attr, &arg->attr); } /* `buf` is allowed to be empty so that the proper size may be allocated by the caller */ 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) { (void)req; size_t namelen; size_t entlen; size_t entlen_padded; namelen = strlen(name); entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen; entlen_padded = FUSE_DIRENT_ALIGN(entlen); if ((buf == NULL) || (entlen_padded > bufsize)) return entlen_padded; struct fuse_direntplus *dp = (struct fuse_direntplus *) buf; memset(&dp->entry_out, 0, sizeof(dp->entry_out)); fill_entry(&dp->entry_out, e); struct fuse_dirent *dirent = &dp->dirent; dirent->ino = e->attr.st_ino; dirent->off = off; dirent->namelen = namelen; dirent->type = (e->attr.st_mode & S_IFMT) >> 12; memcpy(dirent->name, name, namelen); memset(dirent->name + namelen, 0, entlen_padded - entlen); return entlen_padded; } static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f) { arg->fh = f->fh; if (f->backing_id > 0) { arg->backing_id = f->backing_id; arg->open_flags |= FOPEN_PASSTHROUGH; } if (f->direct_io) arg->open_flags |= FOPEN_DIRECT_IO; if (f->keep_cache) arg->open_flags |= FOPEN_KEEP_CACHE; if (f->cache_readdir) arg->open_flags |= FOPEN_CACHE_DIR; if (f->nonseekable) arg->open_flags |= FOPEN_NONSEEKABLE; if (f->noflush) arg->open_flags |= FOPEN_NOFLUSH; if (f->parallel_direct_writes) arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES; } int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e) { struct fuse_entry_out arg; size_t size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg); /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant negative entry */ if (!e->ino && req->se->conn.proto_minor < 4) return fuse_reply_err(req, ENOENT); memset(&arg, 0, sizeof(arg)); fill_entry(&arg, e); return send_reply_ok(req, &arg, size); } int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *f) { alignas(uint64_t) char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)]; size_t entrysize = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out); struct fuse_entry_out *earg = (struct fuse_entry_out *) buf; struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize); memset(buf, 0, sizeof(buf)); fill_entry(earg, e); fill_open(oarg, f); return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out)); } int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout) { struct fuse_attr_out arg; size_t size = req->se->conn.proto_minor < 9 ? FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg); memset(&arg, 0, sizeof(arg)); arg.attr_valid = calc_timeout_sec(attr_timeout); arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); convert_stat(attr, &arg.attr); return send_reply_ok(req, &arg, size); } int fuse_reply_readlink(fuse_req_t req, const char *linkname) { return send_reply_ok(req, linkname, strlen(linkname)); } int fuse_passthrough_open(fuse_req_t req, int fd) { struct fuse_backing_map map = { .fd = fd }; int ret; ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map); if (ret <= 0) { fuse_log(FUSE_LOG_ERR, "fuse: passthrough_open: %s\n", strerror(errno)); return 0; } return ret; } int fuse_passthrough_close(fuse_req_t req, int backing_id) { int ret; ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id); if (ret < 0) fuse_log(FUSE_LOG_ERR, "fuse: passthrough_close: %s\n", strerror(errno)); return ret; } int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f) { struct fuse_open_out arg; memset(&arg, 0, sizeof(arg)); fill_open(&arg, f); return send_reply_ok(req, &arg, sizeof(arg)); } static int do_fuse_reply_write(fuse_req_t req, size_t count) { struct fuse_write_out arg; memset(&arg, 0, sizeof(arg)); arg.size = count; return send_reply_ok(req, &arg, sizeof(arg)); } static int do_fuse_reply_copy(fuse_req_t req, size_t count) { struct fuse_copy_file_range_out arg; memset(&arg, 0, sizeof(arg)); arg.bytes_copied = count; return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_write(fuse_req_t req, size_t count) { /* * This function is also used by FUSE_COPY_FILE_RANGE and its 64-bit * variant. */ if (req->flags.is_copy_file_range_64) return do_fuse_reply_copy(req, count); else return do_fuse_reply_write(req, count); } int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size) { return send_reply_ok(req, buf, size); } static int fuse_send_data_iov_fallback(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, size_t len, fuse_req_t req) { struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); void *mbuf; int res; /* Optimize common case */ if (buf->count == 1 && buf->idx == 0 && buf->off == 0 && !(buf->buf[0].flags & FUSE_BUF_IS_FD)) { /* FIXME: also avoid memory copy if there are multiple buffers but none of them contain an fd */ iov[iov_count].iov_base = buf->buf[0].mem; iov[iov_count].iov_len = len; iov_count++; return fuse_send_msg(se, ch, iov, iov_count, req); } res = posix_memalign(&mbuf, pagesize, len); if (res != 0) return res; mem_buf.buf[0].mem = mbuf; res = fuse_buf_copy(&mem_buf, buf, 0); if (res < 0) { free(mbuf); return -res; } len = res; iov[iov_count].iov_base = mbuf; iov[iov_count].iov_len = len; iov_count++; res = fuse_send_msg(se, ch, iov, iov_count, req); free(mbuf); return res; } struct fuse_ll_pipe { size_t size; int can_grow; int pipe[2]; }; static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp) { close(llp->pipe[0]); close(llp->pipe[1]); free(llp); } #ifdef HAVE_SPLICE #if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC) static int fuse_pipe(int fds[2]) { int rv = pipe(fds); if (rv == -1) return rv; if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 || fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 || fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) { close(fds[0]); close(fds[1]); rv = -1; } return rv; } #else static int fuse_pipe(int fds[2]) { return pipe2(fds, O_CLOEXEC | O_NONBLOCK); } #endif static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se) { struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key); if (llp == NULL) { int res; llp = malloc(sizeof(struct fuse_ll_pipe)); if (llp == NULL) return NULL; res = fuse_pipe(llp->pipe); if (res == -1) { free(llp); return NULL; } /* *the default size is 16 pages on linux */ llp->size = pagesize * 16; llp->can_grow = 1; pthread_setspecific(se->pipe_key, llp); } return llp; } #endif static void fuse_ll_clear_pipe(struct fuse_session *se) { struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key); if (llp) { pthread_setspecific(se->pipe_key, NULL); fuse_ll_pipe_free(llp); } } #if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE) static int read_back(int fd, char *buf, size_t len) { int res; res = read(fd, buf, len); if (res == -1) { fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno)); return -EIO; } if (res != len) { fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zd\n", res, len); return -EIO; } return 0; } static int grow_pipe_to_max(int pipefd) { int res; long max; long maxfd; char buf[32]; maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY | O_CLOEXEC); if (maxfd < 0) return -errno; res = read(maxfd, buf, sizeof(buf) - 1); if (res < 0) { int saved_errno; saved_errno = errno; close(maxfd); return -saved_errno; } close(maxfd); buf[res] = '\0'; res = libfuse_strtol(buf, &max); if (res) return res; res = fcntl(pipefd, F_SETPIPE_SZ, max); if (res < 0) return -errno; return max; } static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *buf, unsigned int flags, fuse_req_t req) { int res; size_t len = fuse_buf_size(buf); struct fuse_out_header *out = iov[0].iov_base; struct fuse_ll_pipe *llp; int splice_flags; size_t pipesize; size_t total_buf_size; size_t idx; size_t headerlen; struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len); if (se->broken_splice_nonblock) goto fallback; if (flags & FUSE_BUF_NO_SPLICE) goto fallback; total_buf_size = 0; for (idx = buf->idx; idx < buf->count; idx++) { total_buf_size += buf->buf[idx].size; if (idx == buf->idx) total_buf_size -= buf->off; } if (total_buf_size < 2 * pagesize) goto fallback; if (se->conn.proto_minor < 14 || !(se->conn.want_ext & FUSE_CAP_SPLICE_WRITE)) goto fallback; llp = fuse_ll_get_pipe(se); if (llp == NULL) goto fallback; headerlen = iov_length(iov, iov_count); out->len = headerlen + len; /* * Heuristic for the required pipe size, does not work if the * source contains less than page size fragments */ pipesize = pagesize * (iov_count + buf->count + 1) + out->len; if (llp->size < pipesize) { if (llp->can_grow) { res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize); if (res == -1) { res = grow_pipe_to_max(llp->pipe[0]); if (res > 0) llp->size = res; llp->can_grow = 0; goto fallback; } llp->size = res; } if (llp->size < pipesize) goto fallback; } res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK); if (res == -1) goto fallback; if (res != headerlen) { res = -EIO; fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res, headerlen); goto clear_pipe; } pipe_buf.buf[0].flags = FUSE_BUF_IS_FD; pipe_buf.buf[0].fd = llp->pipe[1]; res = fuse_buf_copy(&pipe_buf, buf, FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK); if (res < 0) { if (res == -EAGAIN || res == -EINVAL) { /* * Should only get EAGAIN on kernels with * broken SPLICE_F_NONBLOCK support (<= * 2.6.35) where this error or a short read is * returned even if the pipe itself is not * full * * EINVAL might mean that splice can't handle * this combination of input and output. */ if (res == -EAGAIN) se->broken_splice_nonblock = 1; pthread_setspecific(se->pipe_key, NULL); fuse_ll_pipe_free(llp); goto fallback; } res = -res; goto clear_pipe; } if (res != 0 && res < len) { struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len); void *mbuf; size_t now_len = res; /* * For regular files a short count is either * 1) due to EOF, or * 2) because of broken SPLICE_F_NONBLOCK (see above) * * For other inputs it's possible that we overflowed * the pipe because of small buffer fragments. */ res = posix_memalign(&mbuf, pagesize, len); if (res != 0) goto clear_pipe; mem_buf.buf[0].mem = mbuf; mem_buf.off = now_len; res = fuse_buf_copy(&mem_buf, buf, 0); if (res > 0) { char *tmpbuf; size_t extra_len = res; /* * Trickiest case: got more data. Need to get * back the data from the pipe and then fall * back to regular write. */ tmpbuf = malloc(headerlen); if (tmpbuf == NULL) { free(mbuf); res = ENOMEM; goto clear_pipe; } res = read_back(llp->pipe[0], tmpbuf, headerlen); free(tmpbuf); if (res != 0) { free(mbuf); goto clear_pipe; } res = read_back(llp->pipe[0], mbuf, now_len); if (res != 0) { free(mbuf); goto clear_pipe; } len = now_len + extra_len; iov[iov_count].iov_base = mbuf; iov[iov_count].iov_len = len; iov_count++; res = fuse_send_msg(se, ch, iov, iov_count, req); free(mbuf); return res; } free(mbuf); res = now_len; } len = res; out->len = headerlen + len; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, " unique: %llu, success, outsize: %i (splice)\n", (unsigned long long) out->unique, out->len); } splice_flags = 0; if ((flags & FUSE_BUF_SPLICE_MOVE) && (se->conn.want_ext & FUSE_CAP_SPLICE_MOVE)) splice_flags |= SPLICE_F_MOVE; if (se->io != NULL && se->io->splice_send != NULL) { res = se->io->splice_send(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL, out->len, splice_flags, se->userdata); } else { res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL, out->len, splice_flags); } if (res == -1) { res = -errno; perror("fuse: splice from pipe"); goto clear_pipe; } if (res != out->len) { res = -EIO; fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n", res, out->len); goto clear_pipe; } return 0; clear_pipe: fuse_ll_clear_pipe(se); return res; fallback: return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len, req); } #else static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, struct iovec *iov, int iov_count, struct fuse_bufvec *req_data, unsigned int flags, fuse_req_t req) { size_t len = fuse_buf_size(req_data); (void) flags; return fuse_send_data_iov_fallback(se, ch, iov, iov_count, req_data, len, req); } #endif int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags) { struct iovec iov[2]; struct fuse_out_header out; int res; if (req->flags.is_uring) return fuse_reply_data_uring(req, bufv, flags); iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); out.unique = req->unique; out.error = 0; res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags, req); if (res <= 0) { fuse_free_req(req); return res; } else { return fuse_reply_err(req, res); } } int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf) { struct fuse_statfs_out arg; size_t size = req->se->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg); memset(&arg, 0, sizeof(arg)); convert_statfs(stbuf, &arg.st); return send_reply_ok(req, &arg, size); } int fuse_reply_xattr(fuse_req_t req, size_t count) { struct fuse_getxattr_out arg; memset(&arg, 0, sizeof(arg)); arg.size = count; return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_lock(fuse_req_t req, const struct flock *lock) { struct fuse_lk_out arg; memset(&arg, 0, sizeof(arg)); arg.lk.type = lock->l_type; if (lock->l_type != F_UNLCK) { arg.lk.start = lock->l_start; if (lock->l_len == 0) arg.lk.end = OFFSET_MAX; else arg.lk.end = lock->l_start + lock->l_len - 1; } arg.lk.pid = lock->l_pid; return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_bmap(fuse_req_t req, uint64_t idx) { struct fuse_bmap_out arg; memset(&arg, 0, sizeof(arg)); arg.block = idx; return send_reply_ok(req, &arg, sizeof(arg)); } static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov, size_t count) { struct fuse_ioctl_iovec *fiov; size_t i; fiov = malloc(sizeof(fiov[0]) * count); if (!fiov) return NULL; for (i = 0; i < count; i++) { fiov[i].base = (uintptr_t) iov[i].iov_base; fiov[i].len = iov[i].iov_len; } return fiov; } int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov, size_t in_count, const struct iovec *out_iov, size_t out_count) { struct fuse_ioctl_out arg; struct fuse_ioctl_iovec *in_fiov = NULL; struct fuse_ioctl_iovec *out_fiov = NULL; struct iovec iov[4]; size_t count = 1; int res; memset(&arg, 0, sizeof(arg)); arg.flags |= FUSE_IOCTL_RETRY; arg.in_iovs = in_count; arg.out_iovs = out_count; iov[count].iov_base = &arg; iov[count].iov_len = sizeof(arg); count++; if (req->se->conn.proto_minor < 16) { if (in_count) { iov[count].iov_base = (void *)in_iov; iov[count].iov_len = sizeof(in_iov[0]) * in_count; count++; } if (out_count) { iov[count].iov_base = (void *)out_iov; iov[count].iov_len = sizeof(out_iov[0]) * out_count; count++; } } else { /* Can't handle non-compat 64bit ioctls on 32bit */ if (sizeof(void *) == 4 && req->flags.ioctl_64bit) { res = fuse_reply_err(req, EINVAL); goto out; } if (in_count) { in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count); if (!in_fiov) goto enomem; iov[count].iov_base = (void *)in_fiov; iov[count].iov_len = sizeof(in_fiov[0]) * in_count; count++; } if (out_count) { out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count); if (!out_fiov) goto enomem; iov[count].iov_base = (void *)out_fiov; iov[count].iov_len = sizeof(out_fiov[0]) * out_count; count++; } } res = send_reply_iov(req, 0, iov, count); out: free(in_fiov); free(out_fiov); return res; enomem: res = fuse_reply_err(req, ENOMEM); goto out; } int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size) { struct fuse_ioctl_out arg; struct iovec iov[3]; size_t count = 1; memset(&arg, 0, sizeof(arg)); arg.result = result; iov[count].iov_base = &arg; iov[count].iov_len = sizeof(arg); count++; if (size) { iov[count].iov_base = (char *) buf; iov[count].iov_len = size; count++; } return send_reply_iov(req, 0, iov, count); } int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count) { struct iovec *padded_iov; struct fuse_ioctl_out arg; int res; padded_iov = malloc((count + 2) * sizeof(struct iovec)); if (padded_iov == NULL) return fuse_reply_err(req, ENOMEM); memset(&arg, 0, sizeof(arg)); arg.result = result; padded_iov[1].iov_base = &arg; padded_iov[1].iov_len = sizeof(arg); memcpy(&padded_iov[2], iov, count * sizeof(struct iovec)); res = send_reply_iov(req, 0, padded_iov, count + 2); free(padded_iov); return res; } int fuse_reply_poll(fuse_req_t req, unsigned revents) { struct fuse_poll_out arg; memset(&arg, 0, sizeof(arg)); arg.revents = revents; return send_reply_ok(req, &arg, sizeof(arg)); } int fuse_reply_lseek(fuse_req_t req, off_t off) { struct fuse_lseek_out arg; memset(&arg, 0, sizeof(arg)); arg.offset = off; return send_reply_ok(req, &arg, sizeof(arg)); } #ifdef HAVE_STATX int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout) { struct fuse_statx_out arg; memset(&arg, 0, sizeof(arg)); arg.flags = flags; arg.attr_valid = calc_timeout_sec(attr_timeout); arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout); memcpy(&arg.stat, statx, sizeof(arg.stat)); return send_reply_ok(req, &arg, sizeof(arg)); } #else int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout) { (void)req; (void)flags; (void)statx; (void)attr_timeout; return -ENOSYS; } #endif static void _do_lookup(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)op_in; char *name = (char *)in_payload; if (req->se->op.lookup) req->se->op.lookup(req, nodeid, name); else fuse_reply_err(req, ENOSYS); } static void do_lookup(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_lookup(req, nodeid, NULL, inarg); } static void _do_forget(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_forget_in *arg = (struct fuse_forget_in *)op_in; if (req->se->op.forget) req->se->op.forget(req, nodeid, arg->nlookup); else fuse_reply_none(req); } static void do_forget(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_forget(req, nodeid, inarg, NULL); } static void _do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)nodeid; unsigned int i; const struct fuse_batch_forget_in *arg = op_in; const struct fuse_forget_one *forgets = in_payload; if (req->se->op.forget_multi) { req->se->op.forget_multi(req, arg->count, (struct fuse_forget_data *)in_payload); } else if (req->se->op.forget) { for (i = 0; i < arg->count; i++) { const struct fuse_forget_one *forget = &forgets[i]; struct fuse_req *dummy_req; dummy_req = fuse_ll_alloc_req(req->se); if (dummy_req == NULL) break; dummy_req->unique = req->unique; dummy_req->ctx = req->ctx; dummy_req->ch = NULL; req->se->op.forget(dummy_req, forget->nodeid, forget->nlookup); } fuse_reply_none(req); } else { fuse_reply_none(req); } } static void do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { struct fuse_batch_forget_in *arg = (void *)inarg; struct fuse_forget_one *param = (void *)PARAM(arg); _do_batch_forget(req, nodeid, inarg, param); } static void _do_getattr(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_getattr_in *arg = (struct fuse_getattr_in *)op_in; (void)in_payload; struct fuse_file_info *fip = NULL; struct fuse_file_info fi; if (req->se->conn.proto_minor >= 9) { if (arg->getattr_flags & FUSE_GETATTR_FH) { memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fip = &fi; } } if (req->se->op.getattr) req->se->op.getattr(req, nodeid, fip); else fuse_reply_err(req, ENOSYS); } static void do_getattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_getattr(req, nodeid, inarg, NULL); } static void _do_setattr(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_setattr_in *arg = op_in; uint32_t valid = arg->valid; if (req->se->op.setattr) { struct fuse_file_info *fi = NULL; struct fuse_file_info fi_store; struct stat stbuf; memset(&stbuf, 0, sizeof(stbuf)); convert_attr(arg, &stbuf); if (arg->valid & FATTR_FH) { valid &= ~FATTR_FH; memset(&fi_store, 0, sizeof(fi_store)); fi = &fi_store; fi->fh = arg->fh; } valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME | FUSE_SET_ATTR_KILL_SUID | FUSE_SET_ATTR_KILL_SGID | FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW | FUSE_SET_ATTR_CTIME; req->se->op.setattr(req, nodeid, &stbuf, valid, fi); } else fuse_reply_err(req, ENOSYS); } static void do_setattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_setattr(req, nodeid, inarg, NULL); } static void _do_access(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_access_in *arg = op_in; if (req->se->op.access) req->se->op.access(req, nodeid, arg->mask); else fuse_reply_err(req, ENOSYS); } static void do_access(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_access(req, nodeid, inarg, NULL); } static void _do_readlink(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)op_in; (void)in_payload; if (req->se->op.readlink) req->se->op.readlink(req, nodeid); else fuse_reply_err(req, ENOSYS); } static void do_readlink(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_readlink(req, nodeid, inarg, NULL); } static void _do_mknod(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const struct fuse_mknod_in *arg = (struct fuse_mknod_in *)op_in; const char *name = in_payload; if (req->se->conn.proto_minor >= 12) req->ctx.umask = arg->umask; if (req->se->op.mknod) req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev); else fuse_reply_err(req, ENOSYS); } static void do_mknod(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg; char *name = PARAM(arg); if (req->se->conn.proto_minor < 12) name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE; _do_mknod(req, nodeid, inarg, name); } static void _do_mkdir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const char *name = in_payload; const struct fuse_mkdir_in *arg = op_in; if (req->se->conn.proto_minor >= 12) req->ctx.umask = arg->umask; if (req->se->op.mkdir) req->se->op.mkdir(req, nodeid, name, arg->mode); else fuse_reply_err(req, ENOSYS); } static void do_mkdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { const struct fuse_mkdir_in *arg = inarg; const char *name = PARAM(arg); _do_mkdir(req, nodeid, inarg, name); } static void _do_unlink(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)op_in; const char *name = in_payload; if (req->se->op.unlink) req->se->op.unlink(req, nodeid, name); else fuse_reply_err(req, ENOSYS); } static void do_unlink(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_unlink(req, nodeid, NULL, inarg); } static void _do_rmdir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)op_in; const char *name = in_payload; if (req->se->op.rmdir) req->se->op.rmdir(req, nodeid, name); else fuse_reply_err(req, ENOSYS); } static void do_rmdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_rmdir(req, nodeid, NULL, inarg); } static void _do_symlink(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)op_in; const char *name = (char *)in_payload; const char *linkname = name + strlen(name) + 1; if (req->se->op.symlink) req->se->op.symlink(req, linkname, nodeid, name); else fuse_reply_err(req, ENOSYS); } static void do_symlink(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_symlink(req, nodeid, NULL, inarg); } static void _do_rename(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const struct fuse_rename_in *arg = (struct fuse_rename_in *)op_in; const char *oldname = in_payload; const char *newname = oldname + strlen(oldname) + 1; if (req->se->op.rename) req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0); else fuse_reply_err(req, ENOSYS); } static void do_rename(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { const struct fuse_rename_in *arg = inarg; const void *payload = PARAM(arg); _do_rename(req, nodeid, arg, payload); } static void _do_rename2(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const struct fuse_rename2_in *arg = op_in; const char *oldname = in_payload; const char *newname = oldname + strlen(oldname) + 1; if (req->se->op.rename) req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, arg->flags); else fuse_reply_err(req, ENOSYS); } static void do_rename2(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { const struct fuse_rename2_in *arg = inarg; const void *payload = PARAM(arg); _do_rename2(req, nodeid, arg, payload); } static void _do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_create_in *arg = op_in; if (req->se->op.tmpfile) { struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; if (req->se->conn.proto_minor >= 12) req->ctx.umask = arg->umask; req->se->op.tmpfile(req, nodeid, arg->mode, &fi); } else fuse_reply_err(req, ENOSYS); } static void do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { struct fuse_create_in *arg = (struct fuse_create_in *) inarg; _do_tmpfile(req, nodeid, arg, NULL); } static void _do_link(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_link_in *arg = (struct fuse_link_in *)op_in; if (req->se->op.link) req->se->op.link(req, arg->oldnodeid, nodeid, in_payload); else fuse_reply_err(req, ENOSYS); } static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { const struct fuse_link_in *arg = inarg; const void *name = PARAM(arg); _do_link(req, nodeid, inarg, name); } static void _do_create(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const struct fuse_create_in *arg = op_in; const char *name = in_payload; if (req->se->op.create) { struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; if (req->se->conn.proto_minor >= 12) req->ctx.umask = arg->umask; if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2) fi.kill_suidgid = (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0; req->se->op.create(req, nodeid, name, arg->mode, &fi); } else { fuse_reply_err(req, ENOSYS); } } static void do_create(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { const struct fuse_create_in *arg = (struct fuse_create_in *)inarg; void *payload = PARAM(arg); if (req->se->conn.proto_minor < 12) payload = (char *)inarg + sizeof(struct fuse_open_in); _do_create(req, nodeid, arg, payload); } static void _do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_open_in *arg = (struct fuse_open_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2) fi.kill_suidgid = (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0; if (req->se->op.open) req->se->op.open(req, nodeid, &fi); else if (req->se->conn.want_ext & FUSE_CAP_NO_OPEN_SUPPORT) fuse_reply_err(req, ENOSYS); else fuse_reply_open(req, &fi); } static void do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_open(req, nodeid, inarg, NULL); } static void _do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_read_in *arg = (struct fuse_read_in *)op_in; if (req->se->op.read) { struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->conn.proto_minor >= 9) { fi.lock_owner = arg->lock_owner; fi.flags = arg->flags; } req->se->op.read(req, nodeid, arg->size, arg->offset, &fi); } else fuse_reply_err(req, ENOSYS); } static void do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_read(req, nodeid, inarg, NULL); } static void _do_write(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_write_in *arg = (struct fuse_write_in *)op_in; const char *buf = in_payload; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0; if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2) fi.kill_suidgid = (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0; if (req->se->conn.proto_minor >= 9) { fi.lock_owner = arg->lock_owner; fi.flags = arg->flags; } if (req->se->op.write) req->se->op.write(req, nodeid, buf, arg->size, arg->offset, &fi); else fuse_reply_err(req, ENOSYS); } static void do_write(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { struct fuse_write_in *arg = (struct fuse_write_in *)inarg; const void *payload; if (req->se->conn.proto_minor < 9) payload = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE; else payload = PARAM(arg); _do_write(req, nodeid, arg, payload); } static void _do_write_buf(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, struct fuse_bufvec *bufv) { struct fuse_session *se = req->se; struct fuse_write_in *arg = (struct fuse_write_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.writepage = arg->write_flags & FUSE_WRITE_CACHE; if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2) fi.kill_suidgid = (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0; if (se->conn.proto_minor >= 9) { fi.lock_owner = arg->lock_owner; fi.flags = arg->flags; } se->op.write_buf(req, nodeid, bufv, arg->offset, &fi); } static void do_write_buf(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg, const struct fuse_buf *ibuf) { struct fuse_session *se = req->se; struct fuse_bufvec bufv = { .buf[0] = *ibuf, .count = 1, }; struct fuse_write_in *arg = (struct fuse_write_in *)inarg; if (se->conn.proto_minor < 9) { bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE; bufv.buf[0].size -= sizeof(struct fuse_in_header) + FUSE_COMPAT_WRITE_IN_SIZE; assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD)); } else { if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) bufv.buf[0].mem = PARAM(arg); bufv.buf[0].size -= sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in); } if (bufv.buf[0].size < arg->size) { fuse_log(FUSE_LOG_ERR, "fuse: %s: buffer size too small\n", __func__); fuse_reply_err(req, EIO); goto out; } bufv.buf[0].size = arg->size; _do_write_buf(req, nodeid, inarg, &bufv); out: /* Need to reset the pipe if ->write_buf() didn't consume all data */ if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) fuse_ll_clear_pipe(se); } static void _do_flush(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_flush_in *arg = (struct fuse_flush_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.flush = 1; if (req->se->conn.proto_minor >= 7) fi.lock_owner = arg->lock_owner; if (req->se->op.flush) req->se->op.flush(req, nodeid, &fi); else fuse_reply_err(req, ENOSYS); } static void do_flush(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_flush(req, nodeid, inarg, NULL); } static void _do_release(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_release_in *arg = op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; fi.fh = arg->fh; if (req->se->conn.proto_minor >= 8) { fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; fi.lock_owner = arg->lock_owner; } if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { fi.flock_release = 1; fi.lock_owner = arg->lock_owner; } if (req->se->op.release) req->se->op.release(req, nodeid, &fi); else fuse_reply_err(req, 0); } static void do_release(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_release(req, nodeid, inarg, NULL); } static void _do_fsync(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_fsync_in *arg = op_in; struct fuse_file_info fi; int datasync = arg->fsync_flags & 1; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.fsync) req->se->op.fsync(req, nodeid, datasync, &fi); else fuse_reply_err(req, ENOSYS); } static void do_fsync(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_fsync(req, nodeid, inarg, NULL); } static void _do_opendir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_open_in *arg = op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; /* XXX: fuse_open_in::open_flags */ if (req->se->op.opendir) req->se->op.opendir(req, nodeid, &fi); else if (req->se->conn.want_ext & FUSE_CAP_NO_OPENDIR_SUPPORT) fuse_reply_err(req, ENOSYS); else fuse_reply_open(req, &fi); } static void do_opendir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_opendir(req, nodeid, inarg, NULL); } static void _do_readdir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_read_in *arg = (struct fuse_read_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.readdir) req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi); else fuse_reply_err(req, ENOSYS); } static void do_readdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_readdir(req, nodeid, inarg, NULL); } static void _do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_read_in *arg = (struct fuse_read_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.readdirplus) req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi); else fuse_reply_err(req, ENOSYS); } static void do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_readdirplus(req, nodeid, inarg, NULL); } static void _do_releasedir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_release_in *arg = (struct fuse_release_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.flags = arg->flags; fi.fh = arg->fh; if (req->se->op.releasedir) req->se->op.releasedir(req, nodeid, &fi); else fuse_reply_err(req, 0); } static void do_releasedir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_releasedir(req, nodeid, inarg, NULL); } static void _do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_fsync_in *arg = (struct fuse_fsync_in *)op_in; struct fuse_file_info fi; int datasync = arg->fsync_flags & 1; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.fsyncdir) req->se->op.fsyncdir(req, nodeid, datasync, &fi); else fuse_reply_err(req, ENOSYS); } static void do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_fsyncdir(req, nodeid, inarg, NULL); } static void _do_statfs(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void) nodeid; (void)op_in; (void)in_payload; if (req->se->op.statfs) req->se->op.statfs(req, nodeid); else { struct statvfs buf = { .f_namemax = 255, .f_bsize = 512, }; fuse_reply_statfs(req, &buf); } } static void do_statfs(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_statfs(req, nodeid, inarg, NULL); } static void _do_setxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)op_in; const char *name = in_payload; const char *value = name + strlen(name) + 1; /* XXX:The API should be extended to support extra_flags/setxattr_flags */ if (req->se->op.setxattr) req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags); else fuse_reply_err(req, ENOSYS); } static void do_setxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { struct fuse_session *se = req->se; unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT); const struct fuse_setxattr_in *arg = inarg; char *payload = xattr_ext ? PARAM(arg) : (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE; _do_setxattr(req, nodeid, arg, payload); } static void _do_getxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { const struct fuse_getxattr_in *arg = op_in; if (req->se->op.getxattr) req->se->op.getxattr(req, nodeid, in_payload, arg->size); else fuse_reply_err(req, ENOSYS); } static void do_getxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { const struct fuse_getxattr_in *arg = inarg; const void *payload = PARAM(arg); _do_getxattr(req, nodeid, arg, payload); } static void _do_listxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg, const void *in_payload) { (void)in_payload; const struct fuse_getxattr_in *arg = inarg; if (req->se->op.listxattr) req->se->op.listxattr(req, nodeid, arg->size); else fuse_reply_err(req, ENOSYS); } static void do_listxattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_listxattr(req, nodeid, inarg, NULL); } static void _do_removexattr(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg, const void *in_payload) { (void)inarg; const char *name = in_payload; if (req->se->op.removexattr) req->se->op.removexattr(req, nodeid, name); else fuse_reply_err(req, ENOSYS); } static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_removexattr(req, nodeid, NULL, inarg); } static void convert_fuse_file_lock(const struct fuse_file_lock *fl, struct flock *flock) { memset(flock, 0, sizeof(struct flock)); flock->l_type = fl->type; flock->l_whence = SEEK_SET; flock->l_start = fl->start; if (fl->end == OFFSET_MAX) flock->l_len = 0; else flock->l_len = fl->end - fl->start + 1; flock->l_pid = fl->pid; } static void _do_getlk(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_lk_in *arg = op_in; struct fuse_file_info fi; struct flock flock; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.lock_owner = arg->owner; convert_fuse_file_lock(&arg->lk, &flock); if (req->se->op.getlk) req->se->op.getlk(req, nodeid, &fi, &flock); else fuse_reply_err(req, ENOSYS); } static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_getlk(req, nodeid, inarg, NULL); } static void do_setlk_common(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, int sleep) { const struct fuse_lk_in *arg = op_in; struct fuse_file_info fi; struct flock flock; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.lock_owner = arg->owner; if (arg->lk_flags & FUSE_LK_FLOCK) { int op = 0; switch (arg->lk.type) { case F_RDLCK: op = LOCK_SH; break; case F_WRLCK: op = LOCK_EX; break; case F_UNLCK: op = LOCK_UN; break; } if (!sleep) op |= LOCK_NB; if (req->se->op.flock) req->se->op.flock(req, nodeid, &fi, op); else fuse_reply_err(req, ENOSYS); } else { convert_fuse_file_lock(&arg->lk, &flock); if (req->se->op.setlk) req->se->op.setlk(req, nodeid, &fi, &flock, sleep); else fuse_reply_err(req, ENOSYS); } } static void _do_setlk(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; do_setlk_common(req, nodeid, op_in, 0); } static void do_setlk(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_setlk(req, nodeid, inarg, NULL); } static void _do_setlkw(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; do_setlk_common(req, nodeid, op_in, 1); } static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_setlkw(req, nodeid, inarg, NULL); } static int find_interrupted(struct fuse_session *se, struct fuse_req *req) { struct fuse_req *curr; for (curr = se->list.next; curr != &se->list; curr = curr->next) { if (curr->unique == req->u.i.unique) { fuse_interrupt_func_t func; void *data; curr->ref_cnt++; pthread_mutex_unlock(&se->lock); /* Ugh, ugly locking */ pthread_mutex_lock(&curr->lock); pthread_mutex_lock(&se->lock); curr->interrupted = 1; func = curr->u.ni.func; data = curr->u.ni.data; pthread_mutex_unlock(&se->lock); if (func) func(curr, data); pthread_mutex_unlock(&curr->lock); pthread_mutex_lock(&se->lock); curr->ref_cnt--; if (!curr->ref_cnt) { destroy_req(curr); } return 1; } } for (curr = se->interrupts.next; curr != &se->interrupts; curr = curr->next) { if (curr->u.i.unique == req->u.i.unique) return 1; } return 0; } static void _do_interrupt(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_interrupt_in *arg = op_in; struct fuse_session *se = req->se; (void) nodeid; if (se->debug) fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); req->u.i.unique = arg->unique; pthread_mutex_lock(&se->lock); if (find_interrupted(se, req)) { fuse_chan_put(req->ch); req->ch = NULL; destroy_req(req); } else list_add_req(req, &se->interrupts); pthread_mutex_unlock(&se->lock); } static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_interrupt(req, nodeid, inarg, NULL); } static struct fuse_req *check_interrupt(struct fuse_session *se, struct fuse_req *req) { struct fuse_req *curr; for (curr = se->interrupts.next; curr != &se->interrupts; curr = curr->next) { if (curr->u.i.unique == req->unique) { req->interrupted = 1; list_del_req(curr); fuse_chan_put(curr->ch); curr->ch = NULL; destroy_req(curr); return NULL; } } curr = se->interrupts.next; if (curr != &se->interrupts) { list_del_req(curr); list_init_req(curr); return curr; } else return NULL; } static void _do_bmap(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_bmap_in *arg = op_in; if (req->se->op.bmap) req->se->op.bmap(req, nodeid, arg->blocksize, arg->block); else fuse_reply_err(req, ENOSYS); } static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_bmap(req, nodeid, inarg, NULL); } static void _do_ioctl(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)op_in; unsigned int flags = arg->flags; const void *in_buf = in_payload; struct fuse_file_info fi; if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want_ext & FUSE_CAP_IOCTL_DIR)) { fuse_reply_err(req, ENOTTY); return; } memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 && !(flags & FUSE_IOCTL_32BIT)) { req->flags.ioctl_64bit = 1; } if (req->se->op.ioctl) req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg, &fi, flags, in_buf, arg->in_size, arg->out_size); else fuse_reply_err(req, ENOSYS); } static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { const struct fuse_ioctl_in *arg = inarg; void *in_buf = arg->in_size ? PARAM(arg) : NULL; _do_ioctl(req, nodeid, arg, in_buf); } void fuse_pollhandle_destroy(struct fuse_pollhandle *ph) { free(ph); } static void _do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; struct fuse_poll_in *arg = (struct fuse_poll_in *)op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fi.poll_events = arg->events; if (req->se->op.poll) { struct fuse_pollhandle *ph = NULL; if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) { ph = malloc(sizeof(struct fuse_pollhandle)); if (ph == NULL) { fuse_reply_err(req, ENOMEM); return; } ph->kh = arg->kh; ph->se = req->se; } req->se->op.poll(req, nodeid, &fi, ph); } else { fuse_reply_err(req, ENOSYS); } } static void do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_poll(req, nodeid, inarg, NULL); } static void _do_fallocate(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_fallocate_in *arg = op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.fallocate) req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi); else fuse_reply_err(req, ENOSYS); } static void do_fallocate(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_fallocate(req, nodeid, inarg, NULL); } static void copy_file_range_common(fuse_req_t req, const fuse_ino_t nodeid_in, const struct fuse_copy_file_range_in *arg) { struct fuse_file_info fi_in, fi_out; memset(&fi_in, 0, sizeof(fi_in)); fi_in.fh = arg->fh_in; memset(&fi_out, 0, sizeof(fi_out)); fi_out.fh = arg->fh_out; if (req->se->op.copy_file_range) req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in, arg->nodeid_out, arg->off_out, &fi_out, arg->len, arg->flags); else fuse_reply_err(req, ENOSYS); } static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in, const void *op_in, const void *in_payload) { const struct fuse_copy_file_range_in *arg = op_in; struct fuse_copy_file_range_in arg_tmp; (void) in_payload; /* fuse_write_out can only handle 32bit copy size */ if (arg->len > 0xfffff000) { arg_tmp = *arg; arg_tmp.len = 0xfffff000; arg = &arg_tmp; } copy_file_range_common(req, nodeid_in, arg); } static void do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in, const void *inarg) { _do_copy_file_range(req, nodeid_in, inarg, NULL); } static void _do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in, const void *op_in, const void *in_payload) { (void) in_payload; req->flags.is_copy_file_range_64 = 1; /* Limit size on 32bit userspace to avoid conversion overflow */ if (sizeof(size_t) == 4) _do_copy_file_range(req, nodeid_in, op_in, NULL); else copy_file_range_common(req, nodeid_in, op_in); } static void do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in, const void *inarg) { _do_copy_file_range_64(req, nodeid_in, inarg, NULL); } /* * Note that the uint64_t offset in struct fuse_lseek_in is derived from * linux kernel loff_t and is therefore signed. */ static void _do_lseek(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_lseek_in *arg = op_in; struct fuse_file_info fi; memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; if (req->se->op.lseek) req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi); else fuse_reply_err(req, ENOSYS); } static void do_lseek(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg) { _do_lseek(req, nodeid, inarg, NULL); } #ifdef HAVE_STATX static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_statx_in *arg = op_in; struct fuse_file_info *fip = NULL; struct fuse_file_info fi; if (arg->getattr_flags & FUSE_GETATTR_FH) { memset(&fi, 0, sizeof(fi)); fi.fh = arg->fh; fip = &fi; } if (req->se->op.statx) req->se->op.statx(req, nodeid, arg->sx_flags, arg->sx_mask, fip); else fuse_reply_err(req, ENOSYS); } #else static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; (void)nodeid; (void)op_in; fuse_reply_err(req, ENOSYS); } #endif static void do_statx(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_statx(req, nodeid, inarg, NULL); } static bool want_flags_valid(uint64_t capable, uint64_t want) { uint64_t unknown_flags = want & (~capable); if (unknown_flags != 0) { fuse_log(FUSE_LOG_ERR, "fuse: unknown connection 'want' flags: 0x%08llx\n", (unsigned long long)unknown_flags); return false; } return true; } /** * Get the wanted capability flags, converting from old format if necessary */ int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn) { struct fuse_session *se = container_of(conn, struct fuse_session, conn); /* * Convert want to want_ext if necessary. * For the high level interface this function might be called * twice, once from the high level interface and once from the * low level interface. Both, with different want_ext_default and * want_default values. In order to suppress a failure for the * second call, we check if the lower 32 bits of want_ext are * already set to the value of want. */ if (conn->want != se->conn_want && fuse_lower_32_bits(conn->want_ext) != conn->want) { if (conn->want_ext != se->conn_want_ext) { fuse_log(FUSE_LOG_ERR, "%s: Both conn->want_ext and conn->want are set.\n" "want=%x want_ext=%llx, se->want=%x se->want_ext=%llx\n", __func__, conn->want, (unsigned long long)conn->want_ext, se->conn_want, (unsigned long long)se->conn_want_ext); return -EINVAL; } /* high bits from want_ext, low bits from want */ conn->want_ext = fuse_higher_32_bits(conn->want_ext) | conn->want; } /* ensure there won't be a second conversion */ conn->want = fuse_lower_32_bits(conn->want_ext); return 0; } bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag) { struct fuse_session *se = container_of(conn, struct fuse_session, conn); if (conn->capable_ext & flag) { conn->want_ext |= flag; se->conn_want_ext |= flag; conn->want |= flag; se->conn_want |= flag; return true; } return false; } void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag) { struct fuse_session *se = container_of(conn, struct fuse_session, conn); conn->want_ext &= ~flag; se->conn_want_ext &= ~flag; conn->want &= ~flag; se->conn_want &= ~flag; } bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag) { return conn->capable_ext & flag ? true : false; } /* Prevent bogus data races (bogus since "init" is called before * multi-threading becomes relevant */ static __attribute__((no_sanitize("thread"))) void _do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { (void)in_payload; const struct fuse_init_in *arg = op_in; struct fuse_init_out outarg; struct fuse_session *se = req->se; size_t bufsize = se->bufsize; size_t outargsize = sizeof(outarg); uint64_t inargflags = 0; uint64_t outargflags = 0; bool buf_reallocable = se->buf_reallocable; (void) nodeid; bool enable_io_uring = false; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor); if (arg->major == 7 && arg->minor >= 6) { fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags); fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead); } } se->conn.proto_major = arg->major; se->conn.proto_minor = arg->minor; se->conn.capable_ext = 0; se->conn.want_ext = 0; memset(&outarg, 0, sizeof(outarg)); outarg.major = FUSE_KERNEL_VERSION; outarg.minor = FUSE_KERNEL_MINOR_VERSION; if (arg->major < 7) { fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n", arg->major, arg->minor); fuse_reply_err(req, EPROTO); return; } if (arg->major > 7) { /* Wait for a second INIT request with a 7.X version */ send_reply_ok(req, &outarg, sizeof(outarg)); return; } if (arg->minor >= 6) { if (arg->max_readahead < se->conn.max_readahead) se->conn.max_readahead = arg->max_readahead; inargflags = arg->flags; if (inargflags & FUSE_INIT_EXT) inargflags = inargflags | (uint64_t) arg->flags2 << 32; if (inargflags & FUSE_ASYNC_READ) se->conn.capable_ext |= FUSE_CAP_ASYNC_READ; if (inargflags & FUSE_POSIX_LOCKS) se->conn.capable_ext |= FUSE_CAP_POSIX_LOCKS; if (inargflags & FUSE_ATOMIC_O_TRUNC) se->conn.capable_ext |= FUSE_CAP_ATOMIC_O_TRUNC; if (inargflags & FUSE_EXPORT_SUPPORT) se->conn.capable_ext |= FUSE_CAP_EXPORT_SUPPORT; if (inargflags & FUSE_DONT_MASK) se->conn.capable_ext |= FUSE_CAP_DONT_MASK; if (inargflags & FUSE_FLOCK_LOCKS) se->conn.capable_ext |= FUSE_CAP_FLOCK_LOCKS; if (inargflags & FUSE_AUTO_INVAL_DATA) se->conn.capable_ext |= FUSE_CAP_AUTO_INVAL_DATA; if (inargflags & FUSE_DO_READDIRPLUS) se->conn.capable_ext |= FUSE_CAP_READDIRPLUS; if (inargflags & FUSE_READDIRPLUS_AUTO) se->conn.capable_ext |= FUSE_CAP_READDIRPLUS_AUTO; if (inargflags & FUSE_ASYNC_DIO) se->conn.capable_ext |= FUSE_CAP_ASYNC_DIO; if (inargflags & FUSE_WRITEBACK_CACHE) se->conn.capable_ext |= FUSE_CAP_WRITEBACK_CACHE; if (inargflags & FUSE_NO_OPEN_SUPPORT) se->conn.capable_ext |= FUSE_CAP_NO_OPEN_SUPPORT; if (inargflags & FUSE_PARALLEL_DIROPS) se->conn.capable_ext |= FUSE_CAP_PARALLEL_DIROPS; if (inargflags & FUSE_POSIX_ACL) se->conn.capable_ext |= FUSE_CAP_POSIX_ACL; if (inargflags & FUSE_HANDLE_KILLPRIV) se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV; if (inargflags & FUSE_HANDLE_KILLPRIV_V2) se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV_V2; if (inargflags & FUSE_CACHE_SYMLINKS) se->conn.capable_ext |= FUSE_CAP_CACHE_SYMLINKS; if (inargflags & FUSE_NO_OPENDIR_SUPPORT) se->conn.capable_ext |= FUSE_CAP_NO_OPENDIR_SUPPORT; if (inargflags & FUSE_EXPLICIT_INVAL_DATA) se->conn.capable_ext |= FUSE_CAP_EXPLICIT_INVAL_DATA; if (inargflags & FUSE_SETXATTR_EXT) se->conn.capable_ext |= FUSE_CAP_SETXATTR_EXT; if (!(inargflags & FUSE_MAX_PAGES)) { size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() + FUSE_BUFFER_HEADER_SIZE; if (bufsize > max_bufsize) { bufsize = max_bufsize; } buf_reallocable = false; } if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP) se->conn.capable_ext |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP; if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY)) se->conn.capable_ext |= FUSE_CAP_EXPIRE_ONLY; if (inargflags & FUSE_PASSTHROUGH) se->conn.capable_ext |= FUSE_CAP_PASSTHROUGH; if (inargflags & FUSE_NO_EXPORT_SUPPORT) se->conn.capable_ext |= FUSE_CAP_NO_EXPORT_SUPPORT; if (inargflags & FUSE_OVER_IO_URING) se->conn.capable_ext |= FUSE_CAP_OVER_IO_URING; } else { se->conn.max_readahead = 0; } if (se->conn.proto_minor >= 14) { #ifdef HAVE_SPLICE #ifdef HAVE_VMSPLICE if ((se->io == NULL) || (se->io->splice_send != NULL)) { se->conn.capable_ext |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; } #endif if ((se->io == NULL) || (se->io->splice_receive != NULL)) { se->conn.capable_ext |= FUSE_CAP_SPLICE_READ; } #endif } if (se->conn.proto_minor >= 18) se->conn.capable_ext |= FUSE_CAP_IOCTL_DIR; /* Default settings for modern filesystems. * * Most of these capabilities were disabled by default in * libfuse2 for backwards compatibility reasons. In libfuse3, * we can finally enable them by default (as long as they're * supported by the kernel). */ #define LL_SET_DEFAULT(cond, cap) \ if ((cond)) \ fuse_set_feature_flag(&se->conn, cap) LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ); LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA); LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO); LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR); LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC); LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ); LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS); LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS); LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS); LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir, FUSE_CAP_READDIRPLUS_AUTO); LL_SET_DEFAULT(1, FUSE_CAP_OVER_IO_URING); /* This could safely become default, but libfuse needs an API extension * to support it * LL_SET_DEFAULT(1, FUSE_CAP_SETXATTR_EXT); */ se->conn.time_gran = 1; if (se->op.init) { // Apply the first 32 bits of capable_ext to capable se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext); se->op.init(se->userdata, &se->conn); /* * se->conn.want is 32-bit value and deprecated in favour of * se->conn.want_ext * Userspace might still use conn.want - we need to convert it */ fuse_convert_to_conn_want_ext(&se->conn); } if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) { fuse_reply_err(req, EPROTO); se->error = -EPROTO; fuse_session_exit(se); return; } unsigned max_read_mo = get_max_read(se->mo); if (se->conn.max_read != max_read_mo) { fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() " "requested different maximum read size (%u vs %u)\n", se->conn.max_read, max_read_mo); fuse_reply_err(req, EPROTO); se->error = -EPROTO; fuse_session_exit(se); return; } if (bufsize < FUSE_MIN_READ_BUFFER) { fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n", bufsize); bufsize = FUSE_MIN_READ_BUFFER; } if (buf_reallocable) bufsize = UINT_MAX; se->conn.max_write = MIN(se->conn.max_write, bufsize - FUSE_BUFFER_HEADER_SIZE); se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE; if (arg->flags & FUSE_MAX_PAGES) { outarg.flags |= FUSE_MAX_PAGES; outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1; } outargflags = outarg.flags; /* Always enable big writes, this is superseded by the max_write option */ outargflags |= FUSE_BIG_WRITES; if (se->conn.want_ext & FUSE_CAP_ASYNC_READ) outargflags |= FUSE_ASYNC_READ; if (se->conn.want_ext & FUSE_CAP_POSIX_LOCKS) outargflags |= FUSE_POSIX_LOCKS; if (se->conn.want_ext & FUSE_CAP_ATOMIC_O_TRUNC) outargflags |= FUSE_ATOMIC_O_TRUNC; if (se->conn.want_ext & FUSE_CAP_EXPORT_SUPPORT) outargflags |= FUSE_EXPORT_SUPPORT; if (se->conn.want_ext & FUSE_CAP_DONT_MASK) outargflags |= FUSE_DONT_MASK; if (se->conn.want_ext & FUSE_CAP_FLOCK_LOCKS) outargflags |= FUSE_FLOCK_LOCKS; if (se->conn.want_ext & FUSE_CAP_AUTO_INVAL_DATA) outargflags |= FUSE_AUTO_INVAL_DATA; if (se->conn.want_ext & FUSE_CAP_READDIRPLUS) outargflags |= FUSE_DO_READDIRPLUS; if (se->conn.want_ext & FUSE_CAP_READDIRPLUS_AUTO) outargflags |= FUSE_READDIRPLUS_AUTO; if (se->conn.want_ext & FUSE_CAP_ASYNC_DIO) outargflags |= FUSE_ASYNC_DIO; if (se->conn.want_ext & FUSE_CAP_WRITEBACK_CACHE) outargflags |= FUSE_WRITEBACK_CACHE; if (se->conn.want_ext & FUSE_CAP_PARALLEL_DIROPS) outargflags |= FUSE_PARALLEL_DIROPS; if (se->conn.want_ext & FUSE_CAP_POSIX_ACL) outargflags |= FUSE_POSIX_ACL; if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV) outargflags |= FUSE_HANDLE_KILLPRIV; if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2) outargflags |= FUSE_HANDLE_KILLPRIV_V2; if (se->conn.want_ext & FUSE_CAP_CACHE_SYMLINKS) outargflags |= FUSE_CACHE_SYMLINKS; if (se->conn.want_ext & FUSE_CAP_EXPLICIT_INVAL_DATA) outargflags |= FUSE_EXPLICIT_INVAL_DATA; if (se->conn.want_ext & FUSE_CAP_SETXATTR_EXT) outargflags |= FUSE_SETXATTR_EXT; if (se->conn.want_ext & FUSE_CAP_DIRECT_IO_ALLOW_MMAP) outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP; if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH) { outargflags |= FUSE_PASSTHROUGH; /* * outarg.max_stack_depth includes the fuse stack layer, * so it is one more than max_backing_stack_depth. */ outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1; } if (se->conn.want_ext & FUSE_CAP_NO_EXPORT_SUPPORT) outargflags |= FUSE_NO_EXPORT_SUPPORT; if (se->uring.enable && se->conn.want_ext & FUSE_CAP_OVER_IO_URING) { outargflags |= FUSE_OVER_IO_URING; enable_io_uring = true; } if ((inargflags & FUSE_REQUEST_TIMEOUT) && se->conn.request_timeout) { outargflags |= FUSE_REQUEST_TIMEOUT; outarg.request_timeout = se->conn.request_timeout; } outarg.max_readahead = se->conn.max_readahead; outarg.max_write = se->conn.max_write; if (se->conn.proto_minor >= 13) { if (se->conn.max_background >= (1 << 16)) se->conn.max_background = (1 << 16) - 1; if (se->conn.congestion_threshold > se->conn.max_background) se->conn.congestion_threshold = se->conn.max_background; if (!se->conn.congestion_threshold) { se->conn.congestion_threshold = se->conn.max_background * 3 / 4; } outarg.max_background = se->conn.max_background; outarg.congestion_threshold = se->conn.congestion_threshold; } if (se->conn.proto_minor >= 23) outarg.time_gran = se->conn.time_gran; if (se->debug) { fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor); fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags); fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n", outarg.max_readahead); fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write); fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n", outarg.max_background); fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n", outarg.congestion_threshold); fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n", outarg.time_gran); if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH) fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n", outarg.max_stack_depth); } if (arg->minor < 5) outargsize = FUSE_COMPAT_INIT_OUT_SIZE; else if (arg->minor < 23) outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE; /* XXX: Add an option to make non-available io-uring fatal */ if (enable_io_uring) { int ring_rc = fuse_uring_start(se); if (ring_rc != 0) { fuse_log(FUSE_LOG_INFO, "fuse: failed to start io-uring: %s\n", strerror(ring_rc)); outargflags &= ~FUSE_OVER_IO_URING; enable_io_uring = false; } } if (inargflags & FUSE_INIT_EXT) { outargflags |= FUSE_INIT_EXT; outarg.flags2 = outargflags >> 32; } outarg.flags = outargflags; /* * Has to be set before replying, as new kernel requests might * immediately arrive and got_init is used for op-code sanity. * Especially with external handlers, where we have no control * over the thread scheduling. */ se->got_init = 1; send_reply_ok(req, &outarg, outargsize); if (enable_io_uring) fuse_uring_wake_ring_threads(se); } static __attribute__((no_sanitize("thread"))) void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_init(req, nodeid, inarg, NULL); } static void _do_destroy(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in, const void *in_payload) { struct fuse_session *se = req->se; char *mountpoint; (void) nodeid; (void)op_in; (void)in_payload; mountpoint = atomic_exchange(&se->mountpoint, NULL); free(mountpoint); se->got_destroy = 1; se->got_init = 0; if (se->op.destroy) se->op.destroy(se->userdata); send_reply_ok(req, NULL, 0); } static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) { _do_destroy(req, nodeid, inarg, NULL); } static void list_del_nreq(struct fuse_notify_req *nreq) { struct fuse_notify_req *prev = nreq->prev; struct fuse_notify_req *next = nreq->next; prev->next = next; next->prev = prev; } static void list_add_nreq(struct fuse_notify_req *nreq, struct fuse_notify_req *next) { struct fuse_notify_req *prev = next->prev; nreq->next = next; nreq->prev = prev; prev->next = nreq; next->prev = nreq; } static void list_init_nreq(struct fuse_notify_req *nreq) { nreq->next = nreq; nreq->prev = nreq; } static void _do_notify_reply(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, const struct fuse_buf *buf) { struct fuse_session *se = req->se; struct fuse_notify_req *nreq; struct fuse_notify_req *head; pthread_mutex_lock(&se->lock); head = &se->notify_list; for (nreq = head->next; nreq != head; nreq = nreq->next) { if (nreq->unique == req->unique) { list_del_nreq(nreq); break; } } pthread_mutex_unlock(&se->lock); if (nreq != head) nreq->reply(nreq, req, nodeid, inarg, buf); } static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid, const void *inarg, const struct fuse_buf *ibuf) { struct fuse_buf buf = *ibuf; buf.size -= sizeof(struct fuse_in_header); _do_notify_reply(req, nodeid, inarg, &buf); } static int send_notify_iov(struct fuse_session *se, int notify_code, struct iovec *iov, int count) { struct fuse_out_header out; struct fuse_req *req = NULL; if (!se->got_init) return -ENOTCONN; out.unique = 0; out.error = notify_code; iov[0].iov_base = &out; iov[0].iov_len = sizeof(struct fuse_out_header); return fuse_send_msg(se, NULL, iov, count, req); } int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph) { if (ph != NULL) { struct fuse_notify_poll_wakeup_out outarg; struct iovec iov[2]; outarg.kh = ph->kh; iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2); } else { return 0; } } int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len) { struct fuse_notify_inval_inode_out outarg; struct iovec iov[2]; if (!se) return -EINVAL; if (se->conn.proto_minor < 12) return -ENOSYS; outarg.ino = ino; outarg.off = off; outarg.len = len; iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2); } int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se) { struct iovec iov[1]; if (!se) return -EINVAL; if (se->conn.proto_minor < 44) return -ENOSYS; return send_notify_iov(se, FUSE_NOTIFY_INC_EPOCH, iov, 1); } /** * Notify parent attributes and the dentry matching parent/name * * Underlying base function for fuse_lowlevel_notify_inval_entry() and * fuse_lowlevel_notify_expire_entry(). * * @warning * Only checks if fuse_lowlevel_notify_inval_entry() is supported by * the kernel. All other flags will fall back to * fuse_lowlevel_notify_inval_entry() if not supported! * DO THE PROPER CHECKS IN THE DERIVED FUNCTION! * * @param se the session object * @param parent inode number * @param name file name * @param namelen strlen() of file name * @param flags flags to control if the entry should be expired or invalidated * @return zero for success, -errno for failure */ static int fuse_lowlevel_notify_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen, enum fuse_notify_entry_flags flags) { struct fuse_notify_inval_entry_out outarg; struct iovec iov[3]; if (!se) return -EINVAL; if (se->conn.proto_minor < 12) return -ENOSYS; outarg.parent = parent; outarg.namelen = namelen; outarg.flags = 0; if (flags & FUSE_LL_EXPIRE_ONLY) outarg.flags |= FUSE_EXPIRE_ONLY; iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3); } int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen) { return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE); } int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen) { if (!se) return -EINVAL; if (!(se->conn.capable_ext & FUSE_CAP_EXPIRE_ONLY)) return -ENOSYS; return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY); } int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen) { struct fuse_notify_delete_out outarg; struct iovec iov[3]; if (!se) return -EINVAL; if (se->conn.proto_minor < 18) return -ENOSYS; outarg.parent = parent; outarg.child = child; outarg.namelen = namelen; outarg.padding = 0; iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); iov[2].iov_base = (void *)name; iov[2].iov_len = namelen + 1; return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3); } 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) { struct fuse_out_header out; struct fuse_notify_store_out outarg; struct iovec iov[3]; size_t size = fuse_buf_size(bufv); int res; struct fuse_req *req = NULL; if (!se) return -EINVAL; if (se->conn.proto_minor < 15) return -ENOSYS; out.unique = 0; out.error = FUSE_NOTIFY_STORE; outarg.nodeid = ino; outarg.offset = offset; outarg.size = size; outarg.padding = 0; iov[0].iov_base = &out; iov[0].iov_len = sizeof(out); iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags, req); if (res > 0) res = -res; return res; } struct fuse_retrieve_req { struct fuse_notify_req nreq; void *cookie; }; static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq, fuse_req_t req, fuse_ino_t ino, const void *inarg, const struct fuse_buf *ibuf) { struct fuse_session *se = req->se; struct fuse_retrieve_req *rreq = container_of(nreq, struct fuse_retrieve_req, nreq); const struct fuse_notify_retrieve_in *arg = inarg; struct fuse_bufvec bufv = { .buf[0] = *ibuf, .count = 1, }; if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD)) bufv.buf[0].mem = PARAM(arg); bufv.buf[0].size -= sizeof(struct fuse_notify_retrieve_in); if (bufv.buf[0].size < arg->size) { fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n"); fuse_reply_none(req); goto out; } bufv.buf[0].size = arg->size; if (se->op.retrieve_reply) { se->op.retrieve_reply(req, rreq->cookie, ino, arg->offset, &bufv); } else { fuse_reply_none(req); } out: free(rreq); if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count) fuse_ll_clear_pipe(se); } int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie) { struct fuse_notify_retrieve_out outarg; struct iovec iov[2]; struct fuse_retrieve_req *rreq; int err; if (!se) return -EINVAL; if (se->conn.proto_minor < 15) return -ENOSYS; rreq = malloc(sizeof(*rreq)); if (rreq == NULL) return -ENOMEM; pthread_mutex_lock(&se->lock); rreq->cookie = cookie; rreq->nreq.unique = se->notify_ctr++; rreq->nreq.reply = fuse_ll_retrieve_reply; list_add_nreq(&rreq->nreq, &se->notify_list); pthread_mutex_unlock(&se->lock); outarg.notify_unique = rreq->nreq.unique; outarg.nodeid = ino; outarg.offset = offset; outarg.size = size; outarg.padding = 0; iov[1].iov_base = &outarg; iov[1].iov_len = sizeof(outarg); err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2); if (err) { pthread_mutex_lock(&se->lock); list_del_nreq(&rreq->nreq); pthread_mutex_unlock(&se->lock); free(rreq); } return err; } void *fuse_req_userdata(fuse_req_t req) { return req->se->userdata; } const struct fuse_ctx *fuse_req_ctx(fuse_req_t req) { return &req->ctx; } void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data) { pthread_mutex_lock(&req->lock); pthread_mutex_lock(&req->se->lock); req->u.ni.func = func; req->u.ni.data = data; pthread_mutex_unlock(&req->se->lock); if (req->interrupted && func) func(req, data); pthread_mutex_unlock(&req->lock); } int fuse_req_interrupted(fuse_req_t req) { int interrupted; pthread_mutex_lock(&req->se->lock); interrupted = req->interrupted; pthread_mutex_unlock(&req->se->lock); return interrupted; } bool fuse_req_is_uring(fuse_req_t req) { return req->flags.is_uring; } #ifndef HAVE_URING int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr) { (void)req; (void)payload; (void)payload_sz; (void)mr; return -ENOTSUP; } #endif static struct { void (*func)(fuse_req_t req, const fuse_ino_t node, const void *arg); const char *name; } fuse_ll_ops[] = { [FUSE_LOOKUP] = { do_lookup, "LOOKUP" }, [FUSE_FORGET] = { do_forget, "FORGET" }, [FUSE_GETATTR] = { do_getattr, "GETATTR" }, [FUSE_SETATTR] = { do_setattr, "SETATTR" }, [FUSE_READLINK] = { do_readlink, "READLINK" }, [FUSE_SYMLINK] = { do_symlink, "SYMLINK" }, [FUSE_MKNOD] = { do_mknod, "MKNOD" }, [FUSE_MKDIR] = { do_mkdir, "MKDIR" }, [FUSE_UNLINK] = { do_unlink, "UNLINK" }, [FUSE_RMDIR] = { do_rmdir, "RMDIR" }, [FUSE_RENAME] = { do_rename, "RENAME" }, [FUSE_LINK] = { do_link, "LINK" }, [FUSE_OPEN] = { do_open, "OPEN" }, [FUSE_READ] = { do_read, "READ" }, [FUSE_WRITE] = { do_write, "WRITE" }, [FUSE_STATFS] = { do_statfs, "STATFS" }, [FUSE_RELEASE] = { do_release, "RELEASE" }, [FUSE_FSYNC] = { do_fsync, "FSYNC" }, [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" }, [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" }, [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" }, [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" }, [FUSE_FLUSH] = { do_flush, "FLUSH" }, [FUSE_INIT] = { do_init, "INIT" }, [FUSE_OPENDIR] = { do_opendir, "OPENDIR" }, [FUSE_READDIR] = { do_readdir, "READDIR" }, [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" }, [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" }, [FUSE_GETLK] = { do_getlk, "GETLK" }, [FUSE_SETLK] = { do_setlk, "SETLK" }, [FUSE_SETLKW] = { do_setlkw, "SETLKW" }, [FUSE_ACCESS] = { do_access, "ACCESS" }, [FUSE_CREATE] = { do_create, "CREATE" }, [FUSE_TMPFILE] = { do_tmpfile, "TMPFILE" }, [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" }, [FUSE_BMAP] = { do_bmap, "BMAP" }, [FUSE_IOCTL] = { do_ioctl, "IOCTL" }, [FUSE_POLL] = { do_poll, "POLL" }, [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" }, [FUSE_DESTROY] = { do_destroy, "DESTROY" }, [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" }, [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"}, [FUSE_RENAME2] = { do_rename2, "RENAME2" }, [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, [FUSE_COPY_FILE_RANGE_64] = { do_copy_file_range_64, "COPY_FILE_RANGE_64" }, [FUSE_LSEEK] = { do_lseek, "LSEEK" }, [FUSE_STATX] = { do_statx, "STATX" }, [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" }, }; static struct { void (*func)(fuse_req_t req, const fuse_ino_t ino, const void *op_in, const void *op_payload); const char *name; } fuse_ll_ops2[] __attribute__((unused)) = { [FUSE_LOOKUP] = { _do_lookup, "LOOKUP" }, [FUSE_FORGET] = { _do_forget, "FORGET" }, [FUSE_GETATTR] = { _do_getattr, "GETATTR" }, [FUSE_SETATTR] = { _do_setattr, "SETATTR" }, [FUSE_READLINK] = { _do_readlink, "READLINK" }, [FUSE_SYMLINK] = { _do_symlink, "SYMLINK" }, [FUSE_MKNOD] = { _do_mknod, "MKNOD" }, [FUSE_MKDIR] = { _do_mkdir, "MKDIR" }, [FUSE_UNLINK] = { _do_unlink, "UNLINK" }, [FUSE_RMDIR] = { _do_rmdir, "RMDIR" }, [FUSE_RENAME] = { _do_rename, "RENAME" }, [FUSE_LINK] = { _do_link, "LINK" }, [FUSE_OPEN] = { _do_open, "OPEN" }, [FUSE_READ] = { _do_read, "READ" }, [FUSE_WRITE] = { _do_write, "WRITE" }, [FUSE_STATFS] = { _do_statfs, "STATFS" }, [FUSE_RELEASE] = { _do_release, "RELEASE" }, [FUSE_FSYNC] = { _do_fsync, "FSYNC" }, [FUSE_SETXATTR] = { _do_setxattr, "SETXATTR" }, [FUSE_GETXATTR] = { _do_getxattr, "GETXATTR" }, [FUSE_LISTXATTR] = { _do_listxattr, "LISTXATTR" }, [FUSE_REMOVEXATTR] = { _do_removexattr, "REMOVEXATTR" }, [FUSE_FLUSH] = { _do_flush, "FLUSH" }, [FUSE_INIT] = { _do_init, "INIT" }, [FUSE_OPENDIR] = { _do_opendir, "OPENDIR" }, [FUSE_READDIR] = { _do_readdir, "READDIR" }, [FUSE_RELEASEDIR] = { _do_releasedir, "RELEASEDIR" }, [FUSE_FSYNCDIR] = { _do_fsyncdir, "FSYNCDIR" }, [FUSE_GETLK] = { _do_getlk, "GETLK" }, [FUSE_SETLK] = { _do_setlk, "SETLK" }, [FUSE_SETLKW] = { _do_setlkw, "SETLKW" }, [FUSE_ACCESS] = { _do_access, "ACCESS" }, [FUSE_CREATE] = { _do_create, "CREATE" }, [FUSE_TMPFILE] = { _do_tmpfile, "TMPFILE" }, [FUSE_INTERRUPT] = { _do_interrupt, "INTERRUPT" }, [FUSE_BMAP] = { _do_bmap, "BMAP" }, [FUSE_IOCTL] = { _do_ioctl, "IOCTL" }, [FUSE_POLL] = { _do_poll, "POLL" }, [FUSE_FALLOCATE] = { _do_fallocate, "FALLOCATE" }, [FUSE_DESTROY] = { _do_destroy, "DESTROY" }, [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" }, [FUSE_BATCH_FORGET] = { _do_batch_forget, "BATCH_FORGET" }, [FUSE_READDIRPLUS] = { _do_readdirplus, "READDIRPLUS" }, [FUSE_RENAME2] = { _do_rename2, "RENAME2" }, [FUSE_COPY_FILE_RANGE] = { _do_copy_file_range, "COPY_FILE_RANGE" }, [FUSE_COPY_FILE_RANGE_64] = { _do_copy_file_range_64, "COPY_FILE_RANGE_64" }, [FUSE_LSEEK] = { _do_lseek, "LSEEK" }, [FUSE_STATX] = { _do_statx, "STATX" }, [CUSE_INIT] = { _cuse_lowlevel_init, "CUSE_INIT" }, }; /* * For ABI compatibility we cannot allow higher values than CUSE_INIT. * Without ABI compatibility we could use the size of the array. * #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) */ #define FUSE_MAXOP (CUSE_INIT + 1) /** * * @return 0 if sanity is ok, error otherwise */ static inline int fuse_req_opcode_sanity_ok(struct fuse_session *se, enum fuse_opcode in_op) { int err = EIO; if (!se->got_init) { enum fuse_opcode expected; expected = se->cuse_data ? CUSE_INIT : FUSE_INIT; if (in_op != expected) return err; } else if (in_op == FUSE_INIT || in_op == CUSE_INIT) return err; return 0; } static inline void fuse_session_in2req(struct fuse_req *req, struct fuse_in_header *in) { req->unique = in->unique; req->ctx.uid = in->uid; req->ctx.gid = in->gid; req->ctx.pid = in->pid; } /** * Implement -o allow_root */ static inline int fuse_req_check_allow_root(struct fuse_session *se, enum fuse_opcode in_op, uid_t in_uid) { int err = EACCES; if (se->deny_others && in_uid != se->owner && in_uid != 0 && in_op != FUSE_INIT && in_op != FUSE_READ && in_op != FUSE_WRITE && in_op != FUSE_FSYNC && in_op != FUSE_RELEASE && in_op != FUSE_READDIR && in_op != FUSE_FSYNCDIR && in_op != FUSE_RELEASEDIR && in_op != FUSE_NOTIFY_REPLY && in_op != FUSE_READDIRPLUS) return err; return 0; } static const char *opname(enum fuse_opcode opcode) { if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) return "???"; else return fuse_ll_ops[opcode].name; } static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst, struct fuse_bufvec *src) { ssize_t res = fuse_buf_copy(dst, src, 0); if (res < 0) { fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res)); return res; } if ((size_t)res < fuse_buf_size(dst)) { fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n"); return -1; } return 0; } void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf) { fuse_session_process_buf_internal(se, buf, NULL); } /* libfuse internal handler */ void fuse_session_process_buf_internal(struct fuse_session *se, const struct fuse_buf *buf, struct fuse_chan *ch) { const size_t write_header_size = sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in); struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 }; struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size); struct fuse_in_header *in; const void *inarg; struct fuse_req *req; void *mbuf = NULL; int err; int res; if (buf->flags & FUSE_BUF_IS_FD) { if (buf->size < tmpbuf.buf[0].size) tmpbuf.buf[0].size = buf->size; mbuf = malloc(tmpbuf.buf[0].size); if (mbuf == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n"); goto clear_pipe; } tmpbuf.buf[0].mem = mbuf; res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); if (res < 0) goto clear_pipe; in = mbuf; } else { in = buf->mem; } trace_request_process(in->opcode, in->unique); if (se->debug) { fuse_log(FUSE_LOG_DEBUG, "dev unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n", (unsigned long long) in->unique, opname((enum fuse_opcode) in->opcode), in->opcode, (unsigned long long) in->nodeid, buf->size, in->pid); } req = fuse_ll_alloc_req(se); if (req == NULL) { struct fuse_out_header out = { .unique = in->unique, .error = -ENOMEM, }; struct iovec iov = { .iov_base = &out, .iov_len = sizeof(struct fuse_out_header), }; fuse_send_msg(se, ch, &iov, 1, NULL); goto clear_pipe; } fuse_session_in2req(req, in); req->ch = ch ? fuse_chan_get(ch) : NULL; err = fuse_req_opcode_sanity_ok(se, in->opcode); if (err) goto reply_err; err = fuse_req_check_allow_root(se, in->opcode, in->uid); if (err) goto reply_err; err = ENOSYS; if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) goto reply_err; /* Do not process interrupt request */ if (se->conn.no_interrupt && in->opcode == FUSE_INTERRUPT) { if (se->debug) fuse_log(FUSE_LOG_DEBUG, "FUSE_INTERRUPT: reply to kernel to disable interrupt\n"); goto reply_err; } if (!se->conn.no_interrupt && in->opcode != FUSE_INTERRUPT) { struct fuse_req *intr; pthread_mutex_lock(&se->lock); intr = check_interrupt(se, req); list_add_req(req, &se->list); pthread_mutex_unlock(&se->lock); if (intr) fuse_reply_err(intr, EAGAIN); } if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size && (in->opcode != FUSE_WRITE || !se->op.write_buf) && in->opcode != FUSE_NOTIFY_REPLY) { void *newmbuf; err = ENOMEM; newmbuf = realloc(mbuf, buf->size); if (newmbuf == NULL) goto reply_err; mbuf = newmbuf; tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size); tmpbuf.buf[0].mem = (char *)mbuf + write_header_size; res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv); err = -res; if (res < 0) goto reply_err; in = mbuf; } inarg = (void *) &in[1]; if (in->opcode == FUSE_WRITE && se->op.write_buf) do_write_buf(req, in->nodeid, inarg, buf); else if (in->opcode == FUSE_NOTIFY_REPLY) do_notify_reply(req, in->nodeid, inarg, buf); else fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); out_free: free(mbuf); return; reply_err: fuse_reply_err(req, err); clear_pipe: if (buf->flags & FUSE_BUF_IS_FD) fuse_ll_clear_pipe(se); goto out_free; } void fuse_session_process_uring_cqe(struct fuse_session *se, struct fuse_req *req, struct fuse_in_header *in, void *op_in, void *op_payload, size_t payload_len) { int err; fuse_session_in2req(req, in); err = fuse_req_opcode_sanity_ok(se, in->opcode); if (err) goto reply_err; err = fuse_req_check_allow_root(se, in->opcode, in->uid); if (err) goto reply_err; err = ENOSYS; if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops2[in->opcode].func) goto reply_err; if (se->debug) { fuse_log( FUSE_LOG_DEBUG, "cqe unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n", (unsigned long long)in->unique, opname((enum fuse_opcode)in->opcode), in->opcode, (unsigned long long)in->nodeid, payload_len, in->pid); } if (in->opcode == FUSE_WRITE && se->op.write_buf) { struct fuse_bufvec bufv = { .buf[0] = { .size = payload_len, .flags = 0, .mem = op_payload }, .count = 1, }; _do_write_buf(req, in->nodeid, op_in, &bufv); } else if (in->opcode == FUSE_NOTIFY_REPLY) { struct fuse_buf buf = { .size = payload_len, .mem = op_payload }; _do_notify_reply(req, in->nodeid, op_payload, &buf); } else { fuse_ll_ops2[in->opcode].func(req, in->nodeid, op_in, op_payload); } return; reply_err: fuse_reply_err(req, err); } #define LL_OPTION(n,o,v) \ { n, offsetof(struct fuse_session, o), v } static const struct fuse_opt fuse_ll_opts[] = { LL_OPTION("debug", debug, 1), LL_OPTION("-d", debug, 1), LL_OPTION("--debug", debug, 1), LL_OPTION("allow_root", deny_others, 1), LL_OPTION("io_uring", uring.enable, 1), LL_OPTION("io_uring_q_depth=%u", uring.q_depth, -1), FUSE_OPT_END }; void fuse_lowlevel_version(void) { printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION); fuse_mount_version(); } void fuse_lowlevel_help(void) { /* These are not all options, but the ones that are potentially of interest to an end-user */ printf( " -o allow_other allow access by all users\n" " -o allow_root allow access by root\n" " -o auto_unmount auto unmount on process termination\n" " -o io_uring enable io-uring\n" " -o io_uring_q_depth= io-uring queue depth\n" ); } void fuse_session_destroy(struct fuse_session *se) { struct fuse_ll_pipe *llp; if (se->got_init && !se->got_destroy) { if (se->op.destroy) se->op.destroy(se->userdata); } llp = pthread_getspecific(se->pipe_key); if (llp != NULL) fuse_ll_pipe_free(llp); pthread_key_delete(se->pipe_key); sem_destroy(&se->mt_finish); pthread_mutex_destroy(&se->mt_lock); pthread_mutex_destroy(&se->lock); free(se->cuse_data); if (se->fd != -1) close(se->fd); if (se->io != NULL) free(se->io); destroy_mount_opts(se->mo); free(atomic_exchange(&se->mountpoint, NULL)); free(se); } static void fuse_ll_pipe_destructor(void *data) { struct fuse_ll_pipe *llp = data; fuse_ll_pipe_free(llp); } void fuse_buf_free(struct fuse_buf *buf) { if (buf->mem == NULL) return; size_t write_header_sz = sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in); char *ptr = (char *)buf->mem - pagesize + write_header_sz; free(ptr); buf->mem = NULL; } /* * This is used to allocate buffers that hold fuse requests */ static void *buf_alloc(size_t size, bool internal) { /* * For libfuse internal caller add in alignment. That cannot be done * for an external caller, as it is not guaranteed that the external * caller frees the raw pointer. */ if (internal) { size_t write_header_sz = sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in); size_t new_size = ROUND_UP(size + write_header_sz, pagesize); char *buf = aligned_alloc(pagesize, new_size); if (buf == NULL) return NULL; buf += pagesize - write_header_sz; return buf; } else { return malloc(size); } } /* *@param internal true if called from libfuse internal code */ static int _fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan *ch, bool internal) { int err; ssize_t res; size_t bufsize; #ifdef HAVE_SPLICE struct fuse_ll_pipe *llp; struct fuse_buf tmpbuf; pipe_retry: bufsize = se->bufsize; if (se->conn.proto_minor < 14 || !(se->conn.want_ext & FUSE_CAP_SPLICE_READ)) goto fallback; llp = fuse_ll_get_pipe(se); if (llp == NULL) goto fallback; if (llp->size < bufsize) { if (llp->can_grow) { res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize); if (res == -1) { llp->can_grow = 0; res = grow_pipe_to_max(llp->pipe[0]); if (res > 0) llp->size = res; fuse_ll_clear_pipe(se); goto fallback; } llp->size = res; } if (llp->size < bufsize) { fuse_ll_clear_pipe(se); goto fallback; } } if (se->io != NULL && se->io->splice_receive != NULL) { res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL, bufsize, 0, se->userdata); } else { res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL, bufsize, 0); } err = errno; trace_request_receive(err); if (fuse_session_exited(se)) return 0; if (res == -1) { if (err == ENODEV) { /* Filesystem was unmounted, or connection was aborted via /sys/fs/fuse/connections */ fuse_session_exit(se); return 0; } /* FUSE_INIT might have increased the required bufsize */ if (err == EINVAL && bufsize < se->bufsize) { fuse_ll_clear_pipe(se); goto pipe_retry; } if (err != EINTR && err != EAGAIN) perror("fuse: splice from device"); return -err; } if (res < sizeof(struct fuse_in_header)) { fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n"); return -EIO; } tmpbuf = (struct fuse_buf){ .size = res, .flags = FUSE_BUF_IS_FD, .fd = llp->pipe[0], }; /* * Don't bother with zero copy for small requests. * fuse_loop_mt() needs to check for FORGET so this more than * just an optimization. */ if (res < sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + pagesize) { struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 }; struct fuse_bufvec dst = { .count = 1 }; if (!buf->mem) { buf->mem = buf_alloc(bufsize, internal); if (!buf->mem) { fuse_log( FUSE_LOG_ERR, "fuse: failed to allocate read buffer\n"); return -ENOMEM; } buf->mem_size = bufsize; } buf->size = bufsize; buf->flags = 0; dst.buf[0] = *buf; res = fuse_buf_copy(&dst, &src, 0); if (res < 0) { fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res)); fuse_ll_clear_pipe(se); return res; } if (res < tmpbuf.size) { fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n"); fuse_ll_clear_pipe(se); return -EIO; } assert(res == tmpbuf.size); } else { /* Don't overwrite buf->mem, as that would cause a leak */ buf->fd = tmpbuf.fd; buf->flags = tmpbuf.flags; } buf->size = tmpbuf.size; return res; fallback: #endif bufsize = internal ? buf->mem_size : se->bufsize; if (!buf->mem) { bufsize = se->bufsize; /* might have changed */ buf->mem = buf_alloc(bufsize, internal); if (!buf->mem) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate read buffer\n"); return -ENOMEM; } if (internal) buf->mem_size = bufsize; } restart: if (se->io != NULL) { /* se->io->read is never NULL if se->io is not NULL as specified by fuse_session_custom_io()*/ res = se->io->read(ch ? ch->fd : se->fd, buf->mem, bufsize, se->userdata); } else { res = read(ch ? ch->fd : se->fd, buf->mem, bufsize); } err = errno; trace_request_receive(err); if (fuse_session_exited(se)) return 0; if (res == -1) { if (err == EINVAL && internal && se->bufsize > bufsize) { /* FUSE_INIT might have increased the required bufsize */ bufsize = se->bufsize; void *newbuf = buf_alloc(bufsize, internal); if (!newbuf) { fuse_log( FUSE_LOG_ERR, "fuse: failed to (re)allocate read buffer\n"); return -ENOMEM; } fuse_buf_free(buf); buf->mem = newbuf; buf->mem_size = bufsize; goto restart; } /* ENOENT means the operation was interrupted, it's safe to restart */ if (err == ENOENT) goto restart; if (err == ENODEV) { /* Filesystem was unmounted, or connection was aborted via /sys/fs/fuse/connections */ fuse_session_exit(se); return 0; } /* Errors occurring during normal operation: EINTR (read interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem umounted) */ if (err != EINTR && err != EAGAIN) perror("fuse: reading device"); return -err; } if ((size_t)res < sizeof(struct fuse_in_header)) { fuse_log(FUSE_LOG_ERR, "short read on fuse device\n"); return -EIO; } buf->size = res; return res; } int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf) { return _fuse_session_receive_buf(se, buf, NULL, false); } /* libfuse internal handler */ int fuse_session_receive_buf_internal(struct fuse_session *se, struct fuse_buf *buf, struct fuse_chan *ch) { /* * if run internally thread buffers are from libfuse - we can * reallocate them */ if (unlikely(!se->got_init) && !se->buf_reallocable) se->buf_reallocable = true; return _fuse_session_receive_buf(se, buf, ch, true); } struct fuse_session * fuse_session_new_versioned(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, struct libfuse_version *version, void *userdata) { int err; struct fuse_session *se; struct mount_opts *mo; if (op == NULL || op_size == 0) { fuse_log(FUSE_LOG_ERR, "fuse: warning: empty op list passed to fuse_session_new()\n"); return NULL; } if (version == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: warning: version not passed to fuse_session_new()\n"); return NULL; } if (sizeof(struct fuse_lowlevel_ops) < op_size) { fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n"); op_size = sizeof(struct fuse_lowlevel_ops); } if (args == NULL || args->argc == 0) { fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n"); return NULL; } se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session)); if (se == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n"); goto out1; } se->fd = -1; se->conn.max_write = FUSE_DEFAULT_MAX_PAGES_LIMIT * getpagesize(); se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE; se->conn.max_readahead = UINT_MAX; /* * Allow overriding with env, mostly to avoid the need to modify * all tests. I.e. to test with and without io-uring being enabled. */ se->uring.enable = getenv("FUSE_URING_ENABLE") ? atoi(getenv("FUSE_URING_ENABLE")) : SESSION_DEF_URING_ENABLE; se->uring.q_depth = getenv("FUSE_URING_QUEUE_DEPTH") ? atoi(getenv("FUSE_URING_QUEUE_DEPTH")) : SESSION_DEF_URING_Q_DEPTH; /* Parse options */ if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) goto out2; if(se->deny_others) { /* Allowing access only by root is done by instructing * kernel to allow access by everyone, and then restricting * access to root and mountpoint owner in libfuse. */ // We may be adding the option a second time, but // that doesn't hurt. if(fuse_opt_add_arg(args, "-oallow_other") == -1) goto out2; } mo = parse_mount_opts(args); if (mo == NULL) goto out3; if(args->argc == 1 && args->argv[0][0] == '-') { fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but " "will be ignored\n"); } else if (args->argc != 1) { int i; fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `"); for(i = 1; i < args->argc-1; i++) fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]); fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]); goto out4; } if (se->debug) fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION); list_init_req(&se->list); list_init_req(&se->interrupts); list_init_nreq(&se->notify_list); se->notify_ctr = 1; pthread_mutex_init(&se->lock, NULL); sem_init(&se->mt_finish, 0, 0); pthread_mutex_init(&se->mt_lock, NULL); err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor); if (err) { fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n", strerror(err)); goto out5; } memcpy(&se->op, op, op_size); se->owner = getuid(); se->userdata = userdata; se->mo = mo; /* Fuse server application should pass the version it was compiled * against and pass it. If a libfuse version accidentally introduces an * ABI incompatibility, it might be possible to 'fix' that at run time, * by checking the version numbers. */ se->version = *version; return se; out5: sem_destroy(&se->mt_finish); pthread_mutex_destroy(&se->mt_lock); pthread_mutex_destroy(&se->lock); out4: fuse_opt_free_args(args); out3: if (mo != NULL) destroy_mount_opts(mo); out2: free(se); out1: return NULL; } struct fuse_session *fuse_session_new_30(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata); struct fuse_session *fuse_session_new_30(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata) { struct fuse_lowlevel_ops null_ops = { 0 }; /* unknown version */ struct libfuse_version version = { 0 }; /* * This function is the ABI interface function from fuse_session_new in * compat.c. External libraries like "fuser" might call fuse_session_new() * with NULL ops and then pass that session to fuse_session_mount(). * The actual FUSE operations are handled in their own library. */ if (op == NULL) { op = &null_ops; op_size = sizeof(null_ops); } return fuse_session_new_versioned(args, op, op_size, &version, userdata); } FUSE_SYMVER("fuse_session_custom_io_317", "fuse_session_custom_io@@FUSE_3.17") int fuse_session_custom_io_317(struct fuse_session *se, const struct fuse_custom_io *io, size_t op_size, int fd) { #ifndef HAVE_CUSTOM_IO (void)se; (void)io; (void)op_size; (void)fd; fuse_log(FUSE_LOG_ERR, "fuse: custom io is not enabled in this build\n"); return -ENOTSUP; #else if (sizeof(struct fuse_custom_io) < op_size) { fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n"); op_size = sizeof(struct fuse_custom_io); } if (fd < 0) { fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to " "fuse_session_custom_io()\n", fd); return -EBADF; } if (io == NULL) { fuse_log(FUSE_LOG_ERR, "No custom IO passed to " "fuse_session_custom_io()\n"); return -EINVAL; } else if (io->read == NULL || io->writev == NULL) { /* If the user provides their own file descriptor, we can't guarantee that the default behavior of the io operations made in libfuse will function properly. Therefore, we enforce the user to implement these io operations when using custom io. */ fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must " "implement both io->read() and io->writev\n"); return -EINVAL; } se->io = calloc(1, sizeof(struct fuse_custom_io)); if (se->io == NULL) { fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. " "Error: %s\n", strerror(errno)); return -errno; } se->fd = fd; memcpy(se->io, io, op_size); return 0; #endif } int fuse_session_custom_io_30(struct fuse_session *se, const struct fuse_custom_io *io, int fd); FUSE_SYMVER("fuse_session_custom_io_30", "fuse_session_custom_io@FUSE_3.0") int fuse_session_custom_io_30(struct fuse_session *se, const struct fuse_custom_io *io, int fd) { return fuse_session_custom_io_317(se, io, offsetof(struct fuse_custom_io, clone_fd), fd); } int fuse_session_mount(struct fuse_session *se, const char *_mountpoint) { int fd; char *mountpoint; if (_mountpoint == NULL) { fuse_log(FUSE_LOG_ERR, "Invalid null-ptr mountpoint!\n"); return -1; } mountpoint = strdup(_mountpoint); if (mountpoint == NULL) { fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for mountpoint. Error: %s\n", strerror(errno)); return -1; } /* * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos * would ensue. */ do { fd = open("/dev/null", O_RDWR); if (fd > 2) close(fd); } while (fd >= 0 && fd <= 2); /* * To allow FUSE daemons to run without privileges, the caller may open * /dev/fuse before launching the file system and pass on the file * descriptor by specifying /dev/fd/N as the mount point. Note that the * parent process takes care of performing the mount in this case. */ fd = fuse_mnt_parse_fuse_fd(mountpoint); if (fd != -1) { if (fcntl(fd, F_GETFD) == -1) { fuse_log(FUSE_LOG_ERR, "fuse: Invalid file descriptor /dev/fd/%u\n", fd); goto error_out; } goto out; } /* Open channel */ fd = fuse_kern_mount(mountpoint, se->mo); if (fd == -1) goto error_out; out: se->fd = fd; se->mountpoint = mountpoint; return 0; error_out: free(mountpoint); return -1; } int fuse_session_fd(struct fuse_session *se) { return se->fd; } void fuse_session_unmount(struct fuse_session *se) { if (se->mountpoint != NULL) { char *mountpoint = atomic_exchange(&se->mountpoint, NULL); fuse_kern_unmount(mountpoint, se->fd); se->fd = -1; free(mountpoint); } } #ifdef linux int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) { char *buf; size_t bufsize = 1024; char path[128]; int ret; int fd; unsigned long pid = req->ctx.pid; char *s; sprintf(path, "/proc/%lu/task/%lu/status", pid, pid); retry: buf = malloc(bufsize); if (buf == NULL) return -ENOMEM; ret = -EIO; fd = open(path, O_RDONLY); if (fd == -1) goto out_free; ret = read(fd, buf, bufsize); close(fd); if (ret < 0) { ret = -EIO; goto out_free; } if ((size_t)ret == bufsize) { free(buf); bufsize *= 4; goto retry; } buf[ret] = '\0'; ret = -EIO; s = strstr(buf, "\nGroups:"); if (s == NULL) goto out_free; s += 8; ret = 0; while (1) { char *end; unsigned long val = strtoul(s, &end, 0); if (end == s) break; s = end; if (ret < size) list[ret] = val; ret++; } out_free: free(buf); return ret; } #else /* linux */ /* * This is currently not implemented on other than Linux... */ int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[]) { (void) req; (void) size; (void) list; return -ENOSYS; } #endif /* Prevent spurious data race warning - we don't care * about races for this flag */ __attribute__((no_sanitize_thread)) void fuse_session_exit(struct fuse_session *se) { atomic_store_explicit(&se->mt_exited, 1, memory_order_relaxed); sem_post(&se->mt_finish); } __attribute__((no_sanitize_thread)) void fuse_session_reset(struct fuse_session *se) { se->mt_exited = false; se->error = 0; } __attribute__((no_sanitize_thread)) int fuse_session_exited(struct fuse_session *se) { bool exited = atomic_load_explicit(&se->mt_exited, memory_order_relaxed); return exited ? 1 : 0; } fuse-3.18.3/lib/fuse_misc.h0000644000175000017500000000344715250106036014420 0ustar berndbernd/* 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 LGPL2.txt */ #include /* Versioned symbols cannot be used in some cases because it - not supported on MacOSX (in MachO binary format) Note: "@@" denotes the default symbol, "@" is binary a compat version. */ #ifdef LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS # if HAVE_SYMVER_ATTRIBUTE # define FUSE_SYMVER(sym1, sym2) __attribute__ ((symver (sym2))) # else # define FUSE_SYMVER(sym1, sym2) __asm__("\t.symver " sym1 "," sym2); # endif #else #define FUSE_SYMVER(sym1, sym2) #endif #ifdef HAVE_STRUCT_STAT_ST_ATIM /* Linux */ #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atim.tv_nsec = (val) #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctim.tv_nsec = (val) #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtim.tv_nsec = (val) #elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC) /* FreeBSD */ #define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) #define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) #define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) #define ST_ATIM_NSEC_SET(stbuf, val) (stbuf)->st_atimespec.tv_nsec = (val) #define ST_CTIM_NSEC_SET(stbuf, val) (stbuf)->st_ctimespec.tv_nsec = (val) #define ST_MTIM_NSEC_SET(stbuf, val) (stbuf)->st_mtimespec.tv_nsec = (val) #else #define ST_ATIM_NSEC(stbuf) 0 #define ST_CTIM_NSEC(stbuf) 0 #define ST_MTIM_NSEC(stbuf) 0 #define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0) #define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0) #define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0) #endif fuse-3.18.3/lib/fuse_opt.c0000644000175000017500000002135515250106036014260 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Implementation of option parsing routines (dealing with `struct fuse_args`). This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include "fuse_config.h" #include "fuse_i.h" #include "fuse_opt.h" #include "fuse_misc.h" #include #include #include #include struct fuse_opt_context { void *data; const struct fuse_opt *opt; fuse_opt_proc_t proc; int argctr; int argc; char **argv; struct fuse_args outargs; char *opts; int nonopt; }; void fuse_opt_free_args(struct fuse_args *args) { if (args) { if (args->argv && args->allocated) { int i; for (i = 0; i < args->argc; i++) free(args->argv[i]); free(args->argv); } args->argc = 0; args->argv = NULL; args->allocated = 0; } } static int alloc_failed(void) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); return -1; } int fuse_opt_add_arg(struct fuse_args *args, const char *arg) { char **newargv; char *newarg; assert(!args->argv || args->allocated); newarg = strdup(arg); if (!newarg) return alloc_failed(); newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *)); if (!newargv) { free(newarg); return alloc_failed(); } args->argv = newargv; args->allocated = 1; args->argv[args->argc++] = newarg; args->argv[args->argc] = NULL; return 0; } static int fuse_opt_insert_arg_common(struct fuse_args *args, int pos, const char *arg) { assert(pos <= args->argc); if (fuse_opt_add_arg(args, arg) == -1) return -1; if (pos != args->argc - 1) { char *newarg = args->argv[args->argc - 1]; memmove(&args->argv[pos + 1], &args->argv[pos], sizeof(char *) * (args->argc - pos - 1)); args->argv[pos] = newarg; } return 0; } int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) { return fuse_opt_insert_arg_common(args, pos, arg); } static int next_arg(struct fuse_opt_context *ctx, const char *opt) { if (ctx->argctr + 1 >= ctx->argc) { fuse_log(FUSE_LOG_ERR, "fuse: missing argument after `%s'\n", opt); return -1; } ctx->argctr++; return 0; } static int add_arg(struct fuse_opt_context *ctx, const char *arg) { return fuse_opt_add_arg(&ctx->outargs, arg); } static int add_opt_common(char **opts, const char *opt, int esc) { unsigned oldlen = *opts ? strlen(*opts) : 0; char *d = realloc(*opts, oldlen + 1 + strlen(opt) * 2 + 1); if (!d) return alloc_failed(); *opts = d; if (oldlen) { d += oldlen; *d++ = ','; } for (; *opt; opt++) { if (esc && (*opt == ',' || *opt == '\\')) *d++ = '\\'; *d++ = *opt; } *d = '\0'; return 0; } int fuse_opt_add_opt(char **opts, const char *opt) { return add_opt_common(opts, opt, 0); } int fuse_opt_add_opt_escaped(char **opts, const char *opt) { return add_opt_common(opts, opt, 1); } static int add_opt(struct fuse_opt_context *ctx, const char *opt) { return add_opt_common(&ctx->opts, opt, 1); } static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key, int iso) { if (key == FUSE_OPT_KEY_DISCARD) return 0; if (key != FUSE_OPT_KEY_KEEP && ctx->proc) { int res = ctx->proc(ctx->data, arg, key, &ctx->outargs); if (res == -1 || !res) return res; } if (iso) return add_opt(ctx, arg); else return add_arg(ctx, arg); } static int match_template(const char *t, const char *arg, unsigned *sepp) { int arglen = strlen(arg); const char *sep = strchr(t, '='); sep = sep ? sep : strchr(t, ' '); if (sep && (!sep[1] || sep[1] == '%')) { int tlen = sep - t; if (sep[0] == '=') tlen ++; if (arglen >= tlen && strncmp(arg, t, tlen) == 0) { *sepp = sep - t; return 1; } } if (strcmp(t, arg) == 0) { *sepp = 0; return 1; } return 0; } static const struct fuse_opt *find_opt(const struct fuse_opt *opt, const char *arg, unsigned *sepp) { for (; opt && opt->templ; opt++) if (match_template(opt->templ, arg, sepp)) return opt; return NULL; } int fuse_opt_match(const struct fuse_opt *opts, const char *opt) { unsigned dummy; return find_opt(opts, opt, &dummy) ? 1 : 0; } static int process_opt_param(void *var, const char *format, const char *param, const char *arg) { assert(format[0] == '%'); if (format[1] == 's') { char **s = var; char *copy = strdup(param); if (!copy) return alloc_failed(); free(*s); *s = copy; } else { if (sscanf(param, format, var) != 1) { fuse_log(FUSE_LOG_ERR, "fuse: invalid parameter in option `%s'\n", arg); return -1; } } return 0; } static int process_opt(struct fuse_opt_context *ctx, const struct fuse_opt *opt, unsigned sep, const char *arg, int iso) { if (opt->offset == -1U) { if (call_proc(ctx, arg, opt->value, iso) == -1) return -1; } else { void *var = (char *)ctx->data + opt->offset; if (sep && opt->templ[sep + 1]) { const char *param = arg + sep; if (opt->templ[sep] == '=') param ++; if (process_opt_param(var, opt->templ + sep + 1, param, arg) == -1) return -1; } else *(int *)var = opt->value; } return 0; } static int process_opt_sep_arg(struct fuse_opt_context *ctx, const struct fuse_opt *opt, unsigned sep, const char *arg, int iso) { int res; char *newarg; char *param; if (next_arg(ctx, arg) == -1) return -1; param = ctx->argv[ctx->argctr]; newarg = malloc(sep + strlen(param) + 1); if (!newarg) return alloc_failed(); memcpy(newarg, arg, sep); strcpy(newarg + sep, param); res = process_opt(ctx, opt, sep, newarg, iso); free(newarg); return res; } static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso) { unsigned sep; const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep); if (opt) { for (; opt; opt = find_opt(opt + 1, arg, &sep)) { int res; if (sep && opt->templ[sep] == ' ' && !arg[sep]) res = process_opt_sep_arg(ctx, opt, sep, arg, iso); else res = process_opt(ctx, opt, sep, arg, iso); if (res == -1) return -1; } return 0; } else return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso); } static int process_real_option_group(struct fuse_opt_context *ctx, char *opts) { char *s = opts; char *d = s; int end = 0; while (!end) { if (*s == '\0') end = 1; if (*s == ',' || end) { int res; *d = '\0'; res = process_gopt(ctx, opts, 1); if (res == -1) return -1; d = opts; } else { if (s[0] == '\\' && s[1] != '\0') { s++; if (s[0] >= '0' && s[0] <= '3' && s[1] >= '0' && s[1] <= '7' && s[2] >= '0' && s[2] <= '7') { *d++ = (s[0] - '0') * 0100 + (s[1] - '0') * 0010 + (s[2] - '0'); s += 2; } else { *d++ = *s; } } else { *d++ = *s; } } s++; } return 0; } static int process_option_group(struct fuse_opt_context *ctx, const char *opts) { int res; char *copy = strdup(opts); if (!copy) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); return -1; } res = process_real_option_group(ctx, copy); free(copy); return res; } static int process_one(struct fuse_opt_context *ctx, const char *arg) { if (ctx->nonopt || arg[0] != '-') return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0); else if (arg[1] == 'o') { if (arg[2]) return process_option_group(ctx, arg + 2); else { if (next_arg(ctx, arg) == -1) return -1; return process_option_group(ctx, ctx->argv[ctx->argctr]); } } else if (arg[1] == '-' && !arg[2]) { if (add_arg(ctx, arg) == -1) return -1; ctx->nonopt = ctx->outargs.argc; return 0; } else return process_gopt(ctx, arg, 0); } static int opt_parse(struct fuse_opt_context *ctx) { if (ctx->argc) { if (add_arg(ctx, ctx->argv[0]) == -1) return -1; } for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++) if (process_one(ctx, ctx->argv[ctx->argctr]) == -1) return -1; if (ctx->opts) { if (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 || fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1) return -1; } /* If option separator ("--") is the last argument, remove it */ if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc && strcmp(ctx->outargs.argv[ctx->outargs.argc - 1], "--") == 0) { free(ctx->outargs.argv[ctx->outargs.argc - 1]); ctx->outargs.argv[--ctx->outargs.argc] = NULL; } return 0; } int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc) { int res; struct fuse_opt_context ctx = { .data = data, .opt = opts, .proc = proc, }; if (!args || !args->argv || !args->argc) return 0; ctx.argc = args->argc; ctx.argv = args->argv; res = opt_parse(&ctx); if (res != -1) { struct fuse_args tmp = *args; *args = ctx.outargs; ctx.outargs = tmp; } free(ctx.opts); fuse_opt_free_args(&ctx.outargs); return res; } fuse-3.18.3/lib/fuse_signals.c0000644000175000017500000001166415250106036015120 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Utility functions for setting signal handlers. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include "fuse_config.h" #include "fuse_lowlevel.h" #include "fuse_i.h" #include #include #include #include #include #ifdef HAVE_BACKTRACE #include #endif /* * Must not handle SIGCANCEL, as that is used to wake up threads from * syscalls reading requests from /dev/fuse */ static int teardown_sigs[] = { SIGHUP, SIGINT, SIGTERM }; static int ignore_sigs[] = { SIGPIPE}; static int fail_sigs[] = { SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV }; static struct fuse_session *fuse_instance; #ifdef HAVE_BACKTRACE #define BT_STACK_SZ (1024 * 1024) static void *backtrace_buffer[BT_STACK_SZ]; #endif static void dump_stack(void) { #ifdef HAVE_BACKTRACE char **strings; int nptrs = backtrace(backtrace_buffer, BT_STACK_SZ); strings = backtrace_symbols(backtrace_buffer, nptrs); if (strings == NULL) { fuse_log(FUSE_LOG_ERR, "Failed to get backtrace symbols: %s\n", strerror(errno)); return; } for (int idx = 0; idx < nptrs; idx++) fuse_log(FUSE_LOG_ERR, "%s\n", strings[idx]); free(strings); #endif } static void exit_handler(int sig) { if (fuse_instance == NULL) { fuse_log(FUSE_LOG_ERR, "fuse_instance is NULL\n"); return; } if (fuse_instance->debug) fuse_log(FUSE_LOG_ERR, "exit_handler called with sig %d\n", sig); fuse_session_exit(fuse_instance); if (sig < 0) { fuse_log(FUSE_LOG_ERR, "assertion error: signal value <= 0\n"); dump_stack(); abort(); fuse_instance->error = sig; } fuse_instance->error = sig; } static void exit_backtrace(int sig) { if (fuse_instance == NULL) return; fuse_session_exit(fuse_instance); fuse_remove_signal_handlers(fuse_instance); fuse_log(FUSE_LOG_ERR, "Got signal: %d\n", sig); dump_stack(); abort(); } static void do_nothing(int sig) { (void) sig; } static int set_one_signal_handler(int sig, void (*handler)(int), int remove) { struct sigaction sa; struct sigaction old_sa; memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = remove ? SIG_DFL : handler; sigemptyset(&(sa.sa_mask)); sa.sa_flags = 0; if (sigaction(sig, NULL, &old_sa) == -1) { perror("fuse: cannot get old signal handler"); return -1; } if (old_sa.sa_handler == (remove ? handler : SIG_DFL) && sigaction(sig, &sa, NULL) == -1) { perror("fuse: cannot set signal handler"); return -1; } return 0; } static int _fuse_set_signal_handlers(int signals[], int nr_signals, void (*handler)(int)) { for (int idx = 0; idx < nr_signals; idx++) { int signal = signals[idx]; /* * If we used SIG_IGN instead of the do_nothing function, * then we would be unable to tell if we set SIG_IGN (and * thus should reset to SIG_DFL in fuse_remove_signal_handlers) * or if it was already set to SIG_IGN (and should be left * untouched. */ if (set_one_signal_handler(signal, handler, 0) == -1) { fuse_log(FUSE_LOG_ERR, "Failed to install signal handler for sig %d\n", signal); return -1; } } return 0; } int fuse_set_signal_handlers(struct fuse_session *se) { size_t nr_signals; int rc; nr_signals = sizeof(teardown_sigs) / sizeof(teardown_sigs[0]); rc = _fuse_set_signal_handlers(teardown_sigs, nr_signals, exit_handler); if (rc < 0) return rc; nr_signals = sizeof(ignore_sigs) / sizeof(ignore_sigs[0]); rc = _fuse_set_signal_handlers(ignore_sigs, nr_signals, do_nothing); if (rc < 0) return rc; /* * needs to be set independently if already set, as some applications * may have multiple sessions and might rely on traditional behavior * that the last session is used. */ fuse_instance = se; return 0; } int fuse_set_fail_signal_handlers(struct fuse_session *se) { size_t nr_signals = sizeof(fail_sigs) / sizeof(fail_sigs[0]); int rc = _fuse_set_signal_handlers(fail_sigs, nr_signals, exit_backtrace); if (rc < 0) return rc; /* See fuse_set_signal_handlers, why set unconditionally */ fuse_instance = se; return 0; } static void _fuse_remove_signal_handlers(int signals[], int nr_signals, void (*handler)(int)) { for (int idx = 0; idx < nr_signals; idx++) set_one_signal_handler(signals[idx], handler, 1); } void fuse_remove_signal_handlers(struct fuse_session *se) { size_t nr_signals; if (fuse_instance != se) fuse_log(FUSE_LOG_ERR, "fuse: fuse_remove_signal_handlers: unknown session\n"); else fuse_instance = NULL; nr_signals = sizeof(teardown_sigs) / sizeof(teardown_sigs[0]); _fuse_remove_signal_handlers(teardown_sigs, nr_signals, exit_handler); nr_signals = sizeof(ignore_sigs) / sizeof(ignore_sigs[0]); _fuse_remove_signal_handlers(ignore_sigs, nr_signals, do_nothing); nr_signals = sizeof(fail_sigs) / sizeof(fail_sigs[0]); _fuse_remove_signal_handlers(fail_sigs, nr_signals, exit_backtrace); } fuse-3.18.3/lib/fuse_uring.c0000644000175000017500000005636415250106036014612 0ustar berndbernd/* * FUSE: Filesystem in Userspace * Copyright (C) 2025 Bernd Schubert * * Implementation of (most of) FUSE-over-io-uring. * * This program can be distributed under the terms of the GNU LGPLv2. * See the file LGPL2.txt */ #define _GNU_SOURCE #include "fuse_i.h" #include "fuse_kernel.h" #include "fuse_uring_i.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Size of command data area in SQE when IORING_SETUP_SQE128 is used */ #define FUSE_URING_MAX_SQE128_CMD_DATA 80 struct fuse_ring_ent { struct fuse_ring_queue *ring_queue; /* back pointer */ struct fuse_req req; struct fuse_uring_req_header *req_header; void *op_payload; size_t req_payload_sz; /* commit id of a fuse request */ uint64_t req_commit_id; enum fuse_uring_cmd last_cmd; /* header and payload */ struct iovec iov[2]; }; struct fuse_ring_queue { /* back pointer */ struct fuse_ring_pool *ring_pool; int qid; int numa_node; pthread_t tid; int eventfd; size_t req_header_sz; struct io_uring ring; pthread_mutex_t ring_lock; bool cqe_processing; /* size depends on queue depth */ struct fuse_ring_ent ent[]; }; /** * Main fuse_ring structure, holds all fuse-ring data */ struct fuse_ring_pool { struct fuse_session *se; /* number of queues */ size_t nr_queues; /* number of per queue entries */ size_t queue_depth; /* max payload size for fuse requests*/ size_t max_req_payload_sz; /* size of a single queue */ size_t queue_mem_size; unsigned int started_threads; unsigned int failed_threads; /* Avoid sending queue entries before FUSE_INIT reply*/ sem_t init_sem; pthread_cond_t thread_start_cond; pthread_mutex_t thread_start_mutex; /* pointer to the first queue */ struct fuse_ring_queue *queues; }; static size_t fuse_ring_queue_size(const size_t q_depth) { const size_t req_size = sizeof(struct fuse_ring_ent) * q_depth; return sizeof(struct fuse_ring_queue) + req_size; } static struct fuse_ring_queue * fuse_uring_get_queue(struct fuse_ring_pool *fuse_ring, int qid) { void *ptr = ((char *)fuse_ring->queues) + (qid * fuse_ring->queue_mem_size); return ptr; } /** * return a pointer to the 80B area */ static void *fuse_uring_get_sqe_cmd(struct io_uring_sqe *sqe) { return (void *)&sqe->cmd[0]; } static void fuse_uring_sqe_set_req_data(struct fuse_uring_cmd_req *req, const unsigned int qid, const uint64_t commit_id) { req->qid = qid; req->commit_id = commit_id; req->flags = 0; } static void fuse_uring_sqe_prepare(struct io_uring_sqe *sqe, struct fuse_ring_ent *req, __u32 cmd_op) { /* These fields should be written once, never change */ sqe->opcode = IORING_OP_URING_CMD; /* * IOSQE_FIXED_FILE: fd is the index to the fd *array* * given to io_uring_register_files() */ sqe->flags = IOSQE_FIXED_FILE; sqe->fd = 0; sqe->rw_flags = 0; sqe->ioprio = 0; sqe->off = 0; io_uring_sqe_set_data(sqe, req); sqe->cmd_op = cmd_op; sqe->__pad1 = 0; } static int fuse_uring_commit_sqe(struct fuse_ring_pool *ring_pool, struct fuse_ring_queue *queue, struct fuse_ring_ent *ring_ent) { bool locked = false; struct fuse_session *se = ring_pool->se; struct fuse_uring_req_header *rrh = ring_ent->req_header; struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out; struct fuse_uring_ent_in_out *ent_in_out = (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; struct io_uring_sqe *sqe; if (pthread_self() != queue->tid) { pthread_mutex_lock(&queue->ring_lock); locked = true; } sqe = io_uring_get_sqe(&queue->ring); if (sqe == NULL) { /* This is an impossible condition, unless there is a bug. * The kernel sent back an SQEs, which is assigned to a request. * There is no way to get out of SQEs, as the number of * SQEs matches the number tof requests. */ se->error = -EIO; fuse_log(FUSE_LOG_ERR, "Failed to get a ring SQEs\n"); return -EIO; } ring_ent->last_cmd = FUSE_IO_URING_CMD_COMMIT_AND_FETCH; fuse_uring_sqe_prepare(sqe, ring_ent, ring_ent->last_cmd); fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid, ring_ent->req_commit_id); if (se->debug) { fuse_log(FUSE_LOG_DEBUG, " unique: %" PRIu64 ", result=%d\n", out->unique, ent_in_out->payload_sz); } if (!queue->cqe_processing) io_uring_submit(&queue->ring); if (locked) pthread_mutex_unlock(&queue->ring_lock); return 0; } int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr) { struct fuse_ring_ent *ring_ent; /* Not possible without io-uring interface */ if (!req->flags.is_uring) return -EINVAL; ring_ent = container_of(req, struct fuse_ring_ent, req); *payload = ring_ent->op_payload; *payload_sz = ring_ent->req_payload_sz; /* * For now unused, but will be used later when the application can * allocate the buffers itself and register them for rdma. */ if (mr) *mr = NULL; return 0; } int send_reply_uring(fuse_req_t req, int error, const void *arg, size_t argsize) { int res; struct fuse_ring_ent *ring_ent = container_of(req, struct fuse_ring_ent, req); struct fuse_uring_req_header *rrh = ring_ent->req_header; struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out; struct fuse_uring_ent_in_out *ent_in_out = (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; struct fuse_ring_queue *queue = ring_ent->ring_queue; struct fuse_ring_pool *ring_pool = queue->ring_pool; size_t max_payload_sz = ring_pool->max_req_payload_sz; if (argsize > max_payload_sz) { fuse_log(FUSE_LOG_ERR, "argsize %zu exceeds buffer size %zu", argsize, max_payload_sz); error = -EINVAL; } else if (argsize) { if (arg != ring_ent->op_payload) memcpy(ring_ent->op_payload, arg, argsize); } ent_in_out->payload_sz = argsize; out->error = error; out->unique = req->unique; res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent); fuse_free_req(req); return res; } int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags) { struct fuse_ring_ent *ring_ent = container_of(req, struct fuse_ring_ent, req); struct fuse_ring_queue *queue = ring_ent->ring_queue; struct fuse_ring_pool *ring_pool = queue->ring_pool; struct fuse_uring_req_header *rrh = ring_ent->req_header; struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out; struct fuse_uring_ent_in_out *ent_in_out = (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; size_t max_payload_sz = ring_ent->req_payload_sz; struct fuse_bufvec dest_vec = FUSE_BUFVEC_INIT(max_payload_sz); int res; dest_vec.buf[0].mem = ring_ent->op_payload; dest_vec.buf[0].size = max_payload_sz; res = fuse_buf_copy(&dest_vec, bufv, flags); out->error = res < 0 ? res : 0; out->unique = req->unique; ent_in_out->payload_sz = res > 0 ? res : 0; res = fuse_uring_commit_sqe(ring_pool, queue, ring_ent); fuse_free_req(req); return res; } /** * Copy the iov into the ring buffer and submit and commit/fetch sqe */ int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count) { struct fuse_ring_ent *ring_ent = container_of(req, struct fuse_ring_ent, req); struct fuse_ring_queue *queue = ring_ent->ring_queue; struct fuse_ring_pool *ring_pool = queue->ring_pool; struct fuse_uring_req_header *rrh = ring_ent->req_header; struct fuse_out_header *out = (struct fuse_out_header *)&rrh->in_out; struct fuse_uring_ent_in_out *ent_in_out = (struct fuse_uring_ent_in_out *)&rrh->ring_ent_in_out; size_t max_buf = ring_pool->max_req_payload_sz; size_t len = 0; int res = 0; /* copy iov into the payload, idx=0 is the header section */ for (int idx = 1; idx < count; idx++) { struct iovec *cur = &iov[idx]; if (len + cur->iov_len > max_buf) { fuse_log(FUSE_LOG_ERR, "iov[%d] exceeds buffer size %zu", idx, max_buf); res = -EINVAL; /* Gracefully handle this? */ break; } memcpy(ring_ent->op_payload + len, cur->iov_base, cur->iov_len); len += cur->iov_len; } ent_in_out->payload_sz = len; out->error = res; out->unique = req->unique; out->len = len; return fuse_uring_commit_sqe(ring_pool, queue, ring_ent); } static int fuse_queue_setup_io_uring(struct io_uring *ring, size_t qid, size_t depth, int fd, int evfd) { int rc; struct io_uring_params params = {0}; int files[2] = { fd, evfd }; depth += 1; /* for the eventfd poll SQE */ params.flags = IORING_SETUP_SQE128; /* Replies are batched and flushed in one io_uring_enter; don't let a * single failing commit SQE stall submission of the rest of the batch. */ params.flags |= IORING_SETUP_SUBMIT_ALL; /* Avoid cq overflow */ params.flags |= IORING_SETUP_CQSIZE; params.cq_entries = depth * 2; /* These flags should help to increase performance, but actually * make it a bit slower - reason should get investigated. */ if (0) { /* Has the main slow down effect */ params.flags |= IORING_SETUP_SINGLE_ISSUER; // params.flags |= IORING_SETUP_DEFER_TASKRUN; params.flags |= IORING_SETUP_TASKRUN_FLAG; /* Second main effect to make it slower */ params.flags |= IORING_SETUP_COOP_TASKRUN; } rc = io_uring_queue_init_params(depth, ring, ¶ms); if (rc != 0) { fuse_log(FUSE_LOG_ERR, "Failed to setup qid %zu: %d (%s)\n", qid, rc, strerror(-rc)); return rc; } rc = io_uring_register_files(ring, files, 1); if (rc != 0) { rc = -errno; fuse_log(FUSE_LOG_ERR, "Failed to register files for ring idx %zu: %s", qid, strerror(errno)); return rc; } return 0; } static void fuse_session_destruct_uring(struct fuse_ring_pool *fuse_ring) { for (size_t qid = 0; qid < fuse_ring->nr_queues; qid++) { struct fuse_ring_queue *queue = fuse_uring_get_queue(fuse_ring, qid); if (queue->tid != 0) { uint64_t value = 1ULL; int rc; rc = write(queue->eventfd, &value, sizeof(value)); if (rc != sizeof(value)) fprintf(stderr, "Wrote to eventfd=%d err=%s: rc=%d\n", queue->eventfd, strerror(errno), rc); pthread_cancel(queue->tid); pthread_join(queue->tid, NULL); queue->tid = 0; } if (queue->eventfd >= 0) { close(queue->eventfd); queue->eventfd = -1; } if (queue->ring.ring_fd != -1) io_uring_queue_exit(&queue->ring); for (size_t idx = 0; idx < fuse_ring->queue_depth; idx++) { struct fuse_ring_ent *ent = &queue->ent[idx]; numa_free(ent->op_payload, ent->req_payload_sz); numa_free(ent->req_header, queue->req_header_sz); } pthread_mutex_destroy(&queue->ring_lock); } free(fuse_ring->queues); pthread_cond_destroy(&fuse_ring->thread_start_cond); pthread_mutex_destroy(&fuse_ring->thread_start_mutex); free(fuse_ring); } static int fuse_uring_register_ent(struct fuse_ring_queue *queue, struct fuse_ring_ent *ent) { struct io_uring_sqe *sqe; sqe = io_uring_get_sqe(&queue->ring); if (sqe == NULL) { /* * All SQEs are idle here - no good reason this * could fail */ fuse_log(FUSE_LOG_ERR, "Failed to get all ring SQEs"); return -EIO; } ent->last_cmd = FUSE_IO_URING_CMD_REGISTER; fuse_uring_sqe_prepare(sqe, ent, ent->last_cmd); /* only needed for fetch */ ent->iov[0].iov_base = ent->req_header; ent->iov[0].iov_len = queue->req_header_sz; ent->iov[1].iov_base = ent->op_payload; ent->iov[1].iov_len = ent->req_payload_sz; sqe->addr = (uint64_t)(ent->iov); sqe->len = 2; /* this is a fetch, kernel does not read commit id */ fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid, 0); return 0; } static int fuse_uring_register_queue(struct fuse_ring_queue *queue) { struct fuse_ring_pool *ring_pool = queue->ring_pool; unsigned int sq_ready; struct io_uring_sqe *sqe; int res; for (size_t idx = 0; idx < ring_pool->queue_depth; idx++) { struct fuse_ring_ent *ent = &queue->ent[idx]; res = fuse_uring_register_ent(queue, ent); if (res != 0) return res; } sq_ready = io_uring_sq_ready(&queue->ring); if (sq_ready != ring_pool->queue_depth) { fuse_log(FUSE_LOG_ERR, "SQE ready mismatch, expected %zu got %u\n", ring_pool->queue_depth, sq_ready); return -EINVAL; } /* Poll SQE for the eventfd to wake up on teardown */ sqe = io_uring_get_sqe(&queue->ring); if (sqe == NULL) { fuse_log(FUSE_LOG_ERR, "Failed to get eventfd SQE"); return -EIO; } io_uring_prep_poll_add(sqe, queue->eventfd, POLLIN); io_uring_sqe_set_data(sqe, (void *)(uintptr_t)queue->eventfd); /* Only preparation until here, no submission yet */ return 0; } static struct fuse_ring_pool *fuse_create_ring(struct fuse_session *se) { struct fuse_ring_pool *fuse_ring = NULL; const size_t nr_queues = get_nprocs_conf(); size_t payload_sz = se->bufsize - FUSE_BUFFER_HEADER_SIZE; size_t queue_sz; if (se->debug) fuse_log(FUSE_LOG_DEBUG, "starting io-uring q-depth=%d\n", se->uring.q_depth); fuse_ring = calloc(1, sizeof(*fuse_ring)); if (fuse_ring == NULL) { fuse_log(FUSE_LOG_ERR, "Allocating the ring failed\n"); goto err; } queue_sz = fuse_ring_queue_size(se->uring.q_depth); fuse_ring->queues = calloc(1, queue_sz * nr_queues); if (fuse_ring->queues == NULL) { fuse_log(FUSE_LOG_ERR, "Allocating the queues failed\n"); goto err; } fuse_ring->se = se; fuse_ring->nr_queues = nr_queues; fuse_ring->queue_depth = se->uring.q_depth; fuse_ring->max_req_payload_sz = payload_sz; fuse_ring->queue_mem_size = queue_sz; /* * very basic queue initialization, that cannot fail and will * allow easy cleanup if something (like mmap) fails in the middle * below */ for (size_t qid = 0; qid < nr_queues; qid++) { struct fuse_ring_queue *queue = fuse_uring_get_queue(fuse_ring, qid); queue->ring.ring_fd = -1; queue->numa_node = numa_node_of_cpu(qid); queue->qid = qid; queue->ring_pool = fuse_ring; queue->eventfd = -1; pthread_mutex_init(&queue->ring_lock, NULL); } pthread_cond_init(&fuse_ring->thread_start_cond, NULL); pthread_mutex_init(&fuse_ring->thread_start_mutex, NULL); sem_init(&fuse_ring->init_sem, 0, 0); return fuse_ring; err: if (fuse_ring) fuse_session_destruct_uring(fuse_ring); return NULL; } static void fuse_uring_resubmit(struct fuse_ring_queue *queue, struct fuse_ring_ent *ent) { struct io_uring_sqe *sqe; sqe = io_uring_get_sqe(&queue->ring); if (sqe == NULL) { /* This is an impossible condition, unless there is a bug. * The kernel sent back an SQEs, which is assigned to a request. * There is no way to get out of SQEs, as the number of * SQEs matches the number tof requests. */ queue->ring_pool->se->error = -EIO; fuse_log(FUSE_LOG_ERR, "Failed to get a ring SQEs\n"); return; } fuse_uring_sqe_prepare(sqe, ent, ent->last_cmd); switch (ent->last_cmd) { case FUSE_IO_URING_CMD_REGISTER: sqe->addr = (uint64_t)(ent->iov); sqe->len = 2; fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid, 0); break; case FUSE_IO_URING_CMD_COMMIT_AND_FETCH: fuse_uring_sqe_set_req_data(fuse_uring_get_sqe_cmd(sqe), queue->qid, ent->req_commit_id); break; default: fuse_log(FUSE_LOG_ERR, "Unknown command type: %d\n", ent->last_cmd); queue->ring_pool->se->error = -EINVAL; break; } /* caller submits */ } static void fuse_uring_handle_cqe(struct fuse_ring_queue *queue, struct io_uring_cqe *cqe) { struct fuse_ring_ent *ent = io_uring_cqe_get_data(cqe); if (!ent) { fuse_log(FUSE_LOG_ERR, "cqe=%p io_uring_cqe_get_data returned NULL\n", cqe); return; } struct fuse_req *req = &ent->req; struct fuse_ring_pool *fuse_ring = queue->ring_pool; struct fuse_uring_req_header *rrh = ent->req_header; struct fuse_in_header *in = (struct fuse_in_header *)&rrh->in_out; struct fuse_uring_ent_in_out *ent_in_out = &rrh->ring_ent_in_out; ent->req_commit_id = ent_in_out->commit_id; if (unlikely(ent->req_commit_id == 0)) { /* * If this happens kernel will not find the response - it will * be stuck forever - better to abort immediately. */ fuse_log(FUSE_LOG_ERR, "Received invalid commit_id=0\n"); abort(); } memset(&req->flags, 0, sizeof(req->flags)); memset(&req->u, 0, sizeof(req->u)); req->flags.is_uring = 1; req->ref_cnt++; req->ch = NULL; /* not needed for uring */ req->interrupted = 0; list_init_req(req); fuse_session_process_uring_cqe(fuse_ring->se, req, in, &rrh->op_in, ent->op_payload, ent_in_out->payload_sz); } static int fuse_uring_queue_handle_cqes(struct fuse_ring_queue *queue) { struct fuse_ring_pool *ring_pool = queue->ring_pool; struct fuse_session *se = ring_pool->se; size_t num_completed = 0; struct io_uring_cqe *cqe; unsigned int head; struct fuse_ring_ent *ent; int ret = 0; io_uring_for_each_cqe(&queue->ring, head, cqe) { int err = 0; num_completed++; err = cqe->res; if (unlikely(err != 0)) { if (err > 0 && ((uintptr_t)io_uring_cqe_get_data(cqe) == (unsigned int)queue->eventfd)) { /* teardown from eventfd */ return -ENOTCONN; } switch (err) { case -EAGAIN: fallthrough; case -EINTR: ent = io_uring_cqe_get_data(cqe); fuse_uring_resubmit(queue, ent); continue; default: break; } /* -ENOTCONN is ok on umount */ if (err != -ENOTCONN) { se->error = cqe->res; /* return first error */ if (ret == 0) ret = err; } } else { fuse_uring_handle_cqe(queue, cqe); } } if (num_completed) io_uring_cq_advance(&queue->ring, num_completed); return ret == 0 ? 0 : num_completed; } /** * In per-core-queue configuration we have thread per core - the thread * to that core */ static void fuse_uring_set_thread_core(int qid) { cpu_set_t mask; int rc; CPU_ZERO(&mask); CPU_SET(qid, &mask); rc = sched_setaffinity(0, sizeof(cpu_set_t), &mask); if (rc != 0) fuse_log(FUSE_LOG_ERR, "Failed to bind qid=%d to its core: %s\n", qid, strerror(errno)); if (0) { const int policy = SCHED_IDLE; const struct sched_param param = { .sched_priority = sched_get_priority_min(policy), }; /* Set the lowest possible priority, so that the application * submitting requests is not moved away from the current core. */ rc = sched_setscheduler(0, policy, ¶m); if (rc != 0) fuse_log(FUSE_LOG_ERR, "Failed to set scheduler: %s\n", strerror(errno)); } } /* * @return negative error code or io-uring file descriptor */ static int fuse_uring_init_queue(struct fuse_ring_queue *queue) { struct fuse_ring_pool *ring = queue->ring_pool; struct fuse_session *se = ring->se; int res; size_t page_sz = sysconf(_SC_PAGESIZE); queue->eventfd = eventfd(0, EFD_CLOEXEC); if (queue->eventfd < 0) { res = -errno; fuse_log(FUSE_LOG_ERR, "Failed to create eventfd for qid %d: %s\n", queue->qid, strerror(errno)); return res; } res = fuse_queue_setup_io_uring(&queue->ring, queue->qid, ring->queue_depth, se->fd, queue->eventfd); if (res != 0) { fuse_log(FUSE_LOG_ERR, "qid=%d io_uring init failed\n", queue->qid); return res; } queue->req_header_sz = ROUND_UP(sizeof(struct fuse_uring_req_header), page_sz); for (size_t idx = 0; idx < ring->queue_depth; idx++) { struct fuse_ring_ent *ring_ent = &queue->ent[idx]; struct fuse_req *req = &ring_ent->req; ring_ent->ring_queue = queue; /* * Also allocate the header to have it page aligned, which * is a requirement for page pinning */ ring_ent->req_header = numa_alloc_local(queue->req_header_sz); if (!ring_ent->req_header) return -ENOMEM; ring_ent->req_payload_sz = ring->max_req_payload_sz; ring_ent->op_payload = numa_alloc_local(ring_ent->req_payload_sz); if (!ring_ent->op_payload) return -ENOMEM; req->se = se; pthread_mutex_init(&req->lock, NULL); req->flags.is_uring = 1; req->ref_cnt = 1; /* extra ref to avoid destruction */ list_init_req(req); } res = fuse_uring_register_queue(queue); if (res != 0) { fuse_log( FUSE_LOG_ERR, "Grave fuse-uring error on preparing SQEs, aborting\n"); se->error = -EIO; fuse_session_exit(se); return res; } return queue->ring.ring_fd; } static void *fuse_uring_thread(void *arg) { struct fuse_ring_queue *queue = arg; struct fuse_ring_pool *ring_pool = queue->ring_pool; struct fuse_session *se = ring_pool->se; int err; char thread_name[16] = { 0 }; snprintf(thread_name, 16, "fuse-ring-%d", queue->qid); thread_name[15] = '\0'; fuse_set_thread_name(thread_name); fuse_uring_set_thread_core(queue->qid); err = fuse_uring_init_queue(queue); pthread_mutex_lock(&ring_pool->thread_start_mutex); if (err < 0) ring_pool->failed_threads++; ring_pool->started_threads++; pthread_cond_broadcast(&ring_pool->thread_start_cond); pthread_mutex_unlock(&ring_pool->thread_start_mutex); if (err < 0) { fuse_log(FUSE_LOG_ERR, "qid=%d queue setup failed\n", queue->qid); goto err_non_fatal; } sem_wait(&ring_pool->init_sem); /* Not using fuse_session_exited(se), as that cannot be inlined */ while (!atomic_load_explicit(&se->mt_exited, memory_order_relaxed)) { io_uring_submit_and_wait(&queue->ring, 1); pthread_mutex_lock(&queue->ring_lock); queue->cqe_processing = true; err = fuse_uring_queue_handle_cqes(queue); queue->cqe_processing = false; pthread_mutex_unlock(&queue->ring_lock); if (err < 0) goto err; } return NULL; err: fuse_session_exit(se); err_non_fatal: return NULL; } static int fuse_uring_start_ring_threads(struct fuse_ring_pool *ring) { int rc = 0; for (size_t qid = 0; qid < ring->nr_queues; qid++) { struct fuse_ring_queue *queue = fuse_uring_get_queue(ring, qid); rc = pthread_create(&queue->tid, NULL, fuse_uring_thread, queue); if (rc != 0) break; } return rc; } static int fuse_uring_sanity_check(struct fuse_session *se) { if (se->uring.q_depth == 0) { fuse_log(FUSE_LOG_ERR, "io-uring queue depth must be > 0\n"); return -EINVAL; } _Static_assert(sizeof(struct fuse_uring_cmd_req) <= FUSE_URING_MAX_SQE128_CMD_DATA, "SQE128_CMD_DATA has 80B cmd data"); return 0; } int fuse_uring_start(struct fuse_session *se) { int err = 0; struct fuse_ring_pool *fuse_ring; fuse_uring_sanity_check(se); fuse_ring = fuse_create_ring(se); if (fuse_ring == NULL) { err = -EADDRNOTAVAIL; goto err; } se->uring.pool = fuse_ring; /* Hold off threads from send fuse ring entries (SQEs) */ sem_init(&fuse_ring->init_sem, 0, 0); pthread_cond_init(&fuse_ring->thread_start_cond, NULL); pthread_mutex_init(&fuse_ring->thread_start_mutex, NULL); err = fuse_uring_start_ring_threads(fuse_ring); if (err) goto err; /* * Wait for all threads to start or to fail */ pthread_mutex_lock(&fuse_ring->thread_start_mutex); while (fuse_ring->started_threads < fuse_ring->nr_queues) pthread_cond_wait(&fuse_ring->thread_start_cond, &fuse_ring->thread_start_mutex); if (fuse_ring->failed_threads != 0) err = -EADDRNOTAVAIL; pthread_mutex_unlock(&fuse_ring->thread_start_mutex); err: if (err) { /* Note all threads need to have been started */ if (fuse_ring) fuse_session_destruct_uring(fuse_ring); se->uring.pool = NULL; } return err; } int fuse_uring_stop(struct fuse_session *se) { struct fuse_ring_pool *ring = se->uring.pool; if (ring == NULL) return 0; fuse_session_destruct_uring(ring); return 0; } void fuse_uring_wake_ring_threads(struct fuse_session *se) { struct fuse_ring_pool *ring = se->uring.pool; /* Wake up the threads to let them send SQEs */ for (size_t qid = 0; qid < ring->nr_queues; qid++) sem_post(&ring->init_sem); } fuse-3.18.3/lib/fuse_uring_i.h0000644000175000017500000000407315250106036015115 0ustar berndbernd/* * FUSE: Filesystem in Userspace * Copyright (C) 2025 Bernd Schubert * This program can be distributed under the terms of the GNU LGPLv2. * See the file LGPL2.txt */ #ifndef FUSE_URING_I_H_ #define FUSE_URING_I_H_ #include "fuse_config.h" #include "fuse_lowlevel.h" #include "fuse_kernel.h" #ifndef HAVE_URING #include "util.h" #endif #include // IWYU pragma: keep /* io-uring defaults */ #define SESSION_DEF_URING_ENABLE (0) #define SESSION_DEF_URING_Q_DEPTH (8) void fuse_session_process_uring_cqe(struct fuse_session *se, struct fuse_req *req, struct fuse_in_header *in, void *in_header, void *in_payload, size_t payload_len); #ifdef HAVE_URING struct fuse_in_header; int fuse_uring_start(struct fuse_session *se); void fuse_uring_wake_ring_threads(struct fuse_session *se); int fuse_uring_stop(struct fuse_session *se); int send_reply_uring(fuse_req_t req, int error, const void *arg, size_t argsize); int fuse_reply_data_uring(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags); int fuse_send_msg_uring(fuse_req_t req, struct iovec *iov, int count); #else // HAVE_URING static inline int fuse_uring_start(struct fuse_session *se FUSE_VAR_UNUSED) { return -ENOTSUP; } static inline void fuse_uring_wake_ring_threads(struct fuse_session *se FUSE_VAR_UNUSED) { } static inline int fuse_uring_stop(struct fuse_session *se FUSE_VAR_UNUSED) { return -ENOTSUP; } static inline int send_reply_uring(fuse_req_t req FUSE_VAR_UNUSED, int error FUSE_VAR_UNUSED, const void *arg FUSE_VAR_UNUSED, size_t argsize FUSE_VAR_UNUSED) { return -ENOTSUP; } static inline int fuse_reply_data_uring(fuse_req_t req FUSE_VAR_UNUSED, struct fuse_bufvec *bufv FUSE_VAR_UNUSED, enum fuse_buf_copy_flags flags FUSE_VAR_UNUSED) { return -ENOTSUP; } static inline int fuse_send_msg_uring(fuse_req_t req FUSE_VAR_UNUSED, struct iovec *iov FUSE_VAR_UNUSED, int count FUSE_VAR_UNUSED) { return -ENOTSUP; } #endif // HAVE_URING #endif // FUSE_URING_I_H_ fuse-3.18.3/lib/fuse_versionscript0000644000175000017500000001033015250106036016136 0ustar berndberndFUSE_3.0 { global: fuse_destroy; fuse_exit; fuse_loop; fuse_loop_mt; fuse_reply_attr; fuse_reply_buf; fuse_reply_entry; fuse_reply_err; fuse_reply_none; fuse_reply_readlink; fuse_reply_write; fuse_reply_xattr; fuse_req_userdata; fuse_session_destroy; fuse_session_exit; fuse_session_exited; fuse_session_loop; fuse_session_loop_mt; fuse_session_reset; fuse_session_fd; fuse_opt_parse; fuse_opt_add_opt; fuse_opt_add_arg; fuse_opt_free_args; fuse_opt_match; fuse_parse_cmdline; fuse_remove_signal_handlers; fuse_reply_create; fuse_reply_open; fuse_reply_statfs; fuse_set_signal_handlers; fuse_add_direntry; fuse_add_direntry_plus; fuse_daemonize; fuse_get_session; fuse_interrupted; fuse_session_new; fuse_main_real; fuse_mount; fuse_session_custom_io; fuse_session_mount; fuse_new; fuse_opt_insert_arg; fuse_reply_lock; fuse_req_interrupt_func; fuse_req_interrupted; fuse_unmount; fuse_session_unmount; fuse_fs_access; fuse_fs_bmap; fuse_fs_chmod; fuse_fs_chown; fuse_fs_create; fuse_fs_destroy; fuse_fs_flush; fuse_fs_fsync; fuse_fs_fsyncdir; fuse_fs_getattr; fuse_fs_getxattr; fuse_fs_init; fuse_fs_link; fuse_fs_listxattr; fuse_fs_lock; fuse_fs_mkdir; fuse_fs_mknod; fuse_fs_new; fuse_fs_open; fuse_fs_opendir; fuse_fs_read; fuse_fs_readdir; fuse_fs_readlink; fuse_fs_release; fuse_fs_releasedir; fuse_fs_removexattr; fuse_fs_rename; fuse_fs_rmdir; fuse_fs_setxattr; fuse_fs_statfs; fuse_fs_symlink; fuse_fs_truncate; fuse_fs_unlink; fuse_fs_utimens; fuse_fs_write; fuse_reply_iov; fuse_version; fuse_pkgversion; fuse_reply_bmap; cuse_lowlevel_new; cuse_lowlevel_main; cuse_lowlevel_setup; cuse_lowlevel_teardown; fuse_fs_ioctl; fuse_fs_poll; fuse_get_context; fuse_getgroups; fuse_lowlevel_notify_inval_entry; fuse_lowlevel_notify_inval_inode; fuse_lowlevel_notify_poll; fuse_notify_poll; fuse_opt_add_opt_escaped; fuse_pollhandle_destroy; fuse_reply_ioctl; fuse_reply_ioctl_iov; fuse_reply_ioctl_retry; fuse_reply_poll; fuse_req_ctx; fuse_req_getgroups; fuse_buf_copy; fuse_buf_size; fuse_fs_read_buf; fuse_fs_write_buf; fuse_lowlevel_notify_retrieve; fuse_lowlevel_notify_store; fuse_reply_data; fuse_session_process_buf; fuse_session_receive_buf; fuse_start_cleanup_thread; fuse_stop_cleanup_thread; fuse_clean_cache; fuse_lowlevel_notify_delete; fuse_fs_flock; fuse_fs_fallocate; fuse_lowlevel_help; fuse_lowlevel_version; fuse_cmdline_help; fuse_apply_conn_info_opts; fuse_parse_conn_info_opts; fuse_fs_lseek; fuse_reply_lseek; local: *; }; FUSE_3.1 { global: fuse_lib_help; fuse_invalidate_path; fuse_new_30; fuse_new_31; fuse_new; } FUSE_3.0; FUSE_3.2 { global: fuse_session_loop_mt; fuse_session_loop_mt_31; fuse_session_loop_mt_32; fuse_loop_mt; fuse_loop_mt_31; } FUSE_3.1; FUSE_3.3 { global: fuse_open_channel; } FUSE_3.2; FUSE_3.4 { global: fuse_fs_copy_file_range; } FUSE_3.3; FUSE_3.7 { global: fuse_set_log_func; fuse_log; } FUSE_3.4; FUSE_3.12 { global: fuse_session_loop_mt; fuse_session_loop_mt_312; fuse_loop_mt; fuse_loop_mt_32; fuse_loop_mt_312; fuse_loop_cfg_create; fuse_loop_cfg_destroy; fuse_loop_cfg_set_idle_threads; fuse_loop_cfg_set_max_threads; fuse_loop_cfg_set_clone_fd; fuse_loop_cfg_convert; fuse_parse_cmdline; fuse_parse_cmdline_30; fuse_parse_cmdline_312; fuse_lowlevel_notify_expire_entry; } FUSE_3.4; FUSE_3.17 { global: fuse_main_real_versioned; fuse_session_new_versioned; _fuse_new_30; _fuse_new_31; fuse_passthrough_open; fuse_passthrough_close; fuse_session_custom_io_30; fuse_session_custom_io_317; fuse_set_fail_signal_handlers; fuse_log_enable_syslog; fuse_log_close_syslog; } FUSE_3.12; FUSE_3.17.3 { global: fuse_set_feature_flag; fuse_unset_feature_flag; fuse_get_feature_flag; # Not part of public API, for internal testing only fuse_convert_to_conn_want_ext; } FUSE_3.17; FUSE_3.18 { global: fuse_req_is_uring; fuse_req_get_payload; fuse_lowlevel_notify_increment_epoch; fuse_reply_statx; fuse_fs_statx; } FUSE_3.17; # Local Variables: # indent-tabs-mode: t # End: fuse-3.18.3/lib/helper.c0000644000175000017500000003372715250106036013721 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Helper functions to create (simple) standalone programs. With the aid of these functions it should be possible to create full FUSE file system by implementing nothing but the request handlers. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #include "fuse_config.h" #include "fuse_i.h" #include "fuse_misc.h" #include "fuse_opt.h" #include "fuse_lowlevel.h" #include "mount_util.h" #include #include #include #include #include #include #include #include #define FUSE_HELPER_OPT(t, p) \ { t, offsetof(struct fuse_cmdline_opts, p), 1 } static const struct fuse_opt fuse_helper_opts[] = { FUSE_HELPER_OPT("-h", show_help), FUSE_HELPER_OPT("--help", show_help), FUSE_HELPER_OPT("-V", show_version), FUSE_HELPER_OPT("--version", show_version), FUSE_HELPER_OPT("-d", debug), FUSE_HELPER_OPT("debug", debug), FUSE_HELPER_OPT("-d", foreground), FUSE_HELPER_OPT("debug", foreground), FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP), FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP), FUSE_HELPER_OPT("-f", foreground), FUSE_HELPER_OPT("-s", singlethread), FUSE_HELPER_OPT("fsname=", nodefault_subtype), FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_KEEP), #ifndef __FreeBSD__ FUSE_HELPER_OPT("subtype=", nodefault_subtype), FUSE_OPT_KEY("subtype=", FUSE_OPT_KEY_KEEP), #endif FUSE_HELPER_OPT("clone_fd", clone_fd), FUSE_HELPER_OPT("max_idle_threads=%u", max_idle_threads), FUSE_HELPER_OPT("max_threads=%u", max_threads), FUSE_OPT_END }; struct fuse_conn_info_opts { int atomic_o_trunc; int no_remote_posix_lock; int no_remote_flock; int splice_write; int splice_move; int splice_read; int no_splice_write; int no_splice_move; int no_splice_read; int auto_inval_data; int no_auto_inval_data; int no_readdirplus; int no_readdirplus_auto; int async_dio; int no_async_dio; int writeback_cache; int no_writeback_cache; int async_read; int sync_read; unsigned max_write; unsigned max_readahead; unsigned max_background; unsigned congestion_threshold; unsigned time_gran; int set_max_write; int set_max_readahead; int set_max_background; int set_congestion_threshold; int set_time_gran; }; #define CONN_OPTION(t, p, v) \ { t, offsetof(struct fuse_conn_info_opts, p), v } static const struct fuse_opt conn_info_opt_spec[] = { CONN_OPTION("max_write=%u", max_write, 0), CONN_OPTION("max_write=", set_max_write, 1), CONN_OPTION("max_readahead=%u", max_readahead, 0), CONN_OPTION("max_readahead=", set_max_readahead, 1), CONN_OPTION("max_background=%u", max_background, 0), CONN_OPTION("max_background=", set_max_background, 1), CONN_OPTION("congestion_threshold=%u", congestion_threshold, 0), CONN_OPTION("congestion_threshold=", set_congestion_threshold, 1), CONN_OPTION("sync_read", sync_read, 1), CONN_OPTION("async_read", async_read, 1), CONN_OPTION("atomic_o_trunc", atomic_o_trunc, 1), CONN_OPTION("no_remote_lock", no_remote_posix_lock, 1), CONN_OPTION("no_remote_lock", no_remote_flock, 1), CONN_OPTION("no_remote_flock", no_remote_flock, 1), CONN_OPTION("no_remote_posix_lock", no_remote_posix_lock, 1), CONN_OPTION("splice_write", splice_write, 1), CONN_OPTION("no_splice_write", no_splice_write, 1), CONN_OPTION("splice_move", splice_move, 1), CONN_OPTION("no_splice_move", no_splice_move, 1), CONN_OPTION("splice_read", splice_read, 1), CONN_OPTION("no_splice_read", no_splice_read, 1), CONN_OPTION("auto_inval_data", auto_inval_data, 1), CONN_OPTION("no_auto_inval_data", no_auto_inval_data, 1), CONN_OPTION("readdirplus=no", no_readdirplus, 1), CONN_OPTION("readdirplus=yes", no_readdirplus, 0), CONN_OPTION("readdirplus=yes", no_readdirplus_auto, 1), CONN_OPTION("readdirplus=auto", no_readdirplus, 0), CONN_OPTION("readdirplus=auto", no_readdirplus_auto, 0), CONN_OPTION("async_dio", async_dio, 1), CONN_OPTION("no_async_dio", no_async_dio, 1), CONN_OPTION("writeback_cache", writeback_cache, 1), CONN_OPTION("no_writeback_cache", no_writeback_cache, 1), CONN_OPTION("time_gran=%u", time_gran, 0), CONN_OPTION("time_gran=", set_time_gran, 1), FUSE_OPT_END }; void fuse_cmdline_help(void) { printf(" -h --help print help\n" " -V --version print version\n" " -d -o debug enable debug output (implies -f)\n" " -f foreground operation\n" " -s disable multi-threaded operation\n" " -o clone_fd use separate fuse device fd for each thread\n" " (may improve performance)\n" " -o max_idle_threads the maximum number of idle worker threads\n" " allowed (default: -1)\n" " -o max_threads the maximum number of worker threads\n" " allowed (default: 10)\n"); } static int fuse_helper_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) outargs; struct fuse_cmdline_opts *opts = data; switch (key) { case FUSE_OPT_KEY_NONOPT: if (!opts->mountpoint) { if (fuse_mnt_parse_fuse_fd(arg) != -1) { return fuse_opt_add_opt(&opts->mountpoint, arg); } char mountpoint[PATH_MAX] = ""; if (realpath(arg, mountpoint) == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: bad mount point `%s': %s\n", arg, strerror(errno)); return -1; } return fuse_opt_add_opt(&opts->mountpoint, mountpoint); } else { fuse_log(FUSE_LOG_ERR, "fuse: invalid argument `%s'\n", arg); return -1; } default: /* Pass through unknown options */ return 1; } } /* Under FreeBSD, there is no subtype option so this function actually sets the fsname */ static int add_default_subtype(const char *progname, struct fuse_args *args) { int res; char *subtype_opt; const char *basename = strrchr(progname, '/'); if (basename == NULL) basename = progname; else if (basename[1] != '\0') basename++; subtype_opt = (char *) malloc(strlen(basename) + 64); if (subtype_opt == NULL) { fuse_log(FUSE_LOG_ERR, "fuse: memory allocation failed\n"); return -1; } #ifdef __FreeBSD__ sprintf(subtype_opt, "-ofsname=%s", basename); #else sprintf(subtype_opt, "-osubtype=%s", basename); #endif res = fuse_opt_add_arg(args, subtype_opt); free(subtype_opt); return res; } int fuse_parse_cmdline_312(struct fuse_args *args, struct fuse_cmdline_opts *opts); FUSE_SYMVER("fuse_parse_cmdline_312", "fuse_parse_cmdline@@FUSE_3.12") int fuse_parse_cmdline_312(struct fuse_args *args, struct fuse_cmdline_opts *opts) { memset(opts, 0, sizeof(struct fuse_cmdline_opts)); opts->max_idle_threads = UINT_MAX; /* new default in fuse version 3.12 */ opts->max_threads = 10; if (fuse_opt_parse(args, opts, fuse_helper_opts, fuse_helper_opt_proc) == -1) return -1; /* *Linux*: if neither -o subtype nor -o fsname are specified, set subtype to program's basename. *FreeBSD*: if fsname is not specified, set to program's basename. */ if (!opts->nodefault_subtype) if (add_default_subtype(args->argv[0], args) == -1) return -1; return 0; } /** * struct fuse_cmdline_opts got extended in libfuse-3.12 */ int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *opts); FUSE_SYMVER("fuse_parse_cmdline_30", "fuse_parse_cmdline@FUSE_3.0") int fuse_parse_cmdline_30(struct fuse_args *args, struct fuse_cmdline_opts *out_opts) { struct fuse_cmdline_opts opts; int rc = fuse_parse_cmdline_312(args, &opts); if (rc == 0) { /* copy up to the size of the old pre 3.12 struct */ memcpy(out_opts, &opts, offsetof(struct fuse_cmdline_opts, max_idle_threads) + sizeof(opts.max_idle_threads)); } return rc; } int fuse_daemonize(int foreground) { if (!foreground) { int nullfd; int waiter[2]; char completed; if (pipe(waiter)) { perror("fuse_daemonize: pipe"); return -1; } /* * demonize current process by forking it and killing the * parent. This makes current process as a child of 'init'. */ switch(fork()) { case -1: perror("fuse_daemonize: fork"); close(waiter[0]); close(waiter[1]); return -1; case 0: /* child */ close(waiter[0]); waiter[0] = -1; break; default: /* parent */ (void) read(waiter[0], &completed, sizeof(completed)); close(waiter[0]); close(waiter[1]); _exit(0); } if (setsid() == -1) { perror("fuse_daemonize: setsid"); close(waiter[1]); return -1; } (void) chdir("/"); nullfd = open("/dev/null", O_RDWR, 0); if (nullfd != -1) { (void) dup2(nullfd, 0); (void) dup2(nullfd, 1); (void) dup2(nullfd, 2); if (nullfd > 2) close(nullfd); } /* Propagate completion of daemon initialization */ completed = 1; (void) write(waiter[1], &completed, sizeof(completed)); close(waiter[1]); waiter[1] = -1; } else { (void)chdir("/"); } return 0; } int fuse_main_real_versioned(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse *fuse; struct fuse_cmdline_opts opts; int res; struct fuse_loop_config *loop_config = NULL; if (fuse_parse_cmdline(&args, &opts) != 0) return 1; if (opts.show_version) { printf("FUSE library version %s\n", PACKAGE_VERSION); fuse_lowlevel_version(); res = 0; goto out1; } if (opts.show_help) { if(args.argv[0][0] != '\0') printf("usage: %s [options] \n\n", args.argv[0]); printf("FUSE options:\n"); fuse_cmdline_help(); fuse_lib_help(&args); res = 0; goto out1; } if (!opts.show_help && !opts.mountpoint) { fuse_log(FUSE_LOG_ERR, "error: no mountpoint specified\n"); res = 2; goto out1; } struct fuse *_fuse_new_31(struct fuse_args *args, const struct fuse_operations *op, size_t op_size, struct libfuse_version *version, void *user_data); fuse = _fuse_new_31(&args, op, op_size, version, user_data); if (fuse == NULL) { res = 3; goto out1; } if (fuse_mount(fuse,opts.mountpoint) != 0) { res = 4; goto out2; } if (fuse_daemonize(opts.foreground) != 0) { res = 5; goto out3; } struct fuse_session *se = fuse_get_session(fuse); if (fuse_set_signal_handlers(se) != 0) { res = 6; goto out3; } if (opts.singlethread) res = fuse_loop(fuse); else { loop_config = fuse_loop_cfg_create(); if (loop_config == NULL) { res = 7; goto out3; } fuse_loop_cfg_set_clone_fd(loop_config, opts.clone_fd); fuse_loop_cfg_set_idle_threads(loop_config, opts.max_idle_threads); fuse_loop_cfg_set_max_threads(loop_config, opts.max_threads); res = fuse_loop_mt(fuse, loop_config); } if (res) res = 8; fuse_remove_signal_handlers(se); out3: fuse_unmount(fuse); out2: fuse_destroy(fuse); out1: fuse_loop_cfg_destroy(loop_config); free(opts.mountpoint); fuse_opt_free_args(&args); return res; } /* Not symboled, as not part of the official API */ int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data); int fuse_main_real_30(int argc, char *argv[], const struct fuse_operations *op, size_t op_size, void *user_data) { struct libfuse_version version = { 0 }; return fuse_main_real_versioned(argc, argv, op, op_size, &version, user_data); } void fuse_apply_conn_info_opts(struct fuse_conn_info_opts *opts, struct fuse_conn_info *conn) { if(opts->set_max_write) conn->max_write = opts->max_write; if(opts->set_max_background) conn->max_background = opts->max_background; if(opts->set_congestion_threshold) conn->congestion_threshold = opts->congestion_threshold; if(opts->set_time_gran) conn->time_gran = opts->time_gran; if(opts->set_max_readahead) conn->max_readahead = opts->max_readahead; #define LL_ENABLE(cond, cap) \ do { \ if (cond) \ fuse_set_feature_flag(conn, cap); \ } while (0) #define LL_DISABLE(cond, cap) \ do { \ if (cond) \ fuse_unset_feature_flag(conn, cap); \ } while (0) LL_ENABLE(opts->splice_read, FUSE_CAP_SPLICE_READ); LL_DISABLE(opts->no_splice_read, FUSE_CAP_SPLICE_READ); LL_ENABLE(opts->splice_write, FUSE_CAP_SPLICE_WRITE); LL_DISABLE(opts->no_splice_write, FUSE_CAP_SPLICE_WRITE); LL_ENABLE(opts->splice_move, FUSE_CAP_SPLICE_MOVE); LL_DISABLE(opts->no_splice_move, FUSE_CAP_SPLICE_MOVE); LL_ENABLE(opts->auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA); LL_DISABLE(opts->no_auto_inval_data, FUSE_CAP_AUTO_INVAL_DATA); LL_DISABLE(opts->no_readdirplus, FUSE_CAP_READDIRPLUS); LL_DISABLE(opts->no_readdirplus_auto, FUSE_CAP_READDIRPLUS_AUTO); LL_ENABLE(opts->async_dio, FUSE_CAP_ASYNC_DIO); LL_DISABLE(opts->no_async_dio, FUSE_CAP_ASYNC_DIO); LL_ENABLE(opts->writeback_cache, FUSE_CAP_WRITEBACK_CACHE); LL_DISABLE(opts->no_writeback_cache, FUSE_CAP_WRITEBACK_CACHE); LL_ENABLE(opts->async_read, FUSE_CAP_ASYNC_READ); LL_DISABLE(opts->sync_read, FUSE_CAP_ASYNC_READ); LL_DISABLE(opts->no_remote_posix_lock, FUSE_CAP_POSIX_LOCKS); LL_DISABLE(opts->no_remote_flock, FUSE_CAP_FLOCK_LOCKS); } struct fuse_conn_info_opts* fuse_parse_conn_info_opts(struct fuse_args *args) { struct fuse_conn_info_opts *opts; opts = calloc(1, sizeof(struct fuse_conn_info_opts)); if(opts == NULL) { fuse_log(FUSE_LOG_ERR, "calloc failed\n"); return NULL; } if(fuse_opt_parse(args, opts, conn_info_opt_spec, NULL) == -1) { free(opts); return NULL; } return opts; } int fuse_open_channel(const char *mountpoint, const char* options) { struct mount_opts *opts = NULL; int fd = -1; const char *argv[] = { "", "-o", options }; int argc = sizeof(argv) / sizeof(argv[0]); struct fuse_args args = FUSE_ARGS_INIT(argc, (char**) argv); opts = parse_mount_opts(&args); if (opts == NULL) return -1; fd = fuse_kern_mount(mountpoint, opts); destroy_mount_opts(opts); return fd; } fuse-3.18.3/lib/meson.build0000644000175000017500000000431215250106036014424 0ustar berndberndlibfuse_sources = ['fuse.c', 'fuse_i.h', 'fuse_loop.c', 'fuse_loop_mt.c', 'fuse_lowlevel.c', 'fuse_misc.h', 'fuse_opt.c', 'fuse_signals.c', 'buffer.c', 'cuse_lowlevel.c', 'helper.c', 'modules/subdir.c', 'mount_util.c', 'fuse_log.c', 'compat.c', 'util.c', 'util.h' ] if host_machine.system().startswith('linux') libfuse_sources += [ 'mount.c' ] else libfuse_sources += [ 'mount_bsd.c' ] endif deps = [ thread_dep ] if private_cfg.get('HAVE_ICONV') libfuse_sources += [ 'modules/iconv.c' ] libiconv = cc.find_library('iconv', required: false) if libiconv.found() deps += [ libiconv ] endif endif if private_cfg.get('HAVE_URING', false) libfuse_sources += [ 'fuse_uring.c' ] deps += [ dependency('liburing') ] deps += [ dependency('numa') ] endif libdl = cc.find_library('dl', required: false) if libdl.found() deps += [ libdl ] endif if host_machine.system().startswith('netbsd') deps += [ cc.find_library('perfuse'), cc.find_library('puffs') ] else # Required for clock_gettime before glibc 2.17 deps += cc.find_library('rt') endif fusermount_path = join_paths(get_option('prefix'), get_option('bindir')) libfuse = library('fuse3', libfuse_sources, version: base_version, soversion: '4', include_directories: include_dirs, dependencies: deps, install: true, link_depends: 'fuse_versionscript', c_args: [ '-DFUSE_USE_VERSION=317', '-DFUSERMOUNT_DIR="@0@"'.format(fusermount_path) ], link_args: ['-Wl,--version-script,' + meson.current_source_dir() + '/fuse_versionscript' ]) pkg = import('pkgconfig') pkg.generate(libraries: [ libfuse, '-lpthread' ], libraries_private: '-ldl', version: meson.project_version(), name: 'fuse3', description: 'Filesystem in Userspace', subdirs: 'fuse3') libfuse_dep = declare_dependency(include_directories: include_dirs, link_with: libfuse, dependencies: deps) fuse-3.18.3/lib/modules/0000755000175000017500000000000015250106036013732 5ustar berndberndfuse-3.18.3/lib/modules/iconv.c0000644000175000017500000004055115250106036015221 0ustar berndbernd/* fuse iconv module: file name charset conversion Copyright (C) 2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include #include #include #include #include #include #include #include #include #include #include struct iconv { struct fuse_fs *next; pthread_mutex_t lock; char *from_code; char *to_code; iconv_t tofs; iconv_t fromfs; }; struct iconv_dh { struct iconv *ic; void *prev_buf; fuse_fill_dir_t prev_filler; }; static struct iconv *iconv_get(void) { return fuse_get_context()->private_data; } static int iconv_convpath(struct iconv *ic, const char *path, char **newpathp, int fromfs) { size_t pathlen; size_t newpathlen; char *newpath; size_t plen; char *p; size_t res; int err; if (path == NULL) { *newpathp = NULL; return 0; } pathlen = strlen(path); newpathlen = pathlen * 4; newpath = malloc(newpathlen + 1); if (!newpath) return -ENOMEM; plen = newpathlen; p = newpath; pthread_mutex_lock(&ic->lock); do { res = iconv(fromfs ? ic->fromfs : ic->tofs, (char **) &path, &pathlen, &p, &plen); if (res == (size_t) -1) { char *tmp; size_t inc; err = -EILSEQ; if (errno != E2BIG) goto err; inc = (pathlen + 1) * 4; newpathlen += inc; int dp = p - newpath; tmp = realloc(newpath, newpathlen + 1); err = -ENOMEM; if (!tmp) goto err; p = tmp + dp; plen += inc; newpath = tmp; } } while (res == (size_t) -1); pthread_mutex_unlock(&ic->lock); *p = '\0'; *newpathp = newpath; return 0; err: iconv(fromfs ? ic->fromfs : ic->tofs, NULL, NULL, NULL, NULL); pthread_mutex_unlock(&ic->lock); free(newpath); return err; } static int iconv_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_getattr(ic->next, newpath, stbuf, fi); free(newpath); } return err; } static int iconv_access(const char *path, int mask) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_access(ic->next, newpath, mask); free(newpath); } return err; } static int iconv_readlink(const char *path, char *buf, size_t size) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_readlink(ic->next, newpath, buf, size); if (!err) { char *newlink; err = iconv_convpath(ic, buf, &newlink, 1); if (!err) { strncpy(buf, newlink, size - 1); buf[size - 1] = '\0'; free(newlink); } } free(newpath); } return err; } static int iconv_opendir(const char *path, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_opendir(ic->next, newpath, fi); free(newpath); } return err; } static int iconv_dir_fill(void *buf, const char *name, const struct stat *stbuf, off_t off, enum fuse_fill_dir_flags flags) { struct iconv_dh *dh = buf; char *newname; int res = 0; if (iconv_convpath(dh->ic, name, &newname, 1) == 0) { res = dh->prev_filler(dh->prev_buf, newname, stbuf, off, flags); free(newname); } return res; } static int iconv_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 iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { struct iconv_dh dh; dh.ic = ic; dh.prev_buf = buf; dh.prev_filler = filler; err = fuse_fs_readdir(ic->next, newpath, &dh, iconv_dir_fill, offset, fi, flags); free(newpath); } return err; } static int iconv_releasedir(const char *path, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_releasedir(ic->next, newpath, fi); free(newpath); } return err; } static int iconv_mknod(const char *path, mode_t mode, dev_t rdev) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_mknod(ic->next, newpath, mode, rdev); free(newpath); } return err; } static int iconv_mkdir(const char *path, mode_t mode) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_mkdir(ic->next, newpath, mode); free(newpath); } return err; } static int iconv_unlink(const char *path) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_unlink(ic->next, newpath); free(newpath); } return err; } static int iconv_rmdir(const char *path) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_rmdir(ic->next, newpath); free(newpath); } return err; } static int iconv_symlink(const char *from, const char *to) { struct iconv *ic = iconv_get(); char *newfrom; char *newto; int err = iconv_convpath(ic, from, &newfrom, 0); if (!err) { err = iconv_convpath(ic, to, &newto, 0); if (!err) { err = fuse_fs_symlink(ic->next, newfrom, newto); free(newto); } free(newfrom); } return err; } static int iconv_rename(const char *from, const char *to, unsigned int flags) { struct iconv *ic = iconv_get(); char *newfrom; char *newto; int err = iconv_convpath(ic, from, &newfrom, 0); if (!err) { err = iconv_convpath(ic, to, &newto, 0); if (!err) { err = fuse_fs_rename(ic->next, newfrom, newto, flags); free(newto); } free(newfrom); } return err; } static int iconv_link(const char *from, const char *to) { struct iconv *ic = iconv_get(); char *newfrom; char *newto; int err = iconv_convpath(ic, from, &newfrom, 0); if (!err) { err = iconv_convpath(ic, to, &newto, 0); if (!err) { err = fuse_fs_link(ic->next, newfrom, newto); free(newto); } free(newfrom); } return err; } static int iconv_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_chmod(ic->next, newpath, mode, fi); free(newpath); } return err; } static int iconv_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_chown(ic->next, newpath, uid, gid, fi); free(newpath); } return err; } static int iconv_truncate(const char *path, off_t size, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_truncate(ic->next, newpath, size, fi); free(newpath); } return err; } static int iconv_utimens(const char *path, const struct timespec ts[2], struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_utimens(ic->next, newpath, ts, fi); free(newpath); } return err; } static int iconv_create(const char *path, mode_t mode, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_create(ic->next, newpath, mode, fi); free(newpath); } return err; } static int iconv_open_file(const char *path, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_open(ic->next, newpath, fi); free(newpath); } return err; } static int iconv_read_buf(const char *path, struct fuse_bufvec **bufp, size_t size, off_t offset, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_read_buf(ic->next, newpath, bufp, size, offset, fi); free(newpath); } return err; } static int iconv_write_buf(const char *path, struct fuse_bufvec *buf, off_t offset, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_write_buf(ic->next, newpath, buf, offset, fi); free(newpath); } return err; } static int iconv_statfs(const char *path, struct statvfs *stbuf) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_statfs(ic->next, newpath, stbuf); free(newpath); } return err; } static int iconv_flush(const char *path, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_flush(ic->next, newpath, fi); free(newpath); } return err; } static int iconv_release(const char *path, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_release(ic->next, newpath, fi); free(newpath); } return err; } static int iconv_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_fsync(ic->next, newpath, isdatasync, fi); free(newpath); } return err; } static int iconv_fsyncdir(const char *path, int isdatasync, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_fsyncdir(ic->next, newpath, isdatasync, fi); free(newpath); } return err; } static int iconv_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_setxattr(ic->next, newpath, name, value, size, flags); free(newpath); } return err; } static int iconv_getxattr(const char *path, const char *name, char *value, size_t size) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_getxattr(ic->next, newpath, name, value, size); free(newpath); } return err; } static int iconv_listxattr(const char *path, char *list, size_t size) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_listxattr(ic->next, newpath, list, size); free(newpath); } return err; } static int iconv_removexattr(const char *path, const char *name) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_removexattr(ic->next, newpath, name); free(newpath); } return err; } static int iconv_lock(const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_lock(ic->next, newpath, fi, cmd, lock); free(newpath); } return err; } static int iconv_flock(const char *path, struct fuse_file_info *fi, int op) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_flock(ic->next, newpath, fi, op); free(newpath); } return err; } static int iconv_bmap(const char *path, size_t blocksize, uint64_t *idx) { struct iconv *ic = iconv_get(); char *newpath; int err = iconv_convpath(ic, path, &newpath, 0); if (!err) { err = fuse_fs_bmap(ic->next, newpath, blocksize, idx); free(newpath); } return err; } static off_t iconv_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int res = iconv_convpath(ic, path, &newpath, 0); if (!res) { res = fuse_fs_lseek(ic->next, newpath, off, whence, fi); free(newpath); } return res; } #ifdef HAVE_STATX static int iconv_statx(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { struct iconv *ic = iconv_get(); char *newpath; int res = iconv_convpath(ic, path, &newpath, 0); if (!res) { res = fuse_fs_statx(ic->next, newpath, flags, mask, stxbuf, fi); free(newpath); } return res; } #endif static void *iconv_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { struct iconv *ic = iconv_get(); fuse_fs_init(ic->next, conn, cfg); /* Don't touch cfg->nullpath_ok, we can work with either */ return ic; } static void iconv_destroy(void *data) { struct iconv *ic = data; fuse_fs_destroy(ic->next); iconv_close(ic->tofs); iconv_close(ic->fromfs); pthread_mutex_destroy(&ic->lock); free(ic->from_code); free(ic->to_code); free(ic); } static const struct fuse_operations iconv_oper = { .destroy = iconv_destroy, .init = iconv_init, .getattr = iconv_getattr, .access = iconv_access, .readlink = iconv_readlink, .opendir = iconv_opendir, .readdir = iconv_readdir, .releasedir = iconv_releasedir, .mknod = iconv_mknod, .mkdir = iconv_mkdir, .symlink = iconv_symlink, .unlink = iconv_unlink, .rmdir = iconv_rmdir, .rename = iconv_rename, .link = iconv_link, .chmod = iconv_chmod, .chown = iconv_chown, .truncate = iconv_truncate, .utimens = iconv_utimens, .create = iconv_create, .open = iconv_open_file, .read_buf = iconv_read_buf, .write_buf = iconv_write_buf, .statfs = iconv_statfs, .flush = iconv_flush, .release = iconv_release, .fsync = iconv_fsync, .fsyncdir = iconv_fsyncdir, .setxattr = iconv_setxattr, .getxattr = iconv_getxattr, .listxattr = iconv_listxattr, .removexattr = iconv_removexattr, .lock = iconv_lock, .flock = iconv_flock, .bmap = iconv_bmap, .lseek = iconv_lseek, #ifdef HAVE_STATX .statx = iconv_statx, #endif }; static const struct fuse_opt iconv_opts[] = { FUSE_OPT_KEY("-h", 0), FUSE_OPT_KEY("--help", 0), { "from_code=%s", offsetof(struct iconv, from_code), 0 }, { "to_code=%s", offsetof(struct iconv, to_code), 1 }, FUSE_OPT_END }; static void iconv_help(void) { char *charmap; const char *old = setlocale(LC_CTYPE, ""); charmap = strdup(nl_langinfo(CODESET)); if (old) setlocale(LC_CTYPE, old); else perror("setlocale"); printf( " -o from_code=CHARSET original encoding of file names (default: UTF-8)\n" " -o to_code=CHARSET new encoding of the file names (default: %s)\n", charmap); free(charmap); } static int iconv_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) data; (void) arg; (void) outargs; if (!key) { iconv_help(); return -1; } return 1; } static struct fuse_fs *iconv_new(struct fuse_args *args, struct fuse_fs *next[]) { struct fuse_fs *fs; struct iconv *ic; const char *old = NULL; const char *from; const char *to; ic = calloc(1, sizeof(struct iconv)); if (ic == NULL) { fuse_log(FUSE_LOG_ERR, "fuse-iconv: memory allocation failed\n"); return NULL; } if (fuse_opt_parse(args, ic, iconv_opts, iconv_opt_proc) == -1) goto out_free; if (!next[0] || next[1]) { fuse_log(FUSE_LOG_ERR, "fuse-iconv: exactly one next filesystem required\n"); goto out_free; } from = ic->from_code ? ic->from_code : "UTF-8"; to = ic->to_code ? ic->to_code : ""; /* FIXME: detect charset equivalence? */ if (!to[0]) old = setlocale(LC_CTYPE, ""); ic->tofs = iconv_open(from, to); if (ic->tofs == (iconv_t) -1) { fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n", to, from); goto out_free; } ic->fromfs = iconv_open(to, from); if (ic->fromfs == (iconv_t) -1) { fuse_log(FUSE_LOG_ERR, "fuse-iconv: cannot convert from %s to %s\n", from, to); goto out_iconv_close_to; } if (old) { setlocale(LC_CTYPE, old); old = NULL; } ic->next = next[0]; fs = fuse_fs_new(&iconv_oper, sizeof(iconv_oper), ic); if (!fs) goto out_iconv_close_from; return fs; out_iconv_close_from: iconv_close(ic->fromfs); out_iconv_close_to: iconv_close(ic->tofs); out_free: free(ic->from_code); free(ic->to_code); free(ic); if (old) { setlocale(LC_CTYPE, old); } return NULL; } FUSE_REGISTER_MODULE(iconv, iconv_new); fuse-3.18.3/lib/modules/subdir.c0000644000175000017500000003626715250106036015404 0ustar berndbernd/* fuse subdir module: offset paths with a base directory Copyright (C) 2007 Miklos Szeredi This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt */ #include #include #include #include #include #include #include struct subdir { char *base; size_t baselen; int rellinks; struct fuse_fs *next; }; static struct subdir *subdir_get(void) { return fuse_get_context()->private_data; } static int subdir_addpath(struct subdir *d, const char *path, char **newpathp) { char *newpath = NULL; if (path != NULL) { unsigned newlen = d->baselen + strlen(path); newpath = malloc(newlen + 2); if (!newpath) return -ENOMEM; if (path[0] == '/') path++; strcpy(newpath, d->base); strcpy(newpath + d->baselen, path); if (!newpath[0]) strcpy(newpath, "."); } *newpathp = newpath; return 0; } static int subdir_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_getattr(d->next, newpath, stbuf, fi); free(newpath); } return err; } static int subdir_access(const char *path, int mask) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_access(d->next, newpath, mask); free(newpath); } return err; } static int count_components(const char *p) { int ctr; for (; *p == '/'; p++); for (ctr = 0; *p; ctr++) { for (; *p && *p != '/'; p++); for (; *p == '/'; p++); } return ctr; } static void strip_common(const char **sp, const char **tp) { const char *s = *sp; const char *t = *tp; do { for (; *s == '/'; s++); for (; *t == '/'; t++); *tp = t; *sp = s; for (; *s == *t && *s && *s != '/'; s++, t++); } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); } static void transform_symlink(struct subdir *d, const char *path, char *buf, size_t size) { const char *l = buf; size_t llen; char *s; int dotdots; int i; if (l[0] != '/' || d->base[0] != '/') return; strip_common(&l, &path); if (l - buf < (long) d->baselen) return; dotdots = count_components(path); if (!dotdots) return; dotdots--; llen = strlen(l); if (dotdots * 3 + llen + 2 > size) return; s = buf + dotdots * 3; if (llen) memmove(s, l, llen + 1); else if (!dotdots) strcpy(s, "."); else *s = '\0'; for (s = buf, i = 0; i < dotdots; i++, s += 3) memcpy(s, "../", 3); } static int subdir_readlink(const char *path, char *buf, size_t size) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_readlink(d->next, newpath, buf, size); if (!err && d->rellinks) transform_symlink(d, newpath, buf, size); free(newpath); } return err; } static int subdir_opendir(const char *path, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_opendir(d->next, newpath, fi); free(newpath); } return err; } static int subdir_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 subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_readdir(d->next, newpath, buf, filler, offset, fi, flags); free(newpath); } return err; } static int subdir_releasedir(const char *path, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_releasedir(d->next, newpath, fi); free(newpath); } return err; } static int subdir_mknod(const char *path, mode_t mode, dev_t rdev) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_mknod(d->next, newpath, mode, rdev); free(newpath); } return err; } static int subdir_mkdir(const char *path, mode_t mode) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_mkdir(d->next, newpath, mode); free(newpath); } return err; } static int subdir_unlink(const char *path) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_unlink(d->next, newpath); free(newpath); } return err; } static int subdir_rmdir(const char *path) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_rmdir(d->next, newpath); free(newpath); } return err; } static int subdir_symlink(const char *from, const char *path) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_symlink(d->next, from, newpath); free(newpath); } return err; } static int subdir_rename(const char *from, const char *to, unsigned int flags) { struct subdir *d = subdir_get(); char *newfrom; char *newto; int err = subdir_addpath(d, from, &newfrom); if (!err) { err = subdir_addpath(d, to, &newto); if (!err) { err = fuse_fs_rename(d->next, newfrom, newto, flags); free(newto); } free(newfrom); } return err; } static int subdir_link(const char *from, const char *to) { struct subdir *d = subdir_get(); char *newfrom; char *newto; int err = subdir_addpath(d, from, &newfrom); if (!err) { err = subdir_addpath(d, to, &newto); if (!err) { err = fuse_fs_link(d->next, newfrom, newto); free(newto); } free(newfrom); } return err; } static int subdir_chmod(const char *path, mode_t mode, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_chmod(d->next, newpath, mode, fi); free(newpath); } return err; } static int subdir_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_chown(d->next, newpath, uid, gid, fi); free(newpath); } return err; } static int subdir_truncate(const char *path, off_t size, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_truncate(d->next, newpath, size, fi); free(newpath); } return err; } static int subdir_utimens(const char *path, const struct timespec ts[2], struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_utimens(d->next, newpath, ts, fi); free(newpath); } return err; } static int subdir_create(const char *path, mode_t mode, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_create(d->next, newpath, mode, fi); free(newpath); } return err; } static int subdir_open(const char *path, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_open(d->next, newpath, fi); free(newpath); } return err; } static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp, size_t size, off_t offset, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi); free(newpath); } return err; } static int subdir_write_buf(const char *path, struct fuse_bufvec *buf, off_t offset, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi); free(newpath); } return err; } static int subdir_statfs(const char *path, struct statvfs *stbuf) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_statfs(d->next, newpath, stbuf); free(newpath); } return err; } static int subdir_flush(const char *path, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_flush(d->next, newpath, fi); free(newpath); } return err; } static int subdir_release(const char *path, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_release(d->next, newpath, fi); free(newpath); } return err; } static int subdir_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_fsync(d->next, newpath, isdatasync, fi); free(newpath); } return err; } static int subdir_fsyncdir(const char *path, int isdatasync, struct fuse_file_info *fi) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi); free(newpath); } return err; } static int subdir_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_setxattr(d->next, newpath, name, value, size, flags); free(newpath); } return err; } static int subdir_getxattr(const char *path, const char *name, char *value, size_t size) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_getxattr(d->next, newpath, name, value, size); free(newpath); } return err; } static int subdir_listxattr(const char *path, char *list, size_t size) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_listxattr(d->next, newpath, list, size); free(newpath); } return err; } static int subdir_removexattr(const char *path, const char *name) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_removexattr(d->next, newpath, name); free(newpath); } return err; } static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd, struct flock *lock) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_lock(d->next, newpath, fi, cmd, lock); free(newpath); } return err; } static int subdir_flock(const char *path, struct fuse_file_info *fi, int op) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_flock(d->next, newpath, fi, op); free(newpath); } return err; } static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx) { struct subdir *d = subdir_get(); char *newpath; int err = subdir_addpath(d, path, &newpath); if (!err) { err = fuse_fs_bmap(d->next, newpath, blocksize, idx); free(newpath); } return err; } static off_t subdir_lseek(const char *path, off_t off, int whence, struct fuse_file_info *fi) { struct subdir *ic = subdir_get(); char *newpath; int res = subdir_addpath(ic, path, &newpath); if (!res) { res = fuse_fs_lseek(ic->next, newpath, off, whence, fi); free(newpath); } return res; } #ifdef HAVE_STATX static int subdir_statx(const char *path, int flags, int mask, struct statx *stxbuf, struct fuse_file_info *fi) { struct subdir *ic = subdir_get(); char *newpath; int res = subdir_addpath(ic, path, &newpath); if (!res) { res = fuse_fs_statx(ic->next, newpath, flags, mask, stxbuf, fi); free(newpath); } return res; } #endif static void *subdir_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { struct subdir *d = subdir_get(); fuse_fs_init(d->next, conn, cfg); /* Don't touch cfg->nullpath_ok, we can work with either */ return d; } static void subdir_destroy(void *data) { struct subdir *d = data; fuse_fs_destroy(d->next); free(d->base); free(d); } static const struct fuse_operations subdir_oper = { .destroy = subdir_destroy, .init = subdir_init, .getattr = subdir_getattr, .access = subdir_access, .readlink = subdir_readlink, .opendir = subdir_opendir, .readdir = subdir_readdir, .releasedir = subdir_releasedir, .mknod = subdir_mknod, .mkdir = subdir_mkdir, .symlink = subdir_symlink, .unlink = subdir_unlink, .rmdir = subdir_rmdir, .rename = subdir_rename, .link = subdir_link, .chmod = subdir_chmod, .chown = subdir_chown, .truncate = subdir_truncate, .utimens = subdir_utimens, .create = subdir_create, .open = subdir_open, .read_buf = subdir_read_buf, .write_buf = subdir_write_buf, .statfs = subdir_statfs, .flush = subdir_flush, .release = subdir_release, .fsync = subdir_fsync, .fsyncdir = subdir_fsyncdir, .setxattr = subdir_setxattr, .getxattr = subdir_getxattr, .listxattr = subdir_listxattr, .removexattr = subdir_removexattr, .lock = subdir_lock, .flock = subdir_flock, .bmap = subdir_bmap, .lseek = subdir_lseek, #ifdef HAVE_STATX .statx = subdir_statx, #endif }; static const struct fuse_opt subdir_opts[] = { FUSE_OPT_KEY("-h", 0), FUSE_OPT_KEY("--help", 0), { "subdir=%s", offsetof(struct subdir, base), 0 }, { "rellinks", offsetof(struct subdir, rellinks), 1 }, { "norellinks", offsetof(struct subdir, rellinks), 0 }, FUSE_OPT_END }; static void subdir_help(void) { printf( " -o subdir=DIR prepend this directory to all paths (mandatory)\n" " -o [no]rellinks transform absolute symlinks to relative\n"); } static int subdir_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) data; (void) arg; (void) outargs; if (!key) { subdir_help(); return -1; } return 1; } static struct fuse_fs *subdir_new(struct fuse_args *args, struct fuse_fs *next[]) { struct fuse_fs *fs; struct subdir *d; d = calloc(1, sizeof(struct subdir)); if (d == NULL) { fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n"); return NULL; } if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1) goto out_free; if (!next[0] || next[1]) { fuse_log(FUSE_LOG_ERR, "fuse-subdir: exactly one next filesystem required\n"); goto out_free; } if (!d->base) { fuse_log(FUSE_LOG_ERR, "fuse-subdir: missing 'subdir' option\n"); goto out_free; } if (d->base[0] && d->base[strlen(d->base)-1] != '/') { char *tmp = realloc(d->base, strlen(d->base) + 2); if (!tmp) { fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n"); goto out_free; } d->base = tmp; strcat(d->base, "/"); } d->baselen = strlen(d->base); d->next = next[0]; fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d); if (!fs) goto out_free; return fs; out_free: free(d->base); free(d); return NULL; } FUSE_REGISTER_MODULE(subdir, subdir_new); fuse-3.18.3/lib/mount.c0000644000175000017500000004276315250106036013604 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Architecture specific file system mounting (Linux). This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ /* For environ */ #define _GNU_SOURCE #include "fuse_config.h" #include "fuse_i.h" #include "fuse_misc.h" #include "fuse_opt.h" #include "mount_util.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "fuse_mount_compat.h" #ifdef __NetBSD__ #include #define MS_RDONLY MNT_RDONLY #define MS_NOSUID MNT_NOSUID #define MS_NODEV MNT_NODEV #define MS_NOEXEC MNT_NOEXEC #define MS_SYNCHRONOUS MNT_SYNCHRONOUS #define MS_NOATIME MNT_NOATIME #define MS_NOSYMFOLLOW MNT_NOSYMFOLLOW #define umount2(mnt, flags) unmount(mnt, (flags == 2) ? MNT_FORCE : 0) #endif #define FUSERMOUNT_PROG "fusermount3" #define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_COMMFD2_ENV "_FUSE_COMMFD2" #define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE" #ifndef MS_DIRSYNC #define MS_DIRSYNC 128 #endif enum { KEY_KERN_FLAG, KEY_KERN_OPT, KEY_FUSERMOUNT_OPT, KEY_SUBTYPE_OPT, KEY_MTAB_OPT, KEY_ALLOW_OTHER, KEY_RO, }; struct mount_opts { int allow_other; int flags; int auto_unmount; int blkdev; char *fsname; char *subtype; char *subtype_opt; char *mtab_opts; char *fusermount_opts; char *kernel_opts; unsigned max_read; }; #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 } static const struct fuse_opt fuse_mount_opts[] = { FUSE_MOUNT_OPT("allow_other", allow_other), FUSE_MOUNT_OPT("blkdev", blkdev), FUSE_MOUNT_OPT("auto_unmount", auto_unmount), FUSE_MOUNT_OPT("fsname=%s", fsname), FUSE_MOUNT_OPT("max_read=%u", max_read), FUSE_MOUNT_OPT("subtype=%s", subtype), FUSE_OPT_KEY("allow_other", KEY_KERN_OPT), FUSE_OPT_KEY("auto_unmount", KEY_FUSERMOUNT_OPT), FUSE_OPT_KEY("blkdev", KEY_FUSERMOUNT_OPT), FUSE_OPT_KEY("fsname=", KEY_FUSERMOUNT_OPT), FUSE_OPT_KEY("subtype=", KEY_SUBTYPE_OPT), FUSE_OPT_KEY("blksize=", KEY_KERN_OPT), FUSE_OPT_KEY("default_permissions", KEY_KERN_OPT), FUSE_OPT_KEY("context=", KEY_KERN_OPT), FUSE_OPT_KEY("fscontext=", KEY_KERN_OPT), FUSE_OPT_KEY("defcontext=", KEY_KERN_OPT), FUSE_OPT_KEY("rootcontext=", KEY_KERN_OPT), FUSE_OPT_KEY("max_read=", KEY_KERN_OPT), FUSE_OPT_KEY("user=", KEY_MTAB_OPT), FUSE_OPT_KEY("-n", KEY_MTAB_OPT), FUSE_OPT_KEY("-r", KEY_RO), FUSE_OPT_KEY("ro", KEY_KERN_FLAG), FUSE_OPT_KEY("rw", KEY_KERN_FLAG), FUSE_OPT_KEY("suid", KEY_KERN_FLAG), FUSE_OPT_KEY("nosuid", KEY_KERN_FLAG), FUSE_OPT_KEY("dev", KEY_KERN_FLAG), FUSE_OPT_KEY("nodev", KEY_KERN_FLAG), FUSE_OPT_KEY("exec", KEY_KERN_FLAG), FUSE_OPT_KEY("noexec", KEY_KERN_FLAG), FUSE_OPT_KEY("async", KEY_KERN_FLAG), FUSE_OPT_KEY("sync", KEY_KERN_FLAG), FUSE_OPT_KEY("dirsync", KEY_KERN_FLAG), FUSE_OPT_KEY("noatime", KEY_KERN_FLAG), FUSE_OPT_KEY("nodiratime", KEY_KERN_FLAG), FUSE_OPT_KEY("nostrictatime", KEY_KERN_FLAG), FUSE_OPT_KEY("symfollow", KEY_KERN_FLAG), FUSE_OPT_KEY("nosymfollow", KEY_KERN_FLAG), FUSE_OPT_END }; /* * Running fusermount by calling 'posix_spawn' * * @param out_pid might be NULL */ static int fusermount_posix_spawn(posix_spawn_file_actions_t *action, char const * const argv[], pid_t *out_pid) { const char *full_path = FUSERMOUNT_DIR "/" FUSERMOUNT_PROG; pid_t pid; /* See man 7 environ for the global environ pointer */ /* first try the install path */ int status = posix_spawn(&pid, full_path, action, NULL, (char * const *) argv, environ); if (status != 0) { /* if that fails, try a system install */ status = posix_spawnp(&pid, FUSERMOUNT_PROG, action, NULL, (char * const *) argv, environ); } if (status != 0) { fuse_log(FUSE_LOG_ERR, "Failed to call '%s': %s\n", FUSERMOUNT_PROG, strerror(status)); return -status; } if (out_pid) *out_pid = pid; else waitpid(pid, NULL, 0); /* FIXME: check exit code and return error if any */ return 0; } void fuse_mount_version(void) { char const *const argv[] = {FUSERMOUNT_PROG, "--version", NULL}; int status = fusermount_posix_spawn(NULL, argv, NULL); if(status != 0) fuse_log(FUSE_LOG_ERR, "Running '%s --version' failed", FUSERMOUNT_PROG); } struct mount_flags { const char *opt; unsigned long flag; int on; }; static const struct mount_flags mount_flags[] = { {"rw", MS_RDONLY, 0}, {"ro", MS_RDONLY, 1}, {"suid", MS_NOSUID, 0}, {"nosuid", MS_NOSUID, 1}, {"dev", MS_NODEV, 0}, {"nodev", MS_NODEV, 1}, {"exec", MS_NOEXEC, 0}, {"noexec", MS_NOEXEC, 1}, {"async", MS_SYNCHRONOUS, 0}, {"sync", MS_SYNCHRONOUS, 1}, {"noatime", MS_NOATIME, 1}, {"nodiratime", MS_NODIRATIME, 1}, {"norelatime", MS_RELATIME, 0}, {"nostrictatime", MS_STRICTATIME, 0}, {"symfollow", MS_NOSYMFOLLOW, 0}, {"nosymfollow", MS_NOSYMFOLLOW, 1}, #ifndef __NetBSD__ {"dirsync", MS_DIRSYNC, 1}, #endif {NULL, 0, 0} }; unsigned get_max_read(struct mount_opts *o) { return o->max_read; } static void set_mount_flag(const char *s, int *flags) { int i; for (i = 0; mount_flags[i].opt != NULL; i++) { const char *opt = mount_flags[i].opt; if (strcmp(opt, s) == 0) { if (mount_flags[i].on) *flags |= mount_flags[i].flag; else *flags &= ~mount_flags[i].flag; return; } } fuse_log(FUSE_LOG_ERR, "fuse: internal error, can't find mount flag\n"); abort(); } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) outargs; struct mount_opts *mo = data; switch (key) { case KEY_RO: arg = "ro"; /* fall through */ case KEY_KERN_FLAG: set_mount_flag(arg, &mo->flags); return 0; case KEY_KERN_OPT: return fuse_opt_add_opt(&mo->kernel_opts, arg); case KEY_FUSERMOUNT_OPT: return fuse_opt_add_opt_escaped(&mo->fusermount_opts, arg); case KEY_SUBTYPE_OPT: return fuse_opt_add_opt(&mo->subtype_opt, arg); case KEY_MTAB_OPT: return fuse_opt_add_opt(&mo->mtab_opts, arg); /* Third party options like 'x-gvfs-notrash' */ case FUSE_OPT_KEY_OPT: return (strncmp("x-", arg, 2) == 0) ? fuse_opt_add_opt(&mo->mtab_opts, arg) : 1; } /* Pass through unknown options */ return 1; } /* return value: * >= 0 => fd * -1 => error */ static int receive_fd(int fd) { struct msghdr msg; struct iovec iov; char buf[1]; int rv; size_t ccmsg[CMSG_SPACE(sizeof(int)) / sizeof(size_t)]; struct cmsghdr *cmsg; iov.iov_base = buf; iov.iov_len = 1; memset(&msg, 0, sizeof(msg)); msg.msg_name = 0; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; /* old BSD implementations should use msg_accrights instead of * msg_control; the interface is different. */ msg.msg_control = ccmsg; msg.msg_controllen = sizeof(ccmsg); while(((rv = recvmsg(fd, &msg, 0)) == -1) && errno == EINTR); if (rv == -1) { fuse_log(FUSE_LOG_ERR, "recvmsg failed: %s", strerror(errno)); return -1; } if(!rv) { /* EOF */ return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (!cmsg) { fuse_log(FUSE_LOG_ERR, "error retrieving control message header\n"); return -1; } if (cmsg->cmsg_type != SCM_RIGHTS) { fuse_log(FUSE_LOG_ERR, "got control message of unknown type %d\n", cmsg->cmsg_type); return -1; } return *(int*)CMSG_DATA(cmsg); } void fuse_kern_unmount(const char *mountpoint, int fd) { int res; if (fd != -1) { struct pollfd pfd; pfd.fd = fd; pfd.events = 0; res = poll(&pfd, 1, 0); /* Need to close file descriptor, otherwise synchronous umount would recurse into filesystem, and deadlock. Caller expects fuse_kern_unmount to close the fd, so close it anyway. */ close(fd); /* If file poll returns POLLERR on the device file descriptor, then the filesystem is already unmounted or the connection was severed via /sys/fs/fuse/connections/NNN/abort */ if (res == 1 && (pfd.revents & POLLERR)) return; } if (geteuid() == 0) { fuse_mnt_umount("fuse", mountpoint, mountpoint, 1); return; } res = umount2(mountpoint, MNT_DETACH | UMOUNT_NOFOLLOW); if (res == 0) return; char const * const argv[] = { FUSERMOUNT_PROG, "--unmount", "--quiet", "--lazy", "--", mountpoint, NULL }; int status = fusermount_posix_spawn(NULL, argv, NULL); if(status != 0) { fuse_log(FUSE_LOG_ERR, "Spawning %s to unmount failed: %s", FUSERMOUNT_PROG, strerror(-status)); return; } } static int setup_auto_unmount(const char *mountpoint, int quiet) { int fds[2]; pid_t pid; int res; if (!mountpoint) { fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); return -1; } res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); if(res == -1) { fuse_log(FUSE_LOG_ERR, "Setting up auto-unmount socketpair() failed: %s\n", strerror(errno)); return -1; } char arg_fd_entry[30]; snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]); setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1); /* * This helps to identify the FD hold by parent process. * In auto-unmount case, parent process can close this FD explicitly to do unmount. * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV). * One potential use case is to satisfy FD-Leak checks. */ snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]); setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1); char const *const argv[] = { FUSERMOUNT_PROG, "--auto-unmount", "--", mountpoint, NULL, }; // TODO: add error handling for all manipulations of action. posix_spawn_file_actions_t action; posix_spawn_file_actions_init(&action); if (quiet) { posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0); posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0); } posix_spawn_file_actions_addclose(&action, fds[1]); /* * auto-umount runs in the background - it is not waiting for the * process */ int status = fusermount_posix_spawn(&action, argv, &pid); posix_spawn_file_actions_destroy(&action); if(status != 0) { close(fds[0]); close(fds[1]); fuse_log(FUSE_LOG_ERR, "fuse: Setting up auto-unmount failed (spawn): %s", strerror(-status)); return -1; } // passed to child now, so can close here. close(fds[0]); // Now fusermount3 will only exit when fds[1] closes automatically when our // process exits. return 0; // Note: fds[1] is leakend and doesn't get FD_CLOEXEC } static int fuse_mount_fusermount(const char *mountpoint, struct mount_opts *mo, const char *opts, int quiet) { int fds[2]; pid_t pid; int res; if (!mountpoint) { fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); return -1; } res = socketpair(PF_UNIX, SOCK_STREAM, 0, fds); if(res == -1) { fuse_log(FUSE_LOG_ERR, "Running %s: socketpair() failed: %s\n", FUSERMOUNT_PROG, strerror(errno)); return -1; } char arg_fd_entry[30]; snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[0]); setenv(FUSE_COMMFD_ENV, arg_fd_entry, 1); /* * This helps to identify the FD hold by parent process. * In auto-unmount case, parent process can close this FD explicitly to do unmount. * The FD[1] can be got via getenv(FUSE_COMMFD2_ENV). * One potential use case is to satisfy FD-Leak checks. */ snprintf(arg_fd_entry, sizeof(arg_fd_entry), "%i", fds[1]); setenv(FUSE_COMMFD2_ENV, arg_fd_entry, 1); char const *const argv[] = { FUSERMOUNT_PROG, "-o", opts ? opts : "", "--", mountpoint, NULL, }; posix_spawn_file_actions_t action; posix_spawn_file_actions_init(&action); if (quiet) { posix_spawn_file_actions_addopen(&action, STDOUT_FILENO, "/dev/null", O_WRONLY, 0); posix_spawn_file_actions_addopen(&action, STDERR_FILENO, "/dev/null", O_WRONLY, 0); } posix_spawn_file_actions_addclose(&action, fds[1]); int status = fusermount_posix_spawn(&action, argv, &pid); posix_spawn_file_actions_destroy(&action); if(status != 0) { close(fds[0]); close(fds[1]); fuse_log(FUSE_LOG_ERR, "posix_spawn(p)() for %s failed: %s", FUSERMOUNT_PROG, strerror(-status)); return -1; } // passed to child now, so can close here. close(fds[0]); int fd = receive_fd(fds[1]); if (!mo->auto_unmount) { /* with auto_unmount option fusermount3 will not exit until this socket is closed */ close(fds[1]); waitpid(pid, NULL, 0); /* bury zombie */ } if (fd >= 0) fcntl(fd, F_SETFD, FD_CLOEXEC); return fd; } #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif static int fuse_mount_sys(const char *mnt, struct mount_opts *mo, const char *mnt_opts) { char tmp[128]; const char *devname = getenv(FUSE_KERN_DEVICE_ENV) ?: "/dev/fuse"; char *source = NULL; char *type = NULL; struct stat stbuf; int fd; int res; if (!mnt) { fuse_log(FUSE_LOG_ERR, "fuse: missing mountpoint parameter\n"); return -1; } res = stat(mnt, &stbuf); if (res == -1) { fuse_log(FUSE_LOG_ERR, "fuse: failed to access mountpoint %s: %s\n", mnt, strerror(errno)); return -1; } fd = open(devname, O_RDWR | O_CLOEXEC); if (fd == -1) { if (errno == ENODEV || errno == ENOENT) fuse_log(FUSE_LOG_ERR, "fuse: device %s not found. Kernel module not loaded?\n", devname); else fuse_log(FUSE_LOG_ERR, "fuse: failed to open %s: %s\n", devname, strerror(errno)); return -1; } if (!O_CLOEXEC) fcntl(fd, F_SETFD, FD_CLOEXEC); snprintf(tmp, sizeof(tmp), "fd=%i,rootmode=%o,user_id=%u,group_id=%u", fd, stbuf.st_mode & S_IFMT, getuid(), getgid()); res = fuse_opt_add_opt(&mo->kernel_opts, tmp); if (res == -1) goto out_close; source = malloc((mo->fsname ? strlen(mo->fsname) : 0) + (mo->subtype ? strlen(mo->subtype) : 0) + strlen(devname) + 32); type = malloc((mo->subtype ? strlen(mo->subtype) : 0) + 32); if (!type || !source) { fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate memory\n"); goto out_close; } strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); if (mo->subtype) { strcat(type, "."); strcat(type, mo->subtype); } strcpy(source, mo->fsname ? mo->fsname : (mo->subtype ? mo->subtype : devname)); res = mount(source, mnt, type, mo->flags, mo->kernel_opts); if (res == -1 && errno == ENODEV && mo->subtype) { /* Probably missing subtype support */ strcpy(type, mo->blkdev ? "fuseblk" : "fuse"); if (mo->fsname) { if (!mo->blkdev) sprintf(source, "%s#%s", mo->subtype, mo->fsname); } else { strcpy(source, type); } res = mount(source, mnt, type, mo->flags, mo->kernel_opts); } if (res == -1) { /* * Maybe kernel doesn't support unprivileged mounts, in this * case try falling back to fusermount3 */ if (errno == EPERM) { res = -2; } else { int errno_save = errno; if (mo->blkdev && errno == ENODEV && !fuse_mnt_check_fuseblk()) fuse_log(FUSE_LOG_ERR, "fuse: 'fuseblk' support missing\n"); else fuse_log(FUSE_LOG_ERR, "fuse: mount failed: %s\n", strerror(errno_save)); } goto out_close; } #ifndef IGNORE_MTAB if (geteuid() == 0) { char *newmnt = fuse_mnt_resolve_path("fuse", mnt); res = -1; if (!newmnt) goto out_umount; res = fuse_mnt_add_mount("fuse", source, newmnt, type, mnt_opts); free(newmnt); if (res == -1) goto out_umount; } #endif /* IGNORE_MTAB */ free(type); free(source); return fd; out_umount: umount2(mnt, MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */ out_close: free(type); free(source); close(fd); return res; } static int get_mnt_flag_opts(char **mnt_optsp, int flags) { int i; if (!(flags & MS_RDONLY) && fuse_opt_add_opt(mnt_optsp, "rw") == -1) return -1; for (i = 0; mount_flags[i].opt != NULL; i++) { if (mount_flags[i].on && (flags & mount_flags[i].flag) && fuse_opt_add_opt(mnt_optsp, mount_flags[i].opt) == -1) return -1; } return 0; } struct mount_opts *parse_mount_opts(struct fuse_args *args) { struct mount_opts *mo; mo = (struct mount_opts*) malloc(sizeof(struct mount_opts)); if (mo == NULL) return NULL; memset(mo, 0, sizeof(struct mount_opts)); mo->flags = MS_NOSUID | MS_NODEV; if (args && fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) goto err_out; return mo; err_out: destroy_mount_opts(mo); return NULL; } void destroy_mount_opts(struct mount_opts *mo) { free(mo->fsname); free(mo->subtype); free(mo->fusermount_opts); free(mo->subtype_opt); free(mo->kernel_opts); free(mo->mtab_opts); free(mo); } int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo) { int res = -1; char *mnt_opts = NULL; res = -1; if (get_mnt_flag_opts(&mnt_opts, mo->flags) == -1) goto out; if (mo->kernel_opts && fuse_opt_add_opt(&mnt_opts, mo->kernel_opts) == -1) goto out; if (mo->mtab_opts && fuse_opt_add_opt(&mnt_opts, mo->mtab_opts) == -1) goto out; res = fuse_mount_sys(mountpoint, mo, mnt_opts); if (res >= 0 && mo->auto_unmount) { if(0 > setup_auto_unmount(mountpoint, 0)) { // Something went wrong, let's umount like in fuse_mount_sys. umount2(mountpoint, MNT_DETACH | UMOUNT_NOFOLLOW); /* lazy umount */ res = -1; } } else if (res == -2) { if (mo->fusermount_opts && fuse_opt_add_opt(&mnt_opts, mo->fusermount_opts) == -1) goto out; if (mo->subtype) { char *tmp_opts = NULL; res = -1; if (fuse_opt_add_opt(&tmp_opts, mnt_opts) == -1 || fuse_opt_add_opt(&tmp_opts, mo->subtype_opt) == -1) { free(tmp_opts); goto out; } res = fuse_mount_fusermount(mountpoint, mo, tmp_opts, 1); free(tmp_opts); if (res == -1) res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0); } else { res = fuse_mount_fusermount(mountpoint, mo, mnt_opts, 0); } } out: free(mnt_opts); return res; } fuse-3.18.3/lib/mount_bsd.c0000644000175000017500000001374315250106036014430 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2005-2008 Csaba Henk Architecture specific file system mounting (FreeBSD). This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #include "fuse_config.h" #include "fuse_i.h" #include "fuse_misc.h" #include "fuse_opt.h" #include "util.h" #include #include "fuse_mount_compat.h" #include #include #include #include #include #include #include #include #define FUSERMOUNT_PROG "mount_fusefs" #define FUSE_DEV_TRUNK "/dev/fuse" enum { KEY_RO, KEY_KERN }; struct mount_opts { int allow_other; char *kernel_opts; unsigned max_read; }; #define FUSE_DUAL_OPT_KEY(templ, key) \ FUSE_OPT_KEY(templ, key), FUSE_OPT_KEY("no" templ, key) static const struct fuse_opt fuse_mount_opts[] = { { "allow_other", offsetof(struct mount_opts, allow_other), 1 }, { "max_read=%u", offsetof(struct mount_opts, max_read), 1 }, FUSE_OPT_KEY("-r", KEY_RO), /* standard FreeBSD mount options */ FUSE_DUAL_OPT_KEY("dev", KEY_KERN), FUSE_DUAL_OPT_KEY("async", KEY_KERN), FUSE_DUAL_OPT_KEY("atime", KEY_KERN), FUSE_DUAL_OPT_KEY("dev", KEY_KERN), FUSE_DUAL_OPT_KEY("exec", KEY_KERN), FUSE_DUAL_OPT_KEY("suid", KEY_KERN), FUSE_DUAL_OPT_KEY("symfollow", KEY_KERN), FUSE_DUAL_OPT_KEY("rdonly", KEY_KERN), FUSE_DUAL_OPT_KEY("sync", KEY_KERN), FUSE_DUAL_OPT_KEY("union", KEY_KERN), FUSE_DUAL_OPT_KEY("userquota", KEY_KERN), FUSE_DUAL_OPT_KEY("groupquota", KEY_KERN), FUSE_DUAL_OPT_KEY("clusterr", KEY_KERN), FUSE_DUAL_OPT_KEY("clusterw", KEY_KERN), FUSE_DUAL_OPT_KEY("suiddir", KEY_KERN), FUSE_DUAL_OPT_KEY("snapshot", KEY_KERN), FUSE_DUAL_OPT_KEY("multilabel", KEY_KERN), FUSE_DUAL_OPT_KEY("acls", KEY_KERN), FUSE_DUAL_OPT_KEY("force", KEY_KERN), FUSE_DUAL_OPT_KEY("update", KEY_KERN), FUSE_DUAL_OPT_KEY("ro", KEY_KERN), FUSE_DUAL_OPT_KEY("rw", KEY_KERN), FUSE_DUAL_OPT_KEY("auto", KEY_KERN), FUSE_DUAL_OPT_KEY("automounted", KEY_KERN), /* options supported under both Linux and FBSD */ FUSE_DUAL_OPT_KEY("allow_other", KEY_KERN), FUSE_DUAL_OPT_KEY("default_permissions",KEY_KERN), FUSE_OPT_KEY("max_read=", KEY_KERN), FUSE_OPT_KEY("subtype=", KEY_KERN), /* FBSD FUSE specific mount options */ FUSE_DUAL_OPT_KEY("private", KEY_KERN), FUSE_DUAL_OPT_KEY("neglect_shares", KEY_KERN), FUSE_DUAL_OPT_KEY("push_symlinks_in", KEY_KERN), #if __FreeBSD_version >= 1200519 FUSE_DUAL_OPT_KEY("intr", KEY_KERN), #endif /* stock FBSD mountopt parsing routine lets anything be negated... */ /* * Linux specific mount options, but let just the mount util * handle them */ FUSE_OPT_KEY("fsname=", KEY_KERN), FUSE_OPT_END }; void fuse_mount_version(void) { system(FUSERMOUNT_PROG " --version"); } unsigned get_max_read(struct mount_opts *o) { return o->max_read; } static int fuse_mount_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { (void) outargs; struct mount_opts *mo = data; switch (key) { case KEY_RO: arg = "ro"; /* fall through */ case KEY_KERN: return fuse_opt_add_opt(&mo->kernel_opts, arg); } /* Pass through unknown options */ return 1; } void fuse_kern_unmount(const char *mountpoint, int fd) { if (close(fd) < 0) fuse_log(FUSE_LOG_ERR, "closing FD %d failed: %s", fd, strerror(errno)); if (unmount(mountpoint, MNT_FORCE) < 0) fuse_log(FUSE_LOG_ERR, "unmounting %s failed: %s", mountpoint, strerror(errno)); } static int fuse_mount_core(const char *mountpoint, const char *opts) { const char *mountprog = FUSERMOUNT_PROG; long fd; char *fdnam, *dev; pid_t pid, cpid; int status; int err; fdnam = getenv("FUSE_DEV_FD"); if (fdnam) { err = libfuse_strtol(fdnam, &fd); if (err || fd < 0) { fuse_log(FUSE_LOG_ERR, "invalid value given in FUSE_DEV_FD\n"); return -1; } goto mount; } dev = getenv("FUSE_DEV_NAME"); if (! dev) dev = (char *)FUSE_DEV_TRUNK; if ((fd = open(dev, O_RDWR)) < 0) { perror("fuse: failed to open fuse device"); return -1; } mount: if (getenv("FUSE_NO_MOUNT") || ! mountpoint) goto out; pid = fork(); cpid = pid; if (pid == -1) { perror("fuse: fork() failed"); close(fd); return -1; } if (pid == 0) { pid = fork(); if (pid == -1) { perror("fuse: fork() failed"); close(fd); _exit(EXIT_FAILURE); } if (pid == 0) { const char *argv[32]; int a = 0; int ret = -1; if (! fdnam) { ret = asprintf(&fdnam, "%ld", fd); if(ret == -1) { perror("fuse: failed to assemble mount arguments"); close(fd); _exit(EXIT_FAILURE); } } argv[a++] = mountprog; if (opts) { argv[a++] = "-o"; argv[a++] = opts; } argv[a++] = fdnam; argv[a++] = mountpoint; argv[a++] = NULL; execvp(mountprog, (char **) argv); perror("fuse: failed to exec mount program"); free(fdnam); _exit(EXIT_FAILURE); } waitpid(pid, &status, 0); if (!WIFEXITED(status)) _exit(EXIT_FAILURE); _exit(WEXITSTATUS(status)); } if (waitpid(cpid, &status, 0) == -1 || WEXITSTATUS(status) != 0) { perror("fuse: failed to mount file system"); if (close(fd) < 0) perror("fuse: closing FD"); return -1; } out: return fd; } struct mount_opts *parse_mount_opts(struct fuse_args *args) { struct mount_opts *mo; mo = (struct mount_opts*) malloc(sizeof(struct mount_opts)); if (mo == NULL) return NULL; memset(mo, 0, sizeof(struct mount_opts)); if (args && fuse_opt_parse(args, mo, fuse_mount_opts, fuse_mount_opt_proc) == -1) goto err_out; return mo; err_out: destroy_mount_opts(mo); return NULL; } void destroy_mount_opts(struct mount_opts *mo) { free(mo->kernel_opts); free(mo); } int fuse_kern_mount(const char *mountpoint, struct mount_opts *mo) { /* mount util should not try to spawn the daemon */ setenv("MOUNT_FUSEFS_SAFE", "1", 1); /* to notify the mount util it's called from lib */ setenv("MOUNT_FUSEFS_CALL_BY_LIB", "1", 1); return fuse_mount_core(mountpoint, mo->kernel_opts); } fuse-3.18.3/lib/mount_util.c0000644000175000017500000002201015250106036014620 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi Architecture-independent mounting code. This program can be distributed under the terms of the GNU LGPLv2. See the file LGPL2.txt. */ #include "fuse_config.h" #include "mount_util.h" #include "fuse_log.h" #include #include #include #include #include #include #include #include #include #include #if !defined( __NetBSD__) && !defined(__FreeBSD__) && !defined(__DragonFly__) && !defined(__ANDROID__) #include #else #define IGNORE_MTAB #endif #include #include #include "fuse_mount_compat.h" #include #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) #define umount2(mnt, flags) unmount(mnt, ((flags) == 2) ? MNT_FORCE : 0) #endif #ifdef IGNORE_MTAB #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 on a read-only filesystem. */ res = lstat(_PATH_MOUNTED, &stbuf); if (res == -1) { if (errno == ENOENT) return 0; } else { uid_t ruid; int err; 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; res = access("/run/mount/utab", F_OK); if (res == -1) return 0; } return 1; } #endif /* IGNORE_MTAB */ /* * These values become command line arguments of /bin/mount and /bin/umount. * BusyBox mount(8) parses an argument starting with '-' as an option even * behind an end-of-options marker ("--"); NULL would end the argument list * early. * * @return 1 if @value is unsafe as a /bin/mount or /bin/umount argument. */ static int unsafe_operand(const char *value) { return value == NULL || value[0] == '-'; } 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; if (unsafe_operand(fsname) || unsafe_operand(mnt) || unsafe_operand(type) || unsafe_operand(opts)) { fuse_log(FUSE_LOG_DEBUG, "%s: option-like mount argument, skipping mtab update\n", progname); return 0; } 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); if(setuid(geteuid()) == -1) { fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); res = -1; goto out_restore; } /* * fsname comes from -ofsname=, so it can start with '-'. The * setuid() above raises the real uid to 0, so mount(8) is not * in restricted mode either. Terminate the options with "--" * to keep it from parsing the operands as further options. */ 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); if(setuid(geteuid()) == -1) { fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); res = -1; goto out_restore; } if (lazy) { execle("/bin/umount", "/bin/umount", "-i", "-l", "--", rel_mnt, 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; /* * umount(8) may read an option-like rel_mnt as an option: unmount here * instead and leave the mtab/utab record behind */ if (!mtab_needs_update(abs_mnt) || unsafe_operand(rel_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; if (unsafe_operand(mnt)) return 0; 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); if(setuid(geteuid()) == -1) { fprintf(stderr, "%s: setuid: %s\n", progname, strerror(errno)); res = -1; goto out_restore; } 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_fuseblk(void) { char buf[256]; FILE *f = fopen("/proc/filesystems", "r"); if (!f) return 1; while (fgets(buf, sizeof(buf), f)) if (strstr(buf, "fuseblk\n")) { fclose(f); return 1; } fclose(f); return 0; } int fuse_mnt_parse_fuse_fd(const char *mountpoint) { int fd = -1; int len = 0; if (mountpoint == NULL) { fprintf(stderr, "Invalid null-ptr mount-point!\n"); return -1; } if (sscanf(mountpoint, "/dev/fd/%u%n", &fd, &len) == 1 && len == strlen(mountpoint)) { return fd; } return -1; } fuse-3.18.3/lib/mount_util.h0000644000175000017500000000123715250106036014635 0ustar berndbernd/* 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 LGPL2.txt. */ #include int fuse_mnt_add_mount(const char *progname, const char *fsname, const char *mnt, const char *type, const char *opts); int fuse_mnt_remove_mount(const char *progname, const char *mnt); int fuse_mnt_umount(const char *progname, const char *abs_mnt, const char *rel_mnt, int lazy); char *fuse_mnt_resolve_path(const char *progname, const char *orig); int fuse_mnt_check_fuseblk(void); int fuse_mnt_parse_fuse_fd(const char *mountpoint); fuse-3.18.3/lib/usdt.h0000644000175000017500000005761415250106036013427 0ustar berndbernd/* * Copied from https://github.com/libbpf/usdt/ */ // SPDX-License-Identifier: BSD-2-Clause /* * This single-header library defines a collection of variadic macros for * defining and triggering USDTs (User Statically-Defined Tracepoints): * * - For USDTs without associated semaphore: * USDT(group, name, args...) * * - For USDTs with implicit (transparent to the user) semaphore: * USDT_WITH_SEMA(group, name, args...) * USDT_IS_ACTIVE(group, name) * * - For USDTs with explicit (user-defined and provided) semaphore: * USDT_WITH_EXPLICIT_SEMA(sema, group, name, args...) * USDT_SEMA_IS_ACTIVE(sema) * * all of which emit a NOP instruction into the instruction stream, and so * have *zero* overhead for the surrounding code. USDTs are identified by * a combination of `group` and `name` identifiers, which is used by external * tracing tooling (tracers) for identifying exact USDTs of interest. * * USDTs can have an associated (2-byte) activity counter (USDT semaphore), * automatically maintained by Linux kernel whenever any correctly written * BPF-based tracer is attached to the USDT. This USDT semaphore can be used * to check whether there is a need to do any extra data collection and * processing for a given USDT (if necessary), and otherwise avoid extra work * for a common case of USDT not being traced ("active"). * * See documentation for USDT_WITH_SEMA()/USDT_IS_ACTIVE() or * USDT_WITH_EXPLICIT_SEMA()/USDT_SEMA_IS_ACTIVE() APIs below for details on * working with USDTs with implicitly or explicitly associated * USDT semaphores, respectively. * * There is also some additional data recorded into an auxiliary note * section. The data in the note section describes the operands, in terms of * size and location, used by tracing tooling to know where to find USDT * arguments. Each location is encoded as an assembler operand string. * Tracing tools (bpftrace and BPF-based tracers, systemtap, etc) insert * breakpoints on top of the nop, and decode the location operand-strings, * like an assembler, to find the values being passed. * * The operand strings are selected by the compiler for each operand. * They are constrained by inline-assembler codes.The default is: * * #define USDT_ARG_CONSTRAINT nor * * This is a good default if the operands tend to be integral and * moderate in number (smaller than number of registers). In other * cases, the compiler may report "'asm' requires impossible reload" or * similar. In this case, consider simplifying the macro call (fewer * and simpler operands), reduce optimization, or override the default * constraints string via: * * #define USDT_ARG_CONSTRAINT g * #include * * For some historical description of USDT v3 format (the one used by this * library and generally recognized and assumed by BPF-based tracing tools) * see [0]. The more formal specification can be found at [1]. Additional * argument constraints information can be found at [2]. * * Original SystemTap's sys/sdt.h implementation ([3]) was used as a base for * this USDT library implementation. Current implementation differs *a lot* in * terms of exposed user API and general usability, which was the main goal * and focus of the reimplementation work. Nevertheless, underlying recorded * USDT definitions are fully binary compatible and any USDT-based tooling * should work equally well with USDTs defined by either SystemTap's or this * library's USDT implementation. * * [0] https://ecos.sourceware.org/ml/systemtap/2010-q3/msg00145.html * [1] https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation * [2] https://gcc.gnu.org/onlinedocs/gcc/Constraints.html * [3] https://sourceware.org/git/?p=systemtap.git;a=blob;f=includes/sys/sdt.h */ #ifndef __USDT_H #define __USDT_H /* * Changelog: * * 0.1.0 * ----- * - Initial release */ #define USDT_MAJOR_VERSION 0 #define USDT_MINOR_VERSION 1 #define USDT_PATCH_VERSION 0 /* C++20 and C23 added __VA_OPT__ as a standard replacement for non-standard `##__VA_ARGS__` extension */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L) || (defined(__cplusplus) && __cplusplus > 201703L) #define __usdt_va_opt 1 #define __usdt_va_args(...) __VA_OPT__(,) __VA_ARGS__ #else #define __usdt_va_args(...) , ##__VA_ARGS__ #endif /* * Trigger USDT with `group`:`name` identifier and pass through `args` as its * arguments. Zero arguments are acceptable as well. No USDT semaphore is * associated with this USDT. * * Such "semaphoreless" USDTs are commonly used when there is no extra data * collection or processing needed to collect and prepare USDT arguments and * they are just available in the surrounding code. USDT() macro will just * record their locations in CPU registers or in memory for tracing tooling to * be able to access them, if necessary. */ #ifdef __usdt_va_opt #define USDT(group, name, ...) \ __usdt_probe(group, name, __usdt_sema_none, 0 __VA_OPT__(,) __VA_ARGS__) #else #define USDT(group, name, ...) \ __usdt_probe(group, name, __usdt_sema_none, 0, ##__VA_ARGS__) #endif /* * Trigger USDT with `group`:`name` identifier and pass through `args` as its * arguments. Zero arguments are acceptable as well. USDT also get an * implicitly-defined associated USDT semaphore, which will be "activated" by * tracing tooling and can be used to check whether USDT is being actively * observed. * * USDTs with semaphore are commonly used when there is a need to perform * additional data collection and processing to prepare USDT arguments, which * otherwise might not be necessary for the rest of application logic. In such * case, USDT semaphore can be used to avoid unnecessary extra work. If USDT * is not traced (which is presumed to be a common situation), the associated * USDT semaphore is "inactive", and so there is no need to waste resources to * prepare USDT arguments. Use USDT_IS_ACTIVE(group, name) to check whether * USDT is "active". * * N.B. There is an inherent (albeit short) gap between checking whether USDT * is active and triggering corresponding USDT, in which external tracer can * be attached to an USDT and activate USDT semaphore after the activity check. * If such a race occurs, tracers might miss one USDT execution. Tracers are * expected to accommodate such possibility and this is expected to not be * a problem for applications and tracers. * * N.B. Implicit USDT semaphore defined by USDT_WITH_SEMA() is contained * within a single executable or shared library and is not shared outside * them. I.e., if you use USDT_WITH_SEMA() with the same USDT group and name * identifier across executable and shared library, it will work and won't * conflict, per se, but will define independent USDT semaphores, one for each * shared library/executable in which USDT_WITH_SEMA(group, name) is used. * That is, if you attach to this USDT in one shared library (or executable), * then only USDT semaphore within that shared library (or executable) will be * updated by the kernel, while other libraries (or executable) will not see * activated USDT semaphore. In short, it's best to use unique USDT group:name * identifiers across different shared libraries (and, equivalently, between * executable and shared library). This is advanced consideration and is * rarely (if ever) seen in practice, but just to avoid surprises this is * called out here. (Static libraries become a part of final executable, once * linked by linker, so the above considerations don't apply to them.) */ #ifdef __usdt_va_opt #define USDT_WITH_SEMA(group, name, ...) \ __usdt_probe(group, name, \ __usdt_sema_implicit, __usdt_sema_name(group, name) \ __VA_OPT__(,) __VA_ARGS__) #else #define USDT_WITH_SEMA(group, name, ...) \ __usdt_probe(group, name, \ __usdt_sema_implicit, __usdt_sema_name(group, name), \ ##__VA_ARGS__) #endif struct usdt_sema { volatile unsigned short active; }; /* * Check if USDT with `group`:`name` identifier is "active" (i.e., whether it * is attached to by external tracing tooling and is actively observed). * * This macro can be used to decide whether any additional and potentially * expensive data collection or processing should be done to pass extra * information into the given USDT. It is assumed that USDT is triggered with * USDT_WITH_SEMA() macro which will implicitly define associated USDT * semaphore. (If one needs more control over USDT semaphore, see * USDT_DEFINE_SEMA() and USDT_WITH_EXPLICIT_SEMA() macros below.) * * N.B. Such checks are necessarily racy and speculative. Between checking * whether USDT is active and triggering the USDT itself, tracer can be * detached with no notification. This race should be extremely rare and worst * case should result in one-time wasted extra data collection and processing. */ #define USDT_IS_ACTIVE(group, name) ({ \ extern struct usdt_sema __usdt_sema_name(group, name) \ __usdt_asm_name(__usdt_sema_name(group, name)); \ __usdt_sema_implicit(__usdt_sema_name(group, name)); \ __usdt_sema_name(group, name).active > 0; \ }) /* * APIs for working with user-defined explicit USDT semaphores. * * This is a less commonly used advanced API for use cases in which user needs * an explicit control over (potentially shared across multiple USDTs) USDT * semaphore instance. This can be used when there is a group of logically * related USDTs that all need extra data collection and processing whenever * any of a family of related USDTs are "activated" (i.e., traced). In such * a case, all such related USDTs will be associated with the same shared USDT * semaphore defined with USDT_DEFINE_SEMA() and the USDTs themselves will be * triggered with USDT_WITH_EXPLICIT_SEMA() macros, taking an explicit extra * USDT semaphore identifier as an extra parameter. */ /** * Underlying C global variable name for user-defined USDT semaphore with * `sema` identifier. Could be useful for debugging, but normally shouldn't be * used explicitly. */ #define USDT_SEMA(sema) __usdt_sema_##sema /* * Define storage for user-defined USDT semaphore `sema`. * * Should be used only once in non-header source file to let compiler allocate * space for the semaphore variable. Just like with any other global variable. * * This macro can be used anywhere where global variable declaration is * allowed. Just like with global variable definitions, there should be only * one definition of user-defined USDT semaphore with given `sema` identifier, * otherwise compiler or linker will complain about duplicate variable * definition. * * For C++, it is allowed to use USDT_DEFINE_SEMA() both in global namespace * and inside namespaces (including nested namespaces). Just make sure that * USDT_DECLARE_SEMA() is placed within the namespace where this semaphore is * referenced, or any of its parent namespaces, so the C++ language-level * identifier is visible to the code that needs to reference the semaphore. * At the lowest layer, USDT semaphores have global naming and visibility * (they have a corresponding `__usdt_sema_` symbol, which can be linked * against from C or C++ code, if necessary). To keep it simple, putting * USDT_DECLARE_SEMA() declarations into global namespaces is the simplest * no-brainer solution. All these aspects are irrelevant for plain C, because * C doesn't have namespaces and everything is always in the global namespace. * * N.B. Due to USDT metadata being recorded in non-allocatable ELF note * section, it has limitations when it comes to relocations, which, in * practice, means that it's not possible to correctly share USDT semaphores * between main executable and shared libraries, or even between multiple * shared libraries. USDT semaphore has to be contained to individual shared * library or executable to avoid unpleasant surprises with half-working USDT * semaphores. We enforce this by marking semaphore ELF symbols as having * a hidden visibility. This is quite an advanced use case and consideration * and for most users this should have no consequences whatsoever. */ #define USDT_DEFINE_SEMA(sema) \ struct usdt_sema __usdt_sema_sec USDT_SEMA(sema) \ __usdt_asm_name(USDT_SEMA(sema)) \ __attribute__((visibility("hidden"))) = { 0 } /* * Declare extern reference to user-defined USDT semaphore `sema`. * * Refers to a variable defined in another compilation unit by * USDT_DEFINE_SEMA() and allows to use the same USDT semaphore across * multiple compilation units (i.e., .c and .cpp files). * * See USDT_DEFINE_SEMA() notes above for C++ language usage peculiarities. */ #define USDT_DECLARE_SEMA(sema) \ extern struct usdt_sema USDT_SEMA(sema) __usdt_asm_name(USDT_SEMA(sema)) /* * Check if user-defined USDT semaphore `sema` is "active" (i.e., whether it * is attached to by external tracing tooling and is actively observed). * * This macro can be used to decide whether any additional and potentially * expensive data collection or processing should be done to pass extra * information into USDT(s) associated with USDT semaphore `sema`. * * N.B. Such checks are necessarily racy. Between checking the state of USDT * semaphore and triggering associated USDT(s), the active tracer might attach * or detach. This race should be extremely rare and worst case should result * in one-time missed USDT event or wasted extra data collection and * processing. USDT-using tracers should be written with this in mind and is * not a concern of the application defining USDTs with associated semaphore. */ #define USDT_SEMA_IS_ACTIVE(sema) (USDT_SEMA(sema).active > 0) /* * Invoke USDT specified by `group` and `name` identifiers and associate * explicitly user-defined semaphore `sema` with it. Pass through `args` as * USDT arguments. `args` are optional and zero arguments are acceptable. * * Semaphore is defined with the help of USDT_DEFINE_SEMA() macro and can be * checked whether active with USDT_SEMA_IS_ACTIVE(). */ #ifdef __usdt_va_opt #define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \ __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema), ##__VA_ARGS__) #else #define USDT_WITH_EXPLICIT_SEMA(sema, group, name, ...) \ __usdt_probe(group, name, __usdt_sema_explicit, USDT_SEMA(sema) __VA_OPT__(,) __VA_ARGS__) #endif /* * Adjustable implementation aspects */ #ifndef USDT_ARG_CONSTRAINT #if defined __powerpc__ #define USDT_ARG_CONSTRAINT nZr #elif defined __arm__ #define USDT_ARG_CONSTRAINT g #elif defined __loongarch__ #define USDT_ARG_CONSTRAINT nmr #else #define USDT_ARG_CONSTRAINT nor #endif #endif /* USDT_ARG_CONSTRAINT */ #ifndef USDT_NOP #if defined(__ia64__) || defined(__s390__) || defined(__s390x__) #define USDT_NOP nop 0 #else #define USDT_NOP nop #endif #endif /* USDT_NOP */ /* * Implementation details */ /* USDT name for implicitly-defined USDT semaphore, derived from group:name */ #define __usdt_sema_name(group, name) __usdt_sema_##group##__##name /* ELF section into which USDT semaphores are put */ #define __usdt_sema_sec __attribute__((section(".probes"))) #define __usdt_concat(a, b) a ## b #define __usdt_apply(fn, n) __usdt_concat(fn, n) #ifndef __usdt_nth #define __usdt_nth(_, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N #endif #ifndef __usdt_narg #ifdef __usdt_va_opt #define __usdt_narg(...) __usdt_nth(_ __VA_OPT__(,) __VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #else #define __usdt_narg(...) __usdt_nth(_, ##__VA_ARGS__, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #endif #endif /* __usdt_narg */ #define __usdt_hash # #define __usdt_str_(x) #x #define __usdt_str(x) __usdt_str_(x) #ifndef __usdt_asm_name #define __usdt_asm_name(name) __asm__(__usdt_str(name)) #endif #define __usdt_asm1(a) __usdt_str(a) "\n" #define __usdt_asm2(a,b) __usdt_str(a) "," __usdt_str(b) "\n" #define __usdt_asm3(a,b,c) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "\n" #define __usdt_asm5(a,b,c,d,e) __usdt_str(a) "," __usdt_str(b) "," __usdt_str(c) "," \ __usdt_str(d) "," __usdt_str(e) "\n" #ifdef __LP64__ #define __usdt_asm_addr .8byte #else #define __usdt_asm_addr .4byte #endif #define __usdt_asm_strz_(x) __usdt_asm1(.asciz #x) #define __usdt_asm_strz(x) __usdt_asm_strz_(x) #define __usdt_asm_str_(x) __usdt_asm1(.ascii #x) #define __usdt_asm_str(x) __usdt_asm_str_(x) /* "semaphoreless" USDT case */ #ifndef __usdt_sema_none #define __usdt_sema_none(sema) #endif /* implicitly defined __usdt_sema__group__name semaphore (using weak symbols) */ #ifndef __usdt_sema_implicit #define __usdt_sema_implicit(sema) \ __asm__ __volatile__ ( \ __usdt_asm1(.ifndef sema) \ __usdt_asm3( .pushsection .probes, "aw", "progbits") \ __usdt_asm1( .weak sema) \ __usdt_asm1( .hidden sema) \ __usdt_asm1( .align 2) \ __usdt_asm1(sema:) \ __usdt_asm1( .zero 2) \ __usdt_asm2( .type sema, @object) \ __usdt_asm2( .size sema, 2) \ __usdt_asm1( .popsection) \ __usdt_asm1(.endif) \ ); #endif /* externally defined semaphore using USDT_DEFINE_SEMA() and passed explicitly by user */ #ifndef __usdt_sema_explicit #define __usdt_sema_explicit(sema) \ __asm__ __volatile__ ("" :: "m" (sema)); #endif /* main USDT definition (nop and .note.stapsdt metadata) */ #define __usdt_probe(group, name, sema_def, sema, ...) do { \ sema_def(sema) \ __asm__ __volatile__ ( \ __usdt_asm1(990: USDT_NOP) \ __usdt_asm3( .pushsection .note.stapsdt, "", "note") \ __usdt_asm1( .balign 4) \ __usdt_asm3( .4byte 992f-991f,994f-993f,3) \ __usdt_asm1(991: .asciz "stapsdt") \ __usdt_asm1(992: .balign 4) \ __usdt_asm1(993: __usdt_asm_addr 990b) \ __usdt_asm1( __usdt_asm_addr _.stapsdt.base) \ __usdt_asm1( __usdt_asm_addr sema) \ __usdt_asm_strz(group) \ __usdt_asm_strz(name) \ __usdt_asm_args(__VA_ARGS__) \ __usdt_asm1( .ascii "\0") \ __usdt_asm1(994: .balign 4) \ __usdt_asm1( .popsection) \ __usdt_asm1(.ifndef _.stapsdt.base) \ __usdt_asm5( .pushsection .stapsdt.base,"aG","progbits",.stapsdt.base,comdat)\ __usdt_asm1( .weak _.stapsdt.base) \ __usdt_asm1( .hidden _.stapsdt.base) \ __usdt_asm1(_.stapsdt.base:) \ __usdt_asm1( .space 1) \ __usdt_asm2( .size _.stapsdt.base, 1) \ __usdt_asm1( .popsection) \ __usdt_asm1(.endif) \ :: __usdt_asm_ops(__VA_ARGS__) \ ); \ } while (0) /* * NB: gdb PR24541 highlighted an unspecified corner of the sdt.h * operand note format. * * The named register may be a longer or shorter (!) alias for the * storage where the value in question is found. For example, on * i386, 64-bit value may be put in register pairs, and a register * name stored would identify just one of them. Previously, gcc was * asked to emit the %w[id] (16-bit alias of some registers holding * operands), even when a wider 32-bit value was used. * * Bottom line: the byte-width given before the @ sign governs. If * there is a mismatch between that width and that of the named * register, then a sys/sdt.h note consumer may need to employ * architecture-specific heuristics to figure out where the compiler * has actually put the complete value. */ #if defined(__powerpc__) || defined(__powerpc64__) #define __usdt_argref(id) %I[id]%[id] #elif defined(__i386__) #define __usdt_argref(id) %k[id] /* gcc.gnu.org/PR80115 sourceware.org/PR24541 */ #else #define __usdt_argref(id) %[id] #endif #define __usdt_asm_arg(n) __usdt_asm_str(%c[__usdt_asz##n]) \ __usdt_asm1(.ascii "@") \ __usdt_asm_str(__usdt_argref(__usdt_aval##n)) #define __usdt_asm_args0 /* no arguments */ #define __usdt_asm_args1 __usdt_asm_arg(1) #define __usdt_asm_args2 __usdt_asm_args1 __usdt_asm1(.ascii " ") __usdt_asm_arg(2) #define __usdt_asm_args3 __usdt_asm_args2 __usdt_asm1(.ascii " ") __usdt_asm_arg(3) #define __usdt_asm_args4 __usdt_asm_args3 __usdt_asm1(.ascii " ") __usdt_asm_arg(4) #define __usdt_asm_args5 __usdt_asm_args4 __usdt_asm1(.ascii " ") __usdt_asm_arg(5) #define __usdt_asm_args6 __usdt_asm_args5 __usdt_asm1(.ascii " ") __usdt_asm_arg(6) #define __usdt_asm_args7 __usdt_asm_args6 __usdt_asm1(.ascii " ") __usdt_asm_arg(7) #define __usdt_asm_args8 __usdt_asm_args7 __usdt_asm1(.ascii " ") __usdt_asm_arg(8) #define __usdt_asm_args9 __usdt_asm_args8 __usdt_asm1(.ascii " ") __usdt_asm_arg(9) #define __usdt_asm_args10 __usdt_asm_args9 __usdt_asm1(.ascii " ") __usdt_asm_arg(10) #define __usdt_asm_args11 __usdt_asm_args10 __usdt_asm1(.ascii " ") __usdt_asm_arg(11) #define __usdt_asm_args12 __usdt_asm_args11 __usdt_asm1(.ascii " ") __usdt_asm_arg(12) #define __usdt_asm_args(...) __usdt_apply(__usdt_asm_args, __usdt_narg(__VA_ARGS__)) #define __usdt_is_arr(x) (__builtin_classify_type(x) == 14 || __builtin_classify_type(x) == 5) #define __usdt_arg_size(x) (__usdt_is_arr(x) ? sizeof(void *) : sizeof(x)) /* * We can't use __builtin_choose_expr() in C++, so fall back to table-based * signedness determination for known types, utilizing templates magic. */ #ifdef __cplusplus #define __usdt_is_signed(x) (!__usdt_is_arr(x) && __usdt_t<__typeof(x)>::is_signed) #include template struct __usdt_t { static const bool is_signed = false; }; template struct __usdt_t : public __usdt_t {}; template struct __usdt_t : public __usdt_t {}; #define __usdt_def_signed(T) \ template<> struct __usdt_t { static const bool is_signed = true; }; \ template<> struct __usdt_t { static const bool is_signed = true; }; \ template<> struct __usdt_t { static const bool is_signed = true; }; \ template<> struct __usdt_t { static const bool is_signed = true; } #define __usdt_maybe_signed(T) \ template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; }; \ template<> struct __usdt_t { static const bool is_signed = (T)-1 < (T)1; } __usdt_def_signed(signed char); __usdt_def_signed(short); __usdt_def_signed(int); __usdt_def_signed(long); __usdt_def_signed(long long); __usdt_maybe_signed(char); __usdt_maybe_signed(wchar_t); #else /* !__cplusplus */ #define __usdt_is_inttype(x) (__builtin_classify_type(x) >= 1 && __builtin_classify_type(x) <= 4) #define __usdt_inttype(x) __typeof(__builtin_choose_expr(__usdt_is_inttype(x), (x), 0U)) #define __usdt_is_signed(x) ((__usdt_inttype(x))-1 < (__usdt_inttype(x))1) #endif /* __cplusplus */ #define __usdt_asm_op(n, x) \ [__usdt_asz##n] "n" ((__usdt_is_signed(x) ? (int)-1 : 1) * (int)__usdt_arg_size(x)), \ [__usdt_aval##n] __usdt_str(USDT_ARG_CONSTRAINT)(x) #define __usdt_asm_ops0() [__usdt_dummy] "g" (0) #define __usdt_asm_ops1(x) __usdt_asm_op(1, x) #define __usdt_asm_ops2(a,x) __usdt_asm_ops1(a), __usdt_asm_op(2, x) #define __usdt_asm_ops3(a,b,x) __usdt_asm_ops2(a,b), __usdt_asm_op(3, x) #define __usdt_asm_ops4(a,b,c,x) __usdt_asm_ops3(a,b,c), __usdt_asm_op(4, x) #define __usdt_asm_ops5(a,b,c,d,x) __usdt_asm_ops4(a,b,c,d), __usdt_asm_op(5, x) #define __usdt_asm_ops6(a,b,c,d,e,x) __usdt_asm_ops5(a,b,c,d,e), __usdt_asm_op(6, x) #define __usdt_asm_ops7(a,b,c,d,e,f,x) __usdt_asm_ops6(a,b,c,d,e,f), __usdt_asm_op(7, x) #define __usdt_asm_ops8(a,b,c,d,e,f,g,x) __usdt_asm_ops7(a,b,c,d,e,f,g), __usdt_asm_op(8, x) #define __usdt_asm_ops9(a,b,c,d,e,f,g,h,x) __usdt_asm_ops8(a,b,c,d,e,f,g,h), __usdt_asm_op(9, x) #define __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,x) __usdt_asm_ops9(a,b,c,d,e,f,g,h,i), __usdt_asm_op(10, x) #define __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,x) __usdt_asm_ops10(a,b,c,d,e,f,g,h,i,j), __usdt_asm_op(11, x) #define __usdt_asm_ops12(a,b,c,d,e,f,g,h,i,j,k,x) __usdt_asm_ops11(a,b,c,d,e,f,g,h,i,j,k), __usdt_asm_op(12, x) #define __usdt_asm_ops(...) __usdt_apply(__usdt_asm_ops, __usdt_narg(__VA_ARGS__))(__VA_ARGS__) #endif /* __USDT_H */ fuse-3.18.3/lib/util.c0000644000175000017500000000141315250106036013402 0ustar berndbernd #include "fuse_config.h" #ifdef HAVE_PTHREAD_SETNAME_NP #define _GNU_SOURCE #include #endif #include #include #include #ifndef FUSE_USE_VERSION #define FUSE_USE_VERSION (FUSE_MAKE_VERSION(3, 18)) #endif #include "util.h" #include "fuse_log.h" #include "fuse_lowlevel.h" #include int libfuse_strtol(const char *str, long *res) { char *endptr; int base = 10; long val; errno = 0; if (!str) return -EINVAL; val = strtol(str, &endptr, base); if (errno) return -errno; if (endptr == str || *endptr != '\0') return -EINVAL; *res = val; return 0; } void fuse_set_thread_name(const char *name) { #ifdef HAVE_PTHREAD_SETNAME_NP pthread_setname_np(pthread_self(), name); #else (void)name; #endif } fuse-3.18.3/lib/util.h0000644000175000017500000000214015250106036013405 0ustar berndbernd#ifndef FUSE_UTIL_H_ #define FUSE_UTIL_H_ #include #include #define ROUND_UP(val, round_to) (((val) + (round_to - 1)) & ~(round_to - 1)) #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) struct fuse_conn_info; int libfuse_strtol(const char *str, long *res); void fuse_set_thread_name(const char *name); /** * Return the low bits of a number */ static inline uint32_t fuse_lower_32_bits(uint64_t nr) { return (uint32_t)(nr & 0xffffffff); } /** * Return the high bits of a number */ static inline uint64_t fuse_higher_32_bits(uint64_t nr) { return nr & ~0xffffffffULL; } #ifndef FUSE_VAR_UNUSED #define FUSE_VAR_UNUSED __attribute__((__unused__)) #endif #define container_of(ptr, type, member) \ ({ \ unsigned long __mptr = (unsigned long)(ptr); \ ((type *)(__mptr - offsetof(type, member))); \ }) #if __has_attribute(__fallthrough__) #define fallthrough __attribute__((__fallthrough__)) #else #define fallthrough do {} while (0) #endif #endif /* FUSE_UTIL_H_ */ fuse-3.18.3/make_release_tarball.sh0000755000175000017500000000163115250106036016172 0ustar berndbernd#!/bin/sh -x # # Create tarball from Git tag, removing and adding # some files. # set -e if [ -z "$1" ]; then TAG="$(git tag --list 'fuse-3*' --sort=-creatordate | head -1)" else TAG="$1" fi PREV_TAG="$(git tag --list 'fuse-3*' --sort=-creatordate --merged "${TAG}^"| head -1)" MAJOR_REV=${TAG%.*} echo "Creating release tarball for ${TAG}..." git checkout -q "${TAG}" doxygen doc/Doxyfile mkdir "${TAG}" git archive --format=tar "${TAG}" | tar -x "--directory=${TAG}" find "${TAG}" -name .gitignore -delete rm -r "${TAG}/make_release_tarball.sh" \ "${TAG}/.github" \ "${TAG}/.cirrus.yml" cp -a doc/html "${TAG}/doc/" tar -czf "${TAG}.tar.gz" "${TAG}/" signify-openbsd -S -s signify/$MAJOR_REV.sec -m $TAG.tar.gz signify-openbsd -V -m ${TAG}.tar.gz -p signify/$MAJOR_REV.pub echo "Contributors from ${PREV_TAG} to ${TAG}:" git log --pretty="format:%an <%aE>" "${PREV_TAG}..${TAG}" | sort -u fuse-3.18.3/meson.build0000644000175000017500000002562515250106036013670 0ustar berndberndproject('libfuse3', ['c'], version: '3.18.3', meson_version: '>= 0.60.0', default_options: [ 'buildtype=debugoptimized', 'c_std=gnu11', 'cpp_std=c++20', 'warning_level=2', ]) # Would be better to create the version string # from integers, i.e. concatenating strings instead # of splitting a string, but 'project' needs to be # the first meson.build keyword... # split version into base and rc version_parts = meson.project_version().split('-') base_version = version_parts[0] version_list = base_version.split('.') FUSE_MAJOR_VERSION = version_list[0] FUSE_MINOR_VERSION = version_list[1] FUSE_HOTFIX_VERSION = version_list[2] FUSE_RC_VERSION = version_parts.length() > 1 ? version_parts[1] : '' platform = host_machine.system() if platform == 'darwin' error('libfuse does not support OS-X.\n' + 'Take a look at http://osxfuse.github.io/ or the more recent\n' + 'https://www.fuse-t.org/ instead') elif platform == 'cygwin' or platform == 'windows' error('libfuse does not support Windows.\n' + 'Take a look at http://www.secfs.net/winfsp/ instead') endif cc = meson.get_compiler('c') # # Feature detection, the resulting config file is installed # with the package. # Note: Symbols need to be care fully named, to avoid conflicts # with applications linking to libfuse and including # this config. # public_cfg = configuration_data() public_cfg.set('FUSE_MAJOR_VERSION', FUSE_MAJOR_VERSION) public_cfg.set('FUSE_MINOR_VERSION', FUSE_MINOR_VERSION) public_cfg.set('FUSE_HOTFIX_VERSION', FUSE_HOTFIX_VERSION) public_cfg.set('FUSE_RC_VERSION', FUSE_RC_VERSION) # Default includes when checking for presence of functions and # struct members include_default = ''' #include #include #include #include #include #include #include #include /* For pthread_setname_np */ ''' args_default = [ '-D_GNU_SOURCE' ] # # Feature detection, only available at libfuse compilation time, # but not for application linking to libfuse. # private_cfg = configuration_data() private_cfg.set_quoted('PACKAGE_VERSION', meson.project_version()) # Test for presence of some functions test_funcs = [ 'fork', 'fstatat', 'openat', 'readlinkat', 'pipe2', 'splice', 'vmsplice', 'posix_fallocate', 'fdatasync', 'utimensat', 'copy_file_range', 'fallocate', 'fspacectl' ] foreach func : test_funcs private_cfg.set('HAVE_' + func.to_upper(), cc.has_function(func, prefix: include_default, args: args_default)) endforeach # Special case checks that need custom code special_funcs = { 'pthread_setname_np': ''' #include int main(void) { pthread_t thread = pthread_self(); pthread_setname_np(thread, "test"); return 0; } ''', 'close_range': ''' #include #include #ifdef linux #include #endif int main(void) { unsigned int flags = CLOSE_RANGE_UNSHARE; return close_range(3, ~0U, flags); } ''', 'listmount': ''' #include #include #include #include int main(int argc, char *argv[]) { struct mnt_id_req req = { .size = sizeof(struct mnt_id_req), .mnt_id = LSMT_ROOT, }; uint64_t mnt_ids[1]; int n = syscall(SYS_listmount, &req, &mnt_ids, 1, 0); if (n == -1) { return -1; } } ''' } foreach name, code : special_funcs private_cfg.set('HAVE_' + name.to_upper(), cc.links(code, args: args_default, name: name + ' check')) endforeach # Headers checks test_headers = [ 'sys/xattr.h', 'linux/limits.h' ] foreach header : test_headers private_cfg.set('HAVE_' + header.underscorify().to_upper(), cc.has_header(header)) endforeach # Regular function checks private_cfg.set('HAVE_SETXATTR', cc.has_function('setxattr', prefix: '#include ')) private_cfg.set('HAVE_ICONV', cc.has_function('iconv', prefix: '#include ')) private_cfg.set('HAVE_BACKTRACE', cc.has_function('backtrace', prefix: '#include ')) private_cfg.set('HAVE_STATX', cc.has_function('statx', prefix : '#define _GNU_SOURCE\n#include ')) # Struct member checks private_cfg.set('HAVE_STRUCT_STAT_ST_ATIM', cc.has_member('struct stat', 'st_atim', prefix: include_default + '#include ', args: args_default)) private_cfg.set('HAVE_STRUCT_STAT_ST_ATIMESPEC', cc.has_member('struct stat', 'st_atimespec', prefix: include_default + '#include ', args: args_default)) private_cfg.set('USDT_ENABLED', get_option('enable-usdt')) # Check for liburing with SQE128 support code = ''' #include #include int main(void) { struct io_uring ring; int ret = io_uring_queue_init(1, &ring, 0); #ifndef IORING_SETUP_SQE128 #error "No SQE128 support" #endif return ret; }''' liburing = dependency('liburing', required: false) libnuma = dependency('numa', required: false) if get_option('enable-io-uring') and liburing.found() and libnuma.found() if cc.links(code, name: 'liburing linking and SQE128 support', dependencies: [liburing]) private_cfg.set('HAVE_URING', true) endif endif # A custom io peer might not be a kernel and can forge requests libfuse parses # without bounds checks. Off unless a build asks for it. private_cfg.set('HAVE_CUSTOM_IO', get_option('enable-custom-io')) if get_option('enable-custom-io') warning('enable-custom-io lets a peer that might not be a kernel send ' + 'requests that libfuse parses without bounds checks, so a ' + 'forged request can crash or corrupt the filesystem process - ' + 'see doc/README.custom-io.') endif # # Compiler configuration # add_project_arguments('-D_REENTRANT', '-DHAVE_LIBFUSE_PRIVATE_CONFIG_H', '-Wno-sign-compare', '-D_FILE_OFFSET_BITS=64', '-Wstrict-prototypes', '-Wmissing-declarations', '-Wwrite-strings', '-fno-strict-aliasing', language: 'c') add_project_arguments('-D_REENTRANT', '-DHAVE_LIBFUSE_PRIVATE_CONFIG_H', '-D_GNU_SOURCE', '-D_FILE_OFFSET_BITS=64', '-Wno-sign-compare', '-Wmissing-declarations', '-Wwrite-strings', '-fno-strict-aliasing', language: 'cpp') # Some (stupid) GCC versions warn about unused return values even when they are # casted to void. This makes -Wunused-result pretty useless, since there is no # way to suppress the warning when we really *want* to ignore the value. code = ''' __attribute__((warn_unused_result)) int get_4() { return 4; } int main(void) { (void) get_4(); return 0; }''' if not cc.compiles(code, args: [ '-O0', '-Werror=unused-result' ]) message('Compiler warns about unused result even when casting to void') add_project_arguments('-Wno-unused-result', language: 'c') endif # It is hard to detect if the libc supports versioned symbols. Only gnu-libc # seems to provide that, but then glibc is the main target for libfuse, so # enable it by default versioned_symbols = 1 # This is an attempt to detect if another libc is used. code = ''' int main(void) { #if (defined(__UCLIBC__) || defined(__APPLE__)) #error /* libc does not have versioned symbols */ #endif return 0; }''' if not cc.compiles(code, args: [ '-O0' ]) versioned_symbols = 0 endif # The detection can be overridden, which is useful for other (above unhandled) # libcs and also especially useful for testing if get_option('disable-libc-symbol-version') versioned_symbols = 0 endif if versioned_symbols == 1 message('Enabling versioned libc symbols') public_cfg.set('LIBFUSE_BUILT_WITH_VERSIONED_SYMBOLS', 1) # gcc-10 and newer support the symver attribute which we need to use if we # want to support LTO # recent clang and gcc both support __has_attribute (and if they are too old # to have __has_attribute, then they are too old to support symver) # other compilers might not have __has_attribute, but in those cases # it is safe for this check to fail and for us to fallback to the old _asm_ # method for symver. Anyway the attributes not supported by __has_attribute() # unfortunately return true giving a false positive. So let's try to build # using __attribute__ ((symver )) and see the result. code = ''' __attribute__ ((symver ("test@TEST"))) void foo(void) { } int main(void) { return 0; }''' if cc.compiles(code, args: [ '-O0', '-c', '-Werror']) message('Compiler supports symver attribute') add_project_arguments('-DHAVE_SYMVER_ATTRIBUTE', language: 'c') else message('Compiler does not support symver attribute') endif else message('Disabling versioned libc symbols') endif # Older versions of musl libc don't unescape entries in /etc/mtab # Try to detect this behaviour, and work around, if necessary. detect_getmntent_needs_unescape = ''' #define _GNU_SOURCE #include #include #include #include #define dir_space_tab "dir\\040space\\011tab" int main() { const char *fake_mtab = "name " dir_space_tab " type opts 0 0\n"; FILE *f = fmemopen((void *)fake_mtab, strlen(fake_mtab) + 1, "r"); struct mntent *entp = getmntent(f); fclose(f); if(NULL == entp) exit(EXIT_FAILURE); if (0 == strcmp(entp->mnt_dir, dir_space_tab)) printf("needs escaping\n"); else printf("no need to escape\n"); } ''' if not meson.is_cross_build() result = cc.run(detect_getmntent_needs_unescape) if result.compiled() and result.returncode() == 0 and result.stdout().strip() == 'needs escaping' message('getmntent does not unescape') add_project_arguments('-DGETMNTENT_NEEDS_UNESCAPING', language: 'c') endif endif # Write private test results into fuse_config.h (stored in build directory) configure_file(output: 'fuse_config.h', configuration : private_cfg) # Write the test results, installed with the package, # symbols need to be properly prefixed to avoid # symbol (define) conflicts configure_file(output: 'libfuse_config.h', configuration : public_cfg, install: true, install_dir: join_paths(get_option('includedir'), 'fuse3')) # '.' will refer to current build directory, which contains config.h include_dirs = include_directories('include', 'lib', '.') # Common dependencies thread_dep = dependency('threads') # # Read build files from sub-directories # subdirs = [ 'lib', 'include'] if get_option('utils') and not platform.endswith('bsd') and platform != 'dragonfly' subdirs += [ 'util', 'doc' ] endif if get_option('examples') subdirs += 'example' endif if get_option('tests') subdirs += 'test' endif foreach n : subdirs subdir(n) endforeach fuse-3.18.3/meson_options.txt0000644000175000017500000000313415250106036015152 0ustar berndberndoption('disable-mtab', type : 'boolean', value : false, description: 'Disable and ignore usage of /etc/mtab') option('udevrulesdir', type : 'string', value : '', description: 'Where to install udev rules (if empty, query pkg-config(1))') option('initscriptdir', type : 'string', value : '/etc/init.d/', description: 'Init script installation location (if empty, disable init script installation)') option('utils', type : 'boolean', value : true, description: 'Whether or not to build and install helper programs') option('examples', type : 'boolean', value : true, description: 'Whether or not to build example programs') option('useroot', type : 'boolean', value : true, description: 'Set owner and setuid bits on installed files') option('tests', type : 'boolean', value : true, description: 'Compile the test files') option('disable-libc-symbol-version', type : 'boolean', value : false, description: 'Disable versioned symbols through libc') option('enable-usdt', type : 'boolean', value : false, description: 'Enable user statically defined tracepoints for extra observability') option('enable-io-uring', type: 'boolean', value: true, description: 'Enable fuse-over-io-uring support') option('enable-custom-io', type: 'boolean', value: false, description: 'Enable fuse_session_custom_io(), which serves the protocol over a caller-provided fd instead of /dev/fuse. The peer might not be a kernel and can forge requests that libfuse parses without bounds checks, crashing or corrupting the filesystem process - see doc/README.custom-io') fuse-3.18.3/requirements.txt0000644000175000017500000000030715250106036015000 0ustar berndbernd# Packages required for building and testing libfuse only, # no python code is required when using libfuse. # Build packages: meson ninja # Test packages: the suite itself is standard library only. fuse-3.18.3/signify/0000755000175000017500000000000015250106404013163 5ustar berndberndfuse-3.18.3/signify/fuse-3.15.pub0000644000175000017500000000013715250106036015223 0ustar berndbernduntrusted comment: signify public key RWRsNRJIAGSHE0C6WuVmusQlvudAPlmOOkCw1LbuOLuu+25DuAmPCpDf fuse-3.18.3/signify/fuse-3.16.pub0000644000175000017500000000013715250106036015224 0ustar berndbernduntrusted comment: signify public key RWQtnc3WSoYwHGAdfvtTTVX8RsAXrNwMb8xqVwlY8lYY2Fxn2QUDiPYK fuse-3.18.3/signify/fuse-3.17.pub0000644000175000017500000000013715250106036015225 0ustar berndbernduntrusted comment: signify public key RWQqzcI/bjQ4/nouPgwUbs0WorZncrBxJHmiCb2N+GrMs9L6YAcGSFY/ fuse-3.18.3/signify/fuse-3.18.pub0000644000175000017500000000013715250106036015226 0ustar berndbernduntrusted comment: signify public key RWS6gMnNrKp/zRSYWv13J+KwXE26vCUsbC/hVZmjQ8PA3xjixGLjodz3 fuse-3.18.3/signify/fuse-3.19.pub0000644000175000017500000000013715250106036015227 0ustar berndbernduntrusted comment: signify public key RWR4cEcMGJhD3Dnd3NOeJck3WiuVt9A7mrkq+nQYwrwwmMdDDAan/YiU fuse-3.18.3/test/0000755000175000017500000000000015250106404012472 5ustar berndberndfuse-3.18.3/test/cases/0000755000175000017500000000000015250106036013571 5ustar berndberndfuse-3.18.3/test/cases/README.md0000644000175000017500000004457215250106036015064 0ustar berndbernd# Writing a libfuse test ## The runner `test/run-tests.py` is the suite. A plain Python program with no test framework under it — run it directly; `meson test` only wraps it. Per run it - discovers every executable `cases/**/*.sh`, then narrows by `-t`, `-g`, `-X` and `test/exclude`; - runs `printcap` once, so every script sees the same `$FUSE_CAPS`; - gives each test a private work directory and its own cgroup; - launches the script as `bash -e`, cwd its own log directory, and enforces `# TIMEOUT:` as a wall-clock bound; - kills that cgroup afterwards, pass or fail, so a leaked daemon cannot wedge the next test; - turns the exit status plus what it collected — cores, suspicious log lines — into PASS/SKIP/FAIL, prints the counts and the slowest five, and exits non-zero if anything failed. `-j` tests run at once, so nothing may depend on a global name. One run, end to end — `->` calls or execs, `=>` spawns and waits, `..>` writes a file, `[ ]` a process of its own: ```text meson test -C build (two entries: fuse-tests, fuse-tests-io-uring) -> test/run-tests.py --build-dir -> discover() cases/**/*.sh + cases/unit/ markers -> TestRunner.run_all() -> _run_batch(serial group, jobs=1) -> _run_batch(rest, jobs=N) -> run_one(spec) -> prepare() mnt/ src/ tmp/ logs/ + env contract -> write_repro() ..> logs/repro.sh => [ /bin/sh -c LAUNCHER ] ..> /cgroup.procs (self-move) -> ulimit -S -c "$(ulimit -H -c)" -> exec bash -e cases/.sh -> . cases/lib/common.sh -> fuse_mount_at => [ fs daemon ] ..> logs/fs-N-*.out -> fuse_wait_mount -> _fuse_assert_uring -> _check -> python3 cases/lib/checks.py -> fuse_umount -> fusermount3 -u -> _stream() ..> logs/script.out, logs/timestamps.out -- timeout? -> dump_stacks() ..> ps.txt kstack.N.txt gdbstack.N.txt -> _kill() ..> /cgroup.kill -> collect_cores() -> gdb ..> backtrace...txt -> scan_logs() suspicious words, minus logs/.allow -> classify() PASS | FAIL | SKIP(77) -> report() / discard_workdir() -> summarise() ``` ## What a test is An executable `*.sh` anywhere under `test/cases/`. Its **name** is the path below `cases/` without the extension, so `cases/examples/hello-direct.sh` is `examples/hello-direct`. | exit code | meaning | |---------------|------------------------------------| | 0 | PASS | | 77 | SKIP — the script called `_notrun` | | anything else | FAIL | Nothing registers a test anywhere. Dropping the file in and making it executable is the whole step; `test/run-tests.py` discovers it. `test/cases/unit/` is the exception to all of the above. A C test that needs neither a mount nor a gate has no script there — only a file named after the binary, which the runner execs from `$FUSE_TEST_BIN_DIR` with no shell in between. It carries no exec bit, and its content is a header block or nothing at all. ## The skeleton ```sh #!/usr/bin/env bash # GROUP: examples quick . "$TEST_LIB/common.sh" _require_cap FUSE_CAP_WRITEBACK_CACHE # skip (77) if unsupported fuse_mount passthrough_ll -o writeback,source="$TEST_SRC" _check fuse_test_open_write "$TEST_SRC" "$TEST_MNT" fuse_umount ``` `#!/usr/bin/env bash`, not `#!/bin/bash`: FreeBSD has no bash in base, and `common.sh` needs bash for the `FUSE_FS_*` arrays and `$SECONDS`. A case that sources a body from `lib/` gets `common.sh` with it and does not name it itself. Source it directly only when there is no body, or when the case gates before one — a gate has to run before the body, which is the whole test. ## The environment you get The runner exports all of this into every script: ```sh TEST_NAME=examples/hello-ll-direct # discovery name TEST_SCRIPT=/…/test/cases/examples/hello-ll-direct.sh TEST_DIR=/…/test # source tree, never the build dir TEST_LIB=/…/test/cases/lib # what tests source from TEST_WORKDIR=/…/run/examples/hello-ll-direct TEST_MNT=$TEST_WORKDIR/mnt TEST_SRC=$TEST_WORKDIR/src TEST_TMP=$TEST_WORKDIR/tmp TEST_LOGDIR=$TEST_WORKDIR/logs # also the cwd of your script BUILD_DIR=/…/build # meson build root FUSE_EXAMPLE_DIR=$BUILD_DIR/example FUSE_TEST_BIN_DIR=$BUILD_DIR/test FUSE_UTIL_DIR=$BUILD_DIR/util FUSE_CAPS="FUSE_CAP_ASYNC_READ FUSE_CAP_POSIX_LOCKS …" # printcap, run once FUSE_UID=1000 # effective uid FUSE_OS=Linux # platform.system() PATH=$FUSE_UTIL_DIR:$FUSE_EXAMPLE_DIR:$PATH ``` `$TEST_MNT`, `$TEST_SRC` and `$TEST_TMP` already exist and are yours alone, so a test never invents a temporary directory or worries about colliding with a concurrent test. `$FUSE_OS` is exported so no script shells out to `uname -s`. ## Header directives Only two exist. Anything else in the leading comment block is an ordinary comment. ```sh # TIMEOUT: 180 # seconds; the default is 60 # GROUP: examples serial ``` `# GROUP:` names are used by `run-tests.py -g`. ## Errexit is on The runner runs your script as `bash -e`, so any command that fails and is not checked ends the test there. Nothing to add to the script. What it means when writing one is that a command you *expect* to fail must say so — `cmd || true`, or an `if`, or `_assert_errno`. The same applies to a test you write as a bare condition: `[ -n "$x" ] && cmd` returns non-zero when `$x` is empty and ends the test. Write `[ -z "$x" ] || cmd` instead. Run a test by hand the same way (`bash -e cases/…`, or the `repro.sh` the runner writes) or it will behave differently from CI. ## Skipping > Gate on a feature, never on a version. `_require_cap FUSE_CAP_X` asks the > running kernel what it supports; `_require_binary`, `_require_root` and > `_require_prog` ask about the environment. There is deliberately no > `_require_kernel_version`: a version comparison is wrong the moment the fix > is backported. If a feature has no capability flag, grep the filesystem's own > log for whatever it prints when the kernel refuses > (`_require_fs_marker_absent`), or let the test fail on old kernels and have > those targets exclude it by name via `test/exclude` or `-X`. > > A *platform* is the one exception, because it is not a version: > `/proc/self/mountinfo` will not be backported to FreeBSD. `_require_linux > ` states which Linux-only facility the test needs. Put it in the shared > body when a whole family is affected, not in each caller. ```sh _fail # exit 1 with a message _notrun # exit 77; the runner records the reason _require_root # / _require_nonroot _is_linux # true/false, for a conditional section _require_linux # skip off Linux, naming the facility _require_cap FUSE_CAP_NAME # skip unless printcap reported it _require_binary example/null # skip unless $BUILD_DIR/ is executable _require_prog losetup # skip unless it is on $PATH _require_fuse_device # the kernel module, without the setuid check _require_not_32bit_on_64 _require_reachable_without_caps _require_fs_marker_absent [fs-index] ``` Sourcing `common.sh` also gates the case on FUSE being usable at all — the module loaded, and a setuid `fusermount3` when you are not root — because every case that mounts needs both. A case that never mounts says so *before* sourcing, and runs anyway: ```sh _fuse_no_mount_needed=1 . "$TEST_LIB/common.sh" ``` ## Mounting ```sh fuse_mount [args...] # $TEST_MNT, foreground (-f) fuse_mount_at [args...] # explicit mountpoint, no -f fuse_mount_helper [args...] # via mount.fuse3 fuse_umount [idx] # and require the daemon to exit 0 fuse_umount_lazy [idx] # the give-up path; the trap uses it fuse_wait_mount [predicate] fuse_fs_pid [idx] / fuse_fs_log [idx] ``` A filesystem name is resolved under `$FUSE_EXAMPLE_DIR`, or under `$FUSE_TEST_BIN_DIR` when it is prefixed `test/` (so `test/hello` is the `hello` built in `test/`). Each mount gets an index, and every one of them is unmounted and killed by an EXIT trap, so an aborting test never leaks a mount. Register your own cleanup with `_at_exit ` rather than `trap`, or you will replace that trap. ### Daemons run in the foreground `fuse_mount` passes `-f`, and a case that launches a filesystem itself is expected to do the same. The runner owns the process: the daemon has to stay in the test's cgroup for the timeout to reach it, and its stderr has to stay attached to `logs/fs-N-*.out`. That leaves the backgrounded path — `fuse_daemonize_early_start()`, the parent waiting for the mount, `stdout`/`stderr` closed once FUSE_INIT is answered — covered only by the `mount.fuse3` cases, which is where synchronous FUSE_INIT is reached as well. Covering it properly needs foreground and background variants of the existing cases; that has not been done. ## Assertions > Shell owns mounting, sequencing and skipping. It does not own checks. > `_assert_eq`, `_assert_ne`, `_assert_file_eq` and `_wait_for` exist because > shell expresses them exactly. Everything else is a `checks.py` subcommand — > and if what you need is not there, **add a subcommand rather than > approximating it in shell**. An `errno` compared against `strerror` text, a > timestamp rounded by `touch -d`, an option set split by `awk`: each is a > weaker test than the Python one line of `checks.py` would have been. A check is a subcommand of `test/cases/lib/checks.py`, not a command and not a shell function. `_check` runs it: ```sh _check fuse_test_open_write "$TEST_SRC" "$TEST_MNT" # runs: python3 test/cases/lib/checks.py fuse_test_open_write ``` Every name is prefixed `fuse_test_` so a reader never has to wonder whether `unlink` in a test script means coreutils or a check. The list below is all of them; if what you need is missing, add it to `checks.py`. ```sh # file and directory operations fuse_test_unlink [--src ] # create, unlink, require ENOENT fuse_test_mkdir # directory create fuse_test_rmdir [--src ] # directory remove fuse_test_symlink # symlink and read it back fuse_test_create # O_CREAT, then mode/nlink/size fuse_test_link # hard link, nlink, unlink fuse_test_chown # chown uid then gid separately fuse_test_utimens [--ns-tol N] # nanosecond timestamps fuse_test_xattr # set/get/remove fuse_test_statvfs # statvfs succeeds # reading and writing fuse_test_open_read # write via src, read through the mount fuse_test_open_write # create via src, write through the mount fuse_test_append # O_APPEND writes fuse_test_seek # lseek writes fuse_test_open_unlink # write to an unlinked fd fuse_test_truncate_path # grow and shrink by path fuse_test_truncate_fd # grow and shrink by fd # listing and comparison fuse_test_listdir # print the entries fuse_test_listdir_first # print the first entry fuse_test_assert_listdir ... # exactly these entries fuse_test_readdir [--inode-check M] # listing and inodes fuse_test_readdir_big [--inode-check M] # 500 entries fuse_test_passthrough [--inode-check M] # both sides agree # predicates and errno fuse_test_size # print st_size fuse_test_ismount # is it a mountpoint fuse_test_isbigger # is it bigger than that fuse_test_expect_errno [args...] # require exactly that errno # mount state fuse_test_mountinfo # one /proc/self/mountinfo field fuse_test_assert_mount_opt ... # present in mount_options fuse_test_refute_mount_opt ... # absent from mount_options fuse_test_assert_super_opt ... # present in super_options fuse_test_assert_super_opt_prefix

    ... # e.g. user_id= fuse_test_assert_fstype ... # any one is acceptable fuse_test_assert_source ... # any one is acceptable fuse_test_fusermount_rejects # fusermount3 refuses to mount it # the remainder fuse_test_printcap_caps # every FUSE_CAP_* is in the header fuse_test_reachable_without_caps # mode-bit walk up the tree fuse_test_elf_class # 32 or 64, from e_ident fuse_test_null_roundtrip # read zeros, then write fuse_test_cuse_roundtrip # read/write/offset exchange fuse_test_uds_init # a FUSE INIT handshake ``` `--inode-check M` is `exact` (the default) or `nonzero`. `` for `fuse_test_expect_errno` is one of `fuse_test_open_rw`, `fuse_test_open_ro` or `fuse_test_stat`. `` for `fuse_test_fusermount_rejects` is `not_dir_or_regular`, `no_write_access` or `no_such_file`. `common.sh` wraps the common ones in shell functions, which keep the underscore-prefixed naming shell uses elsewhere: `_assert_errno`, `_assert_listdir`, `_assert_xattr_roundtrip`, `mountinfo_field`, `_assert_mount_opt`, `_refute_mount_opt`, `_assert_super_opt`, `_assert_super_opt_prefix`, `_assert_fstype`, `_assert_source`. ## Adding a variant of an existing test A parametrized case becomes a real file, so it gets its own duration, log directory and name in the summary. The variant sets a few variables and sources a shared body from `lib/`: ```sh #!/usr/bin/env bash # cases/examples/hello-ll-mount-fuse-clone_fd.sh # GROUP: examples quick FS_NAME=hello_ll # which example to mount FS_OPTS=clone_fd # -o option list, empty for none LAUNCH=mount_fuse # direct | mount_fuse | mount_fuse_dropcaps . "$TEST_LIB/hello.sh" ``` The shared body carries the gates for the whole family — one `_require_linux "the clone_fd mount option"` in `lib/hello.sh` covers every `clone_fd` variant — so a new caller inherits them. ## Suspicious output fails a test Anything a daemon writes matching `error`, `warning`, `fatal`, `crash`, `abort`, `exception`, `traceback`, `fault` or `uninitialised` fails the test even when it exited 0. If that is a false positive for your test, exempt the exact line: ```sh fuse_allow_output '^ \d\d \[[^]]+ message: .No error: 0.\]' ``` A core dump fails the test the same way. A test that deliberately crashes something opts out per executable with `fuse_allow_core `. ## When a test fails ``` $TEST_WORKDIR/logs/script.out what the test printed $TEST_WORKDIR/logs/fs-0-*.out what the filesystem daemon printed $TEST_WORKDIR/logs/fs-0-*.status its exit status $TEST_WORKDIR/logs/core.. core, one per crashed process $TEST_WORKDIR/logs/backtrace...txt its gdb backtrace $TEST_WORKDIR/logs/repro.sh re-run this one test, same env, by hand ``` On a CI failure this whole tree is downloadable from the job's `test-logs` artifact, minus the raw cores — the backtraces the runner already resolved are what is worth keeping. A test's directory is removed as soon as it passes or skips, and the run directory itself when nothing failed at all — so what is left afterwards is exactly what is worth looking at (and uploading). `--keep-logs` keeps everything anyway. ## Running them `--build-dir` is the only option a run normally needs; it defaults to `.`. ```sh ./test/run-tests.py --build-dir build # everything ./test/run-tests.py -t 'examples/hello-*' # fnmatch on the name, repeatable ./test/run-tests.py -g quick # only this GROUP, repeatable ./test/run-tests.py -X misc/hello-uds # skip one, repeatable ./test/run-tests.py -l # list the selection, run nothing ./test/run-tests.py -j1 -v # serially, output live ./test/run-tests.py -j8 # default is cpu_count // 2 ./test/run-tests.py --repeat 20 -t misc/x # chase a flake ./test/run-tests.py --timeout 300 # override every # TIMEOUT: ./test/run-tests.py --keep-logs # keep passing tests' output too ``` `-t` and `-g` narrow; `-X` and `test/exclude` remove from what is left. A `-t` pattern may also be the path to a case, so it can be tab-completed: `test/cases/examples/cuse.sh` and `examples/cuse` name the same test, from any directory. A directory selects everything under it, by path or by bare name — `-t examples` and `-t test/cases/examples` are the same selection. A pattern that matches no test is an error rather than an empty run. Where the output lands: ```sh --run-dir DIR # this directory, verbatim; so does $FUSE_TEST_RUN_DIR --print-base-dir # print where a run would land, and exit --persist-base-dir DIR # remember DIR in ~/.config/libfuse/tests.conf ``` Without `--run-dir`, a run gets a `run---` leaf under the base, and the leaf is deleted when nothing failed. Unprivileged, without a setuid `fusermount3`, everything that mounts skips itself. `--setuid-helpers` makes the build tree's helpers setuid root (with `sudo`) before the run; it is a no-op once they are. `test/exclude` holds one test name per line for a host that cannot support a test; `-X ` adds to it for one run. `TEST_WITH_VALGRIND=1` traces every daemon and scales the timeouts to match. ## What breaks under -j A test that binds a fixed path, names a device node globally, or takes the first free loop device cannot run concurrently with a copy of itself and must declare `# GROUP: serial`. The three existing cases are `misc/hello-uds` (`hello_ll_uds` hard-codes a socket path in /tmp), `examples/cuse` (it names a device node globally) and `mount/blkdev-fsname-*` (`losetup -f` races). fuse-3.18.3/test/cases/ctests/0000755000175000017500000000000015250106036015076 5ustar berndberndfuse-3.18.3/test/cases/ctests/api-30.sh0000755000175000017500000000025315250106036016426 0ustar berndbernd#!/usr/bin/env bash # GROUP: ctests # Serve a filesystem built against the FUSE_USE_VERSION 30 API. . "$TEST_LIB/common.sh" "$FUSE_TEST_BIN_DIR/test_api_30" "$TEST_MNT" fuse-3.18.3/test/cases/ctests/signals.sh0000755000175000017500000000020015250106036017065 0ustar berndbernd#!/usr/bin/env bash # GROUP: ctests # Signal handling, issue #1182. . "$TEST_LIB/common.sh" "$FUSE_TEST_BIN_DIR/test_signals" fuse-3.18.3/test/cases/ctests/write-cache-writeback.sh0000755000175000017500000000025115250106036021577 0ustar berndbernd#!/usr/bin/env bash # GROUP: ctests . "$TEST_LIB/common.sh" _require_cap FUSE_CAP_WRITEBACK_CACHE "$FUSE_TEST_BIN_DIR/test_write_cache" "$TEST_MNT" -owriteback_cache fuse-3.18.3/test/cases/ctests/write-cache.sh0000755000175000017500000000057715250106036017641 0ustar berndbernd#!/usr/bin/env bash # GROUP: ctests . "$TEST_LIB/common.sh" _require_cap FUSE_CAP_WRITEBACK_CACHE # --delay_ms tests that close(rofd) does not block waiting for pending writes, # which needs a390ccb316be ("fuse: add FOPEN_NOFLUSH"). The suite assumes a # current kernel; an older target excludes this test by name. "$FUSE_TEST_BIN_DIR/test_write_cache" "$TEST_MNT" --delay_ms=200 fuse-3.18.3/test/cases/examples/0000755000175000017500000000000015250106036015407 5ustar berndberndfuse-3.18.3/test/cases/examples/cuse.sh0000755000175000017500000000154215250106036016707 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples serial . "$TEST_LIB/common.sh" # example/cuse is built on FreeBSD too, so an unbuilt binary is not a proxy # for "cannot run": CUSE is a Linux FUSE protocol feature. _require_linux CUSE _require_root _require_binary example/cuse _require_not_32bit_on_64 "$FUSE_EXAMPLE_DIR/cuse" # The device node is named globally, hence GROUP serial. devname=cuse-test-$$ devpath=/dev/$devname # cuse takes no mountpoint: it names its device with --name, and the test # ends by terminating it rather than unmounting anything. log=$TEST_LOGDIR/fs-0-cuse.out "$FUSE_EXAMPLE_DIR/cuse" -f --name="$devname" >"$log" 2>&1 & cuse_pid=$! _at_exit "kill $cuse_pid 2>/dev/null" _wait_for 30 "[ -e '$devpath' ]" || { cat "$log" >&2 _fail "cuse did not create $devpath" } _check fuse_test_cuse_roundtrip "$devpath" "$FUSE_EXAMPLE_DIR/cuse_client" fuse-3.18.3/test/cases/examples/dev-auto-unmount-nonroot.sh0000755000175000017500000000063315250106036022673 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" # Root can mount with dev and auto_unmount; a non-root user cannot use the # device nodes it exposes. Split in two so the summary says which half ran. _require_nonroot _require_binary example/passthrough_ll fuse_mount passthrough_ll -o source=/dev,dev,auto_unmount >/dev/null _assert_errno EACCES fuse_test_open_ro "$TEST_MNT/null" fuse_umount fuse-3.18.3/test/cases/examples/dev-auto-unmount-root.sh0000755000175000017500000000060015250106036022152 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" # Root can mount with dev and auto_unmount; a non-root user cannot use the # device nodes it exposes. Split in two so the summary says which half ran. _require_root _require_binary example/passthrough_ll fuse_mount passthrough_ll -o source=/dev,dev,auto_unmount >/dev/null cat "$TEST_MNT/null" >/dev/null fuse_umount fuse-3.18.3/test/cases/examples/hello-direct-clone_fd.sh0000755000175000017500000000016215250106036022067 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS=clone_fd LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-direct.sh0000755000175000017500000000015215250106036020317 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS= LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-dropcaps-clone_fd.sh0000755000175000017500000000017715250106036022436 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS=clone_fd LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-dropcaps.sh0000755000175000017500000000016715250106036020666 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS= LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-direct-clone_fd.sh0000755000175000017500000000016515250106036022477 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS=clone_fd LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-direct.sh0000755000175000017500000000015515250106036020727 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS= LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-dropcaps-clone_fd.sh0000755000175000017500000000020215250106036023030 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS=clone_fd LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-dropcaps.sh0000755000175000017500000000017215250106036021267 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS= LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-mount-fuse-clone_fd.sh0000755000175000017500000000017115250106036023324 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS=clone_fd LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-ll-mount-fuse.sh0000755000175000017500000000016115250106036021554 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello_ll FS_OPTS= LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-mount-fuse-clone_fd.sh0000755000175000017500000000016615250106036022723 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS=clone_fd LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/hello-mount-fuse.sh0000755000175000017500000000015615250106036021153 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=hello FS_OPTS= LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/ioctl-ll.sh0000755000175000017500000000126315250106036017467 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" _require_binary example/ioctl_ll _require_not_32bit_on_64 "$FUSE_EXAMPLE_DIR/ioctl_ll" fuse_mount ioctl_ll >/dev/null testfile=$TEST_MNT/fioc client=$FUSE_EXAMPLE_DIR/ioctl_ll_client # Restricted ioctls only. The unrestricted FIOC_READ/FIOC_WRITE work with # CUSE rather than a regular FUSE mount, and are covered by examples/cuse. _assert_eq "$("$client" get_size "$testfile")" 0 "initial size" printf 'foobar' >"$testfile" _assert_eq "$("$client" get_size "$testfile")" 6 "size after write" "$client" set_size "$testfile" 3 printf 'foo' >"$TEST_TMP/expected" _assert_file_eq "$testfile" "$TEST_TMP/expected" fuse_umount fuse-3.18.3/test/cases/examples/ioctl.sh0000755000175000017500000000107115250106036017057 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" _require_binary example/ioctl _require_not_32bit_on_64 "$FUSE_EXAMPLE_DIR/ioctl" fuse_mount ioctl >/dev/null testfile=$TEST_MNT/fioc client=$FUSE_EXAMPLE_DIR/ioctl_client _assert_eq "$("$client" "$testfile")" 0 "initial size" printf 'foobar' >"$testfile" _assert_eq "$("$client" "$testfile")" 6 "size after write" # With a size argument the client truncates instead of reporting. "$client" "$testfile" 3 printf 'foo' >"$TEST_TMP/expected" _assert_file_eq "$testfile" "$TEST_TMP/expected" fuse_umount fuse-3.18.3/test/cases/examples/null.sh0000755000175000017500000000105515250106036016721 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" _require_binary example/null # The null filesystem replaces a regular file rather than a directory, so # there is no mountpoint to poll for; it announces itself by the size it # reports growing past what the placeholder holds. mnt_file=$TEST_TMP/file printf 'dummy' >"$mnt_file" null_is_up() { python3 "$TEST_LIB/checks.py" fuse_test_isbigger "$1" 4000 } FUSE_WAIT_PREDICATE=null_is_up fuse_mount_at "$mnt_file" null -f >/dev/null _check fuse_test_null_roundtrip "$mnt_file" fuse_umount fuse-3.18.3/test/cases/examples/passthrough-base-debug.sh0000755000175000017500000000057615250106036022321 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0 -d" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-base.sh0000755000175000017500000000057315250106036021232 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-fh-debug.sh0000755000175000017500000000060115250106036021771 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_fh FS_ARGS="-f -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0 -d" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-fh.sh0000755000175000017500000000057615250106036020720 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_fh FS_ARGS="-f -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-hp-nocache.sh0000755000175000017500000000114615250106036022322 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_hp FS_ARGS="--foreground --nocache" PT_POSITIONAL="$TEST_SRC" INODE_CHECK=exact PT_MIRROR=0 # With the cache on the mount is allowed a stale view of the # source, so nothing may be compared against it. PT_SRC_VISIBLE=1 # The unlinked-testfiles check needs "fuse: fix illegal access to # inode with reused nodeid"; the suite assumes a current kernel. SYSCALL_ARGS=-u . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-hp.sh0000755000175000017500000000071115250106036020721 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_hp FS_ARGS="--foreground" PT_POSITIONAL="$TEST_SRC" INODE_CHECK=exact PT_MIRROR=0 # With the cache on the mount is allowed a stale view of the # source, so nothing may be compared against it. PT_SRC_VISIBLE=0 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-ll-debug.sh0000755000175000017500000000050715250106036022010 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_ll FS_ARGS="-f -o timeout=0 -d" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-ll-writeback-debug.sh0000755000175000017500000000101715250106036023756 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_ll FS_ARGS="-f -o timeout=0 -o writeback -d" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 # With writeback caching the kernel opens files for reading even # when userspace asked for O_WRONLY, which fails unless the # filesystem process has special permission. SYSCALL_ARGS=-53 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-ll-writeback.sh0000755000175000017500000000101415250106036022667 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_ll FS_ARGS="-f -o timeout=0 -o writeback" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 # With writeback caching the kernel opens files for reading even # when userspace asked for O_WRONLY, which fails unless the # filesystem process has special permission. SYSCALL_ARGS=-53 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-ll.sh0000755000175000017500000000050415250106036020721 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough_ll FS_ARGS="-f -o timeout=0" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-plus-debug.sh0000755000175000017500000000060515250106036022363 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f --plus -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0 -d" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-plus.sh0000755000175000017500000000060215250106036021274 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f --plus -o entry_timeout=0,negative_timeout=0,attr_timeout=0,ac_attr_timeout=0" INODE_CHECK=exact PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-zero-ino-debug.sh0000755000175000017500000000065115250106036023143 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f --plus --readdir-zero-inodes -o entry_timeout=0,negative_timeout=0," FS_ARGS+="attr_timeout=0,ac_attr_timeout=0 -d" INODE_CHECK=nonzero PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/passthrough-zero-ino.sh0000755000175000017500000000064615250106036022063 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples passthrough # 500-entry readdir plus test_syscalls over FUSE; the default 60s is # not enough on a loaded runner, and -d makes it slower again. # TIMEOUT: 300 FS_NAME=passthrough FS_ARGS="-f --plus --readdir-zero-inodes -o entry_timeout=0,negative_timeout=0," FS_ARGS+="attr_timeout=0,ac_attr_timeout=0" INODE_CHECK=nonzero PT_MIRROR=1 PT_SRC_VISIBLE=1 . "$TEST_LIB/passthrough.sh" fuse-3.18.3/test/cases/examples/poll.sh0000755000175000017500000000033015250106036016710 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples . "$TEST_LIB/common.sh" fuse_mount poll >/dev/null # poll_client looks at files in its own working directory. (cd "$TEST_MNT" && "$FUSE_EXAMPLE_DIR/poll_client") fuse_umount fuse-3.18.3/test/cases/examples/release-unlink-race.sh0000755000175000017500000000110615250106036021572 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples # Issue #746: RELEASE and UNLINK sent back to back must not race, which is # only triggered when nullpath_ok is set. . "$TEST_LIB/common.sh" fuse_mount test/release_unlink_race >/dev/null # The filesystem mirrors the real tree, so the mount's view of a directory # is that directory prefixed with the mountpoint. race_dir=$TEST_TMP/race mkdir "$race_dir" racefile=$TEST_MNT$race_dir/racefile : >"$racefile" rm "$racefile" # Slow CI pipelines need this for the unlink to finish processing. sleep 3 _assert_listdir "$race_dir" fuse_umount fuse-3.18.3/test/cases/examples/test-hello-direct-clone_fd.sh0000755000175000017500000000016715250106036023051 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS=clone_fd LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/test-hello-direct.sh0000755000175000017500000000015715250106036021301 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS= LAUNCH=direct . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/test-hello-dropcaps-clone_fd.sh0000755000175000017500000000020415250106036023402 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS=clone_fd LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/test-hello-dropcaps.sh0000755000175000017500000000017415250106036021641 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS= LAUNCH=mount_fuse_dropcaps . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/test-hello-mount-fuse-clone_fd.sh0000755000175000017500000000017315250106036023676 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS=clone_fd LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/examples/test-hello-mount-fuse.sh0000755000175000017500000000016315250106036022126 0ustar berndbernd#!/usr/bin/env bash # GROUP: examples quick FS_NAME=test/hello FS_OPTS= LAUNCH=mount_fuse . "$TEST_LIB/hello.sh" fuse-3.18.3/test/cases/lib/0000755000175000017500000000000015250106036014337 5ustar berndberndfuse-3.18.3/test/cases/lib/checks.py0000755000175000017500000010664115250106036016164 0ustar berndbernd#!/usr/bin/env python3 """Everything the shell tests check that shell cannot express exactly. Shell is the dispatch unit, not the implementation language: a test calls this module like any other command and it exits 0 on success, non-zero with a diagnostic on stderr on failure. One subcommand per check, each named fuse_test_* so a test script cannot mistake it for a system command. Re-expressing these in coreutils would silently weaken them -- an errno becomes a strerror string match, an ftruncate on a held fd has no shell equivalent, a nanosecond utimensat becomes whatever `touch -d` rounds to, and a /proc/self/mountinfo parser becomes an awk script that gets the separator field or the \\040 escapes subtly wrong. """ import argparse import errno import filecmp import os import re import shutil import stat import struct import subprocess import sys import time from enum import Enum from os.path import join as pjoin from tempfile import NamedTemporaryFile class CheckFailed(Exception): """An assertion inside a subcommand did not hold; message goes to stderr.""" class InodeCheck(Enum): EXACT = 1 NONZERO = 2 TEST_FILE = os.path.abspath(__file__) with open(TEST_FILE, 'rb') as _fh: TEST_DATA = _fh.read() def name_generator(): """A file name no other invocation in this test will produce. Each check is its own process, so the pid goes into the name -- a plain counter would make the second subcommand collide with the files the first one left behind. """ name_generator.counter += 1 return 'testfile_%d_%d' % (os.getpid(), name_generator.counter) name_generator.counter = 0 def _require(condition, message): if not condition: raise CheckFailed(message) def readdir_inode(path): """Sorted " " lines, from the test/readdir_inode helper.""" binary = pjoin(os.environ['FUSE_TEST_BIN_DIR'], 'readdir_inode') with subprocess.Popen([binary, path], stdout=subprocess.PIPE, universal_newlines=True) as proc: lines = proc.communicate()[0].splitlines() lines.sort() return lines def check_inode(inode_check, actual, expected): if inode_check == InodeCheck.EXACT: _require(expected == actual, 'inode mismatch: got %d, want %d' % (actual, expected)) elif inode_check == InodeCheck.NONZERO: _require(actual != 0, 'inode is zero') def _inode_check(name): return InodeCheck.EXACT if name == 'exact' else InodeCheck.NONZERO class _open_fd: """os.open() as a context manager.""" def __init__(self, name, flags): self.fd = os.open(name, flags) def __enter__(self): return self.fd def __exit__(self, *_exc): os.close(self.fd) def os_create(name): os.close(os.open(name, os.O_CREAT | os.O_RDWR)) def expect_enoent(path): """Require that stat(path) fails with ENOENT.""" try: os.stat(path) except OSError as exc: _require(exc.errno == errno.ENOENT, '%s: expected ENOENT, got %s' % (path, exc.strerror)) return raise CheckFailed('%s: expected ENOENT, but it exists' % path) # ----------------------------------------------------------- POSIX operations def cmd_unlink(mnt_dir, src_dir=None): name = name_generator() fullname = mnt_dir + "/" + name srcname = fullname if src_dir is not None: srcname = pjoin(src_dir, name) with open(srcname, 'wb') as fh: fh.write(b'hello') _require(name in os.listdir(mnt_dir), '%s did not appear' % name) os.unlink(fullname) expect_enoent(fullname) _require(name not in os.listdir(mnt_dir), '%s still listed' % name) def cmd_mkdir(mnt_dir): dirname = name_generator() fullname = mnt_dir + "/" + dirname os.mkdir(fullname) fstat = os.stat(fullname) _require(stat.S_ISDIR(fstat.st_mode), '%s is not a directory' % fullname) _require(os.listdir(fullname) == [], '%s is not empty' % fullname) # Some filesystems (e.g. BTRFS) don't track st_nlink for directories _require(fstat.st_nlink in (1, 2), 'st_nlink is %d' % fstat.st_nlink) _require(dirname in os.listdir(mnt_dir), '%s did not appear' % dirname) def cmd_rmdir(mnt_dir, src_dir=None): name = name_generator() fullname = mnt_dir + "/" + name srcname = fullname if src_dir is not None: srcname = pjoin(src_dir, name) os.mkdir(srcname) _require(name in os.listdir(mnt_dir), '%s did not appear' % name) os.rmdir(fullname) expect_enoent(fullname) _require(name not in os.listdir(mnt_dir), '%s still listed' % name) def cmd_symlink(mnt_dir): linkname = name_generator() fullname = mnt_dir + "/" + linkname os.symlink("/imaginary/dest", fullname) fstat = os.lstat(fullname) _require(stat.S_ISLNK(fstat.st_mode), '%s is not a symlink' % fullname) _require(os.readlink(fullname) == "/imaginary/dest", 'wrong link target: %s' % os.readlink(fullname)) _require(fstat.st_nlink == 1, 'st_nlink is %d' % fstat.st_nlink) _require(linkname in os.listdir(mnt_dir), '%s did not appear' % linkname) def cmd_create(mnt_dir): name = name_generator() fullname = pjoin(mnt_dir, name) expect_enoent(fullname) _require(name not in os.listdir(mnt_dir), '%s already listed' % name) os.close(os.open(fullname, os.O_CREAT | os.O_RDWR)) _require(name in os.listdir(mnt_dir), '%s did not appear' % name) fstat = os.lstat(fullname) _require(stat.S_ISREG(fstat.st_mode), '%s is not a regular file' % fullname) _require(fstat.st_nlink == 1, 'st_nlink is %d' % fstat.st_nlink) _require(fstat.st_size == 0, 'st_size is %d' % fstat.st_size) def cmd_chown(mnt_dir): filename = pjoin(mnt_dir, name_generator()) os.mkdir(filename) fstat = os.lstat(filename) uid = fstat.st_uid gid = fstat.st_gid uid_new = uid + 1 os.chown(filename, uid_new, -1) fstat = os.lstat(filename) _require(fstat.st_uid == uid_new, 'uid is %d' % fstat.st_uid) _require(fstat.st_gid == gid, 'gid changed to %d' % fstat.st_gid) gid_new = gid + 1 os.chown(filename, -1, gid_new) fstat = os.lstat(filename) _require(fstat.st_uid == uid_new, 'uid changed to %d' % fstat.st_uid) _require(fstat.st_gid == gid_new, 'gid is %d' % fstat.st_gid) def cmd_open_read(src_dir, mnt_dir): name = name_generator() with open(pjoin(src_dir, name), 'wb') as fh_out, \ open(TEST_FILE, 'rb') as fh_in: shutil.copyfileobj(fh_in, fh_out) _require(filecmp.cmp(pjoin(mnt_dir, name), TEST_FILE, False), '%s differs from %s' % (pjoin(mnt_dir, name), TEST_FILE)) def cmd_open_write(src_dir, mnt_dir): name = name_generator() os_create(pjoin(src_dir, name)) fullname = pjoin(mnt_dir, name) with open(fullname, 'wb') as fh_out, \ open(TEST_FILE, 'rb') as fh_in: shutil.copyfileobj(fh_in, fh_out) _require(filecmp.cmp(fullname, TEST_FILE, False), '%s differs from %s' % (fullname, TEST_FILE)) def cmd_append(src_dir, mnt_dir): name = name_generator() os_create(pjoin(src_dir, name)) fullname = pjoin(mnt_dir, name) with _open_fd(fullname, os.O_WRONLY) as fd: os.write(fd, b'foo\n') with _open_fd(fullname, os.O_WRONLY | os.O_APPEND) as fd: os.write(fd, b'bar\n') with open(fullname, 'rb') as fh: got = fh.read() _require(got == b'foo\nbar\n', 'appended file holds %r' % got) def cmd_seek(src_dir, mnt_dir): name = name_generator() os_create(pjoin(src_dir, name)) fullname = pjoin(mnt_dir, name) with _open_fd(fullname, os.O_WRONLY) as fd: os.lseek(fd, 1, os.SEEK_SET) os.write(fd, b'foobar\n') with _open_fd(fullname, os.O_WRONLY) as fd: os.lseek(fd, 4, os.SEEK_SET) os.write(fd, b'com') with open(fullname, 'rb') as fh: got = fh.read() _require(got == b'\0foocom\n', 'file holds %r' % got) def cmd_open_unlink(mnt_dir): name = name_generator() data1 = b'foo' data2 = b'bar' fullname = pjoin(mnt_dir, name) with open(fullname, 'wb+', buffering=0) as fh: fh.write(data1) os.unlink(fullname) expect_enoent(fullname) _require(name not in os.listdir(mnt_dir), '%s still listed' % name) fh.write(data2) fh.seek(0) got = fh.read() _require(got == data1 + data2, 'unlinked file holds %r' % got) def cmd_statvfs(mnt_dir): os.statvfs(mnt_dir) def cmd_link(mnt_dir): name1 = pjoin(mnt_dir, name_generator()) name2 = pjoin(mnt_dir, name_generator()) shutil.copyfile(TEST_FILE, name1) _require(filecmp.cmp(name1, TEST_FILE, False), '%s differs from %s' % (name1, TEST_FILE)) fstat1 = os.lstat(name1) _require(fstat1.st_nlink == 1, 'st_nlink is %d' % fstat1.st_nlink) os.link(name1, name2) fstat1 = os.lstat(name1) fstat2 = os.lstat(name2) _require(fstat1 == fstat2, 'stat of the two links differs') _require(fstat1.st_nlink == 2, 'st_nlink is %d' % fstat1.st_nlink) _require(os.path.basename(name2) in os.listdir(mnt_dir), '%s did not appear' % name2) _require(filecmp.cmp(name1, name2, False), '%s and %s differ' % (name1, name2)) # Since RELEASE requests are asynchronous, it is possible that libfuse # still considers the file to be open at this point and (since # -o hard_remove is not used) renames it instead of deleting it. os.unlink(name2) _require(os.path.basename(name2) not in os.listdir(mnt_dir), '%s still listed' % name2) expect_enoent(name2) # See above, we may have to wait until RELEASE has been received before # the st_nlink value is correct. maxwait = time.time() + 2 fstat1 = os.lstat(name1) while fstat1.st_nlink == 2 and time.time() < maxwait: fstat1 = os.lstat(name1) time.sleep(0.1) _require(fstat1.st_nlink == 1, 'st_nlink is %d' % fstat1.st_nlink) os.unlink(name1) def cmd_readdir(src_dir, mnt_dir, inode_check='exact'): inode_check = _inode_check(inode_check) newdir = name_generator() src_newdir = pjoin(src_dir, newdir) mnt_newdir = pjoin(mnt_dir, newdir) file_ = src_newdir + "/" + name_generator() subdir = src_newdir + "/" + name_generator() subfile = subdir + "/" + name_generator() os.mkdir(src_newdir) shutil.copyfile(TEST_FILE, file_) os.mkdir(subdir) shutil.copyfile(TEST_FILE, subfile) listdir_is = sorted(os.listdir(mnt_newdir)) listdir_should = sorted([os.path.basename(file_), os.path.basename(subdir)]) _require(listdir_is == listdir_should, 'readdir returned %r, want %r' % (listdir_is, listdir_should)) inodes_is = readdir_inode(mnt_newdir) if inode_check == InodeCheck.EXACT: inodes_should = readdir_inode(src_newdir) _require(inodes_is == inodes_should, 'inodes %r, want %r' % (inodes_is, inodes_should)) else: _require(all(int(line.split()[0]) != 0 for line in inodes_is), 'a readdir inode is zero: %r' % inodes_is) os.unlink(file_) os.unlink(subfile) os.rmdir(subdir) os.rmdir(src_newdir) def cmd_readdir_big(src_dir, mnt_dir, inode_check='exact'): inode_check = _inode_check(inode_check) # Add enough entries so that readdir needs to be called multiple times. fnames = [] for i in range(500): fname = ('A rather long filename to make sure that we ' 'fill up the buffer - ' * 3) + str(i) with open(pjoin(src_dir, fname), 'w') as fh: fh.write('File %d' % i) fnames.append(fname) listdir_is = sorted(os.listdir(mnt_dir)) listdir_should = sorted(os.listdir(src_dir)) _require(listdir_is == listdir_should, 'mount lists %d entries, source lists %d' % (len(listdir_is), len(listdir_should))) inodes_is = readdir_inode(mnt_dir) if inode_check == InodeCheck.EXACT: inodes_should = readdir_inode(src_dir) _require(inodes_is == inodes_should, 'readdir inodes differ') else: _require(all(int(line.split()[0]) != 0 for line in inodes_is), 'a readdir inode is zero') for fname in fnames: stat_src = os.stat(pjoin(src_dir, fname)) stat_mnt = os.stat(pjoin(mnt_dir, fname)) check_inode(inode_check, stat_mnt.st_ino, stat_src.st_ino) _require(stat_src.st_mtime == stat_mnt.st_mtime, 'st_mtime differs') _require(stat_src.st_ctime == stat_mnt.st_ctime, 'st_ctime differs') _require(stat_src.st_size == stat_mnt.st_size, 'st_size differs') os.unlink(pjoin(src_dir, fname)) def cmd_truncate_path(mnt_dir): _require(len(TEST_DATA) > 1024, 'test data is too short') filename = pjoin(mnt_dir, name_generator()) with open(filename, 'wb') as fh: fh.write(TEST_DATA) size = os.stat(filename).st_size _require(size == len(TEST_DATA), 'st_size is %d' % size) # Add zeros at the end os.truncate(filename, size + 1024) _require(os.stat(filename).st_size == size + 1024, 'grow failed') with open(filename, 'rb') as fh: _require(fh.read(size) == TEST_DATA, 'data changed on grow') _require(fh.read(1025) == b'\0' * 1024, 'grow did not zero-fill') # Truncate data os.truncate(filename, size - 1024) _require(os.stat(filename).st_size == size - 1024, 'shrink failed') with open(filename, 'rb') as fh: _require(fh.read(size) == TEST_DATA[:size - 1024], 'data changed on shrink') os.unlink(filename) def cmd_truncate_fd(mnt_dir): _require(len(TEST_DATA) > 1024, 'test data is too short') with NamedTemporaryFile('w+b', 0, dir=mnt_dir) as fh: fd = fh.fileno() fh.write(TEST_DATA) size = os.fstat(fd).st_size _require(size == len(TEST_DATA), 'st_size is %d' % size) # Add zeros at the end os.ftruncate(fd, size + 1024) _require(os.fstat(fd).st_size == size + 1024, 'grow failed') fh.seek(0) _require(fh.read(size) == TEST_DATA, 'data changed on grow') _require(fh.read(1025) == b'\0' * 1024, 'grow did not zero-fill') # Truncate data os.ftruncate(fd, size - 1024) _require(os.fstat(fd).st_size == size - 1024, 'shrink failed') fh.seek(0) _require(fh.read(size) == TEST_DATA[:size - 1024], 'data changed on shrink') def cmd_utimens(mnt_dir, ns_tol=0): ns_tol = int(ns_tol) filename = pjoin(mnt_dir, name_generator()) os.mkdir(filename) fstat = os.lstat(filename) atime = fstat.st_atime + 42.28 mtime = fstat.st_mtime - 42.23 atime_ns = fstat.st_atime_ns + int(42.28 * 1e9) mtime_ns = fstat.st_mtime_ns - int(42.23 * 1e9) os.utime(filename, None, ns=(atime_ns, mtime_ns)) fstat = os.lstat(filename) _require(abs(fstat.st_atime - atime) < 1, 'st_atime off by too much') _require(abs(fstat.st_mtime - mtime) < 1, 'st_mtime off by too much') _require(abs(fstat.st_atime_ns - atime_ns) <= ns_tol, 'st_atime_ns off by %d' % abs(fstat.st_atime_ns - atime_ns)) _require(abs(fstat.st_mtime_ns - mtime_ns) <= ns_tol, 'st_mtime_ns off by %d' % abs(fstat.st_mtime_ns - mtime_ns)) def cmd_passthrough(src_dir, mnt_dir, inode_check='exact'): inode_check = _inode_check(inode_check) name = name_generator() src_name = pjoin(src_dir, name) mnt_name = pjoin(mnt_dir, name) # First: write to the source directory _require(name not in os.listdir(src_dir), '%s already in source' % name) _require(name not in os.listdir(mnt_dir), '%s already in mount' % name) with open(src_name, 'w') as fh: fh.write('Hello, world') start_time = time.time() while time.time() - start_time < 10: if name in os.listdir(mnt_dir): break time.sleep(0.1) else: raise CheckFailed('%s did not appear in the mount within 10s' % name) _require(name in os.listdir(src_dir), '%s vanished from source' % name) src_stat = os.stat(src_name) mnt_stat = os.stat(mnt_name) _require(src_stat.st_mode == mnt_stat.st_mode, 'st_mode differs') check_inode(inode_check, mnt_stat.st_ino, src_stat.st_ino) _require(src_stat.st_size == mnt_stat.st_size, 'st_size differs') _require(src_stat.st_mtime == mnt_stat.st_mtime, 'st_mtime differs') # Second: write to the mount directory name = name_generator() src_name = pjoin(src_dir, name) mnt_name = pjoin(mnt_dir, name) _require(name not in os.listdir(src_dir), '%s already in source' % name) _require(name not in os.listdir(mnt_dir), '%s already in mount' % name) with open(mnt_name, 'w') as fh: fh.write('Hello, world') _require(name in os.listdir(src_dir), '%s did not reach the source' % name) _require(name in os.listdir(mnt_dir), '%s not in the mount' % name) src_stat = os.stat(src_name) mnt_stat = os.stat(mnt_name) _require(src_stat.st_mode == mnt_stat.st_mode, 'st_mode differs') check_inode(inode_check, mnt_stat.st_ino, src_stat.st_ino) _require(src_stat.st_size == mnt_stat.st_size, 'st_size differs') _require(abs(src_stat.st_mtime - mnt_stat.st_mtime) < 0.01, 'st_mtime differs') def cmd_xattr(path): os.setxattr(path, b'hello_ll_setxattr_name', b'hello_ll_setxattr_value') got = os.getxattr(path, b'hello_ll_getxattr_name') _require(got == b'hello_ll_getxattr_value', 'getxattr returned %r' % got) os.removexattr(path, b'hello_ll_removexattr_name') # ------------------------------------------------------- generic assertions # Operations expect-errno can run. One line each; add one rather than # approximating the check in shell. OPS = { 'fuse_test_open_rw': lambda path: os.close(os.open(path, os.O_RDWR)), 'fuse_test_open_ro': lambda path: os.close(os.open(path, os.O_RDONLY)), 'fuse_test_stat': os.stat, } def cmd_expect_errno(want, op, args): """Run one filesystem operation and require it to fail with *want*. Comparing OSError.errno keeps the check exact -- matching strerror text would be locale-dependent and would conflate distinct errnos. """ code = getattr(errno, want, None) if code is None: raise CheckFailed('unknown errno name %s' % want) handler = OPS.get(op) if handler is None: raise CheckFailed('unknown operation %s (have: %s)' % (op, ' '.join(sorted(OPS)))) try: handler(*args) except OSError as exc: if exc.errno != code: raise CheckFailed('%s %s: expected %s, got %s' % (op, ' '.join(args), want, errno.errorcode.get(exc.errno, exc.errno))) return raise CheckFailed('%s %s: expected %s, but it succeeded' % (op, ' '.join(args), want)) def cmd_assert_listdir(directory, names): got = sorted(os.listdir(directory)) want = sorted(names) _require(got == want, '%s lists %r, want %r' % (directory, got, want)) def cmd_listdir(directory): for name in sorted(os.listdir(directory)): print(name) def cmd_listdir_first(directory): """Print the first entry of *directory*. A subcommand rather than `listdir | head -1` because pipefail is off, so a failing listdir in a pipeline would hand the caller an empty name instead of an error. """ names = sorted(os.listdir(directory)) _require(names, '%s is empty' % directory) print(names[0]) def cmd_size(path): print(os.path.getsize(path)) def cmd_ismount(path): """Exit 0 when *path* is a mountpoint. os.path.ismount() is portable; mountpoint(1) is util-linux only. """ _require(os.path.ismount(path), '%s is not a mountpoint' % path) def cmd_isbigger(path, size): """Exit 0 when *path* is larger than *size* bytes. The mount predicate for a filesystem with no mountpoint of its own: the null filesystem is mounted over a regular file. """ _require(os.stat(path).st_size > int(size), '%s is not larger than %s bytes' % (path, size)) # --------------------------------------------------------------- mount state def parse_mountinfo(mnt_dir): """Return the /proc/self/mountinfo entry for *mnt_dir*, or None. Parses the line for the mountpoint and returns a dict with keys: 'mountpoint' - the mount point path (str) 'fstype' - filesystem type as the kernel sees it, e.g. 'fuse' or 'fuse.' (str) 'source' - mount source field, e.g. 'hello' or '#' fallback form (str) 'mount_options' - per-mount options/attrs (set of str) 'super_options' - superblock options from the filesystem (set of str) These fields are exactly what /proc/self/mountinfo exposes; they capture the post-mount state that differs between the legacy mount(2) path and the new fsopen/fsconfig/fsmount path. """ target = os.path.realpath(mnt_dir) with open('/proc/self/mountinfo') as fh: for line in fh: parts = line.rstrip('\n').split(' ') try: sep = parts.index('-') except ValueError: continue if len(parts) < sep + 4 or sep < 6: continue mountpoint = parts[4].replace('\\040', ' ') if mountpoint != target: continue return { 'mountpoint': mountpoint, 'fstype': parts[sep + 1], 'source': parts[sep + 2].replace('\\040', ' '), 'mount_options': set(parts[5].split(',')), 'super_options': set(parts[sep + 3].split(',')), } return None def _mountinfo(mnt_dir): info = parse_mountinfo(mnt_dir) if info is None: raise CheckFailed('%s not found in /proc/self/mountinfo' % mnt_dir) return info def cmd_mountinfo(mnt_dir, field): """Echo one field of the mountinfo line. Empty output means not mounted.""" info = parse_mountinfo(mnt_dir) if info is None: return _require(field in info, 'no such mountinfo field: %s (have %s)' % (field, ' '.join(sorted(info)))) value = info[field] print(','.join(sorted(value)) if isinstance(value, set) else value) def cmd_assert_mount_opt(mnt_dir, opts): info = _mountinfo(mnt_dir) for opt in opts: _require(opt in info['mount_options'], '%r missing from mount_options=%r' % (opt, sorted(info['mount_options']))) def cmd_refute_mount_opt(mnt_dir, opts): info = _mountinfo(mnt_dir) for opt in opts: _require(opt not in info['mount_options'], 'unexpected %r in mount_options=%r' % (opt, sorted(info['mount_options']))) def cmd_assert_super_opt(mnt_dir, opts): info = _mountinfo(mnt_dir) for opt in opts: _require(opt in info['super_options'], '%r missing from super_options=%r' % (opt, sorted(info['super_options']))) def cmd_assert_super_opt_prefix(mnt_dir, prefixes): info = _mountinfo(mnt_dir) for prefix in prefixes: _require(any(o.startswith(prefix) for o in info['super_options']), 'no super option starts with %r: %r' % (prefix, sorted(info['super_options']))) def cmd_assert_fstype(mnt_dir, expected): """The fstype must be one of *expected*; several are legitimate.""" info = _mountinfo(mnt_dir) _require(info['fstype'] in expected, 'unexpected fstype %r (expected one of %r)' % (info['fstype'], expected)) def cmd_assert_source(mnt_dir, expected): """The source must be one of *expected*. Several are accepted because the ENODEV fallback legitimately produces either 'myfsname' or 'mysub#myfsname'. """ info = _mountinfo(mnt_dir) _require(info['source'] in expected, 'unexpected source %r (expected one of %r)' % (info['source'], expected)) # ------------------------------------------------------------- odds and ends def cmd_printcap_caps(src_root): """Verify that the FUSE_CAP_* name table printcap uses includes every flag from fuse_common.h.""" header_path = pjoin(src_root, 'include', 'fuse_common.h') printcap_path = pjoin(src_root, 'lib', 'fuse_cap_names_i.h') if not os.path.exists(header_path): raise CheckFailed('%s not found' % header_path) header_caps = set() with open(header_path) as fh: for line in fh: match = re.match(r'#define\s+(FUSE_CAP_\w+)\s+', line) if match: header_caps.add(match.group(1)) printcap_caps = set() with open(printcap_path) as fh: for line in fh: if re.match(r'^\s*//', line): # commented out continue match = re.search(r'\{\s*(FUSE_CAP_\w+),\s*"', line) if match: printcap_caps.add(match.group(1)) missing = header_caps - printcap_caps extra = printcap_caps - header_caps if missing or extra: msg = ['%d caps in %s, %d in %s' % (len(header_caps), header_path, len(printcap_caps), printcap_path)] if missing: msg.append('missing in %s: %s' % (printcap_path, sorted(missing))) if extra: msg.append('extra in %s: %s' % (printcap_path, sorted(extra))) raise CheckFailed('\n'.join(msg)) def cmd_reachable_without_caps(path): """Exit 0 when *path* is reachable by a process without CAP_DAC_OVERRIDE. mount.fuse3 execs the fs binary only after dropping all capabilities; the process keeps uid/gid 0 but loses CAP_DAC_OVERRIDE, so the binary and every directory on the way to it must be executable for it by plain permission bits (a user-owned mode-0700 home directory is not). """ def executable_without_caps(st): if st.st_uid == 0: return st.st_mode & stat.S_IXUSR if st.st_gid == 0: return st.st_mode & stat.S_IXGRP return st.st_mode & stat.S_IXOTH path = os.path.realpath(path) while True: if not executable_without_caps(os.stat(path)): raise CheckFailed('%s is not reachable by the capability-less ' 'file system process' % path) if path == '/': return path = os.path.dirname(path) def cmd_elf_class(path): """Print the ELF class of *path*, 32 or 64. Reads e_ident[EI_CLASS] directly rather than grepping file(1) output for the string 'ELF 32-bit'. """ with open(path, 'rb') as fh: ident = fh.read(5) if ident[:4] != b'\x7fELF': raise CheckFailed('%s is not an ELF binary' % path) print({1: 32, 2: 64}.get(ident[4], 0)) def cmd_null_roundtrip(path): """Read zeros from the null filesystem, then write to it.""" with open(path, 'rb') as fh: got = fh.read(382) _require(got == b'\0' * 382, 'read %r rather than zeros' % got[:32]) with open(path, 'wb') as fh: fh.write(b'whatever') def cmd_cuse_roundtrip(devpath, client): """The binary read/write/offset exchange test_cuse performed.""" output = subprocess.check_output([client, devpath, 's']) _require(output == b'0\n', 'initial size is %r' % output) data = b'some test data' off = 5 proc = subprocess.Popen([client, devpath, 'w', str(len(data)), str(off)], stdin=subprocess.PIPE) proc.stdin.write(data) proc.stdin.close() ret = proc.wait(timeout=10) _require(ret == 0, 'write client exited with %d' % ret) want = str(off + len(data)).encode() + b'\n' output = subprocess.check_output([client, devpath, 's']) _require(output == want, 'size is %r, want %r' % (output, want)) out = subprocess.check_output( [client, devpath, 'r', str(off + len(data) + 2), '0']) _require(out == (b'\0' * off) + data, 'read back %r' % out) # ------------------------------------------------------ FUSE INIT over AF_UNIX FUSE_OP_INIT = 26 FUSE_MAJOR_VERSION = 7 FUSE_MINOR_VERSION = 38 _fuse_in_header_fmt = ' for the named reason. fusermount3 reaches its mountpoint checks only once _FUSE_COMMFD names a socket it could hand the /dev/fuse fd back over, so a real socketpair goes in even though the mount is never meant to get that far. """ import socket wanted = _FUSERMOUNT_REJECTIONS.get(reason) if wanted is None: raise CheckFailed('unknown rejection reason %r' % reason) binary = pjoin(os.environ['FUSE_UTIL_DIR'], 'fusermount3') env = dict(os.environ) parent, child = socket.socketpair() try: env['_FUSE_COMMFD'] = str(child.fileno()) proc = subprocess.run([binary, '-o', 'rw', mountpoint], env=env, pass_fds=(child.fileno(),), stderr=subprocess.PIPE, universal_newlines=True) finally: parent.close() child.close() _require(proc.returncode != 0, 'fusermount3 accepted mountpoint %s' % mountpoint) _require(wanted in proc.stderr, 'mountpoint %s: expected %r on stderr, got: %s' % (mountpoint, wanted, proc.stderr.strip())) _require(not os.path.ismount(mountpoint), '%s is a mountpoint after a refused mount' % mountpoint) # ------------------------------------------------------------------ dispatch _INODE_CHECK = {'default': 'exact', 'choices': ('exact', 'nonzero')} def build_parser(): """One subparser per check. Each records how to call its function, so adding a check is one line here and one function above.""" parser = argparse.ArgumentParser(description=__doc__) sub = parser.add_subparsers(dest='cmd', required=True) def add(name, func, *positional, **options): cmd = sub.add_parser(name) for arg in positional: if isinstance(arg, tuple): cmd.add_argument(arg[0], **arg[1]) else: cmd.add_argument(arg) for flag, kwargs in options.items(): cmd.add_argument('--' + flag.replace('_', '-'), dest=flag, **kwargs) names = [a[0] if isinstance(a, tuple) else a for a in positional] names += list(options) cmd.set_defaults(call=lambda args: func(*[getattr(args, n) for n in names])) return cmd add('fuse_test_unlink', cmd_unlink, 'mnt', src={'default': None}) add('fuse_test_mkdir', cmd_mkdir, 'mnt') add('fuse_test_rmdir', cmd_rmdir, 'mnt', src={'default': None}) add('fuse_test_symlink', cmd_symlink, 'mnt') add('fuse_test_create', cmd_create, 'mnt') add('fuse_test_chown', cmd_chown, 'mnt') add('fuse_test_open_read', cmd_open_read, 'src', 'mnt') add('fuse_test_open_write', cmd_open_write, 'src', 'mnt') add('fuse_test_append', cmd_append, 'src', 'mnt') add('fuse_test_seek', cmd_seek, 'src', 'mnt') add('fuse_test_open_unlink', cmd_open_unlink, 'mnt') add('fuse_test_statvfs', cmd_statvfs, 'mnt') add('fuse_test_link', cmd_link, 'mnt') add('fuse_test_readdir', cmd_readdir, 'src', 'mnt', inode_check=_INODE_CHECK) add('fuse_test_readdir_big', cmd_readdir_big, 'src', 'mnt', inode_check=_INODE_CHECK) add('fuse_test_truncate_path', cmd_truncate_path, 'mnt') add('fuse_test_truncate_fd', cmd_truncate_fd, 'mnt') add('fuse_test_utimens', cmd_utimens, 'mnt', ns_tol={'default': 0}) add('fuse_test_passthrough', cmd_passthrough, 'src', 'mnt', inode_check=_INODE_CHECK) add('fuse_test_xattr', cmd_xattr, 'path') add('fuse_test_expect_errno', cmd_expect_errno, 'want', 'op', ('args', {'nargs': '*'})) add('fuse_test_assert_listdir', cmd_assert_listdir, 'dir', ('names', {'nargs': '*'})) add('fuse_test_listdir', cmd_listdir, 'dir') add('fuse_test_listdir_first', cmd_listdir_first, 'dir') add('fuse_test_size', cmd_size, 'path') add('fuse_test_ismount', cmd_ismount, 'path') add('fuse_test_isbigger', cmd_isbigger, 'path', 'size') add('fuse_test_mountinfo', cmd_mountinfo, 'mnt', 'field') for name, func in (('fuse_test_assert_mount_opt', cmd_assert_mount_opt), ('fuse_test_refute_mount_opt', cmd_refute_mount_opt), ('fuse_test_assert_super_opt', cmd_assert_super_opt), ('fuse_test_assert_super_opt_prefix', cmd_assert_super_opt_prefix), ('fuse_test_assert_fstype', cmd_assert_fstype), ('fuse_test_assert_source', cmd_assert_source)): add(name, func, 'mnt', ('values', {'nargs': '+'})) add('fuse_test_fusermount_rejects', cmd_fusermount_rejects, 'mountpoint', 'reason') add('fuse_test_printcap_caps', cmd_printcap_caps, 'src_root') add('fuse_test_reachable_without_caps', cmd_reachable_without_caps, 'path') add('fuse_test_elf_class', cmd_elf_class, 'path') add('fuse_test_null_roundtrip', cmd_null_roundtrip, 'path') add('fuse_test_cuse_roundtrip', cmd_cuse_roundtrip, 'devpath', 'client') add('fuse_test_uds_init', cmd_uds_init, 'sockpath') return parser def main(argv): args = build_parser().parse_args(argv) try: args.call(args) # struct.error is what a daemon replying with a short or overlong packet # raises, which is a check failing rather than this script breaking. except (CheckFailed, OSError, subprocess.SubprocessError, struct.error) as exc: print('checks.py %s: %s' % (args.cmd, exc), file=sys.stderr) return 1 return 0 if __name__ == '__main__': sys.exit(main(sys.argv[1:])) fuse-3.18.3/test/cases/lib/common.sh0000644000175000017500000004173315250106036016173 0ustar berndbernd# common.sh - helper library for the libfuse shell tests. # # Sourced by each lib/ body, and by a case that has none or that gates before # sourcing one. Provides the FUSE verbs (mount, umount, assertions, skip # protocol); it knows nothing about scheduling, which belongs to run-tests.py. # # Scripts run under errexit, imposed once by the runner (`bash -e`), so an # unchecked command that fails ends the test instead of letting the rest of it # run against a broken state. Two consequences show up below: a status that is # examined must be captured in the same command, and the cleanup trap has to # swallow each of its own failures. # # Nothing here is sourced, probed or defaulted: the runner puts the whole # contract in the environment before exec'ing the script, and the variables # below are read as given. A case is therefore not runnable by hand; replay # logs/repro.sh, which restores the environment first. # # TEST_NAME the name the runner reports this test under # TEST_LIB this directory, where checks.py is found # TEST_MNT empty mount point, one per test # TEST_LOGDIR where daemon logs and status files are written # BUILD_DIR build tree root; _require_binary resolves against it # FUSE_EXAMPLE_DIR $BUILD_DIR/example # FUSE_TEST_BIN_DIR $BUILD_DIR/test # FUSE_UTIL_DIR $BUILD_DIR/util, holding fusermount3 and mount.fuse3 # FUSE_CAPS capability names printcap reported, space separated # FUSE_UID effective uid # FUSE_OS uname -s # FUSE_URING_ENABLE 1 when the run expects the daemons to use io_uring # FUSE_VALGRIND command prefix, empty unless the run is under valgrind # # The runner exports more for the cases themselves (TEST_SRC, TEST_TMP, # TEST_WORKDIR); those are not read here. A case may set FUSE_WAIT_PREDICATE # before mounting, to replace the readiness check fuse_mount waits on, and # _fuse_no_mount_needed before sourcing this file, when it never mounts. # A case that gates before sourcing a lib/ body reaches this file twice, and # the second pass must not reset the mount bookkeeping the first one is # already tracking a mount in. [ -z "${_FUSE_COMMON_SH:-}" ] || return 0 _FUSE_COMMON_SH=1 # --------------------------------------------------------------- result protocol # _fail # Print msg to stderr with the test name, then exit 1 (FAIL). # # A test whose subject only reports an unsupported kernel once it has tried to # use it cannot gate on that up front. $FAIL_CALLBACK is its last look, called # with the message; _notrun from there turns the failure into a skip. _fail() { if [ -n "${FAIL_CALLBACK:-}" ]; then local callback=$FAIL_CALLBACK FAIL_CALLBACK= # a failing callback must not recurse "$callback" "$@" fi echo "FAIL: ${TEST_NAME}: $*" >&2 exit 1 } # _notrun # Print reason to stderr, then exit 77 (SKIP). The runner records the reason. # stderr, because fuse_mount echoes the mount index on stdout and its callers # redirect that away; a skip raised inside it would go with it. _notrun() { echo "SKIP: $*" >&2 exit 77 } # _require_root # _notrun unless the effective uid is 0. _require_root() { [ "$FUSE_UID" = 0 ] || _notrun "needs root" } # _require_nonroot # _notrun unless the effective uid is not 0. _require_nonroot() { [ "$FUSE_UID" != 0 ] || _notrun "needs to run as non-root" } # _is_linux # True on Linux. For conditional sections inside a shared body; a whole script # that cannot run elsewhere calls _require_linux instead. _is_linux() { [ "$FUSE_OS" = Linux ] } # _require_linux # _notrun unless $FUSE_OS is Linux. names the Linux-only facility, so # the summary says which one rather than just "not linux". _require_linux() { _is_linux || _notrun "$1 is Linux-only" } # _require_cap # _notrun unless the name appears in $FUSE_CAPS. _require_cap() { local cap=$1 case " $FUSE_CAPS " in *" $cap "*) return 0 ;; esac _notrun "kernel does not offer $cap" } # _require_fuse_device # _notrun unless the kernel side is there. A case that reaches fusermount3 but # never completes a mount needs this much and no more. _require_fuse_device() { [ -e /dev/fuse ] || _notrun "the FUSE kernel module does not seem to be loaded" } # _require_fuse # _notrun unless this user can mount a FUSE filesystem at all: the kernel side # has to be there, and an unprivileged user needs a setuid fusermount3. It runs # when a case sources this file, so a build tree whose fusermount3 was never # chmod 4755'd reports skips rather than a wall of mount failures. _require_fuse() { local fusermount # BSD has no fusermount3 at all; vfs.usermount decides there. _is_linux || return 0 _require_fuse_device [ "$FUSE_UID" != 0 ] || return 0 fusermount=$(command -v fusermount3) || _notrun "no fusermount3 on \$PATH" [ -u "$fusermount" ] || _notrun "$fusermount is not setuid, and we are not root" } # _require_binary # _notrun unless the file exists and is executable. _require_binary() { [ -x "$BUILD_DIR/$1" ] || _notrun "$1 not built" } # _require_prog # _notrun unless `command -v ` succeeds. _require_prog() { command -v "$1" >/dev/null 2>&1 || _notrun "$1 not installed" } # _require_not_32bit_on_64 # _notrun for a 32-bit ELF binary on an x86_64 host. _require_not_32bit_on_64() { local class class=$(_check fuse_test_elf_class "$1") if [ "$class" = 32 ] && [ "$(uname -m)" = x86_64 ]; then _notrun "$1 is a 32-bit binary on a 64-bit host" fi } # _require_reachable_without_caps # _notrun unless the fs binary and every directory above it are executable by # plain permission bits. mount.fuse3 -o drop_privileges execs the fs after # dropping CAP_DAC_OVERRIDE, so a mode-0700 home makes it unreachable. _require_reachable_without_caps() { python3 "$TEST_LIB/checks.py" fuse_test_reachable_without_caps \ "$(_fuse_fs_binary "$1")" || _notrun "$1 is not reachable without CAP_DAC_OVERRIDE" } # _require_fs_marker_absent [fs-index] # _notrun if the mounted daemon's log matched . Used for runtime # "not supported by kernel" markers. # # The daemon may not have written the marker yet when the test looks; the # examples emit it during the first update interval, so poll briefly. _require_fs_marker_absent() { local regex=$1 idx=${2:-0} deadline=$((SECONDS + 3)) while [ $SECONDS -lt $deadline ]; do _skip_if_fs_marker "$regex" "$idx" sleep 0.2 done } # _skip_if_fs_marker [fs-index] # _notrun if the daemon's log already matches , without waiting. For a # marker whose arrival the caller has already waited for, polling again would # only add delay. _skip_if_fs_marker() { local regex=$1 idx=${2:-0} if grep -qE -- "$regex" "$(fuse_fs_log "$idx")"; then _notrun "filesystem reported: $regex" fi } # _wait_fs_marker [fs-index] # _fail unless the daemon's log comes to match . For progress a daemon # reports itself: waiting for the line rather than for a duration lets a slow # machine take longer instead of failing, and lets a fast one stop early. _wait_fs_marker() { local regex=$1 idx=${2:-0} deadline=$((SECONDS + 10)) while [ $SECONDS -lt $deadline ]; do if grep -qE -- "$regex" "$(fuse_fs_log "$idx")"; then return 0 fi sleep 0.1 done _fail "filesystem did not report: $regex" } # ------------------------------------------------------------------- assertions # _assert_eq [msg] _assert_eq() { [ "$1" = "$2" ] || _fail "${3:-assertion failed}: got '$1', want '$2'" } # _assert_ne [msg] _assert_ne() { [ "$1" != "$2" ] || _fail "${3:-assertion failed}: both are '$1'" } # _assert_file_eq _assert_file_eq() { cmp -s "$1" "$2" || _fail "$1 and $2 differ" } # _wait_for # Poll until cmd succeeds. Returns non-zero when the deadline passes, so the # caller decides whether that is a failure or a skip. _wait_for() { # Separate statements: one `local` expands all its words before it # assigns any of them, so a shared one computes the deadline from an # unset secs and the loop ends before it has tried once. local secs=$1 cmd=$2 local deadline=$((SECONDS + secs)) while [ $SECONDS -lt $deadline ]; do if eval "$cmd"; then return 0 fi sleep 0.1 done return 1 } # Everything shell cannot express exactly goes to checks.py: an exact errno, an # fd held across an operation, nanosecond timestamps, directory listings, # /proc/self/mountinfo fields. Add a subcommand there rather than approximating # a check here. # _check [args...] # Run the Python check helper. Its stdout/stderr already carry the diagnostic, # so just propagate the failure. _check() { # Silent on success otherwise, so a step that hangs is invisible. # stderr: callers capture stdout for the check's value. echo "check: $*" >&2 python3 "$TEST_LIB/checks.py" "$@" || _fail "checks.py $1 failed" } # _assert_errno [args...] # op is a checks.py operation name (fuse_test_open_rw, fuse_test_open_ro, # fuse_test_stat). The errno is compared against OSError.errno, never against # locale-dependent strerror text. _assert_errno() { _check fuse_test_expect_errno "$@" } _assert_listdir() { _check fuse_test_assert_listdir "$@"; } _assert_xattr_roundtrip() { _check fuse_test_xattr "$@"; } # set/get/remove # mountinfo_field # Echo one field of the /proc/self/mountinfo line for . Empty output means # the mountpoint is not mounted. mountinfo_field() { _check fuse_test_mountinfo "$1" "$2" } _assert_mount_opt() { _check fuse_test_assert_mount_opt "$@"; } _refute_mount_opt() { _check fuse_test_refute_mount_opt "$@"; } _assert_super_opt() { _check fuse_test_assert_super_opt "$@"; } _assert_super_opt_prefix() { _check fuse_test_assert_super_opt_prefix "$@"; } _assert_fstype() { _check fuse_test_assert_fstype "$@"; } _assert_source() { _check fuse_test_assert_source "$@"; } # ---------------------------------------------------------------- cleanup hooks _FUSE_ATEXIT=() # _at_exit # Register a command to run when the script exits, newest first. Registering is # what installs the EXIT trap, so a test never has to write its own and cannot # clobber the mount unwinding. _at_exit() { _FUSE_ATEXIT+=("$*") trap _fuse_cleanup_all EXIT } # _fuse_cleanup_all # Unwind every mount still registered, newest first, then run the _at_exit # commands. Every step swallows its own failure: under errexit one stuck umount # would otherwise end the trap and leak the remaining mounts, which is exactly # what the trap exists to prevent. _fuse_cleanup_all() { local idx for ((idx = _fuse_fs_count - 1; idx >= 0; idx--)); do fuse_umount_lazy "$idx" || true done for ((idx = ${#_FUSE_ATEXIT[@]} - 1; idx >= 0; idx--)); do eval "${_FUSE_ATEXIT[$idx]}" || true done } # ------------------------------------------------------------------ mount verbs _fuse_fs_count=0 FUSE_FS_PID=() FUSE_FS_LOG=() FUSE_FS_MNT=() FUSE_FS_NAME=() # _fuse_fs_binary # Echo the build-tree path of : $FUSE_TEST_BIN_DIR when the name is # prefixed "test/", $FUSE_EXAMPLE_DIR otherwise. _fuse_fs_binary() { case $1 in test/*) echo "$FUSE_TEST_BIN_DIR/${1#test/}" ;; *) echo "$FUSE_EXAMPLE_DIR/$1" ;; esac } # fuse_mount_at [args...] # Launch the filesystem in the foreground on with its stdout+stderr # redirected to logs/fs--.out. Waits for the mountpoint to # appear. Registers an EXIT trap that lazily unmounts and kills the daemon, so # an aborting test never leaks a mount. # Sets FUSE_FS_PID[idx] and FUSE_FS_LOG[idx]; echoes idx. fuse_mount_at() { local mnt=$1 fs=$2; shift 2 local idx=$_fuse_fs_count local bin log bin=$(_fuse_fs_binary "$fs") [ -x "$bin" ] || _notrun "$fs not built" # Each daemon gets its own log so a multi-mount test stays readable. log=$TEST_LOGDIR/fs-$idx-$(basename "$fs").out "$bin" "$@" "$mnt" >"$log" 2>&1 & FUSE_FS_PID[$idx]=$! FUSE_FS_LOG[$idx]=$log FUSE_FS_MNT[$idx]=$mnt FUSE_FS_NAME[$idx]=$fs _fuse_fs_count=$((idx + 1)) trap _fuse_cleanup_all EXIT fuse_wait_mount "$mnt" "${FUSE_WAIT_PREDICATE:-}" || { _fuse_dump_fs_log $idx _fail "$fs did not mount on $mnt" } echo $idx } # fuse_mount [args...] # fuse_mount_at on $TEST_MNT, with -f so the daemon stays in the foreground. fuse_mount() { local fs=$1; shift fuse_mount_at "$TEST_MNT" "$fs" -f "$@" } # fuse_mount_helper [args...] # Mount via $FUSE_UTIL_DIR/mount.fuse3 instead of exec'ing the fs directly. # # mount.fuse3 execs the filesystem type through /bin/sh, so an example resolves # via $PATH but a binary in test/ has to be named by its absolute path. fuse_mount_helper() { local fs=$1; shift local idx=$_fuse_fs_count local spec=$fs log case $fs in test/*) spec=$(_fuse_fs_binary "$fs") ;; esac log=$TEST_LOGDIR/fs-$idx-$(basename "$fs").out "$FUSE_UTIL_DIR/mount.fuse3" "$spec" "$TEST_MNT" "$@" >"$log" 2>&1 & FUSE_FS_PID[$idx]=$! FUSE_FS_LOG[$idx]=$log FUSE_FS_MNT[$idx]=$TEST_MNT FUSE_FS_NAME[$idx]=$fs _fuse_fs_count=$((idx + 1)) trap _fuse_cleanup_all EXIT fuse_wait_mount "$TEST_MNT" || { _fuse_dump_fs_log $idx _fail "mount.fuse3 $fs did not mount on $TEST_MNT" } echo $idx } # fuse_wait_mount [predicate] # Poll until `checks.py fuse_test_ismount ` succeeds, or until the # caller-supplied predicate (a shell command taking ) succeeds. Fails if # the daemon exits first. fuse_wait_mount() { local path=$1 predicate=${2:-} local idx=$((_fuse_fs_count - 1)) local deadline=$((SECONDS + 30)) local test_cmd if [ -n "$predicate" ]; then test_cmd="$predicate '$path'" else test_cmd="python3 '$TEST_LIB/checks.py' fuse_test_ismount '$path'" fi while [ $SECONDS -lt $deadline ]; do if eval "$test_cmd" >/dev/null 2>&1; then return 0 fi if ! kill -0 "${FUSE_FS_PID[$idx]}" 2>/dev/null; then # The daemon may have exited *after* completing the # mount (mount.fuse3 does), so look once more. eval "$test_cmd" >/dev/null 2>&1 && return 0 return 1 fi sleep 0.1 done return 1 } # fuse_umount [idx] # fusermount3 -u on Linux, umount(8) on BSD (no util/ is built there), then # wait for the daemon; _fail unless it exits 0. Writes # logs/fs--.status. fuse_umount() { local idx=${1:-0} local mnt=${FUSE_FS_MNT[$idx]} pid=${FUSE_FS_PID[$idx]} local rc if _is_linux; then "$FUSE_UTIL_DIR/fusermount3" -u "$mnt" || _fail "fusermount3 -u $mnt failed" else umount "$mnt" || _fail "umount $mnt failed" fi # The daemon exits on its own once the kernel drops the connection; a # daemon that does not is a bug the test must report, not paper over. _wait_for 30 "! kill -0 $pid 2>/dev/null" || _fail "${FUSE_FS_NAME[$idx]} still running 30s after umount" # One command, not `wait; rc=$?`: under errexit a non-zero wait would # abort the script before its status could be reported. rc=0 wait "$pid" || rc=$? # Reaped: the number is free for any process to be assigned next, so # nothing may signal it again. FUSE_FS_PID[$idx]= echo "$rc" >"$TEST_LOGDIR/fs-$idx-$(basename "${FUSE_FS_NAME[$idx]}").status" [ $rc -eq 0 ] || { _fuse_dump_fs_log $idx _fail "${FUSE_FS_NAME[$idx]} exited with $rc" } } # fuse_umount_lazy [idx] # fusermount3 -z -u (Linux) or umount -f (BSD), + SIGTERM + SIGKILL, ignoring # errors. The trap path. fuse_umount_lazy() { local idx=${1:-0} local mnt=${FUSE_FS_MNT[$idx]} pid=${FUSE_FS_PID[$idx]} # The trap runs over every index, fuse_umount'ed ones included. [ -n "$pid" ] || return 0 if _is_linux; then "$FUSE_UTIL_DIR/fusermount3" -z -u "$mnt" >/dev/null 2>&1 || true else umount -f "$mnt" >/dev/null 2>&1 || true fi kill "$pid" 2>/dev/null || true _wait_for 1 "! kill -0 $pid 2>/dev/null" || kill -9 "$pid" 2>/dev/null || true wait "$pid" 2>/dev/null || true FUSE_FS_PID[$idx]= } fuse_fs_pid() { echo "${FUSE_FS_PID[${1:-0}]}" } fuse_fs_log() { echo "${FUSE_FS_LOG[${1:-0}]}" } # _fuse_dump_fs_log # Copy that daemon's log to stderr before failing. The log file survives in # logs/, but a failure line with the daemon's own last words beside it is what # makes a CI log readable without downloading anything. _fuse_dump_fs_log() { local idx=${1:-0} echo "--- ${FUSE_FS_NAME[$idx]} log (${FUSE_FS_LOG[$idx]}) ---" >&2 cat "${FUSE_FS_LOG[$idx]}" >&2 || true echo "--- end log ---" >&2 } # --------------------------------------------------------------- output scanning # fuse_allow_output # Append a false-positive pattern to logs/.allow, one per line. The runner # strips every match before scanning for suspicious words. fuse_allow_output() { printf '%s\n' "$1" >>"$TEST_LOGDIR/.allow" } # fuse_allow_core # Record that a core from is expected in this test. fuse_allow_core() { printf '%s\n' "$1" >>"$TEST_LOGDIR/.allow-core" } # ----------------------------------------------------------------- the fuse gate # Nearly every case reaches /dev/fuse, through the mount verbs or through a # binary that mounts itself, so this is applied on source rather than left to # each case to remember. The few that never mount say so instead. [ -n "${_fuse_no_mount_needed:-}" ] || _require_fuse fuse-3.18.3/test/cases/lib/hello.sh0000644000175000017500000000421015250106036015773 0ustar berndbernd# lib/hello.sh - body for the hello / hello_ll / test/hello cases. # # Caller sets FS_NAME, FS_OPTS and LAUNCH before sourcing: # FS_NAME hello | hello_ll | test/hello # FS_OPTS -o option list, empty for none # LAUNCH direct | mount_fuse | mount_fuse_dropcaps # # The platform gates live here rather than in the 18 callers: three of them # apply to whole columns of the matrix, and a caller that forgot one would # fail on BSD instead of skipping. . "$TEST_LIB/common.sh" # clone_fd needs the /dev/fuse clone device, which is Linux-only. case $FS_OPTS in *clone_fd*) _require_linux "the clone_fd mount option" ;; esac # hello_ll supports single-threading only. FS_EXTRA= [ "$FS_NAME" != hello_ll ] || FS_EXTRA=-s case $LAUNCH in direct) fuse_mount "$FS_NAME" $FS_EXTRA ${FS_OPTS:+-o "$FS_OPTS"} >/dev/null ;; mount_fuse) # util/ is not built on BSD, so there is no mount.fuse3 to invoke. _require_linux "mount.fuse3" fuse_mount_helper "$FS_NAME" ${FS_OPTS:+-o "$FS_OPTS"} >/dev/null ;; mount_fuse_dropcaps) _require_linux "mount.fuse3" _require_root # mount.fuse3 execs the fs only after dropping all capabilities, so # every directory on the way to the binary must be traversable by # plain permission bits - a mode-0700 home is not. _require_reachable_without_caps "$FS_NAME" fuse_mount_helper "$FS_NAME" \ -o "${FS_OPTS:+$FS_OPTS,}drop_privileges" >/dev/null ;; *) _fail "unknown LAUNCH '$LAUNCH'" ;; esac _assert_listdir "$TEST_MNT" hello # Compared against a file rather than against "$(cat ...)": command # substitution eats the trailing newline, so the shell form would not notice # if the example stopped writing one. printf 'Hello World!\n' >"$TEST_TMP/expected" _assert_file_eq "$TEST_MNT/hello" "$TEST_TMP/expected" _assert_errno EACCES fuse_test_open_rw "$TEST_MNT/hello" _assert_errno ENOENT fuse_test_open_rw "$TEST_MNT/hello-does-not-exist" # os.setxattr/getxattr/removexattr, which tst_xattr() used, exist only on Linux # in CPython; FreeBSD's equivalent is extattr(2), a different API. if [ "$FS_NAME" = hello_ll ] && _is_linux; then _assert_xattr_roundtrip "$TEST_MNT" _assert_xattr_roundtrip "$TEST_MNT/hello" fi fuse_umount fuse-3.18.3/test/cases/lib/mountinfo.sh0000644000175000017500000000205715250106036016715 0ustar berndbernd# lib/mountinfo.sh - body for the /proc/self/mountinfo cases. # # Caller sets FS_NAME (hello or hello_ll), optionally MOUNT_OPTS, and defines # mountinfo_assert(). It may also define mountinfo_setup(), which runs before # the mount and may extend MOUNT_OPTS. # # These tests assert what the kernel recorded for a mount, which is what # differs between the legacy mount(2) path and the fsopen/fsconfig/fsmount # path: an option dropped on one of them shows up here and nowhere else. . "$TEST_LIB/common.sh" # Every assertion below is about what /proc/self/mountinfo reports, and # getmntinfo(3) exposes neither the subtype nor the mount/super option split # these tests exist to check. _require_linux "/proc/self/mountinfo" # hello_ll supports single-threading only. FS_EXTRA= [ "$FS_NAME" != hello_ll ] || FS_EXTRA=-s if declare -F mountinfo_setup >/dev/null; then mountinfo_setup fi fuse_mount "$FS_NAME" $FS_EXTRA ${MOUNT_OPTS:+-o "$MOUNT_OPTS"} >/dev/null # While it is still mounted: the mountinfo line disappears with the mount. mountinfo_assert fuse_umount fuse-3.18.3/test/cases/lib/notify.sh0000644000175000017500000000730615250106036016211 0ustar berndbernd# lib/notify.sh - body for the notification / invalidation cases. # # Caller sets before sourcing: # FS_NAME example to mount # NOTIFY 1 to let the filesystem notify the kernel, 0 for --no-notify # NOTIFY_MODE content | size | entry | prune # FS_ARGS extra arguments, optional # MARKER_ABSENT regex the daemon prints when the kernel refuses, optional # # Every mode has the same shape: mount, look at the filesystem, wait for the # filesystem to have moved on, look again. With notification on the kernel must # have seen the change; with it off the kernel's cache must still be serving # what it saw first. . "$TEST_LIB/common.sh" notify_args="--update-interval=1" [ "$NOTIFY" = 1 ] || notify_args="$notify_args --no-notify" # What notify_prune prints once it has issued a prune the kernel accepted, and # once one has taken effect and the contents are new. The prune mode waits for # these rather than for a duration. prune_sent="prune sent" prune_done="prune complete" # $FAIL_CALLBACK, for the marker the daemon may still be about to write. _notify_recheck_marker() { _require_fs_marker_absent "$MARKER_ABSENT" } fuse_mount "$FS_NAME" $notify_args ${FS_ARGS:-} >/dev/null if [ -n "${MARKER_ABSENT:-}" ]; then # Not gated here: nothing has been looked up yet, so no example can # have tried to notify, and none of them reports on kernel support # before it has. The prune mode gates on the report itself below; for # the rest $FAIL_CALLBACK is what catches it. FAIL_CALLBACK=_notify_recheck_marker fi case $NOTIFY_MODE in content) # The file holds a timestamp the filesystem rewrites; notification is # what makes the kernel re-read it. read1=$(cat "$TEST_MNT/current_time") sleep 2 read2=$(cat "$TEST_MNT/current_time") if [ "$NOTIFY" = 1 ]; then _assert_ne "$read1" "$read2" "content did not change" else _assert_eq "$read1" "$read2" "cached content changed" fi ;; size) size=$(_check fuse_test_size "$TEST_MNT/growing") sleep 2 new_size=$(_check fuse_test_size "$TEST_MNT/growing") if [ "$NOTIFY" = 1 ]; then [ "$new_size" -gt "$size" ] || _fail "growing file stayed at $size bytes" else _assert_eq "$new_size" "$size" "cached size changed" fi ;; entry) fname=$(_check fuse_test_listdir_first "$TEST_MNT") if [ ! -e "$TEST_MNT/$fname" ]; then # We hit a race and issued readdir just before the name changed. fname=$(_check fuse_test_listdir_first "$TEST_MNT") [ -e "$TEST_MNT/$fname" ] || _fail "$fname vanished twice in a row" fi sleep 2 if [ "$NOTIFY" != 1 ]; then # Without notification the entry stays visible until the # kernel's own --timeout expires. [ -e "$TEST_MNT/$fname" ] || _fail "$fname expired before the entry timeout" sleep 5 fi _assert_errno ENOENT fuse_test_stat "$TEST_MNT/$fname" ;; prune) fname=$(_check fuse_test_listdir_first "$TEST_MNT") content=$(cat "$TEST_MNT/$fname") if [ "$NOTIFY" = 1 ]; then # The read above is this file's first lookup, which is what lets # the daemon prune at all. From here it reports exactly one of # the two, so the kernel's answer is decided rather than guessed. _wait_fs_marker "$prune_sent|$MARKER_ABSENT" _skip_if_fs_marker "$MARKER_ABSENT" # A prune did go out, so nothing below can be blamed on the # kernel not having the notification at all. _wait_fs_marker "$prune_done" new_content=$(cat "$TEST_MNT/$fname") _assert_ne "$content" "$new_content" "content did not change" else # Nothing is pruned, so there is no progress to wait for; the # point is that the cache keeps serving the first read. sleep 2 new_content=$(cat "$TEST_MNT/$fname") _assert_eq "$content" "$new_content" "cached content changed" fi ;; *) _fail "unknown NOTIFY_MODE '$NOTIFY_MODE'" ;; esac fuse_umount fuse-3.18.3/test/cases/lib/passthrough.sh0000644000175000017500000000713515250106036017250 0ustar berndbernd# lib/passthrough.sh - body for the passthrough* cases. # # Caller sets before sourcing: # FS_NAME example to mount # FS_ARGS its arguments, without the mountpoint # INODE_CHECK exact | nonzero # PT_MIRROR 1 when the example mirrors the whole tree, so the work # directory is $TEST_MNT$TEST_SRC rather than $TEST_MNT # PT_SRC_VISIBLE 1 when a change made directly in $TEST_SRC is expected to # show up under the mount straight away # PT_POSITIONAL extra trailing arguments before the mountpoint, optional # SYSCALL_ARGS extra test_syscalls arguments, optional # # PT_SRC_VISIBLE is one flag covering three decisions the Python made # separately, because they are the same question: with attribute caching on, # passthrough_hp's mount must not be compared against a source directory it is # allowed to have a stale view of. . "$TEST_LIB/common.sh" fuse_mount_at "$TEST_MNT" "$FS_NAME" $FS_ARGS ${PT_POSITIONAL:-} >/dev/null if [ "$PT_MIRROR" = 1 ]; then work_dir=$TEST_MNT$TEST_SRC else work_dir=$TEST_MNT fi # test_syscalls prints "No error" under FreeBSD. fuse_allow_output "^ [0-9][0-9] \[[^]]+ message: 'No error: 0'\]" _check fuse_test_statvfs "$work_dir" _check fuse_test_readdir "$TEST_SRC" "$work_dir" --inode-check "$INODE_CHECK" _check fuse_test_readdir_big "$TEST_SRC" "$work_dir" --inode-check "$INODE_CHECK" _check fuse_test_open_read "$TEST_SRC" "$work_dir" _check fuse_test_open_write "$TEST_SRC" "$work_dir" _check fuse_test_create "$work_dir" [ "$PT_SRC_VISIBLE" != 1 ] || _check fuse_test_passthrough "$TEST_SRC" "$work_dir" --inode-check "$INODE_CHECK" _check fuse_test_append "$TEST_SRC" "$work_dir" _check fuse_test_seek "$TEST_SRC" "$work_dir" _check fuse_test_mkdir "$work_dir" if [ "$PT_SRC_VISIBLE" = 1 ]; then _check fuse_test_rmdir "$work_dir" --src "$TEST_SRC" _check fuse_test_unlink "$work_dir" --src "$TEST_SRC" else # With the cache on, no operation may go through $TEST_SRC: the # cache would become stale. _check fuse_test_rmdir "$work_dir" _check fuse_test_unlink "$work_dir" fi _check fuse_test_symlink "$work_dir" [ "$FUSE_UID" -ne 0 ] || _check fuse_test_chown "$work_dir" # The underlying fs may not have full nanosecond resolution. _check fuse_test_utimens "$work_dir" --ns-tol 1000 [ "$INODE_CHECK" != exact ] || _check fuse_test_link "$work_dir" _check fuse_test_truncate_path "$work_dir" _check fuse_test_truncate_fd "$work_dir" _check fuse_test_open_unlink "$work_dir" # test_syscalls assumes a change in the source directory is reflected in the # mountpoint immediately, so it runs only where that holds. It is an extra # layer on top of the checks above, not a substitute for them. if [ "$PT_SRC_VISIBLE" = 1 ]; then # Its socket test binds under the work directory, and sun_path holds # 108 bytes -- $TEST_MNT$TEST_SRC alone is longer than that. Hand it a # short symlink instead; a symlinked prefix resolves the same for every # syscall it makes. /tmp literally, since shortness is the point. # # A bare link rather than a directory to put one in: _at_exit does not # run when the runner's timeout kills the test, and a dangling link is # the smallest thing to leak outside the work directory. ln without -f, # so a name mktemp -u handed out twice fails here instead of silently # stealing another run's link. short_link=$(mktemp -u /tmp/fuse-pt.XXXXXX) _at_exit "rm -f '$short_link'" ln -s "$work_dir" "$short_link" "$FUSE_TEST_BIN_DIR/test_syscalls" "$short_link" ":$TEST_SRC" \ ${SYSCALL_ARGS:-} || _fail "test_syscalls failed" fi fuse_umount fuse-3.18.3/test/cases/misc/0000755000175000017500000000000015250106036014524 5ustar berndberndfuse-3.18.3/test/cases/misc/hello-uds.sh0000755000175000017500000000171615250106036016764 0ustar berndbernd#!/usr/bin/env bash # GROUP: misc # The protocol goes over a socket here, not /dev/fuse. _fuse_no_mount_needed=1 . "$TEST_LIB/common.sh" _require_binary example/hello_ll_uds # Relative, hence short: sun_path holds 108 bytes, which the run directory # alone can exhaust. The daemon inherits this script's cwd ($TEST_LOGDIR) and # never chdirs, and checks.py runs in it too, so a bare name is the same # socket from both ends. A name of its own per test also keeps a second run, # or the root pass beside the non-root one, out of the way. sockpath=hello_ll.sock # It never calls fuse_mount, so none of the mount verbs apply: it serves the # FUSE protocol over an AF_UNIX socket through fuse_session_custom_io(). "$FUSE_EXAMPLE_DIR/hello_ll_uds" --socket="$sockpath" \ >"$TEST_LOGDIR/fs-0-hello_ll_uds.out" 2>&1 & uds_pid=$! _at_exit "kill $uds_pid 2>/dev/null" _wait_for 10 "[ -S '$sockpath' ]" || _fail "$sockpath never appeared" _check fuse_test_uds_init "$sockpath" fuse-3.18.3/test/cases/misc/printcap.sh0000755000175000017500000000053315250106036016704 0ustar berndbernd#!/usr/bin/env bash # GROUP: misc quick . "$TEST_LIB/common.sh" _require_binary example/printcap # The runner already ran printcap once to build $FUSE_CAPS; this is the case # that fails rather than silently reporting no capabilities when it breaks. "$FUSE_EXAMPLE_DIR/printcap" [ -n "$FUSE_CAPS" ] || _fail "printcap reported no capabilities" fuse-3.18.3/test/cases/mount/0000755000175000017500000000000015250106036014733 5ustar berndberndfuse-3.18.3/test/cases/mount/attrs-default-hello-ll.sh0000755000175000017500000000027215250106036021560 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll mountinfo_assert() { _assert_mount_opt "$TEST_MNT" rw nosuid nodev _refute_mount_opt "$TEST_MNT" ro } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-default-hello.sh0000755000175000017500000000026715250106036021157 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello mountinfo_assert() { _assert_mount_opt "$TEST_MNT" rw nosuid nodev _refute_mount_opt "$TEST_MNT" ro } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-nodev-hello-ll.sh0000755000175000017500000000023715250106036021250 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=nodev mountinfo_assert() { _assert_mount_opt "$TEST_MNT" nodev } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-nodev-hello.sh0000755000175000017500000000023415250106036020640 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=nodev mountinfo_assert() { _assert_mount_opt "$TEST_MNT" nodev } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-nosuid-hello-ll.sh0000755000175000017500000000024115250106036021431 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=nosuid mountinfo_assert() { _assert_mount_opt "$TEST_MNT" nosuid } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-nosuid-hello.sh0000755000175000017500000000023615250106036021030 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=nosuid mountinfo_assert() { _assert_mount_opt "$TEST_MNT" nosuid } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-ro-hello-ll.sh0000755000175000017500000000033515250106036020554 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=ro mountinfo_assert() { _assert_mount_opt "$TEST_MNT" ro _refute_mount_opt "$TEST_MNT" rw _assert_super_opt "$TEST_MNT" ro } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-ro-hello.sh0000755000175000017500000000033215250106036020144 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=ro mountinfo_assert() { _assert_mount_opt "$TEST_MNT" ro _refute_mount_opt "$TEST_MNT" rw _assert_super_opt "$TEST_MNT" ro } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-root-dev-hello-ll.sh0000755000175000017500000000030515250106036021670 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount . "$TEST_LIB/common.sh" _require_root FS_NAME=hello_ll MOUNT_OPTS=dev mountinfo_assert() { _refute_mount_opt "$TEST_MNT" nodev } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-root-dev-hello.sh0000755000175000017500000000030215250106036021260 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount . "$TEST_LIB/common.sh" _require_root FS_NAME=hello MOUNT_OPTS=dev mountinfo_assert() { _refute_mount_opt "$TEST_MNT" nodev } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-root-suid-hello-ll.sh0000755000175000017500000000030715250106036022060 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount . "$TEST_LIB/common.sh" _require_root FS_NAME=hello_ll MOUNT_OPTS=suid mountinfo_assert() { _refute_mount_opt "$TEST_MNT" nosuid } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/attrs-root-suid-hello.sh0000755000175000017500000000030415250106036021450 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount . "$TEST_LIB/common.sh" _require_root FS_NAME=hello MOUNT_OPTS=suid mountinfo_assert() { _refute_mount_opt "$TEST_MNT" nosuid } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/blkdev-fsname-hello-ll.sh0000755000175000017500000000115615250106036021521 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount serial . "$TEST_LIB/common.sh" _require_root _require_prog losetup FS_NAME=hello_ll mountinfo_setup() { loop_file=$TEST_TMP/loop.img dd if=/dev/zero of="$loop_file" bs=1M count=1 status=none loop_dev=$(losetup -f --show "$loop_file") _at_exit "losetup -d '$loop_dev'" MOUNT_OPTS="blkdev,fsname=$loop_dev,subtype=mysub" } mountinfo_assert() { # fstype carries the subtype only where the kernel took it. _assert_fstype "$TEST_MNT" fuseblk.mysub fuseblk # The source must be the device name, not 'fuseblk'. _assert_source "$TEST_MNT" "$loop_dev" } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/blkdev-fsname-hello.sh0000755000175000017500000000115315250106036021111 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount serial . "$TEST_LIB/common.sh" _require_root _require_prog losetup FS_NAME=hello mountinfo_setup() { loop_file=$TEST_TMP/loop.img dd if=/dev/zero of="$loop_file" bs=1M count=1 status=none loop_dev=$(losetup -f --show "$loop_file") _at_exit "losetup -d '$loop_dev'" MOUNT_OPTS="blkdev,fsname=$loop_dev,subtype=mysub" } mountinfo_assert() { # fstype carries the subtype only where the kernel took it. _assert_fstype "$TEST_MNT" fuseblk.mysub fuseblk # The source must be the device name, not 'fuseblk'. _assert_source "$TEST_MNT" "$loop_dev" } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-baseline-hello-ll.sh0000755000175000017500000000032115250106036022572 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.hello_ll fuse _assert_super_opt_prefix "$TEST_MNT" user_id= group_id= } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-baseline-hello.sh0000755000175000017500000000031315250106036022166 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.hello fuse _assert_super_opt_prefix "$TEST_MNT" user_id= group_id= } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-fsname-hello-ll.sh0000755000175000017500000000025115250106036022263 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=fsname=myfsname mountinfo_assert() { _assert_source "$TEST_MNT" myfsname } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-fsname-hello.sh0000755000175000017500000000024615250106036021662 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=fsname=myfsname mountinfo_assert() { _assert_source "$TEST_MNT" myfsname } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-subtype-fsname-hello-ll.sh0000755000175000017500000000035515250106036023761 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=subtype=mysub,fsname=myfsname mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.mysub _assert_source "$TEST_MNT" myfsname mysub#myfsname } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-subtype-fsname-hello.sh0000755000175000017500000000035215250106036023351 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=subtype=mysub,fsname=myfsname mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.mysub _assert_source "$TEST_MNT" myfsname mysub#myfsname } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-subtype-hello-ll.sh0000755000175000017500000000025115250106036022505 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello_ll MOUNT_OPTS=subtype=mysub mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.mysub } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountinfo-subtype-hello.sh0000755000175000017500000000024615250106036022104 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount FS_NAME=hello MOUNT_OPTS=subtype=mysub mountinfo_assert() { _assert_fstype "$TEST_MNT" fuse.mysub } . "$TEST_LIB/mountinfo.sh" fuse-3.18.3/test/cases/mount/mountpoint-symlink-parent.sh0000755000175000017500000000155715250106036022471 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount # # Only the last component of a mountpoint is refused as a symlink, so a # mountpoint reached through a symlinked parent still mounts. Guards against a # resolution rule that rejects a symlink anywhere in the path and so breaks # every user whose mountpoint sits below a symlinked home. . "$TEST_LIB/common.sh" # Root mounts with mount(2) and reaches fusermount3 only on EPERM, so the # resolution rule under test is not on the path a root run takes. _require_nonroot mkdir -p "$TEST_TMP/real/mnt" ln -s "$TEST_TMP/real" "$TEST_TMP/link" fuse_mount_at "$TEST_TMP/link/mnt" hello -f >/dev/null # Named through the real path, not through the symlink: what is being checked # is that the mount landed on the inode the symlink resolved to. _check fuse_test_ismount "$TEST_TMP/real/mnt" _assert_listdir "$TEST_TMP/real/mnt" hello fuse_umount fuse-3.18.3/test/cases/mount/mountpoint-validation.sh0000755000175000017500000000235515250106036021643 0ustar berndbernd#!/usr/bin/env bash # GROUP: mount quick # # fusermount3 refuses a mountpoint it cannot validate. Every case here is # rejected before mount(2) is reached, so this needs the kernel module but # not a setuid fusermount3. _fuse_no_mount_needed=1 . "$TEST_LIB/common.sh" _require_linux "fusermount3" # Root skips the mountpoint checks entirely and follows a symlinked mountpoint. _require_nonroot _require_fuse_device _require_binary util/fusermount3 : >"$TEST_TMP/plain" ln -s "$TEST_SRC" "$TEST_TMP/link-dir" ln -s "$TEST_TMP/plain" "$TEST_TMP/link-reg" ln -s "$TEST_TMP/gone" "$TEST_TMP/link-dangling" mkfifo "$TEST_TMP/fifo" mkdir "$TEST_TMP/nowrite" chmod 500 "$TEST_TMP/nowrite" # O_NOFOLLOW makes fstat() see the final symlink itself, so the target type # cannot make a symlink acceptable as a mountpoint. _check fuse_test_fusermount_rejects "$TEST_TMP/link-dir" not_dir_or_regular _check fuse_test_fusermount_rejects "$TEST_TMP/link-reg" not_dir_or_regular _check fuse_test_fusermount_rejects "$TEST_TMP/link-dangling" not_dir_or_regular _check fuse_test_fusermount_rejects "$TEST_TMP/fifo" not_dir_or_regular _check fuse_test_fusermount_rejects "$TEST_TMP/nowrite" no_write_access _check fuse_test_fusermount_rejects "$TEST_TMP/missing" no_such_file fuse-3.18.3/test/cases/notify/0000755000175000017500000000000015250106036015101 5ustar berndberndfuse-3.18.3/test/cases/notify/file-size-no-notify.sh0000755000175000017500000000016015250106036021244 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=invalidate_path NOTIFY=0 NOTIFY_MODE=size . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/file-size.sh0000755000175000017500000000016015250106036017324 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=invalidate_path NOTIFY=1 NOTIFY_MODE=size . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-expire-no-notify.sh0000755000175000017500000000050315250106036023120 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify . "$TEST_LIB/common.sh" # The kernel has to support expiring an entry rather than # invalidating it; printcap reports whether it does. _require_cap FUSE_CAP_EXPIRE_ONLY FS_NAME=notify_inval_entry NOTIFY=0 NOTIFY_MODE=entry FS_ARGS="--timeout=5 --only-expire" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-expire.sh0000755000175000017500000000050315250106036021200 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify . "$TEST_LIB/common.sh" # The kernel has to support expiring an entry rather than # invalidating it; printcap reports whether it does. _require_cap FUSE_CAP_EXPIRE_ONLY FS_NAME=notify_inval_entry NOTIFY=1 NOTIFY_MODE=entry FS_ARGS="--timeout=5 --only-expire" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-inc-epoch-no-notify.sh0000755000175000017500000000052115250106036023471 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_entry NOTIFY=0 NOTIFY_MODE=entry FS_ARGS="--timeout=5 --inc-epoch" # There is no capability flag for the epoch counter, so the gate # is what notify_inval_entry itself prints when the kernel # refuses the request. MARKER_ABSENT="not supported by kernel" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-inc-epoch.sh0000755000175000017500000000052115250106036021551 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_entry NOTIFY=1 NOTIFY_MODE=entry FS_ARGS="--timeout=5 --inc-epoch" # There is no capability flag for the epoch counter, so the gate # is what notify_inval_entry itself prints when the kernel # refuses the request. MARKER_ABSENT="not supported by kernel" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-invalidate-no-notify.sh0000755000175000017500000000021215250106036023741 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_entry NOTIFY=0 NOTIFY_MODE=entry FS_ARGS="--timeout=5" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-entry-invalidate.sh0000755000175000017500000000021215250106036022021 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_entry NOTIFY=1 NOTIFY_MODE=entry FS_ARGS="--timeout=5" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-inode-no-notify.sh0000755000175000017500000000016615250106036021570 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_inode NOTIFY=0 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/inval-inode.sh0000755000175000017500000000016615250106036017650 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_inval_inode NOTIFY=1 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/invalidate-path-no-notify.sh0000755000175000017500000000016315250106036022432 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=invalidate_path NOTIFY=0 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/invalidate-path.sh0000755000175000017500000000016315250106036020512 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=invalidate_path NOTIFY=1 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/prune-no-notify.sh0000755000175000017500000000044315250106036020512 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_prune NOTIFY=0 NOTIFY_MODE=prune # There is no capability flag for FUSE_NOTIFY_PRUNE, so the gate # is what notify_prune itself prints when the kernel refuses the # request. MARKER_ABSENT="not supported by kernel" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/prune.sh0000755000175000017500000000044315250106036016572 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_prune NOTIFY=1 NOTIFY_MODE=prune # There is no capability flag for FUSE_NOTIFY_PRUNE, so the gate # is what notify_prune itself prints when the kernel refuses the # request. MARKER_ABSENT="not supported by kernel" . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/store-retrieve-no-notify.sh0000755000175000017500000000017115250106036022336 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_store_retrieve NOTIFY=0 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/notify/store-retrieve.sh0000755000175000017500000000017115250106036020416 0ustar berndbernd#!/usr/bin/env bash # GROUP: notify FS_NAME=notify_store_retrieve NOTIFY=1 NOTIFY_MODE=content . "$TEST_LIB/notify.sh" fuse-3.18.3/test/cases/unit/0000755000175000017500000000000015250106036014550 5ustar berndberndfuse-3.18.3/test/cases/unit/test_abi0000644000175000017500000000002415250106036016261 0ustar berndbernd# GROUP: unit quick fuse-3.18.3/test/ci-build.sh0000755000175000017500000001653415250106036014533 0ustar berndbernd#!/bin/bash # # Build one libfuse configuration and run the test suite against it. # # One invocation is one configuration. The workflow's build matrix supplies # the arguments for each of them, and CI runs them as parallel matrix jobs. set -e usage() { cat >&2 <&2; exit 1; } } NAME= CC_BIN=cc CXX_BIN= SANITIZE=0 VALGRIND=0 ROOT=0 IO_URING=0 MESON_OPTS=() cli_work_dir= while [ $# -gt 0 ]; do case $1 in --name) need_arg "$@"; NAME=$2; shift 2 ;; --cc) need_arg "$@"; CC_BIN=$2; shift 2 ;; --cxx) need_arg "$@"; CXX_BIN=$2; shift 2 ;; --meson-opt) need_arg "$@"; MESON_OPTS+=("$2"); shift 2 ;; --work-dir) need_arg "$@"; cli_work_dir=$2; shift 2 ;; --sanitize) SANITIZE=1; shift ;; --valgrind) VALGRIND=1; shift ;; --root) ROOT=1; shift ;; --io-uring) IO_URING=1; shift ;; *) usage ;; esac done [ -n "${NAME}" ] || usage # Make sure binaries can be accessed when invoked by root. umask 0022 SOURCE_DIR="$(readlink -f "$(dirname "$0")/..")" # Where this run's builds and logs go. --work-dir is used verbatim so CI can # predict the path it later uploads; otherwise take the base from run-tests.py # (persisted config, else /var/tmp/fuse-tests) and append a dedicated leaf. # Asking the runner keeps the precedence in one place instead of parsing an # INI in bash. WORK_DIR="${cli_work_dir:-}" if [ -z "${WORK_DIR}" ]; then WORK_DIR="$(python3 "${SOURCE_DIR}/test/run-tests.py" --print-base-dir)" WORK_DIR="${WORK_DIR}/ci-${USER:-unknown}-$(date +%y%m%d%H%M%S)" fi WORK_DIR="$(readlink -f "${WORK_DIR}")" # resolve before the cd below # Named after the configuration, so several of them share one work directory # without colliding and the logs of a whole run stay together. BUILD_DIR="${WORK_DIR}/build-${NAME}" PREFIX_DIR="${WORK_DIR}/install-${NAME}" RUN_DIR="${WORK_DIR}/run" # A stale tree from a previous failed run would poison this one. The install # prefix is owned by root from the last `ninja install`. rm -rf "${BUILD_DIR}" sudo rm -rf "${PREFIX_DIR}" mkdir -p "${BUILD_DIR}" "${PREFIX_DIR}" "${RUN_DIR}" # There are tests that run as root but without CAP_DAC_OVERRIDE. To allow those # to launch built binaries, every directory on the way in must be traversable # by plain permission bits. chmod 0755 "${WORK_DIR}" "${BUILD_DIR}" "${PREFIX_DIR}" "${RUN_DIR}" cd "${BUILD_DIR}" echo "Building ${NAME} in ${BUILD_DIR}" echo "=== System ===" uname -a lsb_release -a 2>/dev/null || cat /etc/os-release 2>/dev/null || true lscpu || true echo "===============" export CC="${CC_BIN}" if [ -n "${CXX_BIN}" ]; then export CXX="${CXX_BIN}" else unset CXX fi # Exported rather than assigned: run-tests.py reads it from the environment of # the process meson spawns. if [ "${VALGRIND}" = 1 ]; then export TEST_WITH_VALGRIND=true else export TEST_WITH_VALGRIND=false fi cp -v "${SOURCE_DIR}/test/lsan_suppress.txt" . export LSAN_OPTIONS="suppressions=${BUILD_DIR}/lsan_suppress.txt" export ASAN_OPTIONS="detect_leaks=1" export UBSAN_OPTIONS=halt_on_error=1 # not the default echo "=== Environment ===" echo "Configuration: ${NAME}" echo "CC: ${CC}" echo "CXX: ${CXX-}" echo "Sanitize: ${SANITIZE}" echo "LSAN_OPTIONS: ${LSAN_OPTIONS}" echo "ASAN_OPTIONS: ${ASAN_OPTIONS}" echo "UBSAN_OPTIONS: ${UBSAN_OPTIONS}" echo "Valgrind: ${TEST_WITH_VALGRIND}" echo "Root: ${ROOT}" echo "IO-uring: ${IO_URING}" echo "===================" meson setup -Dprefix="${PREFIX_DIR}" -Dwerror=true "${MESON_OPTS[@]}" \ "${SOURCE_DIR}" || { cat meson-logs/meson-log.txt; false; } if [ "${SANITIZE}" = 1 ]; then meson configure -Db_sanitize=address,undefined # b_lundef=false is required to work around a clang bug, cf. # https://groups.google.com/forum/#!topic/mesonbuild/tgEdAXIIdC4 meson configure -Db_lundef=false # Reconfigure so the build actually uses them. meson setup --reconfigure "${SOURCE_DIR}" fi meson configure --no-pager # what was actually configured ninja sudo env PATH="$PATH" ninja install # libfuse will first try the install path and then system defaults. sudo chmod 4755 "${PREFIX_DIR}/bin/fusermount3" if [ -x "${PREFIX_DIR}/sbin/fuservicemount3" ]; then sudo chmod 4755 "${PREFIX_DIR}/sbin/fuservicemount3" fi restore_io_uring() { echo "${FUSE_URING_WAS}" | sudo tee "$1" >/dev/null [ -z "${IO_URING_DISABLED_WAS}" ] || sudo sysctl -q -w "kernel.io_uring_disabled=${IO_URING_DISABLED_WAS}" } if [ "${IO_URING}" = 1 ]; then # The kernel parameter is global and defaults to off, and this script is # also run by hand, so put back whatever the machine had. Failing to enable # it is fatal: run-tests.py skips its io-uring invocation where the kernel # does not offer the transport, which is right for a developer machine and # wrong here - a job that silently stops testing io-uring is what this # exists to prevent. param=/sys/module/fuse/parameters/enable_uring sysctl_param=/proc/sys/kernel/io_uring_disabled FUSE_URING_WAS="$(cat "${param}")" || { echo "this kernel has no fuse io-uring support"; exit 1; } # Non-zero denies the daemons io_uring_setup(), which drops them back to # /dev/fuse. Empty before 6.6, where nothing restricts ring creation. IO_URING_DISABLED_WAS="$(cat "${sysctl_param}" 2>/dev/null || true)" # Armed before either write, so a failure between them still restores. trap "restore_io_uring ${param}" EXIT echo Y | sudo tee "${param}" >/dev/null [ -z "${IO_URING_DISABLED_WAS}" ] || sudo sysctl -q -w kernel.io_uring_disabled=0 fi RUN_TESTS_OPTS=(--build-dir .) [ "${IO_URING}" = 1 ] && RUN_TESTS_OPTS+=(--io-uring) if [ "${ROOT}" = 1 ]; then SUDO=(sudo) else SUDO=() RUN_TESTS_OPTS+=(--setuid-helpers) fi # sudo resets the environment, so PATH and FUSE_TEST_RUN_DIR are passed # through env rather than shell-prefix assignments, which sudo would # otherwise drop; harmless when SUDO is empty. Calling run-tests.py directly, # never through `meson test`, keeps its per-test results in the job log # instead of only printing output on failure. rc=0 "${SUDO[@]}" env PATH="$PATH" FUSE_TEST_RUN_DIR="${RUN_DIR}/${NAME}" \ timeout 1800 python3 "${SOURCE_DIR}/test/run-tests.py" \ "${RUN_TESTS_OPTS[@]}" || rc=$? if [ "${ROOT}" = 1 ]; then # upload-artifact has to read what root wrote -- before the failure is # propagated, or one unreadable file fails the whole upload of the very # run whose logs are wanted. sudo chown -R "$(id -u):$(id -g)" "${RUN_DIR}" fi [ "${rc}" = 0 ] || exit "${rc}" # Only reached when everything above passed, because of set -e: a failed run # has to stay inspectable. The logs are kept either way, and are the product. rm -rf "${BUILD_DIR}" sudo rm -rf "${PREFIX_DIR}" fuse-3.18.3/test/ci/0000755000175000017500000000000015250106036013066 5ustar berndberndfuse-3.18.3/test/ci/doxygen.sh0000755000175000017500000000033215250106036015100 0ustar berndbernd#!/bin/bash # The API documentation build. Not a build configuration: it needs no compiler # of its own and none of them has to have run first. set -e cd "$(readlink -f "$(dirname "$0")/../..")" doxygen doc/Doxyfile fuse-3.18.3/test/ci/prepare-runner.sh0000755000175000017500000000441115250106036016372 0ustar berndbernd#!/bin/bash # # Host tuning a CI runner needs and a developer machine must not get. # # Cores must land in the test's own log directory, which run-tests.py makes the # cwd of every test. ubuntu-latest ships apport, so core_pattern is a pipe and # every core disappears into a collector the job then throws away. %p keeps two # crashing processes in one test from overwriting each other, and %e is how the # runner finds the binary to hand gdb. # # Deliberately not part of ci-build.sh: that script is also run by hand, and a # build script has no business rewriting a global kernel tunable -- or, below, # the permission bits on directories outside the tree it builds -- on someone's # workstation. Locally the runner's own warning is enough, and it still fetches # cores through coredumpctl. # # Usage: prepare-runner.sh set -e # Before the writes below, so a mistyped invocation leaves the host alone. # Absolute, because the ancestor walk further down ends at / and `dirname` on # a relative path stops at "." instead -- which is a loop, not a walk. WORK_DIR="$(readlink -f "${1:?usage: prepare-runner.sh }")" SOURCE_DIR="$(readlink -f "$(dirname "$0")/../..")" sudo sysctl -w kernel.core_pattern=core.%e.%p sudo sysctl -w kernel.core_uses_pid=0 # There are tests that run as root but without CAP_DAC_OVERRIDE. To allow those # to launch built binaries, every ancestor of the work directory must be # traversable by plain permission bits; a 0750 home is the usual culprit. This # script does not create the work directory itself -- ci-build.sh chmods that # and the directories below it -- only the ancestors above it. dir="$(dirname "${WORK_DIR}")" while [ "${dir}" != / ]; do if [ -z "$(find "${dir}" -maxdepth 0 -perm -001)" ]; then echo "making ${dir} traversable for the capability-less tests" chmod o+x "${dir}" 2>/dev/null || sudo chmod o+x "${dir}" fi dir="$(dirname "${dir}")" done # Assert it rather than trust the loop: a test that skips itself here leaves a # green job that stopped exercising drop_privileges, which is the one outcome # CI must not produce. python3 "${SOURCE_DIR}/test/cases/lib/checks.py" fuse_test_reachable_without_caps \ "$(dirname "${WORK_DIR}")" || { echo "use --work-dir to build somewhere reachable"; exit 1; } fuse-3.18.3/test/hello.c0000644000175000017500000001036315250106036013745 0ustar berndbernd/* * FUSE: Filesystem in Userspace * Copyright (C) 2001-2007 Miklos Szeredi * * This program can be distributed under the terms of the GNU GPLv2. * See the file GPL2.txt. */ /** @file * * minimal example filesystem using high-level API * * Compile with: * * gcc -Wall hello.c `pkg-config fuse3 --cflags --libs` -o hello * * ## Source code ## * \include hello.c */ #define FUSE_USE_VERSION 31 #include #include #include #include #include #include #include /* * Command line options * * We can't set default values for the char* fields here because * fuse_opt_parse would attempt to free() them when the user specifies * different values on the command line. */ static struct options { const char *filename; const char *contents; int show_help; } options; #define OPTION(t, p) { t, offsetof(struct options, p), 1 } static const struct fuse_opt option_spec[] = { OPTION("--name=%s", filename), OPTION("--contents=%s", contents), OPTION("-h", show_help), OPTION("--help", show_help), FUSE_OPT_END }; static void *hello_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void)conn; cfg->kernel_cache = 1; /* Test setting flags the old way */ conn->want = FUSE_CAP_ASYNC_READ; conn->want &= ~FUSE_CAP_ASYNC_READ; return NULL; } static int hello_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { (void)fi; int res = 0; memset(stbuf, 0, sizeof(struct stat)); if (strcmp(path, "/") == 0) { stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; } else if (strcmp(path + 1, options.filename) == 0) { stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(options.contents); } else res = -ENOENT; return res; } static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi, enum fuse_readdir_flags flags) { (void)offset; (void)fi; (void)flags; if (strcmp(path, "/") != 0) return -ENOENT; filler(buf, ".", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, "..", NULL, 0, FUSE_FILL_DIR_DEFAULTS); filler(buf, options.filename, NULL, 0, FUSE_FILL_DIR_DEFAULTS); return 0; } static int hello_open(const char *path, struct fuse_file_info *fi) { if (strcmp(path + 1, options.filename) != 0) return -ENOENT; if ((fi->flags & O_ACCMODE) != O_RDONLY) return -EACCES; return 0; } static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { size_t len; (void)fi; if (strcmp(path + 1, options.filename) != 0) return -ENOENT; len = strlen(options.contents); if (offset < len) { if (offset + size > len) size = len - offset; memcpy(buf, options.contents + offset, size); } else size = 0; return size; } static const struct fuse_operations hello_oper = { .init = hello_init, .getattr = hello_getattr, .readdir = hello_readdir, .open = hello_open, .read = hello_read, }; static void show_help(const char *progname) { printf("usage: %s [options] \n\n", progname); printf("File-system specific options:\n" " --name= Name of the \"hello\" file\n" " (default: \"hello\")\n" " --contents= Contents \"hello\" file\n" " (default \"Hello, World!\\n\")\n" "\n"); } int main(int argc, char *argv[]) { int ret; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); /* Set defaults -- we have to use strdup so that * fuse_opt_parse can free the defaults if other * values are specified */ options.filename = strdup("hello"); options.contents = strdup("Hello World!\n"); /* Parse options */ if (fuse_opt_parse(&args, &options, option_spec, NULL) == -1) return 1; /* When --help is specified, first print our own file-system * specific help text, then signal fuse_main to show * additional help (by adding `--help` to the options again) * without usage: line (by setting argv[0] to the empty * string) */ if (options.show_help) { show_help(argv[0]); assert(fuse_opt_add_arg(&args, "--help") == 0); args.argv[0][0] = '\0'; } ret = fuse_main(args.argc, args.argv, &hello_oper, NULL); fuse_opt_free_args(&args); return ret; } fuse-3.18.3/test/lsan_suppress.txt0000644000175000017500000000005215250106036016132 0ustar berndbernd# Suppression file for address sanitizer. fuse-3.18.3/test/meson.build0000644000175000017500000000524415250106036014642 0ustar berndbernd# Compile helper programs td = [] foreach prog: [ 'test_write_cache', 'test_setattr', 'test_api_30', 'hello' ] td += executable(prog, prog + '.c', include_directories: include_dirs, link_with: [ libfuse ], dependencies: thread_dep, install: false) endforeach td += executable('test_syscalls', 'test_syscalls.c', include_directories: include_dirs, install: false) td += executable('readdir_inode', 'readdir_inode.c', include_directories: include_dirs, install: false) td += executable('release_unlink_race', 'release_unlink_race.c', dependencies: [ libfuse_dep ], install: false) td += executable('test_want_conversion', 'test_want_conversion.c', dependencies: [ libfuse_dep ], install: false) td += executable('test_signals', 'test_signals.c', dependencies: [ libfuse_dep, thread_dep ], install: false) td += executable('test_abi', 'test_abi.c', dependencies: [ libfuse_dep ], install: false) if meson.is_subproject() # Skipped rather than run: the tests mount filesystems, which is not # something a parent project's `meson test` should do. Exit 77 is how a # test tells meson SKIP. python3 is optional here because nothing else # in this branch needs it, and a parent must still be able to configure. python3 = find_program('python3', required: false) if python3.found() test('libfuse is a subproject, skipping tests', python3, args: ['-c', 'import sys; print("run them with test/run-tests.py ' + '--build-dir ", file=sys.stderr); sys.exit(77)']) endif else # The same definition works both as a regular user and under sudo: # invoke 'meson test -C build' for the unprivileged subset, or # 'sudo -E meson test -C build' to also exercise the tests that require # root (they pick the uid up at runtime). # # Nothing is copied into the build tree: the runner, # its library and the test scripts are read from the source dir, and # the only build artefacts a test needs are the binaries, which it # reaches through --build-dir. That also means no custom_target and no # rebuild after editing a test. # # No --run-dir: it defaults under /var/tmp/fuse-tests, and CI redirects # it with $FUSE_TEST_RUN_DIR so the logs outlive the build tree. runner = find_program('run-tests.py') test('fuse-tests', runner, args: ['--build-dir', meson.project_build_root()], depends: td, timeout: 1800, is_parallel: false) # the runner does its own -j endif fuse-3.18.3/test/readdir_inode.c0000644000175000017500000000310015250106036015421 0ustar berndbernd/* * Prints each directory entry, its inode and d_type as returned by 'readdir'. * Skips '.' and '..' because readdir is not required to return them and * some of our examples don't. However if they are returned, their d_type * should be valid. */ #include #include #include #include #include int main(int argc, char* argv[]) { DIR* dirp; struct dirent* dent; if (argc != 2) { fprintf(stderr, "Usage: readdir_inode dir\n"); return 1; } dirp = opendir(argv[1]); if (dirp == NULL) { perror("failed to open directory"); return 2; } errno = 0; dent = readdir(dirp); while (dent != NULL) { if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) { printf("%llu %d %s\n", (unsigned long long)dent->d_ino, (int)dent->d_type, dent->d_name); if ((long long)dent->d_ino < 0) fprintf(stderr,"%s : bad d_ino %llu\n", dent->d_name, (unsigned long long)dent->d_ino); if ((dent->d_type < 1) || (dent->d_type > 15)) fprintf(stderr,"%s : bad d_type %d\n", dent->d_name, (int)dent->d_type); } else { if (dent->d_type != DT_DIR) fprintf(stderr,"%s : bad d_type %d\n", dent->d_name, (int)dent->d_type); } dent = readdir(dirp); } if (errno != 0) { perror("failed to read directory entry"); return 3; } closedir(dirp); return 0; } fuse-3.18.3/test/release_unlink_race.c0000644000175000017500000000337415250106036016640 0ustar berndbernd/* This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ #define FUSE_USE_VERSION 31 #define _GNU_SOURCE #include #include #include #include #include static void *xmp_init(struct fuse_conn_info *conn, struct fuse_config *cfg) { (void) conn; cfg->use_ino = 1; cfg->nullpath_ok = 1; 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_unlink(const char *path) { int res; res = unlink(path); 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; if(!getenv("RELEASEUNLINKRACE_DELAY_DISABLE")) usleep(100000); res = rename(from, to); if (res == -1) return -errno; return 0; } 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_release(const char *path, struct fuse_file_info *fi) { (void) path; if(!getenv("RELEASEUNLINKRACE_DELAY_DISABLE")) usleep(100000); close(fi->fh); return 0; } static const struct fuse_operations xmp_oper = { .init = xmp_init, .getattr = xmp_getattr, .unlink = xmp_unlink, .rename = xmp_rename, .create = xmp_create, .release = xmp_release, }; int main(int argc, char *argv[]) { umask(0); return fuse_main(argc, argv, &xmp_oper, NULL); } fuse-3.18.3/test/run-tests.py0000755000175000017500000021163315250106036015022 0ustar berndbernd#!/usr/bin/env python3 """Run the libfuse shell test suite. Every executable cases/**/*.sh outside cases/lib is a test, as is every entry in a directory is_shell_exception_dir() names, where the file name is a build-tree binary to run instead. A test's name is the path below cases/ without the extension. Exit code 0 is a pass, 77 a self-declared skip and anything else a failure. The runner knows nothing about FUSE: it owns discovery, working directories, containment, timeouts, parallelism, logs, core dumps and the summary. The FUSE verbs live in cases/lib/common.sh. """ import argparse import ctypes import fnmatch import os import platform import re import resource import shutil import signal import stat import subprocess import sys import threading import time from concurrent.futures import ThreadPoolExecutor, as_completed from dataclasses import dataclass, field, replace from pathlib import Path # Everything the suite reads lives beside this file in the source tree; the # build directory supplies binaries and nothing else, so a test edited in the # source tree runs without a rebuild. TEST_DIR = Path(__file__).resolve().parent CASES_DIR = TEST_DIR / 'cases' # What the cases source, beside them rather than above them; discovery skips it. LIB_DIR = CASES_DIR / 'lib' EXCLUDE_FILE = TEST_DIR / 'exclude' DEFAULT_TIMEOUT = 60.0 # seconds; per-script "# TIMEOUT:" overrides SKIP_EXIT_CODE = 77 # automake convention LAUNCH_FAILED_EXIT_CODE = 125 # launcher could not establish containment LAUNCH_FAILED_MARKER = 'run-tests: containment failed' # util/install_helper.sh installs exactly these setuid; nothing else in util/ # needs the bit. SETUID_HELPERS = ('fusermount3', 'fuservicemount3') GDB_TIMEOUT = 120.0 # gdb can wedge on a huge core or absent symbols GDB_TOP_FRAMES = 12 # frames inlined into the summary # A task wedged in an uninterruptible FUSE request does not die on SIGKILL, so # waiting for one without a bound hangs the run itself. REAP_TIMEOUT = 30.0 # seconds to wait for a killed test to be gone # A daemon under valgrind is an order of magnitude slower, so every timeout is # scaled by one constant rather than each script carrying a second number for a # mode most runs do not use. VALGRIND_TIMEOUT_FACTOR = 10 # --error-exitcode is what makes a finding fail the test: the daemon exits 99 # and fuse_umount's existing status check catches it. Leak checking stays off; # turning it on is a separate decision with its own noise budget. VALGRIND_PREFIX = 'valgrind -q --error-exitcode=99 --' # ==PID== is valgrind's standard output, --PID-- its warnings; the report is # not the verdict, the daemon's exit status is. _VALGRIND_LINE_RE = re.compile(r'^(?:==|--)[0-9]+(?:==|--) .*$', re.MULTILINE) # Test output must land somewhere predictable, so this is the default base for # everything the suite writes. /var/tmp rather than /tmp because it survives a # reboot and no tmpfiles cleaner walks it mid-run, and a fixed name rather than # a mktemp directory because a path you cannot predict is a path you cannot # look in after CI hands you a red build. DEFAULT_BASE_DIR = Path('/var/tmp/fuse-tests') # Tests declaring this group cannot run concurrently with a copy of themselves: # they bind a fixed path, name a device node globally, or take the first free # loop device. They run first, with one job, before the rest fan out. SERIAL_GROUP = 'serial' _CONFIG_SECTION = 'tests' _CONFIG_BASE_DIR_KEY = 'base_dir' IS_LINUX = platform.system() == 'Linux' # FreeBSD's default kern.corefile is "%N.core"; CI sets "core.%N.%P" to get the # shape Linux's "core.%e.%p" produces. Glob those plus the bare "core" and # "core.%p" a stock Linux box writes, so an unconfigured developer machine # still yields a core. CORE_GLOBS = ('core', 'core.*', '*.core') # A daemon writing any of these to its stderr fails the test even when it # exited 0. SUSPICIOUS_WORDS = ('exception', 'error', 'warning', 'fatal', 'traceback', 'fault', 'crash(?:ed)?', 'abort(?:ed)?', 'uninitiali[zs]ed') # libfuse logs this at FUSE_LOG_INFO and then carries on over /dev/fuse, so an # io-uring run that nobody checks passes green while testing the transport it # was meant to replace. IO_URING_FALLBACK = 'failed to start io-uring' IO_URING_CAP = 'FUSE_CAP_OVER_IO_URING' # Every session states its transport on its own stderr, which is a log the # suite keeps either way. off:custom_io is the only refusal a daemon cannot # help: no /dev/fuse fd of its own, so no ring to issue against. IO_URING_STATE_KEY = 'FUSE_INIT: io_uring=' IO_URING_STATES_OK = ('FUSE_INIT: io_uring=on', 'FUSE_INIT: io_uring=off:custom_io') # What -Dsync-init=always/never leave in fuse_config.h; auto writes neither. SYNC_INIT_ENABLED = '#define FUSE_SYNC_INIT_DEFAULT FUSE_SYNC_INIT_ENABLED' SYNC_INIT_DISABLED = '#define FUSE_SYNC_INIT_DEFAULT FUSE_SYNC_INIT_DISABLED' FUSE_URING_PARAM = Path('/sys/module/fuse/parameters/enable_uring') # glibc has no io_uring_setup() wrapper, so this goes through syscall(2), the # way liburing does it. 425 on every architecture but alpha. IO_URING_SETUP = 425 IO_URING_PARAMS_SIZE = 120 # sizeof(struct io_uring_params) # FUSE debug messages "unique: X, error: -Y (...), outsize: Z" contain the word # "error" but only report a request's return code. _FUSE_DEBUG_RE = re.compile( r'^.*unique: \d+, error: -\d+ \(.*\), outsize: \d+.*$', re.MULTILINE) _HEADER_RE = re.compile(r'^#\s*(TIMEOUT|GROUP):\s*(.+?)\s*$') # Two things must happen in the child before the test runs: it must enter its # cgroup leaf and raise its soft core limit. Neither can be done with a # preexec_fn -- run_all() is threaded, and Python between fork() and exec() can # deadlock inside Popen(), where no timeout is watching yet. Only builtins run # here, so nothing forks before the leaf is joined and a daemon the script # spawns cannot escape it. # # `ulimit -H -c` rather than a limit computed in Python: ulimit counts 512-byte # blocks in dash and 1024-byte blocks in bash, and RLIM_INFINITY is -1 in # CPython, which every shell parses as an option. Only the soft limit is raised; # raising a finite hard limit needs privilege. # # The command to exec is passed in rather than built here: the runner decides # whether a test is a script or a binary, and both the spawn and repro.sh must # name the same one. LAUNCHER = f''' [ -z "$1" ] || printf '%s\\n' "$$" >"$1" || {{ echo "{LAUNCH_FAILED_MARKER}: cgroup" >&2; exit {LAUNCH_FAILED_EXIT_CODE} }} ulimit -S -c "$(ulimit -H -c)" || {{ echo "{LAUNCH_FAILED_MARKER}: core limit" >&2 exit {LAUNCH_FAILED_EXIT_CODE} }} shift exec "$@" ''' @dataclass(frozen=True) class TestSpec: """One discovered test and the two facts parsed from its header.""" name: str # "examples/hello-ll-direct" -- path under cases/, no .sh script: Path # absolute path to the script, or to the binary marker timeout: float # seconds; DEFAULT_TIMEOUT unless "# TIMEOUT:" overrides groups: frozenset # from "# GROUP:"; used by -g/--group selection binary: str = '' # marker: the build-tree binary to run; "" for a script @dataclass class CoreDump: """One core file found in a test's log directory.""" path: Path executable: str # %e from the file name, e.g. "passthrough_ll" pid: int # %p from the file name binary: Path | None = None # resolved build-tree binary # logs/backtrace...txt -- deliberately not sharing the "core." # prefix, so CI can upload backtraces while excluding the huge cores with a # single "!**/core.*" pattern. backtrace: Path | None = None # None if gdb is absent top_frames: str = '' # first GDB_TOP_FRAMES frames @dataclass class TestResult: """Outcome of one test script run.""" name: str status: str # "PASS" | "FAIL" | "SKIP" duration: float # wall clock seconds, monotonic exit_code: int # script exit status; negative == killed by signal reason: str # skip reason, kill reason, or "" on a clean pass workdir: Path cores: list = field(default_factory=list) # list[CoreDump], backtraced suspicious: str = '' # first offending log line found by scan_logs() def parse_spec(script: Path, cases_dir: Path) -> TestSpec: """Read the leading comment block of *script* for TIMEOUT and GROUP.""" timeout, groups = DEFAULT_TIMEOUT, set() with script.open() as fh: for line in fh: if not line.startswith('#'): if line.strip(): # first non-comment line ends the header break continue hit = _HEADER_RE.match(line) if not hit: continue if hit.group(1) == 'TIMEOUT': timeout = float(hit.group(2)) else: groups.update(hit.group(2).split()) return TestSpec(name=str(script.relative_to(cases_dir).with_suffix('')), script=script, timeout=timeout, groups=frozenset(groups), # discover() collects nothing else without a suffix binary='' if script.suffix else script.name) def read_core_pattern() -> str: """The kernel's core-file pattern, Linux and FreeBSD spelling alike.""" if IS_LINUX: try: return Path('/proc/sys/kernel/core_pattern').read_text().strip() except OSError: return '' proc = subprocess.run(['sysctl', '-n', 'kern.corefile'], capture_output=True, text=True, check=False) return proc.stdout.strip() def io_uring_setup_error() -> str: """The errno text when io_uring_setup() is refused, else "". Asked as the user the daemons will run as, so it answers for them. """ libc = ctypes.CDLL(None, use_errno=True) libc.syscall.restype = ctypes.c_long ring = libc.syscall(IO_URING_SETUP, 1, ctypes.create_string_buffer(IO_URING_PARAMS_SIZE)) if ring < 0: return os.strerror(ctypes.get_errno()) os.close(ring) return '' def raise_nofile_limit() -> None: """Raise RLIMIT_NOFILE to the hard limit; -j multiplies fd pressure.""" soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE) if soft >= hard: return try: resource.setrlimit(resource.RLIMIT_NOFILE, (hard, hard)) except (ValueError, OSError): return if hard != resource.RLIM_INFINITY and hard < 1024: print(f'note: RLIMIT_NOFILE hard limit is only {hard}; ' 'reduce -j if tests fail with EMFILE') def setuid_helpers(build_dir: Path) -> None: """chown root:root + chmod 4755 the build tree's mount helpers. Opt-in because it needs sudo and mutates the build tree; without it an unprivileged run skips every test that mounts. """ sudo = [] if os.geteuid() == 0 else ['sudo'] for name in SETUID_HELPERS: helper = build_dir / 'util' / name if not helper.exists(): # fuservicemount3 is not always built continue info = helper.stat() if info.st_uid == 0 and info.st_mode & stat.S_ISUID: continue for cmd in (['chown', 'root:root', str(helper)], ['chmod', '4755', str(helper)]): if subprocess.run(sudo + cmd, check=False).returncode: sys.exit(f'{" ".join(sudo + cmd)} failed') class CgroupManager: """A cgroup-v2 tree for the run, one leaf per test. The launcher puts itself into its leaf before it execs the test, so each descendant the script spawns -- the fs daemon, fusermount3, anything a helper backgrounds -- inherits it. Writing "1" to the leaf's cgroup.kill reaps the whole subtree atomically, which is the only reliable way to stop a wedged FUSE daemon that has already been reparented to init. cgroup-v2 is Linux-only, and FreeBSD does not mount /proc at all by default, so every method here is disabled off Linux and the runner falls back to killpg(). """ def __init__(self, root: Path | None): self.root = root self._counter = 0 self._lock = threading.Lock() @classmethod def create(cls, tag: str) -> "CgroupManager": """Create the run root under the delegated base; disabled on failure.""" base = cls.delegated_base() if base is None: if IS_LINUX: print('note: no writable delegated cgroup; containing tests ' 'with killpg() instead of cgroup.kill') else: print(f'note: cgroups are Linux-only; containing tests with ' f'killpg() on {platform.system()}') return cls(None) root = base / f'fuse-tests-{tag}' try: root.mkdir(exist_ok=True) except OSError as exc: print(f'note: cannot create {root} ({exc}); containing tests with ' 'killpg() instead of cgroup.kill') return cls(None) return cls(root) @staticmethod def delegated_base() -> Path | None: """Parent of this process's own cgroup, if it is writable.""" if not IS_LINUX: return None try: for line in Path('/proc/self/cgroup').read_text().splitlines(): if not line.startswith('0::'): continue own = Path('/sys/fs/cgroup') / line[3:].lstrip('/') base = own.parent if os.access(base, os.W_OK): return base except OSError: pass return None def new_leaf(self) -> Path | None: """mkdir one leaf; None when disabled.""" if self.root is None: return None with self._lock: self._counter += 1 leaf = self.root / f'test-{self._counter}' try: leaf.mkdir(exist_ok=True) except OSError: return None return leaf def procs_path(self, leaf: Path | None) -> str: """leaf/cgroup.procs for the launcher to write itself into, or "". The runner never writes it: a process moving *itself* needs write access to the destination cgroup.procs alone, while moving another process also needs it on the common ancestor -- so the launcher works under strictly more delegation setups than the runner would. """ return '' if leaf is None else str(leaf / 'cgroup.procs') def kill_leaf(self, leaf: Path | None) -> None: """echo 1 > leaf/cgroup.kill, then rmdir. No-op when disabled.""" if leaf is None: return try: (leaf / 'cgroup.kill').write_text('1\n') except OSError: pass # The kill is asynchronous; a leaf with a process still in it cannot be # removed, so give it a moment rather than leaking the directory. for _ in range(50): try: leaf.rmdir() return except OSError: time.sleep(0.1) def cleanup(self) -> None: """Kill and remove every remaining leaf, then the root.""" if self.root is None: return for leaf in sorted(self.root.glob('test-*')): self.kill_leaf(leaf) try: self.root.rmdir() except OSError: pass REEXEC_SENTINEL = 'FUSE_TESTS_UNDER_SCOPE' # set on the re-exec'd child def reexec_under_user_scope_if_needed() -> None: """Re-exec under a systemd user scope so cgroup leaves have a writable parent. Returns unchanged when already delegated or when systemd-run is unavailable; replaces this process otherwise.""" if not IS_LINUX or os.environ.get(REEXEC_SENTINEL): return if CgroupManager.delegated_base() is not None: return systemd_run = shutil.which('systemd-run') if systemd_run is None: return os.environ[REEXEC_SENTINEL] = '1' argv = [systemd_run, '--user', '--scope', '--quiet', sys.executable, os.path.abspath(__file__)] + sys.argv[1:] try: os.execv(systemd_run, argv) except OSError: return def config_path() -> Path: """Path to the persisted runner config.""" return Path.home() / '.config' / 'libfuse' / 'tests.conf' def read_configured_base_dir() -> str | None: """Return the persisted base_dir, or None if unset or unreadable.""" import configparser parser = configparser.ConfigParser() try: parser.read(config_path()) except (OSError, configparser.Error): return None return parser.get(_CONFIG_SECTION, _CONFIG_BASE_DIR_KEY, fallback=None) def write_configured_base_dir(base_dir: str) -> None: """Persist base_dir, preserving any other keys already in the file.""" import configparser parser = configparser.ConfigParser() path = config_path() try: parser.read(path) except (OSError, configparser.Error): pass if not parser.has_section(_CONFIG_SECTION): parser.add_section(_CONFIG_SECTION) parser.set(_CONFIG_SECTION, _CONFIG_BASE_DIR_KEY, base_dir) path.parent.mkdir(parents=True, exist_ok=True) with path.open('w') as fh: parser.write(fh) def resolve_base_dir() -> Path: """The base a per-run leaf is appended to.""" return Path(read_configured_base_dir() or str(DEFAULT_BASE_DIR)) def resolve_run_dir(args: argparse.Namespace) -> Path: """Pick the run directory: --run-dir, $FUSE_TEST_RUN_DIR, config, default. --run-dir and $FUSE_TEST_RUN_DIR are used verbatim, because a caller that names a directory means that directory: CI has to hand the path to a later upload step, and `meson test` cannot pass arguments to a registered test, so the env var is the only channel it has. The persisted config value and DEFAULT_BASE_DIR are *bases*: a run--- leaf is appended so two runs on one machine -- or two users sharing /var/tmp -- cannot land in the same directory. """ if args.run_dir: return Path(args.run_dir) env_run_dir = os.environ.get('FUSE_TEST_RUN_DIR') if env_run_dir: return Path(env_run_dir) return resolve_base_dir() / run_leaf_name(args) def make_run_dir(run_dir: Path) -> bool: """mkdir the run directory, and say whether this call created it. Which matters at the end: a directory the runner made is its own to delete, one it merely found is not. """ try: run_dir.mkdir(parents=True) except FileExistsError: return False return True def resolve_valgrind() -> str: """The command prefix every daemon launch gets, or "" when off. Resolved once here and exported, so the policy lives in one place and no test re-implements the no/false/0 spellings. """ value = os.environ.get('TEST_WITH_VALGRIND', 'no').lower().strip() return '' if value in ('no', 'false', '0') else VALGRIND_PREFIX def run_leaf_name(args: argparse.Namespace) -> str: """The per-run leaf appended to a base directory. The timestamp is second-resolution, so the pid is what keeps two runs started in the same second apart: a shared leaf is a shared work directory, log and pid file for every test, and the first run to finish clean deletes them all. The io-uring invocation gets its own suffix, so which transport a kept directory holds is visible without opening it. A verbatim --run-dir stays verbatim; the caller chose that path. """ user = os.environ.get('USER') or os.environ.get('LOGNAME') or 'unknown' mode = '-iouring' if getattr(args, 'io_uring', False) else '' return f'run-{user}-{time.strftime("%y%m%d%H%M%S")}-{os.getpid()}{mode}' def as_test_name(pattern: str, cases_dir: Path) -> str: """A -t pattern as a discovery name, so shell completion can supply it: "test/cases/examples/cuse.sh" and "examples/cuse" name the same test. Resolved as a path rather than matched as text, against the cwd first so a completed path works from wherever it was completed, then against cases/ so a bare "examples" means the same thing from every directory. A directory selects what is under it. Anything that is not a path into cases/ is returned as given and stays an fnmatch pattern. """ for base in (Path.cwd(), cases_dir): resolved = (base / pattern).resolve() if not resolved.is_relative_to(cases_dir): continue rel = resolved.relative_to(cases_dir) if resolved.is_dir(): return str(rel / '*') return str(rel.with_suffix('')) if rel.suffix == '.sh' else str(rel) return pattern def is_shell_exception_dir(directory: Path) -> bool: """True when the cases/**/*.sh rule does not apply inside *directory*. The runner decides what a file is by where it sits, so the exceptions are listed once here. Today every one of them holds binary markers. """ return directory.name in ('unit',) def shell_scripts(cases_dir: Path) -> list: """Executable cases/**/*.sh, outside cases/lib and the shell-exception directories.""" return [path for path in cases_dir.rglob('*.sh') if LIB_DIR not in path.parents and not is_shell_exception_dir(path.parent) and os.access(path, os.X_OK)] def binary_markers(cases_dir: Path) -> list: """

    / -- one marker per C test that needs no script. A binary name has no suffix, so a suffixed entry is malformed and is said so rather than skipped. Only .md is allowed, for documentation. """ markers = [] for directory in sorted(cases_dir.iterdir()): if not directory.is_dir() or not is_shell_exception_dir(directory): continue for path in sorted(directory.iterdir()): if path.name.startswith('.') or path.suffix == '.md': continue if not path.is_file() or path.suffix: sys.exit(f'{path}: not a binary name; ' f'{directory} holds markers only') markers.append(path) return markers def discover(cases_dir: Path, patterns: list, groups: set, exclude: set) -> list: """Executable cases/**/*.sh plus the binary markers, filtered by fnmatch patterns, GROUP membership, and the exclude set (CLI -X plus test/exclude).""" patterns = [as_test_name(p, cases_dir) for p in patterns] names, specs = [], [] for script in sorted([*shell_scripts(cases_dir), *binary_markers(cases_dir)]): spec = parse_spec(script, cases_dir) names.append(spec.name) if spec.name in exclude: continue if patterns and not any(fnmatch.fnmatch(spec.name, p) for p in patterns): continue if groups and not (groups & spec.groups): continue specs.append(spec) # Checked against every name rather than against the selection, so that -g # or -X narrowing the result to nothing is not reported as a bad pattern. for pattern in patterns: if not any(fnmatch.fnmatch(name, pattern) for name in names): sys.exit(f'{pattern}: matches no test') return specs class TestRunner: """Runs TestSpecs, one worker thread each, and reports.""" def __init__(self, build_dir: Path, run_dir: Path, run_dir_created: bool, jobs: int, keep_logs: bool, verbose: bool, io_uring: bool = False, io_uring_depth: int | None = None): self.build_dir = build_dir self.run_dir = run_dir self.run_dir_created = run_dir_created self.jobs = jobs self.keep_logs = keep_logs self.verbose = verbose self.io_uring = io_uring self.io_uring_depth = io_uring_depth self.valgrind = resolve_valgrind() self.core_pattern = read_core_pattern() self.fuse_caps = self.read_fuse_caps() self.sync_init = self.read_sync_init() self._cgroup = CgroupManager.create(str(os.getpid())) self._stop = threading.Event() self._print_lock = threading.Lock() self._gdb = shutil.which('gdb') # Overwritten per run_all() call; set here so run_one() always has a # reference even if it is ever driven without run_all(). self._run_started = time.monotonic() self.report_environment() # ---------------------------------------------------------------- startup def build_path(self, base: str | None = None) -> str: """$PATH with the build tree's util/ and example/ ahead of *base*. util/ first for anything that spawns the mount helper by name: an installed one older than the build tree makes printcap emit "unrecognized option '--sync-init'", and a tree whose helper is not installed system-wide at all would find no helper whatsoever. """ if base is None: base = os.environ.get('PATH', '') return os.pathsep.join([str(self.build_dir / 'util'), str(self.build_dir / 'example'), base]) def read_fuse_caps(self) -> frozenset: """The FUSE_CAP_* names printcap reports, read once per run. printcap lives in example/, not util/, so this works the same way on every platform. It mounts to negotiate, so it needs the same $PATH a test gets rather than the ambient one -- otherwise it reaches for a mount helper that this build may not have installed anywhere, and every _require_cap test silently skips. """ printcap = self.build_dir / 'example' / 'printcap' if not os.access(printcap, os.X_OK): print(f'note: {printcap} not built; no capability is available ' 'and every _require_cap test will skip') return frozenset() proc = subprocess.run([str(printcap)], capture_output=True, text=True, timeout=30, check=False, env=dict(os.environ, PATH=self.build_path())) if proc.returncode != 0: print(f'note: printcap failed ({proc.returncode}); ' 'every _require_cap test will skip') return frozenset() return frozenset(line.strip() for line in proc.stdout.splitlines() if line.startswith('\t')) def read_sync_init(self) -> str: """Which -Dsync-init the library was built with: auto, always, never. A property of the build, not of the run, so it is read where the io-uring preflight reads HAVE_URING rather than selected on the command line. """ try: config = (self.build_dir / 'fuse_config.h').read_text() except OSError: return 'unknown' for define, mode in ((SYNC_INIT_ENABLED, 'always'), (SYNC_INIT_DISABLED, 'never')): if define in config: return mode return 'auto' def preflight_io_uring(self) -> str: """Return "" when the io-uring transport can actually be exercised, else the reason the whole invocation skips with exit 77. Checked in this order, so the message names the first thing that is actually wrong. """ if not IS_LINUX: return f'fuse-io-uring is Linux-only, this is {platform.system()}' try: config = (self.build_dir / 'fuse_config.h').read_text() except OSError: return f'{self.build_dir}/fuse_config.h is unreadable' if 'HAVE_URING' not in config: return 'the library was built with -Denable-io-uring=false' if IO_URING_CAP in self.fuse_caps: return '' # printcap reports capable_ext, so the capability's absence *is* the # kernel's answer. The module parameter only tells the two reasons # apart. try: enabled = FUSE_URING_PARAM.read_text().strip() except OSError: return 'this kernel has no fuse io-uring support' if enabled in ('N', '0'): return ('io-uring is disabled in the fuse module\n' f' echo Y | sudo tee {FUSE_URING_PARAM}') return f'the kernel did not offer {IO_URING_CAP}' def report_environment(self) -> None: """Say what will silently degrade before any test runs.""" if self.core_pattern.startswith('|'): print('note: core_pattern is piped to systemd-coredump; cores ' 'will be fetched via coredumpctl. For in-workdir cores run:') print(' sudo sysctl -w kernel.core_pattern=core.%e.%p') if self._gdb is None: print('note: gdb not found; cores will be kept but not backtraced') # ------------------------------------------------------------ preparation def prepare(self, spec: TestSpec): """Create the workdir tree, build the env dict, allocate the cgroup leaf. Returns (workdir, env, leaf).""" workdir = self.run_dir / spec.name logs = workdir / 'logs' for sub in ('mnt', 'src', 'tmp', 'logs'): (workdir / sub).mkdir(parents=True, exist_ok=True) util_dir = self.build_dir / 'util' example_dir = self.build_dir / 'example' env = dict(os.environ) env.update({ 'TEST_NAME': spec.name, 'TEST_SCRIPT': str(spec.script), 'TEST_DIR': str(TEST_DIR), 'TEST_LIB': str(LIB_DIR), 'TEST_WORKDIR': str(workdir), 'TEST_MNT': str(workdir / 'mnt'), 'TEST_SRC': str(workdir / 'src'), 'TEST_TMP': str(workdir / 'tmp'), 'TEST_LOGDIR': str(logs), 'BUILD_DIR': str(self.build_dir), 'FUSE_EXAMPLE_DIR': str(example_dir), 'FUSE_TEST_BIN_DIR': str(self.build_dir / 'test'), 'FUSE_UTIL_DIR': str(util_dir), 'FUSE_CAPS': ' '.join(sorted(self.fuse_caps)), 'FUSE_UID': str(os.geteuid()), 'FUSE_OS': platform.system(), # Exported as 0 rather than left unset: fuse_session_new() reads it # from the environment, so a value in the developer's shell would # otherwise change what the default run tests without saying so. 'FUSE_URING_ENABLE': '1' if self.io_uring else '0', # Asked of every session, not only the ones a mount verb started, # so the transport a test never launched through the shell -- a # self-mounting C test, a daemon the script backgrounded itself -- # is on the record too. It lands in that daemon's log, because # none of them redirects fuse_log() anywhere else. 'FUSE_INIT_STATUS': '1', 'FUSE_VALGRIND': self.valgrind, }) if self.io_uring_depth is not None: env['FUSE_URING_QUEUE_DEPTH'] = str(self.io_uring_depth) env['PATH'] = self.build_path(env.get('PATH', '')) return workdir, env, self._cgroup.new_leaf() def child_argv(self, spec: TestSpec) -> list: """The command the launcher execs for *spec*. bash -e for a script: errexit is the runner's rule, not something 88 files have to remember. A marker names a binary, which the launcher execs itself; there is no shell in between to impose errexit on, and none is wanted -- the binary's exit status is already the verdict. """ if spec.binary: return [str(self.build_dir / 'test' / spec.binary)] return ['bash', '-e', str(spec.script)] def write_repro(self, spec: TestSpec, workdir: Path, env: dict) -> None: """Write logs/repro.sh: the env deltas, the cd, and the command. It execs what the launcher execs, so the reproducer cannot pass where the run failed. """ import shlex lines = ['#!/bin/sh', '# Re-run this one test by hand, with the environment the', '# runner built for it.', ''] for key, value in sorted(env.items()): if os.environ.get(key) == value and key != 'PATH': continue lines.append(f'export {key}={shlex.quote(value)}') lines += ['', f'cd {shlex.quote(str(workdir / "logs"))}', 'exec ' + shlex.join(self.child_argv(spec)), ''] repro = workdir / 'logs' / 'repro.sh' repro.write_text('\n'.join(lines)) repro.chmod(0o755) # -------------------------------------------------------------- execution def _stream(self, proc: subprocess.Popen, logs: Path, name: str, started: float) -> None: """Copy the script's merged output to logs/script.out until EOF, and a copy prefixed with elapsed time to logs/timestamps.out. A timed-out test's script.out has no way to tell "stalled right after the last line" from "was still grinding right up to the kill" -- the CI step that prints it afterwards timestamps when it printed, not when the test produced it. timestamps.out is named to pick up the same "*.out" glob so CI shows it for free. """ with (logs / 'script.out').open('wb') as out, \ (logs / 'timestamps.out').open('wb') as timestamps: for line in proc.stdout: out.write(line) out.flush() elapsed = time.monotonic() - started timestamps.write(f'+{elapsed:8.3f}s '.encode() + line) timestamps.flush() if self.verbose: text = line.decode('utf8', errors='replace').rstrip('\n') with self._print_lock: print(f'[{name}] {text}') proc.stdout.close() def _kill(self, proc: subprocess.Popen, leaf: Path | None) -> None: """Stop a timed-out or interrupted test: cgroup.kill on the leaf when there is one, else killpg() on the session the script leads.""" if leaf is not None: try: (leaf / 'cgroup.kill').write_text('1\n') return except OSError: pass for sig in (signal.SIGTERM, signal.SIGKILL): try: os.killpg(proc.pid, sig) except OSError: return try: proc.wait(timeout=5.0) return except subprocess.TimeoutExpired: continue def dump_stacks(self, proc: subprocess.Popen, leaf: Path | None, logs: Path) -> None: """On a timeout, before _kill() tears the containment down, write a snapshot of the whole process table, plus every thread's kernel stack and (when gdb is available) user backtrace for every process still in the containment. A thread blocked in an uninterruptible syscall never answers PTRACE_ATTACH, so the kernel stack is taken first -- it needs no attach and is often the only trace such a thread ever yields. The process table is taken before either, while nothing has stopped a thread yet. """ self._dump_process_table(logs) for pid in self._containment_pids(proc, leaf): self._dump_kernel_stacks(pid, logs) if self._gdb is not None: self._dump_gdb_backtrace(pid, logs) @staticmethod def _dump_process_table(logs: Path) -> None: """ps auxwww, so a hang that involves a process outside the test's own containment -- a daemon an earlier test leaked, say -- is still visible in the report. """ result = subprocess.run(['ps', 'auxwww'], capture_output=True, text=True, check=False) (logs / 'ps.txt').write_text(result.stdout + result.stderr) @staticmethod def _proc_identity(pid: int) -> str: """A " (): " header line for a dump. Which pid was the daemon and which the client blocked on it is the first question asked of a stack dump, and a bare pid answers it for nobody reading the report minutes or days later. """ try: comm = Path(f'/proc/{pid}/comm').read_text().strip() except OSError: comm = '?' try: raw = Path(f'/proc/{pid}/cmdline').read_bytes() cmdline = raw.decode('utf8', errors='replace').replace('\0', ' ') except OSError: cmdline = '' # An argument may hold a newline; a header that is not one line # breaks every reader that greps the dump for its pid. return f'=== pid {pid} ({comm}): {" ".join(cmdline.split())} ===' @staticmethod def _as_text(data) -> str: """TimeoutExpired carries its partial output undecoded even when the run was in text mode.""" if data is None: return '' return data if isinstance(data, str) \ else data.decode('utf8', errors='replace') @staticmethod def _uninterruptible_tids(pid: int) -> list: """Threads of *pid* in uninterruptible sleep, D in /proc. Such a thread never answers PTRACE_ATTACH, so gdb waits on it until GDB_TIMEOUT kills it. That is per pid, and a wedged filesystem leaves several -- the client blocked on it and the daemon's own threads -- so the dump can outlast the timeout that asked for it by minutes. """ wedged = [] try: tids = sorted(int(tid) for tid in os.listdir(f'/proc/{pid}/task')) except OSError: return wedged for tid in tids: try: status = Path(f'/proc/{pid}/task/{tid}/status').read_text() except OSError: continue # exited between listdir() and here for line in status.splitlines(): if line.startswith('State:'): if line.split()[1] == 'D': wedged.append(tid) break return wedged @staticmethod def _containment_pids(proc: subprocess.Popen, leaf: Path | None) -> list: """Every pid sharing the test's cgroup leaf, or just proc.pid when cgroups are disabled.""" if leaf is not None: try: pids = [int(line) for line in (leaf / 'cgroup.procs').read_text().split()] if pids: return pids except OSError: pass return [proc.pid] @staticmethod def _dump_kernel_stacks(pid: int, logs: Path) -> None: """sudo cat /proc//task/*/stack for every thread of *pid*. /proc//task//stack is gated on CAP_SYS_ADMIN unconditionally -- unlike ptrace, ownership and Yama's exceptions are not enough -- to keep it from leaking kernel addresses. sudo is what gets it on a non-root run; -n so a runner without passwordless sudo fails the read immediately instead of blocking on a password prompt nothing answers. """ task_dir = Path(f'/proc/{pid}/task') try: tids = sorted(int(tid) for tid in os.listdir(task_dir)) except OSError: return lines = [TestRunner._proc_identity(pid)] for tid in tids: stack_path = task_dir / str(tid) / 'stack' result = subprocess.run(['sudo', '-n', 'cat', str(stack_path)], capture_output=True, text=True, check=False) stack = result.stdout if result.returncode == 0 else \ f'(unreadable: {result.stderr.strip() or result.returncode})\n' lines.append(f'=== tid {tid} ===\n{stack}') (logs / f'kstack.{pid}.txt').write_text('\n'.join(lines)) def _dump_gdb_backtrace(self, pid: int, logs: Path) -> None: """sudo gdb -p backtraces, written beside the kernel stacks. Bare "bt" for every thread first and "bt full" only after it: the locals are worth having, but they bury the frame list they belong to under pages of struct dumps, and the frame list is what is read first. sudo, not a Yama prctl exception: the wedged pid is as likely to be a daemon the test forked after launch as the test's own exec-chain, and an exception only covers the specific task that calls it, not children it forks afterwards. Root's CAP_SYS_PTRACE reaches either one uniformly. Best-effort: a thread ptrace cannot stop, or a runner without passwordless sudo, just leaves gdb's or sudo's own error text in the file. Skipped entirely where a thread is already in uninterruptible sleep: the attach cannot complete, so the whole GDB_TIMEOUT buys one line saying gdb was killed, and the kernel stack taken just before is what such a thread yields instead. """ wedged = self._uninterruptible_tids(pid) if wedged: tids = ' '.join(str(tid) for tid in wedged) (logs / f'gdbstack.{pid}.txt').write_text( f'{self._proc_identity(pid)}\n' f'(skipped: tid {tids} in uninterruptible sleep, so the ' f'attach cannot complete -- see kstack.{pid}.txt)\n') return argv = ['sudo', '-n', self._gdb, '--batch', '--nx', '-ex', 'set pagination off', '-ex', 'thread apply all bt', '-ex', 'set print pretty on', '-ex', 'thread apply all bt full', '-p', str(pid)] try: proc = subprocess.run(argv, capture_output=True, text=True, timeout=GDB_TIMEOUT, check=False) out = proc.stdout + proc.stderr except subprocess.TimeoutExpired as expired: # A pid gdb cannot finish with is the interesting one often # enough that whatever it did print has to be kept. out = (self._as_text(expired.stdout) + self._as_text(expired.stderr) + f'\n(gdb killed after {GDB_TIMEOUT:.0f}s)\n') (logs / f'gdbstack.{pid}.txt').write_text( f'{self._proc_identity(pid)}\n{out}') def _log_started(self, name: str) -> None: """A "test X is now running" line, timestamped against the whole run's own start rather than the test's -- so under -j the console log (which CI keeps regardless of pass/fail) shows what was in flight and since when, not only what has finished. """ elapsed = time.monotonic() - self._run_started with self._print_lock: print(f'+{elapsed:8.3f}s START {name}') sys.stdout.flush() def run_one(self, spec: TestSpec) -> TestResult: """Spawn the test, enforce spec.timeout, collect the result.""" workdir, env, leaf = self.prepare(spec) self.write_repro(spec, workdir, env) logs = workdir / 'logs' timeout = self.effective_timeout(spec) started = time.monotonic() self._log_started(spec.name) proc = subprocess.Popen( ['/bin/sh', '-c', LAUNCHER, 'run-tests', self._cgroup.procs_path(leaf), *self.child_argv(spec)], env=env, cwd=str(logs), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, start_new_session=True) # exec keeps the pid, so this is still the script and still the group # leader that "kill -- -$(cat pid)" targets. (workdir / 'pid').write_text(f'{proc.pid}\n') if leaf is not None: (workdir / 'cgroup').write_text(f'{leaf}\n') # _stream blocks until EOF, so read in a thread and wait with a # deadline here; that is what makes the timeout a hard wall-clock bound. reader = threading.Thread(target=self._stream, args=(proc, logs, spec.name, started), daemon=True) reader.start() reader.join(timeout=timeout) reason = '' if reader.is_alive(): reason = f'timeout after {timeout:.0f}s' self.dump_stacks(proc, leaf, logs) self._kill(proc, leaf) reader.join(timeout=5.0) try: proc.wait(timeout=REAP_TIMEOUT) except subprocess.TimeoutExpired: # Report it and carry on: the run is worth more than this one # process, and everything worth reading is already on disk. unkillable = f'unkillable after {REAP_TIMEOUT:.0f}s' reason = f'{reason}, {unkillable}' if reason else unkillable # Always reap the subtree: a passing script may still have leaked a # daemon, and that would wedge the next test on the same mountpoint. self._cgroup.kill_leaf(leaf) duration = time.monotonic() - started cores = self.collect_cores(workdir, leaf) suspicious = self.scan_logs(workdir) if proc.returncode == 0 else '' result = self.classify(spec, workdir, proc.returncode, duration, reason, cores, suspicious) (workdir / 'status').write_text( f'{result.status} {result.duration:.3f} {result.reason}\n'.rstrip() + '\n') return result def effective_timeout(self, spec: TestSpec) -> float: """The wall-clock bound actually enforced for *spec*.""" if self.valgrind: return spec.timeout * VALGRIND_TIMEOUT_FACTOR return spec.timeout def classify(self, spec: TestSpec, workdir: Path, code: int, duration: float, reason: str, cores: list, suspicious: str) -> TestResult: """Turn an exit status plus the collected evidence into a verdict.""" unexpected = [c for c in cores if not self.core_is_allowed(workdir, c)] transport = self.wrong_transport(workdir) if reason: # killed by the runner status = 'FAIL' elif code == SKIP_EXIT_CODE: status, reason = 'SKIP', self.skip_reason(workdir) elif code == LAUNCH_FAILED_EXIT_CODE and self.launch_failed(workdir): status, reason = 'FAIL', 'could not establish containment' elif code != 0: status = 'FAIL' reason = (f'killed by signal {-code}' if code < 0 else f'exit {code}') elif unexpected: core = unexpected[0] status = 'FAIL' reason = f'core: {core.executable} (pid {core.pid})' elif suspicious: status, reason = 'FAIL', f'suspicious output: {suspicious}' elif transport: status, reason = 'FAIL', transport else: status = 'PASS' return TestResult(name=spec.name, status=status, duration=duration, exit_code=code, reason=reason, workdir=workdir, cores=unexpected, suspicious=suspicious) @staticmethod def skip_reason(workdir: Path) -> str: """The reason _notrun printed, taken from the script's own output.""" try: text = (workdir / 'logs' / 'script.out').read_text(errors='replace') except OSError: return '' for line in reversed(text.splitlines()): if line.startswith('SKIP: '): return line[len('SKIP: '):] return '' def wrong_transport(self, workdir: Path) -> str: """Under --io-uring, the first session that did not get a ring, or "". A test that started no session reports nothing and so has nothing to prove. off:custom_io is the one refusal a daemon cannot avoid: the ring is issued against the session's own /dev/fuse fd, which a custom-io session does not have. timestamps.out holds the same lines behind an elapsed-time prefix, so matching on the start of the line reports each session once. """ if not self.io_uring: return '' for out in sorted((workdir / 'logs').glob('*.out')): try: text = out.read_text(errors='replace') except OSError: continue for line in text.splitlines(): if (line.startswith(IO_URING_STATE_KEY) and line not in IO_URING_STATES_OK): return f'{out.name}: {line}' return '' @staticmethod def launch_failed(workdir: Path) -> bool: """True when exit 125 came from the launcher, not from the test.""" try: text = (workdir / 'logs' / 'script.out').read_text(errors='replace') except OSError: return False return LAUNCH_FAILED_MARKER in text # ----------------------------------------------------------- log scanning def scan_logs(self, workdir: Path) -> str: """Strip logs/.allow patterns, then look for suspicious words in every logs/*.out. Returns the first offending line, or "".""" logs = workdir / 'logs' allow = [] try: for line in (logs / '.allow').read_text().splitlines(): if line.strip(): allow.append(re.compile(line, re.MULTILINE)) except OSError: pass words = [re.compile(r'\b{}\b'.format(w), re.IGNORECASE | re.MULTILINE) for w in self.suspicious_words()] for out in sorted(logs.glob('*.out')): try: buf = out.read_text(errors='replace') except OSError: continue for pattern in allow: buf = pattern.sub('', buf) buf = _FUSE_DEBUG_RE.sub('', buf) buf = self.strip_extra(buf) for word in words: hit = word.search(buf) if hit: line_start = buf.rfind('\n', 0, hit.start()) + 1 line_end = buf.find('\n', hit.end()) if line_end == -1: line_end = len(buf) return f'{out.name}: {buf[line_start:line_end].strip()}' return '' def suspicious_words(self) -> tuple: """The word list scan_logs() looks for. Under --io-uring it gains the message libfuse prints before falling back to /dev/fuse. The status file keeps only the last session of a binary that runs several, so the log stays the backstop for the earlier ones. """ if self.io_uring: return SUSPICIOUS_WORDS + (re.escape(IO_URING_FALLBACK),) return SUSPICIOUS_WORDS def strip_extra(self, buf: str) -> str: """Drop the noise a mode adds to every daemon's log. Valgrind's own lines go before the word scan. Built in rather than a per-test fuse_allow_output, because it applies to every test whenever valgrind is on. """ if self.valgrind: return _VALGRIND_LINE_RE.sub('', buf) return buf # ---------------------------------------------------------- core handling @staticmethod def core_is_allowed(workdir: Path, core: CoreDump) -> bool: """True when the test declared a core from this executable expected.""" try: names = (workdir / 'logs' / '.allow-core').read_text().split() except OSError: return False return core.executable in names def resolve_binary(self, executable: str) -> Path | None: """Map a core's %e back to the build-tree binary that produced it. %e is a bare basename, so search the three directories the suite runs binaries from. An unrecognised name (a system tool, or %e truncated at 16 chars) yields None; gdb still produces a usable backtrace from the core alone, just without symbol names for the main executable. """ for directory in (self.build_dir / 'example', self.build_dir / 'test', self.build_dir / 'util'): candidate = directory / executable if candidate.is_file(): return candidate return None def collect_cores(self, workdir: Path, leaf: Path | None) -> list: """Every core matching CORE_GLOBS in logs/, backtraced. When core_pattern is a pipe, nothing lands in logs/ at all. The fallback then asks the journal for cores recorded against *this test's* cgroup -- COREDUMP_CGROUP, which is exactly the leaf written to $TEST_WORKDIR/cgroup. A time-window query is deliberately not used: under -j the test intervals overlap, so one crash would be handed to every worker whose window contains it and fail unrelated tests. With no leaf to match on -- cgroups disabled, or not Linux -- the fallback yields nothing and the startup note is the only signal. CI sets a relative pattern on both platforms, so this costs no CI coverage. """ logs = workdir / 'logs' found = [] for glob in CORE_GLOBS: for path in sorted(logs.glob(glob)): found.append(self._core_from_name(path)) if not found and self.core_pattern.startswith('|'): found = self._cores_from_journal(logs, leaf) for core in found: core.binary = self.resolve_binary(core.executable) self.backtrace(core) return found @staticmethod def _core_from_name(path: Path) -> CoreDump: """Parse a core file name into the %e and %p the pattern encoded. core.. is what CI configures and .core is FreeBSD's default, but a developer machine often has a bare "core" or "core." pattern, which names no executable at all. Every shape still yields a CoreDump -- the executable is only used to find symbols for gdb. """ parts = path.name.split('.') if parts[0] == 'core': if len(parts) >= 3 and parts[-1].isdigit(): return CoreDump(path=path, executable='.'.join(parts[1:-1]), pid=int(parts[-1])) if len(parts) == 2 and parts[1].isdigit(): return CoreDump(path=path, executable='unknown', pid=int(parts[1])) if len(parts) == 1: return CoreDump(path=path, executable='unknown', pid=0) if path.name.endswith('.core'): return CoreDump(path=path, executable=path.name[:-len('.core')], pid=0) return CoreDump(path=path, executable=path.name, pid=0) def _cores_from_journal(self, logs: Path, leaf: Path | None) -> list: """Cores systemd-coredump captured for this test's cgroup.""" if leaf is None or not IS_LINUX or shutil.which('coredumpctl') is None: return [] import json proc = subprocess.run( ['journalctl', '-t', 'systemd-coredump', f'COREDUMP_CGROUP={self._cgroup_relative(leaf)}', '-o', 'json'], capture_output=True, text=True, check=False) cores = [] for line in proc.stdout.splitlines(): try: entry = json.loads(line) except ValueError: continue pid = int(entry.get('COREDUMP_PID', 0)) exe = os.path.basename(entry.get('COREDUMP_COMM', '') or '') if not pid: continue path = logs / f'core.{exe}.{pid}' dumped = subprocess.run( ['coredumpctl', 'dump', str(pid), '--output', str(path)], capture_output=True, check=False) if dumped.returncode == 0 and path.exists(): cores.append(CoreDump(path=path, executable=exe, pid=pid)) return cores @staticmethod def _cgroup_relative(leaf: Path) -> str: """The leaf path as the journal records it (without the mount point).""" return '/' + str(leaf.relative_to('/sys/fs/cgroup')) def backtrace(self, core: CoreDump) -> None: """Run gdb on *core*, write the full backtrace beside it as backtrace...txt, and keep the top frames for the summary. "thread apply all bt full" rather than a plain bt: a FUSE daemon is multi-threaded and the crashing thread is rarely the only interesting one. --nx so a developer's ~/.gdbinit cannot change the output. """ if self._gdb is None: return argv = [self._gdb, '--batch', '--nx', '-ex', 'set pagination off', '-ex', 'set print pretty on', '-ex', 'thread apply all bt full'] argv += ['--', str(core.binary)] if core.binary else [] argv += [str(core.path)] try: proc = subprocess.run(argv, capture_output=True, text=True, timeout=GDB_TIMEOUT, check=False) except subprocess.TimeoutExpired: return out = core.path.parent / f'backtrace.{core.executable}.{core.pid}.txt' out.write_text(proc.stdout + proc.stderr) core.backtrace = out frames = [line for line in proc.stdout.splitlines() if line.startswith('#')] core.top_frames = '\n'.join(frames[:GDB_TOP_FRAMES]) if len(frames) > GDB_TOP_FRAMES: core.top_frames += (f'\n ... {len(frames) - GDB_TOP_FRAMES} ' f'more frames, full: {out}') # ------------------------------------------------------------- scheduling def run_all(self, specs: list) -> int: """Run the serial group first with one job, then fan the rest out. Returns 0 when nothing failed.""" self._run_started = time.monotonic() serial = [s for s in specs if SERIAL_GROUP in s.groups] parallel = [s for s in specs if SERIAL_GROUP not in s.groups] results = self._run_batch(serial, 1) + \ self._run_batch(parallel, self.jobs) return self.summarise(results, time.monotonic() - self._run_started) def _run_batch(self, specs: list, jobs: int) -> list: """ThreadPoolExecutor over specs; print a live line per finished test.""" results = [] if not specs: return results # as_completed() rather than map(): map yields in submission order, so # a finished test would be reported -- and its workdir freed -- only # once every test submitted before it has landed. with ThreadPoolExecutor(max_workers=jobs) as pool: futures = [pool.submit(self._run_guarded, spec) for spec in specs] for future in as_completed(futures): result = future.result() if result is not None: results.append(result) self.report(result) self.discard_workdir(result) return results def _run_guarded(self, spec: TestSpec): """run_one(), unless SIGINT already asked the run to stop.""" if self._stop.is_set(): return None return self.run_one(spec) def report(self, result: TestResult) -> None: """One line per finished test, plus where to look when it failed.""" elapsed = time.monotonic() - self._run_started with self._print_lock: line = (f'+{elapsed:8.3f}s {result.status:<5} {result.name:<50} ' f'{result.duration:6.2f}s') if result.reason: line += f' {result.reason}' print(line) if result.status == 'FAIL': print(f' logs: {result.workdir / "logs"}') sys.stdout.flush() def discard_workdir(self, result: TestResult) -> None: """Drop a finished test's directory unless it failed. Only a failure is ever read, and deleting as each test lands keeps the run's disk use flat instead of holding all of them to the end. """ if self.keep_logs or result.status == 'FAIL': return shutil.rmtree(result.workdir, ignore_errors=True) def discard_run_dir(self, results: list) -> None: """Drop the run directory after a clean run, but only what this run made. --run-dir is used verbatim, so it can name a directory that was already there holding anything at all; rmtree on that is data loss, not cleanup. discard_workdir() has taken each test's own directory by now, so all that is left of this run are the empty parents the test names needed. """ if self.run_dir_created: shutil.rmtree(self.run_dir, ignore_errors=True) return for result in results: directory = result.workdir.parent while directory != self.run_dir: try: directory.rmdir() # empty only; never recursive except OSError: break directory = directory.parent def mode_note(self) -> str: """Extra text for the summary header naming a non-default mode. The io-uring invocation selects nothing, so its counts must match the default run's; without the label the two are indistinguishable in a CI log. A -Dsync-init build is invisible for the same reason. """ note = ', io-uring' if self.io_uring else '' if self.sync_init != 'auto': note += f', sync-init={self.sync_init}' return note def summarise(self, results: list, elapsed: float) -> int: """Print the counts, the slowest tests and every failure.""" passed = [r for r in results if r.status == 'PASS'] failed = [r for r in results if r.status == 'FAIL'] skipped = [r for r in results if r.status == 'SKIP'] print() print(f'{len(results)} tests: {len(passed)} passed, {len(failed)} ' f'failed, {len(skipped)} skipped in {elapsed:.1f}s ' f'(-j{self.jobs}{self.mode_note()})') slowest = sorted(results, key=lambda r: r.duration, reverse=True)[:5] if slowest: print() print('slowest:') for result in slowest: print(f' {result.duration:5.1f}s {result.name}') if failed: print() print('failed:') for result in failed: print(f' {result.name} {result.reason}') print(f' logs: {result.workdir / "logs" / "script.out"}') for core in result.cores: if core.top_frames: for frame in core.top_frames.splitlines(): print(f' {frame}') elif core.backtrace is None: print(f' core kept, not backtraced: {core.path}') print(f' repro: sh {result.workdir / "logs" / "repro.sh"}') if not failed and not self.keep_logs: self.discard_run_dir(results) else: print() print(f'test output kept in {self.run_dir}') return 1 if failed else 0 def stop(self) -> None: """Ask the workers to stop launching new tests.""" self._stop.set() def stopping(self) -> bool: """True once stop() has been asked for.""" return self._stop.is_set() def cleanup(self) -> None: self._cgroup.cleanup() def read_exclude_file() -> set: """One test name per line; blank lines and #-comments ignored, missing file is fine.""" try: text = EXCLUDE_FILE.read_text() except OSError: return set() names = set() for line in text.splitlines(): line = line.split('#', 1)[0].strip() if line: names.add(line) return names def parse_args(argv: list) -> argparse.Namespace: parser = argparse.ArgumentParser( description='Run the libfuse shell test suite.') parser.add_argument('-j', '--jobs', type=int, default=max(1, (os.cpu_count() or 2) // 2), help='parallel tests (default: cpu_count // 2)') parser.add_argument('-t', '--test', action='append', default=[], metavar='PATTERN', help='fnmatch against the test name, or the path to ' 'a case; repeatable') parser.add_argument('-g', '--group', action='append', default=[], help='only tests declaring "# GROUP: "') parser.add_argument('-X', '--exclude', action='append', default=[], metavar='NAME', help='skip this test; repeatable, adds to test/exclude') parser.add_argument('--build-dir', default='.', help='meson build root (default: .)') parser.add_argument('--setuid-helpers', action='store_true', help="chown root:root + chmod 4755 the build tree's " 'fusermount3 (needs sudo); without it an ' 'unprivileged run skips every mounting test') parser.add_argument('--run-dir', default=None, help='where to write per-test output, verbatim') parser.add_argument('--persist-base-dir', default=None, metavar='DIR', help='write DIR to ~/.config/libfuse/tests.conf ' 'and exit') parser.add_argument('--print-base-dir', action='store_true', help='print the resolved base directory and exit') parser.add_argument('--timeout', type=float, default=None, metavar='SECS', help="override every script's timeout") parser.add_argument('--io-uring', action='store_true', help='run every test over fuse-io-uring; exits 77 ' 'when the kernel or the build does not offer it') parser.add_argument('--io-uring-queue-depth', type=int, default=None, metavar='N', help="export FUSE_URING_QUEUE_DEPTH; default is " "libfuse's 8") parser.add_argument('-l', '--list', action='store_true', help='print the selected tests and exit') parser.add_argument('-v', '--verbose', action='store_true', help="stream each script's output live") parser.add_argument('--keep-logs', action='store_true', help="keep every test's output, not just the failures'") parser.add_argument('--repeat', type=int, default=1, metavar='N', help='run the selection N times') return parser.parse_args(argv) def main(argv: list) -> int: args = parse_args(argv) if args.persist_base_dir: write_configured_base_dir(args.persist_base_dir) return 0 if args.print_base_dir: print(resolve_base_dir()) return 0 build_dir = Path(args.build_dir).resolve() exclude = read_exclude_file() | set(args.exclude) if args.list: for spec in discover(CASES_DIR, args.test, set(args.group), exclude): print(spec.name) return 0 if args.setuid_helpers: setuid_helpers(build_dir) reexec_under_user_scope_if_needed() raise_nofile_limit() run_dir = resolve_run_dir(args) runner = TestRunner(build_dir=build_dir, run_dir=run_dir, run_dir_created=make_run_dir(run_dir), jobs=args.jobs, keep_logs=args.keep_logs, verbose=args.verbose, io_uring=args.io_uring, io_uring_depth=args.io_uring_queue_depth) if args.io_uring: # A missing precondition skips the whole invocation rather than # failing it, so a plain `meson test` on a machine that never enabled # the module parameter reports one SKIP instead of 88 failures. CI does # not rely on that: ci-build.sh enables the parameter itself. reason = runner.preflight_io_uring() if reason: print(f'SKIP: {reason}') runner.cleanup() return SKIP_EXIT_CODE # The capability says the kernel offers the transport, not that this # user may open a ring. Asked here rather than skipped on, because a # run that then fails every ring check is the honest report. refused = io_uring_setup_error() if refused: print(f'warning: io_uring_setup() failed with {refused}; the ' 'daemons will fall back to /dev/fuse') print(' sudo sysctl -w kernel.io_uring_disabled=0') specs = discover(CASES_DIR, args.test, set(args.group), exclude) if args.timeout is not None: specs = [replace(s, timeout=args.timeout) for s in specs] def on_signal(signum, frame): # The first one lets the tests already running finish, which is # usually what an interrupt means. Asking twice means the test in # flight is the problem, so take the containment down with us -- # otherwise the run sits out its full timeout before it can react. if runner.stopping(): print('\ninterrupted again: killing the tests still running') runner.cleanup() os._exit(128 + signum) print('\ninterrupted: waiting for the running tests to finish') runner.stop() signal.signal(signal.SIGINT, on_signal) signal.signal(signal.SIGTERM, on_signal) print(f'running {len(specs)} tests from {CASES_DIR} in {run_dir}') rc = 0 try: for _ in range(args.repeat): rc |= runner.run_all(specs) finally: runner.cleanup() return rc if __name__ == '__main__': sys.exit(main(sys.argv[1:])) fuse-3.18.3/test/stracedecode.c0000644000175000017500000001215115250106036015264 0ustar berndbernd#include #include #include "fuse_kernel.h" static struct { const char *name; } fuse_ll_ops[] = { [FUSE_LOOKUP] = { "LOOKUP" }, [FUSE_FORGET] = { "FORGET" }, [FUSE_GETATTR] = { "GETATTR" }, [FUSE_SETATTR] = { "SETATTR" }, [FUSE_READLINK] = { "READLINK" }, [FUSE_SYMLINK] = { "SYMLINK" }, [FUSE_MKNOD] = { "MKNOD" }, [FUSE_MKDIR] = { "MKDIR" }, [FUSE_UNLINK] = { "UNLINK" }, [FUSE_RMDIR] = { "RMDIR" }, [FUSE_RENAME] = { "RENAME" }, [FUSE_LINK] = { "LINK" }, [FUSE_OPEN] = { "OPEN" }, [FUSE_READ] = { "READ" }, [FUSE_WRITE] = { "WRITE" }, [FUSE_STATFS] = { "STATFS" }, [FUSE_RELEASE] = { "RELEASE" }, [FUSE_FSYNC] = { "FSYNC" }, [FUSE_SETXATTR] = { "SETXATTR" }, [FUSE_GETXATTR] = { "GETXATTR" }, [FUSE_LISTXATTR] = { "LISTXATTR" }, [FUSE_REMOVEXATTR] = { "REMOVEXATTR" }, [FUSE_FLUSH] = { "FLUSH" }, [FUSE_INIT] = { "INIT" }, [FUSE_OPENDIR] = { "OPENDIR" }, [FUSE_READDIR] = { "READDIR" }, [FUSE_RELEASEDIR] = { "RELEASEDIR" }, [FUSE_FSYNCDIR] = { "FSYNCDIR" }, [FUSE_GETLK] = { "GETLK" }, [FUSE_SETLK] = { "SETLK" }, [FUSE_SETLKW] = { "SETLKW" }, [FUSE_ACCESS] = { "ACCESS" }, [FUSE_CREATE] = { "CREATE" }, [FUSE_TMPFILE] = { "TMPFILE" }, [FUSE_INTERRUPT] = { "INTERRUPT" }, [FUSE_BMAP] = { "BMAP" }, [FUSE_DESTROY] = { "DESTROY" }, [FUSE_READDIRPLUS] = { "READDIRPLUS" }, }; #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) static const char *opname(enum fuse_opcode opcode) { if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) return "???"; else return fuse_ll_ops[opcode].name; } static void process_buf(int dir, char *buf, int len) { static unsigned long long prevuniq = -1; static int prevopcode; if (!dir) { struct fuse_in_header *in = (struct fuse_in_header *) buf; buf += sizeof(struct fuse_in_header); printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n", (unsigned long long) in->unique, opname((enum fuse_opcode) in->opcode), in->opcode, (unsigned long) in->nodeid, in->len, len); switch (in->opcode) { case FUSE_READ: { struct fuse_read_in *arg = (struct fuse_read_in *) buf; printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n", arg->fh, arg->offset, arg->size, arg->read_flags, arg->lock_owner, arg->flags); break; } case FUSE_WRITE: { struct fuse_write_in *arg = (struct fuse_write_in *) buf; printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n", arg->fh, arg->offset, arg->size, arg->write_flags, arg->lock_owner, arg->flags); break; } } prevuniq = in->unique; prevopcode = in->opcode; } else { struct fuse_out_header *out = (struct fuse_out_header *) buf; buf += sizeof(struct fuse_out_header); printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n", (unsigned long long) out->unique, out->error, strerror(-out->error), out->len, len); if (out->unique == prevuniq) { switch (prevopcode) { case FUSE_GETATTR: { struct fuse_attr_out *arg = (struct fuse_attr_out *) buf; printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n", arg->attr_valid, arg->attr_valid_nsec, arg->attr.ino, arg->attr.size, arg->attr.blocks); break; } case FUSE_LOOKUP: { struct fuse_entry_out *arg = (struct fuse_entry_out *) buf; printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n", arg->nodeid, arg->attr_valid, arg->attr_valid_nsec, arg->attr.ino, arg->attr.size, arg->attr.blocks); break; } } } } } int main(void) { FILE *in = stdin; while (1) { int dir; int res; char buf[1048576]; unsigned len = 0; memset(buf, 0, sizeof(buf)); while (1) { char str[32]; res = fscanf(in, "%30s", str); if (res != 1 && feof(in)) return 0; if (res == 0) continue; if (strncmp(str, "read(", 5) == 0) { dir = 0; break; } else if (strncmp(str, "writev(", 7) == 0) { dir = 1; break; } } while (1) { int c = getc(in); if (c == '"') { while (1) { int val; c = getc(in); if (c == EOF) { fprintf(stderr, "eof in string\n"); break; } if (c == '\n') { fprintf(stderr, "eol in string\n"); break; } if (c == '"') break; if (c != '\\') { val = c; } else { c = getc(in); switch (c) { case 'n': val = '\n'; break; case 'r': val = '\r'; break; case 't': val = '\t'; break; case '"': val = '"'; break; case '\\': val = '\\'; break; case 'x': res = scanf("%x", &val); if (res != 1) { fprintf(stderr, "parse error\n"); continue; } break; default: fprintf(stderr, "unknown sequence: '\\%c'\n", c); continue; } } buf[len++] = val; } } if (c == '\n') break; } process_buf(dir, buf, len); memset(buf, 0, len); len = 0; } } fuse-3.18.3/test/test_abi.c0000644000175000017500000000053015250106036014427 0ustar berndbernd#define FUSE_USE_VERSION 30 #include "fuse.h" #include #include int main(void) { if (sizeof(struct fuse_file_info) != 64) { fprintf(stderr, "struct fuse_file_info size mismatch\n"); exit(1); } if (sizeof(struct fuse_conn_info) != 128) { fprintf(stderr, "struct fuse_conn_info size mismatch\n"); exit(1); } } fuse-3.18.3/test/test_api_30.c0000644000175000017500000001312515250106036014753 0ustar berndbernd/* * FUSE: Filesystem in Userspace * * Minimal low level filesystem built against the FUSE_USE_VERSION 30 API, * so that the old API keeps being compiled and exercised. * * This program can be distributed under the terms of the GNU GPLv2. * See the file GPL2.txt. */ #define FUSE_USE_VERSION 30 /* the high level header has to keep building at this version as well */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __linux__ #include #else #include #endif #define FILE_INO 2 static const char file_name[] = "hello"; static const char file_contents[] = "Hello World!\n"; static int tfs_stat(fuse_ino_t ino, struct stat *stbuf) { stbuf->st_ino = ino; switch (ino) { case FUSE_ROOT_ID: stbuf->st_mode = S_IFDIR | 0755; stbuf->st_nlink = 2; break; case FILE_INO: stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; stbuf->st_size = strlen(file_contents); break; default: return -1; } return 0; } static void tfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { struct fuse_entry_param e; if (parent != FUSE_ROOT_ID || strcmp(name, file_name) != 0) { fuse_reply_err(req, ENOENT); return; } memset(&e, 0, sizeof(e)); e.ino = FILE_INO; e.attr_timeout = 1.0; e.entry_timeout = 1.0; tfs_stat(e.ino, &e.attr); fuse_reply_entry(req, &e); } 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) == -1) fuse_reply_err(req, ENOENT); else fuse_reply_attr(req, &stbuf, 1.0); } 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 = realloc(b->p, b->size); assert(b->p != NULL); memset(&stbuf, 0, sizeof(stbuf)); stbuf.st_ino = ino; fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf, b->size); } static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, off_t off, size_t maxsize) { size_t offset = (size_t) off; if (off < 0 || offset >= bufsize) return fuse_reply_buf(req, NULL, 0); if (bufsize - offset < maxsize) maxsize = bufsize - offset; return fuse_reply_buf(req, buf + offset, maxsize); } static void tfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct dirbuf b; (void) fi; if (ino != FUSE_ROOT_ID) { fuse_reply_err(req, ENOTDIR); return; } memset(&b, 0, sizeof(b)); dirbuf_add(req, &b, ".", FUSE_ROOT_ID); dirbuf_add(req, &b, "..", FUSE_ROOT_ID); 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) { if (ino != FILE_INO) fuse_reply_err(req, EISDIR); else if ((fi->flags & O_ACCMODE) != O_RDONLY) fuse_reply_err(req, EACCES); else fuse_reply_open(req, fi); } 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, strlen(file_contents), off, size); } static const struct fuse_lowlevel_ops tfs_oper = { .lookup = tfs_lookup, .getattr = tfs_getattr, .readdir = tfs_readdir, .open = tfs_open, .read = tfs_read, }; static void *run_fs(void *data) { struct fuse_session *se = (struct fuse_session *)data; assert(fuse_session_loop(se) == 0); return NULL; } static void check_readdir(const char *mountpoint) { DIR *dir = opendir(mountpoint); const struct dirent *ent; int found = 0; assert(dir != NULL); while ((ent = readdir(dir)) != NULL) { if (strcmp(ent->d_name, file_name) == 0) found = 1; } assert(closedir(dir) == 0); assert(found == 1); } static void check_read(const char *mountpoint) { char path[PATH_MAX]; char buf[sizeof(file_contents)]; int fd; ssize_t len; assert(snprintf(path, PATH_MAX, "%s/%s", mountpoint, file_name) > 0); fd = open(path, O_RDONLY); if (fd == -1) { perror(path); assert(0); } len = read(fd, buf, sizeof(buf)); assert(len == (ssize_t) strlen(file_contents)); assert(memcmp(buf, file_contents, len) == 0); assert(close(fd) == 0); } int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts fuse_opts; pthread_t fs_thread; assert(fuse_parse_cmdline(&args, &fuse_opts) == 0); #ifndef __FreeBSD__ assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0); #endif se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); assert(se != NULL); assert(fuse_set_signal_handlers(se) == 0); assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0); assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0); check_readdir(fuse_opts.mountpoint); check_read(fuse_opts.mountpoint); /* * fuse_session_exit() does not interrupt read(), so nudge this thread * with the ignored signal to let the loop free its receive buffer. */ fuse_session_exit(se); assert(pthread_kill(fs_thread, SIGPIPE) == 0); assert(pthread_join(fs_thread, NULL) == 0); fuse_session_unmount(se); fuse_remove_signal_handlers(se); fuse_session_destroy(se); free(fuse_opts.mountpoint); fuse_opt_free_args(&args); printf("Test completed successfully.\n"); return 0; } fuse-3.18.3/test/test_setattr.c0000644000175000017500000001054615250106036015372 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ #define FUSE_USE_VERSION 30 /* Not really needed - just to test build with FUSE_USE_VERSION == 30 */ #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __linux__ #include #else #include #endif #define FILE_INO 2 #define FILE_NAME "truncate_me" static int got_fh; static mode_t file_mode = S_IFREG | 0644; 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 = file_mode; stbuf->st_nlink = 1; stbuf->st_size = 0; } 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; else goto err_out; 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_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, 5); } static void tfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { if (ino == FUSE_ROOT_ID) fuse_reply_err(req, EISDIR); else { assert(ino == FILE_INO); fi->fh = FILE_INO; fuse_reply_open(req, fi); } } static void tfs_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi) { if(ino != FILE_INO || !(to_set & FUSE_SET_ATTR_MODE)) { fuse_reply_err(req, EINVAL); return; } if(fi == NULL) fprintf(stderr, "setattr with fi == NULL\n"); else if (fi->fh != FILE_INO) fprintf(stderr, "setattr with wrong fi->fh\n"); else { fprintf(stderr, "setattr ok\n"); got_fh = 1; file_mode = attr->st_mode; } tfs_getattr(req, ino, fi); } static struct fuse_lowlevel_ops tfs_oper = { .lookup = tfs_lookup, .getattr = tfs_getattr, .open = tfs_open, .setattr = tfs_setattr, }; static void* run_fs(void *data) { struct fuse_session *se = (struct fuse_session*) data; assert(fuse_session_loop(se) == 0); return NULL; } static void test_fs(char *mountpoint) { char fname[PATH_MAX]; int fd; assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME, mountpoint) > 0); fd = open(fname, O_WRONLY); if (fd == -1) { perror(fname); assert(0); } assert(fchmod(fd, 0600) == 0); close(fd); } int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts fuse_opts; pthread_t fs_thread; assert(fuse_parse_cmdline(&args, &fuse_opts) == 0); #ifndef __FreeBSD__ assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0); #endif se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); assert (se != NULL); assert(fuse_set_signal_handlers(se) == 0); assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0); /* Start file-system thread */ assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0); /* Do test */ test_fs(fuse_opts.mountpoint); /* Stop file system */ assert(pthread_cancel(fs_thread) == 0); fuse_session_unmount(se); assert(got_fh == 1); fuse_remove_signal_handlers(se); fuse_session_destroy(se); printf("Test completed successfully.\n"); return 0; } /** * Local Variables: * mode: c * indent-tabs-mode: nil * c-basic-offset: 4 * End: */ fuse-3.18.3/test/test_signals.c0000644000175000017500000001121115250106036015332 0ustar berndbernd/* * FUSE: Filesystem in Userspace * Copyright (C) 2025 Bernd Schubert * * Test for signal handling in libfuse. * * This program can be distributed under the terms of the GNU LGPLv2. * See the file GPL2.txt */ #define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17) #include "fuse_config.h" #include "fuse_lowlevel.h" #include "fuse_i.h" #include #include #include #include #include #include #include #include #include #include static void test_ll_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) { (void)parent; (void)name; /* Simulate slow lookup to test signal interruption */ sleep(2); fuse_reply_err(req, ENOENT); } static void test_ll_getattr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { (void)ino; (void)fi; /* Simulate slow getattr to test signal interruption */ sleep(2); fuse_reply_err(req, ENOENT); } static const struct fuse_lowlevel_ops test_ll_ops = { .lookup = test_ll_lookup, .getattr = test_ll_getattr, }; static void *signal_sender_thread(void *arg) { (void)arg; usleep(2 * 1000 * 1000); /* Send SIGTERM to the process */ kill(getpid(), SIGTERM); return NULL; } static void fork_child(void) { struct fuse_args args = FUSE_ARGS_INIT(0, NULL); struct fuse_session *se; struct fuse_loop_config *loop_config; pthread_t sig_thread; char *mountpoint = NULL; int ret = -1; /* Add the program name to arg[0] */ if (fuse_opt_add_arg(&args, "test_signals")) { fprintf(stderr, "Failed to add argument\n"); goto out_free_mountpoint; } /* Add debug flag to see more output */ fuse_opt_add_arg(&args, "-d"); /* Create temporary mount point */ mountpoint = strdup("/tmp/fuse_test_XXXXXX"); if (!mountpoint || !mkdtemp(mountpoint)) { fprintf(stderr, "Failed to create temp dir\n"); goto out_free_args; } /* Create session */ se = fuse_session_new(&args, &test_ll_ops, sizeof(test_ll_ops), NULL); if (!se) { fprintf(stderr, "Failed to create FUSE session\n"); goto out_free_mountpoint; } /* Mount filesystem */ if (fuse_session_mount(se, mountpoint)) { fprintf(stderr, "Failed to mount FUSE filesystem\n"); goto out_destroy_session; } /* Create loop config */ loop_config = fuse_loop_cfg_create(); if (!loop_config) { fprintf(stderr, "Failed to create loop config\n"); goto out_unmount; } fuse_loop_cfg_set_clone_fd(loop_config, 0); fuse_loop_cfg_set_max_threads(loop_config, 2); /* Set up signal handlers */ if (fuse_set_signal_handlers(se)) { fprintf(stderr, "Failed to set up signal handlers\n"); goto out_destroy_config; } /* Create thread that will send signals */ if (pthread_create(&sig_thread, NULL, signal_sender_thread, NULL)) { fprintf(stderr, "Failed to create signal sender thread\n"); goto out_remove_handlers; } /* Enter FUSE loop */ ret = fuse_session_loop_mt_312(se, loop_config); printf("Debug: fuse_session_loop_mt_312 returned %d\n", ret); printf("Debug: session exited state: %d\n", fuse_session_exited(se)); printf("Debug: session status: %d\n", se->error); /* Check exit status before cleanup */ int clean_exit = (fuse_session_exited(se) && se->error == SIGTERM); /* Clean up */ pthread_join(sig_thread, NULL); fuse_remove_signal_handlers(se); fuse_session_unmount(se); fuse_session_destroy(se); fuse_loop_cfg_destroy(loop_config); rmdir(mountpoint); free(mountpoint); fuse_opt_free_args(&args); /* Use saved exit status */ if (clean_exit) { printf("Debug: Clean shutdown via SIGTERM\n"); exit(0); } printf("Debug: Exiting with status %d\n", ret != 0); exit(ret != 0); out_remove_handlers: fuse_remove_signal_handlers(se); out_destroy_config: fuse_loop_cfg_destroy(loop_config); out_unmount: fuse_session_unmount(se); out_destroy_session: fuse_session_destroy(se); out_free_mountpoint: rmdir(mountpoint); free(mountpoint); out_free_args: fuse_opt_free_args(&args); exit(1); } static void run_test_in_child(void) { pid_t child; int status; child = fork(); if (child == -1) { perror("fork"); exit(1); } if (child == 0) fork_child(); /* In parent process */ if (waitpid(child, &status, 0) == -1) { perror("waitpid"); exit(1); } /* Check if child exited due to SIGTERM - this is expected */ if (WIFSIGNALED(status) && WTERMSIG(status) == SIGTERM) { printf("Child process terminated by SIGTERM as expected\n"); exit(0); } /* For any other type of exit, maintain existing behavior */ exit(WIFEXITED(status) ? WEXITSTATUS(status) : 1); } int main(void) { printf("Testing SIGTERM handling in libfuse\n"); run_test_in_child(); printf("SIGTERM handling test passed\n"); return 0; } fuse-3.18.3/test/test_syscalls.c0000644000175000017500000012642115250106036015541 0ustar berndbernd#define _GNU_SOURCE #include "fuse_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef ALLPERMS # define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)/* 07777 */ #endif static const char *basepath; static const char *basepath_r; static char testfile[1024]; static char testfile2[1024]; static char testdir[1024]; static char testdir2[1024]; static char testsock[1024]; static char subfile[1280]; static char testfile_r[1024]; static char testfile2_r[1024]; static char testdir_r[1024]; static char testdir2_r[1024]; static char subfile_r[1280]; static char testname[256]; static char testdata[] = "abcdefghijklmnopqrstuvwxyz"; static char testdata2[] = "1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./"; static const char *testdir_files[] = { "f1", "f2", NULL}; static long seekdir_offsets[4]; static char zerodata[4096]; static int testdatalen = sizeof(testdata) - 1; static int testdata2len = sizeof(testdata2) - 1; static unsigned int testnum = 0; static unsigned int select_test = 0; static unsigned int skip_test = 0; static unsigned int unlinked_test = 0; #define MAX_ENTRIES 1024 #define MAX_TESTS 100 static struct test { int fd; struct stat stat; } tests[MAX_TESTS]; static void test_perror(const char *func, const char *msg) { fprintf(stderr, "%s %s() - %s: %s\n", testname, func, msg, strerror(errno)); } static void test_error(const char *func, const char *msg, ...) __attribute__ ((format (printf, 2, 3))); static void __start_test(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); static void test_error(const char *func, const char *msg, ...) { va_list ap; fprintf(stderr, "%s %s() - ", testname, func); va_start(ap, msg); vfprintf(stderr, msg, ap); va_end(ap); fprintf(stderr, "\n"); } static int is_dot_or_dotdot(const char *name) { return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')); } /* * Seconds since the first line this process printed. The origin is taken * lazily so it needs no init call and cannot precede the first test. */ static double test_elapsed(void) { static struct timespec start; struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); if (start.tv_sec == 0 && start.tv_nsec == 0) start = now; return (now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec) / 1e9; } static void success(void) { fprintf(stderr, "+%8.3fs %s OK\n", test_elapsed(), testname); } #define this_test (&tests[testnum-1]) #define next_test (&tests[testnum]) static void __start_test(const char *fmt, ...) { unsigned int n; va_list ap; n = sprintf(testname, "%3i [", testnum); va_start(ap, fmt); n += vsprintf(testname + n, fmt, ap); va_end(ap); sprintf(testname + n, "]"); // Use dedicated testfile per test sprintf(testfile, "%s/testfile.%d", basepath, testnum); sprintf(testfile_r, "%s/testfile.%d", basepath_r, testnum); if (testnum > MAX_TESTS) { fprintf(stderr, "%s - too many tests\n", testname); exit(1); } /* A test that never finishes prints nothing otherwise, leaving the log * ending at the last test that passed. stderr, so a SIGKILL cannot * swallow it. */ fprintf(stderr, "+%8.3fs %s START\n", test_elapsed(), testname); this_test->fd = -1; } #define start_test(msg, args...) { \ testnum++; \ if ((select_test && testnum != select_test) || \ (testnum == skip_test)) { \ return 0; \ } \ __start_test(msg, ##args); \ } #define PERROR(msg) test_perror(__FUNCTION__, msg) #define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static int st_check_size(struct stat *st, int len) { if (st->st_size != len) { ERROR("length %u instead of %u", (int) st->st_size, (int) len); return -1; } return 0; } static int check_size(const char *path, int len) { struct stat stbuf; int res = stat(path, &stbuf); if (res == -1) { PERROR("stat"); return -1; } return st_check_size(&stbuf, len); } static int check_testfile_size(const char *path, int len) { this_test->stat.st_size = len; return check_size(path, len); } static int st_check_type(struct stat *st, mode_t type) { if ((st->st_mode & S_IFMT) != type) { ERROR("type 0%o instead of 0%o", st->st_mode & S_IFMT, type); return -1; } return 0; } static int check_type(const char *path, mode_t type) { struct stat stbuf; int res = lstat(path, &stbuf); if (res == -1) { PERROR("lstat"); return -1; } return st_check_type(&stbuf, type); } static int st_check_mode(struct stat *st, mode_t mode) { if ((st->st_mode & ALLPERMS) != mode) { ERROR("mode 0%o instead of 0%o", st->st_mode & ALLPERMS, mode); return -1; } return 0; } static int check_mode(const char *path, mode_t mode) { struct stat stbuf; int res = lstat(path, &stbuf); if (res == -1) { PERROR("lstat"); return -1; } return st_check_mode(&stbuf, mode); } static int check_testfile_mode(const char *path, mode_t mode) { this_test->stat.st_mode &= ~ALLPERMS; this_test->stat.st_mode |= mode; return check_mode(path, mode); } static int check_times(const char *path, time_t atime, time_t mtime) { int err = 0; struct stat stbuf; int res = lstat(path, &stbuf); if (res == -1) { PERROR("lstat"); return -1; } if (stbuf.st_atime != atime) { ERROR("atime %li instead of %li", stbuf.st_atime, atime); err--; } if (stbuf.st_mtime != mtime) { ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); err--; } if (err) return -1; return 0; } #if 0 static int fcheck_times(int fd, time_t atime, time_t mtime) { int err = 0; struct stat stbuf; int res = fstat(fd, &stbuf); if (res == -1) { PERROR("fstat"); return -1; } if (stbuf.st_atime != atime) { ERROR("atime %li instead of %li", stbuf.st_atime, atime); err--; } if (stbuf.st_mtime != mtime) { ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); err--; } if (err) return -1; return 0; } #endif static int st_check_nlink(struct stat *st, nlink_t nlink) { if (st->st_nlink != nlink) { ERROR("nlink %li instead of %li", (long) st->st_nlink, (long) nlink); return -1; } return 0; } static int check_nlink(const char *path, nlink_t nlink) { struct stat stbuf; int res = lstat(path, &stbuf); if (res == -1) { PERROR("lstat"); return -1; } return st_check_nlink(&stbuf, nlink); } static int fcheck_stat(int fd, int flags, struct stat *st) { struct stat stbuf; int res = fstat(fd, &stbuf); if (res == -1) { if (flags & O_PATH) { // With O_PATH fd, the server does not have to keep // the inode alive so FUSE inode may be stale or bad if (errno == ESTALE || errno == EIO || errno == ENOENT || errno == EBADF) return 0; } PERROR("fstat"); return -1; } int err = 0; err += st_check_type(&stbuf, st->st_mode & S_IFMT); err += st_check_mode(&stbuf, st->st_mode & ALLPERMS); err += st_check_size(&stbuf, st->st_size); err += st_check_nlink(&stbuf, st->st_nlink); return err; } static int check_nonexist(const char *path) { struct stat stbuf; int res = lstat(path, &stbuf); if (res == 0) { ERROR("file should not exist"); return -1; } if (errno != ENOENT) { ERROR("file should not exist: %s", strerror(errno)); return -1; } return 0; } static int check_buffer(const char *buf, const char *data, unsigned len) { if (memcmp(buf, data, len) != 0) { ERROR("data mismatch"); return -1; } return 0; } static int check_data(const char *path, const char *data, int offset, unsigned len) { char buf[4096]; int res; int fd = open(path, O_RDONLY); if (fd == -1) { PERROR("open"); return -1; } if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { PERROR("lseek"); close(fd); return -1; } while (len) { int rdlen = len < sizeof(buf) ? len : sizeof(buf); res = read(fd, buf, rdlen); if (res == -1) { PERROR("read"); close(fd); return -1; } if (res != rdlen) { ERROR("short read: %u instead of %u", res, rdlen); close(fd); return -1; } if (check_buffer(buf, data, rdlen) != 0) { close(fd); return -1; } data += rdlen; len -= rdlen; } res = close(fd); if (res == -1) { PERROR("close"); return -1; } return 0; } static int fcheck_data(int fd, const char *data, int offset, unsigned len) { char buf[4096]; int res; if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { PERROR("lseek"); return -1; } while (len) { int rdlen = len < sizeof(buf) ? len : sizeof(buf); res = read(fd, buf, rdlen); if (res == -1) { PERROR("read"); return -1; } if (res != rdlen) { ERROR("short read: %u instead of %u", res, rdlen); return -1; } if (check_buffer(buf, data, rdlen) != 0) { return -1; } data += rdlen; len -= rdlen; } return 0; } static int check_dir_contents(const char *path, const char **contents) { int i; int res; int err = 0; int found[MAX_ENTRIES]; const char *cont[MAX_ENTRIES]; DIR *dp; for (i = 0; contents[i]; i++) { assert(i < MAX_ENTRIES - 3); found[i] = 0; cont[i] = contents[i]; } cont[i] = NULL; dp = opendir(path); if (dp == NULL) { PERROR("opendir"); return -1; } memset(found, 0, sizeof(found)); while(1) { struct dirent *de; errno = 0; de = readdir(dp); if (de == NULL) { if (errno) { PERROR("readdir"); closedir(dp); return -1; } break; } if (is_dot_or_dotdot(de->d_name)) continue; for (i = 0; cont[i] != NULL; i++) { assert(i < MAX_ENTRIES); if (strcmp(cont[i], de->d_name) == 0) { if (found[i]) { ERROR("duplicate entry <%s>", de->d_name); err--; } else found[i] = 1; break; } } if (!cont[i]) { ERROR("unexpected entry <%s>", de->d_name); err --; } } for (i = 0; cont[i] != NULL; i++) { if (!found[i]) { ERROR("missing entry <%s>", cont[i]); err--; } } res = closedir(dp); if (res == -1) { PERROR("closedir"); return -1; } if (err) return -1; return 0; } static int create_file(const char *path, const char *data, int len) { int res; int fd; unlink(path); fd = creat(path, 0644); if (fd == -1) { PERROR("creat"); return -1; } if (len) { res = write(fd, data, len); if (res == -1) { PERROR("write"); close(fd); return -1; } if (res != len) { ERROR("write is short: %u instead of %u", res, len); close(fd); return -1; } } res = close(fd); if (res == -1) { PERROR("close"); return -1; } res = check_type(path, S_IFREG); if (res == -1) return -1; res = check_mode(path, 0644); if (res == -1) return -1; res = check_nlink(path, 1); if (res == -1) return -1; res = check_size(path, len); if (res == -1) return -1; if (len) { res = check_data(path, data, 0, len); if (res == -1) return -1; } return 0; } static int create_path_fd(const char *path, const char *data, int len) { int path_fd; int res; res = create_file(path, data, len); if (res == -1) return -1; path_fd = open(path, O_PATH); if (path_fd == -1) PERROR("open(O_PATH)"); return path_fd; } // Can be called once per test static int create_testfile(const char *path, const char *data, int len) { struct test *t = this_test; struct stat *st = &t->stat; int res, fd; if (t->fd > 0) { ERROR("testfile already created"); return -1; } fd = create_path_fd(path, data, len); if (fd == -1) return -1; t->fd = fd; res = fstat(fd, st); if (res == -1) { PERROR("fstat"); return -1; } return 0; } static int check_unlinked_testfile(int fd) { struct stat *st = &this_test->stat; st->st_nlink = 0; return fcheck_stat(fd, O_PATH, st); } // Check recorded testfiles after all tests completed static int check_unlinked_testfiles(void) { int fd; int res, err = 0; int num = testnum; if (!unlinked_test) return 0; testnum = 0; while (testnum < num) { fd = next_test->fd; start_test("check_unlinked_testfile"); if (fd == -1) continue; err += check_unlinked_testfile(fd); res = close(fd); if (res == -1) { PERROR("close(test_fd)"); err--; } } if (err) { fprintf(stderr, "%i unlinked testfile checks failed\n", -err); return 1; } return err; } static int cleanup_dir(const char *path, const char **dir_files, int quiet) { int i; int err = 0; for (i = 0; dir_files[i]; i++) { int res; char fpath[1280]; sprintf(fpath, "%s/%s", path, dir_files[i]); res = unlink(fpath); if (res == -1 && !quiet) { PERROR("unlink"); err --; } } if (err) return -1; return 0; } static int create_dir(const char *path, const char **dir_files) { int res; int i; rmdir(path); res = mkdir(path, 0755); if (res == -1) { PERROR("mkdir"); return -1; } res = check_type(path, S_IFDIR); if (res == -1) return -1; res = check_mode(path, 0755); if (res == -1) return -1; for (i = 0; dir_files[i]; i++) { char fpath[1280]; sprintf(fpath, "%s/%s", path, dir_files[i]); res = create_file(fpath, "", 0); if (res == -1) { cleanup_dir(path, dir_files, 1); return -1; } } res = check_dir_contents(path, dir_files); if (res == -1) { cleanup_dir(path, dir_files, 1); return -1; } return 0; } static int test_truncate(int len) { const char *data = testdata; int datalen = testdatalen; int res; start_test("truncate(%u)", (int) len); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; res = truncate(testfile, len); if (res == -1) { PERROR("truncate"); return -1; } res = check_testfile_size(testfile, len); if (res == -1) return -1; if (len > 0) { if (len <= datalen) { res = check_data(testfile, data, 0, len); if (res == -1) return -1; } else { res = check_data(testfile, data, 0, datalen); if (res == -1) return -1; res = check_data(testfile, zerodata, datalen, len - datalen); if (res == -1) return -1; } } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; success(); return 0; } static int test_ftruncate(int len, int mode) { const char *data = testdata; int datalen = testdatalen; int res; int fd; start_test("ftruncate(%u) mode: 0%03o", len, mode); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; fd = open(testfile, O_WRONLY); if (fd == -1) { PERROR("open"); return -1; } res = fchmod(fd, mode); if (res == -1) { PERROR("fchmod"); close(fd); return -1; } res = check_testfile_mode(testfile, mode); if (res == -1) { close(fd); return -1; } res = ftruncate(fd, len); if (res == -1) { PERROR("ftruncate"); close(fd); return -1; } close(fd); res = check_testfile_size(testfile, len); if (res == -1) return -1; if (len > 0) { if (len <= datalen) { res = check_data(testfile, data, 0, len); if (res == -1) return -1; } else { res = check_data(testfile, data, 0, datalen); if (res == -1) return -1; res = check_data(testfile, zerodata, datalen, len - datalen); if (res == -1) return -1; } } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; success(); return 0; } static int test_seekdir(void) { int i; int res; DIR *dp; struct dirent *de = NULL; start_test("seekdir"); res = create_dir(testdir, testdir_files); if (res == -1) return res; dp = opendir(testdir); if (dp == NULL) { PERROR("opendir"); return -1; } /* Remember dir offsets */ for (i = 0; i < ARRAY_SIZE(seekdir_offsets); i++) { seekdir_offsets[i] = telldir(dp); errno = 0; de = readdir(dp); if (de == NULL) { if (errno) { PERROR("readdir"); goto fail; } break; } } /* Walk until the end of directory */ while (de) de = readdir(dp); /* Start from the last valid dir offset and seek backwards */ for (i--; i >= 0; i--) { seekdir(dp, seekdir_offsets[i]); de = readdir(dp); if (de == NULL) { ERROR("Unexpected end of directory after seekdir()"); goto fail; } } closedir(dp); res = cleanup_dir(testdir, testdir_files, 0); if (!res) success(); return res; fail: closedir(dp); cleanup_dir(testdir, testdir_files, 1); return -1; } #ifdef HAVE_COPY_FILE_RANGE static int test_copy_file_range(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; int fd_in, fd_out; off_t pos_in = 0, pos_out = 0; start_test("copy_file_range"); unlink(testfile); fd_in = open(testfile, O_CREAT | O_RDWR, 0644); if (fd_in == -1) { PERROR("creat"); return -1; } res = write(fd_in, data, datalen); if (res == -1) { PERROR("write"); close(fd_in); return -1; } if (res != datalen) { ERROR("write is short: %u instead of %u", res, datalen); close(fd_in); return -1; } unlink(testfile2); fd_out = creat(testfile2, 0644); if (fd_out == -1) { PERROR("creat"); close(fd_in); return -1; } res = copy_file_range(fd_in, &pos_in, fd_out, &pos_out, datalen, 0); if (res == -1) { PERROR("copy_file_range"); close(fd_in); close(fd_out); return -1; } if (res != datalen) { ERROR("copy is short: %u instead of %u", res, datalen); close(fd_in); close(fd_out); return -1; } res = close(fd_in); if (res == -1) { PERROR("close"); close(fd_out); return -1; } res = close(fd_out); if (res == -1) { PERROR("close"); return -1; } err = check_data(testfile2, data, 0, datalen); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; if (err) return -1; res = unlink(testfile2); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile2); if (res == -1) return -1; if (err) return -1; success(); return 0; } #else static int test_copy_file_range(void) { return 0; } #endif #ifdef HAVE_STATX static int test_statx(void) { struct statx sb; char msg[] = "hi"; size_t msg_size = sizeof(msg); struct timespec tp; int res; memset(&sb, 0, sizeof(sb)); unlink(testfile); start_test("statx"); res = create_testfile(testfile, msg, msg_size); if (res == -1) return -1; res = statx(-1, testfile, AT_EMPTY_PATH, STATX_BASIC_STATS | STATX_BTIME, &sb); if (res == -1) return -1; if (sb.stx_size != msg_size) return -1; clock_gettime(CLOCK_REALTIME, &tp); if (sb.stx_btime.tv_sec > tp.tv_sec) return -1; if (sb.stx_btime.tv_sec == tp.tv_sec && sb.stx_btime.tv_nsec >= tp.tv_nsec) return -1; unlink(testfile); success(); return 0; } #else static int test_statx(void) { return 0; } #endif static int test_utime(void) { struct utimbuf utm; time_t atime = 987631200; time_t mtime = 123116400; int res; start_test("utime"); res = create_testfile(testfile, NULL, 0); if (res == -1) return -1; utm.actime = atime; utm.modtime = mtime; res = utime(testfile, &utm); if (res == -1) { PERROR("utime"); return -1; } res = check_times(testfile, atime, mtime); if (res == -1) { return -1; } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; success(); return 0; } static int test_create(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; int fd; start_test("create"); unlink(testfile); fd = creat(testfile, 0644); if (fd == -1) { PERROR("creat"); return -1; } res = write(fd, data, datalen); if (res == -1) { PERROR("write"); close(fd); return -1; } if (res != datalen) { ERROR("write is short: %u instead of %u", res, datalen); close(fd); return -1; } res = close(fd); if (res == -1) { PERROR("close"); return -1; } res = check_type(testfile, S_IFREG); if (res == -1) return -1; err += check_mode(testfile, 0644); err += check_nlink(testfile, 1); err += check_size(testfile, datalen); err += check_data(testfile, data, 0, datalen); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_create_unlink(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; int fd; start_test("create+unlink"); unlink(testfile); fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644); if (fd == -1) { PERROR("creat"); return -1; } res = unlink(testfile); if (res == -1) { PERROR("unlink"); close(fd); return -1; } res = check_nonexist(testfile); if (res == -1) { close(fd); return -1; } res = write(fd, data, datalen); if (res == -1) { PERROR("write"); close(fd); return -1; } if (res != datalen) { ERROR("write is short: %u instead of %u", res, datalen); close(fd); return -1; } struct stat st = { .st_mode = S_IFREG | 0644, .st_size = datalen, }; err = fcheck_stat(fd, O_RDWR, &st); err += fcheck_data(fd, data, 0, datalen); res = close(fd); if (res == -1) { PERROR("close"); err--; } if (err) return -1; success(); return 0; } static int test_mknod(void) { int err = 0; int res; start_test("mknod"); unlink(testfile); res = mknod(testfile, 0644, 0); if (res == -1) { PERROR("mknod"); return -1; } res = check_type(testfile, S_IFREG); if (res == -1) return -1; err += check_mode(testfile, 0644); err += check_nlink(testfile, 1); err += check_size(testfile, 0); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; if (err) return -1; success(); return 0; } #define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode) static int do_test_open(int exist, int flags, const char *flags_str, int mode) { char buf[4096]; const char *data = testdata; int datalen = testdatalen; unsigned currlen = 0; int err = 0; int res; int fd; off_t off; start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode); unlink(testfile); if (exist) { res = create_file(testfile_r, testdata2, testdata2len); if (res == -1) return -1; currlen = testdata2len; } fd = open(testfile, flags, mode); if ((flags & O_CREAT) && (flags & O_EXCL) && exist) { if (fd != -1) { ERROR("open should have failed"); close(fd); return -1; } else if (errno == EEXIST) goto succ; } if (!(flags & O_CREAT) && !exist) { if (fd != -1) { ERROR("open should have failed"); close(fd); return -1; } else if (errno == ENOENT) goto succ; } if (fd == -1) { PERROR("open"); return -1; } if (flags & O_TRUNC) currlen = 0; err += check_type(testfile, S_IFREG); if (exist) err += check_mode(testfile, 0644); else err += check_mode(testfile, mode); err += check_nlink(testfile, 1); err += check_size(testfile, currlen); if (exist && !(flags & O_TRUNC) && (mode & S_IRUSR)) err += check_data(testfile, testdata2, 0, testdata2len); res = write(fd, data, datalen); if ((flags & O_ACCMODE) != O_RDONLY) { if (res == -1) { PERROR("write"); err --; } else if (res != datalen) { ERROR("write is short: %u instead of %u", res, datalen); err --; } else { if (datalen > (int) currlen) currlen = datalen; err += check_size(testfile, currlen); if (mode & S_IRUSR) { err += check_data(testfile, data, 0, datalen); if (exist && !(flags & O_TRUNC) && testdata2len > datalen) err += check_data(testfile, testdata2 + datalen, datalen, testdata2len - datalen); } } } else { if (res != -1) { ERROR("write should have failed"); err --; } else if (errno != EBADF) { PERROR("write"); err --; } } off = lseek(fd, SEEK_SET, 0); if (off == (off_t) -1) { PERROR("lseek"); err--; } else if (off != 0) { ERROR("offset should have returned 0"); err --; } res = read(fd, buf, sizeof(buf)); if ((flags & O_ACCMODE) != O_WRONLY) { if (res == -1) { PERROR("read"); err--; } else { int readsize = currlen < sizeof(buf) ? currlen : sizeof(buf); if (res != readsize) { ERROR("read is short: %i instead of %u", res, readsize); err--; } else { if ((flags & O_ACCMODE) != O_RDONLY) { err += check_buffer(buf, data, datalen); if (exist && !(flags & O_TRUNC) && testdata2len > datalen) err += check_buffer(buf + datalen, testdata2 + datalen, testdata2len - datalen); } else if (exist) err += check_buffer(buf, testdata2, testdata2len); } } } else { if (res != -1) { ERROR("read should have failed"); err --; } else if (errno != EBADF) { PERROR("read"); err --; } } res = close(fd); if (res == -1) { PERROR("close"); return -1; } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; res = check_nonexist(testfile_r); if (res == -1) return -1; if (err) return -1; succ: success(); return 0; } #define test_open_acc(flags, mode, err) \ do_test_open_acc(flags, #flags, mode, err) static int do_test_open_acc(int flags, const char *flags_str, int mode, int err) { const char *data = testdata; int datalen = testdatalen; int res; int fd; start_test("open_acc(%s) mode: 0%03o message: '%s'", flags_str, mode, strerror(err)); unlink(testfile); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; res = chmod(testfile, mode); if (res == -1) { PERROR("chmod"); return -1; } res = check_testfile_mode(testfile, mode); if (res == -1) return -1; fd = open(testfile, flags); if (fd == -1) { if (err != errno) { PERROR("open"); return -1; } } else { if (err) { ERROR("open should have failed"); close(fd); return -1; } close(fd); } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; res = check_nonexist(testfile_r); if (res == -1) return -1; success(); return 0; } static int test_symlink(void) { char buf[1024]; const char *data = testdata; int datalen = testdatalen; int linklen = strlen(testfile); int err = 0; int res; start_test("symlink"); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; unlink(testfile2); res = symlink(testfile, testfile2); if (res == -1) { PERROR("symlink"); return -1; } res = check_type(testfile2, S_IFLNK); if (res == -1) return -1; err += check_mode(testfile2, 0777); err += check_nlink(testfile2, 1); res = readlink(testfile2, buf, sizeof(buf)); if (res == -1) { PERROR("readlink"); err--; } if (res != linklen) { ERROR("short readlink: %u instead of %u", res, linklen); err--; } if (memcmp(buf, testfile, linklen) != 0) { ERROR("link mismatch"); err--; } err += check_size(testfile2, datalen); err += check_data(testfile2, data, 0, datalen); res = unlink(testfile2); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile2); if (res == -1) return -1; if (err) return -1; res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; success(); return 0; } static int test_link(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; start_test("link"); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; unlink(testfile2); res = link(testfile, testfile2); if (res == -1) { PERROR("link"); return -1; } res = check_type(testfile2, S_IFREG); if (res == -1) return -1; err += check_mode(testfile2, 0644); err += check_nlink(testfile2, 2); err += check_size(testfile2, datalen); err += check_data(testfile2, data, 0, datalen); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; err += check_nlink(testfile2, 1); res = unlink(testfile2); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile2); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_link2(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; start_test("link-unlink-link"); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; unlink(testfile2); res = link(testfile, testfile2); if (res == -1) { PERROR("link"); return -1; } res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; res = link(testfile2, testfile); if (res == -1) { PERROR("link"); } res = check_type(testfile, S_IFREG); if (res == -1) return -1; err += check_mode(testfile, 0644); err += check_nlink(testfile, 2); err += check_size(testfile, datalen); err += check_data(testfile, data, 0, datalen); res = unlink(testfile2); if (res == -1) { PERROR("unlink"); return -1; } err += check_nlink(testfile, 1); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_rename_file(void) { const char *data = testdata; int datalen = testdatalen; int err = 0; int res; start_test("rename file"); res = create_testfile(testfile, data, datalen); if (res == -1) return -1; unlink(testfile2); res = rename(testfile, testfile2); if (res == -1) { PERROR("rename"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; res = check_type(testfile2, S_IFREG); if (res == -1) return -1; err += check_mode(testfile2, 0644); err += check_nlink(testfile2, 1); err += check_size(testfile2, datalen); err += check_data(testfile2, data, 0, datalen); res = unlink(testfile2); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile2); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_rename_dir(void) { int err = 0; int res; start_test("rename dir"); res = create_dir(testdir, testdir_files); if (res == -1) return -1; rmdir(testdir2); res = rename(testdir, testdir2); if (res == -1) { PERROR("rename"); cleanup_dir(testdir, testdir_files, 1); return -1; } res = check_nonexist(testdir); if (res == -1) { cleanup_dir(testdir, testdir_files, 1); return -1; } res = check_type(testdir2, S_IFDIR); if (res == -1) { cleanup_dir(testdir2, testdir_files, 1); return -1; } err += check_mode(testdir2, 0755); err += check_dir_contents(testdir2, testdir_files); err += cleanup_dir(testdir2, testdir_files, 0); res = rmdir(testdir2); if (res == -1) { PERROR("rmdir"); return -1; } res = check_nonexist(testdir2); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_rename_dir_loop(void) { #define PATH(p) (snprintf(path, sizeof path, "%s/%s", testdir, p), path) #define PATH2(p) (snprintf(path2, sizeof path2, "%s/%s", testdir, p), path2) char path[1280], path2[1280]; int err = 0; int res; start_test("rename dir loop"); res = create_dir(testdir, testdir_files); if (res == -1) return -1; res = mkdir(PATH("a"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } res = rename(PATH("a"), PATH2("a")); if (res == -1) { PERROR("rename"); goto fail; } errno = 0; res = rename(PATH("a"), PATH2("a/b")); if (res == 0 || errno != EINVAL) { PERROR("rename"); goto fail; } res = mkdir(PATH("a/b"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } res = mkdir(PATH("a/b/c"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } errno = 0; res = rename(PATH("a"), PATH2("a/b/c")); if (res == 0 || errno != EINVAL) { PERROR("rename"); goto fail; } errno = 0; res = rename(PATH("a"), PATH2("a/b/c/a")); if (res == 0 || errno != EINVAL) { PERROR("rename"); goto fail; } errno = 0; res = rename(PATH("a/b/c"), PATH2("a")); if (res == 0 || errno != ENOTEMPTY) { PERROR("rename"); goto fail; } res = open(PATH("a/foo"), O_CREAT, 0644); if (res == -1) { PERROR("open"); goto fail; } close(res); res = rename(PATH("a/foo"), PATH2("a/bar")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/bar"), PATH2("a/foo")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/foo"), PATH2("a/b/bar")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/b/bar"), PATH2("a/foo")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/foo"), PATH2("a/b/c/bar")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/b/c/bar"), PATH2("a/foo")); if (res == -1) { PERROR("rename"); goto fail; } res = open(PATH("a/bar"), O_CREAT, 0644); if (res == -1) { PERROR("open"); goto fail; } close(res); res = rename(PATH("a/foo"), PATH2("a/bar")); if (res == -1) { PERROR("rename"); goto fail; } unlink(PATH("a/bar")); res = rename(PATH("a/b"), PATH2("a/d")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/d"), PATH2("a/b")); if (res == -1) { PERROR("rename"); goto fail; } res = mkdir(PATH("a/d"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } res = rename(PATH("a/b"), PATH2("a/d")); if (res == -1) { PERROR("rename"); goto fail; } res = rename(PATH("a/d"), PATH2("a/b")); if (res == -1) { PERROR("rename"); goto fail; } res = mkdir(PATH("a/d"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } res = mkdir(PATH("a/d/e"), 0755); if (res == -1) { PERROR("mkdir"); goto fail; } errno = 0; res = rename(PATH("a/b"), PATH2("a/d")); if (res == 0 || (errno != ENOTEMPTY && errno != EEXIST)) { PERROR("rename"); goto fail; } rmdir(PATH("a/d/e")); rmdir(PATH("a/d")); rmdir(PATH("a/b/c")); rmdir(PATH("a/b")); rmdir(PATH("a")); err += cleanup_dir(testdir, testdir_files, 0); res = rmdir(testdir); if (res == -1) { PERROR("rmdir"); goto fail; } res = check_nonexist(testdir); if (res == -1) return -1; if (err) return -1; success(); return 0; fail: unlink(PATH("a/bar")); rmdir(PATH("a/d/e")); rmdir(PATH("a/d")); rmdir(PATH("a/b/c")); rmdir(PATH("a/b")); rmdir(PATH("a")); cleanup_dir(testdir, testdir_files, 1); rmdir(testdir); return -1; #undef PATH2 #undef PATH } static int test_mkfifo(void) { int res; int err = 0; start_test("mkfifo"); unlink(testfile); res = mkfifo(testfile, 0644); if (res == -1) { PERROR("mkfifo"); return -1; } res = check_type(testfile, S_IFIFO); if (res == -1) return -1; err += check_mode(testfile, 0644); err += check_nlink(testfile, 1); res = unlink(testfile); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testfile); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_mkdir(void) { int res; int err = 0; const char *dir_contents[] = {NULL}; start_test("mkdir"); rmdir(testdir); res = mkdir(testdir, 0755); if (res == -1) { PERROR("mkdir"); return -1; } res = check_type(testdir, S_IFDIR); if (res == -1) return -1; err += check_mode(testdir, 0755); /* Some file systems (like btrfs) don't track link count for directories */ //err += check_nlink(testdir, 2); err += check_dir_contents(testdir, dir_contents); res = rmdir(testdir); if (res == -1) { PERROR("rmdir"); return -1; } res = check_nonexist(testdir); if (res == -1) return -1; if (err) return -1; success(); return 0; } static int test_socket(void) { struct sockaddr_un su; int fd; int res; int err = 0; const size_t test_sock_len = strlen(testsock) + 1; start_test("socket"); if (test_sock_len > sizeof(su.sun_path)) { fprintf(stderr, "Need to shorten mount point by %zu chars\n", strlen(testsock) + 1 - sizeof(su.sun_path)); return -1; } unlink(testsock); fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd < 0) { PERROR("socket"); return -1; } su.sun_family = AF_UNIX; strncpy(su.sun_path, testsock, test_sock_len); su.sun_path[sizeof(su.sun_path) - 1] = '\0'; res = bind(fd, (struct sockaddr*)&su, sizeof(su)); if (res == -1) { PERROR("bind"); return -1; } res = check_type(testsock, S_IFSOCK); if (res == -1) { close(fd); return -1; } err += check_nlink(testsock, 1); close(fd); res = unlink(testsock); if (res == -1) { PERROR("unlink"); return -1; } res = check_nonexist(testsock); if (res == -1) return -1; if (err) return -1; success(); return 0; } #define test_create_ro_dir(flags) \ do_test_create_ro_dir(flags, #flags) static int do_test_create_ro_dir(int flags, const char *flags_str) { int res; int err = 0; int fd; start_test("open(%s) in read-only directory", flags_str); rmdir(testdir); res = mkdir(testdir, 0555); if (res == -1) { PERROR("mkdir"); return -1; } fd = open(subfile, flags, 0644); if (fd != -1) { close(fd); unlink(subfile); ERROR("open should have failed"); err--; } else { res = check_nonexist(subfile); if (res == -1) err--; } unlink(subfile); res = rmdir(testdir); if (res == -1) { PERROR("rmdir"); return -1; } res = check_nonexist(testdir); if (res == -1) return -1; if (err) return -1; success(); return 0; } #ifndef __FreeBSD__ /* this tests open with O_TMPFILE note that this will only work with the fuse low level api you will get ENOTSUP with the high level api */ static int test_create_tmpfile(void) { rmdir(testdir); int res = mkdir(testdir, 0777); if (res) return -1; start_test("create tmpfile"); int fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); if(fd == -1) { if (errno == ENOTSUP) { /* don't bother if we're working on an old kernel or on the high level API */ return 0; } PERROR("open O_TMPFILE | O_RDWR"); return -1; } close(fd); fd = open(testdir, O_TMPFILE | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR); if(fd == -1){ PERROR("open with O_TMPFILE | O_WRONLY | O_EXCL"); return -1; }; close(fd); fd = open(testdir, O_TMPFILE | O_RDONLY, S_IRUSR); if (fd != -1) { ERROR("open with O_TMPFILE | O_RDONLY succeeded"); return -1; } success(); return 0; } static int test_create_and_link_tmpfile(void) { /* skip this test for now since the github runner will fail in the linkat call below */ return 0; rmdir(testdir); unlink(testfile); int res = mkdir(testdir, 0777); if (res) return -1; start_test("create and link tmpfile"); int fd = open(testdir, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR); if(fd == -1) { if (errno == ENOTSUP) { /* don't bother if we're working on an old kernel or on the high level API */ return 0; } PERROR("open with O_TMPFILE | O_RDWR | O_EXCL"); return -1; } if (!linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) { ERROR("linkat succeeded on a tmpfile opened with O_EXCL"); return -1; } close(fd); fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR); if(fd == -1) { PERROR("open O_TMPFILE"); return -1; } if (check_nonexist(testfile)) { return -1; } if (linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) { PERROR("linkat tempfile"); return -1; } close(fd); if (check_nlink(testfile, 1)) { return -1; } unlink(testfile); success(); return 0; } #endif int main(int argc, char *argv[]) { int err = 0; int a; int is_root; /* Piped stdout is fully buffered, so a killed test loses whatever it * had printed about what it was doing. */ setvbuf(stdout, NULL, _IOLBF, 0); umask(0); if (argc < 2 || argc > 4) { fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#] [-u]\n", argv[0]); return 1; } basepath = argv[1]; basepath_r = basepath; for (a = 2; a < argc; a++) { char *endptr; char *arg = argv[a]; if (arg[0] == ':') { basepath_r = arg + 1; } else { if (arg[0] == '-') { arg++; if (arg[0] == 'u') { unlinked_test = 1; endptr = arg + 1; } else { skip_test = strtoul(arg, &endptr, 10); } } else { select_test = strtoul(arg, &endptr, 10); } if (arg[0] == '\0' || *endptr != '\0') { fprintf(stderr, "invalid option: '%s'\n", argv[a]); return 1; } } } assert(strlen(basepath) < 512); assert(strlen(basepath_r) < 512); if (basepath[0] != '/') { fprintf(stderr, "testdir must be an absolute path\n"); return 1; } sprintf(testfile, "%s/testfile", basepath); sprintf(testfile2, "%s/testfile2", basepath); sprintf(testdir, "%s/testdir", basepath); sprintf(testdir2, "%s/testdir2", basepath); sprintf(subfile, "%s/subfile", testdir2); sprintf(testsock, "%s/testsock", basepath); sprintf(testfile_r, "%s/testfile", basepath_r); sprintf(testfile2_r, "%s/testfile2", basepath_r); sprintf(testdir_r, "%s/testdir", basepath_r); sprintf(testdir2_r, "%s/testdir2", basepath_r); sprintf(subfile_r, "%s/subfile", testdir2_r); is_root = (geteuid() == 0); err += test_create(); err += test_create_unlink(); err += test_symlink(); err += test_link(); err += test_link2(); err += test_mknod(); err += test_mkfifo(); err += test_mkdir(); err += test_rename_file(); err += test_rename_dir(); err += test_rename_dir_loop(); err += test_seekdir(); err += test_socket(); err += test_utime(); err += test_truncate(0); err += test_truncate(testdatalen / 2); err += test_truncate(testdatalen); err += test_truncate(testdatalen + 100); err += test_ftruncate(0, 0600); err += test_ftruncate(testdatalen / 2, 0600); err += test_ftruncate(testdatalen, 0600); err += test_ftruncate(testdatalen + 100, 0600); err += test_ftruncate(0, 0400); err += test_ftruncate(0, 0200); err += test_ftruncate(0, 0000); err += test_open(0, O_RDONLY, 0); err += test_open(1, O_RDONLY, 0); err += test_open(1, O_RDWR, 0); err += test_open(1, O_WRONLY, 0); err += test_open(0, O_RDWR | O_CREAT, 0600); err += test_open(1, O_RDWR | O_CREAT, 0600); err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600); err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600); err += test_open(0, O_RDONLY | O_CREAT, 0600); err += test_open(0, O_RDONLY | O_CREAT, 0400); err += test_open(0, O_RDONLY | O_CREAT, 0200); err += test_open(0, O_RDONLY | O_CREAT, 0000); err += test_open(0, O_WRONLY | O_CREAT, 0600); err += test_open(0, O_WRONLY | O_CREAT, 0400); err += test_open(0, O_WRONLY | O_CREAT, 0200); err += test_open(0, O_WRONLY | O_CREAT, 0000); err += test_open(0, O_RDWR | O_CREAT, 0400); err += test_open(0, O_RDWR | O_CREAT, 0200); err += test_open(0, O_RDWR | O_CREAT, 0000); err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600); err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600); err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000); err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000); err += test_open_acc(O_RDONLY, 0600, 0); err += test_open_acc(O_WRONLY, 0600, 0); err += test_open_acc(O_RDWR, 0600, 0); err += test_open_acc(O_RDONLY, 0400, 0); err += test_open_acc(O_WRONLY, 0200, 0); if(!is_root) { err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES); err += test_open_acc(O_WRONLY, 0400, EACCES); err += test_open_acc(O_RDWR, 0400, EACCES); err += test_open_acc(O_RDONLY, 0200, EACCES); err += test_open_acc(O_RDWR, 0200, EACCES); err += test_open_acc(O_RDONLY, 0000, EACCES); err += test_open_acc(O_WRONLY, 0000, EACCES); err += test_open_acc(O_RDWR, 0000, EACCES); } err += test_create_ro_dir(O_CREAT); err += test_create_ro_dir(O_CREAT | O_EXCL); err += test_create_ro_dir(O_CREAT | O_WRONLY); err += test_create_ro_dir(O_CREAT | O_TRUNC); err += test_copy_file_range(); err += test_statx(); #ifndef __FreeBSD__ err += test_create_tmpfile(); err += test_create_and_link_tmpfile(); #endif unlink(testfile2); unlink(testsock); rmdir(testdir); rmdir(testdir2); if (err) { fprintf(stderr, "%i tests failed\n", -err); return 1; } return check_unlinked_testfiles(); } fuse-3.18.3/test/test_want_conversion.c0000644000175000017500000001205515250106036017117 0ustar berndbernd#define FUSE_USE_VERSION FUSE_MAKE_VERSION(3, 17) #include "util.h" #include "fuse_i.h" #include "fuse_lowlevel.h" #include #include #include #include #include static void print_conn_info(const char *prefix, struct fuse_conn_info *conn) { struct fuse_session *se = container_of(conn, struct fuse_session, conn); printf("%s: want=0x%" PRIx32 " want_ext=0x%" PRIx64 " want_default=0x%" PRIx32 " want_ext_default=0x%" PRIx64 "\n", prefix, conn->want, conn->want_ext, se->conn_want, se->conn_want_ext); } static void application_init_old_style(struct fuse_conn_info *conn) { /* Simulate application init the old style */ conn->want |= FUSE_CAP_ASYNC_READ; conn->want &= ~FUSE_CAP_SPLICE_READ; /* * Also use new style API, as that might happen through * fuse_apply_conn_info_opts() */ fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR); } static void application_init_new_style(struct fuse_conn_info *conn) { /* Simulate application init the new style */ fuse_set_feature_flag(conn, FUSE_CAP_ASYNC_READ); fuse_set_feature_flag(conn, FUSE_CAP_IOCTL_DIR); fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ); } static void test_fuse_fs_init(struct fuse_conn_info *conn, bool new_style) { /* High-level init */ fuse_set_feature_flag(conn, FUSE_CAP_EXPORT_SUPPORT); if (new_style) application_init_new_style(conn); else application_init_old_style(conn); } static void test_do_init(struct fuse_conn_info *conn, bool new_style) { /* Initial setup */ conn->capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS | FUSE_CAP_FLOCK_LOCKS | FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ | FUSE_CAP_IOCTL_DIR; conn->capable = fuse_lower_32_bits(conn->capable_ext); fuse_set_feature_flag(conn, FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE); print_conn_info("Initial state", conn); int rc; test_fuse_fs_init(conn, new_style); print_conn_info("After init", conn); rc = fuse_convert_to_conn_want_ext(conn); assert(rc == 0); /* Verify all expected flags are set */ assert(!(conn->want_ext & FUSE_CAP_SPLICE_READ)); assert(conn->want_ext & FUSE_CAP_SPLICE_WRITE); assert(conn->want_ext & FUSE_CAP_SPLICE_MOVE); assert(conn->want_ext & FUSE_CAP_EXPORT_SUPPORT); assert(conn->want_ext & FUSE_CAP_ASYNC_READ); assert(conn->want_ext & FUSE_CAP_IOCTL_DIR); /* Verify no other flags are set */ assert(conn->want_ext == (FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_EXPORT_SUPPORT | FUSE_CAP_ASYNC_READ | FUSE_CAP_IOCTL_DIR)); print_conn_info("After init", conn); } static void test_want_conversion_basic(void) { const struct fuse_lowlevel_ops ops = { 0 }; struct fuse_args args = FUSE_ARGS_INIT(0, NULL); struct fuse_session *se; struct fuse_conn_info *conn; /* Add the program name to arg[0] */ if (fuse_opt_add_arg(&args, "test_signals")) { fprintf(stderr, "Failed to add argument\n"); errx(1, "Failed to add argument"); } se = fuse_session_new(&args, &ops, sizeof(ops), NULL); assert(se); conn = &se->conn; printf("\nTesting basic want conversion, old style:\n"); test_do_init(conn, false); fuse_session_destroy(se); se = fuse_session_new(&args, &ops, sizeof(ops), NULL); assert(se); conn = &se->conn; printf("\nTesting basic want conversion, new style:\n"); test_do_init(conn, true); print_conn_info("After init", conn); fuse_session_destroy(se); fuse_opt_free_args(&args); } static void test_want_conversion_conflict(void) { struct fuse_conn_info conn = { 0 }; int rc; printf("\nTesting want conversion conflict:\n"); /* Test conflicting values */ /* Initialize like fuse_lowlevel.c does */ conn.capable_ext = FUSE_CAP_SPLICE_READ | FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE | FUSE_CAP_POSIX_LOCKS | FUSE_CAP_FLOCK_LOCKS; conn.capable = fuse_lower_32_bits(conn.capable_ext); conn.want_ext = conn.capable_ext; conn.want = fuse_lower_32_bits(conn.want_ext); print_conn_info("Test conflict initial", &conn); /* Simulate application init modifying capabilities */ conn.want_ext |= FUSE_CAP_ATOMIC_O_TRUNC; /* Add new capability */ conn.want &= ~FUSE_CAP_SPLICE_READ; /* Remove a capability */ rc = fuse_convert_to_conn_want_ext(&conn); assert(rc == -EINVAL); print_conn_info("Test conflict after", &conn); printf("Want conversion conflict test passed\n"); } static void test_want_conversion_high_bits(void) { struct fuse_conn_info conn = { 0 }; int rc; printf("\nTesting want conversion high bits preservation:\n"); /* Test high bits preservation */ conn.want_ext = (1ULL << 33) | FUSE_CAP_ASYNC_READ; conn.want = fuse_lower_32_bits(conn.want_ext); print_conn_info("Test high bits initial", &conn); rc = fuse_convert_to_conn_want_ext(&conn); assert(rc == 0); assert(conn.want_ext == ((1ULL << 33) | FUSE_CAP_ASYNC_READ)); print_conn_info("Test high bits after", &conn); printf("Want conversion high bits test passed\n"); } int main(void) { test_want_conversion_basic(); test_want_conversion_conflict(); test_want_conversion_high_bits(); return 0; } fuse-3.18.3/test/test_write_cache.c0000644000175000017500000001632115250106036016156 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2016 Nikolaus Rath This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ #define FUSE_USE_VERSION 30 /* Not really needed - just to test build with FUSE_USE_VERSION == 30 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __linux__ #include #else #include #endif #define FILE_INO 2 #define FILE_NAME "write_me" /* Command line parsing */ struct options { int writeback; int data_size; int delay_ms; } options = { .writeback = 0, .data_size = 2048, .delay_ms = 0, }; #define WRITE_SYSCALLS 64 #define OPTION(t, p) { t, offsetof(struct options, p), 1 } static const struct fuse_opt option_spec[] = { OPTION("writeback_cache", writeback), OPTION("--data-size=%d", data_size), OPTION("--delay_ms=%d", delay_ms), FUSE_OPT_END }; static int got_write; static atomic_int write_cnt; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static int write_start, write_done; static void tfs_init(void *userdata, struct fuse_conn_info *conn) { (void)userdata; if (options.writeback) { assert(fuse_get_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE)); fuse_set_feature_flag(conn, FUSE_CAP_WRITEBACK_CACHE); } } 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 | 0222; stbuf->st_nlink = 1; stbuf->st_size = 0; } 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; else goto err_out; 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_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, 5); } static void tfs_open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { if (ino == FUSE_ROOT_ID) fuse_reply_err(req, EISDIR); else { assert(ino == FILE_INO); /* Test close(rofd) does not block waiting for pending writes */ fi->noflush = !options.writeback && options.delay_ms && (fi->flags & O_ACCMODE) == O_RDONLY; fuse_reply_open(req, fi); } } static void tfs_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { (void)fi; (void)buf; (void)off; size_t expected; assert(ino == FILE_INO); expected = options.data_size; if (options.writeback) expected *= 2; write_cnt++; if (size != expected && !options.writeback) fprintf(stderr, "ERROR: Expected %zd bytes, got %zd\n!", expected, size); else got_write = 1; /* Simulate waiting for pending writes */ if (options.delay_ms) { pthread_mutex_lock(&lock); write_start = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); usleep(options.delay_ms * 1000); pthread_mutex_lock(&lock); write_done = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&lock); } fuse_reply_write(req, size); } static struct fuse_lowlevel_ops tfs_oper = { .init = tfs_init, .lookup = tfs_lookup, .getattr = tfs_getattr, .open = tfs_open, .write = tfs_write, }; static void *close_rofd(void *data) { int rofd = (int)(long)data; /* Wait for first write to start */ pthread_mutex_lock(&lock); while (!write_start && !write_done) pthread_cond_wait(&cond, &lock); pthread_mutex_unlock(&lock); close(rofd); printf("rofd closed. write_start: %d write_done: %d\n", write_start, write_done); /* First write should not have been completed */ if (write_done) fprintf(stderr, "ERROR: close(rofd) blocked on write!\n"); return NULL; } static void *run_fs(void *data) { struct fuse_session *se = (struct fuse_session *)data; assert(fuse_session_loop(se) == 0); return NULL; } static void test_fs(char *mountpoint) { char fname[PATH_MAX]; char *buf; const size_t iosize = options.data_size; const size_t dsize = options.data_size * WRITE_SYSCALLS; int fd, rofd; pthread_t rofd_thread; off_t off = 0; buf = malloc(dsize); assert(buf != NULL); assert((fd = open("/dev/urandom", O_RDONLY)) != -1); assert(read(fd, buf, dsize) == dsize); close(fd); assert(snprintf(fname, PATH_MAX, "%s/" FILE_NAME, mountpoint) > 0); fd = open(fname, O_WRONLY); if (fd == -1) { perror(fname); assert(0); } if (options.delay_ms) { /* Verify that close(rofd) does not block waiting for pending writes */ rofd = open(fname, O_RDONLY); assert(pthread_create(&rofd_thread, NULL, close_rofd, (void *)(long)rofd) == 0); /* Give close_rofd time to start */ usleep(options.delay_ms * 1000); } for (int cnt = 0; cnt < WRITE_SYSCALLS; cnt++) { assert(pwrite(fd, buf + off, iosize, off) == iosize); off += iosize; assert(off <= dsize); } free(buf); close(fd); if (options.delay_ms) { printf("rwfd closed. write_start: %d write_done: %d\n", write_start, write_done); assert(pthread_join(rofd_thread, NULL) == 0); } } int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); struct fuse_session *se; struct fuse_cmdline_opts fuse_opts; pthread_t fs_thread; assert(fuse_opt_parse(&args, &options, option_spec, NULL) == 0); assert(fuse_parse_cmdline(&args, &fuse_opts) == 0); #ifndef __FreeBSD__ assert(fuse_opt_add_arg(&args, "-oauto_unmount") == 0); #endif se = fuse_session_new(&args, &tfs_oper, sizeof(tfs_oper), NULL); fuse_opt_free_args(&args); assert(se != NULL); assert(fuse_set_signal_handlers(se) == 0); assert(fuse_session_mount(se, fuse_opts.mountpoint) == 0); /* Start file-system thread */ assert(pthread_create(&fs_thread, NULL, run_fs, (void *)se) == 0); /* Write test data */ test_fs(fuse_opts.mountpoint); free(fuse_opts.mountpoint); /* Stop file system */ fuse_session_exit(se); fuse_session_unmount(se); assert(pthread_join(fs_thread, NULL) == 0); assert(got_write == 1); /* * when writeback cache is enabled, kernel side can merge requests, but * memory pressure, system 'sync' might trigger data flushes before - flush * might happen in between write syscalls - merging subpage writes into * a single page and pages into large fuse requests might or might not work. * Though we can expect that that at least some (but maybe all) write * system calls can be merged. */ if (options.writeback) assert(write_cnt < WRITE_SYSCALLS); else assert(write_cnt == WRITE_SYSCALLS); fuse_remove_signal_handlers(se); fuse_session_destroy(se); printf("Test completed successfully.\n"); return 0; } /** * Local Variables: * mode: c * indent-tabs-mode: nil * c-basic-offset: 4 * End: */ fuse-3.18.3/tsan_suppressions.txt0000644000175000017500000000017115250106036016056 0ustar berndbernd# Use with # TSAN_OPTIONS="suppressions=tsan_suppressions.txt" ./myprogram # False positive race:pthread_setcancelstate fuse-3.18.3/util/0000755000175000017500000000000015250106404012470 5ustar berndberndfuse-3.18.3/util/fuse.conf0000644000175000017500000000132515250106036014303 0ustar berndbernd# The file /etc/fuse.conf allows for the following parameters: # # user_allow_other - Using the allow_other mount option works fine as root, but # in order to have it work as a regular user, you need to set user_allow_other # in /etc/fuse.conf as well. This option allows non-root users to use the # allow_other option. You need allow_other if you want users other than the # owner of a mounted fuse to access it. This option must appear on a line by # itself. There is no value; just the presence of the option activates it. #user_allow_other # mount_max = n - this option sets the maximum number of mounts. # It must be typed exactly as shown (with a single space before and after the # equals sign). #mount_max = 1000 fuse-3.18.3/util/fusermount.c0000644000175000017500000012234315250106036015051 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ /* This program does the mounting and unmounting of FUSE filesystems */ #define _GNU_SOURCE /* for clone,strchrnul and close_range */ #include "fuse_config.h" #include "mount_util.h" #include "util.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fuse_mount_compat.h" #include #include #include #include #include #include #if defined HAVE_CLOSE_RANGE && defined linux #include #endif #if defined HAVE_LISTMOUNT #include #include #include #endif #define FUSE_COMMFD_ENV "_FUSE_COMMFD" #define FUSE_KERN_DEVICE_ENV "FUSE_KERN_DEVICE" #define FUSE_DEV "/dev/fuse" static const char *progname; static int user_allow_other = 0; static int mount_max = 1000; static int auto_unmount = 0; #ifdef GETMNTENT_NEEDS_UNESCAPING // Older versions of musl libc don't unescape entries in /etc/mtab // unescapes octal sequences like \040 in-place // That's ok, because unescaping can not extend the length of the string. static void unescape(char *buf) { char *src = buf; char *dest = buf; while (1) { char *next_src = strchrnul(src, '\\'); int offset = next_src - src; memmove(dest, src, offset); src = next_src; dest += offset; if(*src == '\0') { *dest = *src; return; } src++; if('0' <= src[0] && src[0] < '2' && '0' <= src[1] && src[1] < '8' && '0' <= src[2] && src[2] < '8') { *dest++ = (src[0] - '0') << 6 | (src[1] - '0') << 3 | (src[2] - '0') << 0; src += 3; } else if (src[0] == '\\') { *dest++ = '\\'; src += 1; } else { *dest++ = '\\'; } } } static struct mntent *GETMNTENT(FILE *stream) { struct mntent *entp = getmntent(stream); if(entp != NULL) { unescape(entp->mnt_fsname); unescape(entp->mnt_dir); unescape(entp->mnt_type); unescape(entp->mnt_opts); } return entp; } #else #define GETMNTENT getmntent #endif // GETMNTENT_NEEDS_UNESCAPING /* * Take a ',' separated option string and extract "x-" options */ static int extract_x_options(const char *original, char **non_x_opts, char **x_opts) { size_t orig_len; const char *opt, *opt_end; orig_len = strlen(original) + 1; *non_x_opts = calloc(1, orig_len); *x_opts = calloc(1, orig_len); size_t non_x_opts_len = orig_len; size_t x_opts_len = orig_len; if (*non_x_opts == NULL || *x_opts == NULL) { fprintf(stderr, "%s: Failed to allocate %zuB.\n", __func__, orig_len); return -ENOMEM; } for (opt = original; opt < original + orig_len; opt = opt_end + 1) { char *opt_buf; opt_end = strchr(opt, ','); if (opt_end == NULL) opt_end = original + orig_len; size_t opt_len = opt_end - opt; size_t opt_len_left = orig_len - (opt - original); size_t buf_len; bool is_x_opts; if (strncmp(opt, "x-", MIN(2, opt_len_left)) == 0) { buf_len = x_opts_len; is_x_opts = true; opt_buf = *x_opts; } else { buf_len = non_x_opts_len; is_x_opts = false; opt_buf = *non_x_opts; } if (buf_len < orig_len) { strncat(opt_buf, ",", 2); buf_len -= 1; } /* omits ',' */ if ((ssize_t)(buf_len - opt_len) < 0) { /* This would be a bug */ fprintf(stderr, "%s: no buf space left in copy, orig='%s'\n", __func__, original); return -EIO; } strncat(opt_buf, opt, opt_end - opt); buf_len -= opt_len; if (is_x_opts) x_opts_len = buf_len; else non_x_opts_len = buf_len; } return 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; } #endif /* * Check whether the file specified in "fusermount3 -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 fusermount3 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]; const char *type = a[2]; 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 && (!type || strcmp(entp->mnt_type, type) == 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, const char *type) { pid_t pid, p; int status; const char *a[3] = { last, mnt, type }; 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; } #ifndef IGNORE_MTAB 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) | UMOUNT_NOFOLLOW; 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; } drop_privs(); res = chdir_to_parent(copy, &last); if (res == -1) { restore_privs(); goto out; } res = umount2(last, umount_flags); restore_privs(); if (res == -1 && !quiet) { fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, strerror(errno)); } out: free(copy); 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_mtab(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; } #ifdef HAVE_LISTMOUNT static int count_fuse_fs_ls_mnt(void) { #define SMBUF_SIZE 1024 #define MNT_ID_LEN 128 int fuse_count = 0; int n_mounts = 0; int ret = 0; uint64_t mnt_ids[MNT_ID_LEN]; unsigned char smbuf[SMBUF_SIZE]; struct mnt_id_req req = { .size = sizeof(struct mnt_id_req), }; struct statmount *sm; for (;;) { req.mnt_id = LSMT_ROOT; n_mounts = syscall(SYS_listmount, &req, &mnt_ids, MNT_ID_LEN, 0); if (n_mounts == -1) { if (errno != ENOSYS) { fprintf(stderr, "%s: failed to list mounts: %s\n", progname, strerror(errno)); } return -1; } for (int i = 0; i < n_mounts; i++) { req.mnt_id = mnt_ids[i]; req.param = STATMOUNT_FS_TYPE; ret = syscall(SYS_statmount, &req, &smbuf, SMBUF_SIZE, 0); if (ret) { if (errno == ENOENT) continue; fprintf(stderr, "%s: failed to stat mount %lld: %s\n", progname, req.mnt_id, strerror(errno)); return -1; } sm = (struct statmount *)smbuf; if (sm->mask & STATMOUNT_FS_TYPE && strcmp(&sm->str[sm->fs_type], "fuse") == 0) fuse_count++; } if (n_mounts < MNT_ID_LEN) break; req.param = mnt_ids[MNT_ID_LEN - 1]; } return fuse_count; } static int count_fuse_fs(void) { int count = count_fuse_fs_ls_mnt(); return count >= 0 ? count : count_fuse_fs_mtab(); } #else static int count_fuse_fs(void) { return count_fuse_fs_mtab(); } #endif #else /* IGNORE_MTAB */ static int count_fuse_fs(void) { 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) { (void) quiet; return fuse_mnt_umount(progname, mnt, mnt, lazy); } #endif /* IGNORE_MTAB */ static void strip_line(char *line) { char *s = strchr(line, '#'); size_t len; if (s != NULL) s[0] = '\0'; /* * Count down rather than walk a pointer back: an empty or all-blank * line would form line - 1, which is undefined behaviour even though * the store that follows lands inside the buffer. */ len = strlen(line); while (len > 0 && isspace((unsigned char) line[len - 1])) len--; line[len] = '\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) { if (tmp < -1) fprintf(stderr, "%s: invalid mount_max = %i in %s at line %i\n", progname, tmp, FUSE_CONF, linenum); else 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}, {"diratime", MS_NODIRATIME, 0, 1}, {"nodiratime", MS_NODIRATIME, 1, 1}, {"lazytime", MS_LAZYTIME, 1, 1}, {"nolazytime", MS_LAZYTIME, 0, 1}, {"relatime", MS_RELATIME, 1, 1}, {"norelatime", MS_RELATIME, 0, 1}, {"strictatime", MS_STRICTATIME, 1, 1}, {"nostrictatime", MS_STRICTATIME, 0, 1}, {"dirsync", MS_DIRSYNC, 1, 1}, {"symfollow", MS_NOSYMFOLLOW, 0, 1}, {"nosymfollow", MS_NOSYMFOLLOW, 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 (l > 0 && (*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; } /* The kernel silently truncates the "data" argument to PAGE_SIZE-1 characters. * This can be dangerous if it e.g. truncates the option "group_id=1000" to * "group_id=1". * This wrapper detects this case and bails out with an error. */ static int mount_notrunc(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const char *data) { if (strlen(data) > sysconf(_SC_PAGESIZE) - 1) { fprintf(stderr, "%s: mount options too long\n", progname); errno = EINVAL; return -1; } return mount(source, target, filesystemtype, mountflags, data); } static int do_mount(const char *mnt, const char **typep, mode_t rootmode, int fd, const char *opts, const char *dev, char **sourcep, char **mnt_optsp) { 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 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, "auto_unmount")) { auto_unmount = 1; } else if (!opt_eq(s, len, "nonempty") && !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 %s\n", progname, len, s, FUSE_CONF); 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()); 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_notrunc(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_notrunc(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_notrunc(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; } /* * Resolve the caller-supplied mountpoint exactly once and hand back a * descriptor for the inode it named. O_NOFOLLOW refuses a symlink outright for * an unprivileged caller; root keeps following them, as it always has. */ static int pin_mountpoint(const char *mnt, bool is_root, struct stat *stbuf) { int open_flags = O_PATH | O_CLOEXEC; int fd; if (!is_root) open_flags |= O_NOFOLLOW; fd = open(mnt, open_flags); if (fd == -1) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, mnt, strerror(errno)); return -1; } if (fstat(fd, stbuf) == -1) { fprintf(stderr, "%s: failed to access mountpoint %s: %s\n", progname, mnt, strerror(errno)); close(fd); return -1; } return fd; } static int check_perm(const char **mntp, struct stat *stbuf, int *mountpoint_fd) { int res; int fd; const char *mnt = *mntp; const bool is_root = getuid() == 0; struct statfs fs_buf; size_t i; fd = pin_mountpoint(mnt, is_root, stbuf); if (fd == -1) return -1; /* No permission checking is done for root */ if (is_root) { *mountpoint_fd = fd; return 0; } if (S_ISDIR(stbuf->st_mode)) { res = fchdir(fd); if (res == -1) { fprintf(stderr, "%s: failed to chdir to mountpoint: %s\n", progname, strerror(errno)); goto out_close; } /* * The pinned directory is the CWD, so "." names it without * going through the caller-supplied path a second time. */ *mntp = "."; if ((stbuf->st_mode & S_ISVTX) && stbuf->st_uid != getuid()) { fprintf(stderr, "%s: mountpoint %s not owned by user\n", progname, mnt); res = -1; goto out_close; } res = access(*mntp, W_OK); if (res == -1) { fprintf(stderr, "%s: user has no write access to mountpoint %s\n", progname, mnt); goto out_close; } } else if (S_ISREG(stbuf->st_mode)) { static char procfile[256]; int wfd; snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd); /* * Reopening the pinned inode through its magic link both tests * write access and yields the descriptor mount(2) is pointed * at, so the caller's path is never resolved again. */ wfd = open(procfile, O_WRONLY); if (wfd == -1) { fprintf(stderr, "%s: failed to open %s: %s\n", progname, mnt, strerror(errno)); res = -1; goto out_close; } close(fd); fd = wfd; snprintf(procfile, sizeof(procfile), "/proc/self/fd/%i", fd); *mntp = procfile; } else { fprintf(stderr, "%s: mountpoint %s is not a directory or a regular file\n", progname, mnt); res = -1; goto out_close; } /* 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)); res = -1; goto out_close; } /* Define permitted filesystems for the mount target. This was * originally the same list as used by the ecryptfs mount helper * (https://bazaar.launchpad.net/~ecryptfs/ecryptfs/trunk/view/head:/src/utils/mount.ecryptfs_private.c#L225) * but got expanded as we found more filesystems that needed to be * overlaid. */ typeof(fs_buf.f_type) f_type_whitelist[] = { 0x61756673 /* AUFS_SUPER_MAGIC */, 0x00000187 /* AUTOFS_SUPER_MAGIC */, 0xCA451A4E /* BCACHEFS_STATFS_MAGIC */, 0x9123683E /* BTRFS_SUPER_MAGIC */, 0x00C36400 /* CEPH_SUPER_MAGIC */, 0xFF534D42 /* CIFS_MAGIC_NUMBER */, 0x0000F15F /* ECRYPTFS_SUPER_MAGIC */, 0X2011BAB0 /* EXFAT_SUPER_MAGIC */, 0x0000EF53 /* EXT[234]_SUPER_MAGIC */, 0xF2F52010 /* F2FS_SUPER_MAGIC */, 0x65735546 /* FUSE_SUPER_MAGIC */, 0x01161970 /* GFS2_MAGIC */, 0x47504653 /* GPFS_SUPER_MAGIC */, 0x0000482b /* HFSPLUS_SUPER_MAGIC */, 0x000072B6 /* JFFS2_SUPER_MAGIC */, 0x3153464A /* JFS_SUPER_MAGIC */, 0x0BD00BD0 /* LL_SUPER_MAGIC */, 0X00004D44 /* MSDOS_SUPER_MAGIC */, 0x0000564C /* NCP_SUPER_MAGIC */, 0x00006969 /* NFS_SUPER_MAGIC */, 0x00003434 /* NILFS_SUPER_MAGIC */, 0x5346544E /* NTFS_SB_MAGIC */, 0x7366746E /* NTFS3_SUPER_MAGIC */, 0x5346414f /* OPENAFS_SUPER_MAGIC */, 0x794C7630 /* OVERLAYFS_SUPER_MAGIC */, 0xAAD7AAEA /* PANFS_SUPER_MAGIC */, 0x52654973 /* REISERFS_SUPER_MAGIC */, 0xFE534D42 /* SMB2_SUPER_MAGIC */, 0x73717368 /* SQUASHFS_MAGIC */, 0x01021994 /* TMPFS_MAGIC */, 0x24051905 /* UBIFS_SUPER_MAGIC */, 0x18031977 /* WEKAFS_SUPER_MAGIC */, #if __SIZEOF_LONG__ > 4 0x736675005346544e /* UFSD */, #endif 0x58465342 /* XFS_SB_MAGIC */, 0x2FC12FC1 /* ZFS_SUPER_MAGIC */, 0x858458f6 /* RAMFS_MAGIC */, }; for (i = 0; i < sizeof(f_type_whitelist)/sizeof(f_type_whitelist[0]); i++) { if (f_type_whitelist[i] == fs_buf.f_type) { *mountpoint_fd = fd; return 0; } } fprintf(stderr, "%s: mounting over filesystem type %#010lx is forbidden\n", progname, (unsigned long)fs_buf.f_type); res = -1; out_close: close(fd); return res; } static int open_fuse_device(const char *dev) { int fd; drop_privs(); fd = open(dev, O_RDWR); if (fd == -1) { if (errno == ENODEV || errno == ENOENT)/* check for ENOENT too, for the udev case */ fprintf(stderr, "%s: fuse device %s not found. Kernel module not loaded?\n", progname, dev); else fprintf(stderr, "%s: failed to open %s: %s\n", progname, dev, strerror(errno)); } restore_privs(); return fd; } static int mount_fuse(const char *mnt, const char *opts, const char **type) { int res; int fd; const char *dev = getenv(FUSE_KERN_DEVICE_ENV) ?: FUSE_DEV; struct stat stbuf; char *source = NULL; char *mnt_opts = NULL; const char *real_mnt = mnt; int mountpoint_fd = -1; char *do_mount_opts = NULL; char *x_opts = NULL; 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 %s\n", progname, FUSE_CONF); goto fail_close_fd; } } // Extract any options starting with "x-" res= extract_x_options(opts, &do_mount_opts, &x_opts); if (res) goto fail_close_fd; 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, do_mount_opts, dev, &source, &mnt_opts); 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) { if (x_opts && strlen(x_opts) > 0) { /* * Add back the options starting with "x-" to opts from * do_mount. +2 for ',' and '\0' */ size_t mnt_opts_len = strlen(mnt_opts); size_t x_mnt_opts_len = mnt_opts_len+ strlen(x_opts) + 2; char *x_mnt_opts = calloc(1, x_mnt_opts_len); if (mnt_opts_len) { strcpy(x_mnt_opts, mnt_opts); strncat(x_mnt_opts, ",", 2); } strncat(x_mnt_opts, x_opts, x_mnt_opts_len - mnt_opts_len - 2); free(mnt_opts); mnt_opts = x_mnt_opts; } 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(mnt_opts); free(x_opts); free(do_mount_opts); 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; } /* Helper for should_auto_unmount * * Try opening `mnt` with uid and gid of the calling process. */ static int check_ENOTCONN_as_owner(const char *mnt) { int pid = fork(); if(pid == -1) { perror("fuse: recheck_ENOTCONN_as_owner can't fork"); _exit(EXIT_FAILURE); } else if(pid == 0) { uid_t uid = getuid(); gid_t gid = getgid(); if(setresgid(gid, gid, gid) == -1) { perror("fuse: can't set resgid"); _exit(EXIT_FAILURE); } if(setresuid(uid, uid, uid) == -1) { perror("fuse: can't set resuid"); _exit(EXIT_FAILURE); } int fd = open(mnt, O_RDONLY); if (fd == -1 && (errno == ENOTCONN || errno == ECONNABORTED)) _exit(EXIT_SUCCESS); else _exit(EXIT_FAILURE); } else { int status; int res = waitpid(pid, &status, 0); if (res == -1) { perror("fuse: waiting for child failed"); _exit(EXIT_FAILURE); } return WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS; } } /* The parent fuse process has died: decide whether to auto_unmount. * * In the normal case (umount or fusermount -u), the filesystem * has already been unmounted. If we simply unmount again we can * cause problems with stacked mounts (e.g. autofs). * * So we unmount here only in abnormal case where fuse process has * died without unmount happening. To detect this, we first look in * the mount table to make sure the mountpoint is still mounted and * has proper type. If so, we then see if opening the mount dir is * returning 'Transport endpoint is not connected'. * * The order of these is important, because if autofs is in use, * opening the dir to check for ENOTCONN will cause a new mount * in the normal case where filesystem has been unmounted cleanly. */ static int should_auto_unmount(const char *mnt, const char *type) { char *copy; const char *last; int result = 0; copy = strdup(mnt); if (copy == NULL) { fprintf(stderr, "%s: failed to allocate memory\n", progname); return 0; } if (chdir_to_parent(copy, &last) == -1) goto out; if (check_is_mount(last, mnt, type) == -1) goto out; result = check_ENOTCONN_as_owner(mnt); out: free(copy); return result; } static void usage(void) { printf("%s: [options] mountpoint\n" "Options:\n" " -h print help\n" " -V print version\n" " -o opt[,opt...] mount options\n" " -u unmount\n" " -q quiet\n" " -z lazy unmount\n", progname); exit(1); } static void show_version(void) { printf("fusermount3 version: %s\n", PACKAGE_VERSION); exit(0); } static void close_range_loop(int min_fd, int max_fd, int cfd) { for (int fd = min_fd; fd <= max_fd; fd++) if (fd != cfd) close(fd); } /* * Close all inherited fds that are not needed * Ideally these wouldn't come up at all, applications should better * use FD_CLOEXEC / O_CLOEXEC */ static int close_inherited_fds(int cfd) { int rc = -1; int nullfd; /* We can't even report an error */ if (cfd <= STDERR_FILENO) return -EINVAL; #ifdef HAVE_CLOSE_RANGE if (cfd < STDERR_FILENO + 2) { close_range_loop(STDERR_FILENO + 1, cfd - 1, cfd); } else { rc = close_range(STDERR_FILENO + 1, cfd - 1, 0); if (rc < 0) goto fallback; } /* Close high range */ rc = close_range(cfd + 1, ~0U, 0); #else goto fallback; /* make use of fallback to avoid compiler warnings */ #endif fallback: if (rc < 0) { int max_fd = sysconf(_SC_OPEN_MAX) - 1; close_range_loop(STDERR_FILENO + 1, max_fd, cfd); } nullfd = open("/dev/null", O_RDWR); if (nullfd < 0) { perror("fusermount: cannot open /dev/null"); return -errno; } /* Redirect stdin, stdout, stderr to /dev/null */ dup2(nullfd, STDIN_FILENO); dup2(nullfd, STDOUT_FILENO); dup2(nullfd, STDERR_FILENO); if (nullfd > STDERR_FILENO) close(nullfd); return 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 = NULL; long cfd; const char *opts = ""; const char *type = NULL; int setup_auto_unmount_only = 0; 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'}, {"options", required_argument, NULL, 'o'}, // Note: auto-unmount and comm-fd don't have short versions. // They'ne meant for internal use by mount.c {"auto-unmount", no_argument, NULL, 'U'}, {"comm-fd", required_argument, NULL, 'c'}, {0, 0, 0, 0}}; progname = strdup(argc > 0 ? argv[0] : "fusermount"); 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 'U': unmount = 1; auto_unmount = 1; setup_auto_unmount_only = 1; break; case 'c': commfd = optarg; 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); goto err_out; } } restore_privs(); if (mnt == NULL) exit(1); umask(033); if (!setup_auto_unmount_only && unmount) goto do_unmount; if(commfd == NULL) commfd = getenv(FUSE_COMMFD_ENV); if (commfd == NULL) { fprintf(stderr, "%s: old style mounting not supported\n", progname); goto err_out; } res = libfuse_strtol(commfd, &cfd); if (res) { fprintf(stderr, "%s: invalid _FUSE_COMMFD: %s\n", progname, commfd); goto err_out; } { struct stat statbuf; if (fstat(cfd, &statbuf) == -1) { fprintf(stderr, "%s: fstat of comm fd %li failed: %s\n", progname, cfd, strerror(errno)); goto err_out; } if(!S_ISSOCK(statbuf.st_mode)) { fprintf(stderr, "%s: file descriptor %li is not a socket, can't send fuse fd\n", progname, cfd); goto err_out; } } if (setup_auto_unmount_only) goto wait_for_auto_unmount; fd = mount_fuse(mnt, opts, &type); if (fd == -1) goto err_out; res = send_fd(cfd, fd); if (res != 0) { unmount_fuse(mnt, 1, 1); /* lazy umount */ goto err_out; } close(fd); if (!auto_unmount) { free(mnt); free((void*) type); return 0; } wait_for_auto_unmount: /* 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. */ res = close_inherited_fds(cfd); if (res < 0) exit(EXIT_FAILURE); setsid(); res = chdir("/"); if (res == -1) { fprintf(stderr, "%s: failed to chdir to '/'\n", progname); goto err_out; } 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; } } if (!should_auto_unmount(mnt, type)) { goto success_out; } do_unmount: if (geteuid() == 0) res = unmount_fuse(mnt, quiet, lazy); else { res = umount2(mnt, (lazy ? UMOUNT_DETACH : 0) | UMOUNT_NOFOLLOW); if (res == -1 && !quiet) fprintf(stderr, "%s: failed to unmount %s: %s\n", progname, mnt, strerror(errno)); } if (res == -1) goto err_out; success_out: free((void*) type); free(mnt); return 0; err_out: free((void*) type); free(mnt); exit(1); } fuse-3.18.3/util/init_script0000755000175000017500000000363615250106036014756 0ustar berndbernd#!/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 fusermount3 &>/dev/null || exit 5 # Define LSB log_* functions. . /lib/lsb/init-functions 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-3.18.3/util/install_helper.sh0000755000175000017500000000277315250106036016046 0ustar berndbernd#!/bin/sh # # Don't call this script. It is used internally by the Meson # build system. Thank you for your cooperation. # set -e sysconfdir="$1" bindir="$2" udevrulesdir="$3" useroot="$4" initscriptdir="$5" # Both sysconfdir and bindir are absolute paths (since they are joined # with --prefix in meson.build), but need to be interpreted relative # to DESTDIR (if specified). if [ -z "${DESTDIR}" ]; then # Prevent warnings about uninitialized variable DESTDIR="" else # Get rid of duplicate slash DESTDIR="${DESTDIR%/}" fi install -D -m 644 "${MESON_SOURCE_ROOT}/util/fuse.conf" \ "${DESTDIR}${sysconfdir}/fuse.conf" if $useroot; then chown root:root "${DESTDIR}${bindir}/fusermount3" chmod u+s "${DESTDIR}${bindir}/fusermount3" if test ! -e "${DESTDIR}/dev/fuse"; then mkdir -p "${DESTDIR}/dev" mknod "${DESTDIR}/dev/fuse" -m 0666 c 10 229 fi fi if [ "${udevrulesdir}" != "" ]; then install -D -m 644 "${MESON_SOURCE_ROOT}/util/udev.rules" \ "${DESTDIR}${udevrulesdir}/99-fuse3.rules" fi if [ "$initscriptdir" != "" ]; then install -D -m 755 "${MESON_SOURCE_ROOT}/util/init_script" \ "${DESTDIR}${initscriptdir}/fuse3" if test -x /usr/sbin/update-rc.d && test -z "${DESTDIR}"; then /usr/sbin/update-rc.d fuse3 start 34 S . start 41 0 6 . || /bin/true else echo "== FURTHER ACTION REQUIRED ==" echo "Make sure that your init system will start the ${DESTDIR}${initscriptdir}/init.d/fuse3 init script" fi fi fuse-3.18.3/util/meson.build0000644000175000017500000000245715250106036014643 0ustar berndberndfuseconf_path = join_paths(get_option('prefix'), get_option('sysconfdir'), 'fuse.conf') executable('fusermount3', ['fusermount.c', '../lib/mount_util.c', '../lib/fuse_log.c', '../lib/util.c'], include_directories: include_dirs, install: true, install_dir: get_option('bindir'), c_args: '-DFUSE_CONF="@0@"'.format(fuseconf_path)) executable('mount.fuse3', ['mount.fuse.c'], include_directories: include_dirs, link_with: [ libfuse ], install: true, install_dir: get_option('sbindir'), c_args: '-DFUSE_USE_VERSION=317') udevrulesdir = get_option('udevrulesdir') if udevrulesdir == '' udev = dependency('udev', required: false) if udev.found() udevrulesdir = join_paths(udev.get_variable(pkgconfig: 'udevdir'), 'rules.d') endif endif if udevrulesdir == '' warning('could not determine udevdir, udev.rules will not be installed') endif meson.add_install_script('install_helper.sh', join_paths(get_option('prefix'), get_option('sysconfdir')), join_paths(get_option('prefix'), get_option('bindir')), udevrulesdir, '@0@'.format(get_option('useroot')), get_option('initscriptdir')) fuse-3.18.3/util/mount.fuse.c0000644000175000017500000002500315250106036014740 0ustar berndbernd/* FUSE: Filesystem in Userspace Copyright (C) 2001-2007 Miklos Szeredi This program can be distributed under the terms of the GNU GPLv2. See the file GPL2.txt. */ #include "fuse_config.h" #include #include #include #include #include #include #include #include #include #ifdef linux #include #include #include #include /* for 2.6 kernels */ #if !defined(SECBIT_KEEP_CAPS) && defined(SECURE_KEEP_CAPS) #define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS)) #endif #if !defined(SECBIT_KEEP_CAPS_LOCKED) && defined(SECURE_KEEP_CAPS_LOCKED) #define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED)) #endif #if !defined(SECBIT_NO_SETUID_FIXUP) && defined(SECURE_NO_SETUID_FIXUP) #define SECBIT_NO_SETUID_FIXUP (issecure_mask(SECURE_NO_SETUID_FIXUP)) #endif #if !defined(SECBIT_NO_SETUID_FIXUP_LOCKED) && defined(SECURE_NO_SETUID_FIXUP_LOCKED) #define SECBIT_NO_SETUID_FIXUP_LOCKED (issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)) #endif #if !defined(SECBIT_NOROOT) && defined(SECURE_NOROOT) #define SECBIT_NOROOT (issecure_mask(SECURE_NOROOT)) #endif #if !defined(SECBIT_NOROOT_LOCKED) && defined(SECURE_NOROOT_LOCKED) #define SECBIT_NOROOT_LOCKED (issecure_mask(SECURE_NOROOT_LOCKED)) #endif #endif /* linux < 3.5 */ #ifndef PR_SET_NO_NEW_PRIVS #define PR_SET_NO_NEW_PRIVS 38 #endif #include "fuse.h" 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; if (optlen >= (SIZE_MAX - cmdlen - 4)/4) { fprintf(stderr, "%s: argument too long\n", progname); exit(1); } 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; } static int prepare_fuse_fd(const char *mountpoint, const char* subtype, const char *options) { int fuse_fd = -1; int flags = -1; int subtype_len = strlen(subtype) + 9; char* options_copy = xrealloc(NULL, subtype_len); snprintf(options_copy, subtype_len, "subtype=%s", subtype); options_copy = add_option(options, options_copy); fuse_fd = fuse_open_channel(mountpoint, options_copy); if (fuse_fd == -1) { exit(1); } flags = fcntl(fuse_fd, F_GETFD); if (flags == -1 || fcntl(fuse_fd, F_SETFD, flags & ~FD_CLOEXEC) == -1) { fprintf(stderr, "%s: Failed to clear CLOEXEC: %s\n", progname, strerror(errno)); exit(1); } return fuse_fd; } #ifdef linux static uint64_t get_capabilities(void) { /* * This invokes the capset syscall directly to avoid the libcap * dependency, which isn't really justified just for this. */ struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, .pid = 0, }; struct __user_cap_data_struct data[2]; memset(data, 0, sizeof(data)); if (syscall(SYS_capget, &header, data) == -1) { fprintf(stderr, "%s: Failed to get capabilities: %s\n", progname, strerror(errno)); exit(1); } return data[0].effective | ((uint64_t) data[1].effective << 32); } static void set_capabilities(uint64_t caps) { /* * This invokes the capset syscall directly to avoid the libcap * dependency, which isn't really justified just for this. */ struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, .pid = 0, }; struct __user_cap_data_struct data[2]; memset(data, 0, sizeof(data)); data[0].effective = data[0].permitted = caps; data[1].effective = data[1].permitted = caps >> 32; if (syscall(SYS_capset, &header, data) == -1) { fprintf(stderr, "%s: Failed to set capabilities: %s\n", progname, strerror(errno)); exit(1); } } static void drop_and_lock_capabilities(void) { /* Set and lock securebits. */ if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS_LOCKED | SECBIT_NO_SETUID_FIXUP | SECBIT_NO_SETUID_FIXUP_LOCKED | SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) == -1) { fprintf(stderr, "%s: Failed to set securebits %s\n", progname, strerror(errno)); exit(1); } /* Clear the capability bounding set. */ int cap; for (cap = 0; ; cap++) { int cap_status = prctl(PR_CAPBSET_READ, cap); if (cap_status == 0) { continue; } if (cap_status == -1 && errno == EINVAL) { break; } if (cap_status != 1) { fprintf(stderr, "%s: Failed to get capability %u: %s\n", progname, cap, strerror(errno)); exit(1); } if (prctl(PR_CAPBSET_DROP, cap) == -1) { fprintf(stderr, "%s: Failed to drop capability %u: %s\n", progname, cap, strerror(errno)); } } /* Drop capabilities. */ set_capabilities(0); /* Prevent re-acquisition of privileges. */ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) { fprintf(stderr, "%s: Failed to set no_new_privs: %s\n", progname, strerror(errno)); exit(1); } } #endif int main(int argc, char *argv[]) { char *type = NULL; char *source; char *dup_source = NULL; const char *mountpoint; char *basename; char *options = NULL; char *command = NULL; char *setuid_name = NULL; int i; int dev = 1; int suid = 1; int pass_fuse_fd = 0; int fuse_fd = 0; int drop_privileges = 0; char *dev_fd_mountpoint = NULL; 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", "nofail", "nouser", "users", "auto", "noauto", "_netdev", NULL}; if (strncmp(opt, "setuid=", 7) == 0) { setuid_name = xstrdup(opt + 7); ignore = 1; } else if (strcmp(opt, "drop_privileges") == 0) { pass_fuse_fd = 1; drop_privileges = 1; 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, ","); } free(opts); } } if (drop_privileges) { uint64_t required_caps = CAP_TO_MASK(CAP_SETPCAP) | CAP_TO_MASK(CAP_SYS_ADMIN); if ((get_capabilities() & required_caps) != required_caps) { 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", progname, progname); exit(1); } } if (dev) options = add_option("dev", options); if (suid) options = add_option("suid", options); if (!type) { if (source) { dup_source = xstrdup(source); type = dup_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); } } if (setuid_name && setuid_name[0]) { #ifdef linux if (drop_privileges) { /* * Make securebits more permissive before calling * setuid(). Specifically, if SECBIT_KEEP_CAPS and * SECBIT_NO_SETUID_FIXUP weren't set, setuid() would * have the side effect of dropping all capabilities, * and we need to retain CAP_SETPCAP in order to drop * all privileges before exec(). */ if (prctl(PR_SET_SECUREBITS, SECBIT_KEEP_CAPS | SECBIT_NO_SETUID_FIXUP) == -1) { fprintf(stderr, "%s: Failed to set securebits %s\n", progname, strerror(errno)); exit(1); } } #endif struct passwd *pwd = getpwnam(setuid_name); if (!pwd || setgid(pwd->pw_gid) == -1 || setuid(pwd->pw_uid) == -1) { fprintf(stderr, "%s: Failed to setuid to %s: %s\n", progname, setuid_name, strerror(errno)); exit(1); } } else if (!getenv("HOME")) { /* Hack to make filesystems work in the boot environment */ setenv("HOME", "/root", 0); } if (pass_fuse_fd) { fuse_fd = prepare_fuse_fd(mountpoint, type, options); dev_fd_mountpoint = xrealloc(NULL, 20); snprintf(dev_fd_mountpoint, 20, "/dev/fd/%u", fuse_fd); mountpoint = dev_fd_mountpoint; } #ifdef linux if (drop_privileges) { drop_and_lock_capabilities(); } #endif add_arg(&command, type); if (source) add_arg(&command, source); add_arg(&command, mountpoint); if (options) { add_arg(&command, "-o"); add_arg(&command, options); } free(options); free(dev_fd_mountpoint); free(dup_source); free(setuid_name); execl("/bin/sh", "/bin/sh", "-c", command, NULL); fprintf(stderr, "%s: failed to execute /bin/sh: %s\n", progname, strerror(errno)); if (pass_fuse_fd) close(fuse_fd); free(command); return 1; } fuse-3.18.3/util/parse-backtrace.sh0000755000175000017500000000535215250106036016064 0ustar berndbernd#!/bin/bash tmpfile=`mktemp backtrace.XXX` PROGRAM_PATH='' TRACE_TYPE=glibc print_help() { echo "Usage: " echo " " `basename $0`" [-s] [-p ] -t <\"full trace\">" echo "Options: " echo " -t '' - The entire trace should be put into quotes" echo " for this option" echo " -p path/to/filename - optional path to the binary, typically" echo " autodetected" echo exit 1 } if [ -z "$1" -o "$1" = "-h" -o "$1" = "--help" ]; then rm -f $tmpfile print_help fi while getopts "hf:t:p:" opt; do case $opt in h) print_help ;; f) PROGRAM_PATH="$OPTARG" ;; t) TRACE="$OPTARG" ;; p) PROGRAM_PATH="$OPTARG" ;; *) print_help ;; esac done # use addr2line parse_glibc_trace() { local trace="$1" local filename="$2" local tmpname="" local symbol="" IFS=$'\n' for line in ${trace}; do #echo "Line: '$line" # remove C2 A0 (non breaking space, as inserted by windows) line=$(echo $line | sed 's/\xC2\xA0/ /g') line=`echo $line | egrep "\[" | egrep "\]"` [ -n "$line" ] || continue # cut off additional syslog part - beginning of line to ':' line=$(echo $line line | sed -e 's/.*://') # parse lines like # /usr/lib/libfuse3.so.3(+0x1c0ef) [0x7fca6061c0ef] filename=$(echo $line | awk '{print $1}' | sed -e 's/(.*$//') if [ -z "${filename}" ]; then echo "Failed to get filename path for line: \"$line\"" return fi if [[ $filename != /* ]]; then if [ -n "${PROGRAM_PATH}" ]; then filename="${PROGRAM_PATH}" else tmpname="$(which $filename)" if [ $? -ne 0 ]; then echo "Failed to get path for '$filename'" continue fi filename="${tmpname}" fi fi # for plain glibc backtrace_symbols the symbol is also in column1, # within the brackets () symbol=$(echo $line | awk '{print $1}' | sed -e 's/^.*(//' | sed -e 's/).*//') if [ -z "${symbol}" ]; then echo "Failed to get symbol for line: \"$line\"" continue fi addr2line -a -p -s -C -f -i -e ${filename} ${symbol} done } if [ -z "$TRACE" ]; then echo "Missing backtrace option!" echo print_help fi # For now only glibc backtrace_symbols traces are supported if [ $TRACE_TYPE = "glibc" ]; then parse_glibc_trace "$TRACE" "${PROGRAM_PATH}" else echo "Unknown tracetype: '${TRACE_TYPE}'" fi rm -f $tmpfile fuse-3.18.3/util/udev.rules0000644000175000017500000000003415250106036014505 0ustar berndberndKERNEL=="fuse", MODE="0666" fuse-3.18.3/xfstests/0000755000175000017500000000000015250106036013377 5ustar berndberndfuse-3.18.3/xfstests/README.md0000644000175000017500000000070215250106036014655 0ustar berndberndTo test FUSE with xfstests¹: 1. copy the `mount.fuse.passthrough` file into `/sbin` and edit the `PASSTHROUGH_PATH`, `SCRATCH_SOURCE` and `TEST_SOURCE` variables as needed. 2. Make sure that the `SCRATCH_SOURCE` and `TEST_SOURCE` directories exist. 3. Copy `local.config` into your xfstests directory Tests can then be run with e.g.: ```sh # make # sudo ./check -fuse -b ``` ¹https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/about/ fuse-3.18.3/xfstests/local.config0000644000175000017500000000131515250106036015660 0ustar berndberndexport TEST_DEV=source:/mnt/src/test export TEST_DIR=/mnt/test export SCRATCH_DEV=source:/mnt/src/scratch export SCRATCH_MNT=/mnt/scratch export FSTYP=fuse export FUSE_SUBTYP=.passthrough export MOUNT_OPTIONS="" export TEST_FS_MOUNT_OPTS="" # extra binary options, such as '--direct-io' or '--nopassthrough', etc export EXTRA_BIN_OPTIONS="" # If PASSTHROUGH_PATH is unset, the mount helper is going to look # for the binary '${FUSE_SUBTYP}', though omitting the leading dot '.'. # Example: # with FUSE_SUBTYP=".passthrough", the mount helper is called # 'mount.fuse.passthrough' and that would try to run # 'passthrough'. # export PASSTHROUGH_PATH=/example/passthrough_hp fuse-3.18.3/xfstests/mount.fuse.passthrough0000755000175000017500000000211315250106036017773 0ustar berndbernd#!/bin/bash ulimit -n 1048576 dev="$1" shift mnt="$1" shift # -o shift mntopts="$1" shift # source can be provided as NFS style device (e.g. TEST_DEV=source:/${TEST_SOURCE}) # and/or it can already be inside mount options (passthrough_ll style) if ( echo "$mntopts" | grep -q "source=" ) ; then # Don't pass source as position argument source= elif [[ "$dev" == "source:"* ]]; then source="${dev#"source:"}" else >&2 echo "passthrough source is undefined, aborting!" fi if ( echo "$mntopts" | grep -q remount ) ; then exec mount -i "$dev" "$mnt" -o "$mntopts" fi # set default to SUBTYPE (extracted from this script name) # example: # Copy or link this script to /sbin/mount.fuse.passthrough_hp # If xfstests local.config does not set PASSTHROUGH_PATH, # PASSTHROUGH_PATH will be set to 'passthrough_hp' and exec below # will look that up from $PATH [ -n "$PASSTHROUGH_PATH" ] || PASSTHROUGH_PATH=${0#*mount.fuse.} #echo "EXTRA_BIN_OPTIONS='${EXTRA_BIN_OPTIONS}'" exec "$PASSTHROUGH_PATH" ${EXTRA_BIN_OPTIONS} -o fsname=$dev,allow_other,dev $source "$mnt" -o "$mntopts" "$@"