diff options
author | Nikolaus Rath <Nikolaus@rath.org> | 2016-02-10 19:53:49 -0800 |
---|---|---|
committer | Nikolaus Rath <Nikolaus@rath.org> | 2016-02-10 19:53:49 -0800 |
commit | e812e29d39f0e7aaf9ead9a19a9a4f288300a7e2 (patch) | |
tree | ff8fd1c17b9be6d1aba7ff365614b10e41a1223b | |
parent | b10d21db3185a2b25e3bd35579f57d3c7b8d882e (diff) | |
parent | 80db43d7dce4f3979fe5e92b2d616d635f21029d (diff) | |
download | sshfs-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-- | .gitignore | 1 | ||||
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | ChangeLog | 7 | ||||
-rw-r--r-- | Makefile.am | 17 | ||||
-rw-r--r-- | compat/darwin_compat.c | 246 | ||||
-rw-r--r-- | compat/darwin_compat.h | 49 | ||||
-rw-r--r-- | configure.ac | 23 | ||||
-rw-r--r-- | sshfs.1.in (renamed from sshfs.1) | 12 | ||||
-rw-r--r-- | sshfs.c | 114 | ||||
-rw-r--r-- | sshnodelay.c | 49 |
10 files changed, 501 insertions, 21 deletions
@@ -20,6 +20,7 @@ Makefile *.m4 stamp-h* config.* +sshfs.1 /sshfs /ltmain.sh /configure @@ -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> @@ -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 @@ -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). - - @@ -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__ */ |