Hello community,

here is the log from the commit of package sshfs for openSUSE:Factory checked 
in at 2018-10-04 19:02:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sshfs (Old)
 and      /work/SRC/openSUSE:Factory/.sshfs.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "sshfs"

Thu Oct  4 19:02:22 2018 rev:29 rq:639882 version:2.10

Changes:
--------
--- /work/SRC/openSUSE:Factory/sshfs/sshfs.changes      2017-07-27 
11:13:42.277093877 +0200
+++ /work/SRC/openSUSE:Factory/.sshfs.new/sshfs.changes 2018-10-04 
19:02:29.099140900 +0200
@@ -1,0 +2,20 @@
+Tue Oct  2 17:16:31 UTC 2018 - [email protected]
+
+- sshfs 2.10:
+  * Fix a crash due to a race condition when listing directory contents
+  * Document limited hardlink support
+  * Add support for more SSH options.
+  * Drop support for the nodelay workaround
+  * Drop support for the nodelaysrv workaround
+    The same effect (enabling NODELAY on the server side and
+    enabling X11 forwarding) can be achieved by explicitly passing
+    -o ForwardX11
+  * Remove support for -o workaround=all
+
+-------------------------------------------------------------------
+Tue Oct  2 16:50:34 UTC 2018 - [email protected]
+
+- Add source signature and verify source signature
+- clean up spec file
+
+-------------------------------------------------------------------

Old:
----
  sshfs-2.9.tar.gz

New:
----
  sshfs-2.10.tar.gz
  sshfs-2.10.tar.gz.asc
  sshfs.keyring

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ sshfs.spec ++++++
--- /var/tmp/diff_new_pack.Nvdqwb/_old  2018-10-04 19:02:30.039139911 +0200
+++ /var/tmp/diff_new_pack.Nvdqwb/_new  2018-10-04 19:02:30.039139911 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package sshfs
 #
-# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,18 +17,19 @@
 
 
 Name:           sshfs
-Version:        2.9
+Version:        2.10
 Release:        0
 Summary:        Filesystem client based on SSH file transfer protocol
-License:        GPL-2.0+
+License:        GPL-2.0-or-later
 Group:          System/Filesystems
-Url:            https://github.com/libfuse/sshfs
+URL:            https://github.com/libfuse/sshfs
 Source:         
https://github.com/libfuse/sshfs/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz
-BuildRequires:  automake
-BuildRequires:  fuse-devel
+Source2:        
https://github.com/libfuse/sshfs/releases/download/%{name}-%{version}/%{name}-%{version}.tar.gz.asc
+Source3:        %{name}.keyring
+BuildRequires:  fuse-devel >= 2.3
 BuildRequires:  glib2-devel
-Requires:       fuse
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+BuildRequires:  pkgconfig >= 0.9.0
+Requires:       fuse >= 2.3
 
 %description
 SSHFS is a filesystem client based on the SSH File Transfer Protocol.
@@ -41,17 +42,15 @@
 %setup -q
 
 %build
-%{?suse_update_config:%{suse_update_config -f}}
-autoreconf -fi
-%configure --disable-sshnodelay
-make %{?_smp_mflags} V=1
+%configure
+make %{?_smp_mflags}
 
 %install
-make %{?_smp_mflags} DESTDIR=%{buildroot} install
+%make_install
 
 %files
-%defattr(-,root,root)
-%doc AUTHORS COPYING ChangeLog
+%license COPYING
+%doc AUTHORS
 %{_mandir}/*/*
 %{_bindir}/*
 

++++++ sshfs-2.9.tar.gz -> sshfs-2.10.tar.gz ++++++
++++ 4402 lines of diff (skipped)
++++    retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/AUTHORS new/sshfs-2.10/AUTHORS
--- old/sshfs-2.9/AUTHORS       2017-04-17 22:05:45.000000000 +0200
+++ new/sshfs-2.10/AUTHORS      2017-08-03 18:00:34.000000000 +0200
@@ -21,6 +21,7 @@
 Chris Wolfe <[email protected]>
 gala <[email protected]>
 George Vlahavas <[email protected]>
+Jakub Jelen <[email protected]>
 Julio Merino <[email protected]>
 Julio Merino <[email protected]>
 Mike Kelly <[email protected]>
@@ -30,4 +31,5 @@
 Percy Jahn <[email protected]>
 Qais Patankar <[email protected]>
 Rian Hunter <[email protected]>
+tpoindessous <[email protected]>
 Zoltan Kuscsik <[email protected]>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/ChangeLog new/sshfs-2.10/ChangeLog
--- old/sshfs-2.9/ChangeLog     2017-04-17 22:10:28.000000000 +0200
+++ new/sshfs-2.10/ChangeLog    1970-01-01 01:00:00.000000000 +0100
@@ -1,160 +0,0 @@
-Release 2.9 (2017-04-17)
-------------------------
-
-* Improved support for Cygwin.
-* Various small bugfixes.
-
-Release 2.8 (2016-06-22)
-------------------------
-
-* Added support for the "fsync" extension.
-* Fixed a build problem with bitbake
-
-Release 2.7 (2016-03-01)
-------------------------
-
-* Integrated osxfuse's copy of sshfs, which means that sshfs now works
-  on OS X out of the box.
-* Added -o cache_max_size=N option to let users tune the maximum size of
-  the cache in number of entries.
-* Added -o cache_clean_interval=N and -o cache_min_clean_interval=N
-  options to let users tune the cleaning behavior of the cache.
-
-Release 2.6 (2015-01-28)
-------------------------
-
-* New maintainer (Nikolaus Rath <[email protected]>)
-
-Release 2.5 (2014-01-14)
-------------------------
-
-* Some performance improvements for large directories.
-* New `disable_hardlink` option.
-* Various small bugfixes.
-
-Release 2.4 (2012-03-08)
-------------------------
-
-* New `slave` option.
-* New `idmap`, `uidmap` and `gidmap` options.  
-* Various small bugfixes.
-
-Release 2.3 (2011-07-01)
-------------------------
-
-* Support hard link creation if server is OpenSSH 5.7 or later
-* Small improvements and bug fixes  
-* Check mount point and options before connecting to ssh server
-* New 'delay_connect' option
-
-Release 2.2 (2008-10-20)
-------------------------
-
-* Handle numerical IPv6 addresses enclosed in square brackets
-* Handle commas in usernames
-
-Release 2.1 (2008-07-11)
-------------------------
-
-* Small improvements and bug fixes  
-
-Release 2.0 (2008-04-23)
-------------------------
-
-* Support password authentication with pam_mount
-
-* Support atomic renames if server is OpenSSH 4.9 or later
-
-* Support getting disk usage if server is OpenSSH 5.1 or later
-
-* Small enhancements and bug fixes
-
-What is new in 1.9
-------------------
-
-* Fix a serious bug, that could result in sshfs hanging, crashing, or
-  reporting out-of-memory
-
-What is new in 1.8
-------------------
-
-* Bug fixes
-
-What is new in 1.7
-------------------
-
-* Tolerate servers which print a banner on login
-
-* Small improvements
-
-What is new in 1.6
-------------------
-
-* Workaround for missing truncate operation on old sftp servers
-
-* Bug fixes
-
-What is new in 1.5
-------------------
-
-* Improvements to read performance.  Now both read and write
-  throughput should be very close to 'scp'
-
-* If used with FUSE 2.6.0 or later, then perform better data caching.
-  This should show dramatic speed improvements when a file is opened
-  more than once
-
-* Bug fixes
-
-What is new in 1.4
-------------------
-
-* Updated to version 25 of libfuse API
-
-* This means that the 'cp' of readonly file to sshfs bug is finally
-  solved (as long as using libfuse 2.5.0 or later *and* Linux 2.6.15
-  or later)
-
-* Sshfs now works on FreeBSD
-
-* Added option to "transform" absolute symbolic links
-
-What is new in 1.3
-------------------
-
-* Add workaround for failure to rename to an existing file
-
-* Simple user ID mapping
-
-* Estimate disk usage of files based on size
-
-* Report "infinite" disk space
-
-* Bug fixes
-
-What is new in 1.2
-------------------
-
-* Better compatibility with different sftp servers
-
-* Automatic reconnect (optional)
-
-What is new in 1.1
-------------------
-
-* Performance improvements:
-
-   - directory content caching
-
-   - symlink caching
-
-   - asynchronous writeback
-
-   - readahead
-
-* Fixed '-p' option
-
-What is new in 1.0
-------------------
-
-* Initial release
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/Makefile.am new/sshfs-2.10/Makefile.am
--- old/sshfs-2.9/Makefile.am   2017-04-17 22:03:50.000000000 +0200
+++ new/sshfs-2.10/Makefile.am  2017-08-03 18:00:34.000000000 +0200
@@ -2,6 +2,8 @@
 
 bin_PROGRAMS = sshfs
 
+SUBDIRS = test
+
 sshfs_SOURCES = sshfs.c cache.c cache.h
 if FUSE_OPT_COMPAT
 sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h
@@ -15,28 +17,14 @@
 sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" \
                  -DIDMAP_DEFAULT="\"$(IDMAP_DEFAULT)\""
 
-EXTRA_DIST = sshnodelay.c sshfs.1.in
-CLEANFILES = sshnodelay.so sshfs.1 sshfs.1.tmp
+EXTRA_DIST = sshfs.1.in meson.build
+CLEANFILES = sshfs.1 sshfs.1.tmp
 
 dist_man_MANS = sshfs.1
 
 sshfs.1: sshfs.1.in
        $(AM_V_GEN)sed \
-           -e 's,__IDMAP_DEFAULT__,$(IDMAP_DEFAULT),g' \
-           -e 's,__UNMOUNT_COMMAND__,$(UNMOUNT_COMMAND),g' \
+           -e 's/[@]IDMAP_DEFAULT@/$(IDMAP_DEFAULT)/g' \
+           -e 's/[@]UNMOUNT_COMMAND@/$(UNMOUNT_COMMAND)/g' \
            <$(srcdir)/sshfs.1.in >sshfs.1.tmp || exit 1; \
        mv sshfs.1.tmp sshfs.1
-
-if SSH_NODELAY_SO
-all-local: sshnodelay.so
-
-install-exec-local: sshnodelay.so
-       test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
-       $(INSTALL) -m 755 sshnodelay.so "$(DESTDIR)$(libdir)/sshnodelay.so"
-
-uninstall-local:
-       rm -f "$(DESTDIR)$(libdir)/sshnodelay.so"
-
-sshnodelay.so:
-       $(CC) -Wall -W -s --shared -fPIC $(sshnodelay_libs) sshnodelay.c -o 
sshnodelay.so
-endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/compile new/sshfs-2.10/compile
--- old/sshfs-2.9/compile       2016-01-29 02:13:22.000000000 +0100
+++ new/sshfs-2.10/compile      2017-08-03 17:53:13.000000000 +0200
@@ -3,7 +3,7 @@
 
 scriptversion=2012-10-14.11; # UTC
 
-# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Copyright (C) 1999-2014 Free Software Foundation, Inc.
 # Written by Tom Tromey <[email protected]>.
 #
 # This program is free software; you can redistribute it and/or modify
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/config.h.in new/sshfs-2.10/config.h.in
--- old/sshfs-2.9/config.h.in   2017-04-17 22:13:13.000000000 +0200
+++ new/sshfs-2.10/config.h.in  2017-08-03 18:00:47.000000000 +0200
@@ -21,8 +21,5 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
-/* Compile ssh NODELAY workaround */
-#undef SSH_NODELAY_WORKAROUND
-
 /* Version number of package */
 #undef VERSION
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/configure.ac new/sshfs-2.10/configure.ac
--- old/sshfs-2.9/configure.ac  2017-04-17 22:05:56.000000000 +0200
+++ new/sshfs-2.10/configure.ac 2017-08-03 18:00:34.000000000 +0200
@@ -1,4 +1,4 @@
-AC_INIT(sshfs, 2.9)
+AC_INIT(sshfs, 2.10)
 AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AM_CONFIG_HEADER(config.h)
@@ -8,8 +8,6 @@
 CFLAGS="$CFLAGS -Wall -W"
 LIBS=
 AC_SEARCH_LIBS(dlsym, [dl])
-sshnodelay_libs=$LIBS
-AC_SUBST(sshnodelay_libs)
 LIBS=
 
 case "$target_os" in
@@ -18,31 +16,6 @@
     *) osname=unknown;;
 esac
 
-AC_ARG_ENABLE(sshnodelay,
-       [  --disable-sshnodelay    Don't compile NODELAY workaround for ssh])
-
-if test -z "$enable_sshnodelay"; then
-       AC_MSG_CHECKING([OpenSSH version])
-       [eval `ssh -V 2>&1 | sed -n 
's/^OpenSSH_\([1-9][0-9]*\)\.\([0-9][0-9]*\).*/ssh_major=\1 ssh_minor=\2/p'`]
-       if test "x$ssh_major" != x -a "x$ssh_minor" != x; then
-               if test $ssh_major -gt 4 -o \( $ssh_major = 4 -a $ssh_minor -ge 
4 \); then
-                       AC_MSG_RESULT([$ssh_major.$ssh_minor >= 4.4, disabling 
NODELAY workaround])
-                       enable_sshnodelay=no
-               else
-                       AC_MSG_RESULT([$ssh_major.$ssh_minor < 4.4, enabling 
NODELAY workaround])
-                       enable_sshnodelay=yes
-               fi
-       else
-               AC_MSG_RESULT([not found])
-       fi
-fi
-
-if test "$enable_sshnodelay" = "yes"; then
-       AC_DEFINE(SSH_NODELAY_WORKAROUND, 1, [Compile ssh NODELAY workaround])
-fi
-
-AM_CONDITIONAL(SSH_NODELAY_SO, test "$enable_sshnodelay" = "yes")
-
 export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
 PKG_CHECK_MODULES([SSHFS], [fuse >= 2.3 glib-2.0 gthread-2.0])
 have_fuse_opt_parse=no
@@ -67,5 +40,5 @@
 esac
 AC_SUBST(IDMAP_DEFAULT)
 
-AC_CONFIG_FILES([Makefile])
+AC_CONFIG_FILES([Makefile test/Makefile])
 AC_OUTPUT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/meson.build new/sshfs-2.10/meson.build
--- old/sshfs-2.9/meson.build   1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/meson.build  2017-08-03 18:00:34.000000000 +0200
@@ -0,0 +1,64 @@
+project('sshfs', 'c', version: '2.10.0',
+        meson_version: '>= 0.38',
+        default_options: [ 'buildtype=plain' ])
+
+add_global_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H', '-O2', '-g',
+                     '-Wall', '-Wextra', '-Wno-sign-compare',
+                     '-Wmissing-declarations', '-Wwrite-strings',
+                     language: 'c')
+
+# 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.
+cc = meson.get_compiler('c')
+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_global_arguments('-Wno-unused-result', language: 'c')
+endif
+
+
+cfg = configuration_data()
+
+cfg.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+include_dirs = [ include_directories('.') ]
+sshfs_sources = ['sshfs.c', 'cache.c']
+if target_machine.system() == 'darwin'
+  cfg.set_quoted('IDMAP_DEFAULT', 'user')
+  sshfs_sources += [ 'compat/fuse_opt.c', 'compat/darwin_compat.c' ]
+  include_dirs += [ include_directories('compat') ]
+else
+  cfg.set_quoted('IDMAP_DEFAULT', 'none')
+endif
+
+configure_file(input: 'sshfs.1.in',
+               output: 'sshfs.1',
+               configuration : cfg)
+configure_file(output: 'config.h',
+               configuration : cfg)
+
+sshfs_deps = [ dependency('fuse', version: '>= 2.3'),
+               dependency('glib-2.0'),
+               dependency('gthread-2.0') ]
+
+executable('sshfs', sshfs_sources,
+           include_directories: include_dirs,
+           dependencies: sshfs_deps,
+           c_args: ['-DFUSE_USE_VERSION=26'],
+           install: true,
+           install_dir: get_option('bindir'))
+
+# This is a little ugly. Is there a better way to tell Meson that the
+# manpage is in the build directory?
+install_man(join_paths(meson.current_build_dir(), 'sshfs.1'))
+
+subdir('test')
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/missing new/sshfs-2.10/missing
--- old/sshfs-2.9/missing       2016-01-29 02:13:22.000000000 +0100
+++ new/sshfs-2.10/missing      2017-08-03 17:53:13.000000000 +0200
@@ -3,7 +3,7 @@
 
 scriptversion=2013-10-28.13; # UTC
 
-# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Copyright (C) 1996-2014 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <[email protected]>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/sshfs.1.in new/sshfs-2.10/sshfs.1.in
--- old/sshfs-2.9/sshfs.1.in    2017-04-17 22:03:50.000000000 +0200
+++ new/sshfs-2.10/sshfs.1.in   2017-07-12 17:06:18.000000000 +0200
@@ -7,7 +7,7 @@
 \fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP 
[\fIoptions\fP]
 .SS unmounting
 .TP
-\fB__UNMOUNT_COMMAND__ mountpoint\fP
+\fB@UNMOUNT_COMMAND@ mountpoint\fP
 .SH DESCRIPTION
 SSHFS (Secure SHell FileSystem) is a file system for Linux (and other
 operating systems with a FUSE implementation, such as Mac OS X or FreeBSD)
@@ -97,7 +97,7 @@
 .RE
 .TP
 \fB\-o\fR idmap=TYPE
-user/group ID mapping (default: __IDMAP_DEFAULT__)
+user/group ID mapping (default: @IDMAP_DEFAULT@)
 .RS 8
 .TP
 none
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/sshfs.c new/sshfs-2.10/sshfs.c
--- old/sshfs-2.9/sshfs.c       2017-04-17 22:03:50.000000000 +0200
+++ new/sshfs-2.10/sshfs.c      2017-08-03 17:51:39.000000000 +0200
@@ -132,8 +132,6 @@
 
 #define SFTP_SERVER_PATH "/usr/lib/sftp-server"
 
-#define SSHNODELAY_SO "sshnodelay.so"
-
 /* Asynchronous readdir parameters */
 #define READDIR_START 2
 #define READDIR_MAX 32
@@ -216,8 +214,6 @@
        struct fuse_args ssh_args;
        char *workarounds;
        int rename_workaround;
-       int nodelay_workaround;
-       int nodelaysrv_workaround;
        int truncate_workaround;
        int buflimit_workaround;
        int fstat_workaround;
@@ -297,6 +293,7 @@
        "AddressFamily",
        "BatchMode",
        "BindAddress",
+       "CertificateFile",
        "ChallengeResponseAuthentication",
        "CheckHostIP",
        "Cipher",
@@ -307,28 +304,40 @@
        "ConnectTimeout",
        "ControlMaster",
        "ControlPath",
+       "ControlPersist",
+       "FingerprintHash",
        "GlobalKnownHostsFile",
        "GSSAPIAuthentication",
        "GSSAPIDelegateCredentials",
        "HostbasedAuthentication",
+       "HostbasedKeyTypes",
        "HostKeyAlgorithms",
        "HostKeyAlias",
        "HostName",
        "IdentitiesOnly",
        "IdentityFile",
+       "IdentityAgent",
+       "IPQoS",
        "KbdInteractiveAuthentication",
        "KbdInteractiveDevices",
+       "KexAlgorithms",
        "LocalCommand",
        "LogLevel",
        "MACs",
        "NoHostAuthenticationForLocalhost",
        "NumberOfPasswordPrompts",
        "PasswordAuthentication",
+       "PermitLocalCommand",
+       "PKCS11Provider",
        "Port",
        "PreferredAuthentications",
        "ProxyCommand",
+       "ProxyJump",
+       "ProxyUseFdpass",
+       "PubkeyAcceptedKeyTypes"
        "PubkeyAuthentication",
        "RekeyLimit",
+       "RevokedHostKeys",
        "RhostsRSAAuthentication",
        "RSAAuthentication",
        "ServerAliveCountMax",
@@ -336,9 +345,11 @@
        "SmartcardDevice",
        "StrictHostKeyChecking",
        "TCPKeepAlive",
+       "UpdateHostKeys",
        "UsePrivilegedPort",
        "UserKnownHostsFile",
        "VerifyHostKeyDNS",
+       "VisualHostKey",
        NULL,
 };
 
@@ -408,23 +419,11 @@
 
 static struct fuse_opt workaround_opts[] = {
        SSHFS_OPT("none",       rename_workaround, 0),
-       SSHFS_OPT("none",       nodelay_workaround, 0),
-       SSHFS_OPT("none",       nodelaysrv_workaround, 0),
        SSHFS_OPT("none",       truncate_workaround, 0),
        SSHFS_OPT("none",       buflimit_workaround, 0),
        SSHFS_OPT("none",       fstat_workaround, 0),
-       SSHFS_OPT("all",        rename_workaround, 1),
-       SSHFS_OPT("all",        nodelay_workaround, 1),
-       SSHFS_OPT("all",        nodelaysrv_workaround, 1),
-       SSHFS_OPT("all",        truncate_workaround, 1),
-       SSHFS_OPT("all",        buflimit_workaround, 1),
-       SSHFS_OPT("all",        fstat_workaround, 1),
        SSHFS_OPT("rename",     rename_workaround, 1),
        SSHFS_OPT("norename",   rename_workaround, 0),
-       SSHFS_OPT("nodelay",    nodelay_workaround, 1),
-       SSHFS_OPT("nonodelay",  nodelay_workaround, 0),
-       SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1),
-       SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0),
        SSHFS_OPT("truncate",   truncate_workaround, 1),
        SSHFS_OPT("notruncate", truncate_workaround, 0),
        SSHFS_OPT("buflimit",   buflimit_workaround, 1),
@@ -877,85 +876,6 @@
                _exit(1);
 }
 
-#ifdef SSH_NODELAY_WORKAROUND
-static int do_ssh_nodelay_workaround(void)
-{
-#ifdef __APPLE__
-       char *oldpreload = getenv("DYLD_INSERT_LIBRARIES");
-#else
-       char *oldpreload = getenv("LD_PRELOAD");
-#endif
-       char *newpreload;
-       char sopath[PATH_MAX];
-       int res;
-
-#ifdef __APPLE__
-       char *sshfs_program_path_base = NULL;
-       if (!sshfs_program_path[0]) {
-               goto nobundle;
-       }
-       sshfs_program_path_base = dirname(sshfs_program_path);
-       if (!sshfs_program_path_base) {
-               goto nobundle;
-       }
-       snprintf(sopath, sizeof(sopath), "%s/%s", sshfs_program_path_base,
-             SSHNODELAY_SO);
-       res = access(sopath, R_OK);
-       if (res == -1) {
-               goto nobundle;
-       }
-       goto pathok;
-
-nobundle:
-#endif /* __APPLE__ */
-
-       snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
-       res = access(sopath, R_OK);
-       if (res == -1) {
-               char *s;
-               if (!realpath(sshfs.progname, sopath))
-                       return -1;
-
-               s = strrchr(sopath, '/');
-               if (!s)
-                       s = sopath;
-               else
-                       s++;
-
-               if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath))
-                       return -1;
-
-               strcpy(s, SSHNODELAY_SO);
-               res = access(sopath, R_OK);
-               if (res == -1) {
-                       fprintf(stderr, "sshfs: cannot find %s\n",
-                               SSHNODELAY_SO);
-                       return -1;
-               }
-       }
-
-#ifdef __APPLE__
-pathok:
-#endif
-
-       newpreload = g_strdup_printf("%s%s%s",
-                                    oldpreload ? oldpreload : "",
-                                    oldpreload ? " " : "",
-                                    sopath);
-
-#ifdef __APPLE__
-       if (!newpreload || setenv("DYLD_INSERT_LIBRARIES", newpreload, 1) == -1)
-               fprintf(stderr, "warning: failed set DYLD_INSERT_LIBRARIES for 
ssh nodelay workaround\n");
-#else /* !__APPLE__ */
-       if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
-               fprintf(stderr, "warning: failed set LD_PRELOAD "
-                       "for ssh nodelay workaround\n");
-       }
-#endif /* __APPLE__ */
-       g_free(newpreload);
-       return 0;
-}
-#endif
 
 static int pty_expect_loop(void)
 {
@@ -1089,29 +1009,6 @@
        } else if (pid == 0) {
                int devnull;
 
-#ifdef SSH_NODELAY_WORKAROUND
-               if (sshfs.nodelay_workaround &&
-                   do_ssh_nodelay_workaround() == -1) {
-                       fprintf(stderr,
-                               "warning: ssh nodelay workaround disabled\n");
-               }
-#endif
-
-               if (sshfs.nodelaysrv_workaround) {
-                       int i;
-                       /*
-                        * Hack to work around missing TCP_NODELAY
-                        * setting in sshd
-                        */
-                       for (i = 1; i < sshfs.ssh_args.argc; i++) {
-                               if (strcmp(sshfs.ssh_args.argv[i], "-x") == 0) {
-                                       replace_arg(&sshfs.ssh_args.argv[i],
-                                                   "-X");
-                                       break;
-                               }
-                       }
-               }
-
                devnull = open("/dev/null", O_WRONLY);
 
                if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) {
@@ -2000,6 +1897,9 @@
                           &buf, SSH_FXP_ATTRS, &outbuf);
        if (!err) {
                err = buf_get_attrs(&outbuf, stbuf, NULL);
+#ifdef __APPLE__
+               stbuf->st_blksize = 0;
+#endif
                buf_free(&outbuf);
        }
        buf_free(&buf);
@@ -2175,11 +2075,16 @@
                        outstanding--;
 
                        if (done) {
+                               /* We need to cache want_reply, since processing
+                                  thread may free req right after unlock() if
+                                  want_reply == 0 */
+                               int want_reply;
                                pthread_mutex_lock(&sshfs.lock);
                                if (sshfs_req_pending(req))
                                        req->want_reply = 0;
+                               want_reply = req->want_reply;
                                pthread_mutex_unlock(&sshfs.lock);
-                               if (!req->want_reply)
+                               if (!want_reply)
                                        continue;
                        }
 
@@ -2642,7 +2547,8 @@
        int err;
        (void) isdatasync;
 
-       if (err = sshfs_flush(path, fi))
+        err = sshfs_flush(path, fi);
+        if (err)
                return err;
 
        if (!sshfs.ext_fsync)
@@ -3203,6 +3109,9 @@
        err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
        if (!err) {
                err = buf_get_attrs(&outbuf, stbuf, NULL);
+#ifdef __APPLE__
+               stbuf->st_blksize = 0;
+#endif
                buf_free(&outbuf);
        }
        buf_free(&buf);
@@ -3416,14 +3325,10 @@
 "                           cache if full (default: 5)\n"
 "    -o workaround=LIST     colon separated list of workarounds\n"
 "             none             no workarounds enabled\n"
-"             all              all workarounds enabled\n"
 "             [no]rename       fix renaming to existing file (default: off)\n"
-#ifdef SSH_NODELAY_WORKAROUND
-"             [no]nodelay      set nodelay tcp flag in ssh (default: on)\n"
-#endif
-"             [no]nodelaysrv   set nodelay tcp flag in sshd (default: off)\n"
 "             [no]truncate     fix truncate for old servers (default: off)\n"
 "             [no]buflimit     fix buffer fillup bug in server (default: on)\n"
+"             [no]fstat        fix fstat for old servers (default: off)\n"
 "    -o idmap=TYPE          user/group ID mapping (default: " IDMAP_DEFAULT 
")\n"
 "             none             no translation of the ID space\n"
 "             user             only translate UID/GID of connecting user\n"
@@ -3543,10 +3448,14 @@
        return -1;
 }
 
-int parse_workarounds(void)
+static int parse_workarounds(void)
 {
        int res;
-       char *argv[] = { "", "-o", sshfs.workarounds, NULL };
+        /* Need separate variables because literals are const
+           char */
+        char argv0[] = "";
+        char argv1[] = "-o";
+       char *argv[] = { argv0, argv1, sshfs.workarounds, NULL };
        struct fuse_args args = FUSE_ARGS_INIT(3, argv);
        char *s = sshfs.workarounds;
        if (!s)
@@ -3952,14 +3861,11 @@
                memset(sshfs_program_path, 0, PATH_MAX);
        }
 #endif /* __APPLE__ */
-       g_thread_init(NULL);
 
        sshfs.blksize = 4096;
        /* SFTP spec says all servers should allow at least 32k I/O */
        sshfs.max_read = 32768;
        sshfs.max_write = 32768;
-       sshfs.nodelay_workaround = 1;
-       sshfs.nodelaysrv_workaround = 0;
 #ifdef __APPLE__
        sshfs.rename_workaround = 1;
 #else
@@ -4115,7 +4021,7 @@
                char *mountpoint;
                int multithreaded;
                int foreground;
-#if !defined(__CYGWIN__)
+#if !defined(__APPLE__) && !defined(__CYGWIN__)
                struct stat st;
 #endif
 
@@ -4129,14 +4035,14 @@
                        foreground = 1;
                }
 
-#if !defined(__CYGWIN__)
+#if !defined(__APPLE__) && !defined(__CYGWIN__)
                res = stat(mountpoint, &st);
                if (res == -1) {
                        perror(mountpoint);
                        exit(1);
                }
                sshfs.mnt_mode = st.st_mode;
-#elif defined(__CYGWIN__)
+#else
                sshfs.mnt_mode = S_IFDIR | 0755;
 #endif
 
@@ -4158,6 +4064,13 @@
                        exit(1);
                }
 
+                res = fuse_set_signal_handlers(fuse_get_session(fuse));
+               if (res == -1) {
+                       fuse_unmount(mountpoint, ch);
+                       fuse_destroy(fuse);
+                       exit(1);
+               }
+
                /*
                 * FIXME: trim $PATH so it doesn't contain anything inside the
                 * mountpoint, which would deadlock.
@@ -4170,9 +4083,6 @@
                }
 
                res = fuse_daemonize(foreground);
-               if (res != -1)
-                       res = fuse_set_signal_handlers(fuse_get_session(fuse));
-
                if (res == -1) {
                        fuse_unmount(mountpoint, ch);
                        fuse_destroy(fuse);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/sshnodelay.c new/sshfs-2.10/sshnodelay.c
--- old/sshfs-2.9/sshnodelay.c  2016-02-11 04:54:13.000000000 +0100
+++ new/sshfs-2.10/sshnodelay.c 1970-01-01 01:00:00.000000000 +0100
@@ -1,59 +0,0 @@
-#define _GNU_SOURCE
-#include <dlfcn.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-/* Wrapper around connect(2) to explicitly set TCP_NODELAY. */
-static int nodelay_connect(
-    int (*real_connect)(int, const struct sockaddr *, socklen_t),
-    int sock, const struct sockaddr *addr, socklen_t addrlen)
-{
-       int res = real_connect(sock, addr, addrlen);
-       if (!res && addr->sa_family == AF_INET) {
-               int opt = 1;
-               setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
-       }
-       return res;
-}
-
-#if __APPLE__
-
-/* OS X does not have LD_PRELOAD but has DYLD_INSERT_LIBRARIES.  The right
- * environment variable is set by sshfs.c when attempting to load the
- * sshnodelay workaround.
- *
- * However, things are not that simple: DYLD_INSERT_LIBRARIES does not
- * behave exactly like LD_PRELOAD.  Instead, the dyld dynamic linker will
- * look for __DATA __interpose sections on the libraries given via the
- * DYLD_INSERT_LIBRARIES variable.  The contents of this section are pairs
- * of replacement functions and functions to be replaced, respectively.
- * Prepare such section here. */
-
-int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen);
-
-typedef struct interpose_s {
-       void *new_func;
-       void *orig_func;
-} interpose_t;
-
-static const interpose_t interposers[] \
-       __attribute__ ((section("__DATA, __interpose"))) = {
-       { (void *)custom_connect,  (void *)connect  },
-};
-
-int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
-{
-       return nodelay_connect(connect, sock, addr, addrlen);
-}
-
-#else /* !__APPLE__ */
-
-int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
-{
-       return nodelay_connect(dlsym(RTLD_NEXT, "connect"),
-                              sock, addr, addrlen);
-}
-
-#endif /* !__APPLE__ */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/Makefile.am new/sshfs-2.10/test/Makefile.am
--- old/sshfs-2.9/test/Makefile.am      1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/Makefile.am     2017-08-03 18:00:34.000000000 +0200
@@ -0,0 +1,4 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = meson.build conftest.py pytest.ini test_sshfs.py \
+            util.py wrong_command.c
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/conftest.py new/sshfs-2.10/test/conftest.py
--- old/sshfs-2.9/test/conftest.py      1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/conftest.py     2017-07-12 17:10:18.000000000 +0200
@@ -0,0 +1,89 @@
+import sys
+import pytest
+import time
+import re
+
+# If a test fails, wait a moment before retrieving the captured
+# stdout/stderr. When using a server process, this makes sure that we capture
+# any potential output of the server that comes *after* a test has failed. For
+# example, if a request handler raises an exception, the server first signals 
an
+# error to FUSE (causing the test to fail), and then logs the exception. 
Without
+# the extra delay, the exception will go into nowhere.
[email protected]
+def pytest_pyfunc_call(pyfuncitem):
+    outcome = yield
+    failed = outcome.excinfo is not None
+    if failed:
+        time.sleep(1)
+
[email protected]()
+def pass_capfd(request, capfd):
+    '''Provide capfd object to UnitTest instances'''
+    request.instance.capfd = capfd
+
+def check_test_output(capfd):
+    (stdout, stderr) = capfd.readouterr()
+
+    # Write back what we've read (so that it will still be printed.
+    sys.stdout.write(stdout)
+    sys.stderr.write(stderr)
+
+    # Strip out false positives
+    for (pattern, flags, count) in capfd.false_positives:
+        cp = re.compile(pattern, flags)
+        (stdout, cnt) = cp.subn('', stdout, count=count)
+        if count == 0 or count - cnt > 0:
+            stderr = cp.sub('', stderr, count=count - cnt)
+
+    patterns = [ r'\b{}\b'.format(x) for x in
+                 ('exception', 'error', 'warning', 'fatal', 'traceback',
+                    'fault', 'crash(?:ed)?', 'abort(?:ed)',
+                    'uninitiali[zs]ed') ]
+    patterns += ['^==[0-9]+== ']
+    for pattern in patterns:
+        cp = re.compile(pattern, re.IGNORECASE | re.MULTILINE)
+        hit = cp.search(stderr)
+        if hit:
+            raise AssertionError('Suspicious output to stderr (matched "%s")' 
% hit.group(0))
+        hit = cp.search(stdout)
+        if hit:
+            raise AssertionError('Suspicious output to stdout (matched "%s")' 
% hit.group(0))
+
+def register_output(self, pattern, count=1, flags=re.MULTILINE):
+    '''Register *pattern* as false positive for output checking
+
+    This prevents the test from failing because the output otherwise
+    appears suspicious.
+    '''
+
+    self.false_positives.append((pattern, flags, count))
+
+# This is a terrible hack that allows us to access the fixtures from the
+# pytest_runtest_call hook. Among a lot of other hidden assumptions, it 
probably
+# relies on tests running sequential (i.e., don't dare to use e.g. the xdist
+# plugin)
+current_capfd = None
[email protected]_fixture(autouse=True)
+def save_cap_fixtures(request, capfd):
+    global current_capfd
+    capfd.false_positives = []
+
+    # Monkeypatch in a function to register false positives
+    type(capfd).register_output = register_output
+
+    if request.config.getoption('capture') == 'no':
+        capfd = None
+    current_capfd = capfd
+    bak = current_capfd
+    yield
+
+    # Try to catch problems with this hack (e.g. when running tests
+    # simultaneously)
+    assert bak is current_capfd
+    current_capfd = None
+
[email protected](trylast=True)
+def pytest_runtest_call(item):
+    capfd = current_capfd
+    if capfd is not None:
+        check_test_output(capfd)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/meson.build new/sshfs-2.10/test/meson.build
--- old/sshfs-2.9/test/meson.build      1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/meson.build     2017-07-12 17:10:18.000000000 +0200
@@ -0,0 +1,11 @@
+test_scripts = [ 'conftest.py', 'pytest.ini', 'test_sshfs.py',
+                 'util.py' ]
+custom_target('test_scripts', input: test_scripts,
+              output: test_scripts, build_by_default: true,
+              command: ['cp', '-fPu', '--preserve=mode',
+                        '@INPUT@', meson.current_build_dir() ])
+
+# Provide something helpful when running 'ninja test'
+wrong_cmd = executable('wrong_command', 'wrong_command.c',
+                       install: false)
+test('wrong_cmd', wrong_cmd)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/pytest.ini new/sshfs-2.10/test/pytest.ini
--- old/sshfs-2.9/test/pytest.ini       1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/pytest.ini      2017-07-12 17:10:18.000000000 +0200
@@ -0,0 +1,2 @@
+[pytest]
+addopts = --verbose --assert=rewrite --tb=native -x -r a
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/test_sshfs.py new/sshfs-2.10/test/test_sshfs.py
--- old/sshfs-2.9/test/test_sshfs.py    1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/test_sshfs.py   2017-08-03 17:51:39.000000000 +0200
@@ -0,0 +1,378 @@
+#!/usr/bin/env python3
+
+if __name__ == '__main__':
+    import pytest
+    import sys
+    sys.exit(pytest.main([__file__] + sys.argv[1:]))
+
+import subprocess
+import os
+import sys
+import pytest
+import stat
+import shutil
+import filecmp
+import errno
+from tempfile import NamedTemporaryFile
+from util import (wait_for_mount, umount, cleanup, base_cmdline,
+                  basename, fuse_test_marker, safe_sleep)
+from os.path import join as pjoin
+
+TEST_FILE = __file__
+
+pytestmark = fuse_test_marker()
+
+with open(TEST_FILE, 'rb') as fh:
+    TEST_DATA = fh.read()
+
+def name_generator(__ctr=[0]):
+    __ctr[0] += 1
+    return 'testfile_%d' % __ctr[0]
+
[email protected]("debug", (False, True))
[email protected]("cache_timeout", (0, 1))
+def test_sshfs(tmpdir, debug, cache_timeout, capfd):
+    
+    # Avoid false positives from debug messages
+    #if debug:
+    #    capfd.register_output(r'^   unique: [0-9]+, error: -[0-9]+ .+$',
+    #                          count=0)
+
+    # Test if we can ssh into localhost without password
+    try:
+        res = subprocess.call(['ssh', '-o', 'KbdInteractiveAuthentication=no',
+                               '-o', 'ChallengeResponseAuthentication=no',
+                               '-o', 'PasswordAuthentication=no',
+                               'localhost', '--', 'true'], 
stdin=subprocess.DEVNULL,
+                              timeout=10)
+    except subprocess.TimeoutExpired:
+        res = 1
+    if res != 0:
+        pytest.fail('Unable to ssh into localhost without password prompt.')
+
+    mnt_dir = str(tmpdir.mkdir('mnt'))
+    src_dir = str(tmpdir.mkdir('src'))
+
+    cmdline = base_cmdline + [ pjoin(basename, 'sshfs'),
+                               '-f', 'localhost:' + src_dir, mnt_dir ]
+    if debug:
+        cmdline += [ '-o', 'sshfs_debug' ]
+
+    # SSHFS Cache
+    if cache_timeout == 0:
+        cmdline += [ '-o', 'cache=no' ]
+    else:
+        cmdline += [ '-o', 'cache_timeout=%d' % cache_timeout ]
+
+    # FUSE Cache
+    cmdline += [ '-o', 'entry_timeout=0',
+                 '-o', 'attr_timeout=0' ]
+
+    
+    new_env = dict(os.environ) # copy, don't modify
+
+    # Abort on warnings from glib
+    new_env['G_DEBUG'] = 'fatal-warnings'
+    
+    mount_process = subprocess.Popen(cmdline, env=new_env)
+    try:
+        wait_for_mount(mount_process, mnt_dir)
+
+        tst_statvfs(mnt_dir)
+        tst_readdir(src_dir, mnt_dir)
+        tst_open_read(src_dir, mnt_dir)
+        tst_open_write(src_dir, mnt_dir)
+        tst_create(mnt_dir)
+        tst_passthrough(src_dir, mnt_dir, cache_timeout)
+        tst_mkdir(mnt_dir)
+        tst_rmdir(src_dir, mnt_dir, cache_timeout)
+        tst_unlink(src_dir, mnt_dir, cache_timeout)
+        tst_symlink(mnt_dir)
+        if os.getuid() == 0:
+            tst_chown(mnt_dir)
+
+        # SSHFS only supports one second resolution when setting
+        # file timestamps.
+        tst_utimens(mnt_dir, tol=1)
+
+        tst_link(mnt_dir)
+        tst_truncate_path(mnt_dir)
+        tst_truncate_fd(mnt_dir)
+        tst_open_unlink(mnt_dir)
+    except:
+        cleanup(mnt_dir)
+        raise
+    else:
+        umount(mount_process, mnt_dir)
+
+def tst_unlink(src_dir, mnt_dir, cache_timeout):
+    name = name_generator()
+    fullname = mnt_dir + "/" + name
+    with open(pjoin(src_dir, name), 'wb') as fh:
+        fh.write(b'hello')
+    if cache_timeout:
+        safe_sleep(cache_timeout+1)
+    assert name in os.listdir(mnt_dir)
+    os.unlink(fullname)
+    with pytest.raises(OSError) as exc_info:
+        os.stat(fullname)
+    assert exc_info.value.errno == errno.ENOENT
+    assert name not in os.listdir(mnt_dir)
+    assert name not in os.listdir(src_dir)
+
+def tst_mkdir(mnt_dir):
+    dirname = name_generator()
+    fullname = mnt_dir + "/" + dirname
+    os.mkdir(fullname)
+    fstat = os.stat(fullname)
+    assert stat.S_ISDIR(fstat.st_mode)
+    assert os.listdir(fullname) ==  []
+    assert fstat.st_nlink in (1,2)
+    assert dirname in os.listdir(mnt_dir)
+
+def tst_rmdir(src_dir, mnt_dir, cache_timeout):
+    name = name_generator()
+    fullname = mnt_dir + "/" + name
+    os.mkdir(pjoin(src_dir, name))
+    if cache_timeout:
+        safe_sleep(cache_timeout+1)
+    assert name in os.listdir(mnt_dir)
+    os.rmdir(fullname)
+    with pytest.raises(OSError) as exc_info:
+        os.stat(fullname)
+    assert exc_info.value.errno == errno.ENOENT
+    assert name not in os.listdir(mnt_dir)
+    assert name not in os.listdir(src_dir)
+
+def tst_symlink(mnt_dir):
+    linkname = name_generator()
+    fullname = mnt_dir + "/" + linkname
+    os.symlink("/imaginary/dest", fullname)
+    fstat = os.lstat(fullname)
+    assert stat.S_ISLNK(fstat.st_mode)
+    assert os.readlink(fullname) == "/imaginary/dest"
+    assert fstat.st_nlink == 1
+    assert linkname in os.listdir(mnt_dir)
+
+def tst_create(mnt_dir):
+    name = name_generator()
+    fullname = pjoin(mnt_dir, name)
+    with pytest.raises(OSError) as exc_info:
+        os.stat(fullname)
+    assert exc_info.value.errno == errno.ENOENT
+    assert name not in os.listdir(mnt_dir)
+
+    fd = os.open(fullname, os.O_CREAT | os.O_RDWR)
+    os.close(fd)
+
+    assert name in os.listdir(mnt_dir)
+    fstat = os.lstat(fullname)
+    assert stat.S_ISREG(fstat.st_mode)
+    assert fstat.st_nlink == 1
+    assert fstat.st_size == 0
+
+def tst_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)
+    assert fstat.st_uid == uid_new
+    assert fstat.st_gid == gid
+
+    gid_new = gid + 1
+    os.chown(filename, -1, gid_new)
+    fstat = os.lstat(filename)
+    assert fstat.st_uid == uid_new
+    assert fstat.st_gid == gid_new
+
+def tst_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)
+
+    assert filecmp.cmp(pjoin(mnt_dir, name), TEST_FILE, False)
+
+def tst_open_write(src_dir, mnt_dir):
+    name = name_generator()
+    fd = os.open(pjoin(src_dir, name),
+                 os.O_CREAT | os.O_RDWR)
+    os.close(fd)
+    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)
+
+    assert filecmp.cmp(fullname, TEST_FILE, False)
+
+def tst_open_unlink(mnt_dir):
+    name = pjoin(mnt_dir, 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)
+        with pytest.raises(OSError) as exc_info:
+            os.stat(fullname)
+            assert exc_info.value.errno == errno.ENOENT
+        assert name not in os.listdir(mnt_dir)
+        fh.write(data2)
+        fh.seek(0)
+        assert fh.read() == data1+data2
+
+def tst_statvfs(mnt_dir):
+    os.statvfs(mnt_dir)
+
+def tst_link(mnt_dir):
+    name1 = pjoin(mnt_dir, name_generator())
+    name2 = pjoin(mnt_dir, name_generator())
+    shutil.copyfile(TEST_FILE, name1)
+    assert filecmp.cmp(name1, TEST_FILE, False)
+
+    fstat1 = os.lstat(name1)
+    assert fstat1.st_nlink == 1
+
+    os.link(name1, name2)
+
+    fstat1 = os.lstat(name1)
+    fstat2 = os.lstat(name2)
+    for attr in ('st_mode', 'st_dev', 'st_uid', 'st_gid',
+                 'st_size', 'st_atime', 'st_mtime', 'st_ctime'):
+        assert getattr(fstat1, attr) == getattr(fstat2, attr)
+    assert os.path.basename(name2) in os.listdir(mnt_dir)
+    assert filecmp.cmp(name1, name2, False)
+
+    os.unlink(name2)
+
+    assert os.path.basename(name2) not in os.listdir(mnt_dir)
+    with pytest.raises(FileNotFoundError):
+        os.lstat(name2)
+
+    os.unlink(name1)
+
+def tst_readdir(src_dir, mnt_dir):
+    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 = os.listdir(mnt_newdir)
+    listdir_is.sort()
+    listdir_should = [ os.path.basename(file_), os.path.basename(subdir) ]
+    listdir_should.sort()
+    assert listdir_is == listdir_should
+
+    os.unlink(file_)
+    os.unlink(subfile)
+    os.rmdir(subdir)
+    os.rmdir(src_newdir)
+
+def tst_truncate_path(mnt_dir):
+    assert len(TEST_DATA) > 1024
+
+    filename = pjoin(mnt_dir, name_generator())
+    with open(filename, 'wb') as fh:
+        fh.write(TEST_DATA)
+
+    fstat = os.stat(filename)
+    size = fstat.st_size
+    assert size == len(TEST_DATA)
+
+    # Add zeros at the end
+    os.truncate(filename, size + 1024)
+    assert os.stat(filename).st_size == size + 1024
+    with open(filename, 'rb') as fh:
+        assert fh.read(size) == TEST_DATA
+        assert fh.read(1025) == b'\0' * 1024
+
+    # Truncate data
+    os.truncate(filename, size - 1024)
+    assert os.stat(filename).st_size == size - 1024
+    with open(filename, 'rb') as fh:
+        assert fh.read(size) == TEST_DATA[:size-1024]
+
+    os.unlink(filename)
+
+def tst_truncate_fd(mnt_dir):
+    assert len(TEST_DATA) > 1024
+    with NamedTemporaryFile('w+b', 0, dir=mnt_dir) as fh:
+        fd = fh.fileno()
+        fh.write(TEST_DATA)
+        fstat = os.fstat(fd)
+        size = fstat.st_size
+        assert size == len(TEST_DATA)
+
+        # Add zeros at the end
+        os.ftruncate(fd, size + 1024)
+        assert os.fstat(fd).st_size == size + 1024
+        fh.seek(0)
+        assert fh.read(size) == TEST_DATA
+        assert fh.read(1025) == b'\0' * 1024
+
+        # Truncate data
+        os.ftruncate(fd, size - 1024)
+        assert os.fstat(fd).st_size == size - 1024
+        fh.seek(0)
+        assert fh.read(size) == TEST_DATA[:size-1024]
+
+def tst_utimens(mnt_dir, tol=0):
+    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
+    if sys.version_info < (3,3):
+        os.utime(filename, (atime, mtime))
+    else:
+        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)
+
+    assert abs(fstat.st_atime - atime) < tol
+    assert abs(fstat.st_mtime - mtime) < tol
+    if sys.version_info >= (3,3):
+        assert abs(fstat.st_atime_ns - atime_ns) < tol*1e9
+        assert abs(fstat.st_mtime_ns - mtime_ns) < tol*1e9
+
+def tst_passthrough(src_dir, mnt_dir, cache_timeout):
+    name = name_generator()
+    src_name = pjoin(src_dir, name)
+    mnt_name = pjoin(src_dir, name)
+    assert name not in os.listdir(src_dir)
+    assert name not in os.listdir(mnt_dir)
+    with open(src_name, 'w') as fh:
+        fh.write('Hello, world')
+    assert name in os.listdir(src_dir)
+    if cache_timeout:
+        safe_sleep(cache_timeout+1)
+    assert name in os.listdir(mnt_dir)
+    assert os.stat(src_name) == os.stat(mnt_name)
+
+    name = name_generator()
+    src_name = pjoin(src_dir, name)
+    mnt_name = pjoin(src_dir, name)
+    assert name not in os.listdir(src_dir)
+    assert name not in os.listdir(mnt_dir)
+    with open(mnt_name, 'w') as fh:
+        fh.write('Hello, world')
+    assert name in os.listdir(src_dir)
+    if cache_timeout:
+        safe_sleep(cache_timeout+1)
+    assert name in os.listdir(mnt_dir)
+    assert os.stat(src_name) == os.stat(mnt_name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/util.py new/sshfs-2.10/test/util.py
--- old/sshfs-2.9/test/util.py  1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/util.py 2017-07-12 17:10:18.000000000 +0200
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+import subprocess
+import pytest
+import os
+import stat
+import time
+from os.path import join as pjoin
+
+basename = pjoin(os.path.dirname(__file__), '..')
+
+def wait_for_mount(mount_process, mnt_dir,
+                   test_fn=os.path.ismount):
+    elapsed = 0
+    while elapsed < 30:
+        if test_fn(mnt_dir):
+            return True
+        if mount_process.poll() is not None:
+            pytest.fail('file system process terminated prematurely')
+        time.sleep(0.1)
+        elapsed += 0.1
+    pytest.fail("mountpoint failed to come up")
+
+def cleanup(mnt_dir):
+    subprocess.call(['fusermount', '-z', '-u', mnt_dir],
+                    stdout=subprocess.DEVNULL,
+                    stderr=subprocess.STDOUT)
+
+def umount(mount_process, mnt_dir):
+    subprocess.check_call(['fusermount', '-z', '-u', mnt_dir ])
+    assert not os.path.ismount(mnt_dir)
+
+    # Give mount process a little while to terminate. Popen.wait(timeout)
+    # was only added in 3.3...
+    elapsed = 0
+    while elapsed < 30:
+        code = mount_process.poll()
+        if code is not None:
+            if code == 0:
+                return
+            pytest.fail('file system process terminated with code %s' % 
(code,))
+        time.sleep(0.1)
+        elapsed += 0.1
+    pytest.fail('mount process did not terminate')
+
+def safe_sleep(secs):
+    '''Like time.sleep(), but sleep for at least *secs*
+
+    `time.sleep` may sleep less than the given period if a signal is
+    received. This function ensures that we sleep for at least the
+    desired time.
+    '''
+
+    now = time.time()
+    end = now + secs
+    while now < end:
+        time.sleep(end - now)
+        now = time.time()
+
+def fuse_test_marker():
+    '''Return a pytest.marker that indicates FUSE availability
+
+    If system/user/environment does not support FUSE, return
+    a `pytest.mark.skip` object with more details. If FUSE is
+    supported, return `pytest.mark.uses_fuse()`.
+    '''
+
+    skip = lambda x: pytest.mark.skip(reason=x)
+
+    with subprocess.Popen(['which', 'fusermount'], stdout=subprocess.PIPE,
+                          universal_newlines=True) as which:
+        fusermount_path = which.communicate()[0].strip()
+
+    if not fusermount_path or which.returncode != 0:
+        return skip("Can't find fusermount executable")
+
+    if not os.path.exists('/dev/fuse'):
+        return skip("FUSE kernel module does not seem to be loaded")
+
+    if os.getuid() == 0:
+        return pytest.mark.uses_fuse()
+
+    mode = os.stat(fusermount_path).st_mode
+    if mode & stat.S_ISUID == 0:
+        return skip('fusermount executable not setuid, and we are not root.')
+
+    try:
+        fd = os.open('/dev/fuse', os.O_RDWR)
+    except OSError as exc:
+        return skip('Unable to open /dev/fuse: %s' % exc.strerror)
+    else:
+        os.close(fd)
+
+    return pytest.mark.uses_fuse()
+
+# Use valgrind if requested
+if os.environ.get('TEST_WITH_VALGRIND', 'no').lower().strip() \
+   not in ('no', 'false', '0'):
+    base_cmdline = [ 'valgrind', '-q', '--' ]
+else:
+    base_cmdline = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/sshfs-2.9/test/wrong_command.c new/sshfs-2.10/test/wrong_command.c
--- old/sshfs-2.9/test/wrong_command.c  1970-01-01 01:00:00.000000000 +0100
+++ new/sshfs-2.10/test/wrong_command.c 2017-07-12 17:10:18.000000000 +0200
@@ -0,0 +1,9 @@
+#include <stdio.h>
+
+int main(void) {
+       fprintf(stderr, "\x1B[31m\e[1m"
+               "This is not the command you are looking for.\n"
+               "You probably want to run 'python3 -m pytest test/' instead"
+               "\e[0m\n");
+       return 1;
+}


Reply via email to