3 Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU GPL.
9 #define _GNU_SOURCE /* avoid implicit declaration of *pt* functions */
14 #include <fuse_lowlevel.h>
23 #include <semaphore.h>
28 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/utsname.h>
35 #include <netinet/in.h>
36 #include <netinet/tcp.h>
47 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
48 #define MAP_ANONYMOUS MAP_ANON
52 #define SSH_FXP_INIT 1
53 #define SSH_FXP_VERSION 2
54 #define SSH_FXP_OPEN 3
55 #define SSH_FXP_CLOSE 4
56 #define SSH_FXP_READ 5
57 #define SSH_FXP_WRITE 6
58 #define SSH_FXP_LSTAT 7
59 #define SSH_FXP_FSTAT 8
60 #define SSH_FXP_SETSTAT 9
61 #define SSH_FXP_FSETSTAT 10
62 #define SSH_FXP_OPENDIR 11
63 #define SSH_FXP_READDIR 12
64 #define SSH_FXP_REMOVE 13
65 #define SSH_FXP_MKDIR 14
66 #define SSH_FXP_RMDIR 15
67 #define SSH_FXP_REALPATH 16
68 #define SSH_FXP_STAT 17
69 #define SSH_FXP_RENAME 18
70 #define SSH_FXP_READLINK 19
71 #define SSH_FXP_SYMLINK 20
72 #define SSH_FXP_STATUS 101
73 #define SSH_FXP_HANDLE 102
74 #define SSH_FXP_DATA 103
75 #define SSH_FXP_NAME 104
76 #define SSH_FXP_ATTRS 105
77 #define SSH_FXP_EXTENDED 200
78 #define SSH_FXP_EXTENDED_REPLY 201
80 #define SSH_FILEXFER_ATTR_SIZE 0x00000001
81 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002
82 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
83 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
84 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
88 #define SSH_FX_NO_SUCH_FILE 2
89 #define SSH_FX_PERMISSION_DENIED 3
90 #define SSH_FX_FAILURE 4
91 #define SSH_FX_BAD_MESSAGE 5
92 #define SSH_FX_NO_CONNECTION 6
93 #define SSH_FX_CONNECTION_LOST 7
94 #define SSH_FX_OP_UNSUPPORTED 8
96 #define SSH_FXF_READ 0x00000001
97 #define SSH_FXF_WRITE 0x00000002
98 #define SSH_FXF_APPEND 0x00000004
99 #define SSH_FXF_CREAT 0x00000008
100 #define SSH_FXF_TRUNC 0x00000010
101 #define SSH_FXF_EXCL 0x00000020
103 /* statvfs@openssh.com f_flag flags */
104 #define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001
105 #define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002
107 #define SFTP_EXT_POSIX_RENAME "posix-rename@openssh.com"
108 #define SFTP_EXT_STATVFS "statvfs@openssh.com"
109 #define SFTP_EXT_HARDLINK "hardlink@openssh.com"
111 #define PROTO_VERSION 3
115 #define MAX_REPLY_LEN (1 << 17)
117 #define RENAME_TEMP_CHARS 8
119 #define SFTP_SERVER_PATH "/usr/lib/sftp-server"
121 #define SSHNODELAY_SO "sshnodelay.so"
130 struct list_head *prev;
131 struct list_head *next;
135 typedef void (*request_func)(struct request *);
138 unsigned int want_reply;
144 struct timeval start;
146 request_func end_func;
148 struct list_head list;
153 pthread_cond_t finished;
158 struct sshfs_io *sio;
159 struct list_head list;
170 struct list_head reqs;
175 struct buffer handle;
176 struct list_head write_reqs;
177 pthread_cond_t write_finished;
179 struct read_chunk *readahead;
191 struct fuse_args ssh_args;
193 int rename_workaround;
194 int nodelay_workaround;
195 int nodelaysrv_workaround;
196 int truncate_workaround;
197 int buflimit_workaround;
198 int fstat_workaround;
199 int transform_symlinks;
209 GHashTable *r_uid_map;
210 GHashTable *r_gid_map;
223 pthread_mutex_t lock;
224 pthread_mutex_t lock_write;
225 int processing_thread_started;
226 unsigned int randseed;
234 int remote_uid_detected;
238 unsigned outstanding_len;
239 unsigned max_outstanding_len;
240 pthread_cond_t outstanding_cond;
243 int ext_posix_rename;
250 uint64_t bytes_received;
252 uint64_t num_received;
253 unsigned int min_rtt;
254 unsigned int max_rtt;
256 unsigned int num_connect;
259 static struct sshfs sshfs;
261 static const char *ssh_opts[] = {
265 "ChallengeResponseAuthentication",
271 "ConnectionAttempts",
275 "GlobalKnownHostsFile",
276 "GSSAPIAuthentication",
277 "GSSAPIDelegateCredentials",
278 "HostbasedAuthentication",
284 "KbdInteractiveAuthentication",
285 "KbdInteractiveDevices",
289 "NoHostAuthenticationForLocalhost",
290 "NumberOfPasswordPrompts",
291 "PasswordAuthentication",
293 "PreferredAuthentications",
295 "PubkeyAuthentication",
297 "RhostsRSAAuthentication",
299 "ServerAliveCountMax",
300 "ServerAliveInterval",
302 "StrictHostKeyChecking",
305 "UserKnownHostsFile",
330 #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
332 static struct fuse_opt sshfs_opts[] = {
333 SSHFS_OPT("directport=%s", directport, 0),
334 SSHFS_OPT("ssh_command=%s", ssh_command, 0),
335 SSHFS_OPT("sftp_server=%s", sftp_server, 0),
336 SSHFS_OPT("max_read=%u", max_read, 0),
337 SSHFS_OPT("max_write=%u", max_write, 0),
338 SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0),
339 SSHFS_OPT("-1", ssh_ver, 1),
340 SSHFS_OPT("workaround=%s", workarounds, 0),
341 SSHFS_OPT("idmap=none", idmap, IDMAP_NONE),
342 SSHFS_OPT("idmap=user", idmap, IDMAP_USER),
343 SSHFS_OPT("idmap=file", idmap, IDMAP_FILE),
344 SSHFS_OPT("uidfile=%s", uid_file, 0),
345 SSHFS_OPT("gidfile=%s", gid_file, 0),
346 SSHFS_OPT("nomap=ignore", nomap, NOMAP_IGNORE),
347 SSHFS_OPT("nomap=error", nomap, NOMAP_ERROR),
348 SSHFS_OPT("sshfs_sync", sync_write, 1),
349 SSHFS_OPT("no_readahead", sync_read, 1),
350 SSHFS_OPT("sshfs_debug", debug, 1),
351 SSHFS_OPT("reconnect", reconnect, 1),
352 SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
353 SSHFS_OPT("follow_symlinks", follow_symlinks, 1),
354 SSHFS_OPT("no_check_root", no_check_root, 1),
355 SSHFS_OPT("password_stdin", password_stdin, 1),
356 SSHFS_OPT("delay_connect", delay_connect, 1),
358 FUSE_OPT_KEY("-p ", KEY_PORT),
359 FUSE_OPT_KEY("-C", KEY_COMPRESS),
360 FUSE_OPT_KEY("-V", KEY_VERSION),
361 FUSE_OPT_KEY("--version", KEY_VERSION),
362 FUSE_OPT_KEY("-h", KEY_HELP),
363 FUSE_OPT_KEY("--help", KEY_HELP),
364 FUSE_OPT_KEY("debug", KEY_FOREGROUND),
365 FUSE_OPT_KEY("-d", KEY_FOREGROUND),
366 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
367 FUSE_OPT_KEY("-F ", KEY_CONFIGFILE),
371 static struct fuse_opt workaround_opts[] = {
372 SSHFS_OPT("none", rename_workaround, 0),
373 SSHFS_OPT("none", nodelay_workaround, 0),
374 SSHFS_OPT("none", nodelaysrv_workaround, 0),
375 SSHFS_OPT("none", truncate_workaround, 0),
376 SSHFS_OPT("none", buflimit_workaround, 0),
377 SSHFS_OPT("none", fstat_workaround, 0),
378 SSHFS_OPT("all", rename_workaround, 1),
379 SSHFS_OPT("all", nodelay_workaround, 1),
380 SSHFS_OPT("all", nodelaysrv_workaround, 1),
381 SSHFS_OPT("all", truncate_workaround, 1),
382 SSHFS_OPT("all", buflimit_workaround, 1),
383 SSHFS_OPT("all", fstat_workaround, 1),
384 SSHFS_OPT("rename", rename_workaround, 1),
385 SSHFS_OPT("norename", rename_workaround, 0),
386 SSHFS_OPT("nodelay", nodelay_workaround, 1),
387 SSHFS_OPT("nonodelay", nodelay_workaround, 0),
388 SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1),
389 SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0),
390 SSHFS_OPT("truncate", truncate_workaround, 1),
391 SSHFS_OPT("notruncate", truncate_workaround, 0),
392 SSHFS_OPT("buflimit", buflimit_workaround, 1),
393 SSHFS_OPT("nobuflimit", buflimit_workaround, 0),
394 SSHFS_OPT("fstat", fstat_workaround, 1),
395 SSHFS_OPT("nofstat", fstat_workaround, 0),
399 #define DEBUG(format, args...) \
400 do { if (sshfs.debug) fprintf(stderr, format, args); } while(0)
402 static const char *type_name(uint8_t type)
405 case SSH_FXP_INIT: return "INIT";
406 case SSH_FXP_VERSION: return "VERSION";
407 case SSH_FXP_OPEN: return "OPEN";
408 case SSH_FXP_CLOSE: return "CLOSE";
409 case SSH_FXP_READ: return "READ";
410 case SSH_FXP_WRITE: return "WRITE";
411 case SSH_FXP_LSTAT: return "LSTAT";
412 case SSH_FXP_FSTAT: return "FSTAT";
413 case SSH_FXP_SETSTAT: return "SETSTAT";
414 case SSH_FXP_FSETSTAT: return "FSETSTAT";
415 case SSH_FXP_OPENDIR: return "OPENDIR";
416 case SSH_FXP_READDIR: return "READDIR";
417 case SSH_FXP_REMOVE: return "REMOVE";
418 case SSH_FXP_MKDIR: return "MKDIR";
419 case SSH_FXP_RMDIR: return "RMDIR";
420 case SSH_FXP_REALPATH: return "REALPATH";
421 case SSH_FXP_STAT: return "STAT";
422 case SSH_FXP_RENAME: return "RENAME";
423 case SSH_FXP_READLINK: return "READLINK";
424 case SSH_FXP_SYMLINK: return "SYMLINK";
425 case SSH_FXP_STATUS: return "STATUS";
426 case SSH_FXP_HANDLE: return "HANDLE";
427 case SSH_FXP_DATA: return "DATA";
428 case SSH_FXP_NAME: return "NAME";
429 case SSH_FXP_ATTRS: return "ATTRS";
430 case SSH_FXP_EXTENDED: return "EXTENDED";
431 case SSH_FXP_EXTENDED_REPLY: return "EXTENDED_REPLY";
432 default: return "???";
436 #define container_of(ptr, type, member) ({ \
437 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
438 (type *)( (char *)__mptr - offsetof(type,member) );})
440 #define list_entry(ptr, type, member) \
441 container_of(ptr, type, member)
443 static void list_init(struct list_head *head)
449 static void list_add(struct list_head *new, struct list_head *head)
451 struct list_head *prev = head;
452 struct list_head *next = head->next;
459 static void list_del(struct list_head *entry)
461 struct list_head *prev = entry->prev;
462 struct list_head *next = entry->next;
468 static int list_empty(const struct list_head *head)
470 return head->next == head;
473 /* given a pointer to the uid/gid, and the mapping table, remap the
474 * uid/gid, if necessary */
475 static inline int translate_id(uint32_t *id, GHashTable *map)
478 if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) {
479 *id = GPOINTER_TO_UINT(id_p);
482 switch (sshfs.nomap) {
483 case NOMAP_ERROR: return -1;
484 case NOMAP_IGNORE: return 0;
486 fprintf(stderr, "internal error\n");
491 static inline void buf_init(struct buffer *buf, size_t size)
494 buf->p = (uint8_t *) malloc(size);
496 fprintf(stderr, "sshfs: memory allocation failed\n");
505 static inline void buf_free(struct buffer *buf)
510 static inline void buf_finish(struct buffer *buf)
512 buf->len = buf->size;
515 static inline void buf_clear(struct buffer *buf)
521 static void buf_resize(struct buffer *buf, size_t len)
523 buf->size = (buf->len + len + 63) & ~31;
524 buf->p = (uint8_t *) realloc(buf->p, buf->size);
526 fprintf(stderr, "sshfs: memory allocation failed\n");
531 static inline void buf_check_add(struct buffer *buf, size_t len)
533 if (buf->len + len > buf->size)
534 buf_resize(buf, len);
537 #define _buf_add_mem(b, d, l) \
538 buf_check_add(b, l); \
539 memcpy(b->p + b->len, d, l); \
543 static inline void buf_add_mem(struct buffer *buf, const void *data,
546 _buf_add_mem(buf, data, len);
549 static inline void buf_add_buf(struct buffer *buf, const struct buffer *bufa)
551 _buf_add_mem(buf, bufa->p, bufa->len);
554 static inline void buf_add_uint8(struct buffer *buf, uint8_t val)
556 _buf_add_mem(buf, &val, 1);
559 static inline void buf_add_uint32(struct buffer *buf, uint32_t val)
561 uint32_t nval = htonl(val);
562 _buf_add_mem(buf, &nval, 4);
565 static inline void buf_add_uint64(struct buffer *buf, uint64_t val)
567 buf_add_uint32(buf, val >> 32);
568 buf_add_uint32(buf, val & 0xffffffff);
571 static inline void buf_add_data(struct buffer *buf, const struct buffer *data)
573 buf_add_uint32(buf, data->len);
574 buf_add_mem(buf, data->p, data->len);
577 static inline void buf_add_string(struct buffer *buf, const char *str)
580 data.p = (uint8_t *) str;
581 data.len = strlen(str);
582 buf_add_data(buf, &data);
585 static inline void buf_add_path(struct buffer *buf, const char *path)
589 if (sshfs.base_path[0]) {
591 if (sshfs.base_path[strlen(sshfs.base_path)-1] != '/') {
592 realpath = g_strdup_printf("%s/%s",
596 realpath = g_strdup_printf("%s%s",
601 realpath = g_strdup(sshfs.base_path);
605 realpath = g_strdup(path + 1);
607 realpath = g_strdup(".");
609 buf_add_string(buf, realpath);
613 static int buf_check_get(struct buffer *buf, size_t len)
615 if (buf->len + len > buf->size) {
616 fprintf(stderr, "buffer too short\n");
622 static inline int buf_get_mem(struct buffer *buf, void *data, size_t len)
624 if (buf_check_get(buf, len) == -1)
626 memcpy(data, buf->p + buf->len, len);
631 static inline int buf_get_uint8(struct buffer *buf, uint8_t *val)
633 return buf_get_mem(buf, val, 1);
636 static inline int buf_get_uint32(struct buffer *buf, uint32_t *val)
639 if (buf_get_mem(buf, &nval, 4) == -1)
645 static inline int buf_get_uint64(struct buffer *buf, uint64_t *val)
649 if (buf_get_uint32(buf, &val1) == -1 ||
650 buf_get_uint32(buf, &val2) == -1) {
653 *val = ((uint64_t) val1 << 32) + val2;
657 static inline int buf_get_data(struct buffer *buf, struct buffer *data)
660 if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len)
662 buf_init(data, len + 1);
664 if (buf_get_mem(buf, data->p, data->size) == -1) {
671 static inline int buf_get_string(struct buffer *buf, char **str)
674 if (buf_get_data(buf, &data) == -1)
676 data.p[data.size] = '\0';
677 *str = (char *) data.p;
681 static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
689 uint32_t mode = S_IFREG | 0777;
691 if (buf_get_uint32(buf, &flags) == -1)
695 if ((flags & SSH_FILEXFER_ATTR_SIZE) &&
696 buf_get_uint64(buf, &size) == -1)
698 if ((flags & SSH_FILEXFER_ATTR_UIDGID) &&
699 (buf_get_uint32(buf, &uid) == -1 ||
700 buf_get_uint32(buf, &gid) == -1))
702 if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
703 buf_get_uint32(buf, &mode) == -1)
705 if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
706 if (buf_get_uint32(buf, &atime) == -1 ||
707 buf_get_uint32(buf, &mtime) == -1)
710 if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) {
713 if (buf_get_uint32(buf, &extcount) == -1)
715 for (i = 0; i < extcount; i++) {
717 if (buf_get_data(buf, &tmp) == -1)
720 if (buf_get_data(buf, &tmp) == -1)
726 if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
727 uid = sshfs.local_uid;
728 if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map)
729 if (translate_id(&uid, sshfs.uid_map) == -1)
731 if (sshfs.idmap == IDMAP_FILE && sshfs.gid_map)
732 if (translate_id(&gid, sshfs.gid_map) == -1)
735 memset(stbuf, 0, sizeof(struct stat));
736 stbuf->st_mode = mode;
738 stbuf->st_size = size;
740 stbuf->st_blksize = sshfs.blksize;
741 stbuf->st_blocks = ((size + sshfs.blksize - 1) &
742 ~((unsigned long long) sshfs.blksize - 1)) >> 9;
746 stbuf->st_atime = atime;
747 stbuf->st_ctime = stbuf->st_mtime = mtime;
751 static int buf_get_statvfs(struct buffer *buf, struct statvfs *stbuf)
765 if (buf_get_uint64(buf, &bsize) == -1 ||
766 buf_get_uint64(buf, &frsize) == -1 ||
767 buf_get_uint64(buf, &blocks) == -1 ||
768 buf_get_uint64(buf, &bfree) == -1 ||
769 buf_get_uint64(buf, &bavail) == -1 ||
770 buf_get_uint64(buf, &files) == -1 ||
771 buf_get_uint64(buf, &ffree) == -1 ||
772 buf_get_uint64(buf, &favail) == -1 ||
773 buf_get_uint64(buf, &fsid) == -1 ||
774 buf_get_uint64(buf, &flag) == -1 ||
775 buf_get_uint64(buf, &namemax) == -1) {
779 memset(stbuf, 0, sizeof(struct statvfs));
780 stbuf->f_bsize = bsize;
781 stbuf->f_frsize = frsize;
782 stbuf->f_blocks = blocks;
783 stbuf->f_bfree = bfree;
784 stbuf->f_bavail = bavail;
785 stbuf->f_files = files;
786 stbuf->f_ffree = ffree;
787 stbuf->f_favail = favail;
788 stbuf->f_namemax = namemax;
793 static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
794 fuse_cache_dirfil_t filler)
799 if (buf_get_uint32(buf, &count) == -1)
802 for (i = 0; i < count; i++) {
807 if (buf_get_string(buf, &name) == -1)
809 if (buf_get_string(buf, &longname) != -1) {
811 err = buf_get_attrs(buf, &stbuf, NULL);
813 if (sshfs.follow_symlinks &&
814 S_ISLNK(stbuf.st_mode)) {
817 filler(h, name, &stbuf);
827 static void ssh_add_arg(const char *arg)
829 if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1)
833 #ifdef SSH_NODELAY_WORKAROUND
834 static int do_ssh_nodelay_workaround(void)
836 char *oldpreload = getenv("LD_PRELOAD");
838 char sopath[PATH_MAX];
841 snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
842 res = access(sopath, R_OK);
845 if (!realpath(sshfs.progname, sopath))
848 s = strrchr(sopath, '/');
854 if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath))
857 strcpy(s, SSHNODELAY_SO);
858 res = access(sopath, R_OK);
860 fprintf(stderr, "sshfs: cannot find %s\n",
866 newpreload = g_strdup_printf("%s%s%s",
867 oldpreload ? oldpreload : "",
868 oldpreload ? " " : "",
871 if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
872 fprintf(stderr, "warning: failed set LD_PRELOAD "
873 "for ssh nodelay workaround\n");
880 static int pty_expect_loop(void)
884 const char *passwd_str = "assword:";
885 int timeout = 60 * 1000; /* 1min timeout for the prompt to appear */
886 int passwd_len = strlen(passwd_str);
891 struct pollfd fds[2];
893 fds[0].fd = sshfs.fd;
894 fds[0].events = POLLIN;
895 fds[1].fd = sshfs.ptyfd;
896 fds[1].events = POLLIN;
897 res = poll(fds, 2, timeout);
903 fprintf(stderr, "Timeout waiting for prompt\n");
906 if (fds[0].revents) {
908 * Something happened on stdout of ssh, this
909 * either means, that we are connected, or
910 * that we are disconnected. In any case the
911 * password doesn't matter any more.
916 res = read(sshfs.ptyfd, &c, 1);
922 fprintf(stderr, "EOF while waiting for prompt\n");
927 if (len == passwd_len) {
928 if (memcmp(buf, passwd_str, passwd_len) == 0) {
929 write(sshfs.ptyfd, sshfs.password,
930 strlen(sshfs.password));
932 memmove(buf, buf + 1, passwd_len - 1);
937 if (!sshfs.reconnect) {
938 size_t size = getpagesize();
940 memset(sshfs.password, 0, size);
941 munmap(sshfs.password, size);
942 sshfs.password = NULL;
948 static int pty_master(char **name)
952 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
954 perror("failed to open pty");
957 if (grantpt(mfd) != 0) {
961 if (unlockpt(mfd) != 0) {
965 *name = ptsname(mfd);
970 static void replace_arg(char **argp, const char *newarg)
973 *argp = strdup(newarg);
975 fprintf(stderr, "sshfs: memory allocation failed\n");
980 static int start_ssh(void)
982 char *ptyname = NULL;
986 if (sshfs.password_stdin) {
988 sshfs.ptyfd = pty_master(&ptyname);
989 if (sshfs.ptyfd == -1)
992 sshfs.ptyslavefd = open(ptyname, O_RDWR | O_NOCTTY);
993 if (sshfs.ptyslavefd == -1)
997 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) {
998 perror("failed to create socket pair");
1001 sshfs.fd = sockpair[0];
1005 perror("failed to fork");
1008 } else if (pid == 0) {
1011 #ifdef SSH_NODELAY_WORKAROUND
1012 if (sshfs.nodelay_workaround &&
1013 do_ssh_nodelay_workaround() == -1) {
1015 "warning: ssh nodelay workaround disabled\n");
1019 if (sshfs.nodelaysrv_workaround) {
1022 * Hack to work around missing TCP_NODELAY
1025 for (i = 1; i < sshfs.ssh_args.argc; i++) {
1026 if (strcmp(sshfs.ssh_args.argv[i], "-x") == 0) {
1027 replace_arg(&sshfs.ssh_args.argv[i],
1034 devnull = open("/dev/null", O_WRONLY);
1036 if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) {
1037 perror("failed to redirect input/output");
1040 if (!sshfs.foreground && devnull != -1)
1049 perror("failed to fork");
1058 if (sshfs.password_stdin) {
1062 sfd = open(ptyname, O_RDWR);
1068 close(sshfs.ptyslavefd);
1075 fprintf(stderr, "executing");
1076 for (i = 0; i < sshfs.ssh_args.argc; i++)
1077 fprintf(stderr, " <%s>",
1078 sshfs.ssh_args.argv[i]);
1079 fprintf(stderr, "\n");
1082 execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv);
1083 fprintf(stderr, "failed to execute '%s': %s\n",
1084 sshfs.ssh_args.argv[0], strerror(errno));
1087 waitpid(pid, NULL, 0);
1092 static int connect_to(char *host, char *port)
1097 struct addrinfo *ai;
1098 struct addrinfo hint;
1100 memset(&hint, 0, sizeof(hint));
1101 hint.ai_family = PF_INET;
1102 hint.ai_socktype = SOCK_STREAM;
1103 err = getaddrinfo(host, port, &hint, &ai);
1105 fprintf(stderr, "failed to resolve %s:%s: %s\n", host, port,
1109 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1111 perror("failed to create socket");
1114 err = connect(sock, ai->ai_addr, ai->ai_addrlen);
1116 perror("failed to connect");
1120 err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
1122 perror("warning: failed to set TCP_NODELAY");
1130 static int do_write(struct iovec *iov, size_t count)
1134 res = writev(sshfs.fd, iov, count);
1138 } else if (res == 0) {
1139 fprintf(stderr, "zero write\n");
1143 if ((unsigned) res < iov->iov_len) {
1144 iov->iov_len -= res;
1145 iov->iov_base += res;
1148 res -= iov->iov_len;
1157 static uint32_t sftp_get_id(void)
1159 static uint32_t idctr;
1163 static void buf_to_iov(const struct buffer *buf, struct iovec *iov)
1165 iov->iov_base = buf->p;
1166 iov->iov_len = buf->len;
1169 static size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
1174 for (seg = 0; seg < nr_segs; seg++)
1175 ret += iov[seg].iov_len;
1179 #define SFTP_MAX_IOV 3
1181 static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[],
1186 struct iovec iovout[SFTP_MAX_IOV];
1190 assert(count <= SFTP_MAX_IOV - 1);
1192 buf_add_uint32(&buf, iov_length(iov, count) + 5);
1193 buf_add_uint8(&buf, type);
1194 buf_add_uint32(&buf, id);
1195 buf_to_iov(&buf, &iovout[nout++]);
1196 for (i = 0; i < count; i++)
1197 iovout[nout++] = iov[i];
1198 pthread_mutex_lock(&sshfs.lock_write);
1199 res = do_write(iovout, nout);
1200 pthread_mutex_unlock(&sshfs.lock_write);
1205 static int do_read(struct buffer *buf)
1208 uint8_t *p = buf->p;
1209 size_t size = buf->size;
1211 res = read(sshfs.fd, p, size);
1215 } else if (res == 0) {
1216 fprintf(stderr, "remote host has disconnected\n");
1225 static int sftp_read(uint8_t *type, struct buffer *buf)
1231 res = do_read(&buf2);
1233 if (buf_get_uint32(&buf2, &len) == -1)
1235 if (len > MAX_REPLY_LEN) {
1236 fprintf(stderr, "reply len too large: %u\n", len);
1239 if (buf_get_uint8(&buf2, type) == -1)
1241 buf_init(buf, len - 1);
1248 static void request_free(struct request *req)
1250 buf_free(&req->reply);
1251 sem_destroy(&req->ready);
1255 static void chunk_free(struct read_chunk *chunk)
1257 while (!list_empty(&chunk->reqs)) {
1258 struct read_req *rreq;
1260 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
1261 list_del(&rreq->list);
1262 buf_free(&rreq->data);
1268 static void chunk_put(struct read_chunk *chunk)
1277 static void chunk_put_locked(struct read_chunk *chunk)
1279 pthread_mutex_lock(&sshfs.lock);
1281 pthread_mutex_unlock(&sshfs.lock);
1284 static int clean_req(void *key_, struct request *req)
1289 if (req->want_reply)
1290 sem_post(&req->ready);
1299 static int process_one_request(void)
1304 struct request *req;
1308 res = sftp_read(&type, &buf);
1311 if (buf_get_uint32(&buf, &id) == -1)
1314 pthread_mutex_lock(&sshfs.lock);
1315 req = (struct request *)
1316 g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id));
1318 fprintf(stderr, "request %i not found\n", id);
1322 was_over = sshfs.outstanding_len > sshfs.max_outstanding_len;
1323 sshfs.outstanding_len -= req->len;
1325 sshfs.outstanding_len <= sshfs.max_outstanding_len) {
1326 pthread_cond_broadcast(&sshfs.outstanding_cond);
1328 g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1330 pthread_mutex_unlock(&sshfs.lock);
1334 unsigned int difftime;
1335 unsigned msgsize = buf.size + 5;
1337 gettimeofday(&now, NULL);
1338 difftime = (now.tv_sec - req->start.tv_sec) * 1000;
1339 difftime += (now.tv_usec - req->start.tv_usec) / 1000;
1340 DEBUG(" [%05i] %14s %8ubytes (%ims)\n", id,
1341 type_name(type), msgsize, difftime);
1343 if (difftime < sshfs.min_rtt || !sshfs.num_received)
1344 sshfs.min_rtt = difftime;
1345 if (difftime > sshfs.max_rtt)
1346 sshfs.max_rtt = difftime;
1347 sshfs.total_rtt += difftime;
1348 sshfs.num_received++;
1349 sshfs.bytes_received += msgsize;
1352 req->reply_type = type;
1354 if (req->want_reply)
1355 sem_post(&req->ready);
1357 if (req->end_func) {
1358 pthread_mutex_lock(&sshfs.lock);
1360 pthread_mutex_unlock(&sshfs.lock);
1370 static void close_conn(void)
1374 if (sshfs.ptyfd != -1) {
1378 if (sshfs.ptyslavefd != -1) {
1379 close(sshfs.ptyslavefd);
1380 sshfs.ptyslavefd = -1;
1384 static void *process_requests(void *data_)
1389 if (process_one_request() == -1)
1393 pthread_mutex_lock(&sshfs.lock);
1394 sshfs.processing_thread_started = 0;
1396 g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL);
1398 sshfs.outstanding_len = 0;
1399 pthread_cond_broadcast(&sshfs.outstanding_cond);
1400 pthread_mutex_unlock(&sshfs.lock);
1402 if (!sshfs.reconnect) {
1404 kill(getpid(), SIGTERM);
1409 static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
1414 if (buf_get_uint32(buf, &len) == -1)
1417 if (len < 5 || len > MAX_REPLY_LEN)
1420 if (buf_get_uint8(buf, &type) == -1)
1423 if (type != SSH_FXP_VERSION)
1426 if (buf_get_uint32(buf, version) == -1)
1429 DEBUG("Server version: %u\n", *version);
1434 buf_init(&buf2, len - 5);
1435 if (do_read(&buf2) == -1) {
1444 if (buf_get_string(&buf2, &ext) == -1 ||
1445 buf_get_string(&buf2, &extdata) == -1) {
1450 DEBUG("Extension: %s <%s>\n", ext, extdata);
1452 if (strcmp(ext, SFTP_EXT_POSIX_RENAME) == 0 &&
1453 strcmp(extdata, "1") == 0) {
1454 sshfs.ext_posix_rename = 1;
1455 sshfs.rename_workaround = 0;
1457 if (strcmp(ext, SFTP_EXT_STATVFS) == 0 &&
1458 strcmp(extdata, "2") == 0)
1459 sshfs.ext_statvfs = 1;
1460 if (strcmp(ext, SFTP_EXT_HARDLINK) == 0 &&
1461 strcmp(extdata, "1") == 0)
1462 sshfs.ext_hardlink = 1;
1463 } while (buf2.len < buf2.size);
1469 static int sftp_find_init_reply(uint32_t *version)
1475 res = do_read(&buf);
1479 res = sftp_init_reply_ok(&buf, version);
1483 /* Iterate over any rubbish until the version reply is found */
1484 DEBUG("%c", *buf.p);
1485 memmove(buf.p, buf.p + 1, buf.size - 1);
1487 buf2.p = buf.p + buf.size - 1;
1489 res = do_read(&buf2);
1495 static int sftp_init()
1498 uint32_t version = 0;
1501 if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1)
1504 if (sshfs.password_stdin && pty_expect_loop() == -1)
1507 if (sftp_find_init_reply(&version) == -1)
1510 sshfs.server_version = version;
1511 if (version > PROTO_VERSION) {
1513 "Warning: server uses version: %i, we support: %i\n",
1514 version, PROTO_VERSION);
1523 static int sftp_error_to_errno(uint32_t error)
1526 case SSH_FX_OK: return 0;
1527 case SSH_FX_NO_SUCH_FILE: return ENOENT;
1528 case SSH_FX_PERMISSION_DENIED: return EACCES;
1529 case SSH_FX_FAILURE: return EPERM;
1530 case SSH_FX_BAD_MESSAGE: return EBADMSG;
1531 case SSH_FX_NO_CONNECTION: return ENOTCONN;
1532 case SSH_FX_CONNECTION_LOST: return ECONNABORTED;
1533 case SSH_FX_OP_UNSUPPORTED: return EOPNOTSUPP;
1534 default: return EIO;
1538 static void sftp_detect_uid()
1541 uint32_t id = sftp_get_id();
1546 struct iovec iov[1];
1549 buf_add_string(&buf, ".");
1550 buf_to_iov(&buf, &iov[0]);
1551 if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1554 if (sftp_read(&type, &buf) == -1)
1556 if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1557 fprintf(stderr, "protocol error\n");
1560 if (buf_get_uint32(&buf, &replid) == -1)
1563 fprintf(stderr, "bad reply ID\n");
1566 if (type == SSH_FXP_STATUS) {
1568 if (buf_get_uint32(&buf, &serr) == -1)
1571 fprintf(stderr, "failed to stat home directory (%i)\n", serr);
1574 if (buf_get_attrs(&buf, &stbuf, &flags) != 0)
1577 if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
1580 sshfs.remote_uid = stbuf.st_uid;
1581 sshfs.local_uid = getuid();
1582 sshfs.remote_uid_detected = 1;
1583 DEBUG("remote_uid = %i\n", sshfs.remote_uid);
1586 if (!sshfs.remote_uid_detected)
1587 fprintf(stderr, "failed to detect remote user ID\n");
1592 static int sftp_check_root(const char *base_path)
1595 uint32_t id = sftp_get_id();
1600 struct iovec iov[1];
1602 const char *remote_dir = base_path[0] ? base_path : ".";
1605 buf_add_string(&buf, remote_dir);
1606 buf_to_iov(&buf, &iov[0]);
1607 if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1610 if (sftp_read(&type, &buf) == -1)
1612 if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1613 fprintf(stderr, "protocol error\n");
1616 if (buf_get_uint32(&buf, &replid) == -1)
1619 fprintf(stderr, "bad reply ID\n");
1622 if (type == SSH_FXP_STATUS) {
1624 if (buf_get_uint32(&buf, &serr) == -1)
1627 fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir,
1628 strerror(sftp_error_to_errno(serr)));
1633 int err2 = buf_get_attrs(&buf, &stbuf, &flags);
1639 if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS))
1642 if (S_ISDIR(sshfs.mnt_mode) && !S_ISDIR(stbuf.st_mode)) {
1643 fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host,
1647 if ((sshfs.mnt_mode ^ stbuf.st_mode) & S_IFMT) {
1648 fprintf(stderr, "%s:%s: type of file differs from mountpoint\n",
1649 sshfs.host, remote_dir);
1660 static int connect_remote(void)
1664 if (sshfs.directport)
1665 err = connect_to(sshfs.host, sshfs.directport);
1674 sshfs.num_connect++;
1679 static int start_processing_thread(void)
1682 pthread_t thread_id;
1686 if (sshfs.processing_thread_started)
1689 if (sshfs.fd == -1) {
1690 err = connect_remote();
1695 if (sshfs.detect_uid) {
1697 sshfs.detect_uid = 0;
1700 sigemptyset(&newset);
1701 sigaddset(&newset, SIGTERM);
1702 sigaddset(&newset, SIGINT);
1703 sigaddset(&newset, SIGHUP);
1704 sigaddset(&newset, SIGQUIT);
1705 pthread_sigmask(SIG_BLOCK, &newset, &oldset);
1706 err = pthread_create(&thread_id, NULL, process_requests, NULL);
1708 fprintf(stderr, "failed to create thread: %s\n", strerror(err));
1711 pthread_detach(thread_id);
1712 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1713 sshfs.processing_thread_started = 1;
1717 #if FUSE_VERSION >= 26
1718 static void *sshfs_init(struct fuse_conn_info *conn)
1720 static void *sshfs_init(void)
1723 #if FUSE_VERSION >= 26
1724 /* Readahead should be done by kernel or sshfs but not both */
1725 if (conn->async_read)
1726 sshfs.sync_read = 1;
1729 if (!sshfs.delay_connect)
1730 start_processing_thread();
1735 static int sftp_request_wait(struct request *req, uint8_t type,
1736 uint8_t expect_type, struct buffer *outbuf)
1744 while (sem_wait(&req->ready));
1750 if (req->reply_type != expect_type &&
1751 req->reply_type != SSH_FXP_STATUS) {
1752 fprintf(stderr, "protocol error\n");
1755 if (req->reply_type == SSH_FXP_STATUS) {
1757 if (buf_get_uint32(&req->reply, &serr) == -1)
1762 if (expect_type == SSH_FXP_STATUS)
1769 if (type == SSH_FXP_READ || type == SSH_FXP_READDIR)
1776 err = -sftp_error_to_errno(serr);
1779 buf_init(outbuf, req->reply.size - req->reply.len);
1780 buf_get_mem(&req->reply, outbuf->p, outbuf->size);
1785 if (req->end_func) {
1786 pthread_mutex_lock(&sshfs.lock);
1788 pthread_mutex_unlock(&sshfs.lock);
1794 static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
1795 request_func begin_func, request_func end_func,
1796 int want_reply, void *data,
1797 struct request **reqp)
1801 struct request *req = g_new0(struct request, 1);
1803 req->want_reply = want_reply;
1804 req->end_func = end_func;
1806 sem_init(&req->ready, 0, 0);
1807 buf_init(&req->reply, 0);
1808 pthread_mutex_lock(&sshfs.lock);
1812 err = start_processing_thread();
1814 pthread_mutex_unlock(&sshfs.lock);
1817 req->len = iov_length(iov, count) + 9;
1818 sshfs.outstanding_len += req->len;
1819 while (sshfs.outstanding_len > sshfs.max_outstanding_len)
1820 pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock);
1822 g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req);
1824 gettimeofday(&req->start, NULL);
1826 sshfs.bytes_sent += req->len;
1828 DEBUG("[%05i] %s\n", id, type_name(type));
1829 pthread_mutex_unlock(&sshfs.lock);
1832 if (sftp_send_iov(type, id, iov, count) == -1) {
1835 pthread_mutex_lock(&sshfs.lock);
1836 rmed = g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1837 pthread_mutex_unlock(&sshfs.lock);
1839 if (!rmed && !want_reply) {
1840 /* request already freed */
1852 sftp_request_wait(req, type, 0, NULL);
1860 static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count,
1861 uint8_t expect_type, struct buffer *outbuf)
1864 struct request *req;
1866 err = sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL,
1868 if (expect_type == 0)
1871 return sftp_request_wait(req, type, expect_type, outbuf);
1874 static int sftp_request(uint8_t type, const struct buffer *buf,
1875 uint8_t expect_type, struct buffer *outbuf)
1879 buf_to_iov(buf, &iov);
1880 return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
1883 static int sshfs_getattr(const char *path, struct stat *stbuf)
1887 struct buffer outbuf;
1889 buf_add_path(&buf, path);
1890 err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
1891 &buf, SSH_FXP_ATTRS, &outbuf);
1893 err = buf_get_attrs(&outbuf, stbuf, NULL);
1900 static int count_components(const char *p)
1904 for (; *p == '/'; p++);
1905 for (ctr = 0; *p; ctr++) {
1906 for (; *p && *p != '/'; p++);
1907 for (; *p == '/'; p++);
1912 static void strip_common(const char **sp, const char **tp)
1914 const char *s = *sp;
1915 const char *t = *tp;
1917 for (; *s == '/'; s++);
1918 for (; *t == '/'; t++);
1921 for (; *s == *t && *s && *s != '/'; s++, t++);
1922 } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
1925 static void transform_symlink(const char *path, char **linkp)
1927 const char *l = *linkp;
1928 const char *b = sshfs.base_path;
1934 if (l[0] != '/' || b[0] != '/')
1937 strip_common(&l, &b);
1941 strip_common(&l, &path);
1942 dotdots = count_components(path);
1947 newlink = malloc(dotdots * 3 + strlen(l) + 2);
1949 fprintf(stderr, "sshfs: memory allocation failed\n");
1952 for (s = newlink, i = 0; i < dotdots; i++, s += 3)
1966 static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
1974 if (sshfs.server_version < 3)
1978 buf_add_path(&buf, path);
1979 err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
1984 if(buf_get_uint32(&name, &count) != -1 && count == 1 &&
1985 buf_get_string(&name, &link) != -1) {
1986 if (sshfs.transform_symlinks)
1987 transform_symlink(path, &link);
1988 strncpy(linkbuf, link, size - 1);
1989 linkbuf[size - 1] = '\0';
1999 static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
2000 fuse_cache_dirfil_t filler)
2004 struct buffer handle;
2006 buf_add_path(&buf, path);
2007 err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle);
2010 buf_finish(&handle);
2013 err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
2015 err = buf_get_entries(&name, h, filler);
2022 err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
2031 static int sshfs_mkdir(const char *path, mode_t mode)
2036 buf_add_path(&buf, path);
2037 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2038 buf_add_uint32(&buf, mode);
2039 err = sftp_request(SSH_FXP_MKDIR, &buf, SSH_FXP_STATUS, NULL);
2044 static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
2048 struct buffer handle;
2051 if ((mode & S_IFMT) != S_IFREG)
2055 buf_add_path(&buf, path);
2056 buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_EXCL);
2057 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2058 buf_add_uint32(&buf, mode);
2059 err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
2062 buf_finish(&handle);
2063 err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS,
2073 static int sshfs_symlink(const char *from, const char *to)
2078 if (sshfs.server_version < 3)
2081 /* openssh sftp server doesn't follow standard: link target and
2082 link name are mixed up, so we must also be non-standard :( */
2084 buf_add_string(&buf, from);
2085 buf_add_path(&buf, to);
2086 err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
2091 static int sshfs_unlink(const char *path)
2096 buf_add_path(&buf, path);
2097 err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
2102 static int sshfs_rmdir(const char *path)
2107 buf_add_path(&buf, path);
2108 err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
2113 static int sshfs_do_rename(const char *from, const char *to)
2118 buf_add_path(&buf, from);
2119 buf_add_path(&buf, to);
2120 err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
2125 static int sshfs_ext_posix_rename(const char *from, const char *to)
2130 buf_add_string(&buf, SFTP_EXT_POSIX_RENAME);
2131 buf_add_path(&buf, from);
2132 buf_add_path(&buf, to);
2133 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
2138 static void random_string(char *str, int length)
2141 for (i = 0; i < length; i++)
2142 *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10);
2146 static int sshfs_rename(const char *from, const char *to)
2149 if (sshfs.ext_posix_rename)
2150 err = sshfs_ext_posix_rename(from, to);
2152 err = sshfs_do_rename(from, to);
2153 if (err == -EPERM && sshfs.rename_workaround) {
2154 size_t tolen = strlen(to);
2155 if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
2157 char totmp[PATH_MAX];
2159 random_string(totmp + tolen, RENAME_TEMP_CHARS);
2160 tmperr = sshfs_do_rename(to, totmp);
2162 err = sshfs_do_rename(from, to);
2164 err = sshfs_unlink(totmp);
2166 sshfs_do_rename(totmp, to);
2173 static int sshfs_link(const char *from, const char *to)
2177 if (sshfs.ext_hardlink) {
2181 buf_add_string(&buf, SFTP_EXT_HARDLINK);
2182 buf_add_path(&buf, from);
2183 buf_add_path(&buf, to);
2184 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS,
2192 static int sshfs_chmod(const char *path, mode_t mode)
2197 buf_add_path(&buf, path);
2198 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2199 buf_add_uint32(&buf, mode);
2200 /* FIXME: really needs LSETSTAT extension (debian Bug#640038) */
2201 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2206 static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
2211 if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
2212 uid = sshfs.remote_uid;
2213 if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map)
2214 if(translate_id(&uid, sshfs.r_uid_map) == -1)
2216 if (sshfs.idmap == IDMAP_FILE && sshfs.r_gid_map)
2217 if (translate_id(&gid, sshfs.r_gid_map) == -1)
2221 buf_add_path(&buf, path);
2222 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
2223 buf_add_uint32(&buf, uid);
2224 buf_add_uint32(&buf, gid);
2225 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2230 static int sshfs_truncate_workaround(const char *path, off_t size,
2231 struct fuse_file_info *fi);
2233 static void sshfs_inc_modifver(void)
2235 pthread_mutex_lock(&sshfs.lock);
2237 pthread_mutex_unlock(&sshfs.lock);
2240 static int sshfs_truncate(const char *path, off_t size)
2245 sshfs_inc_modifver();
2246 if (size == 0 || sshfs.truncate_workaround)
2247 return sshfs_truncate_workaround(path, size, NULL);
2250 buf_add_path(&buf, path);
2251 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2252 buf_add_uint64(&buf, size);
2253 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2258 static int sshfs_utime(const char *path, struct utimbuf *ubuf)
2263 buf_add_path(&buf, path);
2264 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
2265 buf_add_uint32(&buf, ubuf->actime);
2266 buf_add_uint32(&buf, ubuf->modtime);
2267 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2272 static inline int sshfs_file_is_conn(struct sshfs_file *sf)
2276 pthread_mutex_lock(&sshfs.lock);
2277 ret = (sf->connver == sshfs.connver);
2278 pthread_mutex_unlock(&sshfs.lock);
2283 static int sshfs_open_common(const char *path, mode_t mode,
2284 struct fuse_file_info *fi)
2289 struct buffer outbuf;
2291 struct sshfs_file *sf;
2292 struct request *open_req;
2293 uint32_t pflags = 0;
2296 uint64_t wrctr = cache_get_write_ctr();
2298 if ((fi->flags & O_ACCMODE) == O_RDONLY)
2299 pflags = SSH_FXF_READ;
2300 else if((fi->flags & O_ACCMODE) == O_WRONLY)
2301 pflags = SSH_FXF_WRITE;
2302 else if ((fi->flags & O_ACCMODE) == O_RDWR)
2303 pflags = SSH_FXF_READ | SSH_FXF_WRITE;
2307 if (fi->flags & O_CREAT)
2308 pflags |= SSH_FXF_CREAT;
2310 if (fi->flags & O_EXCL)
2311 pflags |= SSH_FXF_EXCL;
2313 if (fi->flags & O_TRUNC)
2314 pflags |= SSH_FXF_TRUNC;
2316 sf = g_new0(struct sshfs_file, 1);
2317 list_init(&sf->write_reqs);
2318 pthread_cond_init(&sf->write_finished, NULL);
2319 /* Assume random read after open */
2323 pthread_mutex_lock(&sshfs.lock);
2324 sf->modifver= sshfs.modifver;
2325 sf->connver = sshfs.connver;
2326 pthread_mutex_unlock(&sshfs.lock);
2328 buf_add_path(&buf, path);
2329 buf_add_uint32(&buf, pflags);
2330 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2331 buf_add_uint32(&buf, mode);
2332 buf_to_iov(&buf, &iov);
2333 sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL,
2336 buf_add_path(&buf, path);
2337 type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT;
2338 err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf);
2340 err2 = buf_get_attrs(&outbuf, &stbuf, NULL);
2343 err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE,
2346 buf_finish(&sf->handle);
2347 sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL);
2348 buf_free(&sf->handle);
2353 cache_add_attr(path, &stbuf, wrctr);
2354 buf_finish(&sf->handle);
2355 fi->fh = (unsigned long) sf;
2357 cache_invalidate(path);
2364 static int sshfs_open(const char *path, struct fuse_file_info *fi)
2366 return sshfs_open_common(path, 0, fi);
2369 static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
2371 return (struct sshfs_file *) (uintptr_t) fi->fh;
2374 static int sshfs_flush(const char *path, struct fuse_file_info *fi)
2377 struct sshfs_file *sf = get_sshfs_file(fi);
2378 struct list_head write_reqs;
2379 struct list_head *curr_list;
2381 if (!sshfs_file_is_conn(sf))
2384 if (sshfs.sync_write)
2388 pthread_mutex_lock(&sshfs.lock);
2389 if (!list_empty(&sf->write_reqs)) {
2390 curr_list = sf->write_reqs.prev;
2391 list_del(&sf->write_reqs);
2392 list_init(&sf->write_reqs);
2393 list_add(&write_reqs, curr_list);
2394 while (!list_empty(&write_reqs))
2395 pthread_cond_wait(&sf->write_finished, &sshfs.lock);
2397 err = sf->write_error;
2398 sf->write_error = 0;
2399 pthread_mutex_unlock(&sshfs.lock);
2403 static int sshfs_fsync(const char *path, int isdatasync,
2404 struct fuse_file_info *fi)
2407 return sshfs_flush(path, fi);
2410 static void sshfs_file_put(struct sshfs_file *sf)
2417 static void sshfs_file_get(struct sshfs_file *sf)
2422 static int sshfs_release(const char *path, struct fuse_file_info *fi)
2424 struct sshfs_file *sf = get_sshfs_file(fi);
2425 struct buffer *handle = &sf->handle;
2426 if (sshfs_file_is_conn(sf)) {
2427 sshfs_flush(path, fi);
2428 sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
2431 chunk_put_locked(sf->readahead);
2436 static void sshfs_read_end(struct request *req)
2438 struct read_req *rreq = (struct read_req *) req->data;
2440 rreq->res = req->error;
2441 else if (req->replied) {
2444 if (req->reply_type == SSH_FXP_STATUS) {
2446 if (buf_get_uint32(&req->reply, &serr) != -1) {
2447 if (serr == SSH_FX_EOF)
2450 rreq->res = -sftp_error_to_errno(serr);
2452 } else if (req->reply_type == SSH_FXP_DATA) {
2454 if (buf_get_uint32(&req->reply, &retsize) != -1) {
2455 if (retsize > rreq->size) {
2456 fprintf(stderr, "long read\n");
2457 } else if (buf_check_get(&req->reply, retsize) != -1) {
2458 rreq->res = retsize;
2459 rreq->data = req->reply;
2460 buf_init(&req->reply, 0);
2464 fprintf(stderr, "protocol error\n");
2470 rreq->sio->num_reqs--;
2471 if (!rreq->sio->num_reqs)
2472 pthread_cond_broadcast(&rreq->sio->finished);
2475 static void sshfs_read_begin(struct request *req)
2477 struct read_req *rreq = (struct read_req *) req->data;
2478 rreq->sio->num_reqs++;
2481 static struct read_chunk *sshfs_send_read(struct sshfs_file *sf, size_t size,
2484 struct read_chunk *chunk = g_new0(struct read_chunk, 1);
2485 struct buffer *handle = &sf->handle;
2487 pthread_cond_init(&chunk->sio.finished, NULL);
2488 list_init(&chunk->reqs);
2490 chunk->offset = offset;
2496 struct iovec iov[1];
2497 struct read_req *rreq;
2498 size_t bsize = size < sshfs.max_read ? size : sshfs.max_read;
2500 rreq = g_new0(struct read_req, 1);
2501 rreq->sio = &chunk->sio;
2503 buf_init(&rreq->data, 0);
2504 list_add(&rreq->list, &chunk->reqs);
2507 buf_add_buf(&buf, handle);
2508 buf_add_uint64(&buf, offset);
2509 buf_add_uint32(&buf, bsize);
2510 buf_to_iov(&buf, &iov[0]);
2511 err = sftp_request_send(SSH_FXP_READ, iov, 1,
2527 static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size)
2530 struct read_req *rreq;
2532 pthread_mutex_lock(&sshfs.lock);
2533 while (chunk->sio.num_reqs)
2534 pthread_cond_wait(&chunk->sio.finished, &sshfs.lock);
2535 pthread_mutex_unlock(&sshfs.lock);
2538 if (chunk->sio.error) {
2539 if (chunk->sio.error != MY_EOF)
2540 res = chunk->sio.error;
2545 while (!list_empty(&chunk->reqs) && size) {
2546 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
2548 if (rreq->res < 0) {
2549 chunk->sio.error = rreq->res;
2551 } if (rreq->res == 0) {
2552 chunk->sio.error = MY_EOF;
2554 } else if (size < (size_t) rreq->res) {
2555 buf_get_mem(&rreq->data, buf, size);
2561 buf_get_mem(&rreq->data, buf, rreq->res);
2563 if ((size_t) rreq->res < rreq->size) {
2564 chunk->sio.error = MY_EOF;
2569 list_del(&rreq->list);
2570 buf_free(&rreq->data);
2576 chunk->offset += res;
2581 chunk_put_locked(chunk);
2585 static int sshfs_sync_read(struct sshfs_file *sf, char *buf, size_t size,
2588 struct read_chunk *chunk;
2590 chunk = sshfs_send_read(sf, size, offset);
2591 return wait_chunk(chunk, buf, size);
2594 static void submit_read(struct sshfs_file *sf, size_t size, off_t offset,
2595 struct read_chunk **chunkp)
2597 struct read_chunk *chunk;
2599 chunk = sshfs_send_read(sf, size, offset);
2600 pthread_mutex_lock(&sshfs.lock);
2601 chunk->modifver = sshfs.modifver;
2605 pthread_mutex_unlock(&sshfs.lock);
2608 static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset)
2610 struct read_chunk *ch = sf->readahead;
2611 if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) {
2618 static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size,
2623 struct read_chunk *chunk;
2624 struct read_chunk *chunk_prev = NULL;
2625 size_t origsize = size;
2628 pthread_mutex_lock(&sshfs.lock);
2629 curr_is_seq = sf->is_seq;
2630 sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver);
2631 sf->next_pos = offset + size;
2632 sf->modifver = sshfs.modifver;
2633 chunk = search_read_chunk(sf, offset);
2634 pthread_mutex_unlock(&sshfs.lock);
2636 if (chunk && chunk->size < size) {
2638 size -= chunk->size;
2639 offset += chunk->size;
2644 submit_read(sf, size, offset, &chunk);
2646 if (curr_is_seq && chunk && chunk->size <= size)
2647 submit_read(sf, origsize, offset + size, &sf->readahead);
2650 size_t prev_size = chunk_prev->size;
2651 res = wait_chunk(chunk_prev, rbuf, prev_size);
2652 if (res < (int) prev_size) {
2653 chunk_put_locked(chunk);
2659 res = wait_chunk(chunk, rbuf, size);
2668 static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
2669 struct fuse_file_info *fi)
2671 struct sshfs_file *sf = get_sshfs_file(fi);
2674 if (!sshfs_file_is_conn(sf))
2677 if (sshfs.sync_read)
2678 return sshfs_sync_read(sf, rbuf, size, offset);
2680 return sshfs_async_read(sf, rbuf, size, offset);
2683 static void sshfs_write_begin(struct request *req)
2685 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2688 list_add(&req->list, &sf->write_reqs);
2691 static void sshfs_write_end(struct request *req)
2694 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2697 sf->write_error = req->error;
2698 else if (req->replied) {
2699 if (req->reply_type != SSH_FXP_STATUS) {
2700 fprintf(stderr, "protocol error\n");
2701 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2702 serr != SSH_FX_OK) {
2703 sf->write_error = -EIO;
2706 list_del(&req->list);
2707 pthread_cond_broadcast(&sf->write_finished);
2711 static int sshfs_async_write(struct sshfs_file *sf, const char *wbuf,
2712 size_t size, off_t offset)
2715 struct buffer *handle = &sf->handle;
2717 while (!err && size) {
2719 struct iovec iov[2];
2720 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2723 buf_add_buf(&buf, handle);
2724 buf_add_uint64(&buf, offset);
2725 buf_add_uint32(&buf, bsize);
2726 buf_to_iov(&buf, &iov[0]);
2727 iov[1].iov_base = (void *) wbuf;
2728 iov[1].iov_len = bsize;
2729 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2730 sshfs_write_begin, sshfs_write_end,
2741 static void sshfs_sync_write_begin(struct request *req)
2743 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2747 static void sshfs_sync_write_end(struct request *req)
2750 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2753 sio->error = req->error;
2754 } else if (req->replied) {
2755 if (req->reply_type != SSH_FXP_STATUS) {
2756 fprintf(stderr, "protocol error\n");
2757 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2758 serr != SSH_FX_OK) {
2764 pthread_cond_broadcast(&sio->finished);
2768 static int sshfs_sync_write(struct sshfs_file *sf, const char *wbuf,
2769 size_t size, off_t offset)
2772 struct buffer *handle = &sf->handle;
2773 struct sshfs_io sio = { .error = 0, .num_reqs = 0 };
2775 pthread_cond_init(&sio.finished, NULL);
2777 while (!err && size) {
2779 struct iovec iov[2];
2780 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2783 buf_add_buf(&buf, handle);
2784 buf_add_uint64(&buf, offset);
2785 buf_add_uint32(&buf, bsize);
2786 buf_to_iov(&buf, &iov[0]);
2787 iov[1].iov_base = (void *) wbuf;
2788 iov[1].iov_len = bsize;
2789 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2790 sshfs_sync_write_begin,
2791 sshfs_sync_write_end,
2799 pthread_mutex_lock(&sshfs.lock);
2800 while (sio.num_reqs)
2801 pthread_cond_wait(&sio.finished, &sshfs.lock);
2802 pthread_mutex_unlock(&sshfs.lock);
2810 static int sshfs_write(const char *path, const char *wbuf, size_t size,
2811 off_t offset, struct fuse_file_info *fi)
2814 struct sshfs_file *sf = get_sshfs_file(fi);
2818 if (!sshfs_file_is_conn(sf))
2821 sshfs_inc_modifver();
2823 if (!sshfs.sync_write && !sf->write_error)
2824 err = sshfs_async_write(sf, wbuf, size, offset);
2826 err = sshfs_sync_write(sf, wbuf, size, offset);
2828 return err ? err : (int) size;
2831 static int sshfs_ext_statvfs(const char *path, struct statvfs *stbuf)
2835 struct buffer outbuf;
2837 buf_add_string(&buf, SFTP_EXT_STATVFS);
2838 buf_add_path(&buf, path);
2839 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_EXTENDED_REPLY,
2842 if (buf_get_statvfs(&outbuf, stbuf) == -1)
2851 #if FUSE_VERSION >= 25
2852 static int sshfs_statfs(const char *path, struct statvfs *buf)
2854 if (sshfs.ext_statvfs)
2855 return sshfs_ext_statvfs(path, buf);
2857 buf->f_namemax = 255;
2858 buf->f_bsize = sshfs.blksize;
2860 * df seems to use f_bsize instead of f_frsize, so make them
2863 buf->f_frsize = buf->f_bsize;
2864 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2865 1000ULL * 1024 * 1024 * 1024 / buf->f_frsize;
2866 buf->f_files = buf->f_ffree = 1000000000;
2870 static int sshfs_statfs(const char *path, struct statfs *buf)
2872 if (sshfs.ext_statvfs) {
2874 struct statvfs vbuf;
2876 err = sshfs_ext_statvfs(path, &vbuf);
2878 buf->f_bsize = vbuf.f_bsize;
2879 buf->f_blocks = vbuf.f_blocks;
2880 buf->f_bfree = vbuf.f_bfree;
2881 buf->f_bavail = vbuf.f_bavail;
2882 buf->f_files = vbuf.f_files;
2883 buf->f_ffree = vbuf.f_ffree;
2884 buf->f_namelen = vbuf.f_namemax;
2889 buf->f_namelen = 255;
2890 buf->f_bsize = sshfs.blksize;
2891 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2892 1000ULL * 1024 * 1024 * 1024 / buf->f_bsize;
2893 buf->f_files = buf->f_ffree = 1000000000;
2898 #if FUSE_VERSION >= 25
2899 static int sshfs_create(const char *path, mode_t mode,
2900 struct fuse_file_info *fi)
2902 return sshfs_open_common(path, mode, fi);
2905 static int sshfs_ftruncate(const char *path, off_t size,
2906 struct fuse_file_info *fi)
2910 struct sshfs_file *sf = get_sshfs_file(fi);
2914 if (!sshfs_file_is_conn(sf))
2917 sshfs_inc_modifver();
2918 if (sshfs.truncate_workaround)
2919 return sshfs_truncate_workaround(path, size, fi);
2922 buf_add_buf(&buf, &sf->handle);
2923 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2924 buf_add_uint64(&buf, size);
2925 err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL);
2932 static int sshfs_fgetattr(const char *path, struct stat *stbuf,
2933 struct fuse_file_info *fi)
2937 struct buffer outbuf;
2938 struct sshfs_file *sf = get_sshfs_file(fi);
2942 if (!sshfs_file_is_conn(sf))
2945 if (sshfs.fstat_workaround)
2946 return sshfs_getattr(path, stbuf);
2949 buf_add_buf(&buf, &sf->handle);
2950 err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
2952 err = buf_get_attrs(&outbuf, stbuf, NULL);
2959 static int sshfs_truncate_zero(const char *path)
2962 struct fuse_file_info fi;
2964 fi.flags = O_WRONLY | O_TRUNC;
2965 err = sshfs_open(path, &fi);
2967 sshfs_release(path, &fi);
2972 static size_t calc_buf_size(off_t size, off_t offset)
2974 return offset + sshfs.max_read < size ? sshfs.max_read : size - offset;
2977 static int sshfs_truncate_shrink(const char *path, off_t size)
2982 struct fuse_file_info fi;
2984 data = calloc(size, 1);
2988 fi.flags = O_RDONLY;
2989 res = sshfs_open(path, &fi);
2993 for (offset = 0; offset < size; offset += res) {
2994 size_t bufsize = calc_buf_size(size, offset);
2995 res = sshfs_read(path, data + offset, bufsize, offset, &fi);
2999 sshfs_release(path, &fi);
3003 fi.flags = O_WRONLY | O_TRUNC;
3004 res = sshfs_open(path, &fi);
3008 for (offset = 0; offset < size; offset += res) {
3009 size_t bufsize = calc_buf_size(size, offset);
3010 res = sshfs_write(path, data + offset, bufsize, offset, &fi);
3015 res = sshfs_flush(path, &fi);
3016 sshfs_release(path, &fi);
3023 static int sshfs_truncate_extend(const char *path, off_t size,
3024 struct fuse_file_info *fi)
3028 struct fuse_file_info tmpfi;
3029 struct fuse_file_info *openfi = fi;
3032 openfi->flags = O_WRONLY;
3033 res = sshfs_open(path, openfi);
3037 res = sshfs_write(path, &c, 1, size - 1, openfi);
3039 res = sshfs_flush(path, openfi);
3041 sshfs_release(path, openfi);
3047 * Work around broken sftp servers which don't handle
3048 * SSH_FILEXFER_ATTR_SIZE in SETSTAT request.
3050 * If new size is zero, just open the file with O_TRUNC.
3052 * If new size is smaller than current size, then copy file locally,
3053 * then open/trunc and send it back.
3055 * If new size is greater than current size, then write a zero byte to
3056 * the new end of the file.
3058 static int sshfs_truncate_workaround(const char *path, off_t size,
3059 struct fuse_file_info *fi)
3062 return sshfs_truncate_zero(path);
3067 err = sshfs_fgetattr(path, &stbuf, fi);
3069 err = sshfs_getattr(path, &stbuf);
3072 if (stbuf.st_size == size)
3074 else if (stbuf.st_size > size)
3075 return sshfs_truncate_shrink(path, size);
3077 return sshfs_truncate_extend(path, size, fi);
3081 static int processing_init(void)
3083 signal(SIGPIPE, SIG_IGN);
3085 pthread_mutex_init(&sshfs.lock, NULL);
3086 pthread_mutex_init(&sshfs.lock_write, NULL);
3087 pthread_cond_init(&sshfs.outstanding_cond, NULL);
3088 sshfs.reqtab = g_hash_table_new(NULL, NULL);
3089 if (!sshfs.reqtab) {
3090 fprintf(stderr, "failed to create hash table\n");
3096 static struct fuse_cache_operations sshfs_oper = {
3099 .getattr = sshfs_getattr,
3100 .readlink = sshfs_readlink,
3101 .mknod = sshfs_mknod,
3102 .mkdir = sshfs_mkdir,
3103 .symlink = sshfs_symlink,
3104 .unlink = sshfs_unlink,
3105 .rmdir = sshfs_rmdir,
3106 .rename = sshfs_rename,
3108 .chmod = sshfs_chmod,
3109 .chown = sshfs_chown,
3110 .truncate = sshfs_truncate,
3111 .utime = sshfs_utime,
3113 .flush = sshfs_flush,
3114 .fsync = sshfs_fsync,
3115 .release = sshfs_release,
3117 .write = sshfs_write,
3118 .statfs = sshfs_statfs,
3119 #if FUSE_VERSION >= 25
3120 .create = sshfs_create,
3121 .ftruncate = sshfs_ftruncate,
3122 .fgetattr = sshfs_fgetattr,
3125 .cache_getdir = sshfs_getdir,
3128 static void usage(const char *progname)
3131 "usage: %s [user@]host:[dir] mountpoint [options]\n"
3133 "general options:\n"
3134 " -o opt,[opt...] mount options\n"
3135 " -h --help print help\n"
3136 " -V --version print version\n"
3139 " -p PORT equivalent to '-o port=PORT'\n"
3140 " -C equivalent to '-o compression=yes'\n"
3141 " -F ssh_configfile specifies alternative ssh configuration file\n"
3142 " -1 equivalent to '-o ssh_protocol=1'\n"
3143 " -o reconnect reconnect to server\n"
3144 " -o delay_connect delay connection to server\n"
3145 " -o sshfs_sync synchronous writes\n"
3146 " -o no_readahead synchronous reads (no speculative readahead)\n"
3147 " -o sshfs_debug print some debugging information\n"
3148 " -o cache=BOOL enable caching {yes,no} (default: yes)\n"
3149 " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
3150 " -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n"
3151 " -o workaround=LIST colon separated list of workarounds\n"
3152 " none no workarounds enabled\n"
3153 " all all workarounds enabled\n"
3154 " [no]rename fix renaming to existing file (default: off)\n"
3155 #ifdef SSH_NODELAY_WORKAROUND
3156 " [no]nodelay set nodelay tcp flag in ssh (default: on)\n"
3158 " [no]nodelaysrv set nodelay tcp flag in sshd (default: off)\n"
3159 " [no]truncate fix truncate for old servers (default: off)\n"
3160 " [no]buflimit fix buffer fillup bug in server (default: on)\n"
3161 " -o idmap=TYPE user/group ID mapping, possible types are:\n"
3162 " none no translation of the ID space (default)\n"
3163 " user only translate UID of connecting user\n"
3164 " file translate UIDs/GIDs contained in uidfile/gidfile\n"
3165 " -o uidfile=FILE file containing username:remote_uid mappings\n"
3166 " -o gidfile=FILE file containing groupname:remote_gid mappings\n"
3167 " -o nomap=TYPE with idmap=file, how to handle missing mappings\n"
3168 " ignore don't do any re-mapping\n"
3169 " error return an error (default)\n"
3170 " -o ssh_command=CMD execute CMD instead of 'ssh'\n"
3171 " -o ssh_protocol=N ssh protocol to use (default: 2)\n"
3172 " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n"
3173 " -o directport=PORT directly connect to PORT bypassing ssh\n"
3174 " -o transform_symlinks transform absolute symlinks to relative\n"
3175 " -o follow_symlinks follow symlinks on the server\n"
3176 " -o no_check_root don't check for existence of 'dir' on server\n"
3177 " -o password_stdin read password from stdin (only for pam_mount!)\n"
3178 " -o SSHOPT=VAL ssh options (see man ssh_config)\n"
3182 static int is_ssh_opt(const char *arg)
3184 if (arg[0] != '-') {
3185 unsigned arglen = strlen(arg);
3187 for (o = ssh_opts; *o; o++) {
3188 unsigned olen = strlen(*o);
3189 if (arglen > olen && arg[olen] == '=' &&
3190 strncasecmp(arg, *o, olen) == 0)
3197 static int sshfs_fuse_main(struct fuse_args *args)
3199 #if FUSE_VERSION >= 26
3200 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL);
3202 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper));
3206 static int sshfs_opt_proc(void *data, const char *arg, int key,
3207 struct fuse_args *outargs)
3213 case FUSE_OPT_KEY_OPT:
3214 if (is_ssh_opt(arg)) {
3215 tmp = g_strdup_printf("-o%s", arg);
3222 case FUSE_OPT_KEY_NONOPT:
3223 if (!sshfs.host && strchr(arg, ':')) {
3224 sshfs.host = strdup(arg);
3230 tmp = g_strdup_printf("-oPort=%s", arg + 2);
3236 ssh_add_arg("-oCompression=yes");
3239 case KEY_CONFIGFILE:
3240 tmp = g_strdup_printf("-F%s", arg + 2);
3246 usage(outargs->argv[0]);
3247 fuse_opt_add_arg(outargs, "-ho");
3248 sshfs_fuse_main(outargs);
3252 printf("SSHFS version %s\n", PACKAGE_VERSION);
3253 #if FUSE_VERSION >= 25
3254 fuse_opt_add_arg(outargs, "--version");
3255 sshfs_fuse_main(outargs);
3259 case KEY_FOREGROUND:
3260 sshfs.foreground = 1;
3264 fprintf(stderr, "internal error\n");
3269 static int workaround_opt_proc(void *data, const char *arg, int key,
3270 struct fuse_args *outargs)
3272 (void) data; (void) key; (void) outargs;
3273 fprintf(stderr, "unknown workaround: '%s'\n", arg);
3277 int parse_workarounds(void)
3280 char *argv[] = { "", "-o", sshfs.workarounds, NULL };
3281 struct fuse_args args = FUSE_ARGS_INIT(3, argv);
3282 char *s = sshfs.workarounds;
3286 while ((s = strchr(s, ':')))
3289 res = fuse_opt_parse(&args, &sshfs, workaround_opts,
3290 workaround_opt_proc);
3291 fuse_opt_free_args(&args);
3296 #if FUSE_VERSION == 25
3297 static int fuse_opt_insert_arg(struct fuse_args *args, int pos,
3300 assert(pos <= args->argc);
3301 if (fuse_opt_add_arg(args, arg) == -1)
3304 if (pos != args->argc - 1) {
3305 char *newarg = args->argv[args->argc - 1];
3306 memmove(&args->argv[pos + 1], &args->argv[pos],
3307 sizeof(char *) * (args->argc - pos - 1));
3308 args->argv[pos] = newarg;
3314 static void check_large_read(struct fuse_args *args)
3317 int err = uname(&buf);
3318 if (!err && strcmp(buf.sysname, "Linux") == 0 &&
3319 strncmp(buf.release, "2.4.", 4) == 0)
3320 fuse_opt_insert_arg(args, 1, "-olarge_read");
3323 static int read_password(void)
3325 int size = getpagesize();
3326 int max_password = 64;
3329 sshfs.password = mmap(NULL, size, PROT_READ | PROT_WRITE,
3330 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED,
3332 if (sshfs.password == MAP_FAILED) {
3333 perror("Failed to allocate locked page for password");
3337 /* Don't use fgets() because password might stay in memory */
3338 for (n = 0; n < max_password; n++) {
3341 res = read(0, &sshfs.password[n], 1);
3343 perror("Reading password");
3347 sshfs.password[n] = '\n';
3350 if (sshfs.password[n] == '\n')
3353 if (n == max_password) {
3354 fprintf(stderr, "Password too long\n");
3357 sshfs.password[n+1] = '\0';
3358 ssh_add_arg("-oNumberOfPasswordPrompts=1");
3363 static void set_ssh_command(void)
3370 d = sshfs.ssh_command;
3371 s = sshfs.ssh_command;
3379 replace_arg(&sshfs.ssh_args.argv[0],
3382 if (fuse_opt_insert_arg(&sshfs.ssh_args, i,
3383 sshfs.ssh_command) == -1)
3387 d = sshfs.ssh_command;
3400 static char *find_base_path(void)
3402 char *s = sshfs.host;
3405 for (; *s && *s != ':'; s++) {
3408 * Handle IPv6 numerical address enclosed in square
3412 for (; *s != ']'; s++) {
3414 fprintf(stderr, "missing ']' in hostname\n");
3431 * Remove commas from fsname, as it confuses the fuse option parser.
3433 static void fsname_remove_commas(char *fsname)
3435 if (strchr(fsname, ',') != NULL) {
3447 #if FUSE_VERSION >= 27
3448 static char *fsname_escape_commas(char *fsnameold)
3450 char *fsname = g_malloc(strlen(fsnameold) * 2 + 1);
3454 for (s = fsnameold; *s; s++) {
3455 if (*s == '\\' || *s == ',')
3466 static int ssh_connect(void)
3470 res = processing_init();
3474 if (!sshfs.delay_connect) {
3475 if (connect_remote() == -1)
3478 if (!sshfs.no_check_root &&
3479 sftp_check_root(sshfs.base_path) != 0)
3486 /* remove trailing '\n', like the perl func of the same name */
3487 static inline void chomp(char *line)
3490 if ((p = strrchr(line, '\n')))
3494 /* number of ':' separated fields in a passwd/group file that we care
3496 #define IDMAP_FIELDS 3
3498 /* given a line from a uidmap or gidmap, parse out the name and id */
3499 static void parse_idmap_line(char *line, const char* filename,
3500 const unsigned int lineno, uint32_t *ret_id, char **ret_name)
3503 char *tokens[IDMAP_FIELDS];
3506 for (i = 0; (tok = strsep(&line, ":")) && (i < IDMAP_FIELDS) ; i++) {
3510 char *name_tok, *id_tok;
3512 /* assume name:id format */
3513 name_tok = tokens[0];
3515 } else if (i >= IDMAP_FIELDS) {
3516 /* assume passwd/group file format */
3517 name_tok = tokens[0];
3520 fprintf(stderr, "Unknown format at line %u of '%s'\n",
3526 uint32_t remote_id = strtoul(id_tok, NULL, 10);
3528 fprintf(stderr, "Invalid id number on line %u of '%s': %s\n",
3529 lineno, filename, strerror(errno));
3533 *ret_name = strdup(name_tok);
3534 *ret_id = remote_id;
3537 /* read a uidmap or gidmap */
3538 static void read_id_map(char *file, uint32_t *(*map_fn)(char *),
3539 const char *name_id, GHashTable **idmap, GHashTable **r_idmap)
3541 *idmap = g_hash_table_new(NULL, NULL);
3542 *r_idmap = g_hash_table_new(NULL, NULL);
3546 unsigned int lineno = 0;
3548 fp = fopen(file, "r");
3550 fprintf(stderr, "failed to open '%s': %s\n",
3551 file, strerror(errno));
3555 while (getline(&line, &len, fp) != EOF) {
3560 parse_idmap_line(line, file, lineno, &remote_id, &name);
3562 uint32_t *local_id = map_fn(name);
3563 if (local_id == NULL) {
3565 DEBUG("%s(%u): no local %s\n", name, remote_id, name_id);
3570 DEBUG("%s: remote %s %u => local %s %u\n",
3571 name, name_id, remote_id, name_id, *local_id);
3572 g_hash_table_insert(*idmap, GUINT_TO_POINTER(remote_id), GUINT_TO_POINTER(*local_id));
3573 g_hash_table_insert(*r_idmap, GUINT_TO_POINTER(*local_id), GUINT_TO_POINTER(remote_id));
3578 if (fclose(fp) == EOF) {
3579 fprintf(stderr, "failed to close '%s': %s",
3580 file, strerror(errno));
3588 /* given a username, return a pointer to its uid, or NULL if it doesn't
3589 * exist on this system */
3590 static uint32_t *username_to_uid(char *name)
3593 struct passwd *pw = getpwnam(name);
3596 /* "does not exist" */
3599 fprintf(stderr, "Failed to look up user '%s': %s\n",
3600 name, strerror(errno));
3603 uint32_t *r = malloc(sizeof(uint32_t));
3605 fprintf(stderr, "sshfs: memory allocation failed\n");
3612 /* given a groupname, return a pointer to its gid, or NULL if it doesn't
3613 * exist on this system */
3614 static uint32_t *groupname_to_gid(char *name)
3617 struct group *gr = getgrnam(name);
3620 /* "does not exist" */
3623 fprintf(stderr, "Failed to look up group '%s': %s\n",
3624 name, strerror(errno));
3627 uint32_t *r = malloc(sizeof(uint32_t));
3629 fprintf(stderr, "sshfs: memory allocation failed\n");
3636 static inline void load_uid_map(void)
3638 read_id_map(sshfs.uid_file, &username_to_uid, "uid", &sshfs.uid_map, &sshfs.r_uid_map);
3641 static inline void load_gid_map(void)
3643 read_id_map(sshfs.gid_file, &groupname_to_gid, "gid", &sshfs.gid_map, &sshfs.r_gid_map);
3646 int main(int argc, char *argv[])
3649 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3652 const char *sftp_server;
3655 g_thread_init(NULL);
3657 sshfs.blksize = 4096;
3658 /* SFTP spec says all servers should allow at least 32k I/O */
3659 sshfs.max_read = 32768;
3660 sshfs.max_write = 32768;
3661 sshfs.nodelay_workaround = 1;
3662 sshfs.nodelaysrv_workaround = 0;
3663 sshfs.rename_workaround = 0;
3664 sshfs.truncate_workaround = 0;
3665 sshfs.buflimit_workaround = 1;
3667 sshfs.progname = argv[0];
3670 sshfs.ptyslavefd = -1;
3671 sshfs.delay_connect = 0;
3672 sshfs.detect_uid = 0;
3673 sshfs.idmap = IDMAP_NONE;
3674 sshfs.nomap = NOMAP_ERROR;
3678 ssh_add_arg("-oClearAllForwardings=yes");
3680 if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 ||
3681 parse_workarounds() == -1)
3684 if (sshfs.idmap == IDMAP_USER)
3685 sshfs.detect_uid = 1;
3686 else if (sshfs.idmap == IDMAP_FILE) {
3687 sshfs.uid_map = NULL;
3688 sshfs.gid_map = NULL;
3689 sshfs.r_uid_map = NULL;
3690 sshfs.r_gid_map = NULL;
3691 if (!sshfs.uid_file && !sshfs.gid_file) {
3692 fprintf(stderr, "need a uid_file or gid_file with idmap=file\n");
3700 free(sshfs.uid_file);
3701 free(sshfs.gid_file);
3703 DEBUG("SSHFS version %s\n", PACKAGE_VERSION);
3705 if (sshfs.password_stdin) {
3706 res = read_password();
3711 if (sshfs.buflimit_workaround)
3712 /* Work around buggy sftp-server in OpenSSH. Without this on
3713 a slow server a 10Mbyte buffer would fill up and the server
3715 sshfs.max_outstanding_len = 8388608;
3717 sshfs.max_outstanding_len = ~0;
3720 fprintf(stderr, "missing host\n");
3721 fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
3725 fsname = g_strdup(sshfs.host);
3726 sshfs.base_path = g_strdup(find_base_path());
3728 if (sshfs.ssh_command)
3731 tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
3734 ssh_add_arg(sshfs.host);
3735 if (sshfs.sftp_server)
3736 sftp_server = sshfs.sftp_server;
3737 else if (sshfs.ssh_ver == 1)
3738 sftp_server = SFTP_SERVER_PATH;
3740 sftp_server = "sftp";
3742 if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
3745 ssh_add_arg(sftp_server);
3746 free(sshfs.sftp_server);
3749 res = cache_parse_options(&args);
3753 sshfs.randseed = time(0);
3755 if (sshfs.max_read > 65536)
3756 sshfs.max_read = 65536;
3757 if (sshfs.max_write > 65536)
3758 sshfs.max_write = 65536;
3760 if (fuse_is_lib_option("ac_attr_timeout="))
3761 fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
3762 #if FUSE_VERSION >= 27
3763 libver = fuse_version();
3764 assert(libver >= 27);
3766 fsname = fsname_escape_commas(fsname);
3768 fsname_remove_commas(fsname);
3769 tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
3771 fsname_remove_commas(fsname);
3772 tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
3774 fuse_opt_insert_arg(&args, 1, tmp);
3777 check_large_read(&args);
3779 #if FUSE_VERSION >= 26
3782 struct fuse_chan *ch;
3788 res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded,
3793 res = stat(mountpoint, &st);
3798 sshfs.mnt_mode = st.st_mode;
3800 ch = fuse_mount(mountpoint, &args);
3804 res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC);
3806 perror("WARNING: failed to set FD_CLOEXEC on fuse device");
3808 fuse = fuse_new(ch, &args, cache_init(&sshfs_oper),
3809 sizeof(struct fuse_operations), NULL);
3811 fuse_unmount(mountpoint, ch);
3815 res = ssh_connect();
3817 fuse_unmount(mountpoint, ch);
3822 res = fuse_daemonize(foreground);
3824 res = fuse_set_signal_handlers(fuse_get_session(fuse));
3827 fuse_unmount(mountpoint, ch);
3833 res = fuse_loop_mt(fuse);
3835 res = fuse_loop(fuse);
3842 fuse_remove_signal_handlers(fuse_get_session(fuse));
3843 fuse_unmount(mountpoint, ch);
3848 res = ssh_connect();
3852 res = sshfs_fuse_main(&args);
3856 unsigned int avg_rtt = 0;
3859 avg_rtt = sshfs.total_rtt / sshfs.num_sent;
3862 "sent: %llu messages, %llu bytes\n"
3863 "received: %llu messages, %llu bytes\n"
3864 "rtt min/max/avg: %ums/%ums/%ums\n"
3865 "num connect: %u\n",
3866 (unsigned long long) sshfs.num_sent,
3867 (unsigned long long) sshfs.bytes_sent,
3868 (unsigned long long) sshfs.num_received,
3869 (unsigned long long) sshfs.bytes_received,
3870 sshfs.min_rtt, sshfs.max_rtt, avg_rtt,
3874 fuse_opt_free_args(&args);
3875 fuse_opt_free_args(&sshfs.ssh_args);
3876 free(sshfs.directport);