aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolaus Rath <Nikolaus@rath.org>2016-02-10 19:53:49 -0800
committerNikolaus Rath <Nikolaus@rath.org>2016-02-10 19:53:49 -0800
commite812e29d39f0e7aaf9ead9a19a9a4f288300a7e2 (patch)
treeff8fd1c17b9be6d1aba7ff365614b10e41a1223b
parentb10d21db3185a2b25e3bd35579f57d3c7b8d882e (diff)
parent80db43d7dce4f3979fe5e92b2d616d635f21029d (diff)
downloadsshfs-e812e29d39f0e7aaf9ead9a19a9a4f288300a7e2.tar
sshfs-e812e29d39f0e7aaf9ead9a19a9a4f288300a7e2.tar.gz
sshfs-e812e29d39f0e7aaf9ead9a19a9a4f288300a7e2.tar.bz2
sshfs-e812e29d39f0e7aaf9ead9a19a9a4f288300a7e2.zip
Merge pull request #5 from jmmv/merge-osxfuse
Merge osxfuse.
-rw-r--r--.gitignore1
-rw-r--r--AUTHORS4
-rw-r--r--ChangeLog7
-rw-r--r--Makefile.am17
-rw-r--r--compat/darwin_compat.c246
-rw-r--r--compat/darwin_compat.h49
-rw-r--r--configure.ac23
-rw-r--r--sshfs.1.in (renamed from sshfs.1)12
-rw-r--r--sshfs.c114
-rw-r--r--sshnodelay.c49
10 files changed, 501 insertions, 21 deletions
diff --git a/.gitignore b/.gitignore
index daba941..f39c637 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,7 @@ Makefile
*.m4
stamp-h*
config.*
+sshfs.1
/sshfs
/ltmain.sh
/configure
diff --git a/AUTHORS b/AUTHORS
index 21a9b75..9f05a8f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -15,8 +15,12 @@ Contributors (autogenerated list)
Alan Jenkins <alan.christopher.jenkins@gmail.com>
Alexander Neumann <alexander@bumpern.de>
+Benjamin Fleischer <fleiben@gmail.com>
Chris Wolfe <cwolfe@chromium.org>
+Google Inc.
+Julio Merino <jmmv@google.com>
Mike Kelly <mike@pair.com>
Miklos Szeredi <miklos@szeredi.hu>
Nikolaus Rath <Nikolaus@rath.org>
Percy Jahn <email@percyjahn.de>
+Qais Patankar <qaisjp@gmail.com>
diff --git a/ChangeLog b/ChangeLog
index 6009dcf..02fee35 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,14 @@
+Draft notes for upcoming release
+--------------------------------
+
+* Integrated osxfuse's copy of sshfs, which means that sshfs now works
+ on OS X out of the box.
+
Release 2.7 (2015-01-28)
------------------------
* New maintainer (Nikolaus Rath <Nikolaus@rath.org>)
-
Release 2.6 (2014-01-14)
------------------------
diff --git a/Makefile.am b/Makefile.am
index e1e5510..f003bae 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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' \
+ <sshfs.1.in >sshfs.1.tmp || exit 1; \
+ mv sshfs.1.tmp sshfs.1
+
if SSH_NODELAY_SO
all-local: sshnodelay.so
diff --git a/compat/darwin_compat.c b/compat/darwin_compat.c
new file mode 100644
index 0000000..9b23be2
--- /dev/null
+++ b/compat/darwin_compat.c
@@ -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;
+}
diff --git a/compat/darwin_compat.h b/compat/darwin_compat.h
new file mode 100644
index 0000000..0a16471
--- /dev/null
+++ b/compat/darwin_compat.h
@@ -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_ */
diff --git a/configure.ac b/configure.ac
index 4d7e23c..a91ec3f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,5 @@
AC_INIT(sshfs, 2.6)
+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])
@@ -43,10 +50,22 @@ 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
diff --git a/sshfs.1 b/sshfs.1.in
index 0bad826..fcf3e9f 100644
--- a/sshfs.1
+++ b/sshfs.1.in
@@ -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
@@ -141,6 +141,8 @@ path to sftp server or subsystem (default: sftp)
.TP
\fB\-o\fR directport=PORT
directly connect to PORT bypassing ssh
+\fB\-o\fR slave
+communicate over stdin and stdout bypassing network
.TP
\fB\-o\fR slave
communicate over stdin and stdout bypassing network
@@ -282,5 +284,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).
-
-
diff --git a/sshfs.c b/sshfs.c
index 3904a50..84b2359 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -12,6 +12,9 @@
#include <fuse.h>
#include <fuse_opt.h>
#include <fuse_lowlevel.h>
+#ifdef __APPLE__
+# include <fuse_darwin.h>
+#endif
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
@@ -20,7 +23,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 +43,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"
@@ -127,6 +137,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 +257,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;
@@ -739,8 +757,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 +876,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 +930,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;
}
@@ -1607,6 +1667,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 +2428,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;
@@ -3316,9 +3389,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 +3567,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 +3899,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 +3912,14 @@ 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);
+ }
+
+ /* Until this gets fixed somewhere else. */
+ g_slice_set_config(G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);
+#endif /* __APPLE__ */
g_thread_init(NULL);
sshfs.blksize = 4096;
@@ -3836,7 +3928,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 +3944,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");
diff --git a/sshnodelay.c b/sshnodelay.c
index 7518089..a9f307c 100644
--- a/sshnodelay.c
+++ b/sshnodelay.c
@@ -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__ */