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