Compare commits

..

119 Commits

Author SHA1 Message Date
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
14 changed files with 4944 additions and 940 deletions
+2
View File
@@ -1,12 +1,14 @@
.deps
COPYING
INSTALL
FAQ.txt
Makefile
Makefile.in
aclocal.m4
*.cache
config.*
configure
compile
depcomp
install-sh
missing
+421
View File
@@ -1,3 +1,424 @@
2008-04-23 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.0
2008-04-23 Miklos Szeredi <miklos@szeredi.hu>
* Add manual page. Written by Bartosz Fenski
2008-04-22 Miklos Szeredi <miklos@szeredi.hu>
* Add missing ssh options: ControlMaster, ControlPath,
KbdInteractiveAuthentication, KbdInteractiveDevices, LocalCommand,
RekeyLimit (Debian bug #430225).
* Allow the '-ossh_command=CMD' command to contain parameters.
Escape charater is backslash.
* Limit write requests to 64kB.
* Support "statvfs@openssh.com" extension, which will be available
in OpenSSH 5.1.
2008-04-21 Miklos Szeredi <miklos@szeredi.hu>
* Fix incorrect disk usage reported by 'du' for files of size 4GB
or above. Reported by Christian Boltz.
2008-04-16 Miklos Szeredi <miklos@szeredi.hu>
* If debugging is enabled, print some statistics at exit about the
number of bytes transferred, etc..
2008-03-31 Miklos Szeredi <miklos@szeredi.hu>
* Support "posix-rename@openssh.com" extension available in
OpenSSH 4.9. This allows rename to be atomic even when target
file or directory exists. If available, the extension will be
used instead of the rename operation in the original protocol and
the "-oworkaround=rename" option will be ignored.
2008-03-28 Miklos Szeredi <miklos@szeredi.hu>
* Add support for password authentication with pam_mount.
Original patch and help with testing: John S. Skogtvedt
2008-03-03 Miklos Szeredi <miklos@szeredi.hu>
* Fix ssh debug only appearing if "-d" is used. Reported by
Michael Gorbach
2008-01-03 Miklos Szeredi <miklos@szeredi.hu>
* Fix condition for building of sshnodelay.so
2007-12-17 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.9
2007-12-12 Miklos Szeredi <miklos@szeredi.hu>
* Fix checking for fuse_opt_parse in configure
2007-12-11 Miklos Szeredi <miklos@szeredi.hu>
* Fill in st_ctime attribute with st_mtime, instead of leaving it
zero
* Check for OpenSSH version >= 4.4, and if found, don't build the
sshnodelay.so workaround
2007-12-10 Miklos Szeredi <miklos@szeredi.hu>
* Fix crash on writing files, caused by missing locking around
sshfs_file_get()
* Don't time requests when not debugging
* Add subtype support with libfuse >= 2.7.0
* Abort on allocation failure instead of exit
* Correctly show default of nodelaysrv workaround in help message
2007-05-16 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.8
2007-05-15 Miklos Szeredi <miklos@szeredi.hu>
* Add needed g_thread_init() to fix rare crashes. Reported by
Dimitrios Apostolou
* Fix memory leak in sshfs_open_common()
2007-04-18 Miklos Szeredi <miklos@szeredi.hu>
* Fix crash within gdb, caused by sem_wait() returning with an
error on interrupt. Reported by Dimitrios Apostolou
* Fix spurious cache entries remaining after renaming a directory
2007-02-28 Miklos Szeredi <miklos@szeredi.hu>
* Don't set DISPLAY environment variable to "", because it breaks
ssh-askpass. Make nodelaysrv_workaround default to off, because
with this change it may have security implications.
2007-02-19 Miklos Szeredi <miklos@szeredi.hu>
* OpenSSH sftp-server can read requests faster, than it processes
them, when it's buffer is full it aborts. This can happen on a
large upload to a slow server. Work around this by limiting the
total size of outstanding reqests. Debian bug #365541. Tracked
down by Thue Janus Kristensen
* Add --disable-sshnodelay configure option. The sshnodelay.so
hack shouldnt be needed with OpenSSH client versions >= 4.3
2006-12-20 Miklos Szeredi <miklos@szeredi.hu>
* Work around write performace issues due to missing TCP_NODELAY
in sshd. Reported by Justin Searle
2006-11-10 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug which ommitted directory entries for symlinks with the
-ofollow_symlinks option. Bug reported by Mikael Ståldal
2006-09-29 Miklos Szeredi <miklos@szeredi.hu>
* Fix segfault if there are outstanding writes to the server after
release on the file descriptor. This only happened on FreeBSD.
Reported by Andriy Gapon
2006-08-18 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.7
2006-08-17 Miklos Szeredi <miklos@szeredi.hu>
* Cosmetics on bogus statfs numbers
2006-08-16 Miklos Szeredi <miklos@szeredi.hu>
* Add option 'follow_symlinks' to resolve symlinks on the server.
* On setups where the login shell prints a banner, the sftp
protocol was confused, and bailed out with "reply len too large:
...". So iterate over any rubbish read immediately after login
until a valid reply is found.
* Check remote directory for existence before mounting. Closes
Ubuntu bug #46633
2006-03-10 Miklos Szeredi <miklos@szeredi.hu>
* Use socketpair() instead of pipe() for communication between ssh
and sshfs. Patch from Csaba Henk
* Update to FUSE interface version 26
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.6
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Fix segfault if remote host is down and reconnection is enabled
2006-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug in symlink transformation. Reported by Ralf Hoffmann
2006-02-24 Miklos Szeredi <miklos@szeredi.hu>
* Add workaround for broken truncate on old sftp servers. Can be
enabled with '-oworkaround=truncate'. Patch from Joseph M Link
2006-02-23 Miklos Szeredi <miklos@szeredi.hu>
* Avoid double memcpy on writes. Patch by Joseph M Link
* More memory copy avoidance
2006-02-22 Miklos Szeredi <miklos@szeredi.hu>
* Add -fPIC to the comile flags of sshnodelay.so. Reported by
Anthony Kolasny
2006-02-20 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.5
2006-02-19 Miklos Szeredi <miklos@szeredi.hu>
* Fix compilation with old FUSE versions. Report by Kurt George
Gjerde
2006-02-16 Miklos Szeredi <miklos@szeredi.hu>
* Block TERM/INT/HUP/QUIT signals in sshfs reading thread, so they
will always be received by the FUSE main thread. Fixes the
"double ^C" problem seen on FreeBSD.
* Use 'auto_cache' option if available, so that file cache is not
thrown away on each open. This should make repeated reading of a
file much much faster.
2006-01-31 Miklos Szeredi <miklos@szeredi.hu>
* Fix problems with nodelay workaround on FreeBSD.
2006-01-30 Miklos Szeredi <miklos@szeredi.hu>
* Fix data consitency bug if readahead is enabled and writes are
intermixed with reads. Solution is far from optimal, since it
will prevent readahead in the above situation. If used with FUSE
>= 2.6.0 with Linux-2.6.X, readahead will be done by the kernel,
and hence there will be no performance penalty. Bug reported and
test program written by Wolfgang Köbler. Further testing on
FreeBSD by Csaba Henk
2006-01-29 Miklos Szeredi <miklos@szeredi.hu>
* Add '-olarge_read' option for Linux-2.4.*. This should
generally improve download performance
2006-01-27 Miklos Szeredi <miklos@szeredi.hu>
* Add workaround (enabled by default) for ssh clients not setting
TCP_NODELAY on the network connection. Currently this is all
known versions of openssh. This may improve download speed in
some circumstances
* Make it possible to idividually disable workarounds with a "no"
prefix
* Change '-otransform_symlinks' not to prefix with the mountpoint
(which is fragile wrt. moving/binding the mount). Rather convert
absolute symlinks to relative if possible. Does not yet work if
base path is itself relative
2006-01-25 Miklos Szeredi <miklos@szeredi.hu>
* Use TCP_NODELAY socket option for direct connection. This may
improve download speed in some circumstances
2006-01-20 Miklos Szeredi <miklos@szeredi.hu>
* Update to fuse API 2.6
* Don't do readahead in sshfs if it's done in kernel
2006-01-14 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.4
2006-01-09 Miklos Szeredi <miklos@szeredi.hu>
* Added 'transform_symlinks' option to "fix-up" absolute symlinks.
Patch by Paul Jarc
* Add option parsing implementation, so linking with older than
2.5.0 libfuse still works.
2005-12-09 Miklos Szeredi <miklos@szeredi.hu>
* Use new option parsing interface of FUSE
2005-11-28 Miklos Szeredi <miklos@szeredi.hu>
* Set statvfs::f_frsize
2005-11-23 Miklos Szeredi <miklos@szeredi.hu>
* Fix warnings on 64bit systems. Reported by D. R. Evans
2005-11-16 Miklos Szeredi <miklos@szeredi.hu>
* Replace EPROTO with the more portable EIO
* Fix bug in option parsing. Reported by Csaba Henk
2005-10-29 Miklos Szeredi <miklos@szeredi.hu>
* Use FUSE version 25 if available
* Add <sys/socket.h> include. Reported by Csaba Henk
2005-10-29 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.3
2005-10-28 Miklos Szeredi <miklos@szeredi.hu>
* Add atomic create+open and ftruncate operation. This should fix
issues with 'cp' and other programs failing with "Permission
denied". To be effective, needs FUSE version 2.5 and kernel
version 2.6.15 (just a guess, since neither of them is released
yet).
2005-10-27 Miklos Szeredi <miklos@szeredi.hu>
* Add support for SSH protocol version 1. Bug reported by Miklos
Bagi Jr.
2005-10-26 Miklos Szeredi <miklos@szeredi.hu>
* Fix typo (ConnectTimeout -> ConnectionTimeout) in ssh options.
Bug reported by Miklos Bagi Jr.
2005-10-19 Miklos Szeredi <miklos@szeredi.hu>
* GNOME Nautilus fails to copy file to sshfs filesystem, because
FUSE returns zero free space. So instead return huge (999999999
kbytes) amount of free space, yet it should be obvious that the
number is artificial. Bug report by Peter Kronheimer
2005-10-18 Miklos Szeredi <miklos@szeredi.hu>
* Add remote uid detection and translation ('idmap=user' option).
Idea and implementation details worked out by Jean-Marc Valin
2005-10-17 Miklos Szeredi <miklos@szeredi.hu>
* Add one more missing lock.
* Add workaround for failure to rename to an existing file. Based
on patch by Michael Best
2005-10-15 Miklos Szeredi <miklos@szeredi.hu>
* Protect request ID allocation with mutex. Bug report by Tvrtko
Ursulin
2005-08-17 Miklos Szeredi <miklos@szeredi.hu>
* Try to calculate approximate disk usage of files from their
size, so that 'du' returns meaningful results. Problem reported
by Bernd Amend.
2005-08-15 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.2
2005-08-13 Miklos Szeredi <miklos@szeredi.hu>
* Add 'reconnect' option, which tries to reconnect to the server
when the connection is broken. If a password is required for
connection, it is recommended that you install ssh-askpass, and
set the SSH_ASKPASS environment variable (see 'man ssh' for more
details).
2005-05-05 Miklos Szeredi <miklos@szeredi.hu>
* Work around missing truncate() support in some older sftp
servers (only works for zero size truncate). Thanks to Eduard
Czimbalmos for the bug report and help with testing
2005-04-13 Miklos Szeredi <miklos@szeredi.hu>
* Fix compilation with gcc-2.95. Reported by David A. Gershman
2005-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Make it work on server version 2 (e.g. Sun_SSH_1.0.1). Report
and testing by Pieter J. Kersten
2005-03-04 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.1
2005-03-03 Miklos Szeredi <miklos@szeredi.hu>
* Slightly optimize readahead. Still not clever enough to always
keep the pipe filled.
* Add 'sshfs_debug' option
2005-02-17 Miklos Szeredi <miklos@szeredi.hu>
* Parse 'max_read' mount option and if smaller than 65536 forward
to FUSE
2005-02-16 Miklos Szeredi <miklos@szeredi.hu>
* Added simple readahead (big performance gain in case of
sequential read pattern). Can be disabled with '-o no_readahead'
2005-02-14 Miklos Szeredi <miklos@szeredi.hu>
* Added asynchronous writeback (big performance gain) and made
this the default. Can be disabled with '-o sshfs_sync'
2005-02-09 Miklos Szeredi <miklos@szeredi.hu>
* Added option to start arbitary command instead of 'ssh'
* Re-added '-p PORT' as a convenience option, also '-C' works as
in ssh.
2005-02-08 Miklos Szeredi <miklos@szeredi.hu>
* Add caching of symlinks
* Add support for many ssh options to be passed to ssh
* Port number can now actually be specified with "-o port=PORT",
bug spotted by Andrew Ukrainec
2005-02-07 Miklos Szeredi <miklos@szeredi.hu>
* Separate attribute caching to a separate layer
* Add caching of directory contents
2005-02-03 Miklos Szeredi <miklos@szeredi.hu>
Fix PKG_CONFIG_PATH setting in configure.ac (reported by Alpar
Juttner)
2005-01-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.0
+28 -1
View File
@@ -1,4 +1,31 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = sshfs
sshfs_SOURCES = sshfs.c
sshfs_SOURCES = sshfs.c cache.c cache.h
if FUSE_OPT_COMPAT
sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h
endif
sshfs_LDADD = $(SSHFS_LIBS)
sshfs_CFLAGS = $(SSHFS_CFLAGS)
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\"
EXTRA_DIST = sshnodelay.c FAQ.txt
CLEANFILES = sshnodelay.so
dist_man_MANS = sshfs.1
if SSH_NODELAY_SO
all-local: sshnodelay.so
install-exec-local: sshnodelay.so
test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
$(INSTALL) -m 755 sshnodelay.so "$(DESTDIR)$(libdir)/sshnodelay.so"
uninstall-local:
rm -f "$(DESTDIR)$(libdir)/sshnodelay.so"
sshnodelay.so:
$(CC) -Wall -W -s --shared -fPIC $(sshnodelay_libs) sshnodelay.c -o sshnodelay.so
endif
+96
View File
@@ -1,3 +1,99 @@
What is new in 2.0
------------------
* 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
------------------
+21 -10
View File
@@ -11,7 +11,7 @@ The idea of sshfs was taken from the SSHFS filesystem distributed with
LUFS, which I found very useful. There were some limitations of that
codebase, so I rewrote it. Features of this implementation are:
- Based on FUSE (the best userspace filesystem framework for linux ;)
- Based on FUSE (the best userspace filesystem framework for Linux ;)
- Multithreading: more than one request can be on it's way to the
server
@@ -20,13 +20,22 @@ codebase, so I rewrote it. Features of this implementation are:
- Caching directory contents
- Reconnect on failure
Latest version
==============
The latest version and more information can be found on
http://fuse.sourceforge.net/sshfs.html
How to mount a filesystem
=========================
Once sshfs is installed (see next section) running it is very simple:
sshfs hostname: /mountpoint
sshfs hostname: mountpoint
Note, that it's recommended to run it as user, not as root. For this
to work the mountpoint must be owned by the user. If the username is
@@ -36,6 +45,14 @@ for it (actually it just runs ssh which ask for the password if
needed). You can also specify a directory after the ":". The default
is the home directory.
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 moutpoint
Installing
==========
@@ -53,11 +70,5 @@ installing FUSE, compile sshfs the usual way:
And you are ready to go.
Bugs and feature requests
=========================
Send bug reports to <miklos@szeredi.hu>.
Good luck!
Miklos Szeredi
If checking out from CVS for the first time also do 'autoreconf -i'
before doing './configure'.
+563
View File
@@ -0,0 +1,563 @@
/*
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 <stdlib.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <pthread.h>
#define DEFAULT_CACHE_TIMEOUT 20
#define MAX_CACHE_SIZE 10000
#define MIN_CACHE_CLEAN_INTERVAL 5
#define CACHE_CLEAN_INTERVAL 60
struct cache {
int on;
unsigned stat_timeout;
unsigned dir_timeout;
unsigned link_timeout;
struct fuse_cache_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
};
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 fuse_cache_dirhandle {
const char *path;
fuse_dirh_t h;
fuse_dirfil_t filler;
GPtrArray *dir;
};
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 + MIN_CACHE_CLEAN_INTERVAL &&
(g_hash_table_size(cache.table) > MAX_CACHE_SIZE ||
now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) {
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_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)
{
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
node->stat = *stbuf;
node->stat_valid = time(NULL) + cache.stat_timeout;
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;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
node->dir_valid = time(NULL) + cache.dir_timeout;
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;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
node->link_valid = time(NULL) + cache.link_timeout;
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;
}
static int cache_getattr(const char *path, struct stat *stbuf)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
}
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->oper.readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
return err;
}
static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
const struct stat *stbuf)
{
int err = ch->filler(ch->h, name, 0, 0);
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);
g_free(fullpath);
}
}
return err;
}
static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
struct fuse_cache_dirhandle ch;
int err;
char **dir;
struct node *node;
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++)
filler(h, *dir, 0, 0);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
ch.path = path;
ch.h = h;
ch.filler = filler;
ch.dir = g_ptr_array_new();
err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
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_unity_dirfill(fuse_cache_dirh_t ch, const char *name,
const struct stat *stbuf)
{
(void) stbuf;
return ch->filler(ch->h, name, 0, 0);
}
static int cache_unity_getdir(const char *path, fuse_dirh_t h,
fuse_dirfil_t filler)
{
struct fuse_cache_dirhandle ch;
ch.h = h;
ch.filler = filler;
return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
int err = cache.next_oper->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->oper.mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_unlink(const char *path)
{
int err = cache.next_oper->oper.unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_rmdir(const char *path)
{
int err = cache.next_oper->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->oper.symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
}
static int cache_rename(const char *from, const char *to)
{
int err = cache.next_oper->oper.rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
}
static int cache_link(const char *from, const char *to)
{
int err = cache.next_oper->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)
{
int err = cache.next_oper->oper.chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_chown(const char *path, uid_t uid, gid_t gid)
{
int err = cache.next_oper->oper.chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_truncate(const char *path, off_t size)
{
int err = cache.next_oper->oper.truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_utime(const char *path, struct utimbuf *buf)
{
int err = cache.next_oper->oper.utime(path, buf);
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->oper.write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate(path);
return res;
}
#if FUSE_VERSION >= 25
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf);
}
return err;
}
#endif
static void cache_unity_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_oper)
{
#if FUSE_VERSION >= 23
cache_oper->init = oper->oper.init;
#endif
cache_oper->getattr = oper->oper.getattr;
cache_oper->readlink = oper->oper.readlink;
cache_oper->getdir = cache_unity_getdir;
cache_oper->mknod = oper->oper.mknod;
cache_oper->mkdir = oper->oper.mkdir;
cache_oper->symlink = oper->oper.symlink;
cache_oper->unlink = oper->oper.unlink;
cache_oper->rmdir = oper->oper.rmdir;
cache_oper->rename = oper->oper.rename;
cache_oper->link = oper->oper.link;
cache_oper->chmod = oper->oper.chmod;
cache_oper->chown = oper->oper.chown;
cache_oper->truncate = oper->oper.truncate;
cache_oper->utime = oper->oper.utime;
cache_oper->open = oper->oper.open;
cache_oper->read = oper->oper.read;
cache_oper->write = oper->oper.write;
cache_oper->flush = oper->oper.flush;
cache_oper->release = oper->oper.release;
cache_oper->fsync = oper->oper.fsync;
cache_oper->statfs = oper->oper.statfs;
cache_oper->setxattr = oper->oper.setxattr;
cache_oper->getxattr = oper->oper.getxattr;
cache_oper->listxattr = oper->oper.listxattr;
cache_oper->removexattr = oper->oper.removexattr;
#if FUSE_VERSION >= 25
cache_oper->create = oper->oper.create;
cache_oper->ftruncate = oper->oper.ftruncate;
cache_oper->fgetattr = oper->oper.fgetattr;
#endif
}
static void cache_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_oper)
{
cache_oper->getattr = oper->oper.getattr ? cache_getattr : NULL;
cache_oper->readlink = oper->oper.readlink ? cache_readlink : NULL;
cache_oper->getdir = oper->cache_getdir ? cache_getdir : NULL;
cache_oper->mknod = oper->oper.mknod ? cache_mknod : NULL;
cache_oper->mkdir = oper->oper.mkdir ? cache_mkdir : NULL;
cache_oper->symlink = oper->oper.symlink ? cache_symlink : NULL;
cache_oper->unlink = oper->oper.unlink ? cache_unlink : NULL;
cache_oper->rmdir = oper->oper.rmdir ? cache_rmdir : NULL;
cache_oper->rename = oper->oper.rename ? cache_rename : NULL;
cache_oper->link = oper->oper.link ? cache_link : NULL;
cache_oper->chmod = oper->oper.chmod ? cache_chmod : NULL;
cache_oper->chown = oper->oper.chown ? cache_chown : NULL;
cache_oper->truncate = oper->oper.truncate ? cache_truncate : NULL;
cache_oper->utime = oper->oper.utime ? cache_utime : NULL;
cache_oper->write = oper->oper.write ? cache_write : NULL;
#if FUSE_VERSION >= 25
cache_oper->create = oper->oper.create ? cache_create : NULL;
cache_oper->ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
cache_oper->fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
#endif
}
struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
{
static struct fuse_operations cache_oper;
cache.next_oper = oper;
cache_unity_fill(oper, &cache_oper);
if (cache.on) {
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[] = {
{ "cache=yes", offsetof(struct cache, on), 1 },
{ "cache=no", offsetof(struct cache, on), 0 },
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 },
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 },
FUSE_OPT_END
};
int cache_parse_options(struct fuse_args *args)
{
cache.stat_timeout = DEFAULT_CACHE_TIMEOUT;
cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
cache.on = 1;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
+28
View File
@@ -0,0 +1,28 @@
/*
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>
#ifndef FUSE_VERSION
#define FUSE_VERSION (FUSE_MAJOR_VERSION * 10 + FUSE_MINOR_VERSION)
#endif
typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t;
typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
const struct stat *stbuf);
struct fuse_cache_operations {
struct fuse_operations oper;
int (*cache_getdir) (const char *, fuse_cache_dirh_t, fuse_cache_dirfil_t);
};
struct fuse_operations *cache_init(struct fuse_cache_operations *oper);
int cache_parse_options(struct fuse_args *args);
void cache_add_attr(const char *path, const struct stat *stbuf);
void cache_invalidate(const char *path);
+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_ */
+45 -5
View File
@@ -1,12 +1,52 @@
AC_INIT(sshfs-fuse, 1.0)
AC_INIT(sshfs-fuse, 2.0)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
AC_PROG_CC
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0])
CFLAGS="$CFLAGS -Wall -W -D_REENTRANT $SSHFS_CFLAGS"
LIBS="$SSHFS_LIBS"
AM_PROG_CC_C_O
CFLAGS="$CFLAGS -Wall -W"
LIBS=
AC_SEARCH_LIBS(dlsym, [dl])
sshnodelay_libs=$LIBS
AC_SUBST(sshnodelay_libs)
LIBS=
AC_ARG_ENABLE(sshnodelay,
[ --disable-sshnodelay Don't compile NODELAY workaround for ssh])
if test -z "$enable_sshnodelay"; then
AC_MSG_CHECKING([OpenSSH version])
[eval `ssh -V 2>&1 | sed -n 's/^OpenSSH_\([1-9][0-9]*\)\.\([0-9][0-9]*\).*/ssh_major=\1 ssh_minor=\2/p'`]
if test "x$ssh_major" != x -a "x$ssh_minor" != x; then
if test $ssh_major -gt 4 -o \( $ssh_major = 4 -a $ssh_minor -ge 4 \); then
AC_MSG_RESULT([$ssh_major.$ssh_minor >= 4.4, disabling NODELAY workaround])
enable_sshnodelay=no
else
AC_MSG_RESULT([$ssh_major.$ssh_minor < 4.4, enabling NODELAY workaround])
enable_sshnodelay=yes
fi
else
AC_MSG_RESULT([not found])
fi
fi
if test "$enable_sshnodelay" = "yes"; then
AC_DEFINE(SSH_NODELAY_WORKAROUND, 1, [Compile ssh NODELAY workaround])
fi
AM_CONDITIONAL(SSH_NODELAY_SO, test "$enable_sshnodelay" = "yes")
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0 gthread-2.0])
have_fuse_opt_parse=no
oldlibs="$LIBS"
LIBS="$LIBS $SSHFS_LIBS"
AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes])
LIBS="$oldlibs"
if test "$have_fuse_opt_parse" = no; then
CFLAGS="$CFLAGS -Icompat"
fi
AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no)
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
+11
View File
@@ -0,0 +1,11 @@
#! /bin/bash
(
echo "See http://fuse.sourceforge.net/wiki/index.php/SshfsFaq for the latest"
echo "version of this FAQ"
echo "---"
echo
lynx -nolist -dump http://fuse.sourceforge.net/wiki/index.php/SshfsFaq \
| sed -e '1,12d' -e '/____/,$d'
) > FAQ.txt
+214
View File
@@ -0,0 +1,214 @@
.TH SSHFS "1" "April 2008" "SSHFS version 2.0" "User Commands"
.SH NAME
SSHFS \- filesystem client based on ssh
.SH DESCRIPTION
usage: sshfs [user@]host:[dir] mountpoint [options]
.SS "general options:"
.TP
\fB\-o\fR opt,[opt...]
mount options
.TP
\fB\-h\fR \fB\-\-help\fR
print help
.TP
\fB\-V\fR \fB\-\-version\fR
print version
.SS "SSHFS options:"
.TP
\fB\-p\fR PORT
equivalent to '\-o port=PORT'
.TP
\fB\-C\fR
equivalent to '\-o compression=yes'
.TP
\fB\-1\fR
equivalent to '\-o ssh_protocol=1'
.TP
\fB\-o\fR reconnect
reconnect to server
.TP
\fB\-o\fR sshfs_sync
synchronous writes
.TP
\fB\-o\fR no_readahead
synchronous reads (no speculative readahead)
.TP
\fB\-o\fR sshfs_debug
print some debugging information
.TP
\fB\-o\fR cache=YESNO
enable caching {yes,no} (default: yes)
.TP
\fB\-o\fR cache_timeout=N
sets timeout for caches in seconds (default: 20)
.TP
\fB\-o\fR cache_X_timeout=N
sets timeout for {stat,dir,link} cache
.TP
\fB\-o\fR workaround=LIST
colon separated list of workarounds
.TP
none
no workarounds enabled
.TP
all
all workarounds enabled
.TP
[no]rename
fix renaming to existing file (default: off)
.TP
[no]nodelaysrv
set nodelay tcp flag in ssh (default: off)
.TP
[no]truncate
fix truncate for old servers (default: off)
.TP
[no]buflimit
fix buffer fillup bug in server (default: on)
.TP
\fB\-o\fR idmap=TYPE
user/group ID mapping, possible types are:
.TP
none
no translation of the ID space (default)
.TP
user
only translate UID of connecting user
.TP
\fB\-o\fR ssh_command=CMD
execute CMD instead of 'ssh'
.TP
\fB\-o\fR ssh_protocol=N
ssh protocol to use (default: 2)
.TP
\fB\-o\fR sftp_server=SERV
path to sftp server or subsystem (default: sftp)
.TP
\fB\-o\fR directport=PORT
directly connect to PORT bypassing ssh
.TP
\fB\-o\fR transform_symlinks
transform absolute symlinks to relative
.TP
\fB\-o\fR follow_symlinks
follow symlinks on the server
.TP
\fB\-o\fR no_check_root
don't check for existence of 'dir' on server
.TP
\fB\-o\fR password_stdin
read password from stdin (only for pam_mount!)
.TP
\fB\-o\fR SSHOPT=VAL
ssh options (see man ssh_config)
.SS "FUSE options:"
.TP
\fB\-d\fR \fB\-o\fR debug
enable debug output (implies \fB\-f\fR)
.TP
\fB\-f\fR
foreground operation
.TP
\fB\-s\fR
disable multi\-threaded operation
.TP
\fB\-o\fR allow_other
allow access to other users
.TP
\fB\-o\fR allow_root
allow access to root
.TP
\fB\-o\fR nonempty
allow mounts over non\-empty file/dir
.HP
\fB\-o\fR default_permissions
enable permission checking by kernel
.TP
\fB\-o\fR fsname=NAME
set filesystem name
.TP
\fB\-o\fR subtype=NAME
set filesystem type
.TP
\fB\-o\fR large_read
issue large read requests (2.4 only)
.TP
\fB\-o\fR max_read=N
set maximum size of read requests
.TP
\fB\-o\fR hard_remove
immediate removal (don't hide files)
.TP
\fB\-o\fR use_ino
let filesystem set inode numbers
.TP
\fB\-o\fR readdir_ino
try to fill in d_ino in readdir
.TP
\fB\-o\fR direct_io
use direct I/O
.TP
\fB\-o\fR kernel_cache
cache files in kernel
.TP
\fB\-o\fR [no]auto_cache
enable caching based on modification times
.TP
\fB\-o\fR umask=M
set file permissions (octal)
.TP
\fB\-o\fR uid=N
set file owner
.TP
\fB\-o\fR gid=N
set file group
.TP
\fB\-o\fR entry_timeout=T
cache timeout for names (1.0s)
.TP
\fB\-o\fR negative_timeout=T
cache timeout for deleted names (0.0s)
.TP
\fB\-o\fR attr_timeout=T
cache timeout for attributes (1.0s)
.TP
\fB\-o\fR ac_attr_timeout=T
auto cache timeout for attributes (attr_timeout)
.TP
\fB\-o\fR intr
allow requests to be interrupted
.TP
\fB\-o\fR intr_signal=NUM
signal to send on interrupt (10)
.TP
\fB\-o\fR modules=M1[:M2...]
names of modules to push onto filesystem stack
.TP
\fB\-o\fR max_write=N
set maximum size of write requests
.TP
\fB\-o\fR max_readahead=N
set maximum readahead
.TP
\fB\-o\fR async_read
perform reads asynchronously (default)
.TP
\fB\-o\fR sync_read
perform reads synchronously
.SS "Module options:"
.TP
[subdir]
.TP
\fB\-o\fR subdir=DIR
prepend this directory to all paths (mandatory)
.TP
\fB\-o\fR [no]rellinksa
transform absolute symlinks to relative
.TP
[iconv]
.TP
\fB\-o\fR from_code=CHARSET
original encoding of file names (default: UTF-8)
.TP
\fB\-o\fR to_code=CHARSET
new encoding of the file names (default: ISO-8859-2)
+2875 -924
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
int (*next_connect)(int, const struct sockaddr *, socklen_t) =
dlsym(RTLD_NEXT, "connect");
int res = next_connect(sock, addr, addrlen);
if (!res && addr->sa_family == AF_INET) {
int opt = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}
return res;
}