Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1dbda31786 | |||
| 33667f2a56 | |||
| f627055bc7 | |||
| efeed71295 | |||
| 96c6138978 | |||
| 1afaef8f46 | |||
| e5acfce8ed | |||
| e178150a72 | |||
| c63acf3dd7 | |||
| e3cd445a4e | |||
| 1167c11901 | |||
| a175c2876a | |||
| b2fa759358 | |||
| 1756abe6fd | |||
| f51d7b0c6a | |||
| df10d96ac2 | |||
| a2dda962c4 | |||
| 504e26f938 | |||
| 74bfa3850a | |||
| 0f6f33b1b4 | |||
| a9a1cc0046 | |||
| b5983a0ce8 | |||
| adc55c9d2b | |||
| 451f2075f2 | |||
| 391f676705 | |||
| c1e799b4da | |||
| ebfeebd468 | |||
| d1ddbbcae5 | |||
| e812e29d39 | |||
| 80db43d7dc | |||
| 27e7029148 | |||
| 30e90ae080 | |||
| 9b4ca1aade | |||
| a03d3eab39 | |||
| 665bb97ef6 | |||
| b7e8fee81b | |||
| 869aa42e97 | |||
| d8230e72ca | |||
| e0025219b3 | |||
| 19ab22abec | |||
| 3bf3be3bcd | |||
| ddbe3bee44 | |||
| b10d21db31 | |||
| f7c7713a82 | |||
| 9bcb989454 | |||
| f2b17c299b | |||
| c3d83ee24b | |||
| 1fc97d3f2c | |||
| b42f84218c | |||
| 990f30d767 | |||
| d04fd55128 | |||
| 1458193728 | |||
| 66458931dd | |||
| f4631f0a17 | |||
| 3c44e22ddd | |||
| b389c66b32 | |||
| f64407d865 | |||
| eb60e2d1a2 | |||
| 0d34c7b742 | |||
| ff32332e83 | |||
| c1284b4089 | |||
| 0120e6b461 | |||
| 1ac41d2ae2 | |||
| ea6fa1d7c9 | |||
| 6a954f429c | |||
| 0e87004ab2 | |||
| e6f7fb4e50 | |||
| a6b6b5c820 | |||
| a306a80b6e | |||
| bb3ea51117 | |||
| 20fafed0a4 | |||
| 69b2b3cc0e | |||
| fa9bfc6d08 | |||
| 90619fe249 | |||
| 04a610bad1 | |||
| d8da0c4ed6 | |||
| 163683d9ef | |||
| f2086ccfbc | |||
| b4023a19dd |
@@ -20,6 +20,7 @@ Makefile
|
||||
*.m4
|
||||
stamp-h*
|
||||
config.*
|
||||
sshfs.1
|
||||
/sshfs
|
||||
/ltmain.sh
|
||||
/configure
|
||||
|
||||
@@ -15,8 +15,19 @@ Contributors (autogenerated list)
|
||||
|
||||
Alan Jenkins <alan.christopher.jenkins@gmail.com>
|
||||
Alexander Neumann <alexander@bumpern.de>
|
||||
Benjamin Fleischer <fleiben@gmail.com>
|
||||
Berserker <berserker.troll@yandex.com>
|
||||
Bill Zissimopoulos <billziss@navimatics.com>
|
||||
Chris Wolfe <cwolfe@chromium.org>
|
||||
gala <gala132@users.noreply.github.com>
|
||||
George Vlahavas <vlahavas@gmail.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>
|
||||
Rian Hunter <rian@alum.mit.edu>
|
||||
Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
|
||||
|
||||
@@ -1,10 +1,31 @@
|
||||
Release 2.7 (2015-01-28)
|
||||
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.6 (2014-01-14)
|
||||
Release 2.5 (2014-01-14)
|
||||
------------------------
|
||||
|
||||
* Some performance improvements for large directories.
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
SSHFS FAQ
|
||||
=========
|
||||
|
||||
1. I've found a bug and there's no solution in this FAQ, what
|
||||
should I do?
|
||||
2. Advantage of sshfs over NFS and Samba
|
||||
3. Create the device node
|
||||
4. mv fails with "Operation not permitted"
|
||||
5. cvs fails with "cvs [status aborted]: cannot get working
|
||||
directory: No such file or directory" in a sshfs mounted directory
|
||||
6. Changes on the server are not immediately visible in the
|
||||
mounted directory.
|
||||
7. Configuring the ssh connection
|
||||
8. What are the no_readahead and sshfs_sync options for?
|
||||
9. Why does df return strange values on partitions mounted via
|
||||
sshfs?
|
||||
10. How do I specify the remote mount point (since the example
|
||||
defaults to the home directory)
|
||||
11. sshfs hangs after a while
|
||||
12. Following symlinks on the server side
|
||||
13. Making absolute symlinks work
|
||||
14. Mounting as root
|
||||
15. Exporting via NFS
|
||||
16. Automatical mounting using /etc/fstab
|
||||
17. Why does SVN (etc...) fail with permission denied?
|
||||
18. Why does SVN (etc...) fail to rename files?
|
||||
19. Is there some neat way to do it in reverse?
|
||||
20. Might it be reasonable to disallow loops?
|
||||
21. How to mount through an intermediary ssh server, eg:
|
||||
localhost -> A -> B; mount B from localhost
|
||||
22. Alternative Solution
|
||||
23. I seem to have successfully mounted a remote directory, but
|
||||
performing an `ls -l` on the directory above the mount point shows
|
||||
the mount point's attributes as `? ? ? ? ? ?`. Nothing shows up in
|
||||
the directory either. What am I doing wrong?
|
||||
|
||||
--------------------------------------------------------------------------
|
||||
|
||||
1. I've found a bug and there's no solution in this FAQ, what should I do?
|
||||
|
||||
Please report the bug in the Github issue tracker:
|
||||
https://github.com/libfuse/sshfs/issues
|
||||
|
||||
Also logs with debugging output can be useful for diagnosing the
|
||||
problem. Try running sshfs with the following options:
|
||||
sshfs -odebug,sshfs_debug,loglevel=debug ...
|
||||
|
||||
Doing strace on the application which fails may also sometimes help:
|
||||
strace -f -o /tmp/strace application args ...
|
||||
|
||||
Note that large messages (over 40k) will be rejected from the mailing
|
||||
list. So try to keep the logs as short as possible.
|
||||
|
||||
|
||||
2. Advantage of sshfs over NFS and Samba
|
||||
|
||||
Users can mount remote resources they already have ssh access to,
|
||||
without requiring the remote machine to export the resource.
|
||||
|
||||
The remote resource can be mounted when it is needed in a location
|
||||
that is convenient for the user at that time, without needing to rely
|
||||
on a central, root-controlled file system table.
|
||||
|
||||
Automatic mounting, if desired, can be added to a shell script such as
|
||||
.bashrc (provided authentication is done using RSA/DSA keys).
|
||||
|
||||
Resources can be mounted over slow and unreliable (distant)
|
||||
connections.
|
||||
|
||||
3. Create the device node
|
||||
|
||||
If you don't use udev, you may get this error message:
|
||||
|
||||
fusermount: failed to open /dev/fuse: No such device or address
|
||||
|
||||
Before loading the fuse kernel module, create the device node
|
||||
manually:
|
||||
|
||||
mknod -m 666 /dev/fuse c 10 229
|
||||
|
||||
4. mv fails with "Operation not permitted".
|
||||
|
||||
Use -o workaround=rename (requires sshfs version >= 1.3).
|
||||
|
||||
5. cvs fails with "cvs status aborted?: cannot get working directory: No such
|
||||
file or directory" in a sshfs mounted directory
|
||||
|
||||
Use the -oreaddir_ino option. Example:
|
||||
sshfs -oreaddir_ino hostname:remote_dir mount_point
|
||||
|
||||
6. Changes on the server are not immediately visible in the mounted directory.
|
||||
|
||||
By default, sshfs caches things for 20 seconds, use -o cache_timeout=N
|
||||
to change the default cache timeout (in seconds) or -o cache=no for
|
||||
disabling the cache.
|
||||
|
||||
You can also control cache timeouts for directory listing etc with
|
||||
-o cache_stat_timeout=N,
|
||||
-o cache_dir_timout=N, and
|
||||
-o cache_link_timout=N.
|
||||
|
||||
7. Configuring the ssh connection
|
||||
|
||||
In addition to flags like -C, -p, and -o SSHOPT...=, you may find it
|
||||
easier to edit your /.ssh/config file. You can add an entry with any
|
||||
customization you want, test it with ssh, and finally use it with
|
||||
sshfs. As a bonus, you get a short mnemonic for your configuration.
|
||||
|
||||
8. What are the no_readahead and sshfs_sync options for?
|
||||
|
||||
These disable read and write optimizations respectively. They don't
|
||||
really make sense unless you're doing something special.
|
||||
|
||||
9. Why does df return strange values on partitions mounted via sshfs?
|
||||
|
||||
Because the SFTP protocol doesn't have a statfs operation this is
|
||||
currently not possible to display proper usage on remote partition.
|
||||
|
||||
10. How do I specfy the remote mount point (since the example defaults to the
|
||||
home directory)
|
||||
|
||||
The example shows:
|
||||
sshfs hostname: mountpoint
|
||||
|
||||
To specify a remote mount point use:
|
||||
sshfs hostname:remotemountpoint mountpoint
|
||||
|
||||
This might be obvious to others, but I ended up looking up the
|
||||
interface to sftp to see if I could learn how to specify the remote
|
||||
mount point, then thought about the way that scp specifies the remote
|
||||
directory, and it worked.
|
||||
|
||||
11. sshfs hangs after a while
|
||||
|
||||
Mounting works fine, I can use the files in Mountpoint as good as any
|
||||
other files on my system, but after bit of time, changing nothing on
|
||||
the remote files sshfs crashes. This means, I can not cd into the
|
||||
Mountpoint (xterm hangs, nautilus hangs... every program trying to
|
||||
access the Mountpoint gets stuck, and won't return).
|
||||
|
||||
Solution: add
|
||||
ServerAliveInterval 15
|
||||
|
||||
in your .ssh/config (or use -o ServerAliveInterval=15 on the sshfs
|
||||
command line but I did not test that solution). This will force the
|
||||
ssh connection to stay alive even if you have no activity.
|
||||
|
||||
12. Following symlinks on the server side
|
||||
|
||||
The -o follow_symlinks option will enable this.
|
||||
|
||||
13. Making absolute symlinks work
|
||||
|
||||
Use the -o transform_symlinks option, which will transform absolute
|
||||
symlinks (ones which point somewhere inside the mount) into relative
|
||||
ones.
|
||||
|
||||
14. Mounting as root
|
||||
|
||||
Generally it's not possible to use an sshfs mount as a "real"
|
||||
filesystem shared between multiple users. Some of this functionality
|
||||
can be enabled with the -o allow_other and -o default_permissions
|
||||
options, but files will not be created with the correct ownership,
|
||||
etc...
|
||||
|
||||
15. Exporting via NFS
|
||||
|
||||
Use the userspace NFS daemon http://sourceforge.net/projects/unfs
|
||||
|
||||
16. Automatical mounting using /etc/fstab
|
||||
|
||||
A line in /etc/fstab has the following format:
|
||||
sshfs#USERNAME@REMOTE_HOST:REMOTE_PATH MOUNT_POINT fuse SSHFS_OPTIONS 0 0
|
||||
|
||||
eg.
|
||||
sshfs#guest@guest.login.com:data /mnt/guest fuse \
|
||||
uid=1003,gid=100,umask=0,allow_other 0 0
|
||||
|
||||
17. Why does SVN (etc...) fail with permission denied?
|
||||
|
||||
This is a bug that happens when an application creates a read-only
|
||||
file opened for writing (e.g. open("foo", O_WRONLY|O_CREAT, 0444))
|
||||
|
||||
It has been fixed in sshfs version 1.3, but also requires FUSE version
|
||||
>=2.5.X and Linux kernel version >=2.6.15.
|
||||
|
||||
18. Why does SVN (etc...) fail to rename files?
|
||||
|
||||
$ svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kdelibs
|
||||
svn: Can't move 'kdelibs/.svn/tmp/entries' to 'kdelibs/.svn/entries':
|
||||
Operation not permitted
|
||||
|
||||
The reason is that SFTP protocol version 3 (which is implemented by
|
||||
OpenSSH's sftp-server) defines the rename operation slightly
|
||||
differently than POSIX. The difference is that renaming to an existing
|
||||
file or directory will fail instead of atomically replacing the old
|
||||
file.
|
||||
|
||||
The -o workaround=rename option will try to emulate POSIX rename
|
||||
semantics, but it cannot guarantee atomicity. In most of the cases
|
||||
this doesn't matter, and things will work fine with this option.
|
||||
|
||||
19. Is there some neat way to do it in reverse?
|
||||
|
||||
You want to mount a USB thumb drive onto a file server that is rather
|
||||
remote.
|
||||
|
||||
Assuming this is difficult because the laptop with the thumb drive is
|
||||
sitting behind NAT, firewalls, etc. then you need to create a
|
||||
port-forward:
|
||||
client$ ssh -R 2222:localhost:22 server
|
||||
server$ sshfs -p 2222 localhost:/media/usb1 myusb1
|
||||
|
||||
(Now, is there is there a smarter way that does not involve port
|
||||
opening login permissions in an undesireable direction?)
|
||||
|
||||
20. Might it be reasonable to disallow loops?
|
||||
|
||||
sshfs localhost:/mnt /mnt
|
||||
|
||||
This seems to produce undesirable results. --JoshuaRodman
|
||||
|
||||
21. How to mount through an intermediary ssh server, eg: localhost -> A -> B;
|
||||
mount B from localhost
|
||||
|
||||
Start by mounting the folder you need that is on "a" to a folder on
|
||||
"b" then mount the new folder that is on "a" to a folder on localhost.
|
||||
|
||||
IE: (These are NOT real commands, but a sequence of steps.
|
||||
A mounts B:/home/x on /mnt/Bx
|
||||
localhost mounts A:/mnt/Bx on ~/mydir
|
||||
|
||||
22. Alternative Solution:
|
||||
|
||||
1) Create a shell script to wrap the tunneling of one ssh command over
|
||||
another,
|
||||
$ cat >Atunnel <<EOF
|
||||
#!/bin/bash
|
||||
ssh -q A ssh -q "$@"
|
||||
EOF
|
||||
$ chmod u+x Atunnel
|
||||
|
||||
N.B. make sure to put this somewhere on your path. 2) sshfs mount as
|
||||
normal but using this script as the ssh command.
|
||||
$ sshfs -o ssh_command='Atunnel' B: ~/mydir
|
||||
|
||||
23. I seem to have successfully mounted a remote directory, but performing an
|
||||
`ls -l` on the directory above the mount point shows the mount point's
|
||||
attributes as `? ? ? ? ? ?`. Nothing shows up in the directory either. What
|
||||
am I doing wrong?
|
||||
|
||||
You probably specified a remote path with the tilde (~) in it. This
|
||||
doesn't seem to work. Instead, specify an absolute remote path:
|
||||
sshfs username@remote.host:/home/username/whatever my/mount
|
||||
|
||||
What options do i use to make playing media files (music) over sshfs more
|
||||
efficient?
|
||||
|
||||
MacFUSE doesn't seem to let me move files from one directory to another. It
|
||||
first asks for my local user password (i.e. the password on my Macbook Pro)
|
||||
and then produces the error message "The operation cannot be completed
|
||||
because one or more required items cannot be found. (Error code -120).
|
||||
|
||||
+14
-3
@@ -6,16 +6,27 @@ sshfs_SOURCES = sshfs.c cache.c cache.h
|
||||
if FUSE_OPT_COMPAT
|
||||
sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h
|
||||
endif
|
||||
if DARWIN_COMPAT
|
||||
sshfs_SOURCES += compat/darwin_compat.c compat/darwin_compat.h
|
||||
endif
|
||||
|
||||
sshfs_LDADD = $(SSHFS_LIBS)
|
||||
sshfs_CFLAGS = $(SSHFS_CFLAGS)
|
||||
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\"
|
||||
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" \
|
||||
-DIDMAP_DEFAULT="\"$(IDMAP_DEFAULT)\""
|
||||
|
||||
EXTRA_DIST = sshnodelay.c
|
||||
CLEANFILES = sshnodelay.so
|
||||
EXTRA_DIST = sshnodelay.c sshfs.1.in
|
||||
CLEANFILES = sshnodelay.so sshfs.1 sshfs.1.tmp
|
||||
|
||||
dist_man_MANS = sshfs.1
|
||||
|
||||
sshfs.1: sshfs.1.in
|
||||
$(AM_V_GEN)sed \
|
||||
-e 's,__IDMAP_DEFAULT__,$(IDMAP_DEFAULT),g' \
|
||||
-e 's,__UNMOUNT_COMMAND__,$(UNMOUNT_COMMAND),g' \
|
||||
<$(srcdir)/sshfs.1.in >sshfs.1.tmp || exit 1; \
|
||||
mv sshfs.1.tmp sshfs.1
|
||||
|
||||
if SSH_NODELAY_SO
|
||||
all-local: sshnodelay.so
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ sftp(1) and ssh_config(5)), including the remote port number
|
||||
|
||||
To unmount the filesystem:
|
||||
|
||||
fusermount -u moutpoint
|
||||
fusermount -u mountpoint
|
||||
|
||||
|
||||
Installing
|
||||
|
||||
@@ -14,16 +14,19 @@
|
||||
#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
|
||||
#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 stat_timeout;
|
||||
unsigned dir_timeout;
|
||||
unsigned link_timeout;
|
||||
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_cache_operations *next_oper;
|
||||
GHashTable *table;
|
||||
pthread_mutex_t lock;
|
||||
@@ -70,9 +73,9 @@ static int cache_clean_entry(void *key_, struct node *node, time_t *now)
|
||||
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)) {
|
||||
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;
|
||||
@@ -172,7 +175,7 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
|
||||
if (wrctr == cache.write_ctr) {
|
||||
node = cache_get(path);
|
||||
node->stat = *stbuf;
|
||||
node->stat_valid = time(NULL) + cache.stat_timeout;
|
||||
node->stat_valid = time(NULL) + cache.stat_timeout_secs;
|
||||
if (node->stat_valid > node->valid)
|
||||
node->valid = node->stat_valid;
|
||||
cache_clean();
|
||||
@@ -188,7 +191,7 @@ static void cache_add_dir(const char *path, char **dir)
|
||||
node = cache_get(path);
|
||||
g_strfreev(node->dir);
|
||||
node->dir = dir;
|
||||
node->dir_valid = time(NULL) + cache.dir_timeout;
|
||||
node->dir_valid = time(NULL) + cache.dir_timeout_secs;
|
||||
if (node->dir_valid > node->valid)
|
||||
node->valid = node->dir_valid;
|
||||
cache_clean();
|
||||
@@ -210,7 +213,7 @@ static void cache_add_link(const char *path, const char *link, size_t size)
|
||||
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;
|
||||
node->link_valid = time(NULL) + cache.link_timeout_secs;
|
||||
if (node->link_valid > node->valid)
|
||||
node->valid = node->link_valid;
|
||||
cache_clean();
|
||||
@@ -520,6 +523,10 @@ static void cache_unity_fill(struct fuse_cache_operations *oper,
|
||||
cache_oper->ftruncate = oper->oper.ftruncate;
|
||||
cache_oper->fgetattr = oper->oper.fgetattr;
|
||||
#endif
|
||||
#if FUSE_VERSION >= 29
|
||||
cache_oper->flag_nullpath_ok = oper->oper.flag_nullpath_ok;
|
||||
cache_oper->flag_nopath = oper->oper.flag_nopath;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void cache_fill(struct fuse_cache_operations *oper,
|
||||
@@ -545,6 +552,10 @@ static void cache_fill(struct fuse_cache_operations *oper,
|
||||
cache_oper->ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
|
||||
cache_oper->fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
|
||||
#endif
|
||||
#if FUSE_VERSION >= 29
|
||||
cache_oper->flag_nullpath_ok = 0;
|
||||
cache_oper->flag_nopath = 0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -570,20 +581,28 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *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 },
|
||||
{ "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 = DEFAULT_CACHE_TIMEOUT;
|
||||
cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
|
||||
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
|
||||
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;
|
||||
cache.on = 1;
|
||||
|
||||
return fuse_opt_parse(args, &cache, cache_opts, NULL);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
+23
-4
@@ -1,4 +1,5 @@
|
||||
AC_INIT(sshfs, 2.6)
|
||||
AC_INIT(sshfs, 2.9)
|
||||
AC_CANONICAL_TARGET
|
||||
AM_INIT_AUTOMAKE([foreign subdir-objects])
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -11,6 +12,12 @@ sshnodelay_libs=$LIBS
|
||||
AC_SUBST(sshnodelay_libs)
|
||||
LIBS=
|
||||
|
||||
case "$target_os" in
|
||||
*linux*) osname=linux;;
|
||||
*darwin*) osname=darwin;;
|
||||
*) osname=unknown;;
|
||||
esac
|
||||
|
||||
AC_ARG_ENABLE(sshnodelay,
|
||||
[ --disable-sshnodelay Don't compile NODELAY workaround for ssh])
|
||||
|
||||
@@ -37,16 +44,28 @@ fi
|
||||
AM_CONDITIONAL(SSH_NODELAY_SO, test "$enable_sshnodelay" = "yes")
|
||||
|
||||
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.3 glib-2.0 gthread-2.0])
|
||||
PKG_CHECK_MODULES([SSHFS], [fuse >= 2.3 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"
|
||||
if test "$have_fuse_opt_parse" = no -o "$osname" = darwin; then
|
||||
CFLAGS="$CFLAGS -I${srcdir}/compat"
|
||||
fi
|
||||
AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no)
|
||||
AM_CONDITIONAL(DARWIN_COMPAT, test "$osname" = darwin)
|
||||
|
||||
AC_CHECK_PROG(UNMOUNT_COMMAND, fusermount, fusermount -u, umount)
|
||||
|
||||
# TODO: Figure out why we special-case this in Darwin. Would be nice if
|
||||
# the default setting was consistent across platforms so we wouldn't need
|
||||
# to care about it here.
|
||||
case "$osname" in
|
||||
darwin) IDMAP_DEFAULT=user ;;
|
||||
*) IDMAP_DEFAULT=none ;;
|
||||
esac
|
||||
AC_SUBST(IDMAP_DEFAULT)
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -7,7 +7,7 @@ SSHFS \- filesystem client based on ssh
|
||||
\fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP [\fIoptions\fP]
|
||||
.SS unmounting
|
||||
.TP
|
||||
\fBfusermount -u mountpoint\fP
|
||||
\fB__UNMOUNT_COMMAND__ mountpoint\fP
|
||||
.SH DESCRIPTION
|
||||
SSHFS (Secure SHell FileSystem) is a file system for Linux (and other
|
||||
operating systems with a FUSE implementation, such as Mac OS X or FreeBSD)
|
||||
@@ -97,14 +97,14 @@ fix buffer fillup bug in server (default: on)
|
||||
.RE
|
||||
.TP
|
||||
\fB\-o\fR idmap=TYPE
|
||||
user/group ID mapping, possible types are:
|
||||
user/group ID mapping (default: __IDMAP_DEFAULT__)
|
||||
.RS 8
|
||||
.TP
|
||||
none
|
||||
no translation of the ID space (default)
|
||||
no translation of the ID space
|
||||
.TP
|
||||
user
|
||||
only translate UID of connecting user
|
||||
only translate UID/GID of connecting user
|
||||
.TP
|
||||
file
|
||||
translate UIDs/GIDs based upon the contents of \fBuidfile \fR and
|
||||
@@ -282,5 +282,3 @@ SSHFS has been written by Miklos Szeredi <miklos@szeredi.hu>.
|
||||
.LP
|
||||
This man page was written by Bartosz Fenski <fenio@debian.org> for the
|
||||
Debian GNU/Linux distribution (but it may be used by others).
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_opt.h>
|
||||
#if !defined(__CYGWIN__)
|
||||
#include <fuse_lowlevel.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
# include <fuse_darwin.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -20,7 +25,9 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <semaphore.h>
|
||||
#ifndef __APPLE__
|
||||
# include <semaphore.h>
|
||||
#endif
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <signal.h>
|
||||
@@ -38,6 +45,11 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <limits.h>
|
||||
#ifdef __APPLE__
|
||||
# include <strings.h>
|
||||
# include <libgen.h>
|
||||
# include <darwin_compat.h>
|
||||
#endif
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
@@ -108,6 +120,7 @@
|
||||
#define SFTP_EXT_POSIX_RENAME "posix-rename@openssh.com"
|
||||
#define SFTP_EXT_STATVFS "statvfs@openssh.com"
|
||||
#define SFTP_EXT_HARDLINK "hardlink@openssh.com"
|
||||
#define SFTP_EXT_FSYNC "fsync@openssh.com"
|
||||
|
||||
#define PROTO_VERSION 3
|
||||
|
||||
@@ -127,6 +140,10 @@
|
||||
|
||||
#define MAX_PASSWORD 1024
|
||||
|
||||
#ifdef __APPLE__
|
||||
static char sshfs_program_path[PATH_MAX] = { 0 };
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
struct buffer {
|
||||
uint8_t *p;
|
||||
size_t len;
|
||||
@@ -243,6 +260,10 @@ struct sshfs {
|
||||
int server_version;
|
||||
unsigned remote_uid;
|
||||
unsigned local_uid;
|
||||
#ifdef __APPLE__
|
||||
unsigned remote_gid;
|
||||
unsigned local_gid;
|
||||
#endif
|
||||
int remote_uid_detected;
|
||||
unsigned blksize;
|
||||
char *progname;
|
||||
@@ -255,6 +276,7 @@ struct sshfs {
|
||||
int ext_posix_rename;
|
||||
int ext_statvfs;
|
||||
int ext_hardlink;
|
||||
int ext_fsync;
|
||||
mode_t mnt_mode;
|
||||
struct fuse_operations *op;
|
||||
|
||||
@@ -739,8 +761,17 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (sshfs.remote_uid_detected) {
|
||||
if (uid == sshfs.remote_uid)
|
||||
uid = sshfs.local_uid;
|
||||
if (gid == sshfs.remote_gid)
|
||||
gid = sshfs.local_gid;
|
||||
}
|
||||
#else /* !__APPLE__ */
|
||||
if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
|
||||
uid = sshfs.local_uid;
|
||||
#endif /* __APPLE__ */
|
||||
if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map)
|
||||
if (translate_id(&uid, sshfs.uid_map) == -1)
|
||||
return -EPERM;
|
||||
@@ -849,11 +880,35 @@ static void ssh_add_arg(const char *arg)
|
||||
#ifdef SSH_NODELAY_WORKAROUND
|
||||
static int do_ssh_nodelay_workaround(void)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
char *oldpreload = getenv("DYLD_INSERT_LIBRARIES");
|
||||
#else
|
||||
char *oldpreload = getenv("LD_PRELOAD");
|
||||
#endif
|
||||
char *newpreload;
|
||||
char sopath[PATH_MAX];
|
||||
int res;
|
||||
|
||||
#ifdef __APPLE__
|
||||
char *sshfs_program_path_base = NULL;
|
||||
if (!sshfs_program_path[0]) {
|
||||
goto nobundle;
|
||||
}
|
||||
sshfs_program_path_base = dirname(sshfs_program_path);
|
||||
if (!sshfs_program_path_base) {
|
||||
goto nobundle;
|
||||
}
|
||||
snprintf(sopath, sizeof(sopath), "%s/%s", sshfs_program_path_base,
|
||||
SSHNODELAY_SO);
|
||||
res = access(sopath, R_OK);
|
||||
if (res == -1) {
|
||||
goto nobundle;
|
||||
}
|
||||
goto pathok;
|
||||
|
||||
nobundle:
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
|
||||
res = access(sopath, R_OK);
|
||||
if (res == -1) {
|
||||
@@ -879,15 +934,24 @@ static int do_ssh_nodelay_workaround(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
pathok:
|
||||
#endif
|
||||
|
||||
newpreload = g_strdup_printf("%s%s%s",
|
||||
oldpreload ? oldpreload : "",
|
||||
oldpreload ? " " : "",
|
||||
sopath);
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (!newpreload || setenv("DYLD_INSERT_LIBRARIES", newpreload, 1) == -1)
|
||||
fprintf(stderr, "warning: failed set DYLD_INSERT_LIBRARIES for ssh nodelay workaround\n");
|
||||
#else /* !__APPLE__ */
|
||||
if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
|
||||
fprintf(stderr, "warning: failed set LD_PRELOAD "
|
||||
"for ssh nodelay workaround\n");
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
g_free(newpreload);
|
||||
return 0;
|
||||
}
|
||||
@@ -1488,6 +1552,9 @@ static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
|
||||
if (strcmp(ext, SFTP_EXT_HARDLINK) == 0 &&
|
||||
strcmp(extdata, "1") == 0)
|
||||
sshfs.ext_hardlink = 1;
|
||||
if (strcmp(ext, SFTP_EXT_FSYNC) == 0 &&
|
||||
strcmp(extdata, "1") == 0)
|
||||
sshfs.ext_fsync = 1;
|
||||
} while (buf2.len < buf2.size);
|
||||
buf_free(&buf2);
|
||||
}
|
||||
@@ -1607,6 +1674,10 @@ static void sftp_detect_uid()
|
||||
|
||||
sshfs.remote_uid = stbuf.st_uid;
|
||||
sshfs.local_uid = getuid();
|
||||
#ifdef __APPLE__
|
||||
sshfs.remote_gid = stbuf.st_gid;
|
||||
sshfs.local_gid = getgid();
|
||||
#endif
|
||||
sshfs.remote_uid_detected = 1;
|
||||
DEBUG("remote_uid = %i\n", sshfs.remote_uid);
|
||||
|
||||
@@ -2364,8 +2435,17 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
|
||||
int err;
|
||||
struct buffer buf;
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (sshfs.remote_uid_detected) {
|
||||
if (uid == sshfs.local_uid)
|
||||
uid = sshfs.remote_uid;
|
||||
if (gid == sshfs.local_gid)
|
||||
gid = sshfs.remote_gid;
|
||||
}
|
||||
#else /* !__APPLE__ */
|
||||
if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
|
||||
uid = sshfs.remote_uid;
|
||||
#endif /* __APPLE__ */
|
||||
if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map)
|
||||
if(translate_id(&uid, sshfs.r_uid_map) == -1)
|
||||
return -EPERM;
|
||||
@@ -2559,8 +2639,25 @@ static int sshfs_flush(const char *path, struct fuse_file_info *fi)
|
||||
static int sshfs_fsync(const char *path, int isdatasync,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
int err;
|
||||
(void) isdatasync;
|
||||
return sshfs_flush(path, fi);
|
||||
|
||||
if (err = sshfs_flush(path, fi))
|
||||
return err;
|
||||
|
||||
if (!sshfs.ext_fsync)
|
||||
return err;
|
||||
|
||||
{
|
||||
struct buffer buf;
|
||||
struct sshfs_file *sf = get_sshfs_file(fi);
|
||||
buf_init(&buf, 0);
|
||||
buf_add_string(&buf, SFTP_EXT_FSYNC);
|
||||
buf_add_buf(&buf, &sf->handle);
|
||||
err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
|
||||
buf_free(&buf);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
static void sshfs_file_put(struct sshfs_file *sf)
|
||||
@@ -3277,6 +3374,10 @@ static struct fuse_cache_operations sshfs_oper = {
|
||||
.create = sshfs_create,
|
||||
.ftruncate = sshfs_ftruncate,
|
||||
.fgetattr = sshfs_fgetattr,
|
||||
#endif
|
||||
#if FUSE_VERSION >= 29
|
||||
.flag_nullpath_ok = 1,
|
||||
.flag_nopath = 1,
|
||||
#endif
|
||||
},
|
||||
.cache_getdir = sshfs_getdir,
|
||||
@@ -3304,8 +3405,15 @@ static void usage(const char *progname)
|
||||
" -o sync_readdir synchronous readdir\n"
|
||||
" -o sshfs_debug print some debugging information\n"
|
||||
" -o cache=BOOL enable caching {yes,no} (default: yes)\n"
|
||||
" -o cache_max_size=N sets the maximum size of the cache (default: 10000)\n"
|
||||
" -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
|
||||
" -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n"
|
||||
" -o cache_clean_interval=N\n"
|
||||
" sets the interval for automatic cleaning of the\n"
|
||||
" cache (default: 60)\n"
|
||||
" -o cache_min_clean_interval=N\n"
|
||||
" sets the interval for forced cleaning of the\n"
|
||||
" cache if full (default: 5)\n"
|
||||
" -o workaround=LIST colon separated list of workarounds\n"
|
||||
" none no workarounds enabled\n"
|
||||
" all all workarounds enabled\n"
|
||||
@@ -3316,9 +3424,9 @@ static void usage(const char *progname)
|
||||
" [no]nodelaysrv set nodelay tcp flag in sshd (default: off)\n"
|
||||
" [no]truncate fix truncate for old servers (default: off)\n"
|
||||
" [no]buflimit fix buffer fillup bug in server (default: on)\n"
|
||||
" -o idmap=TYPE user/group ID mapping, possible types are:\n"
|
||||
" none no translation of the ID space (default)\n"
|
||||
" user only translate UID of connecting user\n"
|
||||
" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
|
||||
" none no translation of the ID space\n"
|
||||
" user only translate UID/GID of connecting user\n"
|
||||
" file translate UIDs/GIDs contained in uidfile/gidfile\n"
|
||||
" -o uidfile=FILE file containing username:remote_uid mappings\n"
|
||||
" -o gidfile=FILE file containing groupname:remote_gid mappings\n"
|
||||
@@ -3494,6 +3602,13 @@ static int read_password(void)
|
||||
perror("Failed to allocate locked page for password");
|
||||
return -1;
|
||||
}
|
||||
if (mlock(sshfs.password, size) != 0) {
|
||||
memset(sshfs.password, 0, size);
|
||||
munmap(sshfs.password, size);
|
||||
sshfs.password = NULL;
|
||||
perror("Failed to allocate locked page for password");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Don't use fgets() because password might stay in memory */
|
||||
for (n = 0; n < max_password; n++) {
|
||||
@@ -3819,7 +3934,11 @@ static inline void load_gid_map(void)
|
||||
read_id_map(sshfs.gid_file, &groupname_to_gid, "gid", &sshfs.gid_map, &sshfs.r_gid_map);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
int main(int argc, char *argv[], __unused char *envp[], char **exec_path)
|
||||
#else
|
||||
int main(int argc, char *argv[])
|
||||
#endif
|
||||
{
|
||||
int res;
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
@@ -3828,6 +3947,11 @@ int main(int argc, char *argv[])
|
||||
const char *sftp_server;
|
||||
int libver;
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (!realpath(*exec_path, sshfs_program_path)) {
|
||||
memset(sshfs_program_path, 0, PATH_MAX);
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
g_thread_init(NULL);
|
||||
|
||||
sshfs.blksize = 4096;
|
||||
@@ -3836,7 +3960,11 @@ int main(int argc, char *argv[])
|
||||
sshfs.max_write = 32768;
|
||||
sshfs.nodelay_workaround = 1;
|
||||
sshfs.nodelaysrv_workaround = 0;
|
||||
#ifdef __APPLE__
|
||||
sshfs.rename_workaround = 1;
|
||||
#else
|
||||
sshfs.rename_workaround = 0;
|
||||
#endif
|
||||
sshfs.truncate_workaround = 0;
|
||||
sshfs.buflimit_workaround = 1;
|
||||
sshfs.ssh_ver = 2;
|
||||
@@ -3848,7 +3976,15 @@ int main(int argc, char *argv[])
|
||||
sshfs.delay_connect = 0;
|
||||
sshfs.slave = 0;
|
||||
sshfs.detect_uid = 0;
|
||||
sshfs.idmap = IDMAP_NONE;
|
||||
if (strcmp(IDMAP_DEFAULT, "none") == 0) {
|
||||
sshfs.idmap = IDMAP_NONE;
|
||||
} else if (strcmp(IDMAP_DEFAULT, "user") == 0) {
|
||||
sshfs.idmap = IDMAP_USER;
|
||||
} else {
|
||||
fprintf(stderr, "bad idmap default value built into sshfs; "
|
||||
"assuming none (bad logic in configure script?)\n");
|
||||
sshfs.idmap = IDMAP_NONE;
|
||||
}
|
||||
sshfs.nomap = NOMAP_ERROR;
|
||||
ssh_add_arg("ssh");
|
||||
ssh_add_arg("-x");
|
||||
@@ -3859,6 +3995,14 @@ int main(int argc, char *argv[])
|
||||
parse_workarounds() == -1)
|
||||
exit(1);
|
||||
|
||||
#if FUSE_VERSION >= 29
|
||||
// These workarounds require the "path" argument.
|
||||
if (sshfs.truncate_workaround || sshfs.fstat_workaround) {
|
||||
sshfs_oper.oper.flag_nullpath_ok = 0;
|
||||
sshfs_oper.oper.flag_nopath = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sshfs.idmap == IDMAP_USER)
|
||||
sshfs.detect_uid = 1;
|
||||
else if (sshfs.idmap == IDMAP_FILE) {
|
||||
@@ -3971,7 +4115,9 @@ int main(int argc, char *argv[])
|
||||
char *mountpoint;
|
||||
int multithreaded;
|
||||
int foreground;
|
||||
#if !defined(__CYGWIN__)
|
||||
struct stat st;
|
||||
#endif
|
||||
|
||||
res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded,
|
||||
&foreground);
|
||||
@@ -3983,20 +4129,26 @@ int main(int argc, char *argv[])
|
||||
foreground = 1;
|
||||
}
|
||||
|
||||
#if !defined(__CYGWIN__)
|
||||
res = stat(mountpoint, &st);
|
||||
if (res == -1) {
|
||||
perror(mountpoint);
|
||||
exit(1);
|
||||
}
|
||||
sshfs.mnt_mode = st.st_mode;
|
||||
#elif defined(__CYGWIN__)
|
||||
sshfs.mnt_mode = S_IFDIR | 0755;
|
||||
#endif
|
||||
|
||||
ch = fuse_mount(mountpoint, &args);
|
||||
if (!ch)
|
||||
exit(1);
|
||||
|
||||
#if !defined(__CYGWIN__)
|
||||
res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC);
|
||||
if (res == -1)
|
||||
perror("WARNING: failed to set FD_CLOEXEC on fuse device");
|
||||
#endif
|
||||
|
||||
sshfs.op = cache_init(&sshfs_oper);
|
||||
fuse = fuse_new(ch, &args, sshfs.op,
|
||||
|
||||
+45
-4
@@ -5,14 +5,55 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
|
||||
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
|
||||
/* Wrapper around connect(2) to explicitly set TCP_NODELAY. */
|
||||
static int nodelay_connect(
|
||||
int (*real_connect)(int, const struct sockaddr *, socklen_t),
|
||||
int sock, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
int (*next_connect)(int, const struct sockaddr *, socklen_t) =
|
||||
dlsym(RTLD_NEXT, "connect");
|
||||
int res = next_connect(sock, addr, addrlen);
|
||||
int res = real_connect(sock, addr, addrlen);
|
||||
if (!res && addr->sa_family == AF_INET) {
|
||||
int opt = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
#if __APPLE__
|
||||
|
||||
/* OS X does not have LD_PRELOAD but has DYLD_INSERT_LIBRARIES. The right
|
||||
* environment variable is set by sshfs.c when attempting to load the
|
||||
* sshnodelay workaround.
|
||||
*
|
||||
* However, things are not that simple: DYLD_INSERT_LIBRARIES does not
|
||||
* behave exactly like LD_PRELOAD. Instead, the dyld dynamic linker will
|
||||
* look for __DATA __interpose sections on the libraries given via the
|
||||
* DYLD_INSERT_LIBRARIES variable. The contents of this section are pairs
|
||||
* of replacement functions and functions to be replaced, respectively.
|
||||
* Prepare such section here. */
|
||||
|
||||
int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen);
|
||||
|
||||
typedef struct interpose_s {
|
||||
void *new_func;
|
||||
void *orig_func;
|
||||
} interpose_t;
|
||||
|
||||
static const interpose_t interposers[] \
|
||||
__attribute__ ((section("__DATA, __interpose"))) = {
|
||||
{ (void *)custom_connect, (void *)connect },
|
||||
};
|
||||
|
||||
int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
return nodelay_connect(connect, sock, addr, addrlen);
|
||||
}
|
||||
|
||||
#else /* !__APPLE__ */
|
||||
|
||||
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
|
||||
{
|
||||
return nodelay_connect(dlsym(RTLD_NEXT, "connect"),
|
||||
sock, addr, addrlen);
|
||||
}
|
||||
|
||||
#endif /* !__APPLE__ */
|
||||
|
||||
Reference in New Issue
Block a user