Compare commits

...

350 Commits

Author SHA1 Message Date
Nikolaus Rath 39663c8288 Released 3.3.2 2018-04-29 18:06:03 +01:00
Nikolaus Rath 646a3c417b Fix Travis build environment.
Newest Meson requires Python 3.5.which isn't available in Trusty.
Pip version pin no longer necessary.
2018-03-31 13:26:15 +01:00
G.raud Meyer 303126bad9 New workaround renamexdev to enable moving files across remote filesystems
sshfs.rst: update the documentation.
2018-03-28 19:48:02 +01:00
Nikolaus Rath f0a0cc2b7e Fix rst markup 2017-11-27 19:55:09 +00:00
Brandon Carter 2c7c667576 change make directory command in readme 2017-11-17 18:17:41 +00:00
Nikolaus Rath 1846b685c4 Updated professional support information. 2017-11-13 20:09:54 +00:00
Nikolaus Rath 7f56cfc602 Released 3.3.1 2017-10-25 19:32:34 +01:00
Nikolaus Rath fd3aa6594f meson.build: don't use cp -p instead of --preserve-mode
The latter is not supported on OS X.
2017-10-25 19:30:34 +01:00
Timo Savola 2731a001e5 Fix memory leak on opendir error 2017-10-15 14:31:56 +01:00
Nikolaus Rath 608e7ab89c Ignore fstab-specific mount options
Fixes: #96.
2017-09-26 12:41:30 +01:00
Nikolaus Rath a73dda48bd Install manpage in man1/, not 1/
Fixes: #95.
2017-09-22 10:35:52 +01:00
Nikolaus Rath 7c2550a7e4 Don't attempt to remove non-existing file. 2017-09-20 18:09:59 +01:00
Nikolaus Rath 71aa3b97f6 Released 3.3.0 2017-09-20 18:08:27 +01:00
Nikolaus Rath 14636931ac Add support for printing release contributors. 2017-09-20 18:07:29 +01:00
Nikolaus Rath d193b19a8f Dropped support for writeback caching
As of kernel 4.14, the FUSE module's + writeback implementation is not
compatible with network filesystems, and there are no imminent plans
to change that.

For more details, see
https://marc.info/?l=fuse-devel&m=150592103107662&w=2 or

As a consequence, the -o unreliable_append option has become obsolete
as well.

Fixes: #93
Fixes: #88
Fixes: #81
2017-09-20 17:56:44 +01:00
Nikolaus Rath 949d76d1a2 Add support for mounting from /etc/fstab
Fixes: #92.
2017-09-20 14:43:34 +01:00
Nikolaus Rath 848ff30d90 Dropped FAQ file
Most entries were obsolete. Useful content has been moved to the man
page.
2017-09-20 14:43:34 +01:00
Nikolaus Rath 37c8c1c80b Dropped support for autotools build
It's just too much of a pain to maintain.
2017-09-20 14:43:31 +01:00
Nikolaus Rath 85b950d3c6 Updated manual page with missing options.
Fixes: #82.
2017-09-20 13:32:33 +01:00
Nikolaus Rath b32c4a4ca1 tst_link(): fix test failure 2017-09-20 12:06:31 +01:00
Nikolaus Rath bc47eeb68c travis: fix build procedure. 2017-09-20 11:58:43 +01:00
Nikolaus Rath e4de7d257f Improve documentation for symlink handling options.
Fixes: #51.
2017-09-19 22:34:50 +01:00
Nikolaus Rath 2a818faea5 Use 'buildtype' to set debug/optimization options
Until now, running `mesonconf -D buildtype=debug` didn't have any
effect - which was confusing.
2017-08-22 11:09:03 +02:00
Nikolaus Rath 48cf30d3e2 Converted manpage to Restructured Text 2017-08-18 10:58:47 +02:00
Anatol Pomozov 1f20b5dff5 Bump version number 2017-08-14 10:28:29 +02:00
Nikolaus Rath 5d64c08f69 Released 3.2.0 2017-08-06 12:38:50 +02:00
Nikolaus Rath 586ad60414 Drop -u option to cp
Not supported on OS X, and not strictly necessary.

Fixes: #64.
2017-08-06 11:51:06 +02:00
harrim4n 0bb569557e removed obsolete answers from FAQ 2017-08-06 11:35:37 +02:00
harrim4n da3a3f5bd1 Removed obsolete options from man page 2017-08-06 11:35:37 +02:00
Nikolaus Rath d141ea44c1 Re-enabled writeback cache.
Fixes: #72.
2017-08-06 11:07:23 +02:00
Nikolaus Rath 6ac4046bee Support O_APPEND.
Fixes: #76.
2017-08-06 11:07:23 +02:00
Nikolaus Rath 95c65a6246 Added seek and append tests. 2017-08-06 11:07:23 +02:00
Nikolaus Rath f8df458f23 Actually disable writeback cache, instead of just claiming to do so. 2017-08-06 11:07:23 +02:00
Nikolaus Rath e2a4bc904e Run tests with and without writeback cache. 2017-08-06 10:22:59 +02:00
Nikolaus Rath 70acee8c4b Include ChangeLog.rst in release tarballs. 2017-08-06 10:21:48 +02:00
Nikolaus Rath fc63c64602 Released 3.1.0 2017-08-04 15:42:38 +02:00
Nikolaus Rath 1e6e067fdf Disable writeback cache for now
Writeback cache seems to cause dataloss in some situations.
We need to investigate this first.

See https://github.com/libfuse/sshfs/issues/72.
2017-08-04 15:39:25 +02:00
Nikolaus Rath 44a56f0cac Removed unused variable. 2017-08-04 15:39:16 +02:00
Nikolaus Rath 653de120c8 Don't check st_mode of mountpoint
It is not clear what this check is supposed to achieve, and it seems to
fail in some situations (cf issue #57).

Fixes: #57.
2017-08-03 18:48:37 +02:00
Nikolaus Rath 63300fd564 Accept -o cache_* options for backward compatibility.
Fixes: #73.
2017-08-03 18:26:19 +02:00
Nikolaus Rath 45710c81d7 Travis: use alternative workaround suggested by support. 2017-07-27 21:21:46 +02:00
Nikolaus Rath 161ece55a3 Travis: disable trusty workaround
According to Travis support, this should be working now. We will see...
2017-07-27 19:15:30 +02:00
Benjamin Fleischer db149d1d87 Fall back to global I/O size on macOS
The st_blksize value of struct stat represents the optimal block size
for file I/O operations. FUSE for macOS will use this value when
preforming read or write operations on the file. The smaller st_blksize
is the more context switches are required to complete the operation.

Setting st_blksize to 0 results in FUSE for macOS falling back to the
global I/O size, that can be specified through the "-o iosize=..."
mount-time option.

Fixes osxfuse/osxfuse#389 and osxfuse/sshfs#33
2017-07-13 16:06:05 +02:00
Benjamin Fleischer 861d308a03 Don't require mount point to exists on macOS
By default volumes are mounted under /Volumes on macOS. Since macOS
10.12 the /Volumes directory is root-owned. In order to allow non-
privileged users to mount FUSE volumes under /Volumes FUSE will create
non-existent mount points automatically.

Fixes osxfuse/sshfs#27
2017-07-13 16:04:12 +02:00
Nikolaus Rath 319f0dde18 sshfs_open_commin(): fix compiler warning
wrctr cannot be used without having been initialized,
but the compiler is too dumb to see that.
2017-07-12 16:46:02 +02:00
Nikolaus Rath 82766d1093 sftp_readdir_async(): don't access request when it may have been freed
Fixes: #7
2017-07-12 16:45:17 +02:00
Nikolaus Rath 6f6491cd13 Travis: add /usr/local/lib* to ld configuration 2017-07-08 13:30:44 +02:00
Nikolaus Rath 03a693d295 Travis: install libfuse from git master 2017-07-08 13:23:18 +02:00
Nikolaus Rath 55eb1f00e6 Travis: Build libfuse with gcc-6
gcc-4.8 has trouble with libfuse 3.1.0 symbol versioning.
2017-07-08 13:14:21 +02:00
Nikolaus Rath 37b6969067 Travis: use libfuse 3.1.0 2017-07-08 12:59:20 +02:00
Nikolaus Rath ff6194b5c7 Released 3.0.0 2017-07-08 12:47:09 +02:00
Nikolaus Rath af31551e18 Include test files in "make dist" 2017-07-08 12:43:18 +02:00
Nikolaus Rath 82e899fb21 Switch to libfuse 3.1.0
libfuse 3.0.0 is rather new and not widely used yet, so requiring
libfuse 3.1.0 right away shouldn't be a problem.
2017-07-08 12:26:45 +02:00
Nikolaus Rath 34146444ce Switch to libfuse 3.0. 2017-07-08 12:25:13 +02:00
Nikolaus Rath 6cc86fc0bd Abort on glib assertion errors. 2017-07-08 00:37:25 +02:00
Nikolaus Rath 73e4cf79b0 Travis: use sudo-enabled environment. 2017-07-08 00:34:03 +02:00
Nikolaus Rath a202e2dcc8 Added information about professional support. 2017-07-08 00:34:02 +02:00
Nikolaus Rath c711bf738f Re-enabled cache support. 2017-07-08 00:34:01 +02:00
Nikolaus Rath 493081e8f6 Split readdir() into opendir(), readdir() and releasedir()
This re-enables support for nullpath_ok. The cache remains disabled.
2017-06-22 14:22:58 -07:00
Nikolaus Rath 3033dbc22e Transition from getdir() to readdir(), temporarily disable cache
This commit enables the use of readdir() instead of getdir(). It also
completely disables the cache and the nullpath_ok feature. This will
be fixed in the next commits.
2017-06-22 14:22:58 -07:00
Nikolaus Rath 5f4619bac3 Added unit tests and travis integration 2017-06-22 14:22:57 -07:00
Nikolaus Rath b66ecb9c3a Fix Meson manpage install
Without this, Meson is looking for sshfs.1 in the source
directory. However, since that is a generated file it is in the build
directory.
2017-06-22 14:21:33 -07:00
Nikolaus Rath 9ac5829b89 Compile with -g -O2 by default. 2017-06-22 14:21:07 -07:00
Nikolaus Rath 9cfeaf5120 Added .rst suffix to ChangeLog.
That way, programs are more likely to highlight the file correctly.
2017-06-20 16:39:18 -07:00
Nikolaus Rath 56d6030f9c Document hardlink limitation. 2017-06-20 16:39:16 -07:00
Nikolaus Rath 152617e53f Converted README from Markdown to Restructured Text. 2017-06-20 16:38:46 -07:00
Nikolaus Rath 0908f570dc Dropped obsolete FUSE 2.x #ifdefs 2017-06-20 11:29:19 -07:00
Nikolaus Rath 5bc9ff371d Added .dir-locals.el to setup correct indentation in Emacs 2017-06-19 15:18:11 -07:00
Nikolaus Rath 4379773a9e Updated mailing list information. 2017-06-08 16:53:26 -04:00
Nikolaus Rath 6056149d16 Fixed compiler warnings 2017-06-07 13:42:34 -04:00
Nikolaus Rath 53a14aeaf1 Dropped support for libfuse < 2.9
This is in preparation for the move to libfuse 3.0
2017-06-07 13:42:34 -04:00
Nikolaus Rath 8999210c93 Remove support for "all" workarounds
This should never be used. We may add new workarounds in the future,
and they should only be enabled explicitly when needed.
2017-06-06 16:45:15 -04:00
Nikolaus Rath 5ed2cf8a8b Add fstat workaround to help output. 2017-06-06 16:45:15 -04:00
Nikolaus Rath 9f2eb04371 Document rename workaround. 2017-06-06 16:45:15 -04:00
Nikolaus Rath 6c301e043b Dropped nodelaysrv workaround
The same effect (enabling NODELAY on the server side *and* enabling
X11 forwarding) can be achieved by explicitly passing `-o ForwardX11`
2017-06-06 16:45:15 -04:00
Nikolaus Rath 6d7ce1607a Added support for building with Meson. 2017-06-06 16:45:15 -04:00
Nikolaus Rath 5659d0d2ea Don't call g_thread_init()
No longer required since glib 2.32.
2017-06-06 11:03:14 -04:00
Nikolaus Rath fe3ce10ff8 Fixed compiler warning 2017-06-06 11:02:11 -04:00
Nikolaus Rath 132dd88755 Dropped nodelay workaround
This was a performance improvement for SSH versions prior to
4.4. There is no reason to continue to support this.
2017-06-06 11:01:21 -04:00
Nikolaus Rath af1f3c6235 Fixed Markdown markup. 2017-06-06 10:05:21 -04:00
Nikolaus Rath 8cc069f666 Reworked README
Now also includes mailing list.
2017-06-06 10:03:15 -04:00
Nikolaus Rath d7cb098f1d main(): setup signal handlers before connecting
Otherwise, aborting the password prompt with Ctrl+C will
also kill the sshfs process and leave the mountpoint inaccessible.

Fixes: #9.
2017-06-05 17:28:44 -04:00
Nikolaus Rath c7d8500634 Added changelog entry for commit d93f1. 2017-05-31 13:54:18 -07:00
Nikolaus Rath 2896aed825 Merge branch 'master' of github.com:libfuse/sshfs 2017-05-31 13:52:44 -07:00
tpoindessous 110163d8d1 Update README.md for macOS
On macOS, we don't have fusermount, so we use umount command.

Thanks.
2017-05-31 13:51:30 -07:00
Jakub Jelen d93f137c8f Update the missing options (that make sense from ssh_config) 2017-05-31 13:51:09 -07:00
Nikolaus Rath 1dbda31786 Released 2.9 2017-04-17 13:13:38 -07:00
Nikolaus Rath 33667f2a56 Fixed up version numbers in ChangeLog 2017-04-17 13:09:35 -07:00
Nikolaus Rath f627055bc7 Merge pull request #23 from billziss-gh/master
Port SSHFS to Cygwin
2017-01-12 14:57:45 -08:00
Bill Zissimopoulos efeed71295 remove no longer useful check for fsp_fuse_opt_parse from configure.ac 2017-01-12 11:24:08 -08:00
Nikolaus Rath 96c6138978 Merge pull request #38 from BerserkerTroll/master
sshfs.1.in: remove duplicate "slave" option description
2016-12-30 11:07:57 -08:00
Berserker 1afaef8f46 sshfs.1.in: remove duplicate "slave" option description 2016-12-30 20:52:47 +03:00
Nikolaus Rath e5acfce8ed Merge pull request #27 from benesch/master
Remove call to g_slice_set_config()
2016-07-28 16:22:16 -07:00
Benjamin Fleischer e178150a72 Remove call to g_slice_set_config()
It is unclear why G_SLICE_CONFIG_ALWAYS_MALLOC has been set before but
doing so with the latest version of GLib (2.46.2) results in the
following warning:

GLib-CRITICAL **: g_slice_set_config: assertion 'sys_page_size == 0'
failed

This fixes issue osxfuse/sshfs#17
2016-07-28 12:25:37 -04:00
Nikolaus Rath c63acf3dd7 Merge pull request #24 from kuscsik/master
Makefile: fix path for sshfs.1
2016-07-01 15:09:32 -04:00
Zoltan Kuscsik e3cd445a4e Makefile: fix path for sshfs.1
Fix source path when build directory differs
from the source dir.
2016-07-01 09:30:31 +02:00
Nikolaus Rath 1167c11901 Merge pull request #20 from rianhunter/master
Require paths for truncate/fstat workarounds
2016-06-23 12:10:11 -04:00
Bill Zissimopoulos a175c2876a port sshfs to cygwin 2016-06-22 17:02:30 -07:00
Nikolaus Rath b2fa759358 Released 2.8 2016-06-22 11:38:53 -07:00
Nikolaus Rath 1756abe6fd Fixed release year of version 2.7 2016-06-22 11:37:40 -07:00
Rian Hunter f51d7b0c6a Require paths for truncate/fstat workarounds
Commit 74bfa3850a allowed sshfs to run
without requiring a non-NULL path argument for certain
operations. This was erroneous in the case of using certain
workarounds.
2016-06-06 00:12:42 -07:00
Nikolaus Rath df10d96ac2 Add extra quoting for increased compatibility.
Fixes: #15.
2016-06-05 14:18:49 -04:00
Nikolaus Rath a2dda962c4 Merge branch 'rianhunter-master' 2016-06-05 14:15:52 -04:00
Nikolaus Rath 504e26f938 Added ChangeLog entry for fsync extension 2016-06-05 14:15:36 -04:00
Rian Hunter 74bfa3850a Support the lack of paths when cache is off
Before FUSE 2.9, FUSE had to emulate unlink() if a file was still open
via renaming to a hidden file.  This was due to the requirement that a
valid "path" argument must be submitted for many FUSE operations. FUSE
2.9 introduced the flag_nullpath_ok and flag_nopath flags that allow a
FUSE file system to signal to FUSE that the "path" argument may be NULL
in certain operations.

sshfs doesn't require paths if the cache isn't used so communicate
that information to the FUSE layer.
2016-06-01 23:27:01 -07:00
Rian Hunter 0f6f33b1b4 Implement support for "fsync@openssh.com"
OpenSSH implements fsync() via the extension "fsync@openssh.com". This
change uses that extension when receiving a FUSE fsync request.
2016-06-01 22:34:36 -07:00
Nikolaus Rath a9a1cc0046 Released 2.7 2016-03-01 08:49:53 -08:00
Nikolaus Rath b5983a0ce8 Merge pull request #8 from gapan/master
Restore FAQ file
2016-02-25 08:52:49 -08:00
George Vlahavas adc55c9d2b Restore FAQ file
This commit restores the FAQ file present in sshfs versions up to 2.5.
Changes since the version in the 2.5 release:
 - Remove most wiki markup
 - Edit question about bug reports to point to the Github issue tracker
 - Remove unanswered questions
 - Minor formatting
2016-02-25 15:10:50 +02:00
Nikolaus Rath 451f2075f2 Merge pull request #6 from jmmv/cache-options
Make cache parameters configurable
2016-02-16 10:47:06 -08:00
Julio Merino 391f676705 Explicitly qualify unsigned as unsigned int 2016-02-10 23:18:35 -05:00
Julio Merino c1e799b4da Expose the cache clean interval settings as flags
Allow the user to customize the cache regular and minimum clean intervals
as flags via the new cache_clean_interval and cache_min_clean_interval
options.

While doing this, rename the internal variables and constants to suffix
them with their unit (seconds).
2016-02-10 23:18:35 -05:00
Julio Merino ebfeebd468 Expose the maximum cache size setting as a flag
Allow the user to customize the size of the sshfs cache by adding a new
max_cache_size flag and turning the hardcoded constant into a variable.
2016-02-10 23:18:35 -05:00
Julio Merino d1ddbbcae5 Qualify timeout identifiers with their unit
All timeouts are in seconds, so add a suffix to the identifier names to
clearly denote the unit.
2016-02-10 23:18:35 -05:00
Nikolaus Rath e812e29d39 Merge pull request #5 from jmmv/merge-osxfuse
Merge osxfuse.
2016-02-10 19:53:49 -08:00
Julio Merino 80db43d7dc Improve the sshnodelay hack after osxfuse's merge
Document the strage-looking symbol interposition that is necessary for the
OS X case.

While doing this, homogenize the code to do the real connect call for both
the Linux and OS X cases into a helper function.  This logic is generic
and should not be replicated into various OS-specific cases.
2016-02-08 21:40:30 -05:00
Julio Merino 27e7029148 Unconditionally mlock the password in memory
Revision b4023a19 added an mlock call to ensure the sshfs password is kept
in memory, but did so only for OS X.  This is a good idea in general, so
let's remove the condition.
2016-02-08 21:26:53 -05:00
Julio Merino 30e90ae080 Remove apparently-unnecessary lock
Revision b4023a19dd, which imported the
MacFUSE-specific sshfs fixes into osxfuse-sshfs, added a lock to handle
the refs reference counter of the sshfs_file structure.  However, this
lock was only added for OS X, which is a very strange thing to do.

One may think that this was only because MacFUSE 2.2 had some semantics
that differed from regular FUSE, and that would have been quite stupid
for compatibility reasons.  A few simple tests show no issues after
removing this lock, so let's keep it out for now.  If things break, we
know what to look at.
2016-02-08 21:20:21 -05:00
Julio Merino 9b4ca1aade Avoid using cpp for sshfs.1 generation
Move the logic to determine which values to stick into the manual page
to the configure script and replace the logic to build the sshfs.1
manual page with sed instead of abusing cpp.

I'm not using AC_OUTPUT here because this macro is typically used to
generate support build files.  Final artifacts of the build should, in
general, be built by the Makefile itself.
2016-02-08 21:10:48 -05:00
Julio Merino a03d3eab39 Fix path to compat in -I flag
When defining a -I flag to point into the source directory, we should
prefix the directory with ${srcdir} so that it can be found when the
build is configured to use a build directory that differs from the
source directory.

This fixes "make distcheck".
2016-02-08 20:50:23 -05:00
Julio Merino 665bb97ef6 Document merge of osxfuse's sshfs 2016-02-08 20:50:23 -05:00
Julio Merino b7e8fee81b Sync AUTHORS list after osxfuse-sshfs's merge 2016-02-08 20:50:23 -05:00
Julio Merino 869aa42e97 Remove LIBDIR explicit definition
Makefile.am always sets LIBDIR in CPPFLAGS.  There is no need for sshfs.c
to redefine it to a bogus value when not present, and much less to only
do so for the Darwin case only.
2016-02-08 20:50:23 -05:00
Julio Merino d8230e72ca Drop the cache_enabled hack
cache_enabled leaked the cache.on setting from the cache module abstraction
back into sshfs, and it only did so for the Darwin case.

This hack was being used to avoid calling cache_add_attr and cache_invalidate
when the cache was disabled... but these two functions already do nothing when
in that case: there is no need to do a second check in the caller.
2016-02-08 20:50:22 -05:00
Julio Merino e0025219b3 Drop OSXFUSE_SSHFS_VERSION
Now that we are unifying osxfuse's sshfs into libfuse's version, there
should not be two different version identifiers.  Drop osxfuse's one.
2016-02-08 20:50:22 -05:00
Julio Merino 19ab22abec Improve sshfs.1 manpage generation
* Fix dependencies of the sshfs.1 target to actually specify sshfs.1.in as a
  source.

* Ensure that failures during the generation of sshfs.1 do not result in a
  potentially bogus manpage by first outputting the contents to a temporary
  file unknown to the Makefile rule and then replacing the target file once
  all is known to be OK.

* Use $(AM_V_GEN) in the command to respect automake's silent rules.
2016-02-08 20:50:22 -05:00
Julio Merino 3bf3be3bcd Rename arch to osname
Operating system names are not architectures; therefore, rename the arch
variable to osname to better represent its contents.

While doing this, drop a bunch of unused values from the osname.
2016-02-08 20:46:45 -05:00
Julio Merino ddbe3bee44 Merge remote-tracking branch 'osxfuse/master' into merge-osxfuse
Pull in all changes from osxfuse's fork of sshfs into libfuse's sshfs.
There need not be two different copies of this codebase, particularly
because libfuse's version is already autoconf-ified and can support
multiple platforms.

The merge is mostly clean with just a few manual edits to resolve
conflicts.
2016-02-08 20:46:37 -05:00
Nikolaus Rath b10d21db31 Merge pull request #4 from gala132/patch-1
Fix typo in README.md
2016-02-05 09:25:28 -08:00
gala f7c7713a82 Update README.md
Typo fixed
2016-02-05 09:18:25 +01:00
Nikolaus Rath 3087690aba Released 2.6 2016-01-28 17:16:08 -08:00
Nikolaus Rath 3a60def57e Rename project from sshfs-fuse to sshfs 2016-01-28 17:15:49 -08:00
Nikolaus Rath f5b939d40c Don't attempt to download FAQ for tarball generation. 2016-01-28 17:13:05 -08:00
Nikolaus Rath 9b3fb20112 Added missing ChangeLog entries for 2.4 and 2.5 2016-01-28 17:13:05 -08:00
Nikolaus Rath d20b25cd2d Enable subdir-objects automake option
This is recommended for forward-compatibility.
2016-01-28 17:13:05 -08:00
Nikolaus Rath 055649e2fa Changed Changelog format
Up to now, the Changelog has essentially been a (manually maintained)
copy of the git commit history. This doesn't seem to have any point
other than following the GNU coding standards. I believe it's much
better to use the Changelog to summarize the release-to-release
changes that are most important for users (as was done in the NEWS
file until now).
2016-01-28 17:12:49 -08:00
Nikolaus Rath d18349da3b Removed placeholder README file and switch automake to foreign flavor.
The GNU flavor merely requires to existence of some files (including
README, but we prefer README.md), so there seems to be little point
in using it.
2016-01-28 16:52:50 -08:00
Nikolaus Rath cf10c34573 Updated credits from git. 2016-01-28 16:51:08 -08:00
Nikolaus Rath 008cf7bcf4 Renamed README to README.md for Markdown rendering on Github.
Remaining README file is just to make automake happy.
2015-12-21 19:23:10 -08:00
Miklos Szeredi e4e14109ad sshfs: Increase the maximum length of the password
read from stdin to 1024 characters.

Reported by: Mario A. Valdez-Ramirez.
2015-04-14 11:01:19 +02:00
Qais Patankar 9bcb989454 Fix english 2015-03-16 15:34:34 +01:00
Miklos Szeredi 48122e8043 sshfs-return-the-correct-x_ok-access
sshfs-fuse always returned 0 in access(file, X_OK) calls, causing nautilus
to prompt "Do you want to run "login.defs", or display its contents?" for
text files that were not executable.

Reported by: Alkis Georgopoulos
2014-02-10 14:09:13 +01:00
Benjamin Fleischer f2b17c299b Bump version to 2.5.0 2014-02-03 09:01:38 +01:00
Benjamin Fleischer c3d83ee24b Fix redefinition of struct __local_sem_t 2014-02-03 09:01:26 +01:00
Benjamin Fleischer 1fc97d3f2c Add AC_CANONICAL_TARGET to configure.ac 2014-02-03 09:01:07 +01:00
Benjamin Fleischer b42f84218c Merge tag 'sshfs_2_5'
Conflicts:
	sshfs.c
2014-02-02 23:16:13 +01:00
Miklos Szeredi 6b4415ada4 Released 2.5 2014-01-14 15:23:31 +01:00
Alexander Neumann 6a2d06e36f Implement asynchronous readdir
Accessing directories with many (several thousand) files over sshfs is
slow, because most SFTP server implementations only send a fixed amount
of entries per READDIR command (e.g. OpenSSH SFTP: 100 entries). This
patch implements sending several READDIR commands in parallel, in order
to speed up directory listing in these cases.

An option (sync_readdir) is also added so that users can easily switch
on the old behaviour.

The performance improvement is astonishing. Accessing a directory with
30k files in from a remote server that has a RTT of 15ms via OpenSSH
SFTP:

Synchronous readdir:
 $ ./sshfs -o sync_readdir host:/tmp /mnt/temp
 $ time "ls" -1 /mnt/temp/test | wc -l
 30000
 "ls" -1 /mnt/temp/test  0.07s user 0.01s system 1% cpu 6.928 total

Asynchronous readdir:
 $ ./sshfs host:/tmp /mnt/temp
 $ time "ls" -1 /mnt/temp/test | wc -l
 30000
 "ls" -1 /mnt/temp/test  0.07s user 0.01s system 12% cpu 0.605 total

Accessing a directory with 100k files shows even more dramatic
improvement:

Synchronous readdir:
 $ ./sshfs -o sync_readdir host:/tmp /mnt/temp
 $ time "ls" -1 /mnt/temp/test2 | wc -l
 100000
 "ls" -1 /mnt/temp/test2  0.67s user 1.22s system 0% cpu 3:31.56 total

Asynchronous readdir:
 $ ./sshfs host:/tmp /mnt/temp
 $ time "ls" -1 /mnt/temp/test2 | wc -l
 100000
 "ls" -1 /mnt/temp/test2  0.20s user 0.03s system 14% cpu 1.631 total

This can easily be reproduced by creating a directory on a server and
touching a lot of files in it:
 $ mkdir /tmp/test
 $ cd /tmp/test
 $ for i in $(seq 1 30000); do touch $i; done

Signed-off-by: Alexander Neumann <alexander@bumpern.de>
2014-01-08 16:34:52 +01:00
Miklos Szeredi 334e9e6a27 Add -o disable_hardlink option (debian bug #670926)
Reported by Louis-David Mitterrand
2014-01-08 12:31:18 +01:00
Miklos Szeredi 91c1f2ba9e Map SSH2_FX_FAILURE to ENOTEMPTY for rmdir
Reported by Ross Lagerwall
2014-01-07 18:52:51 +01:00
Benjamin Fleischer 990f30d767 Merge remote-tracking branch 'upstream/master'
Conflicts:
	ChangeLog
	configure.ac
	sshfs.1.in
	sshfs.c
2013-08-03 11:50:50 +02:00
Miklos Szeredi c1d62f2032 fix a typo in man page 2013-04-11 17:58:21 +02:00
Alan Jenkins 61524cd1e8 fix missing newline in manual page 2013-02-18 14:36:51 +01:00
Miklos Szeredi 9f4ba56b52 Add FIXME for deadlock if $PATH contains mountpoint.
Reported by Joachim Kopp
2013-02-05 12:33:36 +01:00
Benjamin Fleischer d04fd55128 Update copyright year in darwin_compat 2013-01-08 15:44:18 +01:00
Benjamin Fleischer 1458193728 Add unnamed semaphore implementation for Mac OS X
In the past we relied on libosxfuse including a working unnamed semaphore
implmentation for Mac OS X. This will not be the case in future releases of
OSXFUSE, therefore we need to add our own implementation.
2013-01-08 15:32:57 +01:00
Miklos Szeredi ce6753c88f When checking root directory use LSTAT not STAT
This prevents I/O error being returned after a successful mount if a symlink is
mounted.

Reported by Bart Friederichs
2012-05-14 16:18:22 +02:00
Benjamin Fleischer 66458931dd Bump version to OSXFUSE SSHFS 2.4.1
The only difference between version 2.4.0 and 2.4.1 is the updated man page to
reflect Darwin/OS X specific changes to upstream SSHFS.
2012-03-11 17:36:01 +01:00
Benjamin Fleischer f4631f0a17 Add Darwin/OS X specific information to man page
* Volumes are unmounted using "umount" not "fusermount"

* idmap=user is the deafault setting on Darwin/OS X
2012-03-11 17:35:25 +01:00
Benjamin Fleischer 3c44e22ddd Bump version to OSXFUSE SSHFS 2.4.0 2012-03-09 22:52:56 +01:00
Benjamin Fleischer b389c66b32 Use "#ifdef __APPLE__" instead of "#if __APPLE__" 2012-03-09 22:51:56 +01:00
Miklos Szeredi f64407d865 Released 2.4 2012-03-09 22:51:49 +01:00
Mike Kelly eb60e2d1a2 make sure idmap files aren't writable by others
otherwise, other local users could change the mapping, and gain access
to things they shouldn't
2012-03-09 22:48:58 +01:00
Chris Wolfe 0d34c7b742 Add slave option to run sftp over stdin and stdout
Add -o slave. This option routes the sftp communication over stdin and stdout,
bypassing SSH and network.
2012-03-09 22:48:58 +01:00
Chris Wolfe ff32332e83 Split fd into separate read and write pipes 2012-03-09 22:48:58 +01:00
Miklos Szeredi c1284b4089 fix unused but set variables
cache.c: In function ‘cache_add_attr’:
cache.c:167:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_dir’:
cache.c:188:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_link’:
cache.c:212:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
2012-03-09 22:48:58 +01:00
Chris Wolfe 0120e6b461 Remove some trailing whitespace.
Verified with `cat -vet` and `grep '\s$'`
2012-03-09 22:48:58 +01:00
Mike Kelly 1ac41d2ae2 skip blank lines 2012-03-09 22:48:58 +01:00
Mike Kelly ea6fa1d7c9 increase portability
getline() isn't widely available yet, use fgets() instead
2012-03-09 22:48:58 +01:00
Mike Kelly 6a954f429c fix typo in error message 2012-03-09 22:44:14 +01:00
Mike Kelly 0e87004ab2 default to erroring if we can't remap a uid/gid
add a '-o nomap=ignore|error' option, which defaults to 'error'
2012-03-09 22:43:58 +01:00
Benjamin Fleischer e6f7fb4e50 Make IDMAP_USER the default option on OS X
UID/GID mapping had been enabled in previous versions of SSHFS for MacFUSE/
OSXFUSE by default. This is the expected behavior.
2012-03-09 22:30:14 +01:00
Miklos Szeredi 857d634e09 Released 2.4 2012-03-08 10:36:10 +01:00
Mike Kelly 4dc10686e0 make sure idmap files aren't writable by others
otherwise, other local users could change the mapping, and gain access
to things they shouldn't
2012-03-08 10:34:39 +01:00
Chris Wolfe b3af91b123 Add slave option to run sftp over stdin and stdout
Add -o slave. This option routes the sftp communication over stdin and stdout,
bypassing SSH and network.
2012-02-14 12:55:15 +01:00
Chris Wolfe acb0832ffd Split fd into separate read and write pipes 2012-02-14 12:55:14 +01:00
Miklos Szeredi c5949f06fa fix unused but set variables
cache.c: In function ‘cache_add_attr’:
cache.c:167:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_dir’:
cache.c:188:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
cache.c: In function ‘cache_add_link’:
cache.c:212:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable]
2012-02-08 10:21:33 +01:00
Chris Wolfe b0f3d73028 Remove some trailing whitespace.
Verified with `cat -vet` and `grep '\s$'`
2012-02-08 10:15:52 +01:00
Mike Kelly a6b6b5c820 Add -o idmap=file, -o uidmap=FILE, -o gidmap=FILE
These options allow you to create a pair of local files, with
username:uid/groupname:gid pairs, one per line. Alternatively, files can
be in standard /etc/passwd / /etc/group format.

The uid/gids are for the remote server, their local counterparts are
looked up with a local getpwnam/getgrnam call. Any stat() calls will
show with the remapped local uid/gid, and any chown() calls will be
remapped back to the remote uid/gid.
2012-01-22 11:19:29 +01:00
Mike Kelly a306a80b6e Fix a possible small memory leak 2012-01-22 11:16:43 +01:00
Mike Kelly bb3ea51117 Fix typo in error message
s/FD_CLOESEC/FD_CLOEXEC/
2012-01-22 11:16:43 +01:00
Miklos Szeredi 20fafed0a4 Fix error handling in sshfs_read_end
Reported by Mike Kelly
2012-01-22 11:16:43 +01:00
Miklos Szeredi 69b2b3cc0e Make chown respect the UID mapping policy
Reported and tested by Vivenzio Pagliari
2012-01-22 11:16:37 +01:00
Miklos Szeredi fa9bfc6d08 Submit max 32k reads and writes to the sftp server
Also don't limit the kernel to 64k reads and writes, rather split into
32k sized chunks and send them to the server all at once.  This is
more efficient and less demanding from the server.

Reported by Ludovic Courtès.  Fix suggested by Niels Möller
2012-01-22 10:45:50 +01:00
Miklos Szeredi 90619fe249 Add locking around modifver and connver 2012-01-22 10:45:36 +01:00
Miklos Szeredi 04a610bad1 Fix double free if reconnection races with request sending
Patch by E. Kuemmerle
2012-01-22 10:45:16 +01:00
Miklos Szeredi d8da0c4ed6 Remove "-oPreferredAuthentications" from ssh options
Remove "-oPreferredAuthentications" from ssh options if the
"password_stdin" option is used.  Reported by E. Kuemmerle
2012-01-22 10:45:06 +01:00
Miklos Szeredi 163683d9ef Add "FIXME: really needs LSETSTAT extension (debian Bug#640038)" 2012-01-22 10:44:55 +01:00
Percy Jahn f2086ccfbc sshfs: fstat workaround
Add "-oworkaround=fstat" for SFTP servers which don't support
the FSTAT message.
2012-01-22 10:44:45 +01:00
Benjamin Fleischer b4023a19dd Apply modified sshfs 2.2 patch from MacFUSE
Based on Amit Singh's work at http://code.google.com/p/macfuse/
2012-01-20 10:02:14 +01:00
Mike Kelly 75bfa9a6c0 skip blank lines 2011-12-21 10:05:08 +01:00
Mike Kelly e8e26c0bc1 increase portability
getline() isn't widely available yet, use fgets() instead
2011-12-21 10:05:08 +01:00
Mike Kelly cfcae008e3 fix typo in error message 2011-12-21 10:05:08 +01:00
Mike Kelly 7ca565d80d default to erroring if we can't remap a uid/gid
add a '-o nomap=ignore|error' option, which defaults to 'error'
2011-12-21 10:05:08 +01:00
Mike Kelly 301cc5218b Add -o idmap=file, -o uidmap=FILE, -o gidmap=FILE
These options allow you to create a pair of local files, with
username:uid/groupname:gid pairs, one per line. Alternatively, files can
be in standard /etc/passwd / /etc/group format.

The uid/gids are for the remote server, their local counterparts are
looked up with a local getpwnam/getgrnam call. Any stat() calls will
show with the remapped local uid/gid, and any chown() calls will be
remapped back to the remote uid/gid.
2011-12-20 15:33:58 +01:00
Mike Kelly d666318c7a Fix a possible small memory leak 2011-12-20 15:33:58 +01:00
Mike Kelly ea0d68651e Fix typo in error message
s/FD_CLOESEC/FD_CLOEXEC/
2011-12-20 15:33:58 +01:00
Miklos Szeredi 2f6665d84e Fix error handling in sshfs_read_end
Reported by Mike Kelly
2011-12-20 14:55:45 +01:00
Miklos Szeredi 2ce4069832 Make chown respect the UID mapping policy
Reported and tested by Vivenzio Pagliari
2011-12-05 13:11:09 +01:00
Miklos Szeredi 97228b866a Submit max 32k reads and writes to the sftp server
Also don't limit the kernel to 64k reads and writes, rather split into
32k sized chunks and send them to the server all at once.  This is
more efficient and less demanding from the server.

Reported by Ludovic Courtès.  Fix suggested by Niels Möller
2011-11-16 14:54:37 +01:00
Miklos Szeredi f3286cdf86 Add locking around modifver and connver 2011-11-14 16:28:13 +01:00
Miklos Szeredi 955751ad36 Fix double free if reconnection races with request sending
Patch by E. Kuemmerle
2011-11-14 15:12:52 +01:00
Miklos Szeredi b5f0c128f5 Remove "-oPreferredAuthentications" from ssh options
Remove "-oPreferredAuthentications" from ssh options if the
"password_stdin" option is used.  Reported by E. Kuemmerle
2011-10-21 17:12:31 +02:00
Miklos Szeredi 77d57a4a5d Add "FIXME: really needs LSETSTAT extension (debian Bug#640038)" 2011-09-23 14:33:32 +02:00
Percy Jahn 19cb995c23 sshfs: fstat workaround
Add "-oworkaround=fstat" for SFTP servers which don't support
the FSTAT message.
2011-08-24 13:22:36 +02:00
Miklos Szeredi 49203ee923 Released 2.3 2011-07-01 14:24:49 +02:00
Miklos Szeredi 6c1968e9e5 Update COPYING 2011-07-01 14:15:39 +02:00
Miklos Szeredi a575d48234 Add hard link operation
Works if the server supports the "hardlink@openssh.com" protocol
extension.
2011-07-01 14:01:29 +02:00
Miklos Szeredi eac5268e87 Fix possible deadlock on reconnection
Reported by Florian Zumbiehl
2011-03-25 13:38:39 +01:00
Miklos Szeredi 6d5e12e1b6 Fix cleanup when ssh connection is terminated.
This prevents sshfs hanging when the server is rebooted, for example.
2011-01-25 11:46:15 +01:00
Miklos Szeredi b1b0c4b6f5 * Set FD_CLOEXEC on fuse device. This prevents deadlocks that
happen in some circumstances (bugzilla.kernel.org #12864).
2010-04-28 08:59:12 +00:00
Miklos Szeredi f018ac3b1c * Check that the remote path specified refers to the same type of
file as the mountpoint, i.e. both are directories or both are
non-directories (debian bug #535343).  Reported by Greg Kochanski

* Allow mounting a single non-directory from the server
2009-07-15 15:57:04 +00:00
Miklos Szeredi 2431a280eb tear down mount on connect failure 2009-07-15 15:08:55 +00:00
Miklos Szeredi 0eabd86300 Check mountpoint and fuse options before starting an ssh
session (debian bug #535333).  This is only supported if compiled
against libfuse-2.6 or later. Reported by Greg Kochanski
2009-07-15 14:27:52 +00:00
Miklos Szeredi ae4614e690 Add option 'delay_connect': This will always create the sshfs mount,
even if the connection to the server can't be established.
2009-07-15 14:20:58 +00:00
Miklos Szeredi b1fa0408fb * Print usage information and version to stdout, not stderr.
Libfuse also needs to be fixed up.  Reported by Kārlis Repsons
2009-02-12 07:11:33 +00:00
Miklos Szeredi 09e37d536f Released 2.2 2008-10-20 12:15:07 +00:00
Miklos Szeredi be44229cfe Escape commas in fsname option if libfuse supports it 2008-10-20 12:03:16 +00:00
Miklos Szeredi c7dbdc1f77 Fix harmless glib assertations with "cache=no" 2008-10-08 18:23:33 +00:00
Miklos Szeredi 8a4015a3b6 * Handle numerical IPv6 addresses enclosed in square brackets. Reported by Andre-John Mas * Fix error if username contains a comma character. Reported by Yang Zhang 2008-10-08 11:07:48 +00:00
Miklos Szeredi fd52ef3e51 Released 2.1 2008-07-11 10:59:12 +00:00
Miklos Szeredi 1abdbe64a3 Add '-F' option to specify the ssh config file 2008-06-24 15:24:01 +00:00
Miklos Szeredi 4b28b15c34 Fix bug in caching which could cause file corruption for append mode writes 2008-05-06 15:10:28 +00:00
Miklos Szeredi 1a76a16bd9 man page update from Bartosz 2008-04-25 06:39:37 +00:00
Miklos Szeredi b1748d87aa Add manual page 2008-04-23 12:12:25 +00:00
Miklos Szeredi ff1a5c7a71 Add manual page 2008-04-23 12:07:39 +00:00
Miklos Szeredi 09579af980 Released 2.0 2008-04-22 16:01:59 +00:00
Miklos Szeredi eeea0ff5a6 Support "statvfs@openssh.com" extension... 2008-04-22 14:25:19 +00:00
Miklos Szeredi 4b88fc4731 Limit write requests to 64kB 2008-04-22 13:36:26 +00:00
Miklos Szeredi b246ad3da0 Allow the '-ossh_command=CMD' command to contain parameters... 2008-04-22 13:00:14 +00:00
Miklos Szeredi c61e700aab Fix incorrect disk usage reported by 'du' for files of size 4GB or above 2008-04-22 10:20:05 +00:00
Miklos Szeredi 4d6e5a03da Support "posix-rename@openssh.com" extension... 2008-03-31 11:30:43 +00:00
Miklos Szeredi 4802b14791 Add support for password authentication with pam_mount. 2008-03-28 19:22:19 +00:00
Miklos Szeredi 03381402b2 *** empty log message *** 2008-03-27 16:18:09 +00:00
Miklos Szeredi e83b2e61d1 Released 1.9 2007-12-17 14:32:22 +00:00
Miklos Szeredi ad9f0cf2a3 Released 1.9 2007-12-11 19:39:58 +00:00
Miklos Szeredi 501b9f712f Fix crash on writing files 2007-12-10 20:25:25 +00:00
Miklos Szeredi 37b408459a change indenting 2007-12-10 18:21:52 +00:00
Miklos Szeredi 1af7516f1e Released 1.8 2007-05-16 11:20:35 +00:00
Miklos Szeredi 15f911853e fixes 2007-05-15 20:09:29 +00:00
Miklos Szeredi eff1631428 Fix spurious cache entries remaining after renaming a directory 2007-04-18 10:24:10 +00:00
Miklos Szeredi 4399cfca84 Fix crash within gdb 2007-04-18 09:44:08 +00:00
Miklos Szeredi dd258a5117 Don't set DISPLAY environment variable to empty string 2007-03-16 13:15:16 +00:00
Miklos Szeredi feeaf76340 fix 2007-02-19 16:04:03 +00:00
Miklos Szeredi b3ffcfe3ac Work around write performace issues due to missing TCP_NODELAY in sshd 2006-12-20 17:48:08 +00:00
Miklos Szeredi d045a9be5e fix 2006-11-11 10:11:55 +00:00
Miklos Szeredi 09d5ee2eee fix segfault 2006-09-29 14:22:54 +00:00
Miklos Szeredi b917f9a420 *** empty log message *** 2006-08-18 10:38:37 +00:00
Miklos Szeredi 2d2ad5176a new release 2006-08-17 10:13:02 +00:00
Miklos Szeredi 006aa04ff4 fix 2006-08-17 09:12:55 +00:00
Miklos Szeredi 4046be4487 fixes 2006-08-16 12:57:23 +00:00
Miklos Szeredi d8c313ff85 fix 2006-04-13 07:44:30 +00:00
Miklos Szeredi 666119d285 fix 2006-03-09 20:03:16 +00:00
Miklos Szeredi f3e8d58bd7 new release 2006-03-09 19:43:13 +00:00
Miklos Szeredi 326ff7f97e fix 2006-03-09 11:25:15 +00:00
Miklos Szeredi 7f4eaea507 fix 2006-03-08 14:32:16 +00:00
Miklos Szeredi 57fc3f4b6a fix 2006-02-24 11:42:40 +00:00
Miklos Szeredi b436754a11 fix 2006-02-23 21:31:41 +00:00
Miklos Szeredi e277fe1ca2 fix 2006-02-23 16:20:55 +00:00
Miklos Szeredi c9c9e9dfbd fix 2006-02-22 16:23:42 +00:00
Miklos Szeredi 3cfb3a6dab new release 2006-02-20 12:11:23 +00:00
Miklos Szeredi 790bb8dd36 fix 2006-02-20 11:44:36 +00:00
Miklos Szeredi accc218cdb revert making rename workaround on by default 2006-02-20 11:32:45 +00:00
Miklos Szeredi 8468900705 fix 2006-02-16 17:02:25 +00:00
Miklos Szeredi b60a970602 fix 2006-02-16 11:51:27 +00:00
Miklos Szeredi 27c1b7b09d fix 2006-02-02 12:07:14 +00:00
Miklos Szeredi 6f0233e11e fix 2006-02-01 15:50:44 +00:00
Miklos Szeredi 89da93d07e fix 2006-01-31 18:34:38 +00:00
Miklos Szeredi cb4239036a fix 2006-01-30 11:05:40 +00:00
Miklos Szeredi 40393a4b0b fix 2006-01-30 09:47:02 +00:00
Miklos Szeredi a6e0d2ddd9 fix 2006-01-27 16:30:55 +00:00
Miklos Szeredi 1cb9aba6ea fix 2006-01-27 12:49:14 +00:00
Miklos Szeredi 3883b4eb0c fix 2006-01-25 14:47:07 +00:00
Miklos Szeredi f1f738d5b8 fix 2006-01-23 17:03:25 +00:00
Miklos Szeredi d2a3ed327e fix 2006-01-20 16:29:23 +00:00
Miklos Szeredi cd6a924cdc fix 2006-01-18 14:05:48 +00:00
Miklos Szeredi 258c5ff728 new release 2006-01-14 23:02:33 +00:00
Miklos Szeredi 747ffa12f6 fix 2006-01-10 10:54:38 +00:00
Miklos Szeredi bad7f96bad *** empty log message *** 2006-01-09 17:27:28 +00:00
Miklos Szeredi a162ae9bd4 version change 2006-01-09 17:19:39 +00:00
Miklos Szeredi 95116f4b12 doc update 2006-01-09 17:01:21 +00:00
Miklos Szeredi 3f854ace05 fix 2006-01-09 16:51:06 +00:00
Miklos Szeredi 6a6476b52b fix 2006-01-09 10:09:09 +00:00
Miklos Szeredi 57a490e12a fix 2005-12-16 11:15:26 +00:00
Miklos Szeredi eddbd3967b fix 2005-12-09 20:30:32 +00:00
Miklos Szeredi 891a3e5d87 updated to use libfuse's option parsing 2005-12-09 17:43:06 +00:00
Miklos Szeredi 5dd6469a84 fix 2005-11-29 07:04:09 +00:00
Miklos Szeredi aa44e01549 fix 2005-11-23 13:13:42 +00:00
Miklos Szeredi e916cdd633 README update 2005-11-22 11:19:45 +00:00
Miklos Szeredi 0096ea860e README update 2005-11-22 11:19:21 +00:00
Miklos Szeredi 1f3cdff4ed fix 2005-11-16 18:50:55 +00:00
Miklos Szeredi c3b0185deb fix 2005-11-16 18:42:35 +00:00
Miklos Szeredi 7e97377d52 fix 2005-11-16 13:05:23 +00:00
Miklos Szeredi adba209812 fix 2005-11-07 15:51:14 +00:00
Miklos Szeredi 5377a9a571 fix 2005-11-07 15:49:24 +00:00
Miklos Szeredi cea6b546d1 *** empty log message *** 2005-10-29 09:59:28 +00:00
Miklos Szeredi 032d201d02 new release 2005-10-29 09:50:33 +00:00
Miklos Szeredi de2f4aabd1 fix 2005-10-28 12:19:21 +00:00
Miklos Szeredi 642d16587c fix 2005-10-28 12:12:57 +00:00
Miklos Szeredi 8bba944723 fix 2005-10-28 09:41:52 +00:00
Miklos Szeredi ad284c89a7 fix 2005-10-27 16:00:19 +00:00
Miklos Szeredi 9e1c63ecb9 fix 2005-10-26 11:30:51 +00:00
Miklos Szeredi 9f6bf0da77 fix 2005-10-20 10:39:51 +00:00
Miklos Szeredi 81928eda76 fix 2005-10-19 11:41:59 +00:00
Miklos Szeredi 1ff673ab5e fix 2005-10-19 11:38:56 +00:00
Miklos Szeredi 6d0e39592d fix 2005-10-19 11:30:11 +00:00
Miklos Szeredi 0bcb97098a add feature 2005-10-18 15:44:58 +00:00
Miklos Szeredi 8e2bfd7c4b fix 2005-10-17 16:01:45 +00:00
Miklos Szeredi d5f5babffd fix 2005-10-17 15:10:52 +00:00
Miklos Szeredi 42076a8575 whitespace cleanup 2005-10-17 12:58:58 +00:00
Miklos Szeredi 0358c96422 fix 2005-10-17 12:57:52 +00:00
Miklos Szeredi 205f9ac27e revert create method 2005-09-08 15:33:35 +00:00
Miklos Szeredi 95381c9bb4 fix 2005-08-23 15:41:02 +00:00
Miklos Szeredi 42676ca0f6 fix 2005-08-23 15:20:37 +00:00
Miklos Szeredi 5098495dbb ChangeLog fix 2005-08-15 16:16:26 +00:00
Miklos Szeredi adf379b056 fix 2005-08-15 09:07:44 +00:00
Miklos Szeredi 82d15b68d4 release 1.2 2005-08-15 08:58:26 +00:00
Miklos Szeredi 2d959740ea fix 2005-08-13 21:33:42 +00:00
Miklos Szeredi 28495b3bb2 reconnection 2005-08-13 21:17:11 +00:00
Miklos Szeredi 61a154807b fix 2005-05-05 11:55:53 +00:00
Miklos Szeredi c67cf9b98b fix 2005-05-05 11:33:39 +00:00
Miklos Szeredi effd586502 fix 2005-04-13 11:38:40 +00:00
Miklos Szeredi b1ddd5f430 fix 2005-03-08 13:11:12 +00:00
Miklos Szeredi b3aac4e035 whitespace fix 2005-03-04 11:22:31 +00:00
Miklos Szeredi 330c126684 fix 2005-03-04 11:19:41 +00:00
Miklos Szeredi 3cdf0a547a fix 2005-03-03 12:59:37 +00:00
Miklos Szeredi e233f82239 documentation fix 2005-02-27 19:39:04 +00:00
Miklos Szeredi 9693a8bf05 fix 2005-02-24 16:37:54 +00:00
Miklos Szeredi 80748b39e4 fix 2005-02-16 14:00:59 +00:00
Miklos Szeredi 8e303b9a01 fix 2005-02-14 17:22:08 +00:00
Miklos Szeredi 838fed1a3a fix 2005-02-09 15:12:51 +00:00
Miklos Szeredi 99acbfff7a fix 2005-02-09 13:45:11 +00:00
Miklos Szeredi 2705253d2c fix 2005-02-09 13:16:36 +00:00
Miklos Szeredi b318855315 fix 2005-02-09 09:46:04 +00:00
Miklos Szeredi da058cf9da fix 2005-02-08 16:47:54 +00:00
Miklos Szeredi a464d3ec2c option parsing 2005-02-08 16:15:58 +00:00
Miklos Szeredi d5696036a5 caching improvements 2005-02-08 11:15:46 +00:00
Miklos Szeredi 551e32210b *** empty log message *** 2005-02-07 17:09:27 +00:00
Miklos Szeredi 240b5f7bb5 fix 2005-02-07 17:08:27 +00:00
Miklos Szeredi 39b1a10bdb directory caching 2005-02-07 16:58:43 +00:00
Miklos Szeredi 386a7f67ab cleanup 2005-02-07 16:12:46 +00:00
Miklos Szeredi cdc0da7956 fix 2005-02-04 10:19:07 +00:00
Miklos Szeredi 733b3b1f4a *** empty log message *** 2005-02-04 10:15:46 +00:00
Miklos Szeredi 88ab18b8f8 release 1.0 2005-01-09 19:48:14 +00:00
Miklos Szeredi 716bfbf697 fix 2004-12-05 21:26:16 +00:00
Miklos Szeredi 7fb3a02ec5 *** empty log message *** 2004-12-04 21:20:50 +00:00
Miklos Szeredi b3483b6bb9 fix 2004-12-04 12:40:21 +00:00
Miklos Szeredi 6f3b9bfdd1 automakeify 2004-12-04 12:29:44 +00:00
Miklos Szeredi c73761963b fix 2004-11-29 19:13:15 +00:00
Miklos Szeredi 5dc1d26e70 optimizations 2004-11-26 12:17:39 +00:00
29 changed files with 7302 additions and 659 deletions
+25
View File
@@ -0,0 +1,25 @@
((python-mode . ((indent-tabs-mode . nil)))
(autoconf-mode . ((indent-tabs-mode . t)))
(c-mode . ((c-file-style . "stroustrup")
(indent-tabs-mode . t)
(tab-width . 8)
(c-basic-offset . 8)
(c-file-offsets .
((block-close . 0)
(brace-list-close . 0)
(brace-list-entry . 0)
(brace-list-intro . +)
(case-label . 0)
(class-close . 0)
(defun-block-intro . +)
(defun-close . 0)
(defun-open . 0)
(else-clause . 0)
(inclass . +)
(label . 0)
(statement . 0)
(statement-block-intro . +)
(statement-case-intro . +)
(statement-cont . +)
(substatement . +)
(topmost-intro . 0))))))
+36
View File
@@ -0,0 +1,36 @@
#
# NOTE! Don't add files that are generated in specific
# subdirectories here. Add them in the ".gitignore" file
# in that subdirectory instead.
#
# NOTE! Please use 'git ls-files -i --exclude-standard'
# command after changing this file, to see if there are
# any tracked files which get ignored after the change.
*.o
*.lo
*.la
*.gz
\#*#
*.orig
*~
Makefile.in
Makefile
*.m4
stamp-h*
config.*
sshfs.1
/sshfs
/ltmain.sh
/configure
/install-sh
/mkinstalldirs
/missing
/*.cache
/depcomp
/compile
/libtool
/INSTALL
/.pc
/patches
/m4
.deps/
+19
View File
@@ -0,0 +1,19 @@
sudo: required
dist: trusty
language:
- c
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- valgrind
- clang
- gcc
- gcc-6
- python-docutils
- python3-pip
install: test/travis-install.sh
script: test/travis-build.sh
+41
View File
@@ -0,0 +1,41 @@
Current Maintainer
------------------
Nikolaus Rath <Nikolaus@rath.org>
Past Maintainers
----------------
Miklos Szeredi <miklos@szeredi.hu> (until 12/2015)
Contributors (autogenerated list)
---------------------------------
Alan Jenkins <alan.christopher.jenkins@gmail.com>
Alexander Neumann <alexander@bumpern.de>
Anatol Pomozov <anatol.pomozov@gmail.com>
Benjamin Fleischer <fleiben@gmail.com>
Berserker <berserker.troll@yandex.com>
Bill Zissimopoulos <billziss@navimatics.com>
Brandon Carter <b-carter@users.noreply.github.com>
Chris Wolfe <cwolfe@chromium.org>
gala <gala132@users.noreply.github.com>
George Vlahavas <vlahavas@gmail.com>
G.raud Meyer <graud@gmx.com>
harrim4n <git@harrim4n.com>
Jakub Jelen <jjelen@redhat.com>
Julio Merino <jmmv@google.com>
Julio Merino <jmmv@meroh.net>
Mike Kelly <mike@pair.com>
Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi <mszeredi@suse.cz>
Nikolaus Rath <Nikolaus@rath.org>
Percy Jahn <email@percyjahn.de>
Qais Patankar <qaisjp@gmail.com>
Reid Wagner <wagnerreid@gmail.com>
Rian Hunter <rian@alum.mit.edu>
Timo Savola <timo.savola@iki.fi>
tpoindessous <thomas@poindessous.com>
Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
+339
View File
@@ -0,0 +1,339 @@
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.
+224
View File
@@ -0,0 +1,224 @@
Release 3.3.2 (2018-04-29)
--------------------------
* New `renamexdev` workaround.
Release 3.3.1 (2017-10-25)
--------------------------
* Manpage is now installed in correct directory.
* SSHFS now supports (or rather: ignores) some options that it may
receive as result of being mounted from ``/etc/mtab``. This includes
things like ``user``, ``netdev``, or ``auto``.
SSHFS 3.3.0 (2017-09-20)
------------------------
* Dropped support for writeback caching (and, as a consequence,
"unreliable append" operation). As of kernel 4.14, the FUSE module's
writeback implementation is not compatible with network filesystems
and there are no imminent plans to change that.
* Add support for mounting from /etc/fstab
* Dropped support for building with autotools.
* Added missing options to man page.
Release 3.2.0 (2017-08-06)
--------------------------
* Re-enabled writeback cache.
* SSHFS now supports O_APPEND.
Release 3.1.0 (2017-08-04)
--------------------------
* Temporarily disabled the writeback cache feature, since there
have been reports of dataloss when appending to files when
writeback caching is enabled.
* Fixed a crash due to a race condition when listing
directory contents.
* For improved backwards compatibility, SSHFS now also silently
accepts the old ``-o cache_*`` options.
Release 3.0.0 (2017-07-08)
--------------------------
* sshfs now requires libfuse 3.1.0 or newer.
* When supported by the kernel, sshfs now uses writeback caching.
* The `cache` option has been renamed to `dir_cache` for clarity.
* Added unit tests
* --debug now behaves like -o debug_sshfs, i.e. it enables sshfs
debugging messages rather than libfuse debugging messages.
* Documented limited hardlink support.
* Added support for building with Meson.
* Added support for more SSH options.
* Dropped support for the *nodelay* workaround - the last OpenSSH
version for which this was useful was released in 2006.
* Dropped 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`
* Removed support for `-o workaround=all`. Workarounds should always
enabled explicitly and only when needed. There is no point in always
enabling a potentially changing set of workarounds.
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 <Nikolaus@rath.org>)
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
-21
View File
@@ -1,21 +0,0 @@
CC = gcc
CFLAGS := -Wall -W -g
LDLIBS := -lpthread -ldl -rdynamic
PKGCONFIG := env PKG_CONFIG_PATH=/usr/local/lib/pkgconfig pkg-config
FUSEVER := $(shell $(PKGCONFIG) --modversion fuse 2> /dev/null)
ifeq ($(FUSEVER),)
LDLIBS += -lfuse
else
CFLAGS += $(shell $(PKGCONFIG) --cflags fuse)
LDLIBS += $(shell $(PKGCONFIG) --libs fuse)
endif
CPPFLAGS := -D_FILE_OFFSET_BITS=64
#CPPFLAGS += -DDEBUG
sshfs: sshfs.o
clean:
rm -f *.o sshfs
+94
View File
@@ -0,0 +1,94 @@
SSHFS
=====
About
-----
SSHFS allows you to mount a remote filesystem using SFTP. Most SSH
servers support and enable this SFTP access by default, so SSHFS is
very simple to use - there's nothing to do on the server-side.
How to use
----------
Once sshfs is installed (see next section) running it is very simple::
sshfs [user@]hostname:[directory] mountpoint
It is recommended to run SSHFS as regular user (not as root). For
this to work the mountpoint must be owned by the user. If username is
omitted SSHFS will use the local username. If the directory is
omitted, SSHFS will mount the (remote) home directory. If you need to
enter a password sshfs will ask for it (actually it just runs ssh
which ask for the password if needed).
Also many ssh options can be specified (see the manual pages for
*sftp(1)* and *ssh_config(5)*), including the remote port number
(``-oport=PORT``)
To unmount the filesystem::
fusermount -u mountpoint
On BSD and OS-X, to unmount the filesystem::
umount mountpoint
Installation
------------
First, download the latest SSHFS release from
https://github.com/libfuse/sshfs/releases. On Linux and BSD, you will
also need to install libfuse_ 3.1.0 or newer. On OS-X, you need
OSXFUSE_ instead. Finally, you need the Glib_ library with development
headers (which should be available from your operating system's
package manager).
To build and install, we recommend to use Meson_ (version 0.38 or
newer) and Ninja_. After extracting the sshfs tarball, create a
(temporary) build directory and run Meson::
$ mkdir build; cd build
$ meson ..
Normally, the default build options will work fine. If you
nevertheless want to adjust them, you can do so with the *mesonconf*
command::
$ mesonconf # list options
$ mesonconf -D strip=true # set an option
To build, test and install SSHFS, you then use Ninja (running the
tests requires the `py.test`_ Python module)::
$ ninja
$ python3 -m pytest test/ # optional, but recommended
$ sudo ninja install
.. _libfuse: http://github.com/libfuse/libfuse
.. _OSXFUSE: https://osxfuse.github.io/
.. _Glib: https://developer.gnome.org/glib/stable/
.. _Meson: http://mesonbuild.com/
.. _Ninja: https://ninja-build.org/
.. _`py.test`: http://www.pytest.org/
Getting Help
------------
If you need help, please ask on the <fuse-sshfs@lists.sourceforge.net>
mailing list (subscribe at
https://lists.sourceforge.net/lists/listinfo/fuse-sshfs).
Please report any bugs on the GitHub issue tracker at
https://github.com/libfuse/libfuse/issues.
Professional Support
--------------------
Professional support is offered via `Rath Consulting`_.
.. _`Rath Consulting`: http://www.rath-consulting.biz
+615
View File
@@ -0,0 +1,615 @@
/*
Caching file system proxy
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include "cache.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <pthread.h>
#define DEFAULT_CACHE_TIMEOUT_SECS 20
#define DEFAULT_MAX_CACHE_SIZE 10000
#define DEFAULT_CACHE_CLEAN_INTERVAL_SECS 60
#define DEFAULT_MIN_CACHE_CLEAN_INTERVAL_SECS 5
struct cache {
int on;
unsigned int stat_timeout_secs;
unsigned int dir_timeout_secs;
unsigned int link_timeout_secs;
unsigned int max_size;
unsigned int clean_interval_secs;
unsigned int min_clean_interval_secs;
struct fuse_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
uint64_t write_ctr;
};
static struct cache cache;
struct node {
struct stat stat;
time_t stat_valid;
char **dir;
time_t dir_valid;
char *link;
time_t link_valid;
time_t valid;
};
struct readdir_handle {
const char *path;
void *buf;
fuse_fill_dir_t filler;
GPtrArray *dir;
uint64_t wrctr;
};
struct file_handle {
/* Did we send an open request to the underlying fs? */
int is_open;
/* If so, this will hold its handle */
unsigned long fs_fh;
};
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
g_strfreev(node->dir);
g_free(node);
}
static int cache_clean_entry(void *key_, struct node *node, time_t *now)
{
(void) key_;
if (*now > node->valid)
return TRUE;
else
return FALSE;
}
static void cache_clean(void)
{
time_t now = time(NULL);
if (now > cache.last_cleaned + cache.min_clean_interval_secs &&
(g_hash_table_size(cache.table) > cache.max_size ||
now > cache.last_cleaned + cache.clean_interval_secs)) {
g_hash_table_foreach_remove(cache.table,
(GHRFunc) cache_clean_entry, &now);
cache.last_cleaned = now;
}
}
static struct node *cache_lookup(const char *path)
{
return (struct node *) g_hash_table_lookup(cache.table, path);
}
static void cache_purge(const char *path)
{
g_hash_table_remove(cache.table, path);
}
static void cache_purge_parent(const char *path)
{
const char *s = strrchr(path, '/');
if (s) {
if (s == path)
g_hash_table_remove(cache.table, "/");
else {
char *parent = g_strndup(path, s - path);
cache_purge(parent);
g_free(parent);
}
}
}
void cache_invalidate(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache.lock);
}
static void cache_invalidate_write(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache.write_ctr++;
pthread_mutex_unlock(&cache.lock);
}
static void cache_invalidate_dir(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache_purge_parent(path);
pthread_mutex_unlock(&cache.lock);
}
static int cache_del_children(const char *key, void *val_, const char *path)
{
(void) val_;
if (strncmp(key, path, strlen(path)) == 0)
return TRUE;
else
return FALSE;
}
static void cache_do_rename(const char *from, const char *to)
{
pthread_mutex_lock(&cache.lock);
g_hash_table_foreach_remove(cache.table, (GHRFunc) cache_del_children,
(char *) from);
cache_purge(from);
cache_purge(to);
cache_purge_parent(from);
cache_purge_parent(to);
pthread_mutex_unlock(&cache.lock);
}
static struct node *cache_get(const char *path)
{
struct node *node = cache_lookup(path);
if (node == NULL) {
char *pathcopy = g_strdup(path);
node = g_new0(struct node, 1);
g_hash_table_insert(cache.table, pathcopy, node);
}
return node;
}
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
{
struct node *node;
pthread_mutex_lock(&cache.lock);
if (wrctr == cache.write_ctr) {
node = cache_get(path);
node->stat = *stbuf;
node->stat_valid = time(NULL) + cache.stat_timeout_secs;
if (node->stat_valid > node->valid)
node->valid = node->stat_valid;
cache_clean();
}
pthread_mutex_unlock(&cache.lock);
}
static void cache_add_dir(const char *path, char **dir)
{
struct node *node;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
g_strfreev(node->dir);
node->dir = dir;
node->dir_valid = time(NULL) + cache.dir_timeout_secs;
if (node->dir_valid > node->valid)
node->valid = node->dir_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
}
static size_t my_strnlen(const char *s, size_t maxsize)
{
const char *p;
for (p = s; maxsize && *p; maxsize--, p++);
return p - s;
}
static void cache_add_link(const char *path, const char *link, size_t size)
{
struct node *node;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
node->link_valid = time(NULL) + cache.link_timeout_secs;
if (node->link_valid > node->valid)
node->valid = node->link_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
}
static int cache_get_attr(const char *path, struct stat *stbuf)
{
struct node *node;
int err = -EAGAIN;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->stat_valid - now >= 0) {
*stbuf = node->stat;
err = 0;
}
}
pthread_mutex_unlock(&cache.lock);
return err;
}
uint64_t cache_get_write_ctr(void)
{
uint64_t res;
pthread_mutex_lock(&cache.lock);
res = cache.write_ctr;
pthread_mutex_unlock(&cache.lock);
return res;
}
static void *cache_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
void *res;
res = cache.next_oper->init(conn, cfg);
// Cache requires a path for each request
cfg->nullpath_ok = 0;
return res;
}
static int cache_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
err = cache.next_oper->getattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
return err;
}
static int cache_readlink(const char *path, char *buf, size_t size)
{
struct node *node;
int err;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->link_valid - now >= 0) {
strncpy(buf, node->link, size-1);
buf[size-1] = '\0';
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
err = cache.next_oper->readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
return err;
}
static int cache_opendir(const char *path, struct fuse_file_info *fi)
{
(void) path;
struct file_handle *cfi;
cfi = malloc(sizeof(struct file_handle));
if(cfi == NULL)
return -ENOMEM;
cfi->is_open = 0;
fi->fh = (unsigned long) cfi;
return 0;
}
static int cache_releasedir(const char *path, struct fuse_file_info *fi)
{
int err;
struct file_handle *cfi;
cfi = (struct file_handle*) fi->fh;
if(cfi->is_open) {
fi->fh = cfi->fs_fh;
err = cache.next_oper->releasedir(path, fi);
} else
err = 0;
free(cfi);
return err;
}
static int cache_dirfill (void *buf, const char *name,
const struct stat *stbuf, off_t off,
enum fuse_fill_dir_flags flags)
{
int err;
struct readdir_handle *ch;
ch = (struct readdir_handle*) buf;
err = ch->filler(ch->buf, name, stbuf, off, flags);
if (!err) {
g_ptr_array_add(ch->dir, g_strdup(name));
if (stbuf->st_mode & S_IFMT) {
char *fullpath;
const char *basepath = !ch->path[1] ? "" : ch->path;
fullpath = g_strdup_printf("%s/%s", basepath, name);
cache_add_attr(fullpath, stbuf, ch->wrctr);
g_free(fullpath);
}
}
return err;
}
static int cache_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 readdir_handle ch;
struct file_handle *cfi;
int err;
char **dir;
struct node *node;
assert(offset == 0);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL && node->dir != NULL) {
time_t now = time(NULL);
if (node->dir_valid - now >= 0) {
for(dir = node->dir; *dir != NULL; dir++)
// FIXME: What about st_mode?
filler(buf, *dir, NULL, 0, 0);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
cfi = (struct file_handle*) fi->fh;
if(cfi->is_open)
fi->fh = cfi->fs_fh;
else {
if(cache.next_oper->opendir) {
err = cache.next_oper->opendir(path, fi);
if(err)
return err;
}
cfi->is_open = 1;
cfi->fs_fh = fi->fh;
}
ch.path = path;
ch.buf = buf;
ch.filler = filler;
ch.dir = g_ptr_array_new();
ch.wrctr = cache_get_write_ctr();
err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi, flags);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err) {
cache_add_dir(path, dir);
} else {
g_strfreev(dir);
}
g_ptr_array_free(ch.dir, FALSE);
return err;
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
int err = cache.next_oper->mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_mkdir(const char *path, mode_t mode)
{
int err = cache.next_oper->mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_unlink(const char *path)
{
int err = cache.next_oper->unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_rmdir(const char *path)
{
int err = cache.next_oper->rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_symlink(const char *from, const char *to)
{
int err = cache.next_oper->symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
}
static int cache_rename(const char *from, const char *to, unsigned int flags)
{
int err = cache.next_oper->rename(from, to, flags);
if (!err)
cache_do_rename(from, to);
return err;
}
static int cache_link(const char *from, const char *to)
{
int err = cache.next_oper->link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
}
return err;
}
static int cache_chmod(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->chmod(path, mode, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_chown(const char *path, uid_t uid, gid_t gid,
struct fuse_file_info *fi)
{
int err = cache.next_oper->chown(path, uid, gid, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_utimens(const char *path, const struct timespec tv[2],
struct fuse_file_info *fi)
{
int err = cache.next_oper->utimens(path, tv, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int res = cache.next_oper->write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate_write(path);
return res;
}
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int err = cache.next_oper->truncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
}
static void cache_fill(struct fuse_operations *oper,
struct fuse_operations *cache_oper)
{
cache_oper->access = oper->access;
cache_oper->chmod = oper->chmod ? cache_chmod : NULL;
cache_oper->chown = oper->chown ? cache_chown : NULL;
cache_oper->create = oper->create ? cache_create : NULL;
cache_oper->flush = oper->flush;
cache_oper->fsync = oper->fsync;
cache_oper->getattr = oper->getattr ? cache_getattr : NULL;
cache_oper->getxattr = oper->getxattr;
cache_oper->init = cache_init;
cache_oper->link = oper->link ? cache_link : NULL;
cache_oper->listxattr = oper->listxattr;
cache_oper->mkdir = oper->mkdir ? cache_mkdir : NULL;
cache_oper->mknod = oper->mknod ? cache_mknod : NULL;
cache_oper->open = oper->open;
cache_oper->opendir = cache_opendir;
cache_oper->read = oper->read;
cache_oper->readdir = oper->readdir ? cache_readdir : NULL;
cache_oper->readlink = oper->readlink ? cache_readlink : NULL;
cache_oper->release = oper->release;
cache_oper->releasedir = cache_releasedir;
cache_oper->removexattr = oper->removexattr;
cache_oper->rename = oper->rename ? cache_rename : NULL;
cache_oper->rmdir = oper->rmdir ? cache_rmdir : NULL;
cache_oper->setxattr = oper->setxattr;
cache_oper->statfs = oper->statfs;
cache_oper->symlink = oper->symlink ? cache_symlink : NULL;
cache_oper->truncate = oper->truncate ? cache_truncate : NULL;
cache_oper->unlink = oper->unlink ? cache_unlink : NULL;
cache_oper->utimens = oper->utimens ? cache_utimens : NULL;
cache_oper->write = oper->write ? cache_write : NULL;
}
struct fuse_operations *cache_wrap(struct fuse_operations *oper)
{
static struct fuse_operations cache_oper;
cache.next_oper = oper;
cache_fill(oper, &cache_oper);
pthread_mutex_init(&cache.lock, NULL);
cache.table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, free_node);
if (cache.table == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;
}
return &cache_oper;
}
static const struct fuse_opt cache_opts[] = {
{ "dcache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "dcache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "dcache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "dcache_stat_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "dcache_dir_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "dcache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "dcache_max_size=%u", offsetof(struct cache, max_size), 0 },
{ "dcache_clean_interval=%u", offsetof(struct cache,
clean_interval_secs), 0 },
{ "dcache_min_clean_interval=%u", offsetof(struct cache,
min_clean_interval_secs), 0 },
/* For backwards compatibility */
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "cache_max_size=%u", offsetof(struct cache, max_size), 0 },
{ "cache_clean_interval=%u", offsetof(struct cache,
clean_interval_secs), 0 },
{ "cache_min_clean_interval=%u", offsetof(struct cache,
min_clean_interval_secs), 0 },
FUSE_OPT_END
};
int cache_parse_options(struct fuse_args *args)
{
cache.stat_timeout_secs = DEFAULT_CACHE_TIMEOUT_SECS;
cache.dir_timeout_secs = DEFAULT_CACHE_TIMEOUT_SECS;
cache.link_timeout_secs = DEFAULT_CACHE_TIMEOUT_SECS;
cache.max_size = DEFAULT_MAX_CACHE_SIZE;
cache.clean_interval_secs = DEFAULT_CACHE_CLEAN_INTERVAL_SECS;
cache.min_clean_interval_secs = DEFAULT_MIN_CACHE_CLEAN_INTERVAL_SECS;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
+16
View File
@@ -0,0 +1,16 @@
/*
Caching file system proxy
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include <fuse.h>
#include <fuse_opt.h>
struct fuse_operations *cache_wrap(struct fuse_operations *oper);
int cache_parse_options(struct fuse_args *args);
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr);
void cache_invalidate(const char *path);
uint64_t cache_get_write_ctr(void);
+246
View File
@@ -0,0 +1,246 @@
/*
* Copyright (c) 2006-2008 Amit Singh/Google Inc.
* Copyright (c) 2012 Anatol Pomozov
* Copyright (c) 2011-2013 Benjamin Fleischer
*/
#include "darwin_compat.h"
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
/*
* Semaphore implementation based on:
*
* Copyright (C) 2000,02 Free Software Foundation, Inc.
* This file is part of the GNU C Library.
* Written by Ga<EB>l Le Mignot <address@hidden>
*
* The GNU C Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* The GNU C 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with the GNU C Library; see the file COPYING.LIB. If not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* Semaphores */
#define __SEM_ID_NONE ((int)0x0)
#define __SEM_ID_LOCAL ((int)0xcafef00d)
/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_init.html */
int
darwin_sem_init(darwin_sem_t *sem, int pshared, unsigned int value)
{
if (pshared) {
errno = ENOSYS;
return -1;
}
sem->id = __SEM_ID_NONE;
if (pthread_cond_init(&sem->__data.local.count_cond, NULL)) {
goto cond_init_fail;
}
if (pthread_mutex_init(&sem->__data.local.count_lock, NULL)) {
goto mutex_init_fail;
}
sem->__data.local.count = value;
sem->id = __SEM_ID_LOCAL;
return 0;
mutex_init_fail:
pthread_cond_destroy(&sem->__data.local.count_cond);
cond_init_fail:
return -1;
}
/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_destroy.html */
int
darwin_sem_destroy(darwin_sem_t *sem)
{
int res = 0;
pthread_mutex_lock(&sem->__data.local.count_lock);
sem->id = __SEM_ID_NONE;
pthread_cond_broadcast(&sem->__data.local.count_cond);
if (pthread_cond_destroy(&sem->__data.local.count_cond)) {
res = -1;
}
pthread_mutex_unlock(&sem->__data.local.count_lock);
if (pthread_mutex_destroy(&sem->__data.local.count_lock)) {
res = -1;
}
return res;
}
int
darwin_sem_getvalue(darwin_sem_t *sem, unsigned int *sval)
{
int res = 0;
pthread_mutex_lock(&sem->__data.local.count_lock);
if (sem->id != __SEM_ID_LOCAL) {
res = -1;
errno = EINVAL;
} else {
*sval = sem->__data.local.count;
}
pthread_mutex_unlock(&sem->__data.local.count_lock);
return res;
}
/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_post.html */
int
darwin_sem_post(darwin_sem_t *sem)
{
int res = 0;
pthread_mutex_lock(&sem->__data.local.count_lock);
if (sem->id != __SEM_ID_LOCAL) {
res = -1;
errno = EINVAL;
} else if (sem->__data.local.count < DARWIN_SEM_VALUE_MAX) {
sem->__data.local.count++;
if (sem->__data.local.count == 1) {
pthread_cond_signal(&sem->__data.local.count_cond);
}
} else {
errno = ERANGE;
res = -1;
}
pthread_mutex_unlock(&sem->__data.local.count_lock);
return res;
}
/* http://www.opengroup.org/onlinepubs/009695399/functions/sem_timedwait.html */
int
darwin_sem_timedwait(darwin_sem_t *sem, const struct timespec *abs_timeout)
{
int res = 0;
if (abs_timeout &&
(abs_timeout->tv_nsec < 0 || abs_timeout->tv_nsec >= 1000000000)) {
errno = EINVAL;
return -1;
}
pthread_cleanup_push((void(*)(void*))&pthread_mutex_unlock,
&sem->__data.local.count_lock);
pthread_mutex_lock(&sem->__data.local.count_lock);
if (sem->id != __SEM_ID_LOCAL) {
errno = EINVAL;
res = -1;
} else {
if (!sem->__data.local.count) {
res = pthread_cond_timedwait(&sem->__data.local.count_cond,
&sem->__data.local.count_lock,
abs_timeout);
}
if (res) {
assert(res == ETIMEDOUT);
res = -1;
errno = ETIMEDOUT;
} else if (sem->id != __SEM_ID_LOCAL) {
res = -1;
errno = EINVAL;
} else {
sem->__data.local.count--;
}
}
pthread_cleanup_pop(1);
return res;
}
/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_trywait.html */
int
darwin_sem_trywait(darwin_sem_t *sem)
{
int res = 0;
pthread_mutex_lock(&sem->__data.local.count_lock);
if (sem->id != __SEM_ID_LOCAL) {
res = -1;
errno = EINVAL;
} else if (sem->__data.local.count) {
sem->__data.local.count--;
} else {
res = -1;
errno = EAGAIN;
}
pthread_mutex_unlock (&sem->__data.local.count_lock);
return res;
}
/* http://www.opengroup.org/onlinepubs/007908799/xsh/sem_wait.html */
int
darwin_sem_wait(darwin_sem_t *sem)
{
int res = 0;
pthread_cleanup_push((void(*)(void*))&pthread_mutex_unlock,
&sem->__data.local.count_lock);
pthread_mutex_lock(&sem->__data.local.count_lock);
if (sem->id != __SEM_ID_LOCAL) {
errno = EINVAL;
res = -1;
} else {
if (!sem->__data.local.count) {
pthread_cond_wait(&sem->__data.local.count_cond,
&sem->__data.local.count_lock);
if (!sem->__data.local.count) {
/* spurious wakeup, assume it is an interruption */
res = -1;
errno = EINTR;
goto out;
}
}
if (sem->id != __SEM_ID_LOCAL) {
res = -1;
errno = EINVAL;
} else {
sem->__data.local.count--;
}
}
out:
pthread_cleanup_pop(1);
return res;
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2006-2008 Amit Singh/Google Inc.
* Copyright (c) 2011-2013 Benjamin Fleischer
*/
#ifndef _DARWIN_COMPAT_
#define _DARWIN_COMPAT_
#include <pthread.h>
/* Semaphores */
typedef struct darwin_sem {
int id;
union {
struct
{
unsigned int count;
pthread_mutex_t count_lock;
pthread_cond_t count_cond;
} local;
} __data;
} darwin_sem_t;
#define DARWIN_SEM_VALUE_MAX ((int32_t)32767)
int darwin_sem_init(darwin_sem_t *sem, int pshared, unsigned int value);
int darwin_sem_destroy(darwin_sem_t *sem);
int darwin_sem_getvalue(darwin_sem_t *sem, unsigned int *value);
int darwin_sem_post(darwin_sem_t *sem);
int darwin_sem_timedwait(darwin_sem_t *sem, const struct timespec *abs_timeout);
int darwin_sem_trywait(darwin_sem_t *sem);
int darwin_sem_wait(darwin_sem_t *sem);
/* Caller must not include <semaphore.h> */
typedef darwin_sem_t sem_t;
#define sem_init(s, p, v) darwin_sem_init(s, p, v)
#define sem_destroy(s) darwin_sem_destroy(s)
#define sem_getvalue(s, v) darwin_sem_getvalue(s, v)
#define sem_post(s) darwin_sem_post(s)
#define sem_timedwait(s, t) darwin_sem_timedwait(s, t)
#define sem_trywait(s) darwin_sem_trywait(s)
#define sem_wait(s) darwin_sem_wait(s)
#define SEM_VALUE_MAX DARWIN_SEM_VALUE_MAX
#endif /* _DARWIN_COMPAT_ */
+364
View File
@@ -0,0 +1,364 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPL.
See the file COPYING.LIB
*/
#include "fuse_opt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
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 && args->argv && args->allocated) {
int i;
for (i = 0; i < args->argc; i++)
free(args->argv[i]);
free(args->argv);
args->argv = NULL;
args->allocated = 0;
}
}
static int alloc_failed(void)
{
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
{
char **newargv;
char *newarg;
assert(!args->argv || args->allocated);
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
newarg = newargv ? strdup(arg) : NULL;
if (!newargv || !newarg)
return alloc_failed();
args->argv = newargv;
args->allocated = 1;
args->argv[args->argc++] = newarg;
args->argv[args->argc] = NULL;
return 0;
}
int fuse_opt_insert_arg(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;
}
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
{
if (ctx->argctr + 1 >= ctx->argc) {
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
return -1;
}
ctx->argctr++;
return 0;
}
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
{
return fuse_opt_add_arg(&ctx->outargs, arg);
}
int fuse_opt_add_opt(char **opts, const char *opt)
{
char *newopts;
if (!*opts)
newopts = strdup(opt);
else {
unsigned oldlen = strlen(*opts);
newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
if (newopts) {
newopts[oldlen] = ',';
strcpy(newopts + oldlen + 1, opt);
}
}
if (!newopts)
return alloc_failed();
*opts = newopts;
return 0;
}
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
{
return fuse_opt_add_opt(&ctx->opts, opt);
}
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 *copy = strdup(param);
if (!copy)
return alloc_failed();
*(char **) var = copy;
} else {
if (sscanf(param, format, var) != 1) {
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
return -1;
}
}
return 0;
}
static int process_opt(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
if (opt->offset == -1U) {
if (call_proc(ctx, arg, opt->value, iso) == -1)
return -1;
} else {
void *var = ctx->data + opt->offset;
if (sep && opt->templ[sep + 1]) {
const char *param = arg + sep;
if (opt->templ[sep] == '=')
param ++;
if (process_opt_param(var, opt->templ + sep + 1,
param, arg) == -1)
return -1;
} else
*(int *)var = opt->value;
}
return 0;
}
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 *sep;
do {
int res;
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;
opts = sep + 1;
} while (sep);
return 0;
}
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
{
int res;
char *copy;
const char *sep = strchr(opts, ',');
if (!sep)
return process_gopt(ctx, opts, 1);
copy = strdup(opts);
if (!copy) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
res = process_real_option_group(ctx, copy);
free(copy);
return res;
}
static int process_one(struct fuse_opt_context *ctx, const char *arg)
{
if (ctx->nonopt || arg[0] != '-')
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
else if (arg[1] == 'o') {
if (arg[2])
return process_option_group(ctx, arg + 2);
else {
if (next_arg(ctx, arg) == -1)
return -1;
return process_option_group(ctx, ctx->argv[ctx->argctr]);
}
} else if (arg[1] == '-' && !arg[2]) {
if (add_arg(ctx, arg) == -1)
return -1;
ctx->nonopt = ctx->outargs.argc;
return 0;
} else
return process_gopt(ctx, arg, 0);
}
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 (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
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;
}
+258
View File
@@ -0,0 +1,258 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#ifndef _FUSE_OPT_H_
#define _FUSE_OPT_H_
/* This file defines the option parsing interface of FUSE */
#ifdef __cplusplus
extern "C" {
#endif
/**
* Option description
*
* This structure describes a single option, and 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().
*/
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 { .templ = NULL }
/**
* 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 charater 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 arguemnt 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 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 beggining 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_ */
+30
View File
@@ -0,0 +1,30 @@
#!/bin/sh
#
# Create tarball from Git tag, removing and adding
# some files.
#
set -e
if [ -z "$1" ]; then
TAG="$(git tag --list 'sshfs-3*' --sort=-taggerdate | head -1)"
else
TAG="$1"
fi
echo "Creating release tarball for ${TAG}..."
mkdir "${TAG}"
git archive --format=tar "${TAG}" | tar -x "--directory=${TAG}"
find "${TAG}" -name .gitignore -delete
rm "${TAG}/make_release_tarball.sh" \
"${TAG}/.travis.yml" \
"${TAG}/test/travis-build.sh" \
"${TAG}/test/travis-install.sh"
tar -cJf "${TAG}.tar.xz" "${TAG}/"
gpg --armor --detach-sign "${TAG}.tar.xz"
PREV_TAG="$(git tag --list 'sshfs-3*' --sort=-taggerdate --merged "${TAG}^"| head -1)"
echo "Contributors from ${PREV_TAG} to ${TAG}:"
git log --pretty="format:%an <%aE>" "${PREV_TAG}..${TAG}" | sort -u
+72
View File
@@ -0,0 +1,72 @@
project('sshfs', 'c', version: '3.3.2',
meson_version: '>= 0.38',
default_options: [ 'buildtype=debugoptimized' ])
add_global_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H',
'-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
rst2man = find_program('rst2man', required: false)
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(output: 'config.h',
configuration : cfg)
sshfs_deps = [ dependency('fuse3', version: '>= 3.1.0'),
dependency('glib-2.0'),
dependency('gthread-2.0') ]
executable('sshfs', sshfs_sources,
include_directories: include_dirs,
dependencies: sshfs_deps,
c_args: ['-DFUSE_USE_VERSION=31'],
install: true,
install_dir: get_option('bindir'))
if rst2man.found()
custom_target('manpages', input: [ 'sshfs.rst' ], output: [ 'sshfs.1' ],
command: [rst2man, '@INPUT@', '@OUTPUT@'], install: true,
install_dir: join_paths(get_option('mandir'), 'man1'))
else
message('rst2man not found, not building manual page.')
endif
meson.add_install_script('utils/install_helper.sh',
get_option('sbindir'),
get_option('bindir'))
subdir('test')
+3839 -638
View File
File diff suppressed because it is too large Load Diff
+286
View File
@@ -0,0 +1,286 @@
=======
SSHFS
=======
---------------------------------------------
filesystem client based on SSH
---------------------------------------------
:Manual section: 1
:Manual group: User Commands
Synopsis
========
To mount a filesystem::
sshfs [user@]host:[dir] mountpoint [options]
If *host* is a numeric IPv6 address, it needs to be enclosed in square
brackets.
To unmount it::
fusermount3 -u mountpoint # Linux
umount mountpoint # OS X, FreeBSD
Description
===========
SSHFS allows you to mount a remote filesystem using SSH (more
precisely, the SFTP subsystem). Most SSH servers support and enable
this SFTP access by default, so SSHFS is very simple to use - there's
nothing to do on the server-side.
SSHFS uses FUSE (Filesystem in Userspace) and should work on any
operating system that provides a FUSE implementation. Currently,
this includes Linux, FreeBSD and Mac OS X.
It is recommended to run SSHFS as regular user (not as root). For
this to work the mountpoint must be owned by the user. If username is
omitted SSHFS will use the local username. If the directory is
omitted, SSHFS will mount the (remote) home directory. If you need to
enter a password sshfs will ask for it (actually it just runs ssh
which ask for the password if needed).
Options
=======
-o opt,[opt...]
mount options, see below for details. A a variety of SSH options can
be given here as well, see the manual pages for *sftp(1)* and
*ssh_config(5)*.
-h, --help
print help and exit.
-V, --version
print version information and exit.
-d, --debug
print debugging information.
-p PORT
equivalent to '-o port=PORT'
-f
do not daemonize, stay in foreground.
-s
Single threaded operation.
-C
equivalent to '-o compression=yes'
-F ssh_configfile
specifies alternative ssh configuration file
-1
equivalent to '-o ssh_protocol=1'
-o reconnect
automatically reconnect to server if connection is
interrupted. Attempts to access files that were opened before the
reconnection will give errors and need to be re-opened.
-o delay_connect
Don't immediately connect to server, wait until mountpoint is first
accessed.
-o sshfs_sync
synchronous writes. This will slow things down, but may be useful
in some situations.
-o no_readahead
Only read exactly the data that was requested, instead of
speculatively reading more to anticipate the next read request.
-o sync_readdir
synchronous readdir. This will slow things down, but may be useful
in some situations.
-o workaround=LIST
Enable the specified workaround. See the `Caveats` section below
for some additional information. Possible values are:
:rename: Emulate overwriting an existing file by deleting and
renaming.
:renamexdev: Make rename fail with EXDEV instead of the default EPERM
to allow moving files across remote filesystems.
:truncate: Work around servers that don't support truncate by
coping the whole file, truncating it locally, and sending it
back.
:fstat: Work around broken servers that don't support *fstat()* by
using *stat* instead.
:buflimit: Work around OpenSSH "buffer fillup" bug.
-o idmap=TYPE
How to map remote UID/GIDs to local values. Possible values are:
:none: no translation of the ID space (default).
:user: map the UID/GID of the remote user to UID/GID of the
mounting user.
:file: translate UIDs/GIDs based upon the contents of `--uidfile`
and `--gidfile`.
-o uidfile=FILE
file containing ``username:uid`` mappings for `-o idmap=file`
-o gidfile=FILE
file containing ``groupname:gid`` mappings for `-o idmap=file`
-o nomap=TYPE
with idmap=file, how to handle missing mappings:
:ignore: don't do any re-mapping
:error: return an error (default)
-o ssh_command=CMD
execute CMD instead of 'ssh'
-o ssh_protocol=N
ssh protocol to use (default: 2)
-o sftp_server=SERV
path to sftp server or subsystem (default: sftp)
-o directport=PORT
directly connect to PORT bypassing ssh
-o slave
communicate over stdin and stdout bypassing network
-o disable_hardlink
With this option set, attempts to call `link(2)` will fail with
error code ENOSYS.
-o transform_symlinks
transform absolute symlinks on remote side to relative
symlinks. This means that if e.g. on the server side
``/foo/bar/com`` is a symlink to ``/foo/blub``, SSHFS will
transform the link target to ``../blub`` on the client side.
-o follow_symlinks
follow symlinks on the server, i.e. present them as regular
files on the client. If a symlink is dangling (i.e, the target does
not exist) the behavior depends on the remote server - the entry
may appear as a symlink on the client, or it may appear as a
regular file that cannot be accessed.
-o no_check_root
don't check for existence of 'dir' on server
-o password_stdin
read password from stdin (only for pam_mount!)
-o dir_cache=BOOL
Enables (*yes*) or disables (*no*) the SSHFS directory cache. The
directory cache holds the names of directory entries. Enabling it
allows `readdir(3)` system calls to be processed without network
access.
-o dcache_max_size=N
sets the maximum size of the directory cache.
-o dcache_timeout=N
sets timeout for directory cache in seconds.
-o dcache_{stat,link,dir}_timeout=N
sets separate timeout for {attributes, symlinks, names} in the
directory cache.
-o dcache_clean_interval=N
sets the interval for automatic cleaning of the directory cache.
-o dcache_min_clean_interval=N
sets the interval for forced cleaning of the directory cache
when full.
In addition, SSHFS accepts several options common to all FUSE file
systems. These are described in the `mount.fuse` manpage (look
for "general", "libfuse specific", and "high-level API" options).
Caveats / Workarounds
=====================
Hardlinks
~~~~~~~~~
If the SSH server supports the *hardlinks* extension, SSHFS will allow
you to create hardlinks. However, hardlinks will always appear as
individual files when seen through an SSHFS mount, i.e. they will
appear to have different inodes and an *st_nlink* value of 1.
Rename
~~~~~~
Some SSH servers do not support atomically overwriting the destination
when renaming a file. In this case you will get an error when you
attempt to rename a file and the destination already exists. A
workaround is to first remove the destination file, and then do the
rename. SSHFS can do this automatically if you call it with `-o
workaround=rename`. However, in this case it is still possible that
someone (or something) recreates the destination file after SSHFS has
removed it, but before SSHFS had the time to rename the old file. In
this case, the rename will still fail.
Permission denied when moving files across remote filesystems
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Most SFTP servers return only a generic "failure" when failing to rename
across filesystem boundaries (EXDEV). sshfs normally converts this generic
failure to a permission denied error (EPERM). If the option ``-o
workaround=renamexdev`` is given, generic failures will be considered EXDEV
errors which will make programs like `mv(1)` attempt to actually move the
file after the failed rename.
SSHFS hangs
~~~~~~~~~~~
In some cases, attempts to access the SSHFS mountpoint may freeze if
no filesystem activity has occured for some time. This is typically
caused by the SSH connection being dropped because of inactivity
without SSHFS being informed about that. As a workaround, you can try
to mount with ``-o ServerAliveInterval=15``. This will force the SSH
connection to stay alive even if you have no activity.
Mounting from /etc/fstab
========================
To mount an SSHFS filesystem from ``/etc/fstab``, simply use ``sshfs`
as the file system type. (For backwards compatibility, you may also
use ``fuse.sshfs``).
See also
========
The `mount.fuse(8)` manpage.
Getting Help
============
If you need help, please ask on the <fuse-sshfs@lists.sourceforge.net>
mailing list (subscribe at
https://lists.sourceforge.net/lists/listinfo/fuse-sshfs).
Please report any bugs on the GitHub issue tracker at
https://github.com/libfuse/libfuse/issues.
Authors
=======
SSHFS is currently maintained by Nikolaus Rath <Nikolaus@rath.org>,
and was created by Miklos Szeredi <miklos@szeredi.hu>.
This man page was originally written by Bartosz Fenski
<fenio@debian.org> for the Debian GNU/Linux distribution (but it may
be used by others).
+1
View File
@@ -0,0 +1 @@
__pycache__/
+89
View File
@@ -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.
@pytest.mark.hookwrapper
def pytest_pyfunc_call(pyfuncitem):
outcome = yield
failed = outcome.excinfo is not None
if failed:
time.sleep(1)
@pytest.fixture()
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
@pytest.yield_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
@pytest.hookimpl(trylast=True)
def pytest_runtest_call(item):
capfd = current_capfd
if capfd is not None:
check_test_output(capfd)
+11
View File
@@ -0,0 +1,11 @@
# Suppression file for address sanitizer.
# There are some leaks in command line option parsing. They should be
# fixed at some point, but are harmless since the consume just a small,
# constant amount of memory and do not grow.
leak:fuse_opt_parse
# Leaks in fusermount3 are harmless as well (it's a short-lived
# process) - but patches are welcome!
leak:fusermount.c
+11
View File
@@ -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', '-fPp',
'@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)
+2
View File
@@ -0,0 +1,2 @@
[pytest]
addopts = --verbose --assert=rewrite --tb=native -x -r a
+431
View File
@@ -0,0 +1,431 @@
#!/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 contextlib import contextmanager
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]
@pytest.mark.parametrize("debug", (False, True))
@pytest.mark.parametrize("cache_timeout", (0,1))
@pytest.mark.parametrize("sync_rd", (True, False))
def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, 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' ]
if sync_rd:
cmdline += [ '-o', 'sync_readdir' ]
# SSHFS Cache
if cache_timeout == 0:
cmdline += [ '-o', 'dir_cache=no' ]
else:
cmdline += [ '-o', 'dcache_timeout=%d' % cache_timeout,
'-o', 'dir_cache=yes' ]
# 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_append(src_dir, mnt_dir)
tst_seek(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, cache_timeout)
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)
@contextmanager
def os_open(name, flags):
fd = os.open(name, flags)
try:
yield fd
finally:
os.close(fd)
def os_create(name):
os.close(os.open(name, os.O_CREAT | os.O_RDWR))
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_append(src_dir, mnt_dir):
name = name_generator()
os_create(pjoin(src_dir, name))
fullname = pjoin(mnt_dir, name)
with os_open(fullname, os.O_WRONLY) as fd:
os.write(fd, b'foo\n')
with os_open(fullname, os.O_WRONLY|os.O_APPEND) as fd:
os.write(fd, b'bar\n')
with open(fullname, 'rb') as fh:
assert fh.read() == b'foo\nbar\n'
def tst_seek(src_dir, mnt_dir):
name = name_generator()
os_create(pjoin(src_dir, name))
fullname = pjoin(mnt_dir, name)
with os_open(fullname, os.O_WRONLY) as fd:
os.lseek(fd, 1, os.SEEK_SET)
os.write(fd, b'foobar\n')
with os_open(fullname, os.O_WRONLY) as fd:
os.lseek(fd, 4, os.SEEK_SET)
os.write(fd, b'com')
with open(fullname, 'rb') as fh:
assert fh.read() == b'\0foocom\n'
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, cache_timeout):
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)
# The link operation changes st_ctime, and if we're unlucky
# the kernel will keep the old value cached for name1, and
# retrieve the new value for name2 (at least, this is the only
# way I can explain the test failure). To avoid this problem,
# we need to wait until the cached value has expired.
if cache_timeout:
safe_sleep(cache_timeout)
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)
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
set -e
# Disable leak checking for now, there are some issues (or false positives)
# that we still need to fix
export ASAN_OPTIONS="detect_leaks=0"
export LSAN_OPTIONS="suppressions=$(pwd)/test/lsan_suppress.txt"
export CC
TEST_CMD="python3 -m pytest --maxfail=99 test/"
# Standard build with Valgrind
for CC in gcc gcc-6 clang; do
mkdir build-${CC}; cd build-${CC}
if [ ${CC} == 'gcc-6' ]; then
build_opts='-D b_lundef=false'
else
build_opts=''
fi
meson -D werror=true ${build_opts} ../
ninja
TEST_WITH_VALGRIND=true ${TEST_CMD}
cd ..
done
(cd build-$CC; sudo ninja install)
# Sanitized build
CC=clang
for san in undefined address; do
mkdir build-${san}; cd build-${san}
# b_lundef=false is required to work around clang
# bug, cf. https://groups.google.com/forum/#!topic/mesonbuild/tgEdAXIIdC4
meson -D b_sanitize=${san} -D b_lundef=false -D werror=true ..
ninja
${TEST_CMD}
sudo ninja install
cd ..
done
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
set -e
# Meson 0.45 requires Python 3.5 or newer
sudo python3 -m pip install pytest meson==0.44
wget https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip
unzip ninja-linux.zip
chmod 755 ninja
sudo chown root:root ninja
sudo mv -fv ninja /usr/local/bin
valgrind --version
ninja --version
meson --version
# Install fuse
wget https://github.com/libfuse/libfuse/archive/master.zip
unzip master.zip
cd libfuse-master
mkdir build
cd build
export CC=gcc-6
meson ..
ninja
sudo ninja install
test -e /usr/local/lib/pkgconfig || sudo mkdir /usr/local/lib/pkgconfig
sudo mv /usr/local/lib/*/pkgconfig/* /usr/local/lib/pkgconfig/
ls -d1 /usr/local/lib/*-linux-gnu | sudo tee /etc/ld.so.conf.d/usrlocal.conf
sudo ldconfig
# Setup ssh
ssh-keygen -b 768 -t rsa -f ~/.ssh/id_rsa -P ''
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
ssh -o "StrictHostKeyChecking=no" localhost echo "SSH connection succeeded"
+100
View File
@@ -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 = []
+9
View File
@@ -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;
}
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
#
# Don't call this script. It is used internally by the Meson
# build system. Thank you for your cooperation.
#
set -e
bindir="$2"
sbindir="$1"
prefix="${MESON_INSTALL_DESTDIR_PREFIX}"
mkdir -p "${prefix}/${sbindir}"
ln -svf --relative "${prefix}/${bindir}/sshfs" \
"${prefix}/${sbindir}/mount.sshfs"
ln -svf --relative "${prefix}/${bindir}/sshfs" \
"${prefix}/${sbindir}/mount.fuse.sshfs"