source: FTPfs/sshfs-fuse-1.9/sshfs.c @ 195

Last change on this file since 195 was 10, checked in by zsjheng, 17 years ago
File size: 62.5 KB
RevLine 
[10]1/*
2  SSH file system
3  Copyright (C) 2004  Miklos Szeredi <miklos@szeredi.hu>
4
5  This program can be distributed under the terms of the GNU GPL.
6  See the file COPYING.
7*/
8
9#include "config.h"
10
11#include <fuse.h>
12#include <fuse_opt.h>
13#include <assert.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <string.h>
19#include <stdint.h>
20#include <errno.h>
21#include <semaphore.h>
22#include <pthread.h>
23#include <netdb.h>
24#include <signal.h>
25#include <sys/uio.h>
26#include <sys/time.h>
27#include <sys/wait.h>
28#include <sys/socket.h>
29#include <sys/utsname.h>
30#include <netinet/in.h>
31#include <netinet/tcp.h>
32#include <glib.h>
33
34#include "cache.h"
35
36#if FUSE_VERSION >= 23
37#define SSHFS_USE_INIT
38#endif
39
40#define SSH_FXP_INIT                1
41#define SSH_FXP_VERSION             2
42#define SSH_FXP_OPEN                3
43#define SSH_FXP_CLOSE               4
44#define SSH_FXP_READ                5
45#define SSH_FXP_WRITE               6
46#define SSH_FXP_LSTAT               7
47#define SSH_FXP_FSTAT               8
48#define SSH_FXP_SETSTAT             9
49#define SSH_FXP_FSETSTAT           10
50#define SSH_FXP_OPENDIR            11
51#define SSH_FXP_READDIR            12
52#define SSH_FXP_REMOVE             13
53#define SSH_FXP_MKDIR              14
54#define SSH_FXP_RMDIR              15
55#define SSH_FXP_REALPATH           16
56#define SSH_FXP_STAT               17
57#define SSH_FXP_RENAME             18
58#define SSH_FXP_READLINK           19
59#define SSH_FXP_SYMLINK            20
60#define SSH_FXP_STATUS            101
61#define SSH_FXP_HANDLE            102
62#define SSH_FXP_DATA              103
63#define SSH_FXP_NAME              104
64#define SSH_FXP_ATTRS             105
65#define SSH_FXP_EXTENDED          200
66#define SSH_FXP_EXTENDED_REPLY    201
67
68#define SSH_FILEXFER_ATTR_SIZE          0x00000001
69#define SSH_FILEXFER_ATTR_UIDGID        0x00000002
70#define SSH_FILEXFER_ATTR_PERMISSIONS   0x00000004
71#define SSH_FILEXFER_ATTR_ACMODTIME     0x00000008
72#define SSH_FILEXFER_ATTR_EXTENDED      0x80000000
73
74#define SSH_FX_OK                            0
75#define SSH_FX_EOF                           1
76#define SSH_FX_NO_SUCH_FILE                  2
77#define SSH_FX_PERMISSION_DENIED             3
78#define SSH_FX_FAILURE                       4
79#define SSH_FX_BAD_MESSAGE                   5
80#define SSH_FX_NO_CONNECTION                 6
81#define SSH_FX_CONNECTION_LOST               7
82#define SSH_FX_OP_UNSUPPORTED                8
83
84#define SSH_FXF_READ            0x00000001
85#define SSH_FXF_WRITE           0x00000002
86#define SSH_FXF_APPEND          0x00000004
87#define SSH_FXF_CREAT           0x00000008
88#define SSH_FXF_TRUNC           0x00000010
89#define SSH_FXF_EXCL            0x00000020
90
91#define PROTO_VERSION 3
92
93#define MY_EOF 1
94
95#define MAX_REPLY_LEN (1 << 17)
96
97#define RENAME_TEMP_CHARS 8
98
99#define SFTP_SERVER_PATH "/usr/lib/sftp-server"
100
101#define SSHNODELAY_SO "sshnodelay.so"
102
103struct buffer {
104  uint8_t *p;
105  size_t len;
106  size_t size;
107};
108
109struct list_head {
110  struct list_head *prev;
111  struct list_head *next;
112};
113
114struct request;
115typedef void (*request_func)(struct request *);
116
117struct request {
118  unsigned int want_reply;
119  sem_t ready;
120  uint8_t reply_type;
121  int replied;
122  int error;
123  struct buffer reply;
124  struct timeval start;
125  void *data;
126  request_func end_func;
127  size_t len;
128  struct list_head list;
129};
130
131struct read_chunk {
132  sem_t ready;
133  off_t offset;
134  size_t size;
135  struct buffer data;
136  int refs;
137  int res;
138  long modifver;
139};
140
141struct sshfs_file {
142  struct buffer handle;
143  struct list_head write_reqs;
144  pthread_cond_t write_finished;
145  int write_error;
146  struct read_chunk *readahead;
147  off_t next_pos;
148  int is_seq;
149  int connver;
150  int modifver;
151  int refs;
152};
153
154struct sshfs {
155  char *directport;
156  char *ssh_command;
157  char *sftp_server;
158  struct fuse_args ssh_args;
159  char *workarounds;
160  int rename_workaround;
161  int nodelay_workaround;
162  int nodelaysrv_workaround;
163  int truncate_workaround;
164  int buflimit_workaround;
165  int transform_symlinks;
166  int follow_symlinks;
167  int no_check_root;
168  int detect_uid;
169  unsigned max_read;
170  unsigned ssh_ver;
171  int sync_write;
172  int sync_read;
173  int debug;
174  int reconnect;
175  char *host;
176  char *base_path;
177  GHashTable *reqtab;
178  pthread_mutex_t lock;
179  pthread_mutex_t lock_write;
180  int processing_thread_started;
181  unsigned int randseed;
182  int fd;
183  int connver;
184  int server_version;
185  unsigned remote_uid;
186  unsigned local_uid;
187  int remote_uid_detected;
188  unsigned blksize;
189  char *progname;
190  long modifver;
191  unsigned outstanding_len;
192  unsigned max_outstanding_len;
193  pthread_cond_t outstanding_cond;
194};
195
196static struct sshfs sshfs;
197
198static const char *ssh_opts[] = {
199  "AddressFamily",
200  "BatchMode",
201  "BindAddress",
202  "ChallengeResponseAuthentication",
203  "CheckHostIP",
204  "Cipher",
205  "Ciphers",
206  "Compression",
207  "CompressionLevel",
208  "ConnectionAttempts",
209  "ConnectTimeout",
210  "GlobalKnownHostsFile",
211  "GSSAPIAuthentication",
212  "GSSAPIDelegateCredentials",
213  "HostbasedAuthentication",
214  "HostKeyAlgorithms",
215  "HostKeyAlias",
216  "HostName",
217  "IdentityFile",
218  "IdentitiesOnly",
219  "LogLevel",
220  "MACs",
221  "NoHostAuthenticationForLocalhost",
222  "NumberOfPasswordPrompts",
223  "PasswordAuthentication",
224  "Port",
225  "PreferredAuthentications",
226  "ProxyCommand",
227  "PubkeyAuthentication",
228  "RhostsRSAAuthentication",
229  "RSAAuthentication",
230  "ServerAliveInterval",
231  "ServerAliveCountMax",
232  "SmartcardDevice",
233  "StrictHostKeyChecking",
234  "TCPKeepAlive",
235  "UsePrivilegedPort",
236  "UserKnownHostsFile",
237  "VerifyHostKeyDNS",
238  NULL,
239};
240
241enum {
242  KEY_PORT,
243  KEY_COMPRESS,
244  KEY_HELP,
245  KEY_VERSION,
246};
247
248#define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v }
249
250static struct fuse_opt sshfs_opts[] = {
251  SSHFS_OPT("directport=%s",     directport, 0),
252  SSHFS_OPT("ssh_command=%s",    ssh_command, 0),
253  SSHFS_OPT("sftp_server=%s",    sftp_server, 0),
254  SSHFS_OPT("max_read=%u",       max_read, 0),
255  SSHFS_OPT("ssh_protocol=%u",   ssh_ver, 0),
256  SSHFS_OPT("-1",                ssh_ver, 1),
257  SSHFS_OPT("workaround=%s",     workarounds, 0),
258  SSHFS_OPT("idmap=none",        detect_uid, 0),
259  SSHFS_OPT("idmap=user",        detect_uid, 1),
260  SSHFS_OPT("sshfs_sync",        sync_write, 1),
261  SSHFS_OPT("no_readahead",      sync_read, 1),
262  SSHFS_OPT("sshfs_debug",       debug, 1),
263  SSHFS_OPT("reconnect",         reconnect, 1),
264  SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
265  SSHFS_OPT("follow_symlinks",   follow_symlinks, 1),
266  SSHFS_OPT("no_check_root",     no_check_root, 1),
267
268  FUSE_OPT_KEY("-p ",            KEY_PORT),
269  FUSE_OPT_KEY("-C",             KEY_COMPRESS),
270  FUSE_OPT_KEY("-V",             KEY_VERSION),
271  FUSE_OPT_KEY("--version",      KEY_VERSION),
272  FUSE_OPT_KEY("-h",             KEY_HELP),
273  FUSE_OPT_KEY("--help",         KEY_HELP),
274  FUSE_OPT_END
275};
276
277static struct fuse_opt workaround_opts[] = {
278  SSHFS_OPT("none",       rename_workaround, 0),
279  SSHFS_OPT("none",       nodelay_workaround, 0),
280  SSHFS_OPT("none",       nodelaysrv_workaround, 0),
281  SSHFS_OPT("none",       truncate_workaround, 0),
282  SSHFS_OPT("none",       buflimit_workaround, 0),
283  SSHFS_OPT("all",        rename_workaround, 1),
284  SSHFS_OPT("all",        nodelay_workaround, 1),
285  SSHFS_OPT("all",        nodelaysrv_workaround, 1),
286  SSHFS_OPT("all",        truncate_workaround, 1),
287  SSHFS_OPT("all",        buflimit_workaround, 1),
288  SSHFS_OPT("rename",     rename_workaround, 1),
289  SSHFS_OPT("norename",   rename_workaround, 0),
290  SSHFS_OPT("nodelay",    nodelay_workaround, 1),
291  SSHFS_OPT("nonodelay",  nodelay_workaround, 0),
292  SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1),
293  SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0),
294  SSHFS_OPT("truncate",   truncate_workaround, 1),
295  SSHFS_OPT("notruncate", truncate_workaround, 0),
296  SSHFS_OPT("buflimit",   buflimit_workaround, 1),
297  SSHFS_OPT("nobuflimit", buflimit_workaround, 0),
298  FUSE_OPT_END
299};
300
301#define DEBUG(format, args...)            \
302  do { if (sshfs.debug) fprintf(stderr, format, args); } while(0)
303
304static const char *type_name(uint8_t type)
305{
306  switch(type) {
307  case SSH_FXP_INIT:           return "INIT";
308  case SSH_FXP_VERSION:        return "VERSION";
309  case SSH_FXP_OPEN:           return "OPEN";
310  case SSH_FXP_CLOSE:          return "CLOSE";
311  case SSH_FXP_READ:           return "READ";
312  case SSH_FXP_WRITE:          return "WRITE";
313  case SSH_FXP_LSTAT:          return "LSTAT";
314  case SSH_FXP_FSTAT:          return "FSTAT";
315  case SSH_FXP_SETSTAT:        return "SETSTAT";
316  case SSH_FXP_FSETSTAT:       return "FSETSTAT";
317  case SSH_FXP_OPENDIR:        return "OPENDIR";
318  case SSH_FXP_READDIR:        return "READDIR";
319  case SSH_FXP_REMOVE:         return "REMOVE";
320  case SSH_FXP_MKDIR:          return "MKDIR";
321  case SSH_FXP_RMDIR:          return "RMDIR";
322  case SSH_FXP_REALPATH:       return "REALPATH";
323  case SSH_FXP_STAT:           return "STAT";
324  case SSH_FXP_RENAME:         return "RENAME";
325  case SSH_FXP_READLINK:       return "READLINK";
326  case SSH_FXP_SYMLINK:        return "SYMLINK";
327  case SSH_FXP_STATUS:         return "STATUS";
328  case SSH_FXP_HANDLE:         return "HANDLE";
329  case SSH_FXP_DATA:           return "DATA";
330  case SSH_FXP_NAME:           return "NAME";
331  case SSH_FXP_ATTRS:          return "ATTRS";
332  case SSH_FXP_EXTENDED:       return "EXTENDED";
333  case SSH_FXP_EXTENDED_REPLY: return "EXTENDED_REPLY";
334  default:                     return "???";
335  }
336}
337
338#define container_of(ptr, type, member) ({        \
339      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
340      (type *)( (char *)__mptr - offsetof(type,member) );})
341
342#define list_entry(ptr, type, member)   \
343  container_of(ptr, type, member)
344
345static void list_init(struct list_head *head)
346{
347  head->next = head;
348  head->prev = head;
349}
350
351static void list_add(struct list_head *new, struct list_head *head)
352{
353  struct list_head *prev = head;
354  struct list_head *next = head->next;
355  next->prev = new;
356  new->next = next;
357  new->prev = prev;
358  prev->next = new;
359}
360
361static void list_del(struct list_head *entry)
362{
363  struct list_head *prev = entry->prev;
364  struct list_head *next = entry->next;
365  next->prev = prev;
366  prev->next = next;
367
368}
369
370static int list_empty(const struct list_head *head)
371{
372  return head->next == head;
373}
374
375static inline void buf_init(struct buffer *buf, size_t size)
376{
377  if (size) {
378    buf->p = (uint8_t *) malloc(size);
379    if (!buf->p) {
380      fprintf(stderr, "sshfs: memory allocation failed\n");
381      abort();
382    }
383  } else
384    buf->p = NULL;
385  buf->len = 0;
386  buf->size = size;
387}
388
389static inline void buf_free(struct buffer *buf)
390{
391  free(buf->p);
392}
393
394static inline void buf_finish(struct buffer *buf)
395{
396  buf->len = buf->size;
397}
398
399static inline void buf_clear(struct buffer *buf)
400{
401  buf_free(buf);
402  buf_init(buf, 0);
403}
404
405static void buf_resize(struct buffer *buf, size_t len)
406{
407  buf->size = (buf->len + len + 63) & ~31;
408  buf->p = (uint8_t *) realloc(buf->p, buf->size);
409  if (!buf->p) {
410    fprintf(stderr, "sshfs: memory allocation failed\n");
411    abort();
412  }
413}
414
415static inline void buf_check_add(struct buffer *buf, size_t len)
416{
417  if (buf->len + len > buf->size)
418    buf_resize(buf, len);
419}
420
421#define _buf_add_mem(b, d, l)     \
422  buf_check_add(b, l);      \
423  memcpy(b->p + b->len, d, l);    \
424  b->len += l;
425
426
427static inline void buf_add_mem(struct buffer *buf, const void *data,
428                               size_t len)
429{
430  _buf_add_mem(buf, data, len);
431}
432
433static inline void buf_add_buf(struct buffer *buf, const struct buffer *bufa)
434{
435  _buf_add_mem(buf, bufa->p, bufa->len);
436}
437
438static inline void buf_add_uint8(struct buffer *buf, uint8_t val)
439{
440  _buf_add_mem(buf, &val, 1);
441}
442
443static inline void buf_add_uint32(struct buffer *buf, uint32_t val)
444{
445  uint32_t nval = htonl(val);
446  _buf_add_mem(buf, &nval, 4);
447}
448
449static inline void buf_add_uint64(struct buffer *buf, uint64_t val)
450{
451  buf_add_uint32(buf, val >> 32);
452  buf_add_uint32(buf, val & 0xffffffff);
453}
454
455static inline void buf_add_data(struct buffer *buf, const struct buffer *data)
456{
457  buf_add_uint32(buf, data->len);
458  buf_add_mem(buf, data->p, data->len);
459}
460
461static inline void buf_add_string(struct buffer *buf, const char *str)
462{
463  struct buffer data;
464  data.p = (uint8_t *) str;
465  data.len = strlen(str);
466  buf_add_data(buf, &data);
467}
468
469static inline void buf_add_path(struct buffer *buf, const char *path)
470{
471  char *realpath;
472
473  realpath = g_strdup_printf("%s%s", sshfs.base_path,
474           path[1] ? path+1 : ".");
475  buf_add_string(buf, realpath);
476  g_free(realpath);
477}
478
479static int buf_check_get(struct buffer *buf, size_t len)
480{
481  if (buf->len + len > buf->size) {
482    fprintf(stderr, "buffer too short\n");
483    return -1;
484  } else
485    return 0;
486}
487
488static inline int buf_get_mem(struct buffer *buf, void *data, size_t len)
489{
490  if (buf_check_get(buf, len) == -1)
491    return -1;
492  memcpy(data, buf->p + buf->len, len);
493  buf->len += len;
494  return 0;
495}
496
497static inline int buf_get_uint8(struct buffer *buf, uint8_t *val)
498{
499  return buf_get_mem(buf, val, 1);
500}
501
502static inline int buf_get_uint32(struct buffer *buf, uint32_t *val)
503{
504  uint32_t nval;
505  if (buf_get_mem(buf, &nval, 4) == -1)
506    return -1;
507  *val = ntohl(nval);
508  return 0;
509}
510
511static inline int buf_get_uint64(struct buffer *buf, uint64_t *val)
512{
513  uint32_t val1;
514  uint32_t val2;
515  if (buf_get_uint32(buf, &val1) == -1 ||
516      buf_get_uint32(buf, &val2) == -1) {
517    return -1;
518  }
519  *val = ((uint64_t) val1 << 32) + val2;
520  return 0;
521}
522
523static inline int buf_get_data(struct buffer *buf, struct buffer *data)
524{
525  uint32_t len;
526  if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len)
527    return -1;
528  buf_init(data, len + 1);
529  data->size = len;
530  if (buf_get_mem(buf, data->p, data->size) == -1) {
531    buf_free(data);
532    return -1;
533  }
534  return 0;
535}
536
537static inline int buf_get_string(struct buffer *buf, char **str)
538{
539  struct buffer data;
540  if (buf_get_data(buf, &data) == -1)
541    return -1;
542  data.p[data.size] = '\0';
543  *str = (char *) data.p;
544  return 0;
545}
546
547static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
548{
549  uint32_t flags;
550  uint64_t size = 0;
551  uint32_t uid = 0;
552  uint32_t gid = 0;
553  uint32_t atime = 0;
554  uint32_t mtime = 0;
555  uint32_t mode = S_IFREG | 0777;
556
557  if (buf_get_uint32(buf, &flags) == -1)
558    return -1;
559  if (flagsp)
560    *flagsp = flags;
561  if ((flags & SSH_FILEXFER_ATTR_SIZE) &&
562      buf_get_uint64(buf, &size) == -1)
563    return -1;
564  if ((flags & SSH_FILEXFER_ATTR_UIDGID) &&
565      (buf_get_uint32(buf, &uid) == -1 ||
566       buf_get_uint32(buf, &gid) == -1))
567    return -1;
568  if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
569      buf_get_uint32(buf, &mode) == -1)
570    return -1;
571  if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
572    if (buf_get_uint32(buf, &atime) == -1 ||
573        buf_get_uint32(buf, &mtime) == -1)
574      return -1;
575  }
576  if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) {
577    uint32_t extcount;
578    unsigned i;
579    if (buf_get_uint32(buf, &extcount) == -1)
580      return -1;
581    for (i = 0; i < extcount; i++) {
582      struct buffer tmp;
583      if (buf_get_data(buf, &tmp) == -1)
584        return -1;
585      buf_free(&tmp);
586      if (buf_get_data(buf, &tmp) == -1)
587        return -1;
588      buf_free(&tmp);
589    }
590  }
591
592  if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
593    uid = sshfs.local_uid;
594
595  memset(stbuf, 0, sizeof(struct stat));
596  stbuf->st_mode = mode;
597  stbuf->st_nlink = 1;
598  stbuf->st_size = size;
599  if (sshfs.blksize) {
600    stbuf->st_blksize = sshfs.blksize;
601    stbuf->st_blocks = ((size + sshfs.blksize - 1) &
602            ~(sshfs.blksize - 1)) >> 9;
603  }
604  stbuf->st_uid = uid;
605  stbuf->st_gid = gid;
606  stbuf->st_atime = atime;
607  stbuf->st_ctime = stbuf->st_mtime = mtime;
608  return 0;
609}
610
611static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h,
612                           fuse_cache_dirfil_t filler)
613{
614  uint32_t count;
615  unsigned i;
616
617  if (buf_get_uint32(buf, &count) == -1)
618    return -1;
619
620  for (i = 0; i < count; i++) {
621    int err = -1;
622    char *name;
623    char *longname;
624    struct stat stbuf;
625    if (buf_get_string(buf, &name) == -1)
626      return -1;
627    if (buf_get_string(buf, &longname) != -1) {
628      free(longname);
629      if (buf_get_attrs(buf, &stbuf, NULL) != -1) {
630        if (sshfs.follow_symlinks &&
631            S_ISLNK(stbuf.st_mode)) {
632          stbuf.st_mode = 0;
633        }
634        filler(h, name, &stbuf);
635        err = 0;
636      }
637    }
638    free(name);
639    if (err)
640      return err;
641  }
642  return 0;
643}
644
645static void ssh_add_arg(const char *arg)
646{
647  if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1)
648    _exit(1);
649}
650
651#ifdef SSH_NODELAY_WORKAROUND
652static int do_ssh_nodelay_workaround(void)
653{
654  char *oldpreload = getenv("LD_PRELOAD");
655  char *newpreload;
656  char sopath[PATH_MAX];
657  int res;
658
659  snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO);
660  res = access(sopath, R_OK);
661  if (res == -1) {
662    char *s;
663    if (!realpath(sshfs.progname, sopath))
664      return -1;
665
666    s = strrchr(sopath, '/');
667    if (!s)
668      s = sopath;
669    else
670      s++;
671
672    if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath))
673      return -1;
674
675    strcpy(s, SSHNODELAY_SO);
676    res = access(sopath, R_OK);
677    if (res == -1) {
678      fprintf(stderr, "sshfs: cannot find %s\n",
679        SSHNODELAY_SO);
680      return -1;
681    }
682  }
683
684  newpreload = g_strdup_printf("%s%s%s",
685             oldpreload ? oldpreload : "",
686             oldpreload ? " " : "",
687             sopath);
688
689  if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) {
690    fprintf(stderr, "warning: failed set LD_PRELOAD "
691      "for ssh nodelay workaround\n");
692  }
693  g_free(newpreload);
694  return 0;
695}
696#endif
697
698static int start_ssh(void)
699{
700  int sockpair[2];
701  int pid;
702
703  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) {
704    perror("failed to create socket pair");
705    return -1;
706  }
707  sshfs.fd = sockpair[0];
708
709  pid = fork();
710  if (pid == -1) {
711    perror("failed to fork");
712    return -1;
713  } else if (pid == 0) {
714    int devnull;
715
716#ifdef SSH_NODELAY_WORKAROUND
717    if (sshfs.nodelay_workaround &&
718        do_ssh_nodelay_workaround() == -1) {
719      fprintf(stderr,
720        "warning: ssh nodelay workaround disabled\n");
721    }
722#endif
723
724    if (sshfs.nodelaysrv_workaround) {
725      /*
726       * Hack to work around missing TCP_NODELAY
727       * setting in sshd
728       */
729      sshfs.ssh_args.argv[1] = "-X";
730    }
731
732    devnull = open("/dev/null", O_WRONLY);
733
734    if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) {
735      perror("failed to redirect input/output");
736      _exit(1);
737    }
738    if (!sshfs.debug && devnull != -1)
739      dup2(devnull, 2);
740
741    close(devnull);
742    close(sockpair[0]);
743    close(sockpair[1]);
744
745    switch (fork()) {
746    case -1:
747      perror("failed to fork");
748      _exit(1);
749    case 0:
750      break;
751    default:
752      _exit(0);
753    }
754    chdir("/");
755
756    execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv);
757    perror("execvp");
758    _exit(1);
759  }
760  waitpid(pid, NULL, 0);
761  close(sockpair[1]);
762  return 0;
763}
764
765static int connect_to(char *host, char *port)
766{
767  int err;
768  int sock;
769  int opt;
770  struct addrinfo *ai;
771  struct addrinfo hint;
772
773  memset(&hint, 0, sizeof(hint));
774  hint.ai_family = PF_INET;
775  hint.ai_socktype = SOCK_STREAM;
776  err = getaddrinfo(host, port, &hint, &ai);
777  if (err) {
778    fprintf(stderr, "failed to resolve %s:%s: %s\n", host, port,
779      gai_strerror(err));
780    return -1;
781  }
782  sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
783  if (sock == -1) {
784    perror("failed to create socket");
785    return -1;
786  }
787  err = connect(sock, ai->ai_addr, ai->ai_addrlen);
788  if (err == -1) {
789    perror("failed to connect");
790    return -1;
791  }
792  opt = 1;
793  err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
794  if (err == -1)
795    perror("warning: failed to set TCP_NODELAY");
796
797  freeaddrinfo(ai);
798
799  sshfs.fd = sock;
800  return 0;
801}
802
803static int do_write(struct iovec *iov, size_t count)
804{
805  int res;
806  while (count) {
807    res = writev(sshfs.fd, iov, count);
808    if (res == -1) {
809      perror("write");
810      return -1;
811    } else if (res == 0) {
812      fprintf(stderr, "zero write\n");
813      return -1;
814    }
815    do {
816      if ((unsigned) res < iov->iov_len) {
817        iov->iov_len -= res;
818        iov->iov_base += res;
819        break;
820      } else {
821        res -= iov->iov_len;
822        count --;
823        iov ++;
824      }
825    } while(count);
826  }
827  return 0;
828}
829
830static uint32_t sftp_get_id(void)
831{
832  static uint32_t idctr;
833  return idctr++;
834}
835
836static void buf_to_iov(const struct buffer *buf, struct iovec *iov)
837{
838  iov->iov_base = buf->p;
839  iov->iov_len = buf->len;
840}
841
842static size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
843{
844  unsigned long seg;
845  size_t ret = 0;
846
847  for (seg = 0; seg < nr_segs; seg++)
848    ret += iov[seg].iov_len;
849  return ret;
850}
851
852#define SFTP_MAX_IOV 3
853
854static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[],
855                         size_t count)
856{
857  int res;
858  struct buffer buf;
859  struct iovec iovout[SFTP_MAX_IOV];
860  unsigned i;
861  unsigned nout = 0;
862
863  assert(count <= SFTP_MAX_IOV - 1);
864  buf_init(&buf, 9);
865  buf_add_uint32(&buf, iov_length(iov, count) + 5);
866  buf_add_uint8(&buf, type);
867  buf_add_uint32(&buf, id);
868  buf_to_iov(&buf, &iovout[nout++]);
869  for (i = 0; i < count; i++)
870    iovout[nout++] = iov[i];
871  pthread_mutex_lock(&sshfs.lock_write);
872  res = do_write(iovout, nout);
873  pthread_mutex_unlock(&sshfs.lock_write);
874  buf_free(&buf);
875  return res;
876}
877
878static int do_read(struct buffer *buf)
879{
880  int res;
881  uint8_t *p = buf->p;
882  size_t size = buf->size;
883  while (size) {
884    res = read(sshfs.fd, p, size);
885    if (res == -1) {
886      perror("read");
887      return -1;
888    } else if (res == 0) {
889      fprintf(stderr, "remote host has disconnected\n");
890      return -1;
891    }
892    size -= res;
893    p += res;
894  }
895  return 0;
896}
897
898static int sftp_read(uint8_t *type, struct buffer *buf)
899{
900  int res;
901  struct buffer buf2;
902  uint32_t len;
903  buf_init(&buf2, 5);
904  res = do_read(&buf2);
905  if (res != -1) {
906    if (buf_get_uint32(&buf2, &len) == -1)
907      return -1;
908    if (len > MAX_REPLY_LEN) {
909      fprintf(stderr, "reply len too large: %u\n", len);
910      return -1;
911    }
912    if (buf_get_uint8(&buf2, type) == -1)
913      return -1;
914    buf_init(buf, len - 1);
915    res = do_read(buf);
916  }
917  buf_free(&buf2);
918  return res;
919}
920
921static void request_free(struct request *req)
922{
923  buf_free(&req->reply);
924  sem_destroy(&req->ready);
925  g_free(req);
926}
927
928static void chunk_free(struct read_chunk *chunk)
929{
930  buf_free(&chunk->data);
931  sem_destroy(&chunk->ready);
932  g_free(chunk);
933}
934
935static void chunk_put(struct read_chunk *chunk)
936{
937  if (chunk) {
938    chunk->refs--;
939    if (!chunk->refs)
940      chunk_free(chunk);
941  }
942}
943
944static void chunk_put_locked(struct read_chunk *chunk)
945{
946  pthread_mutex_lock(&sshfs.lock);
947  chunk_put(chunk);
948  pthread_mutex_unlock(&sshfs.lock);
949}
950
951static int clean_req(void *key_, struct request *req)
952{
953  (void) key_;
954
955  req->error = -EIO;
956  if (req->want_reply)
957    sem_post(&req->ready);
958  else {
959    if (req->end_func)
960      req->end_func(req);
961    request_free(req);
962  }
963  return TRUE;
964}
965
966static int process_one_request(void)
967{
968  int res;
969  struct buffer buf;
970  uint8_t type;
971  struct request *req;
972  uint32_t id;
973
974  buf_init(&buf, 0);
975  res = sftp_read(&type, &buf);
976  if (res == -1)
977    return -1;
978  if (buf_get_uint32(&buf, &id) == -1)
979    return -1;
980
981  pthread_mutex_lock(&sshfs.lock);
982  req = (struct request *)
983    g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id));
984  if (req == NULL)
985    fprintf(stderr, "request %i not found\n", id);
986  else {
987    int was_over;
988
989    was_over = sshfs.outstanding_len > sshfs.max_outstanding_len;
990    sshfs.outstanding_len -= req->len;
991    if (was_over &&
992        sshfs.outstanding_len <= sshfs.max_outstanding_len) {
993      pthread_cond_broadcast(&sshfs.outstanding_cond);
994    }
995    g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
996  }
997  pthread_mutex_unlock(&sshfs.lock);
998  if (req != NULL) {
999    if (sshfs.debug) {
1000      struct timeval now;
1001      unsigned int difftime;
1002      gettimeofday(&now, NULL);
1003      difftime = (now.tv_sec - req->start.tv_sec) * 1000;
1004      difftime += (now.tv_usec - req->start.tv_usec) / 1000;
1005      DEBUG("  [%05i] %14s %8ubytes (%ims)\n", id,
1006            type_name(type),
1007            (unsigned) buf.size + 5, difftime);
1008    }
1009    req->reply = buf;
1010    req->reply_type = type;
1011    req->replied = 1;
1012    if (req->want_reply)
1013      sem_post(&req->ready);
1014    else {
1015      if (req->end_func) {
1016        pthread_mutex_lock(&sshfs.lock);
1017        req->end_func(req);
1018        pthread_mutex_unlock(&sshfs.lock);
1019      }
1020      request_free(req);
1021    }
1022  } else
1023    buf_free(&buf);
1024
1025  return 0;
1026}
1027
1028static void *process_requests(void *data_)
1029{
1030  (void) data_;
1031
1032  while (1) {
1033    if (process_one_request() == -1)
1034      break;
1035  }
1036
1037  if (!sshfs.reconnect) {
1038    /* harakiri */
1039    kill(getpid(), SIGTERM);
1040  } else {
1041    pthread_mutex_lock(&sshfs.lock);
1042    sshfs.processing_thread_started = 0;
1043    close(sshfs.fd);
1044    sshfs.fd = -1;
1045    g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req,
1046              NULL);
1047    sshfs.connver ++;
1048    pthread_mutex_unlock(&sshfs.lock);
1049  }
1050  return NULL;
1051}
1052
1053static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version)
1054{
1055  uint32_t len;
1056  uint8_t type;
1057
1058  if (buf_get_uint32(buf, &len) == -1)
1059    return -1;
1060
1061  if (len < 5 || len > MAX_REPLY_LEN)
1062    return 1;
1063
1064  if (buf_get_uint8(buf, &type) == -1)
1065    return -1;
1066
1067  if (type != SSH_FXP_VERSION)
1068    return 1;
1069
1070  if (buf_get_uint32(buf, version) == -1)
1071    return -1;
1072
1073  if (len > 5) {
1074    struct buffer buf2;
1075    buf_init(&buf2, len - 5);
1076    return do_read(&buf2);
1077  }
1078  return 0;
1079}
1080
1081static int sftp_find_init_reply(uint32_t *version)
1082{
1083  int res;
1084  struct buffer buf;
1085
1086  buf_init(&buf, 9);
1087  res = do_read(&buf);
1088  while (res != -1) {
1089    struct buffer buf2;
1090
1091    res = sftp_init_reply_ok(&buf, version);
1092    if (res <= 0)
1093      break;
1094
1095    /* Iterate over any rubbish until the version reply is found */
1096    DEBUG("%c", *buf.p);
1097    memmove(buf.p, buf.p + 1, buf.size - 1);
1098    buf.len = 0;
1099    buf2.p = buf.p + buf.size - 1;
1100    buf2.size = 1;
1101    res = do_read(&buf2);
1102  }
1103  buf_free(&buf);
1104  return res;
1105}
1106
1107static int sftp_init()
1108{
1109  int res = -1;
1110  uint32_t version = 0;
1111  struct buffer buf;
1112  buf_init(&buf, 0);
1113  if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1)
1114    goto out;
1115  if (sftp_find_init_reply(&version) == -1)
1116    goto out;
1117
1118  sshfs.server_version = version;
1119  DEBUG("Server version: %i\n", sshfs.server_version);
1120  if (version > PROTO_VERSION) {
1121    fprintf(stderr,
1122      "Warning: server uses version: %i, we support: %i\n",
1123      version, PROTO_VERSION);
1124  }
1125  res = 0;
1126
1127out:
1128  buf_free(&buf);
1129  return res;
1130}
1131
1132static int sftp_error_to_errno(uint32_t error)
1133{
1134  switch (error) {
1135  case SSH_FX_OK:                return 0;
1136  case SSH_FX_NO_SUCH_FILE:      return ENOENT;
1137  case SSH_FX_PERMISSION_DENIED: return EACCES;
1138  case SSH_FX_FAILURE:           return EPERM;
1139  case SSH_FX_BAD_MESSAGE:       return EBADMSG;
1140  case SSH_FX_NO_CONNECTION:     return ENOTCONN;
1141  case SSH_FX_CONNECTION_LOST:   return ECONNABORTED;
1142  case SSH_FX_OP_UNSUPPORTED:    return EOPNOTSUPP;
1143  default:                       return EIO;
1144  }
1145}
1146
1147static void sftp_detect_uid()
1148{
1149  int flags;
1150  uint32_t id = sftp_get_id();
1151  uint32_t replid;
1152  uint8_t type;
1153  struct buffer buf;
1154  struct stat stbuf;
1155  struct iovec iov[1];
1156
1157  buf_init(&buf, 5);
1158  buf_add_string(&buf, ".");
1159  buf_to_iov(&buf, &iov[0]);
1160  if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1161    goto out;
1162  buf_clear(&buf);
1163  if (sftp_read(&type, &buf) == -1)
1164    goto out;
1165  if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1166    fprintf(stderr, "protocol error\n");
1167    goto out;
1168  }
1169  if (buf_get_uint32(&buf, &replid) == -1)
1170    goto out;
1171  if (replid != id) {
1172    fprintf(stderr, "bad reply ID\n");
1173    goto out;
1174  }
1175  if (type == SSH_FXP_STATUS) {
1176    uint32_t serr;
1177    if (buf_get_uint32(&buf, &serr) == -1)
1178      goto out;
1179
1180    fprintf(stderr, "failed to stat home directory (%i)\n", serr);
1181    goto out;
1182  }
1183  if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
1184    goto out;
1185
1186  if (!(flags & SSH_FILEXFER_ATTR_UIDGID))
1187    goto out;
1188
1189  sshfs.remote_uid = stbuf.st_uid;
1190  sshfs.local_uid = getuid();
1191  sshfs.remote_uid_detected = 1;
1192  DEBUG("remote_uid = %i\n", sshfs.remote_uid);
1193
1194out:
1195  if (!sshfs.remote_uid_detected)
1196    fprintf(stderr, "failed to detect remote user ID\n");
1197
1198  buf_free(&buf);
1199}
1200
1201static int sftp_check_root(const char *base_path)
1202{
1203  int flags;
1204  uint32_t id = sftp_get_id();
1205  uint32_t replid;
1206  uint8_t type;
1207  struct buffer buf;
1208  struct stat stbuf;
1209  struct iovec iov[1];
1210  int err = -1;
1211  const char *remote_dir = base_path[0] ? base_path : ".";
1212
1213  buf_init(&buf, 0);
1214  buf_add_string(&buf, remote_dir);
1215  buf_to_iov(&buf, &iov[0]);
1216  if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1)
1217    goto out;
1218  buf_clear(&buf);
1219  if (sftp_read(&type, &buf) == -1)
1220    goto out;
1221  if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) {
1222    fprintf(stderr, "protocol error\n");
1223    goto out;
1224  }
1225  if (buf_get_uint32(&buf, &replid) == -1)
1226    goto out;
1227  if (replid != id) {
1228    fprintf(stderr, "bad reply ID\n");
1229    goto out;
1230  }
1231  if (type == SSH_FXP_STATUS) {
1232    uint32_t serr;
1233    if (buf_get_uint32(&buf, &serr) == -1)
1234      goto out;
1235
1236    fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir,
1237      strerror(sftp_error_to_errno(serr)));
1238
1239    goto out;
1240  }
1241  if (buf_get_attrs(&buf, &stbuf, &flags) == -1)
1242    goto out;
1243
1244  if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS))
1245    goto out;
1246
1247  if (!S_ISDIR(stbuf.st_mode)) {
1248    fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host,
1249      remote_dir);
1250    goto out;
1251  }
1252
1253  err = 0;
1254
1255out:
1256  buf_free(&buf);
1257  return err;
1258}
1259
1260static int connect_remote(void)
1261{
1262  int err;
1263
1264  if (sshfs.directport)
1265    err = connect_to(sshfs.host, sshfs.directport);
1266  else
1267    err = start_ssh();
1268  if (!err)
1269    err = sftp_init();
1270
1271  return err;
1272}
1273
1274static int start_processing_thread(void)
1275{
1276  int err;
1277  pthread_t thread_id;
1278  sigset_t oldset;
1279  sigset_t newset;
1280
1281  if (sshfs.processing_thread_started)
1282    return 0;
1283
1284  if (sshfs.fd == -1) {
1285    err = connect_remote();
1286    if (err)
1287      return -EIO;
1288  }
1289
1290  sigemptyset(&newset);
1291  sigaddset(&newset, SIGTERM);
1292  sigaddset(&newset, SIGINT);
1293  sigaddset(&newset, SIGHUP);
1294  sigaddset(&newset, SIGQUIT);
1295  pthread_sigmask(SIG_BLOCK, &newset, &oldset);
1296  err = pthread_create(&thread_id, NULL, process_requests, NULL);
1297  if (err) {
1298    fprintf(stderr, "failed to create thread: %s\n", strerror(err));
1299    return -EIO;
1300  }
1301  pthread_detach(thread_id);
1302  pthread_sigmask(SIG_SETMASK, &oldset, NULL);
1303  sshfs.processing_thread_started = 1;
1304  return 0;
1305}
1306
1307#ifdef SSHFS_USE_INIT
1308#if FUSE_VERSION >= 26
1309static void *sshfs_init(struct fuse_conn_info *conn)
1310#else
1311  static void *sshfs_init(void)
1312#endif
1313{
1314#if FUSE_VERSION >= 26
1315  /* Readahead should be done by kernel or sshfs but not both */
1316  if (conn->async_read)
1317    sshfs.sync_read = 1;
1318#endif
1319
1320  if (sshfs.detect_uid)
1321    sftp_detect_uid();
1322
1323  start_processing_thread();
1324  return NULL;
1325}
1326#endif
1327
1328static int sftp_request_wait(struct request *req, uint8_t type,
1329                             uint8_t expect_type, struct buffer *outbuf)
1330{
1331  int err;
1332
1333  if (req->error) {
1334    err = req->error;
1335    goto out;
1336  }
1337  while (sem_wait(&req->ready));
1338  if (req->error) {
1339    err = req->error;
1340    goto out;
1341  }
1342  err = -EIO;
1343  if (req->reply_type != expect_type &&
1344      req->reply_type != SSH_FXP_STATUS) {
1345    fprintf(stderr, "protocol error\n");
1346    goto out;
1347  }
1348  if (req->reply_type == SSH_FXP_STATUS) {
1349    uint32_t serr;
1350    if (buf_get_uint32(&req->reply, &serr) == -1)
1351      goto out;
1352
1353    switch (serr) {
1354    case SSH_FX_OK:
1355      if (expect_type == SSH_FXP_STATUS)
1356        err = 0;
1357      else
1358        err = -EIO;
1359      break;
1360
1361    case SSH_FX_EOF:
1362      if (type == SSH_FXP_READ || type == SSH_FXP_READDIR)
1363        err = MY_EOF;
1364      else
1365        err = -EIO;
1366      break;
1367
1368    default:
1369      err = -sftp_error_to_errno(serr);
1370    }
1371  } else {
1372    buf_init(outbuf, req->reply.size - req->reply.len);
1373    buf_get_mem(&req->reply, outbuf->p, outbuf->size);
1374    err = 0;
1375  }
1376
1377out:
1378  if (req->end_func) {
1379    pthread_mutex_lock(&sshfs.lock);
1380    req->end_func(req);
1381    pthread_mutex_unlock(&sshfs.lock);
1382  }
1383  request_free(req);
1384  return err;
1385}
1386
1387static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
1388                             request_func begin_func, request_func end_func,
1389                             int want_reply, void *data,
1390                             struct request **reqp)
1391{
1392  int err;
1393  uint32_t id;
1394  struct request *req = g_new0(struct request, 1);
1395
1396  req->want_reply = want_reply;
1397  req->end_func = end_func;
1398  req->data = data;
1399  sem_init(&req->ready, 0, 0);
1400  buf_init(&req->reply, 0);
1401  pthread_mutex_lock(&sshfs.lock);
1402  if (begin_func)
1403    begin_func(req);
1404  id = sftp_get_id();
1405  err = start_processing_thread();
1406  if (err) {
1407    pthread_mutex_unlock(&sshfs.lock);
1408    goto out;
1409  }
1410  req->len = iov_length(iov, count) + 9;
1411  sshfs.outstanding_len += req->len;
1412  while (sshfs.outstanding_len > sshfs.max_outstanding_len)
1413    pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock);
1414
1415  g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req);
1416  if (sshfs.debug)
1417    gettimeofday(&req->start, NULL);
1418  DEBUG("[%05i] %s\n", id, type_name(type));
1419  pthread_mutex_unlock(&sshfs.lock);
1420
1421  err = -EIO;
1422  if (sftp_send_iov(type, id, iov, count) == -1) {
1423    pthread_mutex_lock(&sshfs.lock);
1424    g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id));
1425    pthread_mutex_unlock(&sshfs.lock);
1426    goto out;
1427  }
1428  if (want_reply)
1429    *reqp = req;
1430  return 0;
1431
1432out:
1433  req->error = err;
1434  if (!want_reply)
1435    sftp_request_wait(req, type, 0, NULL);
1436  else
1437    *reqp = req;
1438
1439  return err;
1440}
1441
1442
1443static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count,
1444                            uint8_t expect_type, struct buffer *outbuf)
1445{
1446  struct request *req;
1447
1448  sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL,
1449        &req);
1450  if (expect_type == 0)
1451    return 0;
1452
1453  return sftp_request_wait(req, type, expect_type, outbuf);
1454}
1455
1456static int sftp_request(uint8_t type, const struct buffer *buf,
1457                        uint8_t expect_type, struct buffer *outbuf)
1458{
1459  struct iovec iov;
1460
1461  buf_to_iov(buf, &iov);
1462  return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
1463}
1464
1465static int sshfs_getattr(const char *path, struct stat *stbuf)
1466{
1467  int err;
1468  struct buffer buf;
1469  struct buffer outbuf;
1470  buf_init(&buf, 0);
1471  buf_add_path(&buf, path);
1472  err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
1473         &buf, SSH_FXP_ATTRS, &outbuf);
1474  if (!err) {
1475    if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
1476      err = -EIO;
1477    buf_free(&outbuf);
1478  }
1479  buf_free(&buf);
1480  return err;
1481}
1482
1483static int count_components(const char *p)
1484{
1485  int ctr;
1486
1487  for (; *p == '/'; p++);
1488  for (ctr = 0; *p; ctr++) {
1489    for (; *p && *p != '/'; p++);
1490    for (; *p == '/'; p++);
1491  }
1492  return ctr;
1493}
1494
1495static void strip_common(const char **sp, const char **tp)
1496{
1497  const char *s = *sp;
1498  const char *t = *tp;
1499  do {
1500    for (; *s == '/'; s++);
1501    for (; *t == '/'; t++);
1502    *tp = t;
1503    *sp = s;
1504    for (; *s == *t && *s && *s != '/'; s++, t++);
1505  } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
1506}
1507
1508static void transform_symlink(const char *path, char **linkp)
1509{
1510  const char *l = *linkp;
1511  const char *b = sshfs.base_path;
1512  char *newlink;
1513  char *s;
1514  int dotdots;
1515  int i;
1516
1517  if (l[0] != '/' || b[0] != '/')
1518    return;
1519
1520  strip_common(&l, &b);
1521  if (*b)
1522    return;
1523
1524  strip_common(&l, &path);
1525  dotdots = count_components(path);
1526  if (!dotdots)
1527    return;
1528  dotdots--;
1529
1530  newlink = malloc(dotdots * 3 + strlen(l) + 2);
1531  if (!newlink) {
1532    fprintf(stderr, "sshfs: memory allocation failed\n");
1533    abort();
1534  }
1535  for (s = newlink, i = 0; i < dotdots; i++, s += 3)
1536    strcpy(s, "../");
1537
1538  if (l[0])
1539    strcpy(s, l);
1540  else if (!dotdots)
1541    strcpy(s, ".");
1542  else
1543    s[0] = '\0';
1544
1545  free(*linkp);
1546  *linkp = newlink;
1547}
1548
1549static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
1550{
1551  int err;
1552  struct buffer buf;
1553  struct buffer name;
1554
1555  assert(size > 0);
1556
1557  if (sshfs.server_version < 3)
1558    return -EPERM;
1559
1560  buf_init(&buf, 0);
1561  buf_add_path(&buf, path);
1562  err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
1563  if (!err) {
1564    uint32_t count;
1565    char *link;
1566    err = -EIO;
1567    if(buf_get_uint32(&name, &count) != -1 && count == 1 &&
1568       buf_get_string(&name, &link) != -1) {
1569      if (sshfs.transform_symlinks)
1570        transform_symlink(path, &link);
1571      strncpy(linkbuf, link, size - 1);
1572      linkbuf[size - 1] = '\0';
1573      free(link);
1574      err = 0;
1575    }
1576    buf_free(&name);
1577  }
1578  buf_free(&buf);
1579  return err;
1580}
1581
1582static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
1583                        fuse_cache_dirfil_t filler)
1584{
1585  int err;
1586  struct buffer buf;
1587  struct buffer handle;
1588  buf_init(&buf, 0);
1589  buf_add_path(&buf, path);
1590  err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle);
1591  if (!err) {
1592    int err2;
1593    buf_finish(&handle);
1594    do {
1595      struct buffer name;
1596      err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
1597      if (!err) {
1598        if (buf_get_entries(&name, h, filler) == -1)
1599          err = -EIO;
1600        buf_free(&name);
1601      }
1602    } while (!err);
1603    if (err == MY_EOF)
1604      err = 0;
1605
1606    err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
1607    if (!err)
1608      err = err2;
1609    buf_free(&handle);
1610  }
1611  buf_free(&buf);
1612  return err;
1613}
1614
1615static int sshfs_mkdir(const char *path, mode_t mode)
1616{
1617  int err;
1618  struct buffer buf;
1619  buf_init(&buf, 0);
1620  buf_add_path(&buf, path);
1621  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
1622  buf_add_uint32(&buf, mode);
1623  err = sftp_request(SSH_FXP_MKDIR, &buf, SSH_FXP_STATUS, NULL);
1624  buf_free(&buf);
1625  return err;
1626}
1627
1628static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
1629{
1630  int err;
1631  struct buffer buf;
1632  struct buffer handle;
1633  (void) rdev;
1634
1635  if ((mode & S_IFMT) != S_IFREG)
1636    return -EPERM;
1637
1638  buf_init(&buf, 0);
1639  buf_add_path(&buf, path);
1640  buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_EXCL);
1641  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
1642  buf_add_uint32(&buf, mode);
1643  err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
1644  if (!err) {
1645    int err2;
1646    buf_finish(&handle);
1647    err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS,
1648            NULL);
1649    if (!err)
1650      err = err2;
1651    buf_free(&handle);
1652  }
1653  buf_free(&buf);
1654  return err;
1655}
1656
1657static int sshfs_symlink(const char *from, const char *to)
1658{
1659  int err;
1660  struct buffer buf;
1661
1662  if (sshfs.server_version < 3)
1663    return -EPERM;
1664
1665  /* openssh sftp server doesn't follow standard: link target and
1666     link name are mixed up, so we must also be non-standard :( */
1667  buf_init(&buf, 0);
1668  buf_add_string(&buf, from);
1669  buf_add_path(&buf, to);
1670  err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
1671  buf_free(&buf);
1672  return err;
1673}
1674
1675static int sshfs_unlink(const char *path)
1676{
1677  int err;
1678  struct buffer buf;
1679  buf_init(&buf, 0);
1680  buf_add_path(&buf, path);
1681  err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
1682  buf_free(&buf);
1683  return err;
1684}
1685
1686static int sshfs_rmdir(const char *path)
1687{
1688  int err;
1689  struct buffer buf;
1690  buf_init(&buf, 0);
1691  buf_add_path(&buf, path);
1692  err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
1693  buf_free(&buf);
1694  return err;
1695}
1696
1697static int sshfs_do_rename(const char *from, const char *to)
1698{
1699  int err;
1700  struct buffer buf;
1701  buf_init(&buf, 0);
1702  buf_add_path(&buf, from);
1703  buf_add_path(&buf, to);
1704  err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
1705  buf_free(&buf);
1706  return err;
1707}
1708
1709static void random_string(char *str, int length)
1710{
1711  int i;
1712  for (i = 0; i < length; i++)
1713    *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10);
1714  *str = '\0';
1715}
1716
1717static int sshfs_rename(const char *from, const char *to)
1718{
1719  int err;
1720  err = sshfs_do_rename(from, to);
1721  if (err == -EPERM && sshfs.rename_workaround) {
1722    size_t tolen = strlen(to);
1723    if (tolen + RENAME_TEMP_CHARS < PATH_MAX) {
1724      int tmperr;
1725      char totmp[PATH_MAX];
1726      strcpy(totmp, to);
1727      random_string(totmp + tolen, RENAME_TEMP_CHARS);
1728      tmperr = sshfs_do_rename(to, totmp);
1729      if (!tmperr) {
1730        err = sshfs_do_rename(from, to);
1731        if (!err)
1732          err = sshfs_unlink(totmp);
1733        else
1734          sshfs_do_rename(totmp, to);
1735      }
1736    }
1737  }
1738  return err;
1739}
1740
1741static int sshfs_chmod(const char *path, mode_t mode)
1742{
1743  int err;
1744  struct buffer buf;
1745  buf_init(&buf, 0);
1746  buf_add_path(&buf, path);
1747  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
1748  buf_add_uint32(&buf, mode);
1749  err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
1750  buf_free(&buf);
1751  return err;
1752}
1753
1754static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
1755{
1756  int err;
1757  struct buffer buf;
1758  buf_init(&buf, 0);
1759  buf_add_path(&buf, path);
1760  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
1761  buf_add_uint32(&buf, uid);
1762  buf_add_uint32(&buf, gid);
1763  err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
1764  buf_free(&buf);
1765  return err;
1766}
1767
1768static int sshfs_truncate_workaround(const char *path, off_t size,
1769                                     struct fuse_file_info *fi);
1770
1771static int sshfs_truncate(const char *path, off_t size)
1772{
1773  int err;
1774  struct buffer buf;
1775
1776  sshfs.modifver ++;
1777  if (size == 0 || sshfs.truncate_workaround)
1778    return sshfs_truncate_workaround(path, size, NULL);
1779
1780  buf_init(&buf, 0);
1781  buf_add_path(&buf, path);
1782  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
1783  buf_add_uint64(&buf, size);
1784  err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
1785  buf_free(&buf);
1786  return err;
1787}
1788
1789static int sshfs_utime(const char *path, struct utimbuf *ubuf)
1790{
1791  int err;
1792  struct buffer buf;
1793  buf_init(&buf, 0);
1794  buf_add_path(&buf, path);
1795  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
1796  buf_add_uint32(&buf, ubuf->actime);
1797  buf_add_uint32(&buf, ubuf->modtime);
1798  err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
1799  buf_free(&buf);
1800  return err;
1801}
1802
1803static inline int sshfs_file_is_conn(struct sshfs_file *sf)
1804{
1805  return sf->connver == sshfs.connver;
1806}
1807
1808static int sshfs_open_common(const char *path, mode_t mode,
1809                             struct fuse_file_info *fi)
1810{
1811  int err;
1812  int err2;
1813  struct buffer buf;
1814  struct buffer outbuf;
1815  struct stat stbuf;
1816  struct sshfs_file *sf;
1817  struct request *open_req;
1818  uint32_t pflags = 0;
1819  struct iovec iov;
1820  uint8_t type;
1821
1822  if ((fi->flags & O_ACCMODE) == O_RDONLY)
1823    pflags = SSH_FXF_READ;
1824  else if((fi->flags & O_ACCMODE) == O_WRONLY)
1825    pflags = SSH_FXF_WRITE;
1826  else if ((fi->flags & O_ACCMODE) == O_RDWR)
1827    pflags = SSH_FXF_READ | SSH_FXF_WRITE;
1828  else
1829    return -EINVAL;
1830
1831  if (fi->flags & O_CREAT)
1832    pflags |= SSH_FXF_CREAT;
1833
1834  if (fi->flags & O_EXCL)
1835    pflags |= SSH_FXF_EXCL;
1836
1837  if (fi->flags & O_TRUNC)
1838    pflags |= SSH_FXF_TRUNC;
1839
1840  sf = g_new0(struct sshfs_file, 1);
1841  list_init(&sf->write_reqs);
1842  pthread_cond_init(&sf->write_finished, NULL);
1843  /* Assume random read after open */
1844  sf->is_seq = 0;
1845  sf->refs = 1;
1846  sf->next_pos = 0;
1847  sf->modifver= sshfs.modifver;
1848  sf->connver = sshfs.connver;
1849  buf_init(&buf, 0);
1850  buf_add_path(&buf, path);
1851  buf_add_uint32(&buf, pflags);
1852  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
1853  buf_add_uint32(&buf, mode);
1854  buf_to_iov(&buf, &iov);
1855  sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL,
1856        &open_req);
1857  buf_clear(&buf);
1858  buf_add_path(&buf, path);
1859  type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT;
1860  err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf);
1861  if (!err2) {
1862    if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1)
1863      err2 = -EIO;
1864    buf_free(&outbuf);
1865  }
1866  err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE,
1867        &sf->handle);
1868  if (!err && err2) {
1869    buf_finish(&sf->handle);
1870    sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL);
1871    buf_free(&sf->handle);
1872    err = err2;
1873  }
1874
1875  if (!err) {
1876    cache_add_attr(path, &stbuf);
1877    buf_finish(&sf->handle);
1878    fi->fh = (unsigned long) sf;
1879  } else {
1880    cache_invalidate(path);
1881    g_free(sf);
1882  }
1883  buf_free(&buf);
1884  return err;
1885}
1886
1887static int sshfs_open(const char *path, struct fuse_file_info *fi)
1888{
1889  return sshfs_open_common(path, 0, fi);
1890}
1891
1892static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
1893{
1894  return (struct sshfs_file *) (uintptr_t) fi->fh;
1895}
1896
1897static int sshfs_flush(const char *path, struct fuse_file_info *fi)
1898{
1899  int err;
1900  struct sshfs_file *sf = get_sshfs_file(fi);
1901  struct list_head write_reqs;
1902  struct list_head *curr_list;
1903
1904  if (!sshfs_file_is_conn(sf))
1905    return -EIO;
1906
1907  if (sshfs.sync_write)
1908    return 0;
1909
1910  (void) path;
1911  pthread_mutex_lock(&sshfs.lock);
1912  if (!list_empty(&sf->write_reqs)) {
1913    curr_list = sf->write_reqs.prev;
1914    list_del(&sf->write_reqs);
1915    list_init(&sf->write_reqs);
1916    list_add(&write_reqs, curr_list);
1917    while (!list_empty(&write_reqs))
1918      pthread_cond_wait(&sf->write_finished, &sshfs.lock);
1919  }
1920  err = sf->write_error;
1921  sf->write_error = 0;
1922  pthread_mutex_unlock(&sshfs.lock);
1923  return err;
1924}
1925
1926static int sshfs_fsync(const char *path, int isdatasync,
1927                       struct fuse_file_info *fi)
1928{
1929  (void) isdatasync;
1930  return sshfs_flush(path, fi);
1931}
1932
1933static void sshfs_file_put(struct sshfs_file *sf)
1934{
1935  sf->refs--;
1936  if (!sf->refs)
1937    g_free(sf);
1938}
1939
1940static void sshfs_file_get(struct sshfs_file *sf)
1941{
1942  sf->refs++;
1943}
1944
1945static int sshfs_release(const char *path, struct fuse_file_info *fi)
1946{
1947  struct sshfs_file *sf = get_sshfs_file(fi);
1948  struct buffer *handle = &sf->handle;
1949  if (sshfs_file_is_conn(sf)) {
1950    sshfs_flush(path, fi);
1951    sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
1952  }
1953  buf_free(handle);
1954  chunk_put_locked(sf->readahead);
1955  sshfs_file_put(sf);
1956  return 0;
1957}
1958
1959static int sshfs_sync_read(struct sshfs_file *sf, char *rbuf, size_t size,
1960                           off_t offset)
1961{
1962  int err;
1963  struct buffer buf;
1964  struct buffer data;
1965  struct buffer *handle = &sf->handle;
1966  buf_init(&buf, 0);
1967  buf_add_buf(&buf, handle);
1968  buf_add_uint64(&buf, offset);
1969  buf_add_uint32(&buf, size);
1970  err = sftp_request(SSH_FXP_READ, &buf, SSH_FXP_DATA, &data);
1971  if (!err) {
1972    uint32_t retsize;
1973    err = -EIO;
1974    if (buf_get_uint32(&data, &retsize) != -1) {
1975      if (retsize > size)
1976        fprintf(stderr, "long read\n");
1977      else {
1978        buf_get_mem(&data, rbuf, retsize);
1979        err = retsize;
1980      }
1981    }
1982    buf_free(&data);
1983  } else if (err == MY_EOF)
1984    err = 0;
1985  buf_free(&buf);
1986  return err;
1987}
1988
1989static void sshfs_read_end(struct request *req)
1990{
1991  struct read_chunk *chunk = (struct read_chunk *) req->data;
1992  if (req->error)
1993    chunk->res = req->error;
1994  else if (req->replied) {
1995    chunk->res = -EIO;
1996
1997    if (req->reply_type == SSH_FXP_STATUS) {
1998      uint32_t serr;
1999      if (buf_get_uint32(&req->reply, &serr) != -1) {
2000        if (serr == SSH_FX_EOF)
2001          chunk->res = 0;
2002      }
2003    } else if (req->reply_type == SSH_FXP_DATA) {
2004      uint32_t retsize;
2005      if (buf_get_uint32(&req->reply, &retsize) != -1) {
2006        if (retsize > chunk->size)
2007          fprintf(stderr, "long read\n");
2008        else {
2009          chunk->res = retsize;
2010          chunk->data = req->reply;
2011          buf_init(&req->reply, 0);
2012        }
2013      }
2014    } else
2015      fprintf(stderr, "protocol error\n");
2016  } else
2017    chunk->res = -EIO;
2018
2019  sem_post(&chunk->ready);
2020  chunk_put(chunk);
2021}
2022
2023static void sshfs_read_begin(struct request *req)
2024{
2025  struct read_chunk *chunk = (struct read_chunk *) req->data;
2026  chunk->refs++;
2027}
2028
2029static void sshfs_send_async_read(struct sshfs_file *sf,
2030                                  struct read_chunk *chunk)
2031{
2032  struct buffer buf;
2033  struct buffer *handle = &sf->handle;
2034  struct iovec iov;
2035
2036  buf_init(&buf, 0);
2037  buf_add_buf(&buf, handle);
2038  buf_add_uint64(&buf, chunk->offset);
2039  buf_add_uint32(&buf, chunk->size);
2040  buf_to_iov(&buf, &iov);
2041  sftp_request_send(SSH_FXP_READ, &iov, 1, sshfs_read_begin,
2042        sshfs_read_end, 0, chunk, NULL);
2043  buf_free(&buf);
2044}
2045
2046static void submit_read(struct sshfs_file *sf, size_t size, off_t offset,
2047                        struct read_chunk **chunkp)
2048{
2049  struct read_chunk *chunk = g_new0(struct read_chunk, 1);
2050
2051  sem_init(&chunk->ready, 0, 0);
2052  buf_init(&chunk->data, 0);
2053  chunk->offset = offset;
2054  chunk->size = size;
2055  chunk->refs = 1;
2056  chunk->modifver = sshfs.modifver;
2057  sshfs_send_async_read(sf, chunk);
2058  pthread_mutex_lock(&sshfs.lock);
2059  chunk_put(*chunkp);
2060  *chunkp = chunk;
2061  pthread_mutex_unlock(&sshfs.lock);
2062}
2063
2064static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size)
2065{
2066  int res;
2067  while (sem_wait(&chunk->ready));
2068  res = chunk->res;
2069  if (res > 0) {
2070    if ((size_t) res > size)
2071      res = size;
2072    buf_get_mem(&chunk->data, buf, res);
2073    chunk->offset += res;
2074    chunk->size -= res;
2075    chunk->res -= res;
2076  }
2077  sem_post(&chunk->ready);
2078  chunk_put_locked(chunk);
2079  return res;
2080}
2081
2082static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset)
2083{
2084  struct read_chunk *ch = sf->readahead;
2085  if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) {
2086    ch->refs++;
2087    return ch;
2088  } else
2089    return NULL;
2090}
2091
2092static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size,
2093                            off_t offset)
2094{
2095  int res = 0;
2096  size_t total = 0;
2097  struct read_chunk *chunk;
2098  struct read_chunk *chunk_prev = NULL;
2099  size_t origsize = size;
2100  int curr_is_seq;
2101
2102  pthread_mutex_lock(&sshfs.lock);
2103  curr_is_seq = sf->is_seq;
2104  sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver);
2105  sf->next_pos = offset + size;
2106  sf->modifver = sshfs.modifver;
2107  chunk = search_read_chunk(sf, offset);
2108  pthread_mutex_unlock(&sshfs.lock);
2109
2110  if (chunk && chunk->size < size) {
2111    chunk_prev = chunk;
2112    size -= chunk->size;
2113    offset += chunk->size;
2114    chunk = NULL;
2115  }
2116
2117  if (!chunk)
2118    submit_read(sf, size, offset, &chunk);
2119
2120  if (curr_is_seq && chunk && chunk->size <= size)
2121    submit_read(sf, origsize, offset + size, &sf->readahead);
2122
2123  if (chunk_prev) {
2124    size_t prev_size = chunk_prev->size;
2125    res = wait_chunk(chunk_prev, rbuf, prev_size);
2126    if (res < (int) prev_size) {
2127      chunk_put_locked(chunk);
2128      return res;
2129    }
2130    rbuf += res;
2131    total += res;
2132  }
2133  res = wait_chunk(chunk, rbuf, size);
2134  if (res > 0)
2135    total += res;
2136  if (res < 0)
2137    return res;
2138
2139  return total;
2140}
2141
2142static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
2143                      struct fuse_file_info *fi)
2144{
2145  struct sshfs_file *sf = get_sshfs_file(fi);
2146  (void) path;
2147
2148  if (!sshfs_file_is_conn(sf))
2149    return -EIO;
2150
2151  if (sshfs.sync_read)
2152    return sshfs_sync_read(sf, rbuf, size, offset);
2153  else
2154    return sshfs_async_read(sf, rbuf, size, offset);
2155}
2156
2157static void sshfs_write_begin(struct request *req)
2158{
2159  struct sshfs_file *sf = (struct sshfs_file *) req->data;
2160
2161  sshfs_file_get(sf);
2162  list_add(&req->list, &sf->write_reqs);
2163}
2164
2165static void sshfs_write_end(struct request *req)
2166{
2167  uint32_t serr;
2168  struct sshfs_file *sf = (struct sshfs_file *) req->data;
2169
2170  if (req->error)
2171    sf->write_error = req->error;
2172  else if (req->replied) {
2173    if (req->reply_type != SSH_FXP_STATUS) {
2174      fprintf(stderr, "protocol error\n");
2175    } else if (buf_get_uint32(&req->reply, &serr) != -1 &&
2176       serr != SSH_FX_OK) {
2177      sf->write_error = -EIO;
2178    }
2179  }
2180  list_del(&req->list);
2181  pthread_cond_broadcast(&sf->write_finished);
2182  sshfs_file_put(sf);
2183}
2184
2185static int sshfs_write(const char *path, const char *wbuf, size_t size,
2186                       off_t offset, struct fuse_file_info *fi)
2187{
2188  int err;
2189  struct buffer buf;
2190  struct sshfs_file *sf = get_sshfs_file(fi);
2191  struct buffer *handle = &sf->handle;
2192  struct iovec iov[2];
2193
2194  (void) path;
2195
2196  if (!sshfs_file_is_conn(sf))
2197    return -EIO;
2198
2199  sshfs.modifver ++;
2200  buf_init(&buf, 0);
2201  buf_add_buf(&buf, handle);
2202  buf_add_uint64(&buf, offset);
2203  buf_add_uint32(&buf, size);
2204  buf_to_iov(&buf, &iov[0]);
2205  iov[1].iov_base = (void *) wbuf;
2206  iov[1].iov_len = size;
2207  if (!sshfs.sync_write && !sf->write_error) {
2208    err = sftp_request_send(SSH_FXP_WRITE, iov, 2,
2209          sshfs_write_begin, sshfs_write_end,
2210          0, sf, NULL);
2211  } else {
2212    err = sftp_request_iov(SSH_FXP_WRITE, iov, 2, SSH_FXP_STATUS,
2213               NULL);
2214  }
2215  buf_free(&buf);
2216  return err ? err : (int) size;
2217}
2218
2219#if FUSE_VERSION >= 25
2220static int sshfs_statfs(const char *path, struct statvfs *buf)
2221{
2222  (void) path;
2223
2224  buf->f_namemax = 255;
2225  buf->f_bsize = sshfs.blksize;
2226  /*
2227   * df seems to use f_bsize instead of f_frsize, so make them
2228   * the same
2229   */
2230  buf->f_frsize = buf->f_bsize;
2231  buf->f_blocks = buf->f_bfree =  buf->f_bavail =
2232    1000ULL * 1024 * 1024 * 1024 / buf->f_frsize;
2233  buf->f_files = buf->f_ffree = 1000000000;
2234  return 0;
2235}
2236#else
2237static int sshfs_statfs(const char *path, struct statfs *buf)
2238{
2239  (void) path;
2240
2241  buf->f_namelen = 255;
2242  buf->f_bsize = sshfs.blksize;
2243  buf->f_blocks = buf->f_bfree = buf->f_bavail =
2244    1000ULL * 1024 * 1024 * 1024 / buf->f_bsize;
2245  buf->f_files = buf->f_ffree = 1000000000;
2246  return 0;
2247}
2248#endif
2249
2250#if FUSE_VERSION >= 25
2251static int sshfs_create(const char *path, mode_t mode,
2252                        struct fuse_file_info *fi)
2253{
2254  return sshfs_open_common(path, mode, fi);
2255}
2256
2257static int sshfs_ftruncate(const char *path, off_t size,
2258                           struct fuse_file_info *fi)
2259{
2260  int err;
2261  struct buffer buf;
2262  struct sshfs_file *sf = get_sshfs_file(fi);
2263
2264  (void) path;
2265
2266  if (!sshfs_file_is_conn(sf))
2267    return -EIO;
2268
2269  sshfs.modifver ++;
2270  if (sshfs.truncate_workaround)
2271    return sshfs_truncate_workaround(path, size, fi);
2272
2273  buf_init(&buf, 0);
2274  buf_add_buf(&buf, &sf->handle);
2275  buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
2276  buf_add_uint64(&buf, size);
2277  err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL);
2278  buf_free(&buf);
2279
2280  return err;
2281}
2282#endif
2283
2284static int sshfs_fgetattr(const char *path, struct stat *stbuf,
2285        struct fuse_file_info *fi)
2286{
2287  int err;
2288  struct buffer buf;
2289  struct buffer outbuf;
2290  struct sshfs_file *sf = get_sshfs_file(fi);
2291
2292  (void) path;
2293
2294  if (!sshfs_file_is_conn(sf))
2295    return -EIO;
2296
2297  buf_init(&buf, 0);
2298  buf_add_buf(&buf, &sf->handle);
2299  err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
2300  if (!err) {
2301    if (buf_get_attrs(&outbuf, stbuf, NULL) == -1)
2302      err = -EIO;
2303    buf_free(&outbuf);
2304  }
2305  buf_free(&buf);
2306  return err;
2307}
2308
2309static int sshfs_truncate_zero(const char *path)
2310{
2311  int err;
2312  struct fuse_file_info fi;
2313
2314  fi.flags = O_WRONLY | O_TRUNC;
2315  err = sshfs_open(path, &fi);
2316  if (!err)
2317    sshfs_release(path, &fi);
2318
2319  return err;
2320}
2321
2322static size_t calc_buf_size(off_t size, off_t offset)
2323{
2324  return offset + sshfs.max_read < size ? sshfs.max_read : size - offset;
2325}
2326
2327static int sshfs_truncate_shrink(const char *path, off_t size)
2328{
2329  int res;
2330  char *data;
2331  off_t offset;
2332  struct fuse_file_info fi;
2333
2334  data = calloc(size, 1);
2335  if (!data)
2336    return -ENOMEM;
2337
2338  fi.flags = O_RDONLY;
2339  res = sshfs_open(path, &fi);
2340  if (res)
2341    goto out;
2342
2343  for (offset = 0; offset < size; offset += res) {
2344    size_t bufsize = calc_buf_size(size, offset);
2345    res = sshfs_read(path, data + offset, bufsize, offset, &fi);
2346    if (res <= 0)
2347      break;
2348  }
2349  sshfs_release(path, &fi);
2350  if (res < 0)
2351    goto out;
2352
2353  fi.flags = O_WRONLY | O_TRUNC;
2354  res = sshfs_open(path, &fi);
2355  if (res)
2356    goto out;
2357
2358  for (offset = 0; offset < size; offset += res) {
2359    size_t bufsize = calc_buf_size(size, offset);
2360    res = sshfs_write(path, data + offset, bufsize, offset, &fi);
2361    if (res < 0)
2362      break;
2363  }
2364  if (res >= 0)
2365    res = sshfs_flush(path, &fi);
2366  sshfs_release(path, &fi);
2367
2368out:
2369  free(data);
2370  return res;
2371}
2372
2373static int sshfs_truncate_extend(const char *path, off_t size,
2374                                 struct fuse_file_info *fi)
2375{
2376  int res;
2377  char c = 0;
2378  struct fuse_file_info tmpfi;
2379  struct fuse_file_info *openfi = fi;
2380  if (!fi) {
2381    openfi = &tmpfi;
2382    openfi->flags = O_WRONLY;
2383    res = sshfs_open(path, openfi);
2384    if (res)
2385      return res;
2386  }
2387  res = sshfs_write(path, &c, 1, size - 1, openfi);
2388  if (res == 1)
2389    res = sshfs_flush(path, openfi);
2390  if (!fi)
2391    sshfs_release(path, openfi);
2392
2393  return res;
2394}
2395
2396/*
2397 * Work around broken sftp servers which don't handle
2398 * SSH_FILEXFER_ATTR_SIZE in SETSTAT request.
2399 *
2400 * If new size is zero, just open the file with O_TRUNC.
2401 *
2402 * If new size is smaller than current size, then copy file locally,
2403 * then open/trunc and send it back.
2404 *
2405 * If new size is greater than current size, then write a zero byte to
2406 * the new end of the file.
2407 */
2408static int sshfs_truncate_workaround(const char *path, off_t size,
2409                                     struct fuse_file_info *fi)
2410{
2411  if (size == 0)
2412    return sshfs_truncate_zero(path);
2413  else {
2414    struct stat stbuf;
2415    int err;
2416    if (fi)
2417      err = sshfs_fgetattr(path, &stbuf, fi);
2418    else
2419      err = sshfs_getattr(path, &stbuf);
2420    if (err)
2421      return err;
2422    if (stbuf.st_size == size)
2423      return 0;
2424    else if (stbuf.st_size > size)
2425      return sshfs_truncate_shrink(path, size);
2426    else
2427      return sshfs_truncate_extend(path, size, fi);
2428  }
2429}
2430
2431static int processing_init(void)
2432{
2433  pthread_mutex_init(&sshfs.lock, NULL);
2434  pthread_mutex_init(&sshfs.lock_write, NULL);
2435  pthread_cond_init(&sshfs.outstanding_cond, NULL);
2436  sshfs.reqtab = g_hash_table_new(NULL, NULL);
2437  if (!sshfs.reqtab) {
2438    fprintf(stderr, "failed to create hash table\n");
2439    return -1;
2440  }
2441  return 0;
2442}
2443
2444static struct fuse_cache_operations sshfs_oper = {
2445  .oper = {
2446#ifdef SSHFS_USE_INIT
2447    .init       = sshfs_init,
2448#endif
2449    .getattr    = sshfs_getattr,
2450    .readlink   = sshfs_readlink,
2451    .mknod      = sshfs_mknod,
2452    .mkdir      = sshfs_mkdir,
2453    .symlink    = sshfs_symlink,
2454    .unlink     = sshfs_unlink,
2455    .rmdir      = sshfs_rmdir,
2456    .rename     = sshfs_rename,
2457    .chmod      = sshfs_chmod,
2458    .chown      = sshfs_chown,
2459    .truncate   = sshfs_truncate,
2460    .utime      = sshfs_utime,
2461    .open       = sshfs_open,
2462    .flush      = sshfs_flush,
2463    .fsync      = sshfs_fsync,
2464    .release    = sshfs_release,
2465    .read       = sshfs_read,
2466    .write      = sshfs_write,
2467    .statfs     = sshfs_statfs,
2468#if FUSE_VERSION >= 25
2469    .create     = sshfs_create,
2470    .ftruncate  = sshfs_ftruncate,
2471    .fgetattr   = sshfs_fgetattr,
2472#endif
2473  },
2474  .cache_getdir = sshfs_getdir,
2475};
2476
2477static void usage(const char *progname)
2478{
2479  fprintf(stderr,
2480"usage: %s [user@]host:[dir] mountpoint [options]\n"
2481"\n"
2482"general options:\n"
2483"    -o opt,[opt...]        mount options\n"
2484"    -h   --help            print help\n"
2485"    -V   --version         print version\n"
2486"\n"
2487"SSHFS options:\n"
2488"    -p PORT                equivalent to '-o port=PORT'\n"
2489"    -C                     equivalent to '-o compression=yes'\n"
2490"    -1                     equivalent to '-o ssh_protocol=1'\n"
2491"    -o reconnect           reconnect to server\n"
2492"    -o sshfs_sync          synchronous writes\n"
2493"    -o no_readahead        synchronous reads (no speculative readahead)\n"
2494"    -o sshfs_debug         print some debugging information\n"
2495"    -o cache=YESNO         enable caching {yes,no} (default: yes)\n"
2496"    -o cache_timeout=N     sets timeout for caches in seconds (default: 20)\n"
2497"    -o cache_X_timeout=N   sets timeout for {stat,dir,link} cache\n"
2498"    -o workaround=LIST     colon separated list of workarounds\n"
2499"             none             no workarounds enabled\n"
2500"             all              all workarounds enabled\n"
2501"             [no]rename       fix renaming to existing file (default: off)\n"
2502#ifdef SSH_NODELAY_WORKAROUND
2503"             [no]nodelay      set nodelay tcp flag in ssh (default: on)\n"
2504#endif
2505"             [no]nodelaysrv   set nodelay tcp flag in sshd (default: off)\n"
2506"             [no]truncate     fix truncate for old servers (default: off)\n"
2507"             [no]buflimit     fix buffer fillup bug in server (default: on)\n"
2508"    -o idmap=TYPE          user/group ID mapping, possible types are:\n"
2509"             none             no translation of the ID space (default)\n"
2510"             user             only translate UID of connecting user\n"
2511"    -o ssh_command=CMD     execute CMD instead of 'ssh'\n"
2512"    -o ssh_protocol=N      ssh protocol to use (default: 2)\n"
2513"    -o sftp_server=SERV    path to sftp server or subsystem (default: sftp)\n"
2514"    -o directport=PORT     directly connect to PORT bypassing ssh\n"
2515"    -o transform_symlinks  transform absolute symlinks to relative\n"
2516"    -o follow_symlinks     follow symlinks on the server\n"
2517"    -o no_check_root       don't check for existence of 'dir' on server\n"
2518"    -o SSHOPT=VAL          ssh options (see man ssh_config)\n"
2519"\n", progname);
2520}
2521
2522static int is_ssh_opt(const char *arg)
2523{
2524  if (arg[0] != '-') {
2525    unsigned arglen = strlen(arg);
2526    const char **o;
2527    for (o = ssh_opts; *o; o++) {
2528      unsigned olen = strlen(*o);
2529      if (arglen > olen && arg[olen] == '=' &&
2530          strncasecmp(arg, *o, olen) == 0)
2531        return 1;
2532    }
2533  }
2534  return 0;
2535}
2536
2537static int sshfs_fuse_main(struct fuse_args *args)
2538{
2539#if FUSE_VERSION >= 26
2540  return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL);
2541#else
2542  return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper));
2543#endif
2544}
2545
2546static int sshfs_opt_proc(void *data, const char *arg, int key,
2547                          struct fuse_args *outargs)
2548{
2549  char *tmp;
2550  (void) data;
2551
2552  switch (key) {
2553  case FUSE_OPT_KEY_OPT:
2554    if (is_ssh_opt(arg)) {
2555      tmp = g_strdup_printf("-o%s", arg);
2556      ssh_add_arg(tmp);
2557      g_free(tmp);
2558      return 0;
2559    }
2560    return 1;
2561
2562  case FUSE_OPT_KEY_NONOPT:
2563    if (!sshfs.host && strchr(arg, ':')) {
2564      sshfs.host = strdup(arg);
2565      return 0;
2566    }
2567    return 1;
2568
2569  case KEY_PORT:
2570    tmp = g_strdup_printf("-oPort=%s", arg + 2);
2571    ssh_add_arg(tmp);
2572    g_free(tmp);
2573    return 0;
2574
2575  case KEY_COMPRESS:
2576    ssh_add_arg("-oCompression=yes");
2577    return 0;
2578
2579  case KEY_HELP:
2580    usage(outargs->argv[0]);
2581    fuse_opt_add_arg(outargs, "-ho");
2582    sshfs_fuse_main(outargs);
2583    exit(1);
2584
2585  case KEY_VERSION:
2586    fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION);
2587#if FUSE_VERSION >= 25
2588    fuse_opt_add_arg(outargs, "--version");
2589    sshfs_fuse_main(outargs);
2590#endif
2591    exit(0);
2592
2593  default:
2594    fprintf(stderr, "internal error\n");
2595    abort();
2596  }
2597}
2598
2599static int workaround_opt_proc(void *data, const char *arg, int key,
2600             struct fuse_args *outargs)
2601{
2602  (void) data; (void) key; (void) outargs;
2603  fprintf(stderr, "unknown workaround: '%s'\n", arg);
2604  return -1;
2605}
2606
2607int parse_workarounds(void)
2608{
2609  int res;
2610  char *argv[] = { "", "-o", sshfs.workarounds, NULL };
2611  struct fuse_args args = FUSE_ARGS_INIT(3, argv);
2612  char *s = sshfs.workarounds;
2613  if (!s)
2614    return 0;
2615
2616  while ((s = strchr(s, ':')))
2617    *s = ',';
2618
2619  res = fuse_opt_parse(&args, &sshfs, workaround_opts,
2620           workaround_opt_proc);
2621  fuse_opt_free_args(&args);
2622
2623  return res;
2624}
2625
2626#if FUSE_VERSION == 25
2627static int fuse_opt_insert_arg(struct fuse_args *args, int pos,
2628                               const char *arg)
2629{
2630  assert(pos <= args->argc);
2631  if (fuse_opt_add_arg(args, arg) == -1)
2632    return -1;
2633
2634  if (pos != args->argc - 1) {
2635    char *newarg = args->argv[args->argc - 1];
2636    memmove(&args->argv[pos + 1], &args->argv[pos],
2637      sizeof(char *) * (args->argc - pos - 1));
2638    args->argv[pos] = newarg;
2639  }
2640  return 0;
2641}
2642#endif
2643
2644void check_large_read(struct fuse_args *args)
2645{
2646  struct utsname buf;
2647  int err = uname(&buf);
2648  if (!err && strcmp(buf.sysname, "Linux") == 0 &&
2649      strncmp(buf.release, "2.4.", 4) == 0)
2650    fuse_opt_insert_arg(args, 1, "-olarge_read");
2651}
2652
2653int main(int argc, char *argv[])
2654{
2655  int res;
2656  struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
2657  char *tmp;
2658  char *fsname;
2659  char *base_path;
2660  const char *sftp_server;
2661  int libver;
2662
2663  g_thread_init(NULL);
2664
2665  sshfs.blksize = 4096;
2666  sshfs.max_read = 65536;
2667  sshfs.nodelay_workaround = 1;
2668  sshfs.nodelaysrv_workaround = 0;
2669  sshfs.rename_workaround = 0;
2670  sshfs.truncate_workaround = 0;
2671  sshfs.buflimit_workaround = 1;
2672  sshfs.ssh_ver = 2;
2673  sshfs.progname = argv[0];
2674  ssh_add_arg("ssh");
2675  ssh_add_arg("-x");
2676  ssh_add_arg("-a");
2677  ssh_add_arg("-oClearAllForwardings=yes");
2678
2679  if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 ||
2680      parse_workarounds() == -1)
2681    exit(1);
2682
2683  if (sshfs.buflimit_workaround)
2684    /* Work around buggy sftp-server in OpenSSH.  Without this on
2685       a slow server a 10Mbyte buffer would fill up and the server
2686       would abort */
2687    sshfs.max_outstanding_len = 8388608;
2688  else
2689    sshfs.max_outstanding_len = ~0;
2690
2691  if (!sshfs.host) {
2692    fprintf(stderr, "missing host\n");
2693    fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
2694    exit(1);
2695  }
2696
2697  fsname = g_strdup(sshfs.host);
2698  base_path = strchr(sshfs.host, ':');
2699  *base_path++ = '\0';
2700  if (base_path[0] && base_path[strlen(base_path)-1] != '/')
2701    sshfs.base_path = g_strdup_printf("%s/", base_path);
2702  else
2703    sshfs.base_path = g_strdup(base_path);
2704
2705  if (sshfs.ssh_command) {
2706    free(sshfs.ssh_args.argv[0]);
2707    sshfs.ssh_args.argv[0] = sshfs.ssh_command;
2708  }
2709
2710  tmp = g_strdup_printf("-%i", sshfs.ssh_ver);
2711  ssh_add_arg(tmp);
2712  g_free(tmp);
2713  ssh_add_arg(sshfs.host);
2714  if (sshfs.sftp_server)
2715    sftp_server = sshfs.sftp_server;
2716  else if (sshfs.ssh_ver == 1)
2717    sftp_server = SFTP_SERVER_PATH;
2718  else
2719    sftp_server = "sftp";
2720
2721  if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL)
2722    ssh_add_arg("-s");
2723
2724  ssh_add_arg(sftp_server);
2725  free(sshfs.sftp_server);
2726
2727  res = processing_init();
2728  if (res == -1)
2729    exit(1);
2730
2731  if (connect_remote() == -1)
2732    exit(1);
2733
2734#ifndef SSHFS_USE_INIT
2735  if (sshfs.detect_uid)
2736    sftp_detect_uid();
2737#endif
2738
2739  if (!sshfs.no_check_root && sftp_check_root(base_path) == -1)
2740    exit(1);
2741
2742  res = cache_parse_options(&args);
2743  if (res == -1)
2744    exit(1);
2745
2746  sshfs.randseed = time(0);
2747
2748  if (sshfs.max_read > 65536)
2749    sshfs.max_read = 65536;
2750
2751  if (fuse_is_lib_option("ac_attr_timeout="))
2752    fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
2753  tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read);
2754  fuse_opt_insert_arg(&args, 1, tmp);
2755  g_free(tmp);
2756#if FUSE_VERSION >= 27
2757  libver = fuse_version();
2758  assert(libver >= 27);
2759  tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
2760#else
2761  tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname);
2762#endif
2763  fuse_opt_insert_arg(&args, 1, tmp);
2764  g_free(tmp);
2765  g_free(fsname);
2766  check_large_read(&args);
2767  res = sshfs_fuse_main(&args);
2768  fuse_opt_free_args(&args);
2769  fuse_opt_free_args(&sshfs.ssh_args);
2770  free(sshfs.directport);
2771
2772  return res;
2773}
Note: See TracBrowser for help on using the repository browser.