[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.16.2.3 and 1.17

version 1.16.2.3, 2002/06/02 22:56:11 version 1.17, 2001/06/23 15:12:20
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 2001,2002 Damien Miller.  All rights reserved.   * Copyright (c) 2001 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: remove all logging, only return status codes */  /* XXX: redesign to allow concurrent overlapped operations */
   /* 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 "ssh.h"
   
 #include "buffer.h"  #include "buffer.h"
 #include "bufaux.h"  #include "bufaux.h"
 #include "getput.h"  #include "getput.h"
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "log.h"  #include "log.h"
 #include "atomicio.h"  #include "atomicio.h"
   #include "pathnames.h"
   
 #include "sftp.h"  #include "sftp.h"
 #include "sftp-common.h"  #include "sftp-common.h"
 #include "sftp-client.h"  #include "sftp-client.h"
   
 /* Minimum amount of data to read at at time */  /* How much data to read/write at at time during copies */
 #define MIN_READ_SIZE   512  /* XXX: what should this be? */
   #define COPY_SIZE       8192
   
 struct sftp_conn {  /* Message ID */
         int fd_in;  static u_int msg_id = 1;
         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 221 
Line 217 
         return(a);          return(a);
 }  }
   
 struct sftp_conn *  int
 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests)  do_init(int fd_in, int fd_out)
 {  {
         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 242 
Line 237 
                 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(NULL);                  return(-1);
         }          }
         version = buffer_get_int(&msg);          version = buffer_get_int(&msg);
   
Line 260 
Line 255 
   
         buffer_free(&msg);          buffer_free(&msg);
   
         ret = xmalloc(sizeof(*ret));          return(version);
         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 = MIN(ret->transfer_buflen, 20480);  
   
         return(ret);  
 }  }
   
 u_int  
 sftp_proto_version(struct sftp_conn *conn)  
 {  
         return(conn->version);  
 }  
   
 int  int
 do_close(struct sftp_conn *conn, char *handle, u_int handle_len)  do_close(int fd_in, int fd_out, 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 = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(fd_out, &msg);
         debug3("Sent message SSH2_FXP_CLOSE I:%d", id);          debug3("Sent message SSH2_FXP_CLOSE I:%d", id);
   
         status = get_status(conn->fd_in, id);          status = get_status(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 307 
Line 284 
   
   
 static int  static int
 do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,  do_lsreaddir(int fd_in, int fd_out, 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 = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(fd_out, &msg);
   
         buffer_clear(&msg);          buffer_clear(&msg);
   
         handle = get_handle(conn->fd_in, id, &handle_len);          handle = get_handle(fd_in, id, &handle_len);
         if (handle == NULL)          if (handle == NULL)
                 return(-1);                  return(-1);
   
Line 333 
Line 310 
                 *dir = xmalloc(sizeof(**dir));                  *dir = xmalloc(sizeof(**dir));
                 (*dir)[0] = NULL;                  (*dir)[0] = NULL;
         }          }
   
   
         for (;;) {          for(;;) {
                 int count;                  int count;
   
                 id = expected_id = conn->msg_id++;                  id = expected_id = msg_id++;
   
                 debug3("Sending SSH2_FXP_READDIR I:%d", id);                  debug3("Sending SSH2_FXP_READDIR I:%d", id);
   
Line 345 
Line 323 
                 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(conn->fd_out, &msg);                  send_msg(fd_out, &msg);
   
                 buffer_clear(&msg);                  buffer_clear(&msg);
   
                 get_msg(conn->fd_in, &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);
Line 369 
Line 347 
                         } else {                          } else {
                                 error("Couldn't read directory: %s",                                  error("Couldn't read directory: %s",
                                     fx2txt(status));                                      fx2txt(status));
                                 do_close(conn, handle, handle_len);                                  do_close(fd_in, fd_out, handle, handle_len);
                                 return(status);                                  return(status);
                         }                          }
                 } else if (type != SSH2_FXP_NAME)                  } else if (type != SSH2_FXP_NAME)
Line 380 
Line 358 
                 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 407 
Line 385 
         }          }
   
         buffer_free(&msg);          buffer_free(&msg);
         do_close(conn, handle, handle_len);          do_close(fd_in, fd_out, handle, handle_len);
         xfree(handle);          xfree(handle);
   
         return(0);          return(0);
 }  }
   
 int  int
 do_ls(struct sftp_conn *conn, char *path)  do_ls(int fd_in, int fd_out, char *path)
 {  {
         return(do_lsreaddir(conn, path, 1, NULL));          return(do_lsreaddir(fd_in, fd_out, path, 1, NULL));
 }  }
   
 int  int
 do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)  do_readdir(int fd_in, int fd_out, char *path, SFTP_DIRENT ***dir)
 {  {
         return(do_lsreaddir(conn, path, 0, dir));          return(do_lsreaddir(fd_in, fd_out, 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 438 
Line 416 
 }  }
   
 int  int
 do_rm(struct sftp_conn *conn, char *path)  do_rm(int fd_in, int fd_out, 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 = conn->msg_id++;          id = msg_id++;
         send_string_request(conn->fd_out, id, SSH2_FXP_REMOVE, path,          send_string_request(fd_out, id, SSH2_FXP_REMOVE, path, strlen(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 delete file: %s", fx2txt(status));                  error("Couldn't delete file: %s", fx2txt(status));
         return(status);          return(status);
 }  }
   
 int  int
 do_mkdir(struct sftp_conn *conn, char *path, Attrib *a)  do_mkdir(int fd_in, int fd_out, char *path, Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = conn->msg_id++;          id = msg_id++;
         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_MKDIR, path,          send_string_attrs_request(fd_out, id, SSH2_FXP_MKDIR, path,
             strlen(path), a);              strlen(path), a);
   
         status = get_status(conn->fd_in, id);          status = get_status(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 470 
Line 447 
 }  }
   
 int  int
 do_rmdir(struct sftp_conn *conn, char *path)  do_rmdir(int fd_in, int fd_out, char *path)
 {  {
         u_int status, id;          u_int status, id;
   
         id = conn->msg_id++;          id = msg_id++;
         send_string_request(conn->fd_out, id, SSH2_FXP_RMDIR, path,          send_string_request(fd_out, id, SSH2_FXP_RMDIR, path, strlen(path));
             strlen(path));  
   
         status = get_status(conn->fd_in, id);          status = get_status(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 486 
Line 462 
 }  }
   
 Attrib *  Attrib *
 do_stat(struct sftp_conn *conn, char *path, int quiet)  do_stat(int fd_in, int fd_out, char *path, int quiet)
 {  {
         u_int id;          u_int id;
   
         id = conn->msg_id++;          id = msg_id++;
           send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
         send_string_request(conn->fd_out, id,          return(get_decode_stat(fd_in, id, quiet));
             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(struct sftp_conn *conn, char *path, int quiet)  do_lstat(int fd_in, int fd_out, char *path, int quiet)
 {  {
         u_int id;          u_int id;
   
         if (conn->version == 0) {          id = msg_id++;
                 if (quiet)          send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
                         debug("Server version does not support lstat operation");          return(get_decode_stat(fd_in, id, quiet));
                 else  
                         log("Server version does not support lstat operation");  
                 return(do_stat(conn, path, quiet));  
         }  
   
         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(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)  do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
 {  {
         u_int id;          u_int id;
   
         id = conn->msg_id++;          id = msg_id++;
         send_string_request(conn->fd_out, id, SSH2_FXP_FSTAT, handle,          send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
             handle_len);          return(get_decode_stat(fd_in, id, quiet));
   
         return(get_decode_stat(conn->fd_in, id, quiet));  
 }  }
   
 int  int
 do_setstat(struct sftp_conn *conn, char *path, Attrib *a)  do_setstat(int fd_in, int fd_out, char *path, Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = conn->msg_id++;          id = msg_id++;
         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_SETSTAT, path,          send_string_attrs_request(fd_out, id, SSH2_FXP_SETSTAT, path,
             strlen(path), a);              strlen(path), a);
   
         status = get_status(conn->fd_in, id);          status = get_status(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 549 
Line 509 
 }  }
   
 int  int
 do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,  do_fsetstat(int fd_in, int fd_out, char *handle, u_int handle_len,
     Attrib *a)      Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
         id = conn->msg_id++;          id = msg_id++;
         send_string_attrs_request(conn->fd_out, id, SSH2_FXP_FSETSTAT, handle,          send_string_attrs_request(fd_out, id, SSH2_FXP_FSETSTAT, handle,
             handle_len, a);              handle_len, a);
   
         status = get_status(conn->fd_in, id);          status = get_status(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 566 
Line 526 
 }  }
   
 char *  char *
 do_realpath(struct sftp_conn *conn, char *path)  do_realpath(int fd_in, int fd_out, 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 = conn->msg_id++;          expected_id = id = msg_id++;
         send_string_request(conn->fd_out, id, SSH2_FXP_REALPATH, path,          send_string_request(fd_out, id, SSH2_FXP_REALPATH, path, strlen(path));
             strlen(path));  
   
         buffer_init(&msg);          buffer_init(&msg);
   
         get_msg(conn->fd_in, &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);
   
Line 613 
Line 572 
 }  }
   
 int  int
 do_rename(struct sftp_conn *conn, char *oldpath, char *newpath)  do_rename(int fd_in, int fd_out, char *oldpath, char *newpath)
 {  {
         Buffer msg;          Buffer msg;
         u_int status, id;          u_int status, id;
Line 621 
Line 580 
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send rename request */          /* Send rename request */
         id = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(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(conn->fd_in, id);          status = get_status(fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,                  error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
                     newpath, fx2txt(status));                      fx2txt(status));
   
         return(status);          return(status);
 }  }
   
 int  int
 do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)  do_symlink(int fd_in, int fd_out, 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 = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(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(conn->fd_in, id);          status = get_status(fd_in, id);
         if (status != SSH2_FX_OK)          if (status != SSH2_FX_OK)
                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,                  error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, newpath,
                     newpath, fx2txt(status));                      fx2txt(status));
   
         return(status);          return(status);
 }  }
   
 char *  char *
 do_readlink(struct sftp_conn *conn, char *path)  do_readlink(int fd_in, int fd_out, 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 = conn->msg_id++;          expected_id = id = msg_id++;
         send_string_request(conn->fd_out, id, SSH2_FXP_READLINK, path,          send_string_request(fd_out, id, SSH2_FXP_READLINK, path, strlen(path));
             strlen(path));  
   
         buffer_init(&msg);          buffer_init(&msg);
   
         get_msg(conn->fd_in, &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);
   
Line 718 
Line 671 
         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(struct sftp_conn *conn, char *remote_path, char *local_path,  do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
     int pflag)      int pflag)
 {  {
         Attrib junk, *a;          int local_fd;
         Buffer msg;          u_int expected_id, handle_len, mode, type, id;
           u_int64_t offset;
         char *handle;          char *handle;
         int local_fd, status, num_req, max_req, write_error;          Buffer msg;
         int read_error, write_errno;          Attrib junk, *a;
         u_int64_t offset, size;          int status;
         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;  
   
         TAILQ_INIT(&requests);          a = do_stat(fd_in, fd_out, remote_path, 0);
   
         a = do_stat(conn, remote_path, 0);  
         if (a == NULL)          if (a == NULL)
                 return(-1);                  return(-1);
   
Line 773 
Line 699 
                 return(-1);                  return(-1);
         }          }
   
         if (a->flags & SSH2_FILEXFER_ATTR_SIZE)          local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
                 size = a->size;          if (local_fd == -1) {
         else                  error("Couldn't open local file \"%s\" for writing: %s",
                 size = 0;                      local_path, strerror(errno));
                   return(-1);
           }
   
         buflen = conn->transfer_buflen;  
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send open request */          /* Send open request */
         id = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(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(conn->fd_in, id, &handle_len);          handle = get_handle(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 */
         write_error = read_error = write_errno = num_req = offset = 0;          offset = 0;
         max_req = 1;          for(;;) {
         while (num_req > 0 || max_req > 0) {  
                 char *data;  
                 u_int len;                  u_int len;
                   char *data;
   
                 /* Send some more requests */                  id = expected_id = msg_id++;
                 while (num_req < max_req) {  
                         debug3("Request range %llu -> %llu (%d/%d)",  
                             (unsigned long long)offset,  
                             (unsigned long long)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);
                 get_msg(conn->fd_in, &msg);                  buffer_put_char(&msg, SSH2_FXP_READ);
                 type = buffer_get_char(&msg);                  buffer_put_int(&msg, id);
                 id = buffer_get_int(&msg);                  buffer_put_string(&msg, handle, handle_len);
                 debug3("Received reply T:%d I:%d R:%d", type, id, max_req);                  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);
   
                 /* Find the request in our queue */                  buffer_clear(&msg);
                 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) {                  get_msg(fd_in, &msg);
                 case SSH2_FXP_STATUS:                  type = buffer_get_char(&msg);
                   id = buffer_get_int(&msg);
                   debug3("Received reply T:%d I:%d", type, id);
                   if (id != expected_id)
                           fatal("ID mismatch (%d != %d)", id, expected_id);
                   if (type == 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",  
                             (unsigned long long)req->offset,  
                             (unsigned long long)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 (len == req->len) {                          if (status == SSH2_FX_EOF)
                                 TAILQ_REMOVE(&requests, req, tq);                                  break;
                                 xfree(req);                          else {
                                 num_req--;                                  error("Couldn't read from remote "
                         } else {                                      "file \"%s\" : %s", remote_path,
                                 /* Resend the request for the missing data */                                       fx2txt(status));
                                 debug3("Short data block, re-requesting "                                  do_close(fd_in, fd_out, handle, handle_len);
                                     "%llu -> %llu (%2d)",                                  goto done;
                                     (unsigned long long)req->offset + len,  
                                     (unsigned long long)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);  
                         }                          }
                         if (max_req > 0) { /* max_req = 0 iff EOF received */                  } else if (type != SSH2_FXP_DATA) {
                                 if (size > 0 && offset > size) {  
                                         /* Only one request at a time  
                                          * after the expected EOF */  
                                         debug3("Finish at %llu (%2d)",  
                                             (unsigned long long)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);
                 }                  }
         }  
   
         /* Sanity check */                  data = buffer_get_string(&msg, &len);
         if (TAILQ_FIRST(&requests) != NULL)                  if (len > COPY_SIZE)
                 fatal("Transfer complete, but requests still in queue");                          fatal("Received more data than asked for %d > %d",
                               len, COPY_SIZE);
   
         if (read_error) {                  debug3("In read loop, got %d offset %llu", len,
                 error("Couldn't read from remote file \"%s\" : %s",                      (unsigned long long)offset);
                     remote_path, fx2txt(status));                  if (atomicio(write, local_fd, data, len) != len) {
                 do_close(conn, handle, handle_len);                          error("Couldn't write to \"%s\": %s", local_path,
         } else if (write_error) {                              strerror(errno));
                 error("Couldn't write to \"%s\": %s", local_path,                          do_close(fd_in, fd_out, handle, handle_len);
                     strerror(write_errno));                          status = -1;
                 status = -1;                          xfree(data);
                 do_close(conn, handle, handle_len);                          goto done;
         } else {  
                 status = do_close(conn, 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));  
                 }                  }
   
                   offset += len;
                   xfree(data);
         }          }
           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(struct sftp_conn *conn, char *local_path, char *remote_path,  do_upload(int fd_in, int fd_out, char *local_path, char *remote_path,
     int pflag)      int pflag)
 {  {
         int local_fd, status;          int local_fd;
         u_int handle_len, id, type;          u_int handle_len, id;
         u_int64_t offset;          u_int64_t offset;
         char *handle, *data;          char *handle;
         Buffer msg;          Buffer msg;
         struct stat sb;          struct stat sb;
         Attrib a;          Attrib a;
         u_int32_t startid;          int status;
         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 995 
Line 846 
         buffer_init(&msg);          buffer_init(&msg);
   
         /* Send open request */          /* Send open request */
         id = conn->msg_id++;          id = 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(conn->fd_out, &msg);          send_msg(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(conn->fd_in, id, &handle_len);          handle = get_handle(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, conn->transfer_buflen);                          len = read(local_fd, data, COPY_SIZE);
                 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, (unsigned long long)offset, len);  
                 } else if (TAILQ_FIRST(&acks) == NULL)  
                         break;                          break;
   
                 if (ack == NULL)                  buffer_clear(&msg);
                         fatal("Unexpected ACK %u", id);                  buffer_put_char(&msg, SSH2_FXP_WRITE);
                   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);
   
                 if (id == startid || len == 0 ||                  status = get_status(fd_in, id);
                     id - ackid >= conn->num_requests) {                  if (status != SSH2_FX_OK) {
                         u_int r_id;                          error("Couldn't write to remote file \"%s\": %s",
                               remote_path, fx2txt(status));
                         buffer_clear(&msg);                          do_close(fd_in, fd_out, handle, handle_len);
                         get_msg(conn->fd_in, &msg);                          close(local_fd);
                         type = buffer_get_char(&msg);                          goto done;
                         r_id = buffer_get_int(&msg);  
   
                         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 != r_id;  
                             ack = TAILQ_NEXT(ack, tq))  
                                 ;  
                         if (ack == NULL)  
                                 fatal("Can't find request for ID %d", r_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, (unsigned long long)ack->offset);  
                         ++ackid;  
                         free(ack);  
                 }                  }
                   debug3("In write loop, got %d offset %llu", len,
                       (unsigned long long)offset);
   
                 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(conn, handle, handle_len);                  do_close(fd_in, fd_out, 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(conn, handle, handle_len, &a);                  do_fsetstat(fd_in, fd_out, handle, handle_len, &a);
   
         status = do_close(conn, handle, handle_len);          status = do_close(fd_in, fd_out, handle, handle_len);
   
 done:  done:
         xfree(handle);          xfree(handle);
         buffer_free(&msg);          buffer_free(&msg);
         return(status);          return status;
 }  }
   

Legend:
Removed from v.1.16.2.3  
changed lines
  Added in v.1.17