From b4023a19dd7ec7a099d2e0df491547cf3bb6bec3 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Fri, 20 Jan 2012 09:22:54 +0100 Subject: Apply modified sshfs 2.2 patch from MacFUSE Based on Amit Singh's work at http://code.google.com/p/macfuse/ --- cache.c | 7 +++ cache.h | 4 ++ sshfs.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- sshnodelay.c | 28 +++++++++++ 4 files changed, 188 insertions(+), 1 deletion(-) diff --git a/cache.c b/cache.c index bb23f8f..7e146e7 100644 --- a/cache.c +++ b/cache.c @@ -559,6 +559,9 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper) cache.next_oper = oper; cache_unity_fill(oper, &cache_oper); +#if __APPLE__ + cache_enabled = cache.on; +#endif if (cache.on) { cache_fill(oper, &cache_oper); pthread_mutex_init(&cache.lock, NULL); @@ -593,3 +596,7 @@ int cache_parse_options(struct fuse_args *args) return fuse_opt_parse(args, &cache, cache_opts, NULL); } + +#if __APPLE__ +int cache_enabled; +#endif diff --git a/cache.h b/cache.h index cec9ca4..23ff970 100644 --- a/cache.h +++ b/cache.h @@ -27,3 +27,7 @@ int cache_parse_options(struct fuse_args *args); void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr); void cache_invalidate(const char *path); uint64_t cache_get_write_ctr(void); + +#if __APPLE__ +extern int cache_enabled; +#endif diff --git a/sshfs.c b/sshfs.c index 22bda6b..d124dcf 100644 --- a/sshfs.c +++ b/sshfs.c @@ -12,6 +12,9 @@ #include #include #include +#if __APPLE__ +# include +#endif #include #include #include @@ -20,7 +23,9 @@ #include #include #include -#include +#if !__APPLE__ +# include +#endif #include #include #include @@ -35,9 +40,17 @@ #include #include #include +#if __APPLE__ +# include +# include +#endif #include "cache.h" +#if __APPLE__ +# define OSXFUSE_SSHFS_VERSION "2.3.0" +#endif + #ifndef MAP_LOCKED #define MAP_LOCKED 0 #endif @@ -118,6 +131,16 @@ #define SSHNODELAY_SO "sshnodelay.so" +#if __APPLE__ + +#ifndef LIBDIR +# define LIBDIR "/usr/local/lib" +#endif + +static char sshfs_program_path[PATH_MAX] = { 0 }; + +#endif /* __APPLE__ */ + struct buffer { uint8_t *p; size_t len; @@ -167,6 +190,9 @@ struct sshfs_file { int connver; int modifver; int refs; +#if __APPLE__ + pthread_mutex_t file_lock; +#endif }; struct sshfs { @@ -207,6 +233,10 @@ struct sshfs { int server_version; unsigned remote_uid; unsigned local_uid; +#if __APPLE__ + unsigned remote_gid; + unsigned local_gid; +#endif int remote_uid_detected; unsigned blksize; char *progname; @@ -661,8 +691,17 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) } } +#if __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__ */ memset(stbuf, 0, sizeof(struct stat)); stbuf->st_mode = mode; @@ -765,11 +804,35 @@ static void ssh_add_arg(const char *arg) #ifdef SSH_NODELAY_WORKAROUND static int do_ssh_nodelay_workaround(void) { +#if __APPLE__ + char *oldpreload = getenv("DYLD_INSERT_LIBRARIES"); +#else char *oldpreload = getenv("LD_PRELOAD"); +#endif char *newpreload; char sopath[PATH_MAX]; int res; +#if __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) { @@ -795,15 +858,24 @@ static int do_ssh_nodelay_workaround(void) } } +#if __APPLE__ +pathok: +#endif + newpreload = g_strdup_printf("%s%s%s", oldpreload ? oldpreload : "", oldpreload ? " " : "", sopath); +#if __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; } @@ -1500,6 +1572,10 @@ static void sftp_detect_uid() sshfs.remote_uid = stbuf.st_uid; sshfs.local_uid = getuid(); +#if __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); @@ -2120,6 +2196,14 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) buf_init(&buf, 0); buf_add_path(&buf, path); buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID); +#if __APPLE__ + if (sshfs.remote_uid_detected) { + if (uid == sshfs.local_uid) + uid = sshfs.remote_uid; + if (gid == sshfs.local_gid) + gid = sshfs.remote_gid; + } +#endif /* __APPLE__ */ buf_add_uint32(&buf, uid); buf_add_uint32(&buf, gid); err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); @@ -2203,6 +2287,9 @@ static int sshfs_open_common(const char *path, mode_t mode, sf = g_new0(struct sshfs_file, 1); list_init(&sf->write_reqs); pthread_cond_init(&sf->write_finished, NULL); +#if __APPLE__ + pthread_mutex_init(&sf->file_lock, NULL); +#endif /* Assume random read after open */ sf->is_seq = 0; sf->refs = 1; @@ -2236,11 +2323,21 @@ static int sshfs_open_common(const char *path, mode_t mode, } if (!err) { +#if __APPLE__ + if (cache_enabled) + cache_add_attr(path, &stbuf, wrctr); +#else cache_add_attr(path, &stbuf, wrctr); +#endif buf_finish(&sf->handle); fi->fh = (unsigned long) sf; } else { +#if __APPLE__ + if (cache_enabled) + cache_invalidate(path); +#else cache_invalidate(path); +#endif g_free(sf); } buf_free(&buf); @@ -2295,14 +2392,32 @@ static int sshfs_fsync(const char *path, int isdatasync, static void sshfs_file_put(struct sshfs_file *sf) { +#if __APPLE__ + pthread_mutex_lock(&sf->file_lock); +#endif sf->refs--; +#if __APPLE__ + if (!sf->refs) { + pthread_mutex_unlock(&sf->file_lock); + g_free(sf); + } else { + pthread_mutex_unlock(&sf->file_lock); + } +#else /* !__APPLE__ */ if (!sf->refs) g_free(sf); +#endif /* !__APPLE__ */ } static void sshfs_file_get(struct sshfs_file *sf) { +#if __APPLE__ + pthread_mutex_lock(&sf->file_lock); +#endif sf->refs++; +#if __APPLE__ + pthread_mutex_unlock(&sf->file_lock); +#endif } static int sshfs_release(const char *path, struct fuse_file_info *fi) @@ -2992,7 +3107,12 @@ static int sshfs_opt_proc(void *data, const char *arg, int key, exit(1); case KEY_VERSION: +#if __APPLE__ + printf("SSHFS version %s (OSXFUSE SSHFS %s)\n", + PACKAGE_VERSION, OSXFUSE_SSHFS_VERSION); +#else printf("SSHFS version %s\n", PACKAGE_VERSION); +#endif #if FUSE_VERSION >= 25 fuse_opt_add_arg(outargs, "--version"); sshfs_fuse_main(outargs); @@ -3076,6 +3196,15 @@ static int read_password(void) perror("Failed to allocate locked page for password"); return -1; } +#if __APPLE__ + 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; + } +#endif /* __APPLE__ */ /* Don't use fgets() because password might stay in memory */ for (n = 0; n < max_password; n++) { @@ -3227,7 +3356,11 @@ static int ssh_connect(void) return 0; } +#if __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); @@ -3236,6 +3369,14 @@ int main(int argc, char *argv[]) const char *sftp_server; int libver; +#if __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; @@ -3243,7 +3384,11 @@ int main(int argc, char *argv[]) sshfs.max_write = 65536; sshfs.nodelay_workaround = 1; sshfs.nodelaysrv_workaround = 0; +#if __APPLE__ + sshfs.rename_workaround = 1; +#else sshfs.rename_workaround = 0; +#endif sshfs.truncate_workaround = 0; sshfs.buflimit_workaround = 1; sshfs.ssh_ver = 2; @@ -3252,6 +3397,9 @@ int main(int argc, char *argv[]) sshfs.ptyfd = -1; sshfs.ptyslavefd = -1; sshfs.delay_connect = 0; +#if __APPLE__ + sshfs.detect_uid = 1; +#endif ssh_add_arg("ssh"); ssh_add_arg("-x"); ssh_add_arg("-a"); diff --git a/sshnodelay.c b/sshnodelay.c index 7518089..e1d9220 100644 --- a/sshnodelay.c +++ b/sshnodelay.c @@ -5,6 +5,32 @@ #include #include +#if __APPLE__ + +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) +{ + int res = 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; +} + +#else /* !__APPLE__ */ + int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) { int (*next_connect)(int, const struct sockaddr *, socklen_t) = @@ -16,3 +42,5 @@ int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) } return res; } + +#endif /* !__APPLE__ */ -- cgit v1.2.3 From f2086ccfbc5e2f84586fb4f68fd8482f0a750b8f Mon Sep 17 00:00:00 2001 From: Percy Jahn Date: Wed, 24 Aug 2011 13:22:36 +0200 Subject: sshfs: fstat workaround Add "-oworkaround=fstat" for SFTP servers which don't support the FSTAT message. --- ChangeLog | 5 +++++ sshfs.c | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 30a7cbf..fb3088f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2011-08-24 Miklos Szeredi + + * Add "-oworkaround=fstat" for SFTP servers which don't support + the FSTAT message. Patch by: Percy Jahn + 2011-07-01 Miklos Szeredi * Released 2.3 diff --git a/sshfs.c b/sshfs.c index d124dcf..6d2183b 100644 --- a/sshfs.c +++ b/sshfs.c @@ -206,6 +206,7 @@ struct sshfs { int nodelaysrv_workaround; int truncate_workaround; int buflimit_workaround; + int fstat_workaround; int transform_symlinks; int follow_symlinks; int no_check_root; @@ -364,11 +365,13 @@ static struct fuse_opt workaround_opts[] = { SSHFS_OPT("none", nodelaysrv_workaround, 0), SSHFS_OPT("none", truncate_workaround, 0), SSHFS_OPT("none", buflimit_workaround, 0), + SSHFS_OPT("none", fstat_workaround, 0), SSHFS_OPT("all", rename_workaround, 1), SSHFS_OPT("all", nodelay_workaround, 1), SSHFS_OPT("all", nodelaysrv_workaround, 1), SSHFS_OPT("all", truncate_workaround, 1), SSHFS_OPT("all", buflimit_workaround, 1), + SSHFS_OPT("all", fstat_workaround, 1), SSHFS_OPT("rename", rename_workaround, 1), SSHFS_OPT("norename", rename_workaround, 0), SSHFS_OPT("nodelay", nodelay_workaround, 1), @@ -379,6 +382,8 @@ static struct fuse_opt workaround_opts[] = { SSHFS_OPT("notruncate", truncate_workaround, 0), SSHFS_OPT("buflimit", buflimit_workaround, 1), SSHFS_OPT("nobuflimit", buflimit_workaround, 0), + SSHFS_OPT("fstat", fstat_workaround, 1), + SSHFS_OPT("nofstat", fstat_workaround, 0), FUSE_OPT_END }; @@ -2808,6 +2813,9 @@ static int sshfs_fgetattr(const char *path, struct stat *stbuf, if (!sshfs_file_is_conn(sf)) return -EIO; + if (sshfs.fstat_workaround) + return sshfs_getattr(path, stbuf); + buf_init(&buf, 0); buf_add_buf(&buf, &sf->handle); err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf); -- cgit v1.2.3 From 163683d9ef91f5f338dd62788ea75c23ebca67de Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 23 Sep 2011 14:33:32 +0200 Subject: Add "FIXME: really needs LSETSTAT extension (debian Bug#640038)" --- sshfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sshfs.c b/sshfs.c index 6d2183b..1d4a1b1 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2189,6 +2189,7 @@ static int sshfs_chmod(const char *path, mode_t mode) buf_add_path(&buf, path); buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS); buf_add_uint32(&buf, mode); + /* FIXME: really needs LSETSTAT extension (debian Bug#640038) */ err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); buf_free(&buf); return err; -- cgit v1.2.3 From d8da0c4ed6fcb336c93503fd980b930de547470f Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 21 Oct 2011 17:12:31 +0200 Subject: Remove "-oPreferredAuthentications" from ssh options Remove "-oPreferredAuthentications" from ssh options if the "password_stdin" option is used. Reported by E. Kuemmerle --- ChangeLog | 5 +++++ sshfs.c | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index fb3088f..5d25cbd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2011-10-21 Miklos Szeredi + + * Remove "-oPreferredAuthentications" from ssh options if the + "password_stdin" option is used. Reported by E. Kuemmerle + 2011-08-24 Miklos Szeredi * Add "-oworkaround=fstat" for SFTP servers which don't support diff --git a/sshfs.c b/sshfs.c index 1d4a1b1..74d0e71 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3237,7 +3237,6 @@ static int read_password(void) } sshfs.password[n+1] = '\0'; ssh_add_arg("-oNumberOfPasswordPrompts=1"); - ssh_add_arg("-oPreferredAuthentications=password,keyboard-interactive"); return 0; } -- cgit v1.2.3 From 04a610bad194a9d375c2b0324b1c8e119465fc57 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 14 Nov 2011 15:12:52 +0100 Subject: Fix double free if reconnection races with request sending Patch by E. Kuemmerle --- ChangeLog | 5 +++++ sshfs.c | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d25cbd..66ca1e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2011-11-14 Miklos Szeredi + + * Fix double free if reconnection races with request sending. + Patch by E. Kuemmerle + 2011-10-21 Miklos Szeredi * Remove "-oPreferredAuthentications" from ssh options if the diff --git a/sshfs.c b/sshfs.c index 74d0e71..5c2bd51 100644 --- a/sshfs.c +++ b/sshfs.c @@ -1828,9 +1828,16 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, err = -EIO; if (sftp_send_iov(type, id, iov, count) == -1) { + gboolean rmed; + pthread_mutex_lock(&sshfs.lock); - g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); + rmed = g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); pthread_mutex_unlock(&sshfs.lock); + + if (!rmed && !want_reply) { + /* request already freed */ + return err; + } goto out; } if (want_reply) @@ -1851,12 +1858,13 @@ out: static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count, uint8_t expect_type, struct buffer *outbuf) { + int err; struct request *req; - sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL, - &req); + err = sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL, + &req); if (expect_type == 0) - return 0; + return err; return sftp_request_wait(req, type, expect_type, outbuf); } -- cgit v1.2.3 From 90619fe249050e3a8145aac526e7eed552464731 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 14 Nov 2011 16:28:13 +0100 Subject: Add locking around modifver and connver --- ChangeLog | 2 ++ sshfs.c | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 66ca1e2..4c6ba2d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * Fix double free if reconnection races with request sending. Patch by E. Kuemmerle + * Add locking around modifver and connver + 2011-10-21 Miklos Szeredi * Remove "-oPreferredAuthentications" from ssh options if the diff --git a/sshfs.c b/sshfs.c index 5c2bd51..08c6447 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2228,12 +2228,19 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) static int sshfs_truncate_workaround(const char *path, off_t size, struct fuse_file_info *fi); +static void sshfs_inc_modifver(void) +{ + pthread_mutex_lock(&sshfs.lock); + sshfs.modifver++; + pthread_mutex_unlock(&sshfs.lock); +} + static int sshfs_truncate(const char *path, off_t size) { int err; struct buffer buf; - sshfs.modifver ++; + sshfs_inc_modifver(); if (size == 0 || sshfs.truncate_workaround) return sshfs_truncate_workaround(path, size, NULL); @@ -2262,7 +2269,13 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf) static inline int sshfs_file_is_conn(struct sshfs_file *sf) { - return sf->connver == sshfs.connver; + int ret; + + pthread_mutex_lock(&sshfs.lock); + ret = (sf->connver == sshfs.connver); + pthread_mutex_unlock(&sshfs.lock); + + return ret; } static int sshfs_open_common(const char *path, mode_t mode, @@ -2308,8 +2321,10 @@ static int sshfs_open_common(const char *path, mode_t mode, sf->is_seq = 0; sf->refs = 1; sf->next_pos = 0; + pthread_mutex_lock(&sshfs.lock); sf->modifver= sshfs.modifver; sf->connver = sshfs.connver; + pthread_mutex_unlock(&sshfs.lock); buf_init(&buf, 0); buf_add_path(&buf, path); buf_add_uint32(&buf, pflags); @@ -2545,7 +2560,9 @@ static void submit_read(struct sshfs_file *sf, size_t size, off_t offset, chunk->offset = offset; chunk->size = size; chunk->refs = 1; + pthread_mutex_lock(&sshfs.lock); chunk->modifver = sshfs.modifver; + pthread_mutex_unlock(&sshfs.lock); sshfs_send_async_read(sf, chunk); pthread_mutex_lock(&sshfs.lock); chunk_put(*chunkp); @@ -2688,7 +2705,7 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size, if (!sshfs_file_is_conn(sf)) return -EIO; - sshfs.modifver ++; + sshfs_inc_modifver(); buf_init(&buf, 0); buf_add_buf(&buf, handle); buf_add_uint64(&buf, offset); @@ -2794,7 +2811,7 @@ static int sshfs_ftruncate(const char *path, off_t size, if (!sshfs_file_is_conn(sf)) return -EIO; - sshfs.modifver ++; + sshfs_inc_modifver(); if (sshfs.truncate_workaround) return sshfs_truncate_workaround(path, size, fi); -- cgit v1.2.3 From fa9bfc6d08fc01d3ac6ec91bec7cdc102aec2df1 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 16 Nov 2011 14:54:37 +0100 Subject: Submit max 32k reads and writes to the sftp server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also don't limit the kernel to 64k reads and writes, rather split into 32k sized chunks and send them to the server all at once. This is more efficient and less demanding from the server. Reported by Ludovic Courtès. Fix suggested by Niels Möller --- ChangeLog | 8 ++ sshfs.c | 375 +++++++++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 269 insertions(+), 114 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4c6ba2d..8f11917 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-11-16 Miklos Szeredi + + * Submit max 32k reads and writes to the sftp server. Also don't + limit the kernel to 64k reads and writes, rather split into 32k + sized chunks and send them to the server all at once. This is + more efficient and less demanding from the server. Reported by + Ludovic Courtès. Fix suggested by Niels Möller + 2011-11-14 Miklos Szeredi * Fix double free if reconnection races with request sending. diff --git a/sshfs.c b/sshfs.c index 08c6447..89b3974 100644 --- a/sshfs.c +++ b/sshfs.c @@ -169,14 +169,27 @@ struct request { struct list_head list; }; +struct sshfs_io { + int num_reqs; + pthread_cond_t finished; + int error; +}; + +struct read_req { + struct sshfs_io *sio; + struct list_head list; + struct buffer data; + size_t size; + ssize_t res; +}; + struct read_chunk { - sem_t ready; off_t offset; size_t size; - struct buffer data; int refs; - int res; long modifver; + struct list_head reqs; + struct sshfs_io sio; }; struct sshfs_file { @@ -1263,8 +1276,14 @@ static void request_free(struct request *req) static void chunk_free(struct read_chunk *chunk) { - buf_free(&chunk->data); - sem_destroy(&chunk->ready); + while (!list_empty(&chunk->reqs)) { + struct read_req *rreq; + + rreq = list_entry(chunk->reqs.prev, struct read_req, list); + list_del(&rreq->list); + buf_free(&rreq->data); + g_free(rreq); + } g_free(chunk); } @@ -2463,131 +2482,178 @@ static int sshfs_release(const char *path, struct fuse_file_info *fi) return 0; } -static int sshfs_sync_read(struct sshfs_file *sf, char *rbuf, size_t size, - off_t offset) -{ - int err; - struct buffer buf; - struct buffer data; - struct buffer *handle = &sf->handle; - buf_init(&buf, 0); - buf_add_buf(&buf, handle); - buf_add_uint64(&buf, offset); - buf_add_uint32(&buf, size); - err = sftp_request(SSH_FXP_READ, &buf, SSH_FXP_DATA, &data); - if (!err) { - uint32_t retsize; - err = -EIO; - if (buf_get_uint32(&data, &retsize) != -1) { - if (retsize > size) - fprintf(stderr, "long read\n"); - else { - buf_get_mem(&data, rbuf, retsize); - err = retsize; - } - } - buf_free(&data); - } else if (err == MY_EOF) - err = 0; - buf_free(&buf); - return err; -} - static void sshfs_read_end(struct request *req) { - struct read_chunk *chunk = (struct read_chunk *) req->data; + struct read_req *rreq = (struct read_req *) req->data; if (req->error) - chunk->res = req->error; + rreq->res = req->error; else if (req->replied) { - chunk->res = -EIO; + rreq->res = -EIO; if (req->reply_type == SSH_FXP_STATUS) { uint32_t serr; if (buf_get_uint32(&req->reply, &serr) != -1) { if (serr == SSH_FX_EOF) - chunk->res = 0; + rreq->res = 0; + } else { + rreq->res = -sftp_error_to_errno(serr); } } else if (req->reply_type == SSH_FXP_DATA) { uint32_t retsize; if (buf_get_uint32(&req->reply, &retsize) != -1) { - if (retsize > chunk->size) + if (retsize > rreq->size) { fprintf(stderr, "long read\n"); - else { - chunk->res = retsize; - chunk->data = req->reply; + } else if (buf_check_get(&req->reply, retsize) != -1) { + rreq->res = retsize; + rreq->data = req->reply; buf_init(&req->reply, 0); } } - } else + } else { fprintf(stderr, "protocol error\n"); - } else - chunk->res = -EIO; + } + } else { + rreq->res = -EIO; + } - sem_post(&chunk->ready); - chunk_put(chunk); + rreq->sio->num_reqs--; + if (!rreq->sio->num_reqs) + pthread_cond_broadcast(&rreq->sio->finished); } static void sshfs_read_begin(struct request *req) { - struct read_chunk *chunk = (struct read_chunk *) req->data; - chunk->refs++; + struct read_req *rreq = (struct read_req *) req->data; + rreq->sio->num_reqs++; } -static void sshfs_send_async_read(struct sshfs_file *sf, - struct read_chunk *chunk) +static struct read_chunk *sshfs_send_read(struct sshfs_file *sf, size_t size, + off_t offset) { - struct buffer buf; + struct read_chunk *chunk = g_new0(struct read_chunk, 1); struct buffer *handle = &sf->handle; - struct iovec iov; - buf_init(&buf, 0); - buf_add_buf(&buf, handle); - buf_add_uint64(&buf, chunk->offset); - buf_add_uint32(&buf, chunk->size); - buf_to_iov(&buf, &iov); - sftp_request_send(SSH_FXP_READ, &iov, 1, sshfs_read_begin, - sshfs_read_end, 0, chunk, NULL); - buf_free(&buf); + pthread_cond_init(&chunk->sio.finished, NULL); + list_init(&chunk->reqs); + chunk->size = size; + chunk->offset = offset; + chunk->refs = 1; + + while (size) { + int err; + struct buffer buf; + struct iovec iov[1]; + struct read_req *rreq; + size_t bsize = size < sshfs.max_read ? size : sshfs.max_read; + + rreq = g_new0(struct read_req, 1); + rreq->sio = &chunk->sio; + rreq->size = bsize; + buf_init(&rreq->data, 0); + list_add(&rreq->list, &chunk->reqs); + + buf_init(&buf, 0); + buf_add_buf(&buf, handle); + buf_add_uint64(&buf, offset); + buf_add_uint32(&buf, bsize); + buf_to_iov(&buf, &iov[0]); + err = sftp_request_send(SSH_FXP_READ, iov, 1, + sshfs_read_begin, + sshfs_read_end, + 0, rreq, NULL); + + buf_free(&buf); + if (err) + break; + + size -= bsize; + offset += bsize; + } + + return chunk; } -static void submit_read(struct sshfs_file *sf, size_t size, off_t offset, - struct read_chunk **chunkp) +static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size) { - struct read_chunk *chunk = g_new0(struct read_chunk, 1); + int res = 0; + struct read_req *rreq; - sem_init(&chunk->ready, 0, 0); - buf_init(&chunk->data, 0); - chunk->offset = offset; - chunk->size = size; - chunk->refs = 1; - pthread_mutex_lock(&sshfs.lock); - chunk->modifver = sshfs.modifver; - pthread_mutex_unlock(&sshfs.lock); - sshfs_send_async_read(sf, chunk); pthread_mutex_lock(&sshfs.lock); - chunk_put(*chunkp); - *chunkp = chunk; + while (chunk->sio.num_reqs) + pthread_cond_wait(&chunk->sio.finished, &sshfs.lock); pthread_mutex_unlock(&sshfs.lock); -} -static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size) -{ - int res; - while (sem_wait(&chunk->ready)); - res = chunk->res; + + if (chunk->sio.error) { + if (chunk->sio.error != MY_EOF) + res = chunk->sio.error; + + goto out; + } + + while (!list_empty(&chunk->reqs) && size) { + rreq = list_entry(chunk->reqs.prev, struct read_req, list); + + if (rreq->res < 0) { + chunk->sio.error = rreq->res; + break; + } if (rreq->res == 0) { + chunk->sio.error = MY_EOF; + break; + } else if (size < (size_t) rreq->res) { + buf_get_mem(&rreq->data, buf, size); + rreq->res -= size; + rreq->size -= size; + res += size; + break; + } else { + buf_get_mem(&rreq->data, buf, rreq->res); + res += rreq->res; + if ((size_t) rreq->res < rreq->size) { + chunk->sio.error = MY_EOF; + break; + } + buf += rreq->res; + size -= rreq->res; + list_del(&rreq->list); + buf_free(&rreq->data); + g_free(rreq); + } + } + if (res > 0) { - if ((size_t) res > size) - res = size; - buf_get_mem(&chunk->data, buf, res); chunk->offset += res; chunk->size -= res; - chunk->res -= res; } - sem_post(&chunk->ready); + +out: chunk_put_locked(chunk); return res; } +static int sshfs_sync_read(struct sshfs_file *sf, char *buf, size_t size, + off_t offset) +{ + struct read_chunk *chunk; + + chunk = sshfs_send_read(sf, size, offset); + return wait_chunk(chunk, buf, size); +} + +static void submit_read(struct sshfs_file *sf, size_t size, off_t offset, + struct read_chunk **chunkp) +{ + struct read_chunk *chunk; + + chunk = sshfs_send_read(sf, size, offset); + pthread_mutex_lock(&sshfs.lock); + chunk->modifver = sshfs.modifver; + chunk_put(*chunkp); + *chunkp = chunk; + chunk->refs++; + pthread_mutex_unlock(&sshfs.lock); +} + static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset) { struct read_chunk *ch = sf->readahead; @@ -2691,14 +2757,110 @@ static void sshfs_write_end(struct request *req) sshfs_file_put(sf); } +static int sshfs_async_write(struct sshfs_file *sf, const char *wbuf, + size_t size, off_t offset) +{ + int err = 0; + struct buffer *handle = &sf->handle; + + while (!err && size) { + struct buffer buf; + struct iovec iov[2]; + size_t bsize = size < sshfs.max_write ? size : sshfs.max_write; + + buf_init(&buf, 0); + buf_add_buf(&buf, handle); + buf_add_uint64(&buf, offset); + buf_add_uint32(&buf, bsize); + buf_to_iov(&buf, &iov[0]); + iov[1].iov_base = (void *) wbuf; + iov[1].iov_len = bsize; + err = sftp_request_send(SSH_FXP_WRITE, iov, 2, + sshfs_write_begin, sshfs_write_end, + 0, sf, NULL); + buf_free(&buf); + size -= bsize; + wbuf += bsize; + offset += bsize; + } + + return err; +} + +static void sshfs_sync_write_begin(struct request *req) +{ + struct sshfs_io *sio = (struct sshfs_io *) req->data; + sio->num_reqs++; +} + +static void sshfs_sync_write_end(struct request *req) +{ + uint32_t serr; + struct sshfs_io *sio = (struct sshfs_io *) req->data; + + if (req->error) { + sio->error = req->error; + } else if (req->replied) { + if (req->reply_type != SSH_FXP_STATUS) { + fprintf(stderr, "protocol error\n"); + } else if (buf_get_uint32(&req->reply, &serr) != -1 && + serr != SSH_FX_OK) { + sio->error = -EIO; + } + } + sio->num_reqs--; + if (!sio->num_reqs) + pthread_cond_broadcast(&sio->finished); +} + + +static int sshfs_sync_write(struct sshfs_file *sf, const char *wbuf, + size_t size, off_t offset) +{ + int err = 0; + struct buffer *handle = &sf->handle; + struct sshfs_io sio = { .error = 0, .num_reqs = 0 }; + + pthread_cond_init(&sio.finished, NULL); + + while (!err && size) { + struct buffer buf; + struct iovec iov[2]; + size_t bsize = size < sshfs.max_write ? size : sshfs.max_write; + + buf_init(&buf, 0); + buf_add_buf(&buf, handle); + buf_add_uint64(&buf, offset); + buf_add_uint32(&buf, bsize); + buf_to_iov(&buf, &iov[0]); + iov[1].iov_base = (void *) wbuf; + iov[1].iov_len = bsize; + err = sftp_request_send(SSH_FXP_WRITE, iov, 2, + sshfs_sync_write_begin, + sshfs_sync_write_end, + 0, &sio, NULL); + buf_free(&buf); + size -= bsize; + wbuf += bsize; + offset += bsize; + } + + pthread_mutex_lock(&sshfs.lock); + while (sio.num_reqs) + pthread_cond_wait(&sio.finished, &sshfs.lock); + pthread_mutex_unlock(&sshfs.lock); + + if (!err) + err = sio.error; + + return err; +} + static int sshfs_write(const char *path, const char *wbuf, size_t size, off_t offset, struct fuse_file_info *fi) { int err; - struct buffer buf; struct sshfs_file *sf = get_sshfs_file(fi); - struct buffer *handle = &sf->handle; - struct iovec iov[2]; (void) path; @@ -2706,22 +2868,12 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size, return -EIO; sshfs_inc_modifver(); - buf_init(&buf, 0); - buf_add_buf(&buf, handle); - buf_add_uint64(&buf, offset); - buf_add_uint32(&buf, size); - buf_to_iov(&buf, &iov[0]); - iov[1].iov_base = (void *) wbuf; - iov[1].iov_len = size; - if (!sshfs.sync_write && !sf->write_error) { - err = sftp_request_send(SSH_FXP_WRITE, iov, 2, - sshfs_write_begin, sshfs_write_end, - 0, sf, NULL); - } else { - err = sftp_request_iov(SSH_FXP_WRITE, iov, 2, SSH_FXP_STATUS, - NULL); - } - buf_free(&buf); + + if (!sshfs.sync_write && !sf->write_error) + err = sshfs_async_write(sf, wbuf, size, offset); + else + err = sshfs_sync_write(sf, wbuf, size, offset); + return err ? err : (int) size; } @@ -3413,8 +3565,9 @@ int main(int argc, char *argv[]) g_thread_init(NULL); sshfs.blksize = 4096; - sshfs.max_read = 65536; - sshfs.max_write = 65536; + /* SFTP spec says all servers should allow at least 32k I/O */ + sshfs.max_read = 32768; + sshfs.max_write = 32768; sshfs.nodelay_workaround = 1; sshfs.nodelaysrv_workaround = 0; #if __APPLE__ @@ -3501,12 +3654,6 @@ int main(int argc, char *argv[]) if (fuse_is_lib_option("ac_attr_timeout=")) fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0"); - tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read); - fuse_opt_insert_arg(&args, 1, tmp); - g_free(tmp); - tmp = g_strdup_printf("-omax_write=%u", sshfs.max_write); - fuse_opt_insert_arg(&args, 1, tmp); - g_free(tmp); #if FUSE_VERSION >= 27 libver = fuse_version(); assert(libver >= 27); -- cgit v1.2.3 From 69b2b3cc0e63dd3a1d7181315f09ceb4b57722be Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 5 Dec 2011 13:11:09 +0100 Subject: Make chown respect the UID mapping policy Reported and tested by Vivenzio Pagliari --- ChangeLog | 5 +++++ sshfs.c | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f11917..9b3fb9c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2011-11-25 Miklos Szeredi + + * Make chown respect the UID mapping policy. Reported and tested + by Vivenzio Pagliari + 2011-11-16 Miklos Szeredi * Submit max 32k reads and writes to the sftp server. Also don't diff --git a/sshfs.c b/sshfs.c index 89b3974..62fadff 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2226,9 +2226,7 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) { int err; struct buffer buf; - buf_init(&buf, 0); - buf_add_path(&buf, path); - buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID); + #if __APPLE__ if (sshfs.remote_uid_detected) { if (uid == sshfs.local_uid) @@ -2236,7 +2234,14 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) if (gid == sshfs.local_gid) gid = sshfs.remote_gid; } -#endif /* __APPLE__ */ +#else /* !__APPLE__ */ + if (sshfs.remote_uid_detected && uid == sshfs.local_uid) + uid = sshfs.remote_uid; +#endif /* !__APPLE__ */ + + buf_init(&buf, 0); + buf_add_path(&buf, path); + buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID); buf_add_uint32(&buf, uid); buf_add_uint32(&buf, gid); err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); -- cgit v1.2.3 From 20fafed0a409160734f3af148e424312c239550d Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 20 Dec 2011 14:55:45 +0100 Subject: Fix error handling in sshfs_read_end Reported by Mike Kelly --- sshfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sshfs.c b/sshfs.c index 62fadff..b971530 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2500,8 +2500,8 @@ static void sshfs_read_end(struct request *req) if (buf_get_uint32(&req->reply, &serr) != -1) { if (serr == SSH_FX_EOF) rreq->res = 0; - } else { - rreq->res = -sftp_error_to_errno(serr); + else + rreq->res = -sftp_error_to_errno(serr); } } else if (req->reply_type == SSH_FXP_DATA) { uint32_t retsize; -- cgit v1.2.3 From bb3ea51117a5dfd98f00fb829f8576e009593dda Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Fri, 16 Dec 2011 14:52:19 -0500 Subject: Fix typo in error message s/FD_CLOESEC/FD_CLOEXEC/ --- sshfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshfs.c b/sshfs.c index b971530..7d7210e 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3703,7 +3703,7 @@ int main(int argc, char *argv[]) res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC); if (res == -1) - perror("WARNING: failed to set FD_CLOESEC on fuse device"); + perror("WARNING: failed to set FD_CLOEXEC on fuse device"); fuse = fuse_new(ch, &args, cache_init(&sshfs_oper), sizeof(struct fuse_operations), NULL); -- cgit v1.2.3 From a306a80b6ea9ca986a444b722acf0ed09beac7bc Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Fri, 16 Dec 2011 14:52:20 -0500 Subject: Fix a possible small memory leak --- sshfs.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sshfs.c b/sshfs.c index 7d7210e..d9226d8 100644 --- a/sshfs.c +++ b/sshfs.c @@ -1454,16 +1454,20 @@ static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version) struct buffer buf2; buf_init(&buf2, len - 5); - if (do_read(&buf2) == -1) + if (do_read(&buf2) == -1) { + buf_free(&buf2); return -1; + } do { char *ext; char *extdata; if (buf_get_string(&buf2, &ext) == -1 || - buf_get_string(&buf2, &extdata) == -1) + buf_get_string(&buf2, &extdata) == -1) { + buf_free(&buf2); return -1; + } DEBUG("Extension: %s <%s>\n", ext, extdata); @@ -1479,6 +1483,7 @@ static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version) strcmp(extdata, "1") == 0) sshfs.ext_hardlink = 1; } while (buf2.len < buf2.size); + buf_free(&buf2); } return 0; } -- cgit v1.2.3 From a6b6b5c820228fe2376705db711d486e9ec866a1 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Fri, 16 Dec 2011 14:52:21 -0500 Subject: Add -o idmap=file, -o uidmap=FILE, -o gidmap=FILE These options allow you to create a pair of local files, with username:uid/groupname:gid pairs, one per line. Alternatively, files can be in standard /etc/passwd / /etc/group format. The uid/gids are for the remote server, their local counterparts are looked up with a local getpwnam/getgrnam call. Any stat() calls will show with the remapped local uid/gid, and any chown() calls will be remapped back to the remote uid/gid. --- ChangeLog | 7 ++ sshfs.1 | 12 ++++ sshfs.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 241 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9b3fb9c..2fa431e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2011-12-16 Mike Kelly + + * Add -o idmap=file, -o uidmap=FILE, -o gidmap=FILE. These options + allow you to create a pair of local files, similar to /etc/passwd or + /etc/group files from the remote server, and use those to remap all + the given UIDs/GIDs. + 2011-11-25 Miklos Szeredi * Make chown respect the UID mapping policy. Reported and tested diff --git a/sshfs.1 b/sshfs.1 index d103ad3..9dcd8aa 100644 --- a/sshfs.1 +++ b/sshfs.1 @@ -102,6 +102,18 @@ no translation of the ID space (default) .TP user only translate UID of connecting user +.TP +file +translate UIDs/GIDs based upon the contents of \fBuidfile \fR and +\fBgidfile\fR +.RE +.TP +\fB\-o\fR uidfile=FILE +file containing username:uid mappings for \fBidmap=file\fR +.RE +.TP +\fB\-o\fR gidfile=FILE +file containing groupname:gid mappings for \fBidmap=file\fR .RE .TP \fB\-o\fR ssh_command=CMD diff --git a/sshfs.c b/sshfs.c index d9226d8..0649805 100644 --- a/sshfs.c +++ b/sshfs.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #if __APPLE__ # include # include @@ -224,6 +226,13 @@ struct sshfs { int follow_symlinks; int no_check_root; int detect_uid; + int idmap; + char *uid_file; + char *gid_file; + GHashTable *uid_map; + GHashTable *gid_map; + GHashTable *r_uid_map; + GHashTable *r_gid_map; unsigned max_read; unsigned max_write; unsigned ssh_ver; @@ -336,6 +345,12 @@ enum { KEY_CONFIGFILE, }; +enum { + IDMAP_NONE, + IDMAP_USER, + IDMAP_FILE, +}; + #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v } static struct fuse_opt sshfs_opts[] = { @@ -347,8 +362,11 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0), SSHFS_OPT("-1", ssh_ver, 1), SSHFS_OPT("workaround=%s", workarounds, 0), - SSHFS_OPT("idmap=none", detect_uid, 0), - SSHFS_OPT("idmap=user", detect_uid, 1), + SSHFS_OPT("idmap=none", idmap, IDMAP_NONE), + SSHFS_OPT("idmap=user", idmap, IDMAP_USER), + SSHFS_OPT("idmap=file", idmap, IDMAP_FILE), + SSHFS_OPT("uidfile=%s", uid_file, 0), + SSHFS_OPT("gidfile=%s", gid_file, 0), SSHFS_OPT("sshfs_sync", sync_write, 1), SSHFS_OPT("no_readahead", sync_read, 1), SSHFS_OPT("sshfs_debug", debug, 1), @@ -474,6 +492,15 @@ static int list_empty(const struct list_head *head) return head->next == head; } +/* given a pointer to the uid/gid, and the mapping table, remap the + * uid/gid, if necessary */ +static inline void translate_id(uint32_t *id, GHashTable *map) +{ + gpointer id_p; + if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) + *id = GPOINTER_TO_UINT(id_p); +} + static inline void buf_init(struct buffer *buf, size_t size) { if (size) { @@ -720,6 +747,10 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) uid = sshfs.local_uid; #endif /* !__APPLE__ */ + if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map) + translate_id(&uid, sshfs.uid_map); + if (sshfs.idmap == IDMAP_FILE && sshfs.gid_map) + translate_id(&gid, sshfs.gid_map); memset(stbuf, 0, sizeof(struct stat)); stbuf->st_mode = mode; @@ -2243,6 +2274,10 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) if (sshfs.remote_uid_detected && uid == sshfs.local_uid) uid = sshfs.remote_uid; #endif /* !__APPLE__ */ + if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map) + translate_id(&uid, sshfs.r_uid_map); + if (sshfs.idmap == IDMAP_FILE && sshfs.r_gid_map) + translate_id(&gid, sshfs.r_gid_map); buf_init(&buf, 0); buf_add_path(&buf, path); @@ -3221,6 +3256,9 @@ static void usage(const char *progname) " -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" +" 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" " -o ssh_command=CMD execute CMD instead of 'ssh'\n" " -o ssh_protocol=N ssh protocol to use (default: 2)\n" " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n" @@ -3551,6 +3589,166 @@ static int ssh_connect(void) return 0; } +/* remove trailing '\n', like the perl func of the same name */ +static inline void chomp(char *line) +{ + char *p = line; + if ((p = strrchr(line, '\n'))) + *p = '\0'; +} + +/* number of ':' separated fields in a passwd/group file that we care + * about */ +#define IDMAP_FIELDS 3 + +/* given a line from a uidmap or gidmap, parse out the name and id */ +static void parse_idmap_line(char *line, const char* filename, + const unsigned int lineno, uint32_t *ret_id, char **ret_name) +{ + chomp(line); + char *tokens[IDMAP_FIELDS]; + char *tok; + int i; + for (i = 0; (tok = strsep(&line, ":")) && (i < IDMAP_FIELDS) ; i++) { + tokens[i] = tok; + } + + char *name_tok, *id_tok; + if (i == 2) { + /* assume name:id format */ + name_tok = tokens[0]; + id_tok = tokens[1]; + } else if (i >= IDMAP_FIELDS) { + /* assume passwd/group file format */ + name_tok = tokens[0]; + id_tok = tokens[2]; + } else { + fprintf(stderr, "Unknown format at line %u of '%s'\n", + lineno, filename); + exit(1); + } + + errno = 0; + uint32_t remote_id = strtoul(id_tok, NULL, 10); + if (errno) { + fprintf(stderr, "Invalid id number on line %u of '%s': %s\n", + lineno, filename, strerror(errno)); + exit(1); + } + + *ret_name = strdup(name_tok); + *ret_id = remote_id; +} + +/* read a uidmap or gidmap */ +static void read_id_map(char *file, uint32_t *(*map_fn)(char *), + const char *name_id, GHashTable **idmap, GHashTable **r_idmap) +{ + *idmap = g_hash_table_new(NULL, NULL); + *r_idmap = g_hash_table_new(NULL, NULL); + FILE *fp; + char *line = NULL; + size_t len = 0; + unsigned int lineno = 0; + + fp = fopen(file, "r"); + if (fp == NULL) { + fprintf(stderr, "failed to open '%s': %s\n", + file, strerror(errno)); + exit(1); + } + + while (getline(&line, &len, fp) != EOF) { + lineno++; + uint32_t remote_id; + char *name; + + parse_idmap_line(line, file, lineno, &remote_id, &name); + + uint32_t *local_id = map_fn(name); + if (local_id == NULL) { + /* not found */ + DEBUG("%s(%u): no local %s\n", name, remote_id, name_id); + free(name); + continue; + } + + DEBUG("%s: remote %s %u => local %s %u\n", + name, name_id, remote_id, name_id, *local_id); + g_hash_table_insert(*idmap, GUINT_TO_POINTER(remote_id), GUINT_TO_POINTER(*local_id)); + g_hash_table_insert(*r_idmap, GUINT_TO_POINTER(*local_id), GUINT_TO_POINTER(remote_id)); + free(name); + free(local_id); + } + + if (fclose(fp) == EOF) { + fprintf(stderr, "failed to close '%s': %s", + file, strerror(errno)); + exit(1); + } + + if (line) + free(line); +} + +/* given a username, return a pointer to its uid, or NULL if it doesn't + * exist on this system */ +static uint32_t *username_to_uid(char *name) +{ + errno = 0; + struct passwd *pw = getpwnam(name); + if (pw == NULL) { + if (errno == 0) { + /* "does not exist" */ + return NULL; + } + fprintf(stderr, "Failed to look up user '%s': %s\n", + name, strerror(errno)); + exit(1); + } + uint32_t *r = malloc(sizeof(uint32_t)); + if (r == NULL) { + fprintf(stderr, "sshfs: memory allocation failed\n"); + abort(); + } + *r = pw->pw_uid; + return r; +} + +/* given a groupname, return a pointer to its gid, or NULL if it doesn't + * exist on this system */ +static uint32_t *groupname_to_gid(char *name) +{ + errno = 0; + struct group *gr = getgrnam(name); + if (gr == NULL) { + if (errno == 0) { + /* "does not exist" */ + return NULL; + } + fprintf(stderr, "Failed to look up group '%s': %s\n", + name, strerror(errno)); + exit(1); + } + uint32_t *r = malloc(sizeof(uint32_t)); + if (r == NULL) { + fprintf(stderr, "sshfs: memory allocation failed\n"); + abort(); + } + *r = gr->gr_gid; + return r; +} + +static inline void load_uid_map(void) +{ + read_id_map(sshfs.uid_file, &username_to_uid, "uid", &sshfs.uid_map, &sshfs.r_uid_map); +} + +static inline void load_gid_map(void) +{ + read_id_map(sshfs.gid_file, &groupname_to_gid, "gid", &sshfs.gid_map, &sshfs.r_gid_map); +} + #if __APPLE__ int main(int argc, char *argv[], __unused char *envp[], char **exec_path) #else @@ -3595,7 +3793,10 @@ int main(int argc, char *argv[]) sshfs.delay_connect = 0; #if __APPLE__ sshfs.detect_uid = 1; +#else + sshfs.detect_uid = 0; #endif + sshfs.idmap = IDMAP_NONE; ssh_add_arg("ssh"); ssh_add_arg("-x"); ssh_add_arg("-a"); @@ -3605,6 +3806,25 @@ int main(int argc, char *argv[]) parse_workarounds() == -1) exit(1); + if (sshfs.idmap == IDMAP_USER) + sshfs.detect_uid = 1; + else if (sshfs.idmap == IDMAP_FILE) { + sshfs.uid_map = NULL; + sshfs.gid_map = NULL; + sshfs.r_uid_map = NULL; + sshfs.r_gid_map = NULL; + if (!sshfs.uid_file && !sshfs.gid_file) { + fprintf(stderr, "need a uid_file or gid_file with idmap=file\n"); + exit(1); + } + if (sshfs.uid_file) + load_uid_map(); + if (sshfs.gid_file) + load_gid_map(); + } + free(sshfs.uid_file); + free(sshfs.gid_file); + DEBUG("SSHFS version %s\n", PACKAGE_VERSION); if (sshfs.password_stdin) { -- cgit v1.2.3 From e6f7fb4e5056bf6488595fb02b65abc1ac8080cc Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Fri, 9 Mar 2012 22:30:14 +0100 Subject: Make IDMAP_USER the default option on OS X UID/GID mapping had been enabled in previous versions of SSHFS for MacFUSE/ OSXFUSE by default. This is the expected behavior. --- sshfs.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sshfs.c b/sshfs.c index 0649805..82c23eb 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3254,8 +3254,13 @@ static void usage(const char *progname) " [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" +#if __APPLE__ +" none no translation of the ID space\n" +" user only translate UID/GID of connecting user (default)\n" +#else " none no translation of the ID space (default)\n" " user only translate UID of connecting user\n" +#endif " 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" @@ -3791,12 +3796,12 @@ int main(int argc, char *argv[]) sshfs.ptyfd = -1; sshfs.ptyslavefd = -1; sshfs.delay_connect = 0; + sshfs.detect_uid = 0; #if __APPLE__ - sshfs.detect_uid = 1; + sshfs.idmap = IDMAP_USER; #else - sshfs.detect_uid = 0; -#endif sshfs.idmap = IDMAP_NONE; +#endif ssh_add_arg("ssh"); ssh_add_arg("-x"); ssh_add_arg("-a"); -- cgit v1.2.3 From 0e87004ab26f7c3f5ad5cb63059bde82ec5f7cec Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 20 Dec 2011 10:27:51 -0500 Subject: default to erroring if we can't remap a uid/gid add a '-o nomap=ignore|error' option, which defaults to 'error' --- sshfs.1 | 11 +++++++++ sshfs.c | 85 ++++++++++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/sshfs.1 b/sshfs.1 index 9dcd8aa..27dd8bc 100644 --- a/sshfs.1 +++ b/sshfs.1 @@ -116,6 +116,17 @@ file containing username:uid mappings for \fBidmap=file\fR file containing groupname:gid mappings for \fBidmap=file\fR .RE .TP +\fB\-o\fR nomap=TYPE +with idmap=file, how to handle missing mappings +.RS 8 +.TP +ignore +don't do any re-mapping +.TP +error +return an error (default) +.RE +.TP \fB\-o\fR ssh_command=CMD execute CMD instead of 'ssh' .TP diff --git a/sshfs.c b/sshfs.c index 82c23eb..615e0be 100644 --- a/sshfs.c +++ b/sshfs.c @@ -227,6 +227,7 @@ struct sshfs { int no_check_root; int detect_uid; int idmap; + int nomap; char *uid_file; char *gid_file; GHashTable *uid_map; @@ -351,6 +352,11 @@ enum { IDMAP_FILE, }; +enum { + NOMAP_IGNORE, + NOMAP_ERROR, +}; + #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v } static struct fuse_opt sshfs_opts[] = { @@ -367,6 +373,8 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("idmap=file", idmap, IDMAP_FILE), SSHFS_OPT("uidfile=%s", uid_file, 0), SSHFS_OPT("gidfile=%s", gid_file, 0), + SSHFS_OPT("nomap=ignore", nomap, NOMAP_IGNORE), + SSHFS_OPT("nomap=error", nomap, NOMAP_ERROR), SSHFS_OPT("sshfs_sync", sync_write, 1), SSHFS_OPT("no_readahead", sync_read, 1), SSHFS_OPT("sshfs_debug", debug, 1), @@ -494,11 +502,20 @@ static int list_empty(const struct list_head *head) /* given a pointer to the uid/gid, and the mapping table, remap the * uid/gid, if necessary */ -static inline void translate_id(uint32_t *id, GHashTable *map) +static inline int translate_id(uint32_t *id, GHashTable *map) { gpointer id_p; - if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) + if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) { *id = GPOINTER_TO_UINT(id_p); + return 0; + } + switch (sshfs.nomap) { + case NOMAP_ERROR: return -1; + case NOMAP_IGNORE: return 0; + default: + fprintf(stderr, "internal error\n"); + abort(); + } } static inline void buf_init(struct buffer *buf, size_t size) @@ -702,36 +719,36 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) uint32_t mode = S_IFREG | 0777; if (buf_get_uint32(buf, &flags) == -1) - return -1; + return -EIO; if (flagsp) *flagsp = flags; if ((flags & SSH_FILEXFER_ATTR_SIZE) && buf_get_uint64(buf, &size) == -1) - return -1; + return -EIO; if ((flags & SSH_FILEXFER_ATTR_UIDGID) && (buf_get_uint32(buf, &uid) == -1 || buf_get_uint32(buf, &gid) == -1)) - return -1; + return -EIO; if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) && buf_get_uint32(buf, &mode) == -1) - return -1; + return -EIO; if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) { if (buf_get_uint32(buf, &atime) == -1 || buf_get_uint32(buf, &mtime) == -1) - return -1; + return -EIO; } if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) { uint32_t extcount; unsigned i; if (buf_get_uint32(buf, &extcount) == -1) - return -1; + return -EIO; for (i = 0; i < extcount; i++) { struct buffer tmp; if (buf_get_data(buf, &tmp) == -1) - return -1; + return -EIO; buf_free(&tmp); if (buf_get_data(buf, &tmp) == -1) - return -1; + return -EIO; buf_free(&tmp); } } @@ -748,9 +765,11 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) uid = sshfs.local_uid; #endif /* !__APPLE__ */ if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map) - translate_id(&uid, sshfs.uid_map); + if (translate_id(&uid, sshfs.uid_map) == -1) + return -EPERM; if (sshfs.idmap == IDMAP_FILE && sshfs.gid_map) - translate_id(&gid, sshfs.gid_map); + if (translate_id(&gid, sshfs.gid_map) == -1) + return -EPERM; memset(stbuf, 0, sizeof(struct stat)); stbuf->st_mode = mode; @@ -817,7 +836,7 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h, unsigned i; if (buf_get_uint32(buf, &count) == -1) - return -1; + return -EIO; for (i = 0; i < count; i++) { int err = -1; @@ -825,16 +844,16 @@ static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h, char *longname; struct stat stbuf; if (buf_get_string(buf, &name) == -1) - return -1; + return -EIO; if (buf_get_string(buf, &longname) != -1) { free(longname); - if (buf_get_attrs(buf, &stbuf, NULL) != -1) { + err = buf_get_attrs(buf, &stbuf, NULL); + if (!err) { if (sshfs.follow_symlinks && S_ISLNK(stbuf.st_mode)) { stbuf.st_mode = 0; } filler(h, name, &stbuf); - err = 0; } } free(name); @@ -1624,7 +1643,7 @@ static void sftp_detect_uid() fprintf(stderr, "failed to stat home directory (%i)\n", serr); goto out; } - if (buf_get_attrs(&buf, &stbuf, &flags) == -1) + if (buf_get_attrs(&buf, &stbuf, &flags) != 0) goto out; if (!(flags & SSH_FILEXFER_ATTR_UIDGID)) @@ -1686,8 +1705,12 @@ static int sftp_check_root(const char *base_path) goto out; } - if (buf_get_attrs(&buf, &stbuf, &flags) == -1) + + int err2 = buf_get_attrs(&buf, &stbuf, &flags); + if (err2) { + err = err2; goto out; + } if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS)) goto out; @@ -1943,8 +1966,7 @@ static int sshfs_getattr(const char *path, struct stat *stbuf) err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT, &buf, SSH_FXP_ATTRS, &outbuf); if (!err) { - if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) - err = -EIO; + err = buf_get_attrs(&outbuf, stbuf, NULL); buf_free(&outbuf); } buf_free(&buf); @@ -2066,8 +2088,7 @@ static int sshfs_getdir(const char *path, fuse_cache_dirh_t h, struct buffer name; err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name); if (!err) { - if (buf_get_entries(&name, h, filler) == -1) - err = -EIO; + err = buf_get_entries(&name, h, filler); buf_free(&name); } } while (!err); @@ -2274,10 +2295,12 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) if (sshfs.remote_uid_detected && uid == sshfs.local_uid) uid = sshfs.remote_uid; #endif /* !__APPLE__ */ - if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map) - translate_id(&uid, sshfs.r_uid_map); + if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map) + if(translate_id(&uid, sshfs.r_uid_map) == -1) + return -EPERM; if (sshfs.idmap == IDMAP_FILE && sshfs.r_gid_map) - translate_id(&gid, sshfs.r_gid_map); + if (translate_id(&gid, sshfs.r_gid_map) == -1) + return -EPERM; buf_init(&buf, 0); buf_add_path(&buf, path); @@ -2402,8 +2425,7 @@ static int sshfs_open_common(const char *path, mode_t mode, type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT; err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf); if (!err2) { - if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1) - err2 = -EIO; + err2 = buf_get_attrs(&outbuf, &stbuf, NULL); buf_free(&outbuf); } err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE, @@ -3043,8 +3065,7 @@ static int sshfs_fgetattr(const char *path, struct stat *stbuf, buf_add_buf(&buf, &sf->handle); err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf); if (!err) { - if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) - err = -EIO; + err = buf_get_attrs(&outbuf, stbuf, NULL); buf_free(&outbuf); } buf_free(&buf); @@ -3264,6 +3285,9 @@ static void usage(const char *progname) " 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" +" -o nomap=TYPE with idmap=file, how to handle missing mappings\n" +" ignore don't do any re-mapping\n" +" error return an error (default)\n" " -o ssh_command=CMD execute CMD instead of 'ssh'\n" " -o ssh_protocol=N ssh protocol to use (default: 2)\n" " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n" @@ -3587,7 +3611,7 @@ static int ssh_connect(void) return -1; if (!sshfs.no_check_root && - sftp_check_root(sshfs.base_path) == -1) + sftp_check_root(sshfs.base_path) != 0) return -1; } @@ -3802,6 +3826,7 @@ int main(int argc, char *argv[]) #else sshfs.idmap = IDMAP_NONE; #endif + sshfs.nomap = NOMAP_ERROR; ssh_add_arg("ssh"); ssh_add_arg("-x"); ssh_add_arg("-a"); -- cgit v1.2.3 From 6a954f429c04282b0d09cb0afb1f9b9bf5aaf878 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 20 Dec 2011 10:27:52 -0500 Subject: fix typo in error message --- sshfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshfs.c b/sshfs.c index 615e0be..5d9dc79 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3844,7 +3844,7 @@ int main(int argc, char *argv[]) sshfs.r_uid_map = NULL; sshfs.r_gid_map = NULL; if (!sshfs.uid_file && !sshfs.gid_file) { - fprintf(stderr, "need a uid_file or gid_file with idmap=file\n"); + fprintf(stderr, "need a uidfile or gidfile with idmap=file\n"); exit(1); } if (sshfs.uid_file) -- cgit v1.2.3 From ea6fa1d7c90bc263740a90359a37be45bd8a4e24 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 20 Dec 2011 10:27:53 -0500 Subject: increase portability getline() isn't widely available yet, use fgets() instead --- sshfs.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/sshfs.c b/sshfs.c index 5d9dc79..08e9307 100644 --- a/sshfs.c +++ b/sshfs.c @@ -42,6 +42,7 @@ #include #include #include +#include #if __APPLE__ # include # include @@ -3618,23 +3619,23 @@ static int ssh_connect(void) return 0; } -/* remove trailing '\n', like the perl func of the same name */ -static inline void chomp(char *line) -{ - char *p = line; - if ((p = strrchr(line, '\n'))) - *p = '\0'; -} - /* number of ':' separated fields in a passwd/group file that we care * about */ #define IDMAP_FIELDS 3 /* given a line from a uidmap or gidmap, parse out the name and id */ static void parse_idmap_line(char *line, const char* filename, - const unsigned int lineno, uint32_t *ret_id, char **ret_name) + const unsigned int lineno, uint32_t *ret_id, char **ret_name, + const int eof) { - chomp(line); + /* chomp off the trailing newline */ + char *p = line; + if ((p = strrchr(line, '\n'))) + *p = '\0'; + else if (!eof) { + fprintf(stderr, "%s:%u: line too long\n", filename, lineno); + exit(1); + } char *tokens[IDMAP_FIELDS]; char *tok; int i; @@ -3652,8 +3653,7 @@ static void parse_idmap_line(char *line, const char* filename, name_tok = tokens[0]; id_tok = tokens[2]; } else { - fprintf(stderr, "Unknown format at line %u of '%s'\n", - lineno, filename); + fprintf(stderr, "%s:%u: unknown format\n", filename, lineno); exit(1); } @@ -3676,8 +3676,7 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), *idmap = g_hash_table_new(NULL, NULL); *r_idmap = g_hash_table_new(NULL, NULL); FILE *fp; - char *line = NULL; - size_t len = 0; + char line[LINE_MAX]; unsigned int lineno = 0; fp = fopen(file, "r"); @@ -3687,12 +3686,12 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), exit(1); } - while (getline(&line, &len, fp) != EOF) { + while (fgets(line, LINE_MAX, fp) != NULL) { lineno++; uint32_t remote_id; char *name; - parse_idmap_line(line, file, lineno, &remote_id, &name); + parse_idmap_line(line, file, lineno, &remote_id, &name, feof(fp)); uint32_t *local_id = map_fn(name); if (local_id == NULL) { @@ -3715,9 +3714,6 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), file, strerror(errno)); exit(1); } - - if (line) - free(line); } /* given a username, return a pointer to its uid, or NULL if it doesn't -- cgit v1.2.3 From 1ac41d2ae2fb4b9c2d02855a7bf814fbe03d76a7 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Tue, 20 Dec 2011 10:27:55 -0500 Subject: skip blank lines --- sshfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sshfs.c b/sshfs.c index 08e9307..a4cc1a7 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3691,6 +3691,10 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), uint32_t remote_id; char *name; + /* skip blank lines */ + if (line[0] == '\n' || line[0] == '\0') + continue; + parse_idmap_line(line, file, lineno, &remote_id, &name, feof(fp)); uint32_t *local_id = map_fn(name); -- cgit v1.2.3 From 0120e6b4612a2eb114a3363bb3c2e654feb6dbe8 Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Tue, 7 Feb 2012 10:42:10 -0500 Subject: Remove some trailing whitespace. Verified with `cat -vet` and `grep '\s$'` --- sshfs.1 | 6 +++--- sshfs.c | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sshfs.1 b/sshfs.1 index 27dd8bc..0768d59 100644 --- a/sshfs.1 +++ b/sshfs.1 @@ -173,7 +173,7 @@ allow access to root \fB\-o\fR nonempty allow mounts over non\-empty file/dir .HP -\fB\-o\fR default_permissions +\fB\-o\fR default_permissions enable permission checking by kernel .TP \fB\-o\fR fsname=NAME @@ -248,7 +248,7 @@ perform reads asynchronously (default) \fB\-o\fR sync_read perform reads synchronously .SS "Module options:" -.TP +.TP [subdir] .TP \fB\-o\fR subdir=DIR @@ -256,7 +256,7 @@ prepend this directory to all paths (mandatory) .TP \fB\-o\fR [no]rellinksa transform absolute symlinks to relative -.TP +.TP [iconv] .TP \fB\-o\fR from_code=CHARSET diff --git a/sshfs.c b/sshfs.c index a4cc1a7..284283b 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2625,7 +2625,7 @@ static struct read_chunk *sshfs_send_read(struct sshfs_file *sf, size_t size, buf_add_uint64(&buf, offset); buf_add_uint32(&buf, bsize); buf_to_iov(&buf, &iov[0]); - err = sftp_request_send(SSH_FXP_READ, iov, 1, + err = sftp_request_send(SSH_FXP_READ, iov, 1, sshfs_read_begin, sshfs_read_end, 0, rreq, NULL); @@ -2714,7 +2714,7 @@ static void submit_read(struct sshfs_file *sf, size_t size, off_t offset, struct read_chunk *chunk; chunk = sshfs_send_read(sf, size, offset); - pthread_mutex_lock(&sshfs.lock); + pthread_mutex_lock(&sshfs.lock); chunk->modifver = sshfs.modifver; chunk_put(*chunkp); *chunkp = chunk; @@ -3515,7 +3515,7 @@ static void set_ssh_command(void) replace_arg(&sshfs.ssh_args.argv[0], sshfs.ssh_command); } else { - if (fuse_opt_insert_arg(&sshfs.ssh_args, i, + if (fuse_opt_insert_arg(&sshfs.ssh_args, i, sshfs.ssh_command) == -1) _exit(1); } @@ -3940,7 +3940,7 @@ int main(int argc, char *argv[]) int foreground; struct stat st; - res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded, + res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded, &foreground); if (res == -1) exit(1); -- cgit v1.2.3 From c1284b4089ced2df04752e144817a4d5182434a9 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Wed, 8 Feb 2012 10:21:33 +0100 Subject: fix unused but set variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cache.c: In function ‘cache_add_attr’: cache.c:167:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable] cache.c: In function ‘cache_add_dir’: cache.c:188:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable] cache.c: In function ‘cache_add_link’: cache.c:212:9: warning: variable ‘now’ set but not used [-Wunused-but-set-variable] --- cache.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/cache.c b/cache.c index 7e146e7..a2e5939 100644 --- a/cache.c +++ b/cache.c @@ -164,7 +164,6 @@ static struct node *cache_get(const char *path) void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr) { struct node *node; - time_t now; if (!cache.on) return; @@ -172,7 +171,6 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr) pthread_mutex_lock(&cache.lock); if (wrctr == cache.write_ctr) { node = cache_get(path); - now = time(NULL); node->stat = *stbuf; node->stat_valid = time(NULL) + cache.stat_timeout; if (node->stat_valid > node->valid) @@ -185,11 +183,9 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr) 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; @@ -209,11 +205,9 @@ static size_t my_strnlen(const char *s, size_t maxsize) 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; -- cgit v1.2.3 From ff32332e8331e8d7cfb08fec90b087437731a4c5 Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Tue, 7 Feb 2012 15:01:50 -0500 Subject: Split fd into separate read and write pipes --- sshfs.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/sshfs.c b/sshfs.c index 284283b..a441a58 100644 --- a/sshfs.c +++ b/sshfs.c @@ -251,7 +251,8 @@ struct sshfs { pthread_mutex_t lock_write; int processing_thread_started; unsigned int randseed; - int fd; + int rfd; + int wfd; int ptyfd; int ptyslavefd; int connver; @@ -963,7 +964,7 @@ static int pty_expect_loop(void) while (1) { struct pollfd fds[2]; - fds[0].fd = sshfs.fd; + fds[0].fd = sshfs.rfd; fds[0].events = POLLIN; fds[1].fd = sshfs.ptyfd; fds[1].events = POLLIN; @@ -1071,7 +1072,8 @@ static int start_ssh(void) perror("failed to create socket pair"); return -1; } - sshfs.fd = sockpair[0]; + sshfs.rfd = sockpair[0]; + sshfs.wfd = sockpair[0]; pid = fork(); if (pid == -1) { @@ -1196,7 +1198,8 @@ static int connect_to(char *host, char *port) freeaddrinfo(ai); - sshfs.fd = sock; + sshfs.rfd = sock; + sshfs.wfd = sock; return 0; } @@ -1204,7 +1207,7 @@ static int do_write(struct iovec *iov, size_t count) { int res; while (count) { - res = writev(sshfs.fd, iov, count); + res = writev(sshfs.wfd, iov, count); if (res == -1) { perror("write"); return -1; @@ -1281,7 +1284,7 @@ static int do_read(struct buffer *buf) uint8_t *p = buf->p; size_t size = buf->size; while (size) { - res = read(sshfs.fd, p, size); + res = read(sshfs.rfd, p, size); if (res == -1) { perror("read"); return -1; @@ -1442,8 +1445,11 @@ static int process_one_request(void) static void close_conn(void) { - close(sshfs.fd); - sshfs.fd = -1; + close(sshfs.rfd); + if (sshfs.rfd != sshfs.wfd) + close(sshfs.wfd); + sshfs.rfd = -1; + sshfs.wfd = -1; if (sshfs.ptyfd != -1) { close(sshfs.ptyfd); sshfs.ptyfd = -1; @@ -1763,7 +1769,7 @@ static int start_processing_thread(void) if (sshfs.processing_thread_started) return 0; - if (sshfs.fd == -1) { + if (sshfs.rfd == -1) { err = connect_remote(); if (err) return -EIO; @@ -3816,7 +3822,8 @@ int main(int argc, char *argv[]) sshfs.buflimit_workaround = 1; sshfs.ssh_ver = 2; sshfs.progname = argv[0]; - sshfs.fd = -1; + sshfs.rfd = -1; + sshfs.wfd = -1; sshfs.ptyfd = -1; sshfs.ptyslavefd = -1; sshfs.delay_connect = 0; -- cgit v1.2.3 From 0d34c7b742fe8f9a7de81afd3f4c906da38b26a3 Mon Sep 17 00:00:00 2001 From: Chris Wolfe Date: Wed, 8 Feb 2012 10:11:10 -0500 Subject: Add slave option to run sftp over stdin and stdout Add -o slave. This option routes the sftp communication over stdin and stdout, bypassing SSH and network. --- ChangeLog | 5 +++++ sshfs.1 | 2 ++ sshfs.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2fa431e..acd1001 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-02-08 Chris Wolfe + + * Add -o slave. This option routes the sftp communication over stdin + and stdout, bypassing SSH and network. + 2011-12-16 Mike Kelly * Add -o idmap=file, -o uidmap=FILE, -o gidmap=FILE. These options diff --git a/sshfs.1 b/sshfs.1 index 0768d59..d316930 100644 --- a/sshfs.1 +++ b/sshfs.1 @@ -138,6 +138,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 transform_symlinks transform absolute symlinks to relative diff --git a/sshfs.c b/sshfs.c index a441a58..8119d68 100644 --- a/sshfs.c +++ b/sshfs.c @@ -244,6 +244,7 @@ struct sshfs { int foreground; int reconnect; int delay_connect; + int slave; char *host; char *base_path; GHashTable *reqtab; @@ -386,6 +387,7 @@ static struct fuse_opt sshfs_opts[] = { SSHFS_OPT("no_check_root", no_check_root, 1), SSHFS_OPT("password_stdin", password_stdin, 1), SSHFS_OPT("delay_connect", delay_connect, 1), + SSHFS_OPT("slave", slave, 1), FUSE_OPT_KEY("-p ", KEY_PORT), FUSE_OPT_KEY("-C", KEY_COMPRESS), @@ -1164,6 +1166,13 @@ static int start_ssh(void) return 0; } +static int connect_slave() +{ + sshfs.rfd = STDIN_FILENO; + sshfs.wfd = STDOUT_FILENO; + return 0; +} + static int connect_to(char *host, char *port) { int err; @@ -1744,7 +1753,9 @@ static int connect_remote(void) { int err; - if (sshfs.directport) + if (sshfs.slave) + err = connect_slave(); + else if (sshfs.directport) err = connect_to(sshfs.host, sshfs.directport); else err = start_ssh(); @@ -3299,6 +3310,7 @@ static void usage(const char *progname) " -o ssh_protocol=N ssh protocol to use (default: 2)\n" " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n" " -o directport=PORT directly connect to PORT bypassing ssh\n" +" -o slave communicate over stdin and stdout bypassing network\n" " -o transform_symlinks transform absolute symlinks to relative\n" " -o follow_symlinks follow symlinks on the server\n" " -o no_check_root don't check for existence of 'dir' on server\n" @@ -3827,6 +3839,7 @@ int main(int argc, char *argv[]) sshfs.ptyfd = -1; sshfs.ptyslavefd = -1; sshfs.delay_connect = 0; + sshfs.slave = 0; sshfs.detect_uid = 0; #if __APPLE__ sshfs.idmap = IDMAP_USER; @@ -3864,6 +3877,16 @@ int main(int argc, char *argv[]) DEBUG("SSHFS version %s\n", PACKAGE_VERSION); + if (sshfs.slave) { + /* Force sshfs to the foreground when using stdin+stdout */ + sshfs.foreground = 1; + } + + if (sshfs.slave && sshfs.password_stdin) { + fprintf(stderr, "the password_stdin and slave options cannot both be specified\n"); + exit(1); + } + if (sshfs.password_stdin) { res = read_password(); if (res == -1) @@ -3952,6 +3975,11 @@ int main(int argc, char *argv[]) if (res == -1) exit(1); + if (sshfs.slave) { + /* Force sshfs to the foreground when using stdin+stdout */ + foreground = 1; + } + res = stat(mountpoint, &st); if (res == -1) { perror(mountpoint); -- cgit v1.2.3 From eb60e2d1a2c66534e6a8ed6d8609c9c89a3deaf9 Mon Sep 17 00:00:00 2001 From: Mike Kelly Date: Fri, 17 Feb 2012 11:35:15 -0500 Subject: make sure idmap files aren't writable by others otherwise, other local users could change the mapping, and gain access to things they shouldn't --- ChangeLog | 6 ++++++ sshfs.c | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/ChangeLog b/ChangeLog index acd1001..19cf11f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-03-08 Miklos Szeredi + + * Make sure idmap files aren't writable by others otherwise, other + local users could change the mapping, and gain access to things + they shouldn't. Patch by Mike Kelly + 2012-02-08 Chris Wolfe * Add -o slave. This option routes the sftp communication over stdin diff --git a/sshfs.c b/sshfs.c index 8119d68..408123c 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3696,6 +3696,7 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), FILE *fp; char line[LINE_MAX]; unsigned int lineno = 0; + uid_t local_uid = getuid(); fp = fopen(file, "r"); if (fp == NULL) { @@ -3703,6 +3704,21 @@ static void read_id_map(char *file, uint32_t *(*map_fn)(char *), file, strerror(errno)); exit(1); } + struct stat st; + if (fstat(fileno(fp), &st) == -1) { + fprintf(stderr, "failed to stat '%s': %s\n", file, + strerror(errno)); + exit(1); + } + if (st.st_uid != local_uid) { + fprintf(stderr, "'%s' is not owned by uid %lu\n", file, + (unsigned long)local_uid); + exit(1); + } + if (st.st_mode & S_IWGRP || st.st_mode & S_IWOTH) { + fprintf(stderr, "'%s' is writable by other users\n", file); + exit(1); + } while (fgets(line, LINE_MAX, fp) != NULL) { lineno++; -- cgit v1.2.3 From f64407d8657ca3cd7adcce44ecacd75fd55141ee Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 8 Mar 2012 10:36:10 +0100 Subject: Released 2.4 --- ChangeLog | 4 ++++ configure.ac | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 19cf11f..618a427 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2012-03-08 Miklos Szeredi + + * Released 2.4 + 2012-03-08 Miklos Szeredi * Make sure idmap files aren't writable by others otherwise, other diff --git a/configure.ac b/configure.ac index 1cf48b3..d433038 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(sshfs-fuse, 2.3) +AC_INIT(sshfs-fuse, 2.4) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) -- cgit v1.2.3 From b389c66b322a0642233be5fa21cdc8916860c660 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Fri, 9 Mar 2012 19:11:55 +0100 Subject: Use "#ifdef __APPLE__" instead of "#if __APPLE__" --- sshfs.c | 62 +++++++++++++++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/sshfs.c b/sshfs.c index 408123c..659645a 100644 --- a/sshfs.c +++ b/sshfs.c @@ -12,7 +12,7 @@ #include #include #include -#if __APPLE__ +#ifdef __APPLE__ # include #endif #include @@ -43,14 +43,14 @@ #include #include #include -#if __APPLE__ +#ifdef __APPLE__ # include # include #endif #include "cache.h" -#if __APPLE__ +#ifdef __APPLE__ # define OSXFUSE_SSHFS_VERSION "2.3.0" #endif @@ -134,7 +134,7 @@ #define SSHNODELAY_SO "sshnodelay.so" -#if __APPLE__ +#ifdef __APPLE__ #ifndef LIBDIR # define LIBDIR "/usr/local/lib" @@ -206,7 +206,7 @@ struct sshfs_file { int connver; int modifver; int refs; -#if __APPLE__ +#ifdef __APPLE__ pthread_mutex_t file_lock; #endif }; @@ -260,7 +260,7 @@ struct sshfs { int server_version; unsigned remote_uid; unsigned local_uid; -#if __APPLE__ +#ifdef __APPLE__ unsigned remote_gid; unsigned local_gid; #endif @@ -757,7 +757,7 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) } } -#if __APPLE__ +#ifdef __APPLE__ if (sshfs.remote_uid_detected) { if (uid == sshfs.remote_uid) uid = sshfs.local_uid; @@ -767,7 +767,7 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) #else /* !__APPLE__ */ if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) uid = sshfs.local_uid; -#endif /* !__APPLE__ */ +#endif /* __APPLE__ */ if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map) if (translate_id(&uid, sshfs.uid_map) == -1) return -EPERM; @@ -876,7 +876,7 @@ static void ssh_add_arg(const char *arg) #ifdef SSH_NODELAY_WORKAROUND static int do_ssh_nodelay_workaround(void) { -#if __APPLE__ +#ifdef __APPLE__ char *oldpreload = getenv("DYLD_INSERT_LIBRARIES"); #else char *oldpreload = getenv("LD_PRELOAD"); @@ -885,7 +885,7 @@ static int do_ssh_nodelay_workaround(void) char sopath[PATH_MAX]; int res; -#if __APPLE__ +#ifdef __APPLE__ char *sshfs_program_path_base = NULL; if (!sshfs_program_path[0]) { goto nobundle; @@ -930,7 +930,7 @@ nobundle: } } -#if __APPLE__ +#ifdef __APPLE__ pathok: #endif @@ -939,7 +939,7 @@ pathok: oldpreload ? " " : "", sopath); -#if __APPLE__ +#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__ */ @@ -947,7 +947,7 @@ pathok: fprintf(stderr, "warning: failed set LD_PRELOAD " "for ssh nodelay workaround\n"); } -#endif /* !__APPLE__ */ +#endif /* __APPLE__ */ g_free(newpreload); return 0; } @@ -1667,7 +1667,7 @@ static void sftp_detect_uid() sshfs.remote_uid = stbuf.st_uid; sshfs.local_uid = getuid(); -#if __APPLE__ +#ifdef __APPLE__ sshfs.remote_gid = stbuf.st_gid; sshfs.local_gid = getgid(); #endif @@ -2302,7 +2302,7 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) int err; struct buffer buf; -#if __APPLE__ +#ifdef __APPLE__ if (sshfs.remote_uid_detected) { if (uid == sshfs.local_uid) uid = sshfs.remote_uid; @@ -2312,7 +2312,7 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid) #else /* !__APPLE__ */ if (sshfs.remote_uid_detected && uid == sshfs.local_uid) uid = sshfs.remote_uid; -#endif /* !__APPLE__ */ +#endif /* __APPLE__ */ if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map) if(translate_id(&uid, sshfs.r_uid_map) == -1) return -EPERM; @@ -2419,7 +2419,7 @@ static int sshfs_open_common(const char *path, mode_t mode, sf = g_new0(struct sshfs_file, 1); list_init(&sf->write_reqs); pthread_cond_init(&sf->write_finished, NULL); -#if __APPLE__ +#ifdef __APPLE__ pthread_mutex_init(&sf->file_lock, NULL); #endif /* Assume random read after open */ @@ -2456,7 +2456,7 @@ static int sshfs_open_common(const char *path, mode_t mode, } if (!err) { -#if __APPLE__ +#ifdef __APPLE__ if (cache_enabled) cache_add_attr(path, &stbuf, wrctr); #else @@ -2465,7 +2465,7 @@ static int sshfs_open_common(const char *path, mode_t mode, buf_finish(&sf->handle); fi->fh = (unsigned long) sf; } else { -#if __APPLE__ +#ifdef __APPLE__ if (cache_enabled) cache_invalidate(path); #else @@ -2525,11 +2525,11 @@ static int sshfs_fsync(const char *path, int isdatasync, static void sshfs_file_put(struct sshfs_file *sf) { -#if __APPLE__ +#ifdef __APPLE__ pthread_mutex_lock(&sf->file_lock); #endif sf->refs--; -#if __APPLE__ +#ifdef __APPLE__ if (!sf->refs) { pthread_mutex_unlock(&sf->file_lock); g_free(sf); @@ -2539,16 +2539,16 @@ static void sshfs_file_put(struct sshfs_file *sf) #else /* !__APPLE__ */ if (!sf->refs) g_free(sf); -#endif /* !__APPLE__ */ +#endif /* __APPLE__ */ } static void sshfs_file_get(struct sshfs_file *sf) { -#if __APPLE__ +#ifdef __APPLE__ pthread_mutex_lock(&sf->file_lock); #endif sf->refs++; -#if __APPLE__ +#ifdef __APPLE__ pthread_mutex_unlock(&sf->file_lock); #endif } @@ -3293,7 +3293,7 @@ static void usage(const char *progname) " [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" -#if __APPLE__ +#ifdef __APPLE__ " none no translation of the ID space\n" " user only translate UID/GID of connecting user (default)\n" #else @@ -3389,7 +3389,7 @@ static int sshfs_opt_proc(void *data, const char *arg, int key, exit(1); case KEY_VERSION: -#if __APPLE__ +#ifdef __APPLE__ printf("SSHFS version %s (OSXFUSE SSHFS %s)\n", PACKAGE_VERSION, OSXFUSE_SSHFS_VERSION); #else @@ -3478,7 +3478,7 @@ static int read_password(void) perror("Failed to allocate locked page for password"); return -1; } -#if __APPLE__ +#ifdef __APPLE__ if (mlock(sshfs.password, size) != 0) { memset(sshfs.password, 0, size); munmap(sshfs.password, size); @@ -3812,7 +3812,7 @@ static inline void load_gid_map(void) read_id_map(sshfs.gid_file, &groupname_to_gid, "gid", &sshfs.gid_map, &sshfs.r_gid_map); } -#if __APPLE__ +#ifdef __APPLE__ int main(int argc, char *argv[], __unused char *envp[], char **exec_path) #else int main(int argc, char *argv[]) @@ -3825,7 +3825,7 @@ int main(int argc, char *argv[]) const char *sftp_server; int libver; -#if __APPLE__ +#ifdef __APPLE__ if (!realpath(*exec_path, sshfs_program_path)) { memset(sshfs_program_path, 0, PATH_MAX); } @@ -3841,7 +3841,7 @@ int main(int argc, char *argv[]) sshfs.max_write = 32768; sshfs.nodelay_workaround = 1; sshfs.nodelaysrv_workaround = 0; -#if __APPLE__ +#ifdef __APPLE__ sshfs.rename_workaround = 1; #else sshfs.rename_workaround = 0; @@ -3857,7 +3857,7 @@ int main(int argc, char *argv[]) sshfs.delay_connect = 0; sshfs.slave = 0; sshfs.detect_uid = 0; -#if __APPLE__ +#ifdef __APPLE__ sshfs.idmap = IDMAP_USER; #else sshfs.idmap = IDMAP_NONE; -- cgit v1.2.3 From 3c44e22dddd84f879026829ca37894d861325b77 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Fri, 9 Mar 2012 19:14:13 +0100 Subject: Bump version to OSXFUSE SSHFS 2.4.0 --- sshfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshfs.c b/sshfs.c index 659645a..6740b82 100644 --- a/sshfs.c +++ b/sshfs.c @@ -51,7 +51,7 @@ #include "cache.h" #ifdef __APPLE__ -# define OSXFUSE_SSHFS_VERSION "2.3.0" +# define OSXFUSE_SSHFS_VERSION "2.4.0" #endif #ifndef MAP_LOCKED -- cgit v1.2.3 From f4631f0a170b26b4a8364aa8706475f304f5f824 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Sun, 11 Mar 2012 16:11:08 +0100 Subject: Add Darwin/OS X specific information to man page * Volumes are unmounted using "umount" not "fusermount" * idmap=user is the deafault setting on Darwin/OS X --- .gitignore | 1 + Makefile.am | 5 +- sshfs.1 | 277 --------------------------------------------------------- sshfs.1.in | 289 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 294 insertions(+), 278 deletions(-) delete mode 100644 sshfs.1 create mode 100644 sshfs.1.in 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/Makefile.am b/Makefile.am index a80788b..b43956c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,10 +12,13 @@ sshfs_CFLAGS = $(SSHFS_CFLAGS) sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" EXTRA_DIST = sshnodelay.c FAQ.txt -CLEANFILES = sshnodelay.so +CLEANFILES = sshnodelay.so sshfs.1 dist_man_MANS = sshfs.1 +sshfs.1: + $(CPP) $(CPPFLAGS) -P -xassembler-with-cpp sshfs.1.in | sed -e '/^$$/d' > sshfs.1 + if SSH_NODELAY_SO all-local: sshnodelay.so diff --git a/sshfs.1 b/sshfs.1 deleted file mode 100644 index d316930..0000000 --- a/sshfs.1 +++ /dev/null @@ -1,277 +0,0 @@ -.TH SSHFS "1" "April 2008" "SSHFS version 2.0" "User Commands" -.SH NAME -SSHFS \- filesystem client based on ssh -.SH SYNOPSIS -.SS mounting -.TP -\fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP [\fIoptions\fP] -.SS unmounting -.TP -\fBfusermount -u 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) -capable of operating on files on a remote computer using just a secure -shell login on the remote computer. On the local computer where the SSHFS -is mounted, the implementation makes use of the FUSE (Filesystem in -Userspace) kernel module. The practical effect of this is that the end user -can seamlessly interact with remote files being securely served over SSH -just as if they were local files on his/her computer. On the remote -computer the SFTP subsystem of SSH is used. -.PP -If \fIhost\fP is a numeric IPv6 address, it needs to be enclosed in -square brackets. -.SH 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\-F\fR ssh_configfile -specifies alternative ssh configuration file -.TP -\fB\-1\fR -equivalent to '\-o ssh_protocol=1' -.TP -\fB\-o\fR reconnect -reconnect to server -.TP -\fB\-o\fR delay_connect -delay connection 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=BOOL -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 -.RS 8 -.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) -.RE -.TP -\fB\-o\fR idmap=TYPE -user/group ID mapping, possible types are: -.RS 8 -.TP -none -no translation of the ID space (default) -.TP -user -only translate UID of connecting user -.TP -file -translate UIDs/GIDs based upon the contents of \fBuidfile \fR and -\fBgidfile\fR -.RE -.TP -\fB\-o\fR uidfile=FILE -file containing username:uid mappings for \fBidmap=file\fR -.RE -.TP -\fB\-o\fR gidfile=FILE -file containing groupname:gid mappings for \fBidmap=file\fR -.RE -.TP -\fB\-o\fR nomap=TYPE -with idmap=file, how to handle missing mappings -.RS 8 -.TP -ignore -don't do any re-mapping -.TP -error -return an error (default) -.RE -.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 -\fB\-o\fR slave -communicate over stdin and stdout bypassing network -.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) -.PD -.SH "AUTHORS" -.LP -SSHFS has been written by Miklos Szeredi . -.LP -This man page was written by Bartosz Fenski for the -Debian GNU/Linux distribution (but it may be used by others). - - diff --git a/sshfs.1.in b/sshfs.1.in new file mode 100644 index 0000000..aef99fd --- /dev/null +++ b/sshfs.1.in @@ -0,0 +1,289 @@ +.TH SSHFS "1" "April 2008" "SSHFS version 2.0" "User Commands" +.SH NAME +SSHFS \- filesystem client based on ssh +.SH SYNOPSIS +.SS mounting +.TP +\fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP [\fIoptions\fP] +.SS unmounting +.TP +#ifdef __APPLE__ +\fBumount mountpoint\fP +#else +\fBfusermount -u mountpoint\fP +#endif +.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) +capable of operating on files on a remote computer using just a secure +shell login on the remote computer. On the local computer where the SSHFS +is mounted, the implementation makes use of the FUSE (Filesystem in +Userspace) kernel module. The practical effect of this is that the end user +can seamlessly interact with remote files being securely served over SSH +just as if they were local files on his/her computer. On the remote +computer the SFTP subsystem of SSH is used. +.PP +If \fIhost\fP is a numeric IPv6 address, it needs to be enclosed in +square brackets. +.SH 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\-F\fR ssh_configfile +specifies alternative ssh configuration file +.TP +\fB\-1\fR +equivalent to '\-o ssh_protocol=1' +.TP +\fB\-o\fR reconnect +reconnect to server +.TP +\fB\-o\fR delay_connect +delay connection 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=BOOL +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 +.RS 8 +.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) +.RE +.TP +\fB\-o\fR idmap=TYPE +user/group ID mapping, possible types are: +.RS 8 +.TP +none +#ifdef __APPLE__ +no translation of the ID space +#else +no translation of the ID space (default) +#endif +.TP +user +#ifdef __APPLE__ +only translate UID/GID of connecting user (default) +#else +only translate UID of connecting user +#endif +.TP +file +translate UIDs/GIDs based upon the contents of \fBuidfile \fR and +\fBgidfile\fR +.RE +.TP +\fB\-o\fR uidfile=FILE +file containing username:uid mappings for \fBidmap=file\fR +.RE +.TP +\fB\-o\fR gidfile=FILE +file containing groupname:gid mappings for \fBidmap=file\fR +.RE +.TP +\fB\-o\fR nomap=TYPE +with idmap=file, how to handle missing mappings +.RS 8 +.TP +ignore +don't do any re-mapping +.TP +error +return an error (default) +.RE +.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 +\fB\-o\fR slave +communicate over stdin and stdout bypassing network +.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) +.PD +.SH "AUTHORS" +.LP +SSHFS has been written by Miklos Szeredi . +.LP +This man page was written by Bartosz Fenski for the +Debian GNU/Linux distribution (but it may be used by others). + + -- cgit v1.2.3 From 66458931ddd09fc15244c5ddf3c1ec73e2fd08b9 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Sun, 11 Mar 2012 17:31:02 +0100 Subject: Bump version to OSXFUSE SSHFS 2.4.1 The only difference between version 2.4.0 and 2.4.1 is the updated man page to reflect Darwin/OS X specific changes to upstream SSHFS. --- sshfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshfs.c b/sshfs.c index 6740b82..bf65aea 100644 --- a/sshfs.c +++ b/sshfs.c @@ -51,7 +51,7 @@ #include "cache.h" #ifdef __APPLE__ -# define OSXFUSE_SSHFS_VERSION "2.4.0" +# define OSXFUSE_SSHFS_VERSION "2.4.1" #endif #ifndef MAP_LOCKED -- cgit v1.2.3 From 14581937282486ab7ce057ec79f226181ef1d45d Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Tue, 8 Jan 2013 14:53:09 +0100 Subject: Add unnamed semaphore implementation for Mac OS X In the past we relied on libosxfuse including a working unnamed semaphore implmentation for Mac OS X. This will not be the case in future releases of OSXFUSE, therefore we need to add our own implementation. --- Makefile.am | 3 + compat/darwin_compat.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++++ compat/darwin_compat.h | 51 ++++++++++ configure.ac | 12 ++- sshfs.c | 3 +- 5 files changed, 313 insertions(+), 2 deletions(-) create mode 100644 compat/darwin_compat.c create mode 100644 compat/darwin_compat.h diff --git a/Makefile.am b/Makefile.am index b43956c..078b2b7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,6 +6,9 @@ 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) diff --git a/compat/darwin_compat.c b/compat/darwin_compat.c new file mode 100644 index 0000000..3883ec6 --- /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-2012 Benjamin Fleischer + */ + +#include "darwin_compat.h" + +#include +#include +#include + +/* + * Semaphore implementation based on: + * + * Copyright (C) 2000,02 Free Software Foundation, Inc. + * This file is part of the GNU C Library. + * Written by Gal Le Mignot + * + * 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..1cdbcce --- /dev/null +++ b/compat/darwin_compat.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2008 Amit Singh/Google Inc. + * Copyright (c) 2011-2012 Benjamin Fleischer + */ + +#ifndef _DARWIN_COMPAT_ +#define _DARWIN_COMPAT_ + +#include + +/* Semaphores */ + +struct __local_sem_t +{ + unsigned int count; + pthread_mutex_t count_lock; + pthread_cond_t count_cond; +}; + +typedef struct fuse_sem { + int id; + union { + struct __local_sem_t 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 */ + +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 d433038..b2556f2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,5 @@ AC_INIT(sshfs-fuse, 2.4) +AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) @@ -11,6 +12,14 @@ sshnodelay_libs=$LIBS AC_SUBST(sshnodelay_libs) LIBS= +case $target_os in + *linux*) arch=linux;; + *netbsd*) arch=netbsd;; + *bsd*) arch=bsd;; + *darwin*) arch=darwin;; + *) arch=unknown;; +esac + AC_ARG_ENABLE(sshnodelay, [ --disable-sshnodelay Don't compile NODELAY workaround for ssh]) @@ -43,10 +52,11 @@ 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 +if test "$have_fuse_opt_parse" = no -o "$arch" = darwin; then CFLAGS="$CFLAGS -Icompat" fi AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no) +AM_CONDITIONAL(DARWIN_COMPAT, test "$arch" = darwin) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/sshfs.c b/sshfs.c index bf65aea..5658412 100644 --- a/sshfs.c +++ b/sshfs.c @@ -23,7 +23,7 @@ #include #include #include -#if !__APPLE__ +#ifndef __APPLE__ # include #endif #include @@ -46,6 +46,7 @@ #ifdef __APPLE__ # include # include +# include #endif #include "cache.h" -- cgit v1.2.3 From d04fd55128d96a3f3de039c9df162211f482a0aa Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Tue, 8 Jan 2013 15:44:18 +0100 Subject: Update copyright year in darwin_compat --- compat/darwin_compat.c | 2 +- compat/darwin_compat.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compat/darwin_compat.c b/compat/darwin_compat.c index 3883ec6..9b23be2 100644 --- a/compat/darwin_compat.c +++ b/compat/darwin_compat.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2006-2008 Amit Singh/Google Inc. * Copyright (c) 2012 Anatol Pomozov - * Copyright (c) 2011-2012 Benjamin Fleischer + * Copyright (c) 2011-2013 Benjamin Fleischer */ #include "darwin_compat.h" diff --git a/compat/darwin_compat.h b/compat/darwin_compat.h index 1cdbcce..1c6ec78 100644 --- a/compat/darwin_compat.h +++ b/compat/darwin_compat.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2006-2008 Amit Singh/Google Inc. - * Copyright (c) 2011-2012 Benjamin Fleischer + * Copyright (c) 2011-2013 Benjamin Fleischer */ #ifndef _DARWIN_COMPAT_ -- cgit v1.2.3 From 1fc97d3f2c02377c1f326ac1a4fc79449d6d3f00 Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Mon, 3 Feb 2014 09:01:07 +0100 Subject: Add AC_CANONICAL_TARGET to configure.ac --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index b64b8d1..7f3008d 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,5 @@ AC_INIT(sshfs-fuse, 2.5) +AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) -- cgit v1.2.3 From c3d83ee24b60564e90440e4b38d58a0a5df8b8ef Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Mon, 3 Feb 2014 09:01:26 +0100 Subject: Fix redefinition of struct __local_sem_t --- compat/darwin_compat.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compat/darwin_compat.h b/compat/darwin_compat.h index 1c6ec78..0a16471 100644 --- a/compat/darwin_compat.h +++ b/compat/darwin_compat.h @@ -10,17 +10,15 @@ /* Semaphores */ -struct __local_sem_t -{ - unsigned int count; - pthread_mutex_t count_lock; - pthread_cond_t count_cond; -}; - -typedef struct fuse_sem { +typedef struct darwin_sem { int id; union { - struct __local_sem_t local; + struct + { + unsigned int count; + pthread_mutex_t count_lock; + pthread_cond_t count_cond; + } local; } __data; } darwin_sem_t; -- cgit v1.2.3 From f2b17c299bedcc729bff8fe9c4a93a6d97f478bd Mon Sep 17 00:00:00 2001 From: Benjamin Fleischer Date: Mon, 3 Feb 2014 09:01:38 +0100 Subject: Bump version to 2.5.0 --- sshfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sshfs.c b/sshfs.c index d43ebc5..b09484c 100644 --- a/sshfs.c +++ b/sshfs.c @@ -52,7 +52,7 @@ #include "cache.h" #ifdef __APPLE__ -# define OSXFUSE_SSHFS_VERSION "2.4.1" +# define OSXFUSE_SSHFS_VERSION "2.5.0" #endif #ifndef MAP_LOCKED -- cgit v1.2.3 From 9bcb98945405db3d64cd8dca409aa18990ff1929 Mon Sep 17 00:00:00 2001 From: Qais Patankar Date: Mon, 16 Jun 2014 22:02:48 +0100 Subject: Fix english --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 1fdad40..c11f21b 100644 --- a/README +++ b/README @@ -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 -- cgit v1.2.3 From 3bf3be3bcd0855f1fb90e9df23eeaf597e98f34a Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:34:04 -0500 Subject: Rename arch to osname Operating system names are not architectures; therefore, rename the arch variable to osname to better represent its contents. While doing this, drop a bunch of unused values from the osname. --- configure.ac | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/configure.ac b/configure.ac index d0ee2eb..7b4a13f 100644 --- a/configure.ac +++ b/configure.ac @@ -12,12 +12,10 @@ sshnodelay_libs=$LIBS AC_SUBST(sshnodelay_libs) LIBS= -case $target_os in - *linux*) arch=linux;; - *netbsd*) arch=netbsd;; - *bsd*) arch=bsd;; - *darwin*) arch=darwin;; - *) arch=unknown;; +case "$target_os" in + *linux*) osname=linux;; + *darwin*) osname=darwin;; + *) osname=unknown;; esac AC_ARG_ENABLE(sshnodelay, @@ -52,11 +50,11 @@ 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 -o "$arch" = darwin; then +if test "$have_fuse_opt_parse" = no -o "$osname" = darwin; then CFLAGS="$CFLAGS -Icompat" fi AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no) -AM_CONDITIONAL(DARWIN_COMPAT, test "$arch" = darwin) +AM_CONDITIONAL(DARWIN_COMPAT, test "$osname" = darwin) AC_CONFIG_FILES([Makefile]) AC_OUTPUT -- cgit v1.2.3 From 19ab22abec86e2167b8169bc7123fd5d1bd496f9 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:37:02 -0500 Subject: Improve sshfs.1 manpage generation * Fix dependencies of the sshfs.1 target to actually specify sshfs.1.in as a source. * Ensure that failures during the generation of sshfs.1 do not result in a potentially bogus manpage by first outputting the contents to a temporary file unknown to the Makefile rule and then replacing the target file once all is known to be OK. * Use $(AM_V_GEN) in the command to respect automake's silent rules. --- Makefile.am | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index c5b92f0..ed3090e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,13 +14,15 @@ sshfs_LDADD = $(SSHFS_LIBS) sshfs_CFLAGS = $(SSHFS_CFLAGS) sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" -EXTRA_DIST = sshnodelay.c -CLEANFILES = sshnodelay.so sshfs.1 +EXTRA_DIST = sshnodelay.c sshfs.1.in +CLEANFILES = sshnodelay.so sshfs.1 sshfs.1.tmp dist_man_MANS = sshfs.1 -sshfs.1: - $(CPP) $(CPPFLAGS) -P -xassembler-with-cpp sshfs.1.in | sed -e '/^$$/d' > sshfs.1 +sshfs.1: sshfs.1.in + $(AM_V_GEN)$(CPP) $(CPPFLAGS) -P -xassembler-with-cpp sshfs.1.in \ + | sed -e '/^$$/d' >sshfs.1.tmp || exit 1; \ + mv sshfs.1.tmp sshfs.1 if SSH_NODELAY_SO all-local: sshnodelay.so -- cgit v1.2.3 From e0025219b33de3cbf3152884b48412feb461c894 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:40:22 -0500 Subject: Drop OSXFUSE_SSHFS_VERSION Now that we are unifying osxfuse's sshfs into libfuse's version, there should not be two different version identifiers. Drop osxfuse's one. --- sshfs.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/sshfs.c b/sshfs.c index eab48c9..6948663 100644 --- a/sshfs.c +++ b/sshfs.c @@ -51,10 +51,6 @@ #include "cache.h" -#ifdef __APPLE__ -# define OSXFUSE_SSHFS_VERSION "2.5.0" -#endif - #ifndef MAP_LOCKED #define MAP_LOCKED 0 #endif @@ -3532,12 +3528,7 @@ static int sshfs_opt_proc(void *data, const char *arg, int key, exit(1); case KEY_VERSION: -#ifdef __APPLE__ - printf("SSHFS version %s (OSXFUSE SSHFS %s)\n", - PACKAGE_VERSION, OSXFUSE_SSHFS_VERSION); -#else printf("SSHFS version %s\n", PACKAGE_VERSION); -#endif #if FUSE_VERSION >= 25 fuse_opt_add_arg(outargs, "--version"); sshfs_fuse_main(outargs); -- cgit v1.2.3 From d8230e72ca01fd27509ef7134f0957c73f164ae3 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:43:01 -0500 Subject: Drop the cache_enabled hack cache_enabled leaked the cache.on setting from the cache module abstraction back into sshfs, and it only did so for the Darwin case. This hack was being used to avoid calling cache_add_attr and cache_invalidate when the cache was disabled... but these two functions already do nothing when in that case: there is no need to do a second check in the caller. --- cache.c | 7 ------- cache.h | 4 ---- sshfs.c | 10 ---------- 3 files changed, 21 deletions(-) diff --git a/cache.c b/cache.c index ffdf71d..6e93157 100644 --- a/cache.c +++ b/cache.c @@ -554,9 +554,6 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper) cache.next_oper = oper; cache_unity_fill(oper, &cache_oper); -#if __APPLE__ - cache_enabled = cache.on; -#endif if (cache.on) { cache_fill(oper, &cache_oper); pthread_mutex_init(&cache.lock, NULL); @@ -591,7 +588,3 @@ int cache_parse_options(struct fuse_args *args) return fuse_opt_parse(args, &cache, cache_opts, NULL); } - -#if __APPLE__ -int cache_enabled; -#endif diff --git a/cache.h b/cache.h index 23ff970..cec9ca4 100644 --- a/cache.h +++ b/cache.h @@ -27,7 +27,3 @@ int cache_parse_options(struct fuse_args *args); void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr); void cache_invalidate(const char *path); uint64_t cache_get_write_ctr(void); - -#if __APPLE__ -extern int cache_enabled; -#endif diff --git a/sshfs.c b/sshfs.c index 6948663..21393f1 100644 --- a/sshfs.c +++ b/sshfs.c @@ -2591,21 +2591,11 @@ static int sshfs_open_common(const char *path, mode_t mode, } if (!err) { -#ifdef __APPLE__ - if (cache_enabled) - cache_add_attr(path, &stbuf, wrctr); -#else cache_add_attr(path, &stbuf, wrctr); -#endif buf_finish(&sf->handle); fi->fh = (unsigned long) sf; } else { -#ifdef __APPLE__ - if (cache_enabled) - cache_invalidate(path); -#else cache_invalidate(path); -#endif g_free(sf); } buf_free(&buf); -- cgit v1.2.3 From 869aa42e97e26365b83b1f779ecab209ee8f4b39 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:49:48 -0500 Subject: Remove LIBDIR explicit definition Makefile.am always sets LIBDIR in CPPFLAGS. There is no need for sshfs.c to redefine it to a bogus value when not present, and much less to only do so for the Darwin case only. --- sshfs.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sshfs.c b/sshfs.c index 21393f1..64c1d8c 100644 --- a/sshfs.c +++ b/sshfs.c @@ -138,13 +138,7 @@ #define MAX_PASSWORD 1024 #ifdef __APPLE__ - -#ifndef LIBDIR -# define LIBDIR "/usr/local/lib" -#endif - static char sshfs_program_path[PATH_MAX] = { 0 }; - #endif /* __APPLE__ */ struct buffer { -- cgit v1.2.3 From b7e8fee81be3a91e55d4d56c5f4f4f2e8ce1e8bf Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 11:57:52 -0500 Subject: Sync AUTHORS list after osxfuse-sshfs's merge --- AUTHORS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/AUTHORS b/AUTHORS index 21a9b75..9f05a8f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,8 +15,12 @@ Contributors (autogenerated list) Alan Jenkins Alexander Neumann +Benjamin Fleischer Chris Wolfe +Google Inc. +Julio Merino Mike Kelly Miklos Szeredi Nikolaus Rath Percy Jahn +Qais Patankar -- cgit v1.2.3 From 665bb97ef616e4de9c501f74db83f6ebc0ddc72a Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 12:18:48 -0500 Subject: Document merge of osxfuse's sshfs --- ChangeLog | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 ) - Release 2.6 (2014-01-14) ------------------------ -- cgit v1.2.3 From a03d3eab39b265fb9fcb5287d81061e7957f355a Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 20:48:45 -0500 Subject: Fix path to compat in -I flag When defining a -I flag to point into the source directory, we should prefix the directory with ${srcdir} so that it can be found when the build is configured to use a build directory that differs from the source directory. This fixes "make distcheck". --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7b4a13f..7fdc36a 100644 --- a/configure.ac +++ b/configure.ac @@ -51,7 +51,7 @@ LIBS="$LIBS $SSHFS_LIBS" AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes]) LIBS="$oldlibs" if test "$have_fuse_opt_parse" = no -o "$osname" = darwin; then - CFLAGS="$CFLAGS -Icompat" + CFLAGS="$CFLAGS -I${srcdir}/compat" fi AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no) AM_CONDITIONAL(DARWIN_COMPAT, test "$osname" = darwin) -- cgit v1.2.3 From 9b4ca1aadefbb75ab4051e0b0e9173709456f7fb Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 21:10:48 -0500 Subject: Avoid using cpp for sshfs.1 generation Move the logic to determine which values to stick into the manual page to the configure script and replace the logic to build the sshfs.1 manual page with sed instead of abusing cpp. I'm not using AC_OUTPUT here because this macro is typically used to generate support build files. Final artifacts of the build should, in general, be built by the Makefile itself. --- Makefile.am | 9 ++++++--- configure.ac | 11 +++++++++++ sshfs.1.in | 18 +++--------------- sshfs.c | 23 +++++++++++------------ 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/Makefile.am b/Makefile.am index ed3090e..f003bae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -12,7 +12,8 @@ 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 sshfs.1.in CLEANFILES = sshnodelay.so sshfs.1 sshfs.1.tmp @@ -20,8 +21,10 @@ CLEANFILES = sshnodelay.so sshfs.1 sshfs.1.tmp dist_man_MANS = sshfs.1 sshfs.1: sshfs.1.in - $(AM_V_GEN)$(CPP) $(CPPFLAGS) -P -xassembler-with-cpp sshfs.1.in \ - | sed -e '/^$$/d' >sshfs.1.tmp || exit 1; \ + $(AM_V_GEN)sed \ + -e 's,__IDMAP_DEFAULT__,$(IDMAP_DEFAULT),g' \ + -e 's,__UNMOUNT_COMMAND__,$(UNMOUNT_COMMAND),g' \ + sshfs.1.tmp || exit 1; \ mv sshfs.1.tmp sshfs.1 if SSH_NODELAY_SO diff --git a/configure.ac b/configure.ac index 7fdc36a..a91ec3f 100644 --- a/configure.ac +++ b/configure.ac @@ -56,5 +56,16 @@ 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.in b/sshfs.1.in index 7d431ed..fcf3e9f 100644 --- a/sshfs.1.in +++ b/sshfs.1.in @@ -7,11 +7,7 @@ SSHFS \- filesystem client based on ssh \fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP [\fIoptions\fP] .SS unmounting .TP -#ifdef __APPLE__ -\fBumount mountpoint\fP -#else -\fBfusermount -u mountpoint\fP -#endif +\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) @@ -101,22 +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 -#ifdef __APPLE__ no translation of the ID space -#else -no translation of the ID space (default) -#endif .TP user -#ifdef __APPLE__ -only translate UID/GID of connecting user (default) -#else -only translate UID of connecting user -#endif +only translate UID/GID of connecting user .TP file translate UIDs/GIDs based upon the contents of \fBuidfile \fR and diff --git a/sshfs.c b/sshfs.c index 64c1d8c..6d5e083 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3413,14 +3413,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" -#ifdef __APPLE__ +" -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 (default)\n" -#else -" none no translation of the ID space (default)\n" -" user only translate UID of connecting user\n" -#endif +" 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" @@ -3975,11 +3970,15 @@ int main(int argc, char *argv[]) sshfs.delay_connect = 0; sshfs.slave = 0; sshfs.detect_uid = 0; -#ifdef __APPLE__ - sshfs.idmap = IDMAP_USER; -#else - sshfs.idmap = IDMAP_NONE; -#endif + 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"); -- cgit v1.2.3 From 30e90ae0800a16992d4a349d1fe9c3f5e3566f56 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 21:20:21 -0500 Subject: Remove apparently-unnecessary lock Revision b4023a19dd7ec7a099d2e0df491547cf3bb6bec3, which imported the MacFUSE-specific sshfs fixes into osxfuse-sshfs, added a lock to handle the refs reference counter of the sshfs_file structure. However, this lock was only added for OS X, which is a very strange thing to do. One may think that this was only because MacFUSE 2.2 had some semantics that differed from regular FUSE, and that would have been quite stupid for compatibility reasons. A few simple tests show no issues after removing this lock, so let's keep it out for now. If things break, we know what to look at. --- sshfs.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/sshfs.c b/sshfs.c index 6d5e083..c97282e 100644 --- a/sshfs.c +++ b/sshfs.c @@ -204,9 +204,6 @@ struct sshfs_file { int connver; int modifver; int refs; -#ifdef __APPLE__ - pthread_mutex_t file_lock; -#endif }; struct sshfs { @@ -2548,9 +2545,6 @@ static int sshfs_open_common(const char *path, mode_t mode, sf = g_new0(struct sshfs_file, 1); list_init(&sf->write_reqs); pthread_cond_init(&sf->write_finished, NULL); -#ifdef __APPLE__ - pthread_mutex_init(&sf->file_lock, NULL); -#endif /* Assume random read after open */ sf->is_seq = 0; sf->refs = 1; @@ -2644,32 +2638,14 @@ static int sshfs_fsync(const char *path, int isdatasync, static void sshfs_file_put(struct sshfs_file *sf) { -#ifdef __APPLE__ - pthread_mutex_lock(&sf->file_lock); -#endif sf->refs--; -#ifdef __APPLE__ - if (!sf->refs) { - pthread_mutex_unlock(&sf->file_lock); - g_free(sf); - } else { - pthread_mutex_unlock(&sf->file_lock); - } -#else /* !__APPLE__ */ if (!sf->refs) g_free(sf); -#endif /* __APPLE__ */ } static void sshfs_file_get(struct sshfs_file *sf) { -#ifdef __APPLE__ - pthread_mutex_lock(&sf->file_lock); -#endif sf->refs++; -#ifdef __APPLE__ - pthread_mutex_unlock(&sf->file_lock); -#endif } static int sshfs_release(const char *path, struct fuse_file_info *fi) -- cgit v1.2.3 From 27e7029148aa24803af8f40ea916213a381c1967 Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 21:26:53 -0500 Subject: Unconditionally mlock the password in memory Revision b4023a19 added an mlock call to ensure the sshfs password is kept in memory, but did so only for OS X. This is a good idea in general, so let's remove the condition. --- sshfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sshfs.c b/sshfs.c index c97282e..84b2359 100644 --- a/sshfs.c +++ b/sshfs.c @@ -3567,7 +3567,6 @@ static int read_password(void) perror("Failed to allocate locked page for password"); return -1; } -#ifdef __APPLE__ if (mlock(sshfs.password, size) != 0) { memset(sshfs.password, 0, size); munmap(sshfs.password, size); @@ -3575,7 +3574,6 @@ static int read_password(void) perror("Failed to allocate locked page for password"); return -1; } -#endif /* __APPLE__ */ /* Don't use fgets() because password might stay in memory */ for (n = 0; n < max_password; n++) { -- cgit v1.2.3 From 80db43d7dce4f3979fe5e92b2d616d635f21029d Mon Sep 17 00:00:00 2001 From: Julio Merino Date: Mon, 8 Feb 2016 21:40:30 -0500 Subject: Improve the sshnodelay hack after osxfuse's merge Document the strage-looking symbol interposition that is necessary for the OS X case. While doing this, homogenize the code to do the real connect call for both the Linux and OS X cases into a helper function. This logic is generic and should not be replicated into various OS-specific cases. --- sshnodelay.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/sshnodelay.c b/sshnodelay.c index e1d9220..a9f307c 100644 --- a/sshnodelay.c +++ b/sshnodelay.c @@ -5,8 +5,32 @@ #include #include +/* 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 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 { @@ -21,26 +45,15 @@ static const interpose_t interposers[] \ int custom_connect(int sock, const struct sockaddr *addr, socklen_t addrlen) { - int res = 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; + return nodelay_connect(connect, sock, addr, addrlen); } #else /* !__APPLE__ */ 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; + return nodelay_connect(dlsym(RTLD_NEXT, "connect"), + sock, addr, addrlen); } #endif /* !__APPLE__ */ -- cgit v1.2.3