[BACK]Return to sftp-client.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/sftp-client.c between version 1.18 and 1.18.2.1

version 1.18, 2001/07/14 15:10:16 version 1.18.2.1, 2002/03/07 17:37:47
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 2001 Damien Miller.  All rights reserved.   * Copyright (c) 2001,2002 Damien Miller.  All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 24 
Line 24 
   
 /* XXX: memleaks */  /* XXX: memleaks */
 /* XXX: signed vs unsigned */  /* XXX: signed vs unsigned */
 /* XXX: redesign to allow concurrent overlapped operations */  /* XXX: remove all logging, only return status codes */
 /* XXX: we use fatal too much, error may be more appropriate in places */  
 /* XXX: copy between two remote sites */  /* XXX: copy between two remote sites */
   
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
   #include <sys/queue.h>
   
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "getput.h"  #include "getput.h"
Line 42 
Line 43 
 #include "sftp-common.h"  #include "sftp-common.h"
 #include "sftp-client.h"  #include "sftp-client.h"
   
 /* How much data to read/write at at time during copies */  /* Minimum amount of data to read at at time */
 /* XXX: what should this be? */  #define MIN_READ_SIZE   512
 #define COPY_SIZE       8192  
   
 /* Message ID */  struct sftp_conn {
 static u_int msg_id = 1;          int fd_in;
           int fd_out;
           u_int transfer_buflen;
           u_int num_requests;
           u_int version;
           u_int msg_id;
   };
   
 static void  static void
 send_msg(int fd, Buffer *m)  send_msg(int fd, Buffer *m)
Line 215 
Line 221 
         return(a);          return(a);
 }  }
   
 int  struct sftp_conn *
 do_init(int fd_in, int fd_out)  do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)
 {  {
         int type, version;          int type, version;
         Buffer msg;          Buffer msg;
           struct sftp_conn *ret;
   
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_INIT);          buffer_put_char(&msg, SSH2_FXP_INIT);
Line 235 
Line 242 
                 error("Invalid packet back from SSH2_FXP_INIT (type %d)",                  error("Invalid packet back from SSH2_FXP_INIT (type %d)",
                     type);                      type);
                 buffer_free(&msg);                  buffer_free(&msg);
                 return(-1);                  return(NULL);
         }          }
         version = buffer_get_int(&msg);          version = buffer_get_int(&msg);
   
Line 253 
Line 260 
   
         buffer_free(&msg);          buffer_free(&msg);
   
         return(version);          ret = xmalloc(sizeof(*ret));
           ret->fd_in = fd_in;
           ret->fd_out = fd_out;
           ret->transfer_buflen = transfer_buflen;
           ret->num_requests = num_requests;
           ret->version = version;
           ret->msg_id = 1;
   
           /* Some filexfer v.0 servers don't support large packets */
           if (version == 0)
                   ret->transfer_buflen = MAX(ret->transfer_buflen, 20480);
   
           return(ret);
 }  }
   
   u_int
   sftp_proto_version(struct sftp_conn *conn)
   {
           return(conn->version);
   }
   
 int  int
 do_close(int fd_in, int fd_out, char *handle, u_int handle_len)  do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
 {  {
         u_int id, status;          u_int id, status;
         Buffer msg;          Buffer msg;
   
         buffer_init(&msg);          buffer_init(&msg);
   
         id = msg_id++;          id = conn->msg_id++;
         buffer_put_char(&msg, SSH2_FXP_CLOSE);          buffer_put_char(&msg, SSH2_FXP_CLOSE);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_string(&msg, handle, handle_len);          buffer_put_string(&msg, handle, handle_len);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
         debug3("Sent message SSH2_FXP_CLOSE I:%d", id);          debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't close file: %s", fx2txt(status));                  error("Couldn't close file: %s", fx2txt(status));
   
Line 282 
Line 307 
   
   
 static int  static int
 do_lsreaddir(int fd_in, int fd_out, char *path, int printflag,  do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
     SFTP_DIRENT ***dir)      SFTP_DIRENT ***dir)
 {  {
         Buffer msg;          Buffer msg;
         u_int type, id, handle_len, i, expected_id, ents = 0;          u_int type, id, handle_len, i, expected_id, ents = 0;
         char *handle;          char *handle;
   
         id = msg_id++;          id = conn->msg_id++;
   
         buffer_init(&msg);          buffer_init(&msg);
         buffer_put_char(&msg, SSH2_FXP_OPENDIR);          buffer_put_char(&msg, SSH2_FXP_OPENDIR);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_cstring(&msg, path);          buffer_put_cstring(&msg, path);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
   
         buffer_clear(&msg);          buffer_clear(&msg);
   
         handle = get_handle(fd_in, id, &handle_len);          handle = get_handle(conn->fd_in, id, &handle_len);
         if (handle == NULL)          if (handle == NULL)
                 return(-1);                  return(-1);
   
Line 308 
Line 333 
                 *dir = xmalloc(sizeof(**dir));                  *dir = xmalloc(sizeof(**dir));
                 (*dir)[0] = NULL;                  (*dir)[0] = NULL;
         }          }
   
   
         for(;;) {          for (;;) {
                 int count;                  int count;
   
                 id = expected_id = msg_id++;                  id = expected_id = conn->msg_id++;
   
                 debug3("Sending SSH2_FXP_READDIR I:%d", id);                  debug3("Sending SSH2_FXP_READDIR I:%d", id);
   
Line 321 
Line 345 
                 buffer_put_char(&msg, SSH2_FXP_READDIR);                  buffer_put_char(&msg, SSH2_FXP_READDIR);
                 buffer_put_int(&msg, id);                  buffer_put_int(&msg, id);
                 buffer_put_string(&msg, handle, handle_len);                  buffer_put_string(&msg, handle, handle_len);
                 send_msg(fd_out, &msg);                  send_msg(conn->fd_out, &msg);
   
                 buffer_clear(&msg);                  buffer_clear(&msg);
   
                 get_msg(fd_in, &msg);                  get_msg(conn->fd_in, &msg);
   
                 type = buffer_get_char(&msg);                  type = buffer_get_char(&msg);
                 id = buffer_get_int(&msg);                  id = buffer_get_int(&msg);
Line 345 
Line 369 
                         } else {                          } else {
                                 error("Couldn't read directory: %s",                                  error("Couldn't read directory: %s",
                                     fx2txt(status));                                      fx2txt(status));
                                 do_close(fd_in, fd_out, handle, handle_len);                                  do_close(conn, handle, handle_len);
                                 return(status);                                  return(status);
                         }                          }
                 } else if (type != SSH2_FXP_NAME)                  } else if (type != SSH2_FXP_NAME)
Line 356 
Line 380 
                 if (count == 0)                  if (count == 0)
                         break;                          break;
                 debug3("Received %d SSH2_FXP_NAME responses", count);                  debug3("Received %d SSH2_FXP_NAME responses", count);
                 for(i = 0; i < count; i++) {                  for (i = 0; i < count; i++) {
                         char *filename, *longname;                          char *filename, *longname;
                         Attrib *a;                          Attrib *a;
   
Line 383 
Line 407 
         }          }
   
         buffer_free(&msg);          buffer_free(&msg);
         do_close(fd_in, fd_out, handle, handle_len);          do_close(conn, handle, handle_len);
         xfree(handle);          xfree(handle);
   
         return(0);          return(0);
 }  }
   
 int  int
 do_ls(int fd_in, int fd_out, char *path)  do_ls(struct sftp_conn *conn, char *path)
 {  {
         return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));          return(do_lsreaddir(conn, path, 1, NULL));
 }  }
   
 int  int
 do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)  do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
 {  {
         return(do_lsreaddir(fd_in, fd_out, path, 0, dir));          return(do_lsreaddir(conn, path, 0, dir));
 }  }
   
 void free_sftp_dirents(SFTP_DIRENT **s)  void free_sftp_dirents(SFTP_DIRENT **s)
 {  {
         int i;          int i;
   
         for(i = 0; s[i]; i++) {          for (i = 0; s[i]; i++) {
                 xfree(s[i]->filename);                  xfree(s[i]->filename);
                 xfree(s[i]->longname);                  xfree(s[i]->longname);
                 xfree(s[i]);                  xfree(s[i]);
Line 414 
Line 438 
 }  }
   
 int  int
 do_rm(int fd_in, int fd_out, char *path)  do_rm(struct sftp_conn *conn, char *path)
 {  {
         u_int status, id;          u_int status, id;
   
         debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);          debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(path));          send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,
         status = get_status(fd_in, id);              strlen(path));
           status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't delete file: %s", fx2txt(status));                  error("Couldn't delete file: %s", fx2txt(status));
         return(status);          return(status);
 }  }
   
 int  int
 do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)  do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,          send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,
             strlen(path), a);              strlen(path), a);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't create directory: %s", fx2txt(status));                  error("Couldn't create directory: %s", fx2txt(status));
   
Line 445 
Line 470 
 }  }
   
 int  int
 do_rmdir(int fd_in, int fd_out, char *path)  do_rmdir(struct sftp_conn *conn, char *path)
 {  {
         u_int status, id;          u_int status, id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));          send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,
               strlen(path));
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't remove directory: %s", fx2txt(status));                  error("Couldn't remove directory: %s", fx2txt(status));
   
Line 460 
Line 486 
 }  }
   
 Attrib *  Attrib *
 do_stat(int fd_in, int fd_out, char *path, int quiet)  do_stat(struct sftp_conn *conn, char *path, int quiet)
 {  {
         u_int id;          u_int id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));  
         return(get_decode_stat(fd_in, id, quiet));          send_string_request(conn->fd_out, id,
               conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
               path, strlen(path));
   
           return(get_decode_stat(conn->fd_in, id, quiet));
 }  }
   
 Attrib *  Attrib *
 do_lstat(int fd_in, int fd_out, char *path, int quiet)  do_lstat(struct sftp_conn *conn, char *path, int quiet)
 {  {
         u_int id;          u_int id;
   
         id = msg_id++;          if (conn->version == 0) {
         send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));                  if (quiet)
         return(get_decode_stat(fd_in, id, quiet));                          debug("Server version does not support lstat operation");
                   else
                           error("Server version does not support lstat operation");
                   return(NULL);
           }
   
           id = conn->msg_id++;
           send_string_request(conn->fd_out, id, SSH2_FXP_LSTAT, path,
               strlen(path));
   
           return(get_decode_stat(conn->fd_in, id, quiet));
 }  }
   
 Attrib *  Attrib *
 do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)  do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
 {  {
         u_int id;          u_int id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);          send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,
         return(get_decode_stat(fd_in, id, quiet));              handle_len);
   
           return(get_decode_stat(conn->fd_in, id, quiet));
 }  }
   
 int  int
 do_setstat(int fd_in, int fd_out, char *path, Attrib *a)  do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,          send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,
             strlen(path), a);              strlen(path), a);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't setstat on \"%s\": %s", path,                  error("Couldn't setstat on \"%s\": %s", path,
                     fx2txt(status));                      fx2txt(status));
Line 507 
Line 549 
 }  }
   
 int  int
 do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,  do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
     Attrib *a)      Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = msg_id++;          id = conn->msg_id++;
         send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,          send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,
             handle_len, a);              handle_len, a);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't fsetstat: %s", fx2txt(status));                  error("Couldn't fsetstat: %s", fx2txt(status));
   
Line 524 
Line 566 
 }  }
   
 char *  char *
 do_realpath(int fd_in, int fd_out, char *path)  do_realpath(struct sftp_conn *conn, char *path)
 {  {
         Buffer msg;          Buffer msg;
         u_int type, expected_id, count, id;          u_int type, expected_id, count, id;
         char *filename, *longname;          char *filename, *longname;
         Attrib *a;          Attrib *a;
   
         expected_id = id = msg_id++;          expected_id = id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));          send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,
               strlen(path));
   
         buffer_init(&msg);          buffer_init(&msg);
   
         get_msg(fd_in, &msg);          get_msg(conn->fd_in, &msg);
         type = buffer_get_char(&msg);          type = buffer_get_char(&msg);
         id = buffer_get_int(&msg);          id = buffer_get_int(&msg);
   
Line 570 
Line 613 
 }  }
   
 int  int
 do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)  do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)
 {  {
         Buffer msg;          Buffer msg;
         u_int status, id;          u_int status, id;
Line 578 
Line 621 
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send rename request */          /* Send rename request */
         id = msg_id++;          id = conn->msg_id++;
         buffer_put_char(&msg, SSH2_FXP_RENAME);          buffer_put_char(&msg, SSH2_FXP_RENAME);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_cstring(&msg, oldpath);          buffer_put_cstring(&msg, oldpath);
         buffer_put_cstring(&msg, newpath);          buffer_put_cstring(&msg, newpath);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
         debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,          debug3("Sent message SSH2_FXP_RENAME \"%s\" -> \"%s\"", oldpath,
             newpath);              newpath);
         buffer_free(&msg);          buffer_free(&msg);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,                  error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
                     fx2txt(status));                      newpath, fx2txt(status));
   
         return(status);          return(status);
 }  }
   
 int  int
 do_symlink(int fd_in, int fd_out, char *oldpath, char *newpath)  do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
 {  {
         Buffer msg;          Buffer msg;
         u_int status, id;          u_int status, id;
   
           if (conn->version < 3) {
                   error("This server does not support the symlink operation");
                   return(SSH2_FX_OP_UNSUPPORTED);
           }
   
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send rename request */          /* Send rename request */
         id = msg_id++;          id = conn->msg_id++;
         buffer_put_char(&msg, SSH2_FXP_SYMLINK);          buffer_put_char(&msg, SSH2_FXP_SYMLINK);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_cstring(&msg, oldpath);          buffer_put_cstring(&msg, oldpath);
         buffer_put_cstring(&msg, newpath);          buffer_put_cstring(&msg, newpath);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
         debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,          debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
             newpath);              newpath);
         buffer_free(&msg);          buffer_free(&msg);
   
         status = get_status(fd_in, id);          status = get_status(conn->fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,                  error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
                     fx2txt(status));                      newpath, fx2txt(status));
   
         return(status);          return(status);
 }  }
   
 char *  char *
 do_readlink(int fd_in, int fd_out, char *path)  do_readlink(struct sftp_conn *conn, char *path)
 {  {
         Buffer msg;          Buffer msg;
         u_int type, expected_id, count, id;          u_int type, expected_id, count, id;
         char *filename, *longname;          char *filename, *longname;
         Attrib *a;          Attrib *a;
   
         expected_id = id = msg_id++;          expected_id = id = conn->msg_id++;
         send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));          send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,
               strlen(path));
   
         buffer_init(&msg);          buffer_init(&msg);
   
         get_msg(fd_in, &msg);          get_msg(conn->fd_in, &msg);
         type = buffer_get_char(&msg);          type = buffer_get_char(&msg);
         id = buffer_get_int(&msg);          id = buffer_get_int(&msg);
   
Line 669 
Line 718 
         return(filename);          return(filename);
 }  }
   
   static void
   send_read_request(int fd_out, u_int id, u_int64_t offset, u_int len,
       char *handle, u_int handle_len)
   {
           Buffer msg;
   
           buffer_init(&msg);
           buffer_clear(&msg);
           buffer_put_char(&msg, SSH2_FXP_READ);
           buffer_put_int(&msg, id);
           buffer_put_string(&msg, handle, handle_len);
           buffer_put_int64(&msg, offset);
           buffer_put_int(&msg, len);
           send_msg(fd_out, &msg);
           buffer_free(&msg);
   }
   
 int  int
 do_download(int fd_in, int fd_out, char *remote_path, char *local_path,  do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
     int pflag)      int pflag)
 {  {
         int local_fd;  
         u_int expected_id, handle_len, mode, type, id;  
         u_int64_t offset;  
         char *handle;  
         Buffer msg;  
         Attrib junk, *a;          Attrib junk, *a;
         int status;          Buffer msg;
           char *handle;
           int local_fd, status, num_req, max_req, write_error;
           int read_error, write_errno;
           u_int64_t offset, size;
           u_int handle_len, mode, type, id, buflen;
           struct request {
                   u_int id;
                   u_int len;
                   u_int64_t offset;
                   TAILQ_ENTRY(request) tq;
           };
           TAILQ_HEAD(reqhead, request) requests;
           struct request *req;
   
         a = do_stat(fd_in, fd_out, remote_path, 0);          TAILQ_INIT(&requests);
   
           a = do_stat(conn, remote_path, 0);
         if (a == NULL)          if (a == NULL)
                 return(-1);                  return(-1);
   
Line 697 
Line 773 
                 return(-1);                  return(-1);
         }          }
   
         local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);          if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
         if (local_fd == -1) {                  size = a->size;
                 error("Couldn't open local file \"%s\" for writing: %s",          else
                     local_path, strerror(errno));                  size = 0;
                 return(-1);  
         }  
   
           buflen = conn->transfer_buflen;
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send open request */          /* Send open request */
         id = msg_id++;          id = conn->msg_id++;
         buffer_put_char(&msg, SSH2_FXP_OPEN);          buffer_put_char(&msg, SSH2_FXP_OPEN);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_cstring(&msg, remote_path);          buffer_put_cstring(&msg, remote_path);
         buffer_put_int(&msg, SSH2_FXF_READ);          buffer_put_int(&msg, SSH2_FXF_READ);
         attrib_clear(&junk); /* Send empty attributes */          attrib_clear(&junk); /* Send empty attributes */
         encode_attrib(&msg, &junk);          encode_attrib(&msg, &junk);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);          debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
   
         handle = get_handle(fd_in, id, &handle_len);          handle = get_handle(conn->fd_in, id, &handle_len);
         if (handle == NULL) {          if (handle == NULL) {
                 buffer_free(&msg);                  buffer_free(&msg);
                 close(local_fd);  
                 return(-1);                  return(-1);
         }          }
   
           local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
           if (local_fd == -1) {
                   error("Couldn't open local file \"%s\" for writing: %s",
                       local_path, strerror(errno));
                   buffer_free(&msg);
                   xfree(handle);
                   return(-1);
           }
   
         /* Read from remote and write to local */          /* Read from remote and write to local */
         offset = 0;          write_error = read_error = write_errno = num_req = offset = 0;
         for(;;) {          max_req = 1;
                 u_int len;          while (num_req > 0 || max_req > 0) {
                 char *data;                  char *data;
                   u_int len;
   
                 id = expected_id = msg_id++;                  /* Send some more requests */
                   while (num_req < max_req) {
                           debug3("Request range %llu -> %llu (%d/%d)",
                               offset, offset + buflen - 1, num_req, max_req);
                           req = xmalloc(sizeof(*req));
                           req->id = conn->msg_id++;
                           req->len = buflen;
                           req->offset = offset;
                           offset += buflen;
                           num_req++;
                           TAILQ_INSERT_TAIL(&requests, req, tq);
                           send_read_request(conn->fd_out, req->id, req->offset,
                               req->len, handle, handle_len);
                   }
   
                 buffer_clear(&msg);                  buffer_clear(&msg);
                 buffer_put_char(&msg, SSH2_FXP_READ);                  get_msg(conn->fd_in, &msg);
                 buffer_put_int(&msg, id);  
                 buffer_put_string(&msg, handle, handle_len);  
                 buffer_put_int64(&msg, offset);  
                 buffer_put_int(&msg, COPY_SIZE);  
                 send_msg(fd_out, &msg);  
                 debug3("Sent message SSH2_FXP_READ I:%d O:%llu S:%u",  
                     id, (unsigned long long)offset, COPY_SIZE);  
   
                 buffer_clear(&msg);  
   
                 get_msg(fd_in, &msg);  
                 type = buffer_get_char(&msg);                  type = buffer_get_char(&msg);
                 id = buffer_get_int(&msg);                  id = buffer_get_int(&msg);
                 debug3("Received reply T:%d I:%d", type, id);                  debug3("Received reply T:%d I:%d R:%d", type, id, max_req);
                 if (id != expected_id)  
                         fatal("ID mismatch (%d != %d)", id, expected_id);                  /* Find the request in our queue */
                 if (type == SSH2_FXP_STATUS) {                  for(req = TAILQ_FIRST(&requests);
                       req != NULL && req->id != id;
                       req = TAILQ_NEXT(req, tq))
                           ;
                   if (req == NULL)
                           fatal("Unexpected reply %u", id);
   
                   switch (type) {
                   case SSH2_FXP_STATUS:
                         status = buffer_get_int(&msg);                          status = buffer_get_int(&msg);
                           if (status != SSH2_FX_EOF)
                                   read_error = 1;
                           max_req = 0;
                           TAILQ_REMOVE(&requests, req, tq);
                           xfree(req);
                           num_req--;
                           break;
                   case SSH2_FXP_DATA:
                           data = buffer_get_string(&msg, &len);
                           debug3("Received data %llu -> %llu", req->offset,
                               req->offset + len - 1);
                           if (len > req->len)
                                   fatal("Received more data than asked for "
                                         "%d > %d", len, req->len);
                           if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
                                atomicio(write, local_fd, data, len) != len) &&
                               !write_error) {
                                   write_errno = errno;
                                   write_error = 1;
                                   max_req = 0;
                           }
                           xfree(data);
   
                         if (status == SSH2_FX_EOF)                          if (len == req->len) {
                                 break;                                  TAILQ_REMOVE(&requests, req, tq);
                         else {                                  xfree(req);
                                 error("Couldn't read from remote "                                  num_req--;
                                     "file \"%s\" : %s", remote_path,                          } else {
                                      fx2txt(status));                                  /* Resend the request for the missing data */
                                 do_close(fd_in, fd_out, handle, handle_len);                                  debug3("Short data block, re-requesting "
                                 goto done;                                      "%llu -> %llu (%2d)", req->offset + len,
                                           req->offset + req->len - 1, num_req);
                                   req->id = conn->msg_id++;
                                   req->len -= len;
                                   req->offset += len;
                                   send_read_request(conn->fd_out, req->id,
                                       req->offset, req->len, handle, handle_len);
                                   /* Reduce the request size */
                                   if (len < buflen)
                                           buflen = MAX(MIN_READ_SIZE, len);
                         }                          }
                 } else if (type != SSH2_FXP_DATA) {                          if (max_req > 0) { /* max_req = 0 iff EOF received */
                                   if (size > 0 && offset > size) {
                                           /* Only one request at a time
                                            * after the expected EOF */
                                           debug3("Finish at %llu (%2d)",
                                               offset, num_req);
                                           max_req = 1;
                                   }
                                   else if (max_req < conn->num_requests + 1) {
                                           ++max_req;
                                   }
                           }
                           break;
                   default:
                         fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",                          fatal("Expected SSH2_FXP_DATA(%d) packet, got %d",
                             SSH2_FXP_DATA, type);                              SSH2_FXP_DATA, type);
                 }                  }
           }
   
                 data = buffer_get_string(&msg, &len);          /* Sanity check */
                 if (len > COPY_SIZE)          if (TAILQ_FIRST(&requests) != NULL)
                         fatal("Received more data than asked for %d > %d",                  fatal("Transfer complete, but requests still in queue");
                             len, COPY_SIZE);  
   
                 debug3("In read loop, got %d offset %llu", len,          if (read_error) {
                     (unsigned long long)offset);                  error("Couldn't read from remote file \"%s\" : %s",
                 if (atomicio(write, local_fd, data, len) != len) {                      remote_path, fx2txt(status));
                         error("Couldn't write to \"%s\": %s", local_path,                  do_close(conn, handle, handle_len);
                             strerror(errno));          } else if (write_error) {
                         do_close(fd_in, fd_out, handle, handle_len);                  error("Couldn't write to \"%s\": %s", local_path,
                         status = -1;                      strerror(write_errno));
                         xfree(data);                  status = -1;
                         goto done;                  do_close(conn, handle, handle_len);
                 }          } else {
                   status = do_close(conn, handle, handle_len);
   
                 offset += len;                  /* Override umask and utimes if asked */
                 xfree(data);                  if (pflag && fchmod(local_fd, mode) == -1)
                           error("Couldn't set mode on \"%s\": %s", local_path,
                                 strerror(errno));
                   if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
                           struct timeval tv[2];
                           tv[0].tv_sec = a->atime;
                           tv[1].tv_sec = a->mtime;
                           tv[0].tv_usec = tv[1].tv_usec = 0;
                           if (utimes(local_path, tv) == -1)
                                   error("Can't set times on \"%s\": %s",
                                         local_path, strerror(errno));
                   }
         }          }
         status = do_close(fd_in, fd_out, handle, handle_len);  
   
         /* Override umask and utimes if asked */  
         if (pflag && fchmod(local_fd, mode) == -1)  
                 error("Couldn't set mode on \"%s\": %s", local_path,  
                     strerror(errno));  
         if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {  
                 struct timeval tv[2];  
                 tv[0].tv_sec = a->atime;  
                 tv[1].tv_sec = a->mtime;  
                 tv[0].tv_usec = tv[1].tv_usec = 0;  
                 if (utimes(local_path, tv) == -1)  
                         error("Can't set times on \"%s\": %s", local_path,  
                             strerror(errno));  
         }  
   
 done:  
         close(local_fd);          close(local_fd);
         buffer_free(&msg);          buffer_free(&msg);
         xfree(handle);          xfree(handle);
         return status;  
           return(status);
 }  }
   
 int  int
 do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,  do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
     int pflag)      int pflag)
 {  {
         int local_fd;          int local_fd, status;
         u_int handle_len, id;          u_int handle_len, id, type;
         u_int64_t offset;          u_int64_t offset;
         char *handle;          char *handle, *data;
         Buffer msg;          Buffer msg;
         struct stat sb;          struct stat sb;
         Attrib a;          Attrib a;
         int status;          u_int32_t startid;
           u_int32_t ackid;
           struct outstanding_ack {
                   u_int id;
                   u_int len;
                   u_int64_t offset;
                   TAILQ_ENTRY(outstanding_ack) tq;
           };
           TAILQ_HEAD(ackhead, outstanding_ack) acks;
           struct outstanding_ack *ack;
   
           TAILQ_INIT(&acks);
   
         if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {          if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
                 error("Couldn't open local file \"%s\" for reading: %s",                  error("Couldn't open local file \"%s\" for reading: %s",
                     local_path, strerror(errno));                      local_path, strerror(errno));
Line 844 
Line 989 
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send open request */          /* Send open request */
         id = msg_id++;          id = conn->msg_id++;
         buffer_put_char(&msg, SSH2_FXP_OPEN);          buffer_put_char(&msg, SSH2_FXP_OPEN);
         buffer_put_int(&msg, id);          buffer_put_int(&msg, id);
         buffer_put_cstring(&msg, remote_path);          buffer_put_cstring(&msg, remote_path);
         buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);          buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
         encode_attrib(&msg, &a);          encode_attrib(&msg, &a);
         send_msg(fd_out, &msg);          send_msg(conn->fd_out, &msg);
         debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);          debug3("Sent message SSH2_FXP_OPEN I:%d P:%s", id, remote_path);
   
         buffer_clear(&msg);          buffer_clear(&msg);
   
         handle = get_handle(fd_in, id, &handle_len);          handle = get_handle(conn->fd_in, id, &handle_len);
         if (handle == NULL) {          if (handle == NULL) {
                 close(local_fd);                  close(local_fd);
                 buffer_free(&msg);                  buffer_free(&msg);
                 return(-1);                  return(-1);
         }          }
   
           startid = ackid = id + 1;
           data = xmalloc(conn->transfer_buflen);
   
         /* Read from local and write to remote */          /* Read from local and write to remote */
         offset = 0;          offset = 0;
         for(;;) {          for (;;) {
                 int len;                  int len;
                 char data[COPY_SIZE];  
   
                 /*                  /*
                  * Can't use atomicio here because it returns 0 on EOF, thus losing                   * Can't use atomicio here because it returns 0 on EOF, thus losing
                  * the last block of the file                   * the last block of the file
                  */                   */
                 do                  do
                         len = read(local_fd, data, COPY_SIZE);                          len = read(local_fd, data, conn->transfer_buflen);
                 while ((len == -1) && (errno == EINTR || errno == EAGAIN));                  while ((len == -1) && (errno == EINTR || errno == EAGAIN));
   
                 if (len == -1)                  if (len == -1)
                         fatal("Couldn't read from \"%s\": %s", local_path,                          fatal("Couldn't read from \"%s\": %s", local_path,
                             strerror(errno));                              strerror(errno));
                 if (len == 0)  
                   if (len != 0) {
                           ack = xmalloc(sizeof(*ack));
                           ack->id = ++id;
                           ack->offset = offset;
                           ack->len = len;
                           TAILQ_INSERT_TAIL(&acks, ack, tq);
   
                           buffer_clear(&msg);
                           buffer_put_char(&msg, SSH2_FXP_WRITE);
                           buffer_put_int(&msg, ack->id);
                           buffer_put_string(&msg, handle, handle_len);
                           buffer_put_int64(&msg, offset);
                           buffer_put_string(&msg, data, len);
                           send_msg(conn->fd_out, &msg);
                           debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",
                                  id, (u_int64_t)offset, len);
                   } else if (TAILQ_FIRST(&acks) == NULL)
                         break;                          break;
   
                 buffer_clear(&msg);                  if (ack == NULL)
                 buffer_put_char(&msg, SSH2_FXP_WRITE);                          fatal("Unexpected ACK %u", id);
                 buffer_put_int(&msg, ++id);  
                 buffer_put_string(&msg, handle, handle_len);  
                 buffer_put_int64(&msg, offset);  
                 buffer_put_string(&msg, data, len);  
                 send_msg(fd_out, &msg);  
                 debug3("Sent message SSH2_FXP_WRITE I:%d O:%llu S:%u",  
                     id, (unsigned long long)offset, len);  
   
                 status = get_status(fd_in, id);                  if (id == startid || len == 0 ||
                 if (status != SSH2_FX_OK) {                      id - ackid >= conn->num_requests) {
                         error("Couldn't write to remote file \"%s\": %s",                          buffer_clear(&msg);
                             remote_path, fx2txt(status));                          get_msg(conn->fd_in, &msg);
                         do_close(fd_in, fd_out, handle, handle_len);                          type = buffer_get_char(&msg);
                         close(local_fd);                          id = buffer_get_int(&msg);
                         goto done;  
                 }  
                 debug3("In write loop, got %d offset %llu", len,  
                     (unsigned long long)offset);  
   
                           if (type != SSH2_FXP_STATUS)
                                   fatal("Expected SSH2_FXP_STATUS(%d) packet, "
                                       "got %d", SSH2_FXP_STATUS, type);
   
                           status = buffer_get_int(&msg);
                           debug3("SSH2_FXP_STATUS %d", status);
   
                           /* Find the request in our queue */
                           for(ack = TAILQ_FIRST(&acks);
                               ack != NULL && ack->id != id;
                               ack = TAILQ_NEXT(ack, tq))
                                   ;
                           if (ack == NULL)
                                   fatal("Can't find request for ID %d", id);
                           TAILQ_REMOVE(&acks, ack, tq);
   
                           if (status != SSH2_FX_OK) {
                                   error("Couldn't write to remote file \"%s\": %s",
                                         remote_path, fx2txt(status));
                                   do_close(conn, handle, handle_len);
                                   close(local_fd);
                                   goto done;
                           }
                           debug3("In write loop, ack for %u %d bytes at %llu",
                              ack->id, ack->len, ack->offset);
                           ++ackid;
                           free(ack);
                   }
                 offset += len;                  offset += len;
         }          }
           xfree(data);
   
         if (close(local_fd) == -1) {          if (close(local_fd) == -1) {
                 error("Couldn't close local file \"%s\": %s", local_path,                  error("Couldn't close local file \"%s\": %s", local_path,
                     strerror(errno));                      strerror(errno));
                 do_close(fd_in, fd_out, handle, handle_len);                  do_close(conn, handle, handle_len);
                 status = -1;                  status = -1;
                 goto done;                  goto done;
         }          }
   
         /* Override umask and utimes if asked */          /* Override umask and utimes if asked */
         if (pflag)          if (pflag)
                 do_fsetstat(fd_in, fd_out, handle, handle_len, &a);                  do_fsetstat(conn, handle, handle_len, &a);
   
         status = do_close(fd_in, fd_out, handle, handle_len);          status = do_close(conn, handle, handle_len);
   
 done:  done:
         xfree(handle);          xfree(handle);
         buffer_free(&msg);          buffer_free(&msg);
         return status;          return(status);
 }  }
   

Legend:
Removed from v.1.18  
changed lines
  Added in v.1.18.2.1