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>
45 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
46 #define MAP_ANONYMOUS MAP_ANON
50 #define SSH_FXP_INIT 1
51 #define SSH_FXP_VERSION 2
52 #define SSH_FXP_OPEN 3
53 #define SSH_FXP_CLOSE 4
54 #define SSH_FXP_READ 5
55 #define SSH_FXP_WRITE 6
56 #define SSH_FXP_LSTAT 7
57 #define SSH_FXP_FSTAT 8
58 #define SSH_FXP_SETSTAT 9
59 #define SSH_FXP_FSETSTAT 10
60 #define SSH_FXP_OPENDIR 11
61 #define SSH_FXP_READDIR 12
62 #define SSH_FXP_REMOVE 13
63 #define SSH_FXP_MKDIR 14
64 #define SSH_FXP_RMDIR 15
65 #define SSH_FXP_REALPATH 16
66 #define SSH_FXP_STAT 17
67 #define SSH_FXP_RENAME 18
68 #define SSH_FXP_READLINK 19
69 #define SSH_FXP_SYMLINK 20
70 #define SSH_FXP_STATUS 101
71 #define SSH_FXP_HANDLE 102
72 #define SSH_FXP_DATA 103
73 #define SSH_FXP_NAME 104
74 #define SSH_FXP_ATTRS 105
75 #define SSH_FXP_EXTENDED 200
76 #define SSH_FXP_EXTENDED_REPLY 201
78 #define SSH_FILEXFER_ATTR_SIZE 0x00000001
79 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002
80 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
81 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
82 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
86 #define SSH_FX_NO_SUCH_FILE 2
87 #define SSH_FX_PERMISSION_DENIED 3
88 #define SSH_FX_FAILURE 4
89 #define SSH_FX_BAD_MESSAGE 5
90 #define SSH_FX_NO_CONNECTION 6
91 #define SSH_FX_CONNECTION_LOST 7
92 #define SSH_FX_OP_UNSUPPORTED 8
94 #define SSH_FXF_READ 0x00000001
95 #define SSH_FXF_WRITE 0x00000002
96 #define SSH_FXF_APPEND 0x00000004
97 #define SSH_FXF_CREAT 0x00000008
98 #define SSH_FXF_TRUNC 0x00000010
99 #define SSH_FXF_EXCL 0x00000020
101 /* statvfs@openssh.com f_flag flags */
102 #define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001
103 #define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002
105 #define SFTP_EXT_POSIX_RENAME "posix-rename@openssh.com"
106 #define SFTP_EXT_STATVFS "statvfs@openssh.com"
107 #define SFTP_EXT_HARDLINK "hardlink@openssh.com"
109 #define PROTO_VERSION 3
113 #define MAX_REPLY_LEN (1 << 17)
115 #define RENAME_TEMP_CHARS 8
117 #define SFTP_SERVER_PATH "/usr/lib/sftp-server"
119 #define SSHNODELAY_SO "sshnodelay.so"
128 struct list_head *prev;
129 struct list_head *next;
133 typedef void (*request_func)(struct request *);
136 unsigned int want_reply;
142 struct timeval start;
144 request_func end_func;
146 struct list_head list;
151 pthread_cond_t finished;
156 struct sshfs_io *sio;
157 struct list_head list;
168 struct list_head reqs;
173 struct buffer handle;
174 struct list_head write_reqs;
175 pthread_cond_t write_finished;
177 struct read_chunk *readahead;
189 struct fuse_args ssh_args;
191 int rename_workaround;
192 int nodelay_workaround;
193 int nodelaysrv_workaround;
194 int truncate_workaround;
195 int buflimit_workaround;
196 int fstat_workaround;
197 int transform_symlinks;
213 pthread_mutex_t lock;
214 pthread_mutex_t lock_write;
215 int processing_thread_started;
216 unsigned int randseed;
224 int remote_uid_detected;
228 unsigned outstanding_len;
229 unsigned max_outstanding_len;
230 pthread_cond_t outstanding_cond;
233 int ext_posix_rename;
240 uint64_t bytes_received;
242 uint64_t num_received;
243 unsigned int min_rtt;
244 unsigned int max_rtt;
246 unsigned int num_connect;
249 static struct sshfs sshfs;
251 static const char *ssh_opts[] = {
255 "ChallengeResponseAuthentication",
261 "ConnectionAttempts",
265 "GlobalKnownHostsFile",
266 "GSSAPIAuthentication",
267 "GSSAPIDelegateCredentials",
268 "HostbasedAuthentication",
274 "KbdInteractiveAuthentication",
275 "KbdInteractiveDevices",
279 "NoHostAuthenticationForLocalhost",
280 "NumberOfPasswordPrompts",
281 "PasswordAuthentication",
283 "PreferredAuthentications",
285 "PubkeyAuthentication",
287 "RhostsRSAAuthentication",
289 "ServerAliveCountMax",
290 "ServerAliveInterval",
292 "StrictHostKeyChecking",
295 "UserKnownHostsFile",
309 #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
311 static struct fuse_opt sshfs_opts[] = {
312 SSHFS_OPT("directport=%s", directport, 0),
313 SSHFS_OPT("ssh_command=%s", ssh_command, 0),
314 SSHFS_OPT("sftp_server=%s", sftp_server, 0),
315 SSHFS_OPT("max_read=%u", max_read, 0),
316 SSHFS_OPT("max_write=%u", max_write, 0),
317 SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0),
318 SSHFS_OPT("-1", ssh_ver, 1),
319 SSHFS_OPT("workaround=%s", workarounds, 0),
320 SSHFS_OPT("idmap=none", detect_uid, 0),
321 SSHFS_OPT("idmap=user", detect_uid, 1),
322 SSHFS_OPT("sshfs_sync", sync_write, 1),
323 SSHFS_OPT("no_readahead", sync_read, 1),
324 SSHFS_OPT("sshfs_debug", debug, 1),
325 SSHFS_OPT("reconnect", reconnect, 1),
326 SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
327 SSHFS_OPT("follow_symlinks", follow_symlinks, 1),
328 SSHFS_OPT("no_check_root", no_check_root, 1),
329 SSHFS_OPT("password_stdin", password_stdin, 1),
330 SSHFS_OPT("delay_connect", delay_connect, 1),
332 FUSE_OPT_KEY("-p ", KEY_PORT),
333 FUSE_OPT_KEY("-C", KEY_COMPRESS),
334 FUSE_OPT_KEY("-V", KEY_VERSION),
335 FUSE_OPT_KEY("--version", KEY_VERSION),
336 FUSE_OPT_KEY("-h", KEY_HELP),
337 FUSE_OPT_KEY("--help", KEY_HELP),
338 FUSE_OPT_KEY("debug", KEY_FOREGROUND),
339 FUSE_OPT_KEY("-d", KEY_FOREGROUND),
340 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
341 FUSE_OPT_KEY("-F ", KEY_CONFIGFILE),
345 static struct fuse_opt workaround_opts[] = {
346 SSHFS_OPT("none", rename_workaround, 0),
347 SSHFS_OPT("none", nodelay_workaround, 0),
348 SSHFS_OPT("none", nodelaysrv_workaround, 0),
349 SSHFS_OPT("none", truncate_workaround, 0),
350 SSHFS_OPT("none", buflimit_workaround, 0),
351 SSHFS_OPT("none", fstat_workaround, 0),
352 SSHFS_OPT("all", rename_workaround, 1),
353 SSHFS_OPT("all", nodelay_workaround, 1),
354 SSHFS_OPT("all", nodelaysrv_workaround, 1),
355 SSHFS_OPT("all", truncate_workaround, 1),
356 SSHFS_OPT("all", buflimit_workaround, 1),
357 SSHFS_OPT("all", fstat_workaround, 1),
358 SSHFS_OPT("rename", rename_workaround, 1),
359 SSHFS_OPT("norename", rename_workaround, 0),
360 SSHFS_OPT("nodelay", nodelay_workaround, 1),
361 SSHFS_OPT("nonodelay", nodelay_workaround, 0),
362 SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1),
363 SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0),
364 SSHFS_OPT("truncate", truncate_workaround, 1),
365 SSHFS_OPT("notruncate", truncate_workaround, 0),
366 SSHFS_OPT("buflimit", buflimit_workaround, 1),
367 SSHFS_OPT("nobuflimit", buflimit_workaround, 0),
368 SSHFS_OPT("fstat", fstat_workaround, 1),
369 SSHFS_OPT("nofstat", fstat_workaround, 0),
373 #define DEBUG(format, args...) \
374 do { if (sshfs.debug) fprintf(stderr, format, args); } while(0)
376 static const char *type_name(uint8_t type)
379 case SSH_FXP_INIT: return "INIT";
380 case SSH_FXP_VERSION: return "VERSION";
381 case SSH_FXP_OPEN: return "OPEN";
382 case SSH_FXP_CLOSE: return "CLOSE";
383 case SSH_FXP_READ: return "READ";
384 case SSH_FXP_WRITE: return "WRITE";
385 case SSH_FXP_LSTAT: return "LSTAT";
386 case SSH_FXP_FSTAT: return "FSTAT";
387 case SSH_FXP_SETSTAT: return "SETSTAT";
388 case SSH_FXP_FSETSTAT: return "FSETSTAT";
389 case SSH_FXP_OPENDIR: return "OPENDIR";
390 case SSH_FXP_READDIR: return "READDIR";
391 case SSH_FXP_REMOVE: return "REMOVE";
392 case SSH_FXP_MKDIR: return "MKDIR";
393 case SSH_FXP_RMDIR: return "RMDIR";
394 case SSH_FXP_REALPATH: return "REALPATH";
395 case SSH_FXP_STAT: return "STAT";
396 case SSH_FXP_RENAME: return "RENAME";
397 case SSH_FXP_READLINK: return "READLINK";
398 case SSH_FXP_SYMLINK: return "SYMLINK";
399 case SSH_FXP_STATUS: return "STATUS";
400 case SSH_FXP_HANDLE: return "HANDLE";
401 case SSH_FXP_DATA: return "DATA";
402 case SSH_FXP_NAME: return "NAME";
403 case SSH_FXP_ATTRS: return "ATTRS";
404 case SSH_FXP_EXTENDED: return "EXTENDED";
405 case SSH_FXP_EXTENDED_REPLY: return "EXTENDED_REPLY";
406 default: return "???";
410 #define container_of(ptr, type, member) ({ \
411 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
412 (type *)( (char *)__mptr - offsetof(type,member) );})
414 #define list_entry(ptr, type, member) \
415 container_of(ptr, type, member)
417 static void list_init(struct list_head *head)
423 static void list_add(struct list_head *new, struct list_head *head)
425 struct list_head *prev = head;
426 struct list_head *next = head->next;
433 static void list_del(struct list_head *entry)
435 struct list_head *prev = entry->prev;
436 struct list_head *next = entry->next;
442 static int list_empty(const struct list_head *head)
444 return head->next == head;
447 static inline void buf_init(struct buffer *buf, size_t size)
450 buf->p = (uint8_t *) malloc(size);
452 fprintf(stderr, "sshfs: memory allocation failed\n");
461 static inline void buf_free(struct buffer *buf)
466 static inline void buf_finish(struct buffer *buf)
468 buf->len = buf->size;
471 static inline void buf_clear(struct buffer *buf)
477 static void buf_resize(struct buffer *buf, size_t len)
479 buf->size = (buf->len + len + 63) & ~31;
480 buf->p = (uint8_t *) realloc(buf->p, buf->size);
482 fprintf(stderr, "sshfs: memory allocation failed\n");
487 static inline void buf_check_add(struct buffer *buf, size_t len)
489 if (buf->len + len > buf->size)
490 buf_resize(buf, len);
493 #define _buf_add_mem(b, d, l) \
494 buf_check_add(b, l); \
495 memcpy(b->p + b->len, d, l); \
499 static inline void buf_add_mem(struct buffer *buf, const void *data,
502 _buf_add_mem(buf, data, len);
505 static inline void buf_add_buf(struct buffer *buf, const struct buffer *bufa)
507 _buf_add_mem(buf, bufa->p, bufa->len);
510 static inline void buf_add_uint8(struct buffer *buf, uint8_t val)
512 _buf_add_mem(buf, &val, 1);
515 static inline void buf_add_uint32(struct buffer *buf, uint32_t val)
517 uint32_t nval = htonl(val);
518 _buf_add_mem(buf, &nval, 4);
521 static inline void buf_add_uint64(struct buffer *buf, uint64_t val)
523 buf_add_uint32(buf, val >> 32);
524 buf_add_uint32(buf, val & 0xffffffff);
527 static inline void buf_add_data(struct buffer *buf, const struct buffer *data)
529 buf_add_uint32(buf, data->len);
530 buf_add_mem(buf, data->p, data->len);
533 static inline void buf_add_string(struct buffer *buf, const char *str)
536 data.p = (uint8_t *) str;
537 data.len = strlen(str);
538 buf_add_data(buf, &data);
541 static inline void buf_add_path(struct buffer *buf, const char *path)
545 if (sshfs.base_path[0]) {
547 if (sshfs.base_path[strlen(sshfs.base_path)-1] != '/') {
548 realpath = g_strdup_printf("%s/%s",
552 realpath = g_strdup_printf("%s%s",
557 realpath = g_strdup(sshfs.base_path);
561 realpath = g_strdup(path + 1);
563 realpath = g_strdup(".");
565 buf_add_string(buf, realpath);
569 static int buf_check_get(struct buffer *buf, size_t len)
571 if (buf->len + len > buf->size) {
572 fprintf(stderr, "buffer too short\n");
578 static inline int buf_get_mem(struct buffer *buf, void *data, size_t len)
580 if (buf_check_get(buf, len) == -1)
582 memcpy(data, buf->p + buf->len, len);
587 static inline int buf_get_uint8(struct buffer *buf, uint8_t *val)
589 return buf_get_mem(buf, val, 1);
592 static inline int buf_get_uint32(struct buffer *buf, uint32_t *val)
595 if (buf_get_mem(buf, &nval, 4) == -1)
601 static inline int buf_get_uint64(struct buffer *buf, uint64_t *val)
605 if (buf_get_uint32(buf, &val1) == -1 ||
606 buf_get_uint32(buf, &val2) == -1) {
609 *val = ((uint64_t) val1 << 32) + val2;
613 static inline int buf_get_data(struct buffer *buf, struct buffer *data)
616 if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len)
618 buf_init(data, len + 1);
620 if (buf_get_mem(buf, data->p, data->size) == -1) {
627 static inline int buf_get_string(struct buffer *buf, char **str)
630 if (buf_get_data(buf, &data) == -1)
632 data.p[data.size] = '\0';
633 *str = (char *) data.p;
637 static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
645 uint32_t mode = S_IFREG | 0777;
647 if (buf_get_uint32(buf, &flags) == -1)
651 if ((flags & SSH_FILEXFER_ATTR_SIZE) &&
652 buf_get_uint64(buf, &size) == -1)
654 if ((flags & SSH_FILEXFER_ATTR_UIDGID) &&
655 (buf_get_uint32(buf, &uid) == -1 ||
656 buf_get_uint32(buf, &gid) == -1))
658 if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
659 buf_get_uint32(buf, &mode) == -1)
661 if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
662 if (buf_get_uint32(buf, &atime) == -1 ||
663 buf_get_uint32(buf, &mtime) == -1)
666 if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) {
669 if (buf_get_uint32(buf, &extcount) == -1)
671 for (i = 0; i < extcount; i++) {
673 if (buf_get_data(buf, &tmp) == -1)
676 if (buf_get_data(buf, &tmp) == -1)
682 if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
683 uid = sshfs.local_uid;
685 memset(stbuf, 0, sizeof(struct stat));
686 stbuf->st_mode = mode;
688 stbuf->st_size = size;
690 stbuf->st_blksize = sshfs.blksize;
691 stbuf->st_blocks = ((size + sshfs.blksize - 1) &
692 ~((unsigned long long) sshfs.blksize - 1)) >> 9;
696 stbuf->st_atime = atime;
697 stbuf->st_ctime = stbuf->st_mtime = mtime;
701 static int buf_get_statvfs(struct buffer *buf, struct statvfs *stbuf)
715 if (buf_get_uint64(buf, &bsize) == -1 ||
716 buf_get_uint64(buf, &frsize) == -1 ||
717 buf_get_uint64(buf, &blocks) == -1 ||
718 buf_get_uint64(buf, &bfree) == -1 ||
719 buf_get_uint64(buf, &bavail) == -1 ||
720 buf_get_uint64(buf, &files) == -1 ||
721 buf_get_uint64(buf, &ffree) == -1 ||
722 buf_get_uint64(buf, &favail) == -1 ||
723 buf_get_uint64(buf, &fsid) == -1 ||
724 buf_get_uint64(buf, &flag) == -1 ||
725 buf_get_uint64(buf, &namemax) == -1) {
729 memset(stbuf, 0, sizeof(struct statvfs));
730 stbuf->f_bsize = bsize;
731 stbuf->f_frsize = frsize;
732 stbuf->f_blocks = blocks;
733 stbuf->f_bfree = bfree;
734 stbuf->f_bavail = bavail;
735 stbuf->f_files = files;
736 stbuf->f_ffree = ffree;
737 stbuf->f_favail = favail;
738 stbuf->f_namemax = namemax;
743 static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
744 fuse_cache_dirfil_t filler)
749 if (buf_get_uint32(buf, &count) == -1)
752 for (i = 0; i < count; i++) {
757 if (buf_get_string(buf, &name) == -1)
759 if (buf_get_string(buf, &longname) != -1) {
761 if (buf_get_attrs(buf, &stbuf, NULL) != -1) {
762 if (sshfs.follow_symlinks &&
763 S_ISLNK(stbuf.st_mode)) {
766 filler(h, name, &stbuf);
777 static void ssh_add_arg(const char *arg)
779 if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1)
783 #ifdef SSH_NODELAY_WORKAROUND
784 static int do_ssh_nodelay_workaround(void)
786 char *oldpreload = getenv("LD_PRELOAD");
788 char sopath[PATH_MAX];
791 snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
792 res = access(sopath, R_OK);
795 if (!realpath(sshfs.progname, sopath))
798 s = strrchr(sopath, '/');
804 if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath))
807 strcpy(s, SSHNODELAY_SO);
808 res = access(sopath, R_OK);
810 fprintf(stderr, "sshfs: cannot find %s\n",
816 newpreload = g_strdup_printf("%s%s%s",
817 oldpreload ? oldpreload : "",
818 oldpreload ? " " : "",
821 if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
822 fprintf(stderr, "warning: failed set LD_PRELOAD "
823 "for ssh nodelay workaround\n");
830 static int pty_expect_loop(void)
834 const char *passwd_str = "assword:";
835 int timeout = 60 * 1000; /* 1min timeout for the prompt to appear */
836 int passwd_len = strlen(passwd_str);
841 struct pollfd fds[2];
843 fds[0].fd = sshfs.fd;
844 fds[0].events = POLLIN;
845 fds[1].fd = sshfs.ptyfd;
846 fds[1].events = POLLIN;
847 res = poll(fds, 2, timeout);
853 fprintf(stderr, "Timeout waiting for prompt\n");
856 if (fds[0].revents) {
858 * Something happened on stdout of ssh, this
859 * either means, that we are connected, or
860 * that we are disconnected. In any case the
861 * password doesn't matter any more.
866 res = read(sshfs.ptyfd, &c, 1);
872 fprintf(stderr, "EOF while waiting for prompt\n");
877 if (len == passwd_len) {
878 if (memcmp(buf, passwd_str, passwd_len) == 0) {
879 write(sshfs.ptyfd, sshfs.password,
880 strlen(sshfs.password));
882 memmove(buf, buf + 1, passwd_len - 1);
887 if (!sshfs.reconnect) {
888 size_t size = getpagesize();
890 memset(sshfs.password, 0, size);
891 munmap(sshfs.password, size);
892 sshfs.password = NULL;
898 static int pty_master(char **name)
902 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
904 perror("failed to open pty");
907 if (grantpt(mfd) != 0) {
911 if (unlockpt(mfd) != 0) {
915 *name = ptsname(mfd);
920 static void replace_arg(char **argp, const char *newarg)
923 *argp = strdup(newarg);
925 fprintf(stderr, "sshfs: memory allocation failed\n");
930 static int start_ssh(void)
932 char *ptyname = NULL;
936 if (sshfs.password_stdin) {
938 sshfs.ptyfd = pty_master(&ptyname);
939 if (sshfs.ptyfd == -1)
942 sshfs.ptyslavefd = open(ptyname, O_RDWR | O_NOCTTY);
943 if (sshfs.ptyslavefd == -1)
947 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) {
948 perror("failed to create socket pair");
951 sshfs.fd = sockpair[0];
955 perror("failed to fork");
958 } else if (pid == 0) {
961 #ifdef SSH_NODELAY_WORKAROUND
962 if (sshfs.nodelay_workaround &&
963 do_ssh_nodelay_workaround() == -1) {
965 "warning: ssh nodelay workaround disabled\n");
969 if (sshfs.nodelaysrv_workaround) {
972 * Hack to work around missing TCP_NODELAY
975 for (i = 1; i < sshfs.ssh_args.argc; i++) {
976 if (strcmp(sshfs.ssh_args.argv[i], "-x") == 0) {
977 replace_arg(&sshfs.ssh_args.argv[i],
984 devnull = open("/dev/null", O_WRONLY);
986 if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) {
987 perror("failed to redirect input/output");
990 if (!sshfs.foreground && devnull != -1)
999 perror("failed to fork");
1008 if (sshfs.password_stdin) {
1012 sfd = open(ptyname, O_RDWR);
1018 close(sshfs.ptyslavefd);
1025 fprintf(stderr, "executing");
1026 for (i = 0; i < sshfs.ssh_args.argc; i++)
1027 fprintf(stderr, " <%s>",
1028 sshfs.ssh_args.argv[i]);
1029 fprintf(stderr, "\n");
1032 execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv);
1033 fprintf(stderr, "failed to execute '%s': %s\n",
1034 sshfs.ssh_args.argv[0], strerror(errno));
1037 waitpid(pid, NULL, 0);
1042 static int connect_to(char *host, char *port)
1047 struct addrinfo *ai;
1048 struct addrinfo hint;
1050 memset(&hint, 0, sizeof(hint));
1051 hint.ai_family = PF_INET;
1052 hint.ai_socktype = SOCK_STREAM;
1053 err = getaddrinfo(host, port, &hint, &ai);
1055 fprintf(stderr, "failed to resolve %s:%s: %s\n", host, port,
1059 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1061 perror("failed to create socket");
1064 err = connect(sock, ai->ai_addr, ai->ai_addrlen);
1066 perror("failed to connect");
1070 err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
1072 perror("warning: failed to set TCP_NODELAY");
1080 static int do_write(struct iovec *iov, size_t count)
1084 res = writev(sshfs.fd, iov, count);
1088 } else if (res == 0) {
1089 fprintf(stderr, "zero write\n");
1093 if ((unsigned) res < iov->iov_len) {
1094 iov->iov_len -= res;
1095 iov->iov_base += res;
1098 res -= iov->iov_len;
1107 static uint32_t sftp_get_id(void)
1109 static uint32_t idctr;
1113 static void buf_to_iov(const struct buffer *buf, struct iovec *iov)
1115 iov->iov_base = buf->p;
1116 iov->iov_len = buf->len;
1119 static size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
1124 for (seg = 0; seg < nr_segs; seg++)
1125 ret += iov[seg].iov_len;
1129 #define SFTP_MAX_IOV 3
1131 static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[],
1136 struct iovec iovout[SFTP_MAX_IOV];
1140 assert(count <= SFTP_MAX_IOV - 1);
1142 buf_add_uint32(&buf, iov_length(iov, count) + 5);
1143 buf_add_uint8(&buf, type);
1144 buf_add_uint32(&buf, id);
1145 buf_to_iov(&buf, &iovout[nout++]);
1146 for (i = 0; i < count; i++)
1147 iovout[nout++] = iov[i];
1148 pthread_mutex_lock(&sshfs.lock_write);
1149 res = do_write(iovout, nout);
1150 pthread_mutex_unlock(&sshfs.lock_write);
1155 static int do_read(struct buffer *buf)
1158 uint8_t *p = buf->p;
1159 size_t size = buf->size;
1161 res = read(sshfs.fd, p, size);
1165 } else if (res == 0) {
1166 fprintf(stderr, "remote host has disconnected\n");
1175 static int sftp_read(uint8_t *type, struct buffer *buf)
1181 res = do_read(&buf2);
1183 if (buf_get_uint32(&buf2, &len) == -1)
1185 if (len > MAX_REPLY_LEN) {
1186 fprintf(stderr, "reply len too large: %u\n", len);
1189 if (buf_get_uint8(&buf2, type) == -1)
1191 buf_init(buf, len - 1);
1198 static void request_free(struct request *req)
1200 buf_free(&req->reply);
1201 sem_destroy(&req->ready);
1205 static void chunk_free(struct read_chunk *chunk)
1207 while (!list_empty(&chunk->reqs)) {
1208 struct read_req *rreq;
1210 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
1211 list_del(&rreq->list);
1212 buf_free(&rreq->data);
1218 static void chunk_put(struct read_chunk *chunk)
1227 static void chunk_put_locked(struct read_chunk *chunk)
1229 pthread_mutex_lock(&sshfs.lock);
1231 pthread_mutex_unlock(&sshfs.lock);
1234 static int clean_req(void *key_, struct request *req)
1239 if (req->want_reply)
1240 sem_post(&req->ready);
1249 static int process_one_request(void)
1254 struct request *req;
1258 res = sftp_read(&type, &buf);
1261 if (buf_get_uint32(&buf, &id) == -1)
1264 pthread_mutex_lock(&sshfs.lock);
1265 req = (struct request *)
1266 g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id));
1268 fprintf(stderr, "request %i not found\n", id);
1272 was_over = sshfs.outstanding_len > sshfs.max_outstanding_len;
1273 sshfs.outstanding_len -= req->len;
1275 sshfs.outstanding_len <= sshfs.max_outstanding_len) {
1276 pthread_cond_broadcast(&sshfs.outstanding_cond);
1278 g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1280 pthread_mutex_unlock(&sshfs.lock);
1284 unsigned int difftime;
1285 unsigned msgsize = buf.size + 5;
1287 gettimeofday(&now, NULL);
1288 difftime = (now.tv_sec - req->start.tv_sec) * 1000;
1289 difftime += (now.tv_usec - req->start.tv_usec) / 1000;
1290 DEBUG(" [%05i] %14s %8ubytes (%ims)\n", id,
1291 type_name(type), msgsize, difftime);
1293 if (difftime < sshfs.min_rtt || !sshfs.num_received)
1294 sshfs.min_rtt = difftime;
1295 if (difftime > sshfs.max_rtt)
1296 sshfs.max_rtt = difftime;
1297 sshfs.total_rtt += difftime;
1298 sshfs.num_received++;
1299 sshfs.bytes_received += msgsize;
1302 req->reply_type = type;
1304 if (req->want_reply)
1305 sem_post(&req->ready);
1307 if (req->end_func) {
1308 pthread_mutex_lock(&sshfs.lock);
1310 pthread_mutex_unlock(&sshfs.lock);
1320 static void close_conn(void)
1324 if (sshfs.ptyfd != -1) {
1328 if (sshfs.ptyslavefd != -1) {
1329 close(sshfs.ptyslavefd);
1330 sshfs.ptyslavefd = -1;
1334 static void *process_requests(void *data_)
1339 if (process_one_request() == -1)
1343 pthread_mutex_lock(&sshfs.lock);
1344 sshfs.processing_thread_started = 0;
1346 g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL);
1348 sshfs.outstanding_len = 0;
1349 pthread_cond_broadcast(&sshfs.outstanding_cond);
1350 pthread_mutex_unlock(&sshfs.lock);
1352 if (!sshfs.reconnect) {
1354 kill(getpid(), SIGTERM);
1359 static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
1364 if (buf_get_uint32(buf, &len) == -1)
1367 if (len < 5 || len > MAX_REPLY_LEN)
1370 if (buf_get_uint8(buf, &type) == -1)
1373 if (type != SSH_FXP_VERSION)
1376 if (buf_get_uint32(buf, version) == -1)
1379 DEBUG("Server version: %u\n", *version);
1384 buf_init(&buf2, len - 5);
1385 if (do_read(&buf2) == -1)
1392 if (buf_get_string(&buf2, &ext) == -1 ||
1393 buf_get_string(&buf2, &extdata) == -1)
1396 DEBUG("Extension: %s <%s>\n", ext, extdata);
1398 if (strcmp(ext, SFTP_EXT_POSIX_RENAME) == 0 &&
1399 strcmp(extdata, "1") == 0) {
1400 sshfs.ext_posix_rename = 1;
1401 sshfs.rename_workaround = 0;
1403 if (strcmp(ext, SFTP_EXT_STATVFS) == 0 &&
1404 strcmp(extdata, "2") == 0)
1405 sshfs.ext_statvfs = 1;
1406 if (strcmp(ext, SFTP_EXT_HARDLINK) == 0 &&
1407 strcmp(extdata, "1") == 0)
1408 sshfs.ext_hardlink = 1;
1409 } while (buf2.len < buf2.size);
1414 static int sftp_find_init_reply(uint32_t *version)
1420 res = do_read(&buf);
1424 res = sftp_init_reply_ok(&buf, version);
1428 /* Iterate over any rubbish until the version reply is found */
1429 DEBUG("%c", *buf.p);
1430 memmove(buf.p, buf.p + 1, buf.size - 1);
1432 buf2.p = buf.p + buf.size - 1;
1434 res = do_read(&buf2);
1440 static int sftp_init()
1443 uint32_t version = 0;
1446 if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1)
1449 if (sshfs.password_stdin && pty_expect_loop() == -1)
1452 if (sftp_find_init_reply(&version) == -1)
1455 sshfs.server_version = version;
1456 if (version > PROTO_VERSION) {
1458 "Warning: server uses version: %i, we support: %i\n",
1459 version, PROTO_VERSION);
1468 static int sftp_error_to_errno(uint32_t error)
1471 case SSH_FX_OK: return 0;
1472 case SSH_FX_NO_SUCH_FILE: return ENOENT;
1473 case SSH_FX_PERMISSION_DENIED: return EACCES;
1474 case SSH_FX_FAILURE: return EPERM;
1475 case SSH_FX_BAD_MESSAGE: return EBADMSG;
1476 case SSH_FX_NO_CONNECTION: return ENOTCONN;
1477 case SSH_FX_CONNECTION_LOST: return ECONNABORTED;
1478 case SSH_FX_OP_UNSUPPORTED: return EOPNOTSUPP;
1479 default: return EIO;
1483 static void sftp_detect_uid()
1486 uint32_t id = sftp_get_id();
1491 struct iovec iov[1];
1494 buf_add_string(&buf, ".");
1495 buf_to_iov(&buf, &iov[0]);
1496 if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1499 if (sftp_read(&type, &buf) == -1)
1501 if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1502 fprintf(stderr, "protocol error\n");
1505 if (buf_get_uint32(&buf, &replid) == -1)
1508 fprintf(stderr, "bad reply ID\n");
1511 if (type == SSH_FXP_STATUS) {
1513 if (buf_get_uint32(&buf, &serr) == -1)
1516 fprintf(stderr, "failed to stat home directory (%i)\n", serr);
1519 if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
1522 if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
1525 sshfs.remote_uid = stbuf.st_uid;
1526 sshfs.local_uid = getuid();
1527 sshfs.remote_uid_detected = 1;
1528 DEBUG("remote_uid = %i\n", sshfs.remote_uid);
1531 if (!sshfs.remote_uid_detected)
1532 fprintf(stderr, "failed to detect remote user ID\n");
1537 static int sftp_check_root(const char *base_path)
1540 uint32_t id = sftp_get_id();
1545 struct iovec iov[1];
1547 const char *remote_dir = base_path[0] ? base_path : ".";
1550 buf_add_string(&buf, remote_dir);
1551 buf_to_iov(&buf, &iov[0]);
1552 if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1555 if (sftp_read(&type, &buf) == -1)
1557 if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1558 fprintf(stderr, "protocol error\n");
1561 if (buf_get_uint32(&buf, &replid) == -1)
1564 fprintf(stderr, "bad reply ID\n");
1567 if (type == SSH_FXP_STATUS) {
1569 if (buf_get_uint32(&buf, &serr) == -1)
1572 fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir,
1573 strerror(sftp_error_to_errno(serr)));
1577 if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
1580 if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS))
1583 if (S_ISDIR(sshfs.mnt_mode) && !S_ISDIR(stbuf.st_mode)) {
1584 fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host,
1588 if ((sshfs.mnt_mode ^ stbuf.st_mode) & S_IFMT) {
1589 fprintf(stderr, "%s:%s: type of file differs from mountpoint\n",
1590 sshfs.host, remote_dir);
1601 static int connect_remote(void)
1605 if (sshfs.directport)
1606 err = connect_to(sshfs.host, sshfs.directport);
1615 sshfs.num_connect++;
1620 static int start_processing_thread(void)
1623 pthread_t thread_id;
1627 if (sshfs.processing_thread_started)
1630 if (sshfs.fd == -1) {
1631 err = connect_remote();
1636 if (sshfs.detect_uid) {
1638 sshfs.detect_uid = 0;
1641 sigemptyset(&newset);
1642 sigaddset(&newset, SIGTERM);
1643 sigaddset(&newset, SIGINT);
1644 sigaddset(&newset, SIGHUP);
1645 sigaddset(&newset, SIGQUIT);
1646 pthread_sigmask(SIG_BLOCK, &newset, &oldset);
1647 err = pthread_create(&thread_id, NULL, process_requests, NULL);
1649 fprintf(stderr, "failed to create thread: %s\n", strerror(err));
1652 pthread_detach(thread_id);
1653 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1654 sshfs.processing_thread_started = 1;
1658 #if FUSE_VERSION >= 26
1659 static void *sshfs_init(struct fuse_conn_info *conn)
1661 static void *sshfs_init(void)
1664 #if FUSE_VERSION >= 26
1665 /* Readahead should be done by kernel or sshfs but not both */
1666 if (conn->async_read)
1667 sshfs.sync_read = 1;
1670 if (!sshfs.delay_connect)
1671 start_processing_thread();
1676 static int sftp_request_wait(struct request *req, uint8_t type,
1677 uint8_t expect_type, struct buffer *outbuf)
1685 while (sem_wait(&req->ready));
1691 if (req->reply_type != expect_type &&
1692 req->reply_type != SSH_FXP_STATUS) {
1693 fprintf(stderr, "protocol error\n");
1696 if (req->reply_type == SSH_FXP_STATUS) {
1698 if (buf_get_uint32(&req->reply, &serr) == -1)
1703 if (expect_type == SSH_FXP_STATUS)
1710 if (type == SSH_FXP_READ || type == SSH_FXP_READDIR)
1717 err = -sftp_error_to_errno(serr);
1720 buf_init(outbuf, req->reply.size - req->reply.len);
1721 buf_get_mem(&req->reply, outbuf->p, outbuf->size);
1726 if (req->end_func) {
1727 pthread_mutex_lock(&sshfs.lock);
1729 pthread_mutex_unlock(&sshfs.lock);
1735 static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
1736 request_func begin_func, request_func end_func,
1737 int want_reply, void *data,
1738 struct request **reqp)
1742 struct request *req = g_new0(struct request, 1);
1744 req->want_reply = want_reply;
1745 req->end_func = end_func;
1747 sem_init(&req->ready, 0, 0);
1748 buf_init(&req->reply, 0);
1749 pthread_mutex_lock(&sshfs.lock);
1753 err = start_processing_thread();
1755 pthread_mutex_unlock(&sshfs.lock);
1758 req->len = iov_length(iov, count) + 9;
1759 sshfs.outstanding_len += req->len;
1760 while (sshfs.outstanding_len > sshfs.max_outstanding_len)
1761 pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock);
1763 g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req);
1765 gettimeofday(&req->start, NULL);
1767 sshfs.bytes_sent += req->len;
1769 DEBUG("[%05i] %s\n", id, type_name(type));
1770 pthread_mutex_unlock(&sshfs.lock);
1773 if (sftp_send_iov(type, id, iov, count) == -1) {
1776 pthread_mutex_lock(&sshfs.lock);
1777 rmed = g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1778 pthread_mutex_unlock(&sshfs.lock);
1780 if (!rmed && !want_reply) {
1781 /* request already freed */
1793 sftp_request_wait(req, type, 0, NULL);
1801 static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count,
1802 uint8_t expect_type, struct buffer *outbuf)
1805 struct request *req;
1807 err = sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL,
1809 if (expect_type == 0)
1812 return sftp_request_wait(req, type, expect_type, outbuf);
1815 static int sftp_request(uint8_t type, const struct buffer *buf,
1816 uint8_t expect_type, struct buffer *outbuf)
1820 buf_to_iov(buf, &iov);
1821 return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
1824 static int sshfs_getattr(const char *path, struct stat *stbuf)
1828 struct buffer outbuf;
1830 buf_add_path(&buf, path);
1831 err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
1832 &buf, SSH_FXP_ATTRS, &outbuf);
1834 if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
1842 static int count_components(const char *p)
1846 for (; *p == '/'; p++);
1847 for (ctr = 0; *p; ctr++) {
1848 for (; *p && *p != '/'; p++);
1849 for (; *p == '/'; p++);
1854 static void strip_common(const char **sp, const char **tp)
1856 const char *s = *sp;
1857 const char *t = *tp;
1859 for (; *s == '/'; s++);
1860 for (; *t == '/'; t++);
1863 for (; *s == *t && *s && *s != '/'; s++, t++);
1864 } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
1867 static void transform_symlink(const char *path, char **linkp)
1869 const char *l = *linkp;
1870 const char *b = sshfs.base_path;
1876 if (l[0] != '/' || b[0] != '/')
1879 strip_common(&l, &b);
1883 strip_common(&l, &path);
1884 dotdots = count_components(path);
1889 newlink = malloc(dotdots * 3 + strlen(l) + 2);
1891 fprintf(stderr, "sshfs: memory allocation failed\n");
1894 for (s = newlink, i = 0; i < dotdots; i++, s += 3)
1908 static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
1916 if (sshfs.server_version < 3)
1920 buf_add_path(&buf, path);
1921 err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
1926 if(buf_get_uint32(&name, &count) != -1 && count == 1 &&
1927 buf_get_string(&name, &link) != -1) {
1928 if (sshfs.transform_symlinks)
1929 transform_symlink(path, &link);
1930 strncpy(linkbuf, link, size - 1);
1931 linkbuf[size - 1] = '\0';
1941 static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
1942 fuse_cache_dirfil_t filler)
1946 struct buffer handle;
1948 buf_add_path(&buf, path);
1949 err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle);
1952 buf_finish(&handle);
1955 err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
1957 if (buf_get_entries(&name, h, filler) == -1)
1965 err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
1974 static int sshfs_mkdir(const char *path, mode_t mode)
1979 buf_add_path(&buf, path);
1980 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
1981 buf_add_uint32(&buf, mode);
1982 err = sftp_request(SSH_FXP_MKDIR, &buf, SSH_FXP_STATUS, NULL);
1987 static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
1991 struct buffer handle;
1994 if ((mode & S_IFMT) != S_IFREG)
1998 buf_add_path(&buf, path);
1999 buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_EXCL);
2000 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2001 buf_add_uint32(&buf, mode);
2002 err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
2005 buf_finish(&handle);
2006 err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS,
2016 static int sshfs_symlink(const char *from, const char *to)
2021 if (sshfs.server_version < 3)
2024 /* openssh sftp server doesn't follow standard: link target and
2025 link name are mixed up, so we must also be non-standard :( */
2027 buf_add_string(&buf, from);
2028 buf_add_path(&buf, to);
2029 err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
2034 static int sshfs_unlink(const char *path)
2039 buf_add_path(&buf, path);
2040 err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
2045 static int sshfs_rmdir(const char *path)
2050 buf_add_path(&buf, path);
2051 err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
2056 static int sshfs_do_rename(const char *from, const char *to)
2061 buf_add_path(&buf, from);
2062 buf_add_path(&buf, to);
2063 err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
2068 static int sshfs_ext_posix_rename(const char *from, const char *to)
2073 buf_add_string(&buf, SFTP_EXT_POSIX_RENAME);
2074 buf_add_path(&buf, from);
2075 buf_add_path(&buf, to);
2076 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
2081 static void random_string(char *str, int length)
2084 for (i = 0; i < length; i++)
2085 *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10);
2089 static int sshfs_rename(const char *from, const char *to)
2092 if (sshfs.ext_posix_rename)
2093 err = sshfs_ext_posix_rename(from, to);
2095 err = sshfs_do_rename(from, to);
2096 if (err == -EPERM && sshfs.rename_workaround) {
2097 size_t tolen = strlen(to);
2098 if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
2100 char totmp[PATH_MAX];
2102 random_string(totmp + tolen, RENAME_TEMP_CHARS);
2103 tmperr = sshfs_do_rename(to, totmp);
2105 err = sshfs_do_rename(from, to);
2107 err = sshfs_unlink(totmp);
2109 sshfs_do_rename(totmp, to);
2116 static int sshfs_link(const char *from, const char *to)
2120 if (sshfs.ext_hardlink) {
2124 buf_add_string(&buf, SFTP_EXT_HARDLINK);
2125 buf_add_path(&buf, from);
2126 buf_add_path(&buf, to);
2127 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS,
2135 static int sshfs_chmod(const char *path, mode_t mode)
2140 buf_add_path(&buf, path);
2141 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2142 buf_add_uint32(&buf, mode);
2143 /* FIXME: really needs LSETSTAT extension (debian Bug#640038) */
2144 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2149 static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
2154 if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
2155 uid = sshfs.remote_uid;
2158 buf_add_path(&buf, path);
2159 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
2160 buf_add_uint32(&buf, uid);
2161 buf_add_uint32(&buf, gid);
2162 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2167 static int sshfs_truncate_workaround(const char *path, off_t size,
2168 struct fuse_file_info *fi);
2170 static void sshfs_inc_modifver(void)
2172 pthread_mutex_lock(&sshfs.lock);
2174 pthread_mutex_unlock(&sshfs.lock);
2177 static int sshfs_truncate(const char *path, off_t size)
2182 sshfs_inc_modifver();
2183 if (size == 0 || sshfs.truncate_workaround)
2184 return sshfs_truncate_workaround(path, size, NULL);
2187 buf_add_path(&buf, path);
2188 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2189 buf_add_uint64(&buf, size);
2190 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2195 static int sshfs_utime(const char *path, struct utimbuf *ubuf)
2200 buf_add_path(&buf, path);
2201 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
2202 buf_add_uint32(&buf, ubuf->actime);
2203 buf_add_uint32(&buf, ubuf->modtime);
2204 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2209 static inline int sshfs_file_is_conn(struct sshfs_file *sf)
2213 pthread_mutex_lock(&sshfs.lock);
2214 ret = (sf->connver == sshfs.connver);
2215 pthread_mutex_unlock(&sshfs.lock);
2220 static int sshfs_open_common(const char *path, mode_t mode,
2221 struct fuse_file_info *fi)
2226 struct buffer outbuf;
2228 struct sshfs_file *sf;
2229 struct request *open_req;
2230 uint32_t pflags = 0;
2233 uint64_t wrctr = cache_get_write_ctr();
2235 if ((fi->flags & O_ACCMODE) == O_RDONLY)
2236 pflags = SSH_FXF_READ;
2237 else if((fi->flags & O_ACCMODE) == O_WRONLY)
2238 pflags = SSH_FXF_WRITE;
2239 else if ((fi->flags & O_ACCMODE) == O_RDWR)
2240 pflags = SSH_FXF_READ | SSH_FXF_WRITE;
2244 if (fi->flags & O_CREAT)
2245 pflags |= SSH_FXF_CREAT;
2247 if (fi->flags & O_EXCL)
2248 pflags |= SSH_FXF_EXCL;
2250 if (fi->flags & O_TRUNC)
2251 pflags |= SSH_FXF_TRUNC;
2253 sf = g_new0(struct sshfs_file, 1);
2254 list_init(&sf->write_reqs);
2255 pthread_cond_init(&sf->write_finished, NULL);
2256 /* Assume random read after open */
2260 pthread_mutex_lock(&sshfs.lock);
2261 sf->modifver= sshfs.modifver;
2262 sf->connver = sshfs.connver;
2263 pthread_mutex_unlock(&sshfs.lock);
2265 buf_add_path(&buf, path);
2266 buf_add_uint32(&buf, pflags);
2267 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2268 buf_add_uint32(&buf, mode);
2269 buf_to_iov(&buf, &iov);
2270 sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL,
2273 buf_add_path(&buf, path);
2274 type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT;
2275 err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf);
2277 if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1)
2281 err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE,
2284 buf_finish(&sf->handle);
2285 sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL);
2286 buf_free(&sf->handle);
2291 cache_add_attr(path, &stbuf, wrctr);
2292 buf_finish(&sf->handle);
2293 fi->fh = (unsigned long) sf;
2295 cache_invalidate(path);
2302 static int sshfs_open(const char *path, struct fuse_file_info *fi)
2304 return sshfs_open_common(path, 0, fi);
2307 static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
2309 return (struct sshfs_file *) (uintptr_t) fi->fh;
2312 static int sshfs_flush(const char *path, struct fuse_file_info *fi)
2315 struct sshfs_file *sf = get_sshfs_file(fi);
2316 struct list_head write_reqs;
2317 struct list_head *curr_list;
2319 if (!sshfs_file_is_conn(sf))
2322 if (sshfs.sync_write)
2326 pthread_mutex_lock(&sshfs.lock);
2327 if (!list_empty(&sf->write_reqs)) {
2328 curr_list = sf->write_reqs.prev;
2329 list_del(&sf->write_reqs);
2330 list_init(&sf->write_reqs);
2331 list_add(&write_reqs, curr_list);
2332 while (!list_empty(&write_reqs))
2333 pthread_cond_wait(&sf->write_finished, &sshfs.lock);
2335 err = sf->write_error;
2336 sf->write_error = 0;
2337 pthread_mutex_unlock(&sshfs.lock);
2341 static int sshfs_fsync(const char *path, int isdatasync,
2342 struct fuse_file_info *fi)
2345 return sshfs_flush(path, fi);
2348 static void sshfs_file_put(struct sshfs_file *sf)
2355 static void sshfs_file_get(struct sshfs_file *sf)
2360 static int sshfs_release(const char *path, struct fuse_file_info *fi)
2362 struct sshfs_file *sf = get_sshfs_file(fi);
2363 struct buffer *handle = &sf->handle;
2364 if (sshfs_file_is_conn(sf)) {
2365 sshfs_flush(path, fi);
2366 sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
2369 chunk_put_locked(sf->readahead);
2374 static void sshfs_read_end(struct request *req)
2376 struct read_req *rreq = (struct read_req *) req->data;
2378 rreq->res = req->error;
2379 else if (req->replied) {
2382 if (req->reply_type == SSH_FXP_STATUS) {
2384 if (buf_get_uint32(&req->reply, &serr) != -1) {
2385 if (serr == SSH_FX_EOF)
2388 rreq->res = -sftp_error_to_errno(serr);
2390 } else if (req->reply_type == SSH_FXP_DATA) {
2392 if (buf_get_uint32(&req->reply, &retsize) != -1) {
2393 if (retsize > rreq->size) {
2394 fprintf(stderr, "long read\n");
2395 } else if (buf_check_get(&req->reply, retsize) != -1) {
2396 rreq->res = retsize;
2397 rreq->data = req->reply;
2398 buf_init(&req->reply, 0);
2402 fprintf(stderr, "protocol error\n");
2408 rreq->sio->num_reqs--;
2409 if (!rreq->sio->num_reqs)
2410 pthread_cond_broadcast(&rreq->sio->finished);
2413 static void sshfs_read_begin(struct request *req)
2415 struct read_req *rreq = (struct read_req *) req->data;
2416 rreq->sio->num_reqs++;
2419 static struct read_chunk *sshfs_send_read(struct sshfs_file *sf, size_t size,
2422 struct read_chunk *chunk = g_new0(struct read_chunk, 1);
2423 struct buffer *handle = &sf->handle;
2425 pthread_cond_init(&chunk->sio.finished, NULL);
2426 list_init(&chunk->reqs);
2428 chunk->offset = offset;
2434 struct iovec iov[1];
2435 struct read_req *rreq;
2436 size_t bsize = size < sshfs.max_read ? size : sshfs.max_read;
2438 rreq = g_new0(struct read_req, 1);
2439 rreq->sio = &chunk->sio;
2441 buf_init(&rreq->data, 0);
2442 list_add(&rreq->list, &chunk->reqs);
2445 buf_add_buf(&buf, handle);
2446 buf_add_uint64(&buf, offset);
2447 buf_add_uint32(&buf, bsize);
2448 buf_to_iov(&buf, &iov[0]);
2449 err = sftp_request_send(SSH_FXP_READ, iov, 1,
2465 static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size)
2468 struct read_req *rreq;
2470 pthread_mutex_lock(&sshfs.lock);
2471 while (chunk->sio.num_reqs)
2472 pthread_cond_wait(&chunk->sio.finished, &sshfs.lock);
2473 pthread_mutex_unlock(&sshfs.lock);
2476 if (chunk->sio.error) {
2477 if (chunk->sio.error != MY_EOF)
2478 res = chunk->sio.error;
2483 while (!list_empty(&chunk->reqs) && size) {
2484 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
2486 if (rreq->res < 0) {
2487 chunk->sio.error = rreq->res;
2489 } if (rreq->res == 0) {
2490 chunk->sio.error = MY_EOF;
2492 } else if (size < (size_t) rreq->res) {
2493 buf_get_mem(&rreq->data, buf, size);
2499 buf_get_mem(&rreq->data, buf, rreq->res);
2501 if ((size_t) rreq->res < rreq->size) {
2502 chunk->sio.error = MY_EOF;
2507 list_del(&rreq->list);
2508 buf_free(&rreq->data);
2514 chunk->offset += res;
2519 chunk_put_locked(chunk);
2523 static int sshfs_sync_read(struct sshfs_file *sf, char *buf, size_t size,
2526 struct read_chunk *chunk;
2528 chunk = sshfs_send_read(sf, size, offset);
2529 return wait_chunk(chunk, buf, size);
2532 static void submit_read(struct sshfs_file *sf, size_t size, off_t offset,
2533 struct read_chunk **chunkp)
2535 struct read_chunk *chunk;
2537 chunk = sshfs_send_read(sf, size, offset);
2538 pthread_mutex_lock(&sshfs.lock);
2539 chunk->modifver = sshfs.modifver;
2543 pthread_mutex_unlock(&sshfs.lock);
2546 static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset)
2548 struct read_chunk *ch = sf->readahead;
2549 if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) {
2556 static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size,
2561 struct read_chunk *chunk;
2562 struct read_chunk *chunk_prev = NULL;
2563 size_t origsize = size;
2566 pthread_mutex_lock(&sshfs.lock);
2567 curr_is_seq = sf->is_seq;
2568 sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver);
2569 sf->next_pos = offset + size;
2570 sf->modifver = sshfs.modifver;
2571 chunk = search_read_chunk(sf, offset);
2572 pthread_mutex_unlock(&sshfs.lock);
2574 if (chunk && chunk->size < size) {
2576 size -= chunk->size;
2577 offset += chunk->size;
2582 submit_read(sf, size, offset, &chunk);
2584 if (curr_is_seq && chunk && chunk->size <= size)
2585 submit_read(sf, origsize, offset + size, &sf->readahead);
2588 size_t prev_size = chunk_prev->size;
2589 res = wait_chunk(chunk_prev, rbuf, prev_size);
2590 if (res < (int) prev_size) {
2591 chunk_put_locked(chunk);
2597 res = wait_chunk(chunk, rbuf, size);
2606 static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
2607 struct fuse_file_info *fi)
2609 struct sshfs_file *sf = get_sshfs_file(fi);
2612 if (!sshfs_file_is_conn(sf))
2615 if (sshfs.sync_read)
2616 return sshfs_sync_read(sf, rbuf, size, offset);
2618 return sshfs_async_read(sf, rbuf, size, offset);
2621 static void sshfs_write_begin(struct request *req)
2623 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2626 list_add(&req->list, &sf->write_reqs);
2629 static void sshfs_write_end(struct request *req)
2632 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2635 sf->write_error = req->error;
2636 else if (req->replied) {
2637 if (req->reply_type != SSH_FXP_STATUS) {
2638 fprintf(stderr, "protocol error\n");
2639 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2640 serr != SSH_FX_OK) {
2641 sf->write_error = -EIO;
2644 list_del(&req->list);
2645 pthread_cond_broadcast(&sf->write_finished);
2649 static int sshfs_async_write(struct sshfs_file *sf, const char *wbuf,
2650 size_t size, off_t offset)
2653 struct buffer *handle = &sf->handle;
2655 while (!err && size) {
2657 struct iovec iov[2];
2658 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2661 buf_add_buf(&buf, handle);
2662 buf_add_uint64(&buf, offset);
2663 buf_add_uint32(&buf, bsize);
2664 buf_to_iov(&buf, &iov[0]);
2665 iov[1].iov_base = (void *) wbuf;
2666 iov[1].iov_len = bsize;
2667 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2668 sshfs_write_begin, sshfs_write_end,
2679 static void sshfs_sync_write_begin(struct request *req)
2681 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2685 static void sshfs_sync_write_end(struct request *req)
2688 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2691 sio->error = req->error;
2692 } else if (req->replied) {
2693 if (req->reply_type != SSH_FXP_STATUS) {
2694 fprintf(stderr, "protocol error\n");
2695 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2696 serr != SSH_FX_OK) {
2702 pthread_cond_broadcast(&sio->finished);
2706 static int sshfs_sync_write(struct sshfs_file *sf, const char *wbuf,
2707 size_t size, off_t offset)
2710 struct buffer *handle = &sf->handle;
2711 struct sshfs_io sio = { .error = 0, .num_reqs = 0 };
2713 pthread_cond_init(&sio.finished, NULL);
2715 while (!err && size) {
2717 struct iovec iov[2];
2718 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2721 buf_add_buf(&buf, handle);
2722 buf_add_uint64(&buf, offset);
2723 buf_add_uint32(&buf, bsize);
2724 buf_to_iov(&buf, &iov[0]);
2725 iov[1].iov_base = (void *) wbuf;
2726 iov[1].iov_len = bsize;
2727 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2728 sshfs_sync_write_begin,
2729 sshfs_sync_write_end,
2737 pthread_mutex_lock(&sshfs.lock);
2738 while (sio.num_reqs)
2739 pthread_cond_wait(&sio.finished, &sshfs.lock);
2740 pthread_mutex_unlock(&sshfs.lock);
2748 static int sshfs_write(const char *path, const char *wbuf, size_t size,
2749 off_t offset, struct fuse_file_info *fi)
2752 struct sshfs_file *sf = get_sshfs_file(fi);
2756 if (!sshfs_file_is_conn(sf))
2759 sshfs_inc_modifver();
2761 if (!sshfs.sync_write && !sf->write_error)
2762 err = sshfs_async_write(sf, wbuf, size, offset);
2764 err = sshfs_sync_write(sf, wbuf, size, offset);
2766 return err ? err : (int) size;
2769 static int sshfs_ext_statvfs(const char *path, struct statvfs *stbuf)
2773 struct buffer outbuf;
2775 buf_add_string(&buf, SFTP_EXT_STATVFS);
2776 buf_add_path(&buf, path);
2777 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_EXTENDED_REPLY,
2780 if (buf_get_statvfs(&outbuf, stbuf) == -1)
2789 #if FUSE_VERSION >= 25
2790 static int sshfs_statfs(const char *path, struct statvfs *buf)
2792 if (sshfs.ext_statvfs)
2793 return sshfs_ext_statvfs(path, buf);
2795 buf->f_namemax = 255;
2796 buf->f_bsize = sshfs.blksize;
2798 * df seems to use f_bsize instead of f_frsize, so make them
2801 buf->f_frsize = buf->f_bsize;
2802 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2803 1000ULL * 1024 * 1024 * 1024 / buf->f_frsize;
2804 buf->f_files = buf->f_ffree = 1000000000;
2808 static int sshfs_statfs(const char *path, struct statfs *buf)
2810 if (sshfs.ext_statvfs) {
2812 struct statvfs vbuf;
2814 err = sshfs_ext_statvfs(path, &vbuf);
2816 buf->f_bsize = vbuf.f_bsize;
2817 buf->f_blocks = vbuf.f_blocks;
2818 buf->f_bfree = vbuf.f_bfree;
2819 buf->f_bavail = vbuf.f_bavail;
2820 buf->f_files = vbuf.f_files;
2821 buf->f_ffree = vbuf.f_ffree;
2822 buf->f_namelen = vbuf.f_namemax;
2827 buf->f_namelen = 255;
2828 buf->f_bsize = sshfs.blksize;
2829 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2830 1000ULL * 1024 * 1024 * 1024 / buf->f_bsize;
2831 buf->f_files = buf->f_ffree = 1000000000;
2836 #if FUSE_VERSION >= 25
2837 static int sshfs_create(const char *path, mode_t mode,
2838 struct fuse_file_info *fi)
2840 return sshfs_open_common(path, mode, fi);
2843 static int sshfs_ftruncate(const char *path, off_t size,
2844 struct fuse_file_info *fi)
2848 struct sshfs_file *sf = get_sshfs_file(fi);
2852 if (!sshfs_file_is_conn(sf))
2855 sshfs_inc_modifver();
2856 if (sshfs.truncate_workaround)
2857 return sshfs_truncate_workaround(path, size, fi);
2860 buf_add_buf(&buf, &sf->handle);
2861 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2862 buf_add_uint64(&buf, size);
2863 err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL);
2870 static int sshfs_fgetattr(const char *path, struct stat *stbuf,
2871 struct fuse_file_info *fi)
2875 struct buffer outbuf;
2876 struct sshfs_file *sf = get_sshfs_file(fi);
2880 if (!sshfs_file_is_conn(sf))
2883 if (sshfs.fstat_workaround)
2884 return sshfs_getattr(path, stbuf);
2887 buf_add_buf(&buf, &sf->handle);
2888 err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
2890 if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
2898 static int sshfs_truncate_zero(const char *path)
2901 struct fuse_file_info fi;
2903 fi.flags = O_WRONLY | O_TRUNC;
2904 err = sshfs_open(path, &fi);
2906 sshfs_release(path, &fi);
2911 static size_t calc_buf_size(off_t size, off_t offset)
2913 return offset + sshfs.max_read < size ? sshfs.max_read : size - offset;
2916 static int sshfs_truncate_shrink(const char *path, off_t size)
2921 struct fuse_file_info fi;
2923 data = calloc(size, 1);
2927 fi.flags = O_RDONLY;
2928 res = sshfs_open(path, &fi);
2932 for (offset = 0; offset < size; offset += res) {
2933 size_t bufsize = calc_buf_size(size, offset);
2934 res = sshfs_read(path, data + offset, bufsize, offset, &fi);
2938 sshfs_release(path, &fi);
2942 fi.flags = O_WRONLY | O_TRUNC;
2943 res = sshfs_open(path, &fi);
2947 for (offset = 0; offset < size; offset += res) {
2948 size_t bufsize = calc_buf_size(size, offset);
2949 res = sshfs_write(path, data + offset, bufsize, offset, &fi);
2954 res = sshfs_flush(path, &fi);
2955 sshfs_release(path, &fi);
2962 static int sshfs_truncate_extend(const char *path, off_t size,
2963 struct fuse_file_info *fi)
2967 struct fuse_file_info tmpfi;
2968 struct fuse_file_info *openfi = fi;
2971 openfi->flags = O_WRONLY;
2972 res = sshfs_open(path, openfi);
2976 res = sshfs_write(path, &c, 1, size - 1, openfi);
2978 res = sshfs_flush(path, openfi);
2980 sshfs_release(path, openfi);
2986 * Work around broken sftp servers which don't handle
2987 * SSH_FILEXFER_ATTR_SIZE in SETSTAT request.
2989 * If new size is zero, just open the file with O_TRUNC.
2991 * If new size is smaller than current size, then copy file locally,
2992 * then open/trunc and send it back.
2994 * If new size is greater than current size, then write a zero byte to
2995 * the new end of the file.
2997 static int sshfs_truncate_workaround(const char *path, off_t size,
2998 struct fuse_file_info *fi)
3001 return sshfs_truncate_zero(path);
3006 err = sshfs_fgetattr(path, &stbuf, fi);
3008 err = sshfs_getattr(path, &stbuf);
3011 if (stbuf.st_size == size)
3013 else if (stbuf.st_size > size)
3014 return sshfs_truncate_shrink(path, size);
3016 return sshfs_truncate_extend(path, size, fi);
3020 static int processing_init(void)
3022 signal(SIGPIPE, SIG_IGN);
3024 pthread_mutex_init(&sshfs.lock, NULL);
3025 pthread_mutex_init(&sshfs.lock_write, NULL);
3026 pthread_cond_init(&sshfs.outstanding_cond, NULL);
3027 sshfs.reqtab = g_hash_table_new(NULL, NULL);
3028 if (!sshfs.reqtab) {
3029 fprintf(stderr, "failed to create hash table\n");
3035 static struct fuse_cache_operations sshfs_oper = {
3038 .getattr = sshfs_getattr,
3039 .readlink = sshfs_readlink,
3040 .mknod = sshfs_mknod,
3041 .mkdir = sshfs_mkdir,
3042 .symlink = sshfs_symlink,
3043 .unlink = sshfs_unlink,
3044 .rmdir = sshfs_rmdir,
3045 .rename = sshfs_rename,
3047 .chmod = sshfs_chmod,
3048 .chown = sshfs_chown,
3049 .truncate = sshfs_truncate,
3050 .utime = sshfs_utime,
3052 .flush = sshfs_flush,
3053 .fsync = sshfs_fsync,
3054 .release = sshfs_release,
3056 .write = sshfs_write,
3057 .statfs = sshfs_statfs,
3058 #if FUSE_VERSION >= 25
3059 .create = sshfs_create,
3060 .ftruncate = sshfs_ftruncate,
3061 .fgetattr = sshfs_fgetattr,
3064 .cache_getdir = sshfs_getdir,
3067 static void usage(const char *progname)
3070 "usage: %s [user@]host:[dir] mountpoint [options]\n"
3072 "general options:\n"
3073 " -o opt,[opt...] mount options\n"
3074 " -h --help print help\n"
3075 " -V --version print version\n"
3078 " -p PORT equivalent to '-o port=PORT'\n"
3079 " -C equivalent to '-o compression=yes'\n"
3080 " -F ssh_configfile specifies alternative ssh configuration file\n"
3081 " -1 equivalent to '-o ssh_protocol=1'\n"
3082 " -o reconnect reconnect to server\n"
3083 " -o delay_connect delay connection to server\n"
3084 " -o sshfs_sync synchronous writes\n"
3085 " -o no_readahead synchronous reads (no speculative readahead)\n"
3086 " -o sshfs_debug print some debugging information\n"
3087 " -o cache=BOOL enable caching {yes,no} (default: yes)\n"
3088 " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
3089 " -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n"
3090 " -o workaround=LIST colon separated list of workarounds\n"
3091 " none no workarounds enabled\n"
3092 " all all workarounds enabled\n"
3093 " [no]rename fix renaming to existing file (default: off)\n"
3094 #ifdef SSH_NODELAY_WORKAROUND
3095 " [no]nodelay set nodelay tcp flag in ssh (default: on)\n"
3097 " [no]nodelaysrv set nodelay tcp flag in sshd (default: off)\n"
3098 " [no]truncate fix truncate for old servers (default: off)\n"
3099 " [no]buflimit fix buffer fillup bug in server (default: on)\n"
3100 " -o idmap=TYPE user/group ID mapping, possible types are:\n"
3101 " none no translation of the ID space (default)\n"
3102 " user only translate UID of connecting user\n"
3103 " -o ssh_command=CMD execute CMD instead of 'ssh'\n"
3104 " -o ssh_protocol=N ssh protocol to use (default: 2)\n"
3105 " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n"
3106 " -o directport=PORT directly connect to PORT bypassing ssh\n"
3107 " -o transform_symlinks transform absolute symlinks to relative\n"
3108 " -o follow_symlinks follow symlinks on the server\n"
3109 " -o no_check_root don't check for existence of 'dir' on server\n"
3110 " -o password_stdin read password from stdin (only for pam_mount!)\n"
3111 " -o SSHOPT=VAL ssh options (see man ssh_config)\n"
3115 static int is_ssh_opt(const char *arg)
3117 if (arg[0] != '-') {
3118 unsigned arglen = strlen(arg);
3120 for (o = ssh_opts; *o; o++) {
3121 unsigned olen = strlen(*o);
3122 if (arglen > olen && arg[olen] == '=' &&
3123 strncasecmp(arg, *o, olen) == 0)
3130 static int sshfs_fuse_main(struct fuse_args *args)
3132 #if FUSE_VERSION >= 26
3133 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL);
3135 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper));
3139 static int sshfs_opt_proc(void *data, const char *arg, int key,
3140 struct fuse_args *outargs)
3146 case FUSE_OPT_KEY_OPT:
3147 if (is_ssh_opt(arg)) {
3148 tmp = g_strdup_printf("-o%s", arg);
3155 case FUSE_OPT_KEY_NONOPT:
3156 if (!sshfs.host && strchr(arg, ':')) {
3157 sshfs.host = strdup(arg);
3163 tmp = g_strdup_printf("-oPort=%s", arg + 2);
3169 ssh_add_arg("-oCompression=yes");
3172 case KEY_CONFIGFILE:
3173 tmp = g_strdup_printf("-F%s", arg + 2);
3179 usage(outargs->argv[0]);
3180 fuse_opt_add_arg(outargs, "-ho");
3181 sshfs_fuse_main(outargs);
3185 printf("SSHFS version %s\n", PACKAGE_VERSION);
3186 #if FUSE_VERSION >= 25
3187 fuse_opt_add_arg(outargs, "--version");
3188 sshfs_fuse_main(outargs);
3192 case KEY_FOREGROUND:
3193 sshfs.foreground = 1;
3197 fprintf(stderr, "internal error\n");
3202 static int workaround_opt_proc(void *data, const char *arg, int key,
3203 struct fuse_args *outargs)
3205 (void) data; (void) key; (void) outargs;
3206 fprintf(stderr, "unknown workaround: '%s'\n", arg);
3210 int parse_workarounds(void)
3213 char *argv[] = { "", "-o", sshfs.workarounds, NULL };
3214 struct fuse_args args = FUSE_ARGS_INIT(3, argv);
3215 char *s = sshfs.workarounds;
3219 while ((s = strchr(s, ':')))
3222 res = fuse_opt_parse(&args, &sshfs, workaround_opts,
3223 workaround_opt_proc);
3224 fuse_opt_free_args(&args);
3229 #if FUSE_VERSION == 25
3230 static int fuse_opt_insert_arg(struct fuse_args *args, int pos,
3233 assert(pos <= args->argc);
3234 if (fuse_opt_add_arg(args, arg) == -1)
3237 if (pos != args->argc - 1) {
3238 char *newarg = args->argv[args->argc - 1];
3239 memmove(&args->argv[pos + 1], &args->argv[pos],
3240 sizeof(char *) * (args->argc - pos - 1));
3241 args->argv[pos] = newarg;
3247 static void check_large_read(struct fuse_args *args)
3250 int err = uname(&buf);
3251 if (!err && strcmp(buf.sysname, "Linux") == 0 &&
3252 strncmp(buf.release, "2.4.", 4) == 0)
3253 fuse_opt_insert_arg(args, 1, "-olarge_read");
3256 static int read_password(void)
3258 int size = getpagesize();
3259 int max_password = 64;
3262 sshfs.password = mmap(NULL, size, PROT_READ | PROT_WRITE,
3263 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED,
3265 if (sshfs.password == MAP_FAILED) {
3266 perror("Failed to allocate locked page for password");
3270 /* Don't use fgets() because password might stay in memory */
3271 for (n = 0; n < max_password; n++) {
3274 res = read(0, &sshfs.password[n], 1);
3276 perror("Reading password");
3280 sshfs.password[n] = '\n';
3283 if (sshfs.password[n] == '\n')
3286 if (n == max_password) {
3287 fprintf(stderr, "Password too long\n");
3290 sshfs.password[n+1] = '\0';
3291 ssh_add_arg("-oNumberOfPasswordPrompts=1");
3296 static void set_ssh_command(void)
3303 d = sshfs.ssh_command;
3304 s = sshfs.ssh_command;
3312 replace_arg(&sshfs.ssh_args.argv[0],
3315 if (fuse_opt_insert_arg(&sshfs.ssh_args, i,
3316 sshfs.ssh_command) == -1)
3320 d = sshfs.ssh_command;
3333 static char *find_base_path(void)
3335 char *s = sshfs.host;
3338 for (; *s && *s != ':'; s++) {
3341 * Handle IPv6 numerical address enclosed in square
3345 for (; *s != ']'; s++) {
3347 fprintf(stderr, "missing ']' in hostname\n");
3364 * Remove commas from fsname, as it confuses the fuse option parser.
3366 static void fsname_remove_commas(char *fsname)
3368 if (strchr(fsname, ',') != NULL) {
3380 #if FUSE_VERSION >= 27
3381 static char *fsname_escape_commas(char *fsnameold)
3383 char *fsname = g_malloc(strlen(fsnameold) * 2 + 1);
3387 for (s = fsnameold; *s; s++) {
3388 if (*s == '\\' || *s == ',')
3399 static int ssh_connect(void)
3403 res = processing_init();
3407 if (!sshfs.delay_connect) {
3408 if (connect_remote() == -1)
3411 if (!sshfs.no_check_root &&
3412 sftp_check_root(sshfs.base_path) == -1)
3419 int main(int argc, char *argv[])
3422 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3425 const char *sftp_server;
3428 g_thread_init(NULL);
3430 sshfs.blksize = 4096;
3431 /* SFTP spec says all servers should allow at least 32k I/O */
3432 sshfs.max_read = 32768;
3433 sshfs.max_write = 32768;
3434 sshfs.nodelay_workaround = 1;
3435 sshfs.nodelaysrv_workaround = 0;
3436 sshfs.rename_workaround = 0;
3437 sshfs.truncate_workaround = 0;
3438 sshfs.buflimit_workaround = 1;
3440 sshfs.progname = argv[0];
3443 sshfs.ptyslavefd = -1;
3444 sshfs.delay_connect = 0;
3448 ssh_add_arg("-oClearAllForwardings=yes");
3450 if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 ||
3451 parse_workarounds() == -1)
3454 DEBUG("SSHFS version %s\n", PACKAGE_VERSION);
3456 if (sshfs.password_stdin) {
3457 res = read_password();
3462 if (sshfs.buflimit_workaround)
3463 /* Work around buggy sftp-server in OpenSSH. Without this on
3464 a slow server a 10Mbyte buffer would fill up and the server
3466 sshfs.max_outstanding_len = 8388608;
3468 sshfs.max_outstanding_len = ~0;
3471 fprintf(stderr, "missing host\n");
3472 fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
3476 fsname = g_strdup(sshfs.host);
3477 sshfs.base_path = g_strdup(find_base_path());
3479 if (sshfs.ssh_command)
3482 tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
3485 ssh_add_arg(sshfs.host);
3486 if (sshfs.sftp_server)
3487 sftp_server = sshfs.sftp_server;
3488 else if (sshfs.ssh_ver == 1)
3489 sftp_server = SFTP_SERVER_PATH;
3491 sftp_server = "sftp";
3493 if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
3496 ssh_add_arg(sftp_server);
3497 free(sshfs.sftp_server);
3500 res = cache_parse_options(&args);
3504 sshfs.randseed = time(0);
3506 if (sshfs.max_read > 65536)
3507 sshfs.max_read = 65536;
3508 if (sshfs.max_write > 65536)
3509 sshfs.max_write = 65536;
3511 if (fuse_is_lib_option("ac_attr_timeout="))
3512 fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
3513 #if FUSE_VERSION >= 27
3514 libver = fuse_version();
3515 assert(libver >= 27);
3517 fsname = fsname_escape_commas(fsname);
3519 fsname_remove_commas(fsname);
3520 tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
3522 fsname_remove_commas(fsname);
3523 tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
3525 fuse_opt_insert_arg(&args, 1, tmp);
3528 check_large_read(&args);
3530 #if FUSE_VERSION >= 26
3533 struct fuse_chan *ch;
3539 res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded,
3544 res = stat(mountpoint, &st);
3549 sshfs.mnt_mode = st.st_mode;
3551 ch = fuse_mount(mountpoint, &args);
3555 res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC);
3557 perror("WARNING: failed to set FD_CLOESEC on fuse device");
3559 fuse = fuse_new(ch, &args, cache_init(&sshfs_oper),
3560 sizeof(struct fuse_operations), NULL);
3562 fuse_unmount(mountpoint, ch);
3566 res = ssh_connect();
3568 fuse_unmount(mountpoint, ch);
3573 res = fuse_daemonize(foreground);
3575 res = fuse_set_signal_handlers(fuse_get_session(fuse));
3578 fuse_unmount(mountpoint, ch);
3584 res = fuse_loop_mt(fuse);
3586 res = fuse_loop(fuse);
3593 fuse_remove_signal_handlers(fuse_get_session(fuse));
3594 fuse_unmount(mountpoint, ch);
3599 res = ssh_connect();
3603 res = sshfs_fuse_main(&args);
3607 unsigned int avg_rtt = 0;
3610 avg_rtt = sshfs.total_rtt / sshfs.num_sent;
3613 "sent: %llu messages, %llu bytes\n"
3614 "received: %llu messages, %llu bytes\n"
3615 "rtt min/max/avg: %ums/%ums/%ums\n"
3616 "num connect: %u\n",
3617 (unsigned long long) sshfs.num_sent,
3618 (unsigned long long) sshfs.bytes_sent,
3619 (unsigned long long) sshfs.num_received,
3620 (unsigned long long) sshfs.bytes_received,
3621 sshfs.min_rtt, sshfs.max_rtt, avg_rtt,
3625 fuse_opt_free_args(&args);
3626 fuse_opt_free_args(&sshfs.ssh_args);
3627 free(sshfs.directport);