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>
48 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
49 #define MAP_ANONYMOUS MAP_ANON
53 #define SSH_FXP_INIT 1
54 #define SSH_FXP_VERSION 2
55 #define SSH_FXP_OPEN 3
56 #define SSH_FXP_CLOSE 4
57 #define SSH_FXP_READ 5
58 #define SSH_FXP_WRITE 6
59 #define SSH_FXP_LSTAT 7
60 #define SSH_FXP_FSTAT 8
61 #define SSH_FXP_SETSTAT 9
62 #define SSH_FXP_FSETSTAT 10
63 #define SSH_FXP_OPENDIR 11
64 #define SSH_FXP_READDIR 12
65 #define SSH_FXP_REMOVE 13
66 #define SSH_FXP_MKDIR 14
67 #define SSH_FXP_RMDIR 15
68 #define SSH_FXP_REALPATH 16
69 #define SSH_FXP_STAT 17
70 #define SSH_FXP_RENAME 18
71 #define SSH_FXP_READLINK 19
72 #define SSH_FXP_SYMLINK 20
73 #define SSH_FXP_STATUS 101
74 #define SSH_FXP_HANDLE 102
75 #define SSH_FXP_DATA 103
76 #define SSH_FXP_NAME 104
77 #define SSH_FXP_ATTRS 105
78 #define SSH_FXP_EXTENDED 200
79 #define SSH_FXP_EXTENDED_REPLY 201
81 #define SSH_FILEXFER_ATTR_SIZE 0x00000001
82 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002
83 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
84 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
85 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
89 #define SSH_FX_NO_SUCH_FILE 2
90 #define SSH_FX_PERMISSION_DENIED 3
91 #define SSH_FX_FAILURE 4
92 #define SSH_FX_BAD_MESSAGE 5
93 #define SSH_FX_NO_CONNECTION 6
94 #define SSH_FX_CONNECTION_LOST 7
95 #define SSH_FX_OP_UNSUPPORTED 8
97 #define SSH_FXF_READ 0x00000001
98 #define SSH_FXF_WRITE 0x00000002
99 #define SSH_FXF_APPEND 0x00000004
100 #define SSH_FXF_CREAT 0x00000008
101 #define SSH_FXF_TRUNC 0x00000010
102 #define SSH_FXF_EXCL 0x00000020
104 /* statvfs@openssh.com f_flag flags */
105 #define SSH2_FXE_STATVFS_ST_RDONLY 0x00000001
106 #define SSH2_FXE_STATVFS_ST_NOSUID 0x00000002
108 #define SFTP_EXT_POSIX_RENAME "posix-rename@openssh.com"
109 #define SFTP_EXT_STATVFS "statvfs@openssh.com"
110 #define SFTP_EXT_HARDLINK "hardlink@openssh.com"
112 #define PROTO_VERSION 3
116 #define MAX_REPLY_LEN (1 << 17)
118 #define RENAME_TEMP_CHARS 8
120 #define SFTP_SERVER_PATH "/usr/lib/sftp-server"
122 #define SSHNODELAY_SO "sshnodelay.so"
131 struct list_head *prev;
132 struct list_head *next;
136 typedef void (*request_func)(struct request *);
139 unsigned int want_reply;
145 struct timeval start;
147 request_func end_func;
149 struct list_head list;
154 pthread_cond_t finished;
159 struct sshfs_io *sio;
160 struct list_head list;
171 struct list_head reqs;
176 struct buffer handle;
177 struct list_head write_reqs;
178 pthread_cond_t write_finished;
180 struct read_chunk *readahead;
192 struct fuse_args ssh_args;
194 int rename_workaround;
195 int nodelay_workaround;
196 int nodelaysrv_workaround;
197 int truncate_workaround;
198 int buflimit_workaround;
199 int fstat_workaround;
200 int transform_symlinks;
210 GHashTable *r_uid_map;
211 GHashTable *r_gid_map;
224 pthread_mutex_t lock;
225 pthread_mutex_t lock_write;
226 int processing_thread_started;
227 unsigned int randseed;
235 int remote_uid_detected;
239 unsigned outstanding_len;
240 unsigned max_outstanding_len;
241 pthread_cond_t outstanding_cond;
244 int ext_posix_rename;
251 uint64_t bytes_received;
253 uint64_t num_received;
254 unsigned int min_rtt;
255 unsigned int max_rtt;
257 unsigned int num_connect;
260 static struct sshfs sshfs;
262 static const char *ssh_opts[] = {
266 "ChallengeResponseAuthentication",
272 "ConnectionAttempts",
276 "GlobalKnownHostsFile",
277 "GSSAPIAuthentication",
278 "GSSAPIDelegateCredentials",
279 "HostbasedAuthentication",
285 "KbdInteractiveAuthentication",
286 "KbdInteractiveDevices",
290 "NoHostAuthenticationForLocalhost",
291 "NumberOfPasswordPrompts",
292 "PasswordAuthentication",
294 "PreferredAuthentications",
296 "PubkeyAuthentication",
298 "RhostsRSAAuthentication",
300 "ServerAliveCountMax",
301 "ServerAliveInterval",
303 "StrictHostKeyChecking",
306 "UserKnownHostsFile",
331 #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
333 static struct fuse_opt sshfs_opts[] = {
334 SSHFS_OPT("directport=%s", directport, 0),
335 SSHFS_OPT("ssh_command=%s", ssh_command, 0),
336 SSHFS_OPT("sftp_server=%s", sftp_server, 0),
337 SSHFS_OPT("max_read=%u", max_read, 0),
338 SSHFS_OPT("max_write=%u", max_write, 0),
339 SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0),
340 SSHFS_OPT("-1", ssh_ver, 1),
341 SSHFS_OPT("workaround=%s", workarounds, 0),
342 SSHFS_OPT("idmap=none", idmap, IDMAP_NONE),
343 SSHFS_OPT("idmap=user", idmap, IDMAP_USER),
344 SSHFS_OPT("idmap=file", idmap, IDMAP_FILE),
345 SSHFS_OPT("uidfile=%s", uid_file, 0),
346 SSHFS_OPT("gidfile=%s", gid_file, 0),
347 SSHFS_OPT("nomap=ignore", nomap, NOMAP_IGNORE),
348 SSHFS_OPT("nomap=error", nomap, NOMAP_ERROR),
349 SSHFS_OPT("sshfs_sync", sync_write, 1),
350 SSHFS_OPT("no_readahead", sync_read, 1),
351 SSHFS_OPT("sshfs_debug", debug, 1),
352 SSHFS_OPT("reconnect", reconnect, 1),
353 SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
354 SSHFS_OPT("follow_symlinks", follow_symlinks, 1),
355 SSHFS_OPT("no_check_root", no_check_root, 1),
356 SSHFS_OPT("password_stdin", password_stdin, 1),
357 SSHFS_OPT("delay_connect", delay_connect, 1),
359 FUSE_OPT_KEY("-p ", KEY_PORT),
360 FUSE_OPT_KEY("-C", KEY_COMPRESS),
361 FUSE_OPT_KEY("-V", KEY_VERSION),
362 FUSE_OPT_KEY("--version", KEY_VERSION),
363 FUSE_OPT_KEY("-h", KEY_HELP),
364 FUSE_OPT_KEY("--help", KEY_HELP),
365 FUSE_OPT_KEY("debug", KEY_FOREGROUND),
366 FUSE_OPT_KEY("-d", KEY_FOREGROUND),
367 FUSE_OPT_KEY("-f", KEY_FOREGROUND),
368 FUSE_OPT_KEY("-F ", KEY_CONFIGFILE),
372 static struct fuse_opt workaround_opts[] = {
373 SSHFS_OPT("none", rename_workaround, 0),
374 SSHFS_OPT("none", nodelay_workaround, 0),
375 SSHFS_OPT("none", nodelaysrv_workaround, 0),
376 SSHFS_OPT("none", truncate_workaround, 0),
377 SSHFS_OPT("none", buflimit_workaround, 0),
378 SSHFS_OPT("none", fstat_workaround, 0),
379 SSHFS_OPT("all", rename_workaround, 1),
380 SSHFS_OPT("all", nodelay_workaround, 1),
381 SSHFS_OPT("all", nodelaysrv_workaround, 1),
382 SSHFS_OPT("all", truncate_workaround, 1),
383 SSHFS_OPT("all", buflimit_workaround, 1),
384 SSHFS_OPT("all", fstat_workaround, 1),
385 SSHFS_OPT("rename", rename_workaround, 1),
386 SSHFS_OPT("norename", rename_workaround, 0),
387 SSHFS_OPT("nodelay", nodelay_workaround, 1),
388 SSHFS_OPT("nonodelay", nodelay_workaround, 0),
389 SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1),
390 SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0),
391 SSHFS_OPT("truncate", truncate_workaround, 1),
392 SSHFS_OPT("notruncate", truncate_workaround, 0),
393 SSHFS_OPT("buflimit", buflimit_workaround, 1),
394 SSHFS_OPT("nobuflimit", buflimit_workaround, 0),
395 SSHFS_OPT("fstat", fstat_workaround, 1),
396 SSHFS_OPT("nofstat", fstat_workaround, 0),
400 #define DEBUG(format, args...) \
401 do { if (sshfs.debug) fprintf(stderr, format, args); } while(0)
403 static const char *type_name(uint8_t type)
406 case SSH_FXP_INIT: return "INIT";
407 case SSH_FXP_VERSION: return "VERSION";
408 case SSH_FXP_OPEN: return "OPEN";
409 case SSH_FXP_CLOSE: return "CLOSE";
410 case SSH_FXP_READ: return "READ";
411 case SSH_FXP_WRITE: return "WRITE";
412 case SSH_FXP_LSTAT: return "LSTAT";
413 case SSH_FXP_FSTAT: return "FSTAT";
414 case SSH_FXP_SETSTAT: return "SETSTAT";
415 case SSH_FXP_FSETSTAT: return "FSETSTAT";
416 case SSH_FXP_OPENDIR: return "OPENDIR";
417 case SSH_FXP_READDIR: return "READDIR";
418 case SSH_FXP_REMOVE: return "REMOVE";
419 case SSH_FXP_MKDIR: return "MKDIR";
420 case SSH_FXP_RMDIR: return "RMDIR";
421 case SSH_FXP_REALPATH: return "REALPATH";
422 case SSH_FXP_STAT: return "STAT";
423 case SSH_FXP_RENAME: return "RENAME";
424 case SSH_FXP_READLINK: return "READLINK";
425 case SSH_FXP_SYMLINK: return "SYMLINK";
426 case SSH_FXP_STATUS: return "STATUS";
427 case SSH_FXP_HANDLE: return "HANDLE";
428 case SSH_FXP_DATA: return "DATA";
429 case SSH_FXP_NAME: return "NAME";
430 case SSH_FXP_ATTRS: return "ATTRS";
431 case SSH_FXP_EXTENDED: return "EXTENDED";
432 case SSH_FXP_EXTENDED_REPLY: return "EXTENDED_REPLY";
433 default: return "???";
437 #define container_of(ptr, type, member) ({ \
438 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
439 (type *)( (char *)__mptr - offsetof(type,member) );})
441 #define list_entry(ptr, type, member) \
442 container_of(ptr, type, member)
444 static void list_init(struct list_head *head)
450 static void list_add(struct list_head *new, struct list_head *head)
452 struct list_head *prev = head;
453 struct list_head *next = head->next;
460 static void list_del(struct list_head *entry)
462 struct list_head *prev = entry->prev;
463 struct list_head *next = entry->next;
469 static int list_empty(const struct list_head *head)
471 return head->next == head;
474 /* given a pointer to the uid/gid, and the mapping table, remap the
475 * uid/gid, if necessary */
476 static inline int translate_id(uint32_t *id, GHashTable *map)
479 if (g_hash_table_lookup_extended(map, GUINT_TO_POINTER(*id), NULL, &id_p)) {
480 *id = GPOINTER_TO_UINT(id_p);
483 switch (sshfs.nomap) {
484 case NOMAP_ERROR: return -1;
485 case NOMAP_IGNORE: return 0;
487 fprintf(stderr, "internal error\n");
492 static inline void buf_init(struct buffer *buf, size_t size)
495 buf->p = (uint8_t *) malloc(size);
497 fprintf(stderr, "sshfs: memory allocation failed\n");
506 static inline void buf_free(struct buffer *buf)
511 static inline void buf_finish(struct buffer *buf)
513 buf->len = buf->size;
516 static inline void buf_clear(struct buffer *buf)
522 static void buf_resize(struct buffer *buf, size_t len)
524 buf->size = (buf->len + len + 63) & ~31;
525 buf->p = (uint8_t *) realloc(buf->p, buf->size);
527 fprintf(stderr, "sshfs: memory allocation failed\n");
532 static inline void buf_check_add(struct buffer *buf, size_t len)
534 if (buf->len + len > buf->size)
535 buf_resize(buf, len);
538 #define _buf_add_mem(b, d, l) \
539 buf_check_add(b, l); \
540 memcpy(b->p + b->len, d, l); \
544 static inline void buf_add_mem(struct buffer *buf, const void *data,
547 _buf_add_mem(buf, data, len);
550 static inline void buf_add_buf(struct buffer *buf, const struct buffer *bufa)
552 _buf_add_mem(buf, bufa->p, bufa->len);
555 static inline void buf_add_uint8(struct buffer *buf, uint8_t val)
557 _buf_add_mem(buf, &val, 1);
560 static inline void buf_add_uint32(struct buffer *buf, uint32_t val)
562 uint32_t nval = htonl(val);
563 _buf_add_mem(buf, &nval, 4);
566 static inline void buf_add_uint64(struct buffer *buf, uint64_t val)
568 buf_add_uint32(buf, val >> 32);
569 buf_add_uint32(buf, val & 0xffffffff);
572 static inline void buf_add_data(struct buffer *buf, const struct buffer *data)
574 buf_add_uint32(buf, data->len);
575 buf_add_mem(buf, data->p, data->len);
578 static inline void buf_add_string(struct buffer *buf, const char *str)
581 data.p = (uint8_t *) str;
582 data.len = strlen(str);
583 buf_add_data(buf, &data);
586 static inline void buf_add_path(struct buffer *buf, const char *path)
590 if (sshfs.base_path[0]) {
592 if (sshfs.base_path[strlen(sshfs.base_path)-1] != '/') {
593 realpath = g_strdup_printf("%s/%s",
597 realpath = g_strdup_printf("%s%s",
602 realpath = g_strdup(sshfs.base_path);
606 realpath = g_strdup(path + 1);
608 realpath = g_strdup(".");
610 buf_add_string(buf, realpath);
614 static int buf_check_get(struct buffer *buf, size_t len)
616 if (buf->len + len > buf->size) {
617 fprintf(stderr, "buffer too short\n");
623 static inline int buf_get_mem(struct buffer *buf, void *data, size_t len)
625 if (buf_check_get(buf, len) == -1)
627 memcpy(data, buf->p + buf->len, len);
632 static inline int buf_get_uint8(struct buffer *buf, uint8_t *val)
634 return buf_get_mem(buf, val, 1);
637 static inline int buf_get_uint32(struct buffer *buf, uint32_t *val)
640 if (buf_get_mem(buf, &nval, 4) == -1)
646 static inline int buf_get_uint64(struct buffer *buf, uint64_t *val)
650 if (buf_get_uint32(buf, &val1) == -1 ||
651 buf_get_uint32(buf, &val2) == -1) {
654 *val = ((uint64_t) val1 << 32) + val2;
658 static inline int buf_get_data(struct buffer *buf, struct buffer *data)
661 if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len)
663 buf_init(data, len + 1);
665 if (buf_get_mem(buf, data->p, data->size) == -1) {
672 static inline int buf_get_string(struct buffer *buf, char **str)
675 if (buf_get_data(buf, &data) == -1)
677 data.p[data.size] = '\0';
678 *str = (char *) data.p;
682 static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
690 uint32_t mode = S_IFREG | 0777;
692 if (buf_get_uint32(buf, &flags) == -1)
696 if ((flags & SSH_FILEXFER_ATTR_SIZE) &&
697 buf_get_uint64(buf, &size) == -1)
699 if ((flags & SSH_FILEXFER_ATTR_UIDGID) &&
700 (buf_get_uint32(buf, &uid) == -1 ||
701 buf_get_uint32(buf, &gid) == -1))
703 if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
704 buf_get_uint32(buf, &mode) == -1)
706 if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
707 if (buf_get_uint32(buf, &atime) == -1 ||
708 buf_get_uint32(buf, &mtime) == -1)
711 if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) {
714 if (buf_get_uint32(buf, &extcount) == -1)
716 for (i = 0; i < extcount; i++) {
718 if (buf_get_data(buf, &tmp) == -1)
721 if (buf_get_data(buf, &tmp) == -1)
727 if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
728 uid = sshfs.local_uid;
729 if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map)
730 if (translate_id(&uid, sshfs.uid_map) == -1)
732 if (sshfs.idmap == IDMAP_FILE && sshfs.gid_map)
733 if (translate_id(&gid, sshfs.gid_map) == -1)
736 memset(stbuf, 0, sizeof(struct stat));
737 stbuf->st_mode = mode;
739 stbuf->st_size = size;
741 stbuf->st_blksize = sshfs.blksize;
742 stbuf->st_blocks = ((size + sshfs.blksize - 1) &
743 ~((unsigned long long) sshfs.blksize - 1)) >> 9;
747 stbuf->st_atime = atime;
748 stbuf->st_ctime = stbuf->st_mtime = mtime;
752 static int buf_get_statvfs(struct buffer *buf, struct statvfs *stbuf)
766 if (buf_get_uint64(buf, &bsize) == -1 ||
767 buf_get_uint64(buf, &frsize) == -1 ||
768 buf_get_uint64(buf, &blocks) == -1 ||
769 buf_get_uint64(buf, &bfree) == -1 ||
770 buf_get_uint64(buf, &bavail) == -1 ||
771 buf_get_uint64(buf, &files) == -1 ||
772 buf_get_uint64(buf, &ffree) == -1 ||
773 buf_get_uint64(buf, &favail) == -1 ||
774 buf_get_uint64(buf, &fsid) == -1 ||
775 buf_get_uint64(buf, &flag) == -1 ||
776 buf_get_uint64(buf, &namemax) == -1) {
780 memset(stbuf, 0, sizeof(struct statvfs));
781 stbuf->f_bsize = bsize;
782 stbuf->f_frsize = frsize;
783 stbuf->f_blocks = blocks;
784 stbuf->f_bfree = bfree;
785 stbuf->f_bavail = bavail;
786 stbuf->f_files = files;
787 stbuf->f_ffree = ffree;
788 stbuf->f_favail = favail;
789 stbuf->f_namemax = namemax;
794 static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
795 fuse_cache_dirfil_t filler)
800 if (buf_get_uint32(buf, &count) == -1)
803 for (i = 0; i < count; i++) {
808 if (buf_get_string(buf, &name) == -1)
810 if (buf_get_string(buf, &longname) != -1) {
812 err = buf_get_attrs(buf, &stbuf, NULL);
814 if (sshfs.follow_symlinks &&
815 S_ISLNK(stbuf.st_mode)) {
818 filler(h, name, &stbuf);
828 static void ssh_add_arg(const char *arg)
830 if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1)
834 #ifdef SSH_NODELAY_WORKAROUND
835 static int do_ssh_nodelay_workaround(void)
837 char *oldpreload = getenv("LD_PRELOAD");
839 char sopath[PATH_MAX];
842 snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
843 res = access(sopath, R_OK);
846 if (!realpath(sshfs.progname, sopath))
849 s = strrchr(sopath, '/');
855 if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath))
858 strcpy(s, SSHNODELAY_SO);
859 res = access(sopath, R_OK);
861 fprintf(stderr, "sshfs: cannot find %s\n",
867 newpreload = g_strdup_printf("%s%s%s",
868 oldpreload ? oldpreload : "",
869 oldpreload ? " " : "",
872 if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
873 fprintf(stderr, "warning: failed set LD_PRELOAD "
874 "for ssh nodelay workaround\n");
881 static int pty_expect_loop(void)
885 const char *passwd_str = "assword:";
886 int timeout = 60 * 1000; /* 1min timeout for the prompt to appear */
887 int passwd_len = strlen(passwd_str);
892 struct pollfd fds[2];
894 fds[0].fd = sshfs.fd;
895 fds[0].events = POLLIN;
896 fds[1].fd = sshfs.ptyfd;
897 fds[1].events = POLLIN;
898 res = poll(fds, 2, timeout);
904 fprintf(stderr, "Timeout waiting for prompt\n");
907 if (fds[0].revents) {
909 * Something happened on stdout of ssh, this
910 * either means, that we are connected, or
911 * that we are disconnected. In any case the
912 * password doesn't matter any more.
917 res = read(sshfs.ptyfd, &c, 1);
923 fprintf(stderr, "EOF while waiting for prompt\n");
928 if (len == passwd_len) {
929 if (memcmp(buf, passwd_str, passwd_len) == 0) {
930 write(sshfs.ptyfd, sshfs.password,
931 strlen(sshfs.password));
933 memmove(buf, buf + 1, passwd_len - 1);
938 if (!sshfs.reconnect) {
939 size_t size = getpagesize();
941 memset(sshfs.password, 0, size);
942 munmap(sshfs.password, size);
943 sshfs.password = NULL;
949 static int pty_master(char **name)
953 mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
955 perror("failed to open pty");
958 if (grantpt(mfd) != 0) {
962 if (unlockpt(mfd) != 0) {
966 *name = ptsname(mfd);
971 static void replace_arg(char **argp, const char *newarg)
974 *argp = strdup(newarg);
976 fprintf(stderr, "sshfs: memory allocation failed\n");
981 static int start_ssh(void)
983 char *ptyname = NULL;
987 if (sshfs.password_stdin) {
989 sshfs.ptyfd = pty_master(&ptyname);
990 if (sshfs.ptyfd == -1)
993 sshfs.ptyslavefd = open(ptyname, O_RDWR | O_NOCTTY);
994 if (sshfs.ptyslavefd == -1)
998 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) {
999 perror("failed to create socket pair");
1002 sshfs.fd = sockpair[0];
1006 perror("failed to fork");
1009 } else if (pid == 0) {
1012 #ifdef SSH_NODELAY_WORKAROUND
1013 if (sshfs.nodelay_workaround &&
1014 do_ssh_nodelay_workaround() == -1) {
1016 "warning: ssh nodelay workaround disabled\n");
1020 if (sshfs.nodelaysrv_workaround) {
1023 * Hack to work around missing TCP_NODELAY
1026 for (i = 1; i < sshfs.ssh_args.argc; i++) {
1027 if (strcmp(sshfs.ssh_args.argv[i], "-x") == 0) {
1028 replace_arg(&sshfs.ssh_args.argv[i],
1035 devnull = open("/dev/null", O_WRONLY);
1037 if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) {
1038 perror("failed to redirect input/output");
1041 if (!sshfs.foreground && devnull != -1)
1050 perror("failed to fork");
1059 if (sshfs.password_stdin) {
1063 sfd = open(ptyname, O_RDWR);
1069 close(sshfs.ptyslavefd);
1076 fprintf(stderr, "executing");
1077 for (i = 0; i < sshfs.ssh_args.argc; i++)
1078 fprintf(stderr, " <%s>",
1079 sshfs.ssh_args.argv[i]);
1080 fprintf(stderr, "\n");
1083 execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv);
1084 fprintf(stderr, "failed to execute '%s': %s\n",
1085 sshfs.ssh_args.argv[0], strerror(errno));
1088 waitpid(pid, NULL, 0);
1093 static int connect_to(char *host, char *port)
1098 struct addrinfo *ai;
1099 struct addrinfo hint;
1101 memset(&hint, 0, sizeof(hint));
1102 hint.ai_family = PF_INET;
1103 hint.ai_socktype = SOCK_STREAM;
1104 err = getaddrinfo(host, port, &hint, &ai);
1106 fprintf(stderr, "failed to resolve %s:%s: %s\n", host, port,
1110 sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
1112 perror("failed to create socket");
1115 err = connect(sock, ai->ai_addr, ai->ai_addrlen);
1117 perror("failed to connect");
1121 err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
1123 perror("warning: failed to set TCP_NODELAY");
1131 static int do_write(struct iovec *iov, size_t count)
1135 res = writev(sshfs.fd, iov, count);
1139 } else if (res == 0) {
1140 fprintf(stderr, "zero write\n");
1144 if ((unsigned) res < iov->iov_len) {
1145 iov->iov_len -= res;
1146 iov->iov_base += res;
1149 res -= iov->iov_len;
1158 static uint32_t sftp_get_id(void)
1160 static uint32_t idctr;
1164 static void buf_to_iov(const struct buffer *buf, struct iovec *iov)
1166 iov->iov_base = buf->p;
1167 iov->iov_len = buf->len;
1170 static size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
1175 for (seg = 0; seg < nr_segs; seg++)
1176 ret += iov[seg].iov_len;
1180 #define SFTP_MAX_IOV 3
1182 static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[],
1187 struct iovec iovout[SFTP_MAX_IOV];
1191 assert(count <= SFTP_MAX_IOV - 1);
1193 buf_add_uint32(&buf, iov_length(iov, count) + 5);
1194 buf_add_uint8(&buf, type);
1195 buf_add_uint32(&buf, id);
1196 buf_to_iov(&buf, &iovout[nout++]);
1197 for (i = 0; i < count; i++)
1198 iovout[nout++] = iov[i];
1199 pthread_mutex_lock(&sshfs.lock_write);
1200 res = do_write(iovout, nout);
1201 pthread_mutex_unlock(&sshfs.lock_write);
1206 static int do_read(struct buffer *buf)
1209 uint8_t *p = buf->p;
1210 size_t size = buf->size;
1212 res = read(sshfs.fd, p, size);
1216 } else if (res == 0) {
1217 fprintf(stderr, "remote host has disconnected\n");
1226 static int sftp_read(uint8_t *type, struct buffer *buf)
1232 res = do_read(&buf2);
1234 if (buf_get_uint32(&buf2, &len) == -1)
1236 if (len > MAX_REPLY_LEN) {
1237 fprintf(stderr, "reply len too large: %u\n", len);
1240 if (buf_get_uint8(&buf2, type) == -1)
1242 buf_init(buf, len - 1);
1249 static void request_free(struct request *req)
1251 buf_free(&req->reply);
1252 sem_destroy(&req->ready);
1256 static void chunk_free(struct read_chunk *chunk)
1258 while (!list_empty(&chunk->reqs)) {
1259 struct read_req *rreq;
1261 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
1262 list_del(&rreq->list);
1263 buf_free(&rreq->data);
1269 static void chunk_put(struct read_chunk *chunk)
1278 static void chunk_put_locked(struct read_chunk *chunk)
1280 pthread_mutex_lock(&sshfs.lock);
1282 pthread_mutex_unlock(&sshfs.lock);
1285 static int clean_req(void *key_, struct request *req)
1290 if (req->want_reply)
1291 sem_post(&req->ready);
1300 static int process_one_request(void)
1305 struct request *req;
1309 res = sftp_read(&type, &buf);
1312 if (buf_get_uint32(&buf, &id) == -1)
1315 pthread_mutex_lock(&sshfs.lock);
1316 req = (struct request *)
1317 g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id));
1319 fprintf(stderr, "request %i not found\n", id);
1323 was_over = sshfs.outstanding_len > sshfs.max_outstanding_len;
1324 sshfs.outstanding_len -= req->len;
1326 sshfs.outstanding_len <= sshfs.max_outstanding_len) {
1327 pthread_cond_broadcast(&sshfs.outstanding_cond);
1329 g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1331 pthread_mutex_unlock(&sshfs.lock);
1335 unsigned int difftime;
1336 unsigned msgsize = buf.size + 5;
1338 gettimeofday(&now, NULL);
1339 difftime = (now.tv_sec - req->start.tv_sec) * 1000;
1340 difftime += (now.tv_usec - req->start.tv_usec) / 1000;
1341 DEBUG(" [%05i] %14s %8ubytes (%ims)\n", id,
1342 type_name(type), msgsize, difftime);
1344 if (difftime < sshfs.min_rtt || !sshfs.num_received)
1345 sshfs.min_rtt = difftime;
1346 if (difftime > sshfs.max_rtt)
1347 sshfs.max_rtt = difftime;
1348 sshfs.total_rtt += difftime;
1349 sshfs.num_received++;
1350 sshfs.bytes_received += msgsize;
1353 req->reply_type = type;
1355 if (req->want_reply)
1356 sem_post(&req->ready);
1358 if (req->end_func) {
1359 pthread_mutex_lock(&sshfs.lock);
1361 pthread_mutex_unlock(&sshfs.lock);
1371 static void close_conn(void)
1375 if (sshfs.ptyfd != -1) {
1379 if (sshfs.ptyslavefd != -1) {
1380 close(sshfs.ptyslavefd);
1381 sshfs.ptyslavefd = -1;
1385 static void *process_requests(void *data_)
1390 if (process_one_request() == -1)
1394 pthread_mutex_lock(&sshfs.lock);
1395 sshfs.processing_thread_started = 0;
1397 g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL);
1399 sshfs.outstanding_len = 0;
1400 pthread_cond_broadcast(&sshfs.outstanding_cond);
1401 pthread_mutex_unlock(&sshfs.lock);
1403 if (!sshfs.reconnect) {
1405 kill(getpid(), SIGTERM);
1410 static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
1415 if (buf_get_uint32(buf, &len) == -1)
1418 if (len < 5 || len > MAX_REPLY_LEN)
1421 if (buf_get_uint8(buf, &type) == -1)
1424 if (type != SSH_FXP_VERSION)
1427 if (buf_get_uint32(buf, version) == -1)
1430 DEBUG("Server version: %u\n", *version);
1435 buf_init(&buf2, len - 5);
1436 if (do_read(&buf2) == -1) {
1445 if (buf_get_string(&buf2, &ext) == -1 ||
1446 buf_get_string(&buf2, &extdata) == -1) {
1451 DEBUG("Extension: %s <%s>\n", ext, extdata);
1453 if (strcmp(ext, SFTP_EXT_POSIX_RENAME) == 0 &&
1454 strcmp(extdata, "1") == 0) {
1455 sshfs.ext_posix_rename = 1;
1456 sshfs.rename_workaround = 0;
1458 if (strcmp(ext, SFTP_EXT_STATVFS) == 0 &&
1459 strcmp(extdata, "2") == 0)
1460 sshfs.ext_statvfs = 1;
1461 if (strcmp(ext, SFTP_EXT_HARDLINK) == 0 &&
1462 strcmp(extdata, "1") == 0)
1463 sshfs.ext_hardlink = 1;
1464 } while (buf2.len < buf2.size);
1470 static int sftp_find_init_reply(uint32_t *version)
1476 res = do_read(&buf);
1480 res = sftp_init_reply_ok(&buf, version);
1484 /* Iterate over any rubbish until the version reply is found */
1485 DEBUG("%c", *buf.p);
1486 memmove(buf.p, buf.p + 1, buf.size - 1);
1488 buf2.p = buf.p + buf.size - 1;
1490 res = do_read(&buf2);
1496 static int sftp_init()
1499 uint32_t version = 0;
1502 if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1)
1505 if (sshfs.password_stdin && pty_expect_loop() == -1)
1508 if (sftp_find_init_reply(&version) == -1)
1511 sshfs.server_version = version;
1512 if (version > PROTO_VERSION) {
1514 "Warning: server uses version: %i, we support: %i\n",
1515 version, PROTO_VERSION);
1524 static int sftp_error_to_errno(uint32_t error)
1527 case SSH_FX_OK: return 0;
1528 case SSH_FX_NO_SUCH_FILE: return ENOENT;
1529 case SSH_FX_PERMISSION_DENIED: return EACCES;
1530 case SSH_FX_FAILURE: return EPERM;
1531 case SSH_FX_BAD_MESSAGE: return EBADMSG;
1532 case SSH_FX_NO_CONNECTION: return ENOTCONN;
1533 case SSH_FX_CONNECTION_LOST: return ECONNABORTED;
1534 case SSH_FX_OP_UNSUPPORTED: return EOPNOTSUPP;
1535 default: return EIO;
1539 static void sftp_detect_uid()
1542 uint32_t id = sftp_get_id();
1547 struct iovec iov[1];
1550 buf_add_string(&buf, ".");
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, "failed to stat home directory (%i)\n", serr);
1575 if (buf_get_attrs(&buf, &stbuf, &flags) != 0)
1578 if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
1581 sshfs.remote_uid = stbuf.st_uid;
1582 sshfs.local_uid = getuid();
1583 sshfs.remote_uid_detected = 1;
1584 DEBUG("remote_uid = %i\n", sshfs.remote_uid);
1587 if (!sshfs.remote_uid_detected)
1588 fprintf(stderr, "failed to detect remote user ID\n");
1593 static int sftp_check_root(const char *base_path)
1596 uint32_t id = sftp_get_id();
1601 struct iovec iov[1];
1603 const char *remote_dir = base_path[0] ? base_path : ".";
1606 buf_add_string(&buf, remote_dir);
1607 buf_to_iov(&buf, &iov[0]);
1608 if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1611 if (sftp_read(&type, &buf) == -1)
1613 if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1614 fprintf(stderr, "protocol error\n");
1617 if (buf_get_uint32(&buf, &replid) == -1)
1620 fprintf(stderr, "bad reply ID\n");
1623 if (type == SSH_FXP_STATUS) {
1625 if (buf_get_uint32(&buf, &serr) == -1)
1628 fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir,
1629 strerror(sftp_error_to_errno(serr)));
1634 int err2 = buf_get_attrs(&buf, &stbuf, &flags);
1640 if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS))
1643 if (S_ISDIR(sshfs.mnt_mode) && !S_ISDIR(stbuf.st_mode)) {
1644 fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host,
1648 if ((sshfs.mnt_mode ^ stbuf.st_mode) & S_IFMT) {
1649 fprintf(stderr, "%s:%s: type of file differs from mountpoint\n",
1650 sshfs.host, remote_dir);
1661 static int connect_remote(void)
1665 if (sshfs.directport)
1666 err = connect_to(sshfs.host, sshfs.directport);
1675 sshfs.num_connect++;
1680 static int start_processing_thread(void)
1683 pthread_t thread_id;
1687 if (sshfs.processing_thread_started)
1690 if (sshfs.fd == -1) {
1691 err = connect_remote();
1696 if (sshfs.detect_uid) {
1698 sshfs.detect_uid = 0;
1701 sigemptyset(&newset);
1702 sigaddset(&newset, SIGTERM);
1703 sigaddset(&newset, SIGINT);
1704 sigaddset(&newset, SIGHUP);
1705 sigaddset(&newset, SIGQUIT);
1706 pthread_sigmask(SIG_BLOCK, &newset, &oldset);
1707 err = pthread_create(&thread_id, NULL, process_requests, NULL);
1709 fprintf(stderr, "failed to create thread: %s\n", strerror(err));
1712 pthread_detach(thread_id);
1713 pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1714 sshfs.processing_thread_started = 1;
1718 #if FUSE_VERSION >= 26
1719 static void *sshfs_init(struct fuse_conn_info *conn)
1721 static void *sshfs_init(void)
1724 #if FUSE_VERSION >= 26
1725 /* Readahead should be done by kernel or sshfs but not both */
1726 if (conn->async_read)
1727 sshfs.sync_read = 1;
1730 if (!sshfs.delay_connect)
1731 start_processing_thread();
1736 static int sftp_request_wait(struct request *req, uint8_t type,
1737 uint8_t expect_type, struct buffer *outbuf)
1745 while (sem_wait(&req->ready));
1751 if (req->reply_type != expect_type &&
1752 req->reply_type != SSH_FXP_STATUS) {
1753 fprintf(stderr, "protocol error\n");
1756 if (req->reply_type == SSH_FXP_STATUS) {
1758 if (buf_get_uint32(&req->reply, &serr) == -1)
1763 if (expect_type == SSH_FXP_STATUS)
1770 if (type == SSH_FXP_READ || type == SSH_FXP_READDIR)
1777 err = -sftp_error_to_errno(serr);
1780 buf_init(outbuf, req->reply.size - req->reply.len);
1781 buf_get_mem(&req->reply, outbuf->p, outbuf->size);
1786 if (req->end_func) {
1787 pthread_mutex_lock(&sshfs.lock);
1789 pthread_mutex_unlock(&sshfs.lock);
1795 static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
1796 request_func begin_func, request_func end_func,
1797 int want_reply, void *data,
1798 struct request **reqp)
1802 struct request *req = g_new0(struct request, 1);
1804 req->want_reply = want_reply;
1805 req->end_func = end_func;
1807 sem_init(&req->ready, 0, 0);
1808 buf_init(&req->reply, 0);
1809 pthread_mutex_lock(&sshfs.lock);
1813 err = start_processing_thread();
1815 pthread_mutex_unlock(&sshfs.lock);
1818 req->len = iov_length(iov, count) + 9;
1819 sshfs.outstanding_len += req->len;
1820 while (sshfs.outstanding_len > sshfs.max_outstanding_len)
1821 pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock);
1823 g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req);
1825 gettimeofday(&req->start, NULL);
1827 sshfs.bytes_sent += req->len;
1829 DEBUG("[%05i] %s\n", id, type_name(type));
1830 pthread_mutex_unlock(&sshfs.lock);
1833 if (sftp_send_iov(type, id, iov, count) == -1) {
1836 pthread_mutex_lock(&sshfs.lock);
1837 rmed = g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1838 pthread_mutex_unlock(&sshfs.lock);
1840 if (!rmed && !want_reply) {
1841 /* request already freed */
1853 sftp_request_wait(req, type, 0, NULL);
1861 static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count,
1862 uint8_t expect_type, struct buffer *outbuf)
1865 struct request *req;
1867 err = sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL,
1869 if (expect_type == 0)
1872 return sftp_request_wait(req, type, expect_type, outbuf);
1875 static int sftp_request(uint8_t type, const struct buffer *buf,
1876 uint8_t expect_type, struct buffer *outbuf)
1880 buf_to_iov(buf, &iov);
1881 return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
1884 static int sshfs_getattr(const char *path, struct stat *stbuf)
1888 struct buffer outbuf;
1890 buf_add_path(&buf, path);
1891 err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
1892 &buf, SSH_FXP_ATTRS, &outbuf);
1894 err = buf_get_attrs(&outbuf, stbuf, NULL);
1901 static int count_components(const char *p)
1905 for (; *p == '/'; p++);
1906 for (ctr = 0; *p; ctr++) {
1907 for (; *p && *p != '/'; p++);
1908 for (; *p == '/'; p++);
1913 static void strip_common(const char **sp, const char **tp)
1915 const char *s = *sp;
1916 const char *t = *tp;
1918 for (; *s == '/'; s++);
1919 for (; *t == '/'; t++);
1922 for (; *s == *t && *s && *s != '/'; s++, t++);
1923 } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
1926 static void transform_symlink(const char *path, char **linkp)
1928 const char *l = *linkp;
1929 const char *b = sshfs.base_path;
1935 if (l[0] != '/' || b[0] != '/')
1938 strip_common(&l, &b);
1942 strip_common(&l, &path);
1943 dotdots = count_components(path);
1948 newlink = malloc(dotdots * 3 + strlen(l) + 2);
1950 fprintf(stderr, "sshfs: memory allocation failed\n");
1953 for (s = newlink, i = 0; i < dotdots; i++, s += 3)
1967 static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
1975 if (sshfs.server_version < 3)
1979 buf_add_path(&buf, path);
1980 err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
1985 if(buf_get_uint32(&name, &count) != -1 && count == 1 &&
1986 buf_get_string(&name, &link) != -1) {
1987 if (sshfs.transform_symlinks)
1988 transform_symlink(path, &link);
1989 strncpy(linkbuf, link, size - 1);
1990 linkbuf[size - 1] = '\0';
2000 static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
2001 fuse_cache_dirfil_t filler)
2005 struct buffer handle;
2007 buf_add_path(&buf, path);
2008 err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle);
2011 buf_finish(&handle);
2014 err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
2016 err = buf_get_entries(&name, h, filler);
2023 err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
2032 static int sshfs_mkdir(const char *path, mode_t mode)
2037 buf_add_path(&buf, path);
2038 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2039 buf_add_uint32(&buf, mode);
2040 err = sftp_request(SSH_FXP_MKDIR, &buf, SSH_FXP_STATUS, NULL);
2045 static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
2049 struct buffer handle;
2052 if ((mode & S_IFMT) != S_IFREG)
2056 buf_add_path(&buf, path);
2057 buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_EXCL);
2058 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2059 buf_add_uint32(&buf, mode);
2060 err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
2063 buf_finish(&handle);
2064 err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS,
2074 static int sshfs_symlink(const char *from, const char *to)
2079 if (sshfs.server_version < 3)
2082 /* openssh sftp server doesn't follow standard: link target and
2083 link name are mixed up, so we must also be non-standard :( */
2085 buf_add_string(&buf, from);
2086 buf_add_path(&buf, to);
2087 err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
2092 static int sshfs_unlink(const char *path)
2097 buf_add_path(&buf, path);
2098 err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
2103 static int sshfs_rmdir(const char *path)
2108 buf_add_path(&buf, path);
2109 err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
2114 static int sshfs_do_rename(const char *from, const char *to)
2119 buf_add_path(&buf, from);
2120 buf_add_path(&buf, to);
2121 err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
2126 static int sshfs_ext_posix_rename(const char *from, const char *to)
2131 buf_add_string(&buf, SFTP_EXT_POSIX_RENAME);
2132 buf_add_path(&buf, from);
2133 buf_add_path(&buf, to);
2134 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
2139 static void random_string(char *str, int length)
2142 for (i = 0; i < length; i++)
2143 *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10);
2147 static int sshfs_rename(const char *from, const char *to)
2150 if (sshfs.ext_posix_rename)
2151 err = sshfs_ext_posix_rename(from, to);
2153 err = sshfs_do_rename(from, to);
2154 if (err == -EPERM && sshfs.rename_workaround) {
2155 size_t tolen = strlen(to);
2156 if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
2158 char totmp[PATH_MAX];
2160 random_string(totmp + tolen, RENAME_TEMP_CHARS);
2161 tmperr = sshfs_do_rename(to, totmp);
2163 err = sshfs_do_rename(from, to);
2165 err = sshfs_unlink(totmp);
2167 sshfs_do_rename(totmp, to);
2174 static int sshfs_link(const char *from, const char *to)
2178 if (sshfs.ext_hardlink) {
2182 buf_add_string(&buf, SFTP_EXT_HARDLINK);
2183 buf_add_path(&buf, from);
2184 buf_add_path(&buf, to);
2185 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS,
2193 static int sshfs_chmod(const char *path, mode_t mode)
2198 buf_add_path(&buf, path);
2199 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2200 buf_add_uint32(&buf, mode);
2201 /* FIXME: really needs LSETSTAT extension (debian Bug#640038) */
2202 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2207 static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
2212 if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
2213 uid = sshfs.remote_uid;
2214 if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map)
2215 if(translate_id(&uid, sshfs.r_uid_map) == -1)
2217 if (sshfs.idmap == IDMAP_FILE && sshfs.r_gid_map)
2218 if (translate_id(&gid, sshfs.r_gid_map) == -1)
2222 buf_add_path(&buf, path);
2223 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
2224 buf_add_uint32(&buf, uid);
2225 buf_add_uint32(&buf, gid);
2226 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2231 static int sshfs_truncate_workaround(const char *path, off_t size,
2232 struct fuse_file_info *fi);
2234 static void sshfs_inc_modifver(void)
2236 pthread_mutex_lock(&sshfs.lock);
2238 pthread_mutex_unlock(&sshfs.lock);
2241 static int sshfs_truncate(const char *path, off_t size)
2246 sshfs_inc_modifver();
2247 if (size == 0 || sshfs.truncate_workaround)
2248 return sshfs_truncate_workaround(path, size, NULL);
2251 buf_add_path(&buf, path);
2252 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2253 buf_add_uint64(&buf, size);
2254 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2259 static int sshfs_utime(const char *path, struct utimbuf *ubuf)
2264 buf_add_path(&buf, path);
2265 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
2266 buf_add_uint32(&buf, ubuf->actime);
2267 buf_add_uint32(&buf, ubuf->modtime);
2268 err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
2273 static inline int sshfs_file_is_conn(struct sshfs_file *sf)
2277 pthread_mutex_lock(&sshfs.lock);
2278 ret = (sf->connver == sshfs.connver);
2279 pthread_mutex_unlock(&sshfs.lock);
2284 static int sshfs_open_common(const char *path, mode_t mode,
2285 struct fuse_file_info *fi)
2290 struct buffer outbuf;
2292 struct sshfs_file *sf;
2293 struct request *open_req;
2294 uint32_t pflags = 0;
2297 uint64_t wrctr = cache_get_write_ctr();
2299 if ((fi->flags & O_ACCMODE) == O_RDONLY)
2300 pflags = SSH_FXF_READ;
2301 else if((fi->flags & O_ACCMODE) == O_WRONLY)
2302 pflags = SSH_FXF_WRITE;
2303 else if ((fi->flags & O_ACCMODE) == O_RDWR)
2304 pflags = SSH_FXF_READ | SSH_FXF_WRITE;
2308 if (fi->flags & O_CREAT)
2309 pflags |= SSH_FXF_CREAT;
2311 if (fi->flags & O_EXCL)
2312 pflags |= SSH_FXF_EXCL;
2314 if (fi->flags & O_TRUNC)
2315 pflags |= SSH_FXF_TRUNC;
2317 sf = g_new0(struct sshfs_file, 1);
2318 list_init(&sf->write_reqs);
2319 pthread_cond_init(&sf->write_finished, NULL);
2320 /* Assume random read after open */
2324 pthread_mutex_lock(&sshfs.lock);
2325 sf->modifver= sshfs.modifver;
2326 sf->connver = sshfs.connver;
2327 pthread_mutex_unlock(&sshfs.lock);
2329 buf_add_path(&buf, path);
2330 buf_add_uint32(&buf, pflags);
2331 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
2332 buf_add_uint32(&buf, mode);
2333 buf_to_iov(&buf, &iov);
2334 sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL,
2337 buf_add_path(&buf, path);
2338 type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT;
2339 err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf);
2341 err2 = buf_get_attrs(&outbuf, &stbuf, NULL);
2344 err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE,
2347 buf_finish(&sf->handle);
2348 sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL);
2349 buf_free(&sf->handle);
2354 cache_add_attr(path, &stbuf, wrctr);
2355 buf_finish(&sf->handle);
2356 fi->fh = (unsigned long) sf;
2358 cache_invalidate(path);
2365 static int sshfs_open(const char *path, struct fuse_file_info *fi)
2367 return sshfs_open_common(path, 0, fi);
2370 static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
2372 return (struct sshfs_file *) (uintptr_t) fi->fh;
2375 static int sshfs_flush(const char *path, struct fuse_file_info *fi)
2378 struct sshfs_file *sf = get_sshfs_file(fi);
2379 struct list_head write_reqs;
2380 struct list_head *curr_list;
2382 if (!sshfs_file_is_conn(sf))
2385 if (sshfs.sync_write)
2389 pthread_mutex_lock(&sshfs.lock);
2390 if (!list_empty(&sf->write_reqs)) {
2391 curr_list = sf->write_reqs.prev;
2392 list_del(&sf->write_reqs);
2393 list_init(&sf->write_reqs);
2394 list_add(&write_reqs, curr_list);
2395 while (!list_empty(&write_reqs))
2396 pthread_cond_wait(&sf->write_finished, &sshfs.lock);
2398 err = sf->write_error;
2399 sf->write_error = 0;
2400 pthread_mutex_unlock(&sshfs.lock);
2404 static int sshfs_fsync(const char *path, int isdatasync,
2405 struct fuse_file_info *fi)
2408 return sshfs_flush(path, fi);
2411 static void sshfs_file_put(struct sshfs_file *sf)
2418 static void sshfs_file_get(struct sshfs_file *sf)
2423 static int sshfs_release(const char *path, struct fuse_file_info *fi)
2425 struct sshfs_file *sf = get_sshfs_file(fi);
2426 struct buffer *handle = &sf->handle;
2427 if (sshfs_file_is_conn(sf)) {
2428 sshfs_flush(path, fi);
2429 sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
2432 chunk_put_locked(sf->readahead);
2437 static void sshfs_read_end(struct request *req)
2439 struct read_req *rreq = (struct read_req *) req->data;
2441 rreq->res = req->error;
2442 else if (req->replied) {
2445 if (req->reply_type == SSH_FXP_STATUS) {
2447 if (buf_get_uint32(&req->reply, &serr) != -1) {
2448 if (serr == SSH_FX_EOF)
2451 rreq->res = -sftp_error_to_errno(serr);
2453 } else if (req->reply_type == SSH_FXP_DATA) {
2455 if (buf_get_uint32(&req->reply, &retsize) != -1) {
2456 if (retsize > rreq->size) {
2457 fprintf(stderr, "long read\n");
2458 } else if (buf_check_get(&req->reply, retsize) != -1) {
2459 rreq->res = retsize;
2460 rreq->data = req->reply;
2461 buf_init(&req->reply, 0);
2465 fprintf(stderr, "protocol error\n");
2471 rreq->sio->num_reqs--;
2472 if (!rreq->sio->num_reqs)
2473 pthread_cond_broadcast(&rreq->sio->finished);
2476 static void sshfs_read_begin(struct request *req)
2478 struct read_req *rreq = (struct read_req *) req->data;
2479 rreq->sio->num_reqs++;
2482 static struct read_chunk *sshfs_send_read(struct sshfs_file *sf, size_t size,
2485 struct read_chunk *chunk = g_new0(struct read_chunk, 1);
2486 struct buffer *handle = &sf->handle;
2488 pthread_cond_init(&chunk->sio.finished, NULL);
2489 list_init(&chunk->reqs);
2491 chunk->offset = offset;
2497 struct iovec iov[1];
2498 struct read_req *rreq;
2499 size_t bsize = size < sshfs.max_read ? size : sshfs.max_read;
2501 rreq = g_new0(struct read_req, 1);
2502 rreq->sio = &chunk->sio;
2504 buf_init(&rreq->data, 0);
2505 list_add(&rreq->list, &chunk->reqs);
2508 buf_add_buf(&buf, handle);
2509 buf_add_uint64(&buf, offset);
2510 buf_add_uint32(&buf, bsize);
2511 buf_to_iov(&buf, &iov[0]);
2512 err = sftp_request_send(SSH_FXP_READ, iov, 1,
2528 static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size)
2531 struct read_req *rreq;
2533 pthread_mutex_lock(&sshfs.lock);
2534 while (chunk->sio.num_reqs)
2535 pthread_cond_wait(&chunk->sio.finished, &sshfs.lock);
2536 pthread_mutex_unlock(&sshfs.lock);
2539 if (chunk->sio.error) {
2540 if (chunk->sio.error != MY_EOF)
2541 res = chunk->sio.error;
2546 while (!list_empty(&chunk->reqs) && size) {
2547 rreq = list_entry(chunk->reqs.prev, struct read_req, list);
2549 if (rreq->res < 0) {
2550 chunk->sio.error = rreq->res;
2552 } if (rreq->res == 0) {
2553 chunk->sio.error = MY_EOF;
2555 } else if (size < (size_t) rreq->res) {
2556 buf_get_mem(&rreq->data, buf, size);
2562 buf_get_mem(&rreq->data, buf, rreq->res);
2564 if ((size_t) rreq->res < rreq->size) {
2565 chunk->sio.error = MY_EOF;
2570 list_del(&rreq->list);
2571 buf_free(&rreq->data);
2577 chunk->offset += res;
2582 chunk_put_locked(chunk);
2586 static int sshfs_sync_read(struct sshfs_file *sf, char *buf, size_t size,
2589 struct read_chunk *chunk;
2591 chunk = sshfs_send_read(sf, size, offset);
2592 return wait_chunk(chunk, buf, size);
2595 static void submit_read(struct sshfs_file *sf, size_t size, off_t offset,
2596 struct read_chunk **chunkp)
2598 struct read_chunk *chunk;
2600 chunk = sshfs_send_read(sf, size, offset);
2601 pthread_mutex_lock(&sshfs.lock);
2602 chunk->modifver = sshfs.modifver;
2606 pthread_mutex_unlock(&sshfs.lock);
2609 static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset)
2611 struct read_chunk *ch = sf->readahead;
2612 if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) {
2619 static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size,
2624 struct read_chunk *chunk;
2625 struct read_chunk *chunk_prev = NULL;
2626 size_t origsize = size;
2629 pthread_mutex_lock(&sshfs.lock);
2630 curr_is_seq = sf->is_seq;
2631 sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver);
2632 sf->next_pos = offset + size;
2633 sf->modifver = sshfs.modifver;
2634 chunk = search_read_chunk(sf, offset);
2635 pthread_mutex_unlock(&sshfs.lock);
2637 if (chunk && chunk->size < size) {
2639 size -= chunk->size;
2640 offset += chunk->size;
2645 submit_read(sf, size, offset, &chunk);
2647 if (curr_is_seq && chunk && chunk->size <= size)
2648 submit_read(sf, origsize, offset + size, &sf->readahead);
2651 size_t prev_size = chunk_prev->size;
2652 res = wait_chunk(chunk_prev, rbuf, prev_size);
2653 if (res < (int) prev_size) {
2654 chunk_put_locked(chunk);
2660 res = wait_chunk(chunk, rbuf, size);
2669 static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
2670 struct fuse_file_info *fi)
2672 struct sshfs_file *sf = get_sshfs_file(fi);
2675 if (!sshfs_file_is_conn(sf))
2678 if (sshfs.sync_read)
2679 return sshfs_sync_read(sf, rbuf, size, offset);
2681 return sshfs_async_read(sf, rbuf, size, offset);
2684 static void sshfs_write_begin(struct request *req)
2686 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2689 list_add(&req->list, &sf->write_reqs);
2692 static void sshfs_write_end(struct request *req)
2695 struct sshfs_file *sf = (struct sshfs_file *) req->data;
2698 sf->write_error = req->error;
2699 else if (req->replied) {
2700 if (req->reply_type != SSH_FXP_STATUS) {
2701 fprintf(stderr, "protocol error\n");
2702 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2703 serr != SSH_FX_OK) {
2704 sf->write_error = -EIO;
2707 list_del(&req->list);
2708 pthread_cond_broadcast(&sf->write_finished);
2712 static int sshfs_async_write(struct sshfs_file *sf, const char *wbuf,
2713 size_t size, off_t offset)
2716 struct buffer *handle = &sf->handle;
2718 while (!err && size) {
2720 struct iovec iov[2];
2721 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2724 buf_add_buf(&buf, handle);
2725 buf_add_uint64(&buf, offset);
2726 buf_add_uint32(&buf, bsize);
2727 buf_to_iov(&buf, &iov[0]);
2728 iov[1].iov_base = (void *) wbuf;
2729 iov[1].iov_len = bsize;
2730 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2731 sshfs_write_begin, sshfs_write_end,
2742 static void sshfs_sync_write_begin(struct request *req)
2744 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2748 static void sshfs_sync_write_end(struct request *req)
2751 struct sshfs_io *sio = (struct sshfs_io *) req->data;
2754 sio->error = req->error;
2755 } else if (req->replied) {
2756 if (req->reply_type != SSH_FXP_STATUS) {
2757 fprintf(stderr, "protocol error\n");
2758 } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2759 serr != SSH_FX_OK) {
2765 pthread_cond_broadcast(&sio->finished);
2769 static int sshfs_sync_write(struct sshfs_file *sf, const char *wbuf,
2770 size_t size, off_t offset)
2773 struct buffer *handle = &sf->handle;
2774 struct sshfs_io sio = { .error = 0, .num_reqs = 0 };
2776 pthread_cond_init(&sio.finished, NULL);
2778 while (!err && size) {
2780 struct iovec iov[2];
2781 size_t bsize = size < sshfs.max_write ? size : sshfs.max_write;
2784 buf_add_buf(&buf, handle);
2785 buf_add_uint64(&buf, offset);
2786 buf_add_uint32(&buf, bsize);
2787 buf_to_iov(&buf, &iov[0]);
2788 iov[1].iov_base = (void *) wbuf;
2789 iov[1].iov_len = bsize;
2790 err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2791 sshfs_sync_write_begin,
2792 sshfs_sync_write_end,
2800 pthread_mutex_lock(&sshfs.lock);
2801 while (sio.num_reqs)
2802 pthread_cond_wait(&sio.finished, &sshfs.lock);
2803 pthread_mutex_unlock(&sshfs.lock);
2811 static int sshfs_write(const char *path, const char *wbuf, size_t size,
2812 off_t offset, struct fuse_file_info *fi)
2815 struct sshfs_file *sf = get_sshfs_file(fi);
2819 if (!sshfs_file_is_conn(sf))
2822 sshfs_inc_modifver();
2824 if (!sshfs.sync_write && !sf->write_error)
2825 err = sshfs_async_write(sf, wbuf, size, offset);
2827 err = sshfs_sync_write(sf, wbuf, size, offset);
2829 return err ? err : (int) size;
2832 static int sshfs_ext_statvfs(const char *path, struct statvfs *stbuf)
2836 struct buffer outbuf;
2838 buf_add_string(&buf, SFTP_EXT_STATVFS);
2839 buf_add_path(&buf, path);
2840 err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_EXTENDED_REPLY,
2843 if (buf_get_statvfs(&outbuf, stbuf) == -1)
2852 #if FUSE_VERSION >= 25
2853 static int sshfs_statfs(const char *path, struct statvfs *buf)
2855 if (sshfs.ext_statvfs)
2856 return sshfs_ext_statvfs(path, buf);
2858 buf->f_namemax = 255;
2859 buf->f_bsize = sshfs.blksize;
2861 * df seems to use f_bsize instead of f_frsize, so make them
2864 buf->f_frsize = buf->f_bsize;
2865 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2866 1000ULL * 1024 * 1024 * 1024 / buf->f_frsize;
2867 buf->f_files = buf->f_ffree = 1000000000;
2871 static int sshfs_statfs(const char *path, struct statfs *buf)
2873 if (sshfs.ext_statvfs) {
2875 struct statvfs vbuf;
2877 err = sshfs_ext_statvfs(path, &vbuf);
2879 buf->f_bsize = vbuf.f_bsize;
2880 buf->f_blocks = vbuf.f_blocks;
2881 buf->f_bfree = vbuf.f_bfree;
2882 buf->f_bavail = vbuf.f_bavail;
2883 buf->f_files = vbuf.f_files;
2884 buf->f_ffree = vbuf.f_ffree;
2885 buf->f_namelen = vbuf.f_namemax;
2890 buf->f_namelen = 255;
2891 buf->f_bsize = sshfs.blksize;
2892 buf->f_blocks = buf->f_bfree = buf->f_bavail =
2893 1000ULL * 1024 * 1024 * 1024 / buf->f_bsize;
2894 buf->f_files = buf->f_ffree = 1000000000;
2899 #if FUSE_VERSION >= 25
2900 static int sshfs_create(const char *path, mode_t mode,
2901 struct fuse_file_info *fi)
2903 return sshfs_open_common(path, mode, fi);
2906 static int sshfs_ftruncate(const char *path, off_t size,
2907 struct fuse_file_info *fi)
2911 struct sshfs_file *sf = get_sshfs_file(fi);
2915 if (!sshfs_file_is_conn(sf))
2918 sshfs_inc_modifver();
2919 if (sshfs.truncate_workaround)
2920 return sshfs_truncate_workaround(path, size, fi);
2923 buf_add_buf(&buf, &sf->handle);
2924 buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2925 buf_add_uint64(&buf, size);
2926 err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL);
2933 static int sshfs_fgetattr(const char *path, struct stat *stbuf,
2934 struct fuse_file_info *fi)
2938 struct buffer outbuf;
2939 struct sshfs_file *sf = get_sshfs_file(fi);
2943 if (!sshfs_file_is_conn(sf))
2946 if (sshfs.fstat_workaround)
2947 return sshfs_getattr(path, stbuf);
2950 buf_add_buf(&buf, &sf->handle);
2951 err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
2953 err = buf_get_attrs(&outbuf, stbuf, NULL);
2960 static int sshfs_truncate_zero(const char *path)
2963 struct fuse_file_info fi;
2965 fi.flags = O_WRONLY | O_TRUNC;
2966 err = sshfs_open(path, &fi);
2968 sshfs_release(path, &fi);
2973 static size_t calc_buf_size(off_t size, off_t offset)
2975 return offset + sshfs.max_read < size ? sshfs.max_read : size - offset;
2978 static int sshfs_truncate_shrink(const char *path, off_t size)
2983 struct fuse_file_info fi;
2985 data = calloc(size, 1);
2989 fi.flags = O_RDONLY;
2990 res = sshfs_open(path, &fi);
2994 for (offset = 0; offset < size; offset += res) {
2995 size_t bufsize = calc_buf_size(size, offset);
2996 res = sshfs_read(path, data + offset, bufsize, offset, &fi);
3000 sshfs_release(path, &fi);
3004 fi.flags = O_WRONLY | O_TRUNC;
3005 res = sshfs_open(path, &fi);
3009 for (offset = 0; offset < size; offset += res) {
3010 size_t bufsize = calc_buf_size(size, offset);
3011 res = sshfs_write(path, data + offset, bufsize, offset, &fi);
3016 res = sshfs_flush(path, &fi);
3017 sshfs_release(path, &fi);
3024 static int sshfs_truncate_extend(const char *path, off_t size,
3025 struct fuse_file_info *fi)
3029 struct fuse_file_info tmpfi;
3030 struct fuse_file_info *openfi = fi;
3033 openfi->flags = O_WRONLY;
3034 res = sshfs_open(path, openfi);
3038 res = sshfs_write(path, &c, 1, size - 1, openfi);
3040 res = sshfs_flush(path, openfi);
3042 sshfs_release(path, openfi);
3048 * Work around broken sftp servers which don't handle
3049 * SSH_FILEXFER_ATTR_SIZE in SETSTAT request.
3051 * If new size is zero, just open the file with O_TRUNC.
3053 * If new size is smaller than current size, then copy file locally,
3054 * then open/trunc and send it back.
3056 * If new size is greater than current size, then write a zero byte to
3057 * the new end of the file.
3059 static int sshfs_truncate_workaround(const char *path, off_t size,
3060 struct fuse_file_info *fi)
3063 return sshfs_truncate_zero(path);
3068 err = sshfs_fgetattr(path, &stbuf, fi);
3070 err = sshfs_getattr(path, &stbuf);
3073 if (stbuf.st_size == size)
3075 else if (stbuf.st_size > size)
3076 return sshfs_truncate_shrink(path, size);
3078 return sshfs_truncate_extend(path, size, fi);
3082 static int processing_init(void)
3084 signal(SIGPIPE, SIG_IGN);
3086 pthread_mutex_init(&sshfs.lock, NULL);
3087 pthread_mutex_init(&sshfs.lock_write, NULL);
3088 pthread_cond_init(&sshfs.outstanding_cond, NULL);
3089 sshfs.reqtab = g_hash_table_new(NULL, NULL);
3090 if (!sshfs.reqtab) {
3091 fprintf(stderr, "failed to create hash table\n");
3097 static struct fuse_cache_operations sshfs_oper = {
3100 .getattr = sshfs_getattr,
3101 .readlink = sshfs_readlink,
3102 .mknod = sshfs_mknod,
3103 .mkdir = sshfs_mkdir,
3104 .symlink = sshfs_symlink,
3105 .unlink = sshfs_unlink,
3106 .rmdir = sshfs_rmdir,
3107 .rename = sshfs_rename,
3109 .chmod = sshfs_chmod,
3110 .chown = sshfs_chown,
3111 .truncate = sshfs_truncate,
3112 .utime = sshfs_utime,
3114 .flush = sshfs_flush,
3115 .fsync = sshfs_fsync,
3116 .release = sshfs_release,
3118 .write = sshfs_write,
3119 .statfs = sshfs_statfs,
3120 #if FUSE_VERSION >= 25
3121 .create = sshfs_create,
3122 .ftruncate = sshfs_ftruncate,
3123 .fgetattr = sshfs_fgetattr,
3126 .cache_getdir = sshfs_getdir,
3129 static void usage(const char *progname)
3132 "usage: %s [user@]host:[dir] mountpoint [options]\n"
3134 "general options:\n"
3135 " -o opt,[opt...] mount options\n"
3136 " -h --help print help\n"
3137 " -V --version print version\n"
3140 " -p PORT equivalent to '-o port=PORT'\n"
3141 " -C equivalent to '-o compression=yes'\n"
3142 " -F ssh_configfile specifies alternative ssh configuration file\n"
3143 " -1 equivalent to '-o ssh_protocol=1'\n"
3144 " -o reconnect reconnect to server\n"
3145 " -o delay_connect delay connection to server\n"
3146 " -o sshfs_sync synchronous writes\n"
3147 " -o no_readahead synchronous reads (no speculative readahead)\n"
3148 " -o sshfs_debug print some debugging information\n"
3149 " -o cache=BOOL enable caching {yes,no} (default: yes)\n"
3150 " -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
3151 " -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n"
3152 " -o workaround=LIST colon separated list of workarounds\n"
3153 " none no workarounds enabled\n"
3154 " all all workarounds enabled\n"
3155 " [no]rename fix renaming to existing file (default: off)\n"
3156 #ifdef SSH_NODELAY_WORKAROUND
3157 " [no]nodelay set nodelay tcp flag in ssh (default: on)\n"
3159 " [no]nodelaysrv set nodelay tcp flag in sshd (default: off)\n"
3160 " [no]truncate fix truncate for old servers (default: off)\n"
3161 " [no]buflimit fix buffer fillup bug in server (default: on)\n"
3162 " -o idmap=TYPE user/group ID mapping, possible types are:\n"
3163 " none no translation of the ID space (default)\n"
3164 " user only translate UID of connecting user\n"
3165 " file translate UIDs/GIDs contained in uidfile/gidfile\n"
3166 " -o uidfile=FILE file containing username:remote_uid mappings\n"
3167 " -o gidfile=FILE file containing groupname:remote_gid mappings\n"
3168 " -o nomap=TYPE with idmap=file, how to handle missing mappings\n"
3169 " ignore don't do any re-mapping\n"
3170 " error return an error (default)\n"
3171 " -o ssh_command=CMD execute CMD instead of 'ssh'\n"
3172 " -o ssh_protocol=N ssh protocol to use (default: 2)\n"
3173 " -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n"
3174 " -o directport=PORT directly connect to PORT bypassing ssh\n"
3175 " -o transform_symlinks transform absolute symlinks to relative\n"
3176 " -o follow_symlinks follow symlinks on the server\n"
3177 " -o no_check_root don't check for existence of 'dir' on server\n"
3178 " -o password_stdin read password from stdin (only for pam_mount!)\n"
3179 " -o SSHOPT=VAL ssh options (see man ssh_config)\n"
3183 static int is_ssh_opt(const char *arg)
3185 if (arg[0] != '-') {
3186 unsigned arglen = strlen(arg);
3188 for (o = ssh_opts; *o; o++) {
3189 unsigned olen = strlen(*o);
3190 if (arglen > olen && arg[olen] == '=' &&
3191 strncasecmp(arg, *o, olen) == 0)
3198 static int sshfs_fuse_main(struct fuse_args *args)
3200 #if FUSE_VERSION >= 26
3201 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL);
3203 return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper));
3207 static int sshfs_opt_proc(void *data, const char *arg, int key,
3208 struct fuse_args *outargs)
3214 case FUSE_OPT_KEY_OPT:
3215 if (is_ssh_opt(arg)) {
3216 tmp = g_strdup_printf("-o%s", arg);
3223 case FUSE_OPT_KEY_NONOPT:
3224 if (!sshfs.host && strchr(arg, ':')) {
3225 sshfs.host = strdup(arg);
3231 tmp = g_strdup_printf("-oPort=%s", arg + 2);
3237 ssh_add_arg("-oCompression=yes");
3240 case KEY_CONFIGFILE:
3241 tmp = g_strdup_printf("-F%s", arg + 2);
3247 usage(outargs->argv[0]);
3248 fuse_opt_add_arg(outargs, "-ho");
3249 sshfs_fuse_main(outargs);
3253 printf("SSHFS version %s\n", PACKAGE_VERSION);
3254 #if FUSE_VERSION >= 25
3255 fuse_opt_add_arg(outargs, "--version");
3256 sshfs_fuse_main(outargs);
3260 case KEY_FOREGROUND:
3261 sshfs.foreground = 1;
3265 fprintf(stderr, "internal error\n");
3270 static int workaround_opt_proc(void *data, const char *arg, int key,
3271 struct fuse_args *outargs)
3273 (void) data; (void) key; (void) outargs;
3274 fprintf(stderr, "unknown workaround: '%s'\n", arg);
3278 int parse_workarounds(void)
3281 char *argv[] = { "", "-o", sshfs.workarounds, NULL };
3282 struct fuse_args args = FUSE_ARGS_INIT(3, argv);
3283 char *s = sshfs.workarounds;
3287 while ((s = strchr(s, ':')))
3290 res = fuse_opt_parse(&args, &sshfs, workaround_opts,
3291 workaround_opt_proc);
3292 fuse_opt_free_args(&args);
3297 #if FUSE_VERSION == 25
3298 static int fuse_opt_insert_arg(struct fuse_args *args, int pos,
3301 assert(pos <= args->argc);
3302 if (fuse_opt_add_arg(args, arg) == -1)
3305 if (pos != args->argc - 1) {
3306 char *newarg = args->argv[args->argc - 1];
3307 memmove(&args->argv[pos + 1], &args->argv[pos],
3308 sizeof(char *) * (args->argc - pos - 1));
3309 args->argv[pos] = newarg;
3315 static void check_large_read(struct fuse_args *args)
3318 int err = uname(&buf);
3319 if (!err && strcmp(buf.sysname, "Linux") == 0 &&
3320 strncmp(buf.release, "2.4.", 4) == 0)
3321 fuse_opt_insert_arg(args, 1, "-olarge_read");
3324 static int read_password(void)
3326 int size = getpagesize();
3327 int max_password = 64;
3330 sshfs.password = mmap(NULL, size, PROT_READ | PROT_WRITE,
3331 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED,
3333 if (sshfs.password == MAP_FAILED) {
3334 perror("Failed to allocate locked page for password");
3338 /* Don't use fgets() because password might stay in memory */
3339 for (n = 0; n < max_password; n++) {
3342 res = read(0, &sshfs.password[n], 1);
3344 perror("Reading password");
3348 sshfs.password[n] = '\n';
3351 if (sshfs.password[n] == '\n')
3354 if (n == max_password) {
3355 fprintf(stderr, "Password too long\n");
3358 sshfs.password[n+1] = '\0';
3359 ssh_add_arg("-oNumberOfPasswordPrompts=1");
3364 static void set_ssh_command(void)
3371 d = sshfs.ssh_command;
3372 s = sshfs.ssh_command;
3380 replace_arg(&sshfs.ssh_args.argv[0],
3383 if (fuse_opt_insert_arg(&sshfs.ssh_args, i,
3384 sshfs.ssh_command) == -1)
3388 d = sshfs.ssh_command;
3401 static char *find_base_path(void)
3403 char *s = sshfs.host;
3406 for (; *s && *s != ':'; s++) {
3409 * Handle IPv6 numerical address enclosed in square
3413 for (; *s != ']'; s++) {
3415 fprintf(stderr, "missing ']' in hostname\n");
3432 * Remove commas from fsname, as it confuses the fuse option parser.
3434 static void fsname_remove_commas(char *fsname)
3436 if (strchr(fsname, ',') != NULL) {
3448 #if FUSE_VERSION >= 27
3449 static char *fsname_escape_commas(char *fsnameold)
3451 char *fsname = g_malloc(strlen(fsnameold) * 2 + 1);
3455 for (s = fsnameold; *s; s++) {
3456 if (*s == '\\' || *s == ',')
3467 static int ssh_connect(void)
3471 res = processing_init();
3475 if (!sshfs.delay_connect) {
3476 if (connect_remote() == -1)
3479 if (!sshfs.no_check_root &&
3480 sftp_check_root(sshfs.base_path) != 0)
3487 /* number of ':' separated fields in a passwd/group file that we care
3489 #define IDMAP_FIELDS 3
3491 /* given a line from a uidmap or gidmap, parse out the name and id */
3492 static void parse_idmap_line(char *line, const char* filename,
3493 const unsigned int lineno, uint32_t *ret_id, char **ret_name,
3496 /* chomp off the trailing newline */
3498 if ((p = strrchr(line, '\n')))
3501 fprintf(stderr, "%s:%u: line too long\n", filename, lineno);
3504 char *tokens[IDMAP_FIELDS];
3507 for (i = 0; (tok = strsep(&line, ":")) && (i < IDMAP_FIELDS) ; i++) {
3511 char *name_tok, *id_tok;
3513 /* assume name:id format */
3514 name_tok = tokens[0];
3516 } else if (i >= IDMAP_FIELDS) {
3517 /* assume passwd/group file format */
3518 name_tok = tokens[0];
3521 fprintf(stderr, "%s:%u: unknown format\n", filename, lineno);
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);
3544 char line[LINE_MAX];
3545 unsigned int lineno = 0;
3547 fp = fopen(file, "r");
3549 fprintf(stderr, "failed to open '%s': %s\n",
3550 file, strerror(errno));
3554 while (fgets(line, LINE_MAX, fp) != NULL) {
3559 parse_idmap_line(line, file, lineno, &remote_id, &name, feof(fp));
3561 uint32_t *local_id = map_fn(name);
3562 if (local_id == NULL) {
3564 DEBUG("%s(%u): no local %s\n", name, remote_id, name_id);
3569 DEBUG("%s: remote %s %u => local %s %u\n",
3570 name, name_id, remote_id, name_id, *local_id);
3571 g_hash_table_insert(*idmap, GUINT_TO_POINTER(remote_id), GUINT_TO_POINTER(*local_id));
3572 g_hash_table_insert(*r_idmap, GUINT_TO_POINTER(*local_id), GUINT_TO_POINTER(remote_id));
3577 if (fclose(fp) == EOF) {
3578 fprintf(stderr, "failed to close '%s': %s",
3579 file, strerror(errno));
3584 /* given a username, return a pointer to its uid, or NULL if it doesn't
3585 * exist on this system */
3586 static uint32_t *username_to_uid(char *name)
3589 struct passwd *pw = getpwnam(name);
3592 /* "does not exist" */
3595 fprintf(stderr, "Failed to look up user '%s': %s\n",
3596 name, strerror(errno));
3599 uint32_t *r = malloc(sizeof(uint32_t));
3601 fprintf(stderr, "sshfs: memory allocation failed\n");
3608 /* given a groupname, return a pointer to its gid, or NULL if it doesn't
3609 * exist on this system */
3610 static uint32_t *groupname_to_gid(char *name)
3613 struct group *gr = getgrnam(name);
3616 /* "does not exist" */
3619 fprintf(stderr, "Failed to look up group '%s': %s\n",
3620 name, strerror(errno));
3623 uint32_t *r = malloc(sizeof(uint32_t));
3625 fprintf(stderr, "sshfs: memory allocation failed\n");
3632 static inline void load_uid_map(void)
3634 read_id_map(sshfs.uid_file, &username_to_uid, "uid", &sshfs.uid_map, &sshfs.r_uid_map);
3637 static inline void load_gid_map(void)
3639 read_id_map(sshfs.gid_file, &groupname_to_gid, "gid", &sshfs.gid_map, &sshfs.r_gid_map);
3642 int main(int argc, char *argv[])
3645 struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
3648 const char *sftp_server;
3651 g_thread_init(NULL);
3653 sshfs.blksize = 4096;
3654 /* SFTP spec says all servers should allow at least 32k I/O */
3655 sshfs.max_read = 32768;
3656 sshfs.max_write = 32768;
3657 sshfs.nodelay_workaround = 1;
3658 sshfs.nodelaysrv_workaround = 0;
3659 sshfs.rename_workaround = 0;
3660 sshfs.truncate_workaround = 0;
3661 sshfs.buflimit_workaround = 1;
3663 sshfs.progname = argv[0];
3666 sshfs.ptyslavefd = -1;
3667 sshfs.delay_connect = 0;
3668 sshfs.detect_uid = 0;
3669 sshfs.idmap = IDMAP_NONE;
3670 sshfs.nomap = NOMAP_ERROR;
3674 ssh_add_arg("-oClearAllForwardings=yes");
3676 if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 ||
3677 parse_workarounds() == -1)
3680 if (sshfs.idmap == IDMAP_USER)
3681 sshfs.detect_uid = 1;
3682 else if (sshfs.idmap == IDMAP_FILE) {
3683 sshfs.uid_map = NULL;
3684 sshfs.gid_map = NULL;
3685 sshfs.r_uid_map = NULL;
3686 sshfs.r_gid_map = NULL;
3687 if (!sshfs.uid_file && !sshfs.gid_file) {
3688 fprintf(stderr, "need a uidfile or gidfile with idmap=file\n");
3696 free(sshfs.uid_file);
3697 free(sshfs.gid_file);
3699 DEBUG("SSHFS version %s\n", PACKAGE_VERSION);
3701 if (sshfs.password_stdin) {
3702 res = read_password();
3707 if (sshfs.buflimit_workaround)
3708 /* Work around buggy sftp-server in OpenSSH. Without this on
3709 a slow server a 10Mbyte buffer would fill up and the server
3711 sshfs.max_outstanding_len = 8388608;
3713 sshfs.max_outstanding_len = ~0;
3716 fprintf(stderr, "missing host\n");
3717 fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
3721 fsname = g_strdup(sshfs.host);
3722 sshfs.base_path = g_strdup(find_base_path());
3724 if (sshfs.ssh_command)
3727 tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
3730 ssh_add_arg(sshfs.host);
3731 if (sshfs.sftp_server)
3732 sftp_server = sshfs.sftp_server;
3733 else if (sshfs.ssh_ver == 1)
3734 sftp_server = SFTP_SERVER_PATH;
3736 sftp_server = "sftp";
3738 if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
3741 ssh_add_arg(sftp_server);
3742 free(sshfs.sftp_server);
3745 res = cache_parse_options(&args);
3749 sshfs.randseed = time(0);
3751 if (sshfs.max_read > 65536)
3752 sshfs.max_read = 65536;
3753 if (sshfs.max_write > 65536)
3754 sshfs.max_write = 65536;
3756 if (fuse_is_lib_option("ac_attr_timeout="))
3757 fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
3758 #if FUSE_VERSION >= 27
3759 libver = fuse_version();
3760 assert(libver >= 27);
3762 fsname = fsname_escape_commas(fsname);
3764 fsname_remove_commas(fsname);
3765 tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
3767 fsname_remove_commas(fsname);
3768 tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
3770 fuse_opt_insert_arg(&args, 1, tmp);
3773 check_large_read(&args);
3775 #if FUSE_VERSION >= 26
3778 struct fuse_chan *ch;
3784 res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded,
3789 res = stat(mountpoint, &st);
3794 sshfs.mnt_mode = st.st_mode;
3796 ch = fuse_mount(mountpoint, &args);
3800 res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC);
3802 perror("WARNING: failed to set FD_CLOEXEC on fuse device");
3804 fuse = fuse_new(ch, &args, cache_init(&sshfs_oper),
3805 sizeof(struct fuse_operations), NULL);
3807 fuse_unmount(mountpoint, ch);
3811 res = ssh_connect();
3813 fuse_unmount(mountpoint, ch);
3818 res = fuse_daemonize(foreground);
3820 res = fuse_set_signal_handlers(fuse_get_session(fuse));
3823 fuse_unmount(mountpoint, ch);
3829 res = fuse_loop_mt(fuse);
3831 res = fuse_loop(fuse);
3838 fuse_remove_signal_handlers(fuse_get_session(fuse));
3839 fuse_unmount(mountpoint, ch);
3844 res = ssh_connect();
3848 res = sshfs_fuse_main(&args);
3852 unsigned int avg_rtt = 0;
3855 avg_rtt = sshfs.total_rtt / sshfs.num_sent;
3858 "sent: %llu messages, %llu bytes\n"
3859 "received: %llu messages, %llu bytes\n"
3860 "rtt min/max/avg: %ums/%ums/%ums\n"
3861 "num connect: %u\n",
3862 (unsigned long long) sshfs.num_sent,
3863 (unsigned long long) sshfs.bytes_sent,
3864 (unsigned long long) sshfs.num_received,
3865 (unsigned long long) sshfs.bytes_received,
3866 sshfs.min_rtt, sshfs.max_rtt, avg_rtt,
3870 fuse_opt_free_args(&args);
3871 fuse_opt_free_args(&sshfs.ssh_args);
3872 free(sshfs.directport);