[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.172 and 1.173

version 1.172, 2023/09/08 05:50:12 version 1.173, 2023/09/08 05:56:13
Line 322 
Line 322 
         return handle;          return handle;
 }  }
   
 /* XXX returning &static is error-prone. Refactor to fill *Attrib argument */  static int
 static Attrib *  get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet, Attrib *a)
 get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)  
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int id;          u_int id;
         u_char type;          u_char type;
         int r;          int r;
         static Attrib a;          Attrib attr;
   
           if (a != NULL)
                   memset(a, '\0', sizeof(*a));
         if ((msg = sshbuf_new()) == NULL)          if ((msg = sshbuf_new()) == NULL)
                 fatal_f("sshbuf_new failed");                  fatal_f("sshbuf_new failed");
         get_msg(conn, msg);          get_msg(conn, msg);
Line 352 
Line 353 
                 else                  else
                         error("stat remote: %s", fx2txt(status));                          error("stat remote: %s", fx2txt(status));
                 sshbuf_free(msg);                  sshbuf_free(msg);
                 return(NULL);                  return -1;
         } else if (type != SSH2_FXP_ATTRS) {          } else if (type != SSH2_FXP_ATTRS) {
                 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",                  fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
                     SSH2_FXP_ATTRS, type);                      SSH2_FXP_ATTRS, type);
         }          }
         if ((r = decode_attrib(msg, &a)) != 0) {          if ((r = decode_attrib(msg, &attr)) != 0) {
                 error_fr(r, "decode_attrib");                  error_fr(r, "decode_attrib");
                 sshbuf_free(msg);                  sshbuf_free(msg);
                 return NULL;                  return -1;
         }          }
           /* success */
           if (a != NULL)
                   *a = attr;
         debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o",          debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o",
             type, id, a.flags, a.perm);              type, id, attr.flags, attr.perm);
         sshbuf_free(msg);          sshbuf_free(msg);
   
         return &a;          return 0;
 }  }
   
 static int  static int
Line 429 
Line 433 
 }  }
   
 struct sftp_conn *  struct sftp_conn *
 do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,  sftp_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
     u_int64_t limit_kbps)      u_int64_t limit_kbps)
 {  {
         u_char type;          u_char type;
Line 540 
Line 544 
         /* Query the server for its limits */          /* Query the server for its limits */
         if (ret->exts & SFTP_EXT_LIMITS) {          if (ret->exts & SFTP_EXT_LIMITS) {
                 struct sftp_limits limits;                  struct sftp_limits limits;
                 if (do_limits(ret, &limits) != 0)                  if (sftp_get_limits(ret, &limits) != 0)
                         fatal_f("limits failed");                          fatal_f("limits failed");
   
                 /* If the caller did not specify, find a good value */                  /* If the caller did not specify, find a good value */
Line 594 
Line 598 
 }  }
   
 int  int
 do_limits(struct sftp_conn *conn, struct sftp_limits *limits)  sftp_get_limits(struct sftp_conn *conn, struct sftp_limits *limits)
 {  {
         u_int id, msg_id;          u_int id, msg_id;
         u_char type;          u_char type;
Line 648 
Line 652 
 }  }
   
 int  int
 do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)  sftp_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
 {  {
         u_int id, status;          u_int id, status;
         struct sshbuf *msg;          struct sshbuf *msg;
Line 676 
Line 680 
   
   
 static int  static int
 do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,  sftp_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
     SFTP_DIRENT ***dir)      SFTP_DIRENT ***dir)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
Line 801 
Line 805 
   
  out:   out:
         sshbuf_free(msg);          sshbuf_free(msg);
         do_close(conn, handle, handle_len);          sftp_close(conn, handle, handle_len);
         free(handle);          free(handle);
   
         if (status != 0 && dir != NULL) {          if (status != 0 && dir != NULL) {
                 /* Don't return results on error */                  /* Don't return results on error */
                 free_sftp_dirents(*dir);                  sftp_free_dirents(*dir);
                 *dir = NULL;                  *dir = NULL;
         } else if (interrupted && dir != NULL && *dir != NULL) {          } else if (interrupted && dir != NULL && *dir != NULL) {
                 /* Don't return partial matches on interrupt */                  /* Don't return partial matches on interrupt */
                 free_sftp_dirents(*dir);                  sftp_free_dirents(*dir);
                 *dir = xcalloc(1, sizeof(**dir));                  *dir = xcalloc(1, sizeof(**dir));
                 **dir = NULL;                  **dir = NULL;
         }          }
Line 819 
Line 823 
 }  }
   
 int  int
 do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)  sftp_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
 {  {
         return(do_lsreaddir(conn, path, 0, dir));          return sftp_lsreaddir(conn, path, 0, dir);
 }  }
   
 void free_sftp_dirents(SFTP_DIRENT **s)  void sftp_free_dirents(SFTP_DIRENT **s)
 {  {
         int i;          int i;
   
Line 839 
Line 843 
 }  }
   
 int  int
 do_rm(struct sftp_conn *conn, const char *path)  sftp_rm(struct sftp_conn *conn, const char *path)
 {  {
         u_int status, id;          u_int status, id;
   
Line 854 
Line 858 
 }  }
   
 int  int
 do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)  sftp_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
 {  {
         u_int status, id;          u_int status, id;
   
Line 872 
Line 876 
 }  }
   
 int  int
 do_rmdir(struct sftp_conn *conn, const char *path)  sftp_rmdir(struct sftp_conn *conn, const char *path)
 {  {
         u_int status, id;          u_int status, id;
   
Line 889 
Line 893 
         return status == SSH2_FX_OK ? 0 : -1;          return status == SSH2_FX_OK ? 0 : -1;
 }  }
   
 Attrib *  int
 do_stat(struct sftp_conn *conn, const char *path, int quiet)  sftp_stat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
 {  {
         u_int id;          u_int id;
   
Line 902 
Line 906 
             conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,              conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
             path, strlen(path));              path, strlen(path));
   
         return(get_decode_stat(conn, id, quiet));          return get_decode_stat(conn, id, quiet, a);
 }  }
   
 Attrib *  int
 do_lstat(struct sftp_conn *conn, const char *path, int quiet)  sftp_lstat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
 {  {
         u_int id;          u_int id;
   
         if (conn->version == 0) {          if (conn->version == 0) {
                 if (quiet)                  do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
                         debug("Server version does not support lstat operation");                      "Server version does not support lstat operation");
                 else                  return sftp_stat(conn, path, quiet, a);
                         logit("Server version does not support lstat operation");  
                 return(do_stat(conn, path, quiet));  
         }          }
   
         id = conn->msg_id++;          id = conn->msg_id++;
         send_string_request(conn, id, SSH2_FXP_LSTAT, path,          send_string_request(conn, id, SSH2_FXP_LSTAT, path,
             strlen(path));              strlen(path));
   
         return(get_decode_stat(conn, id, quiet));          return get_decode_stat(conn, id, quiet, a);
 }  }
   
 #ifdef notyet  #ifdef notyet
 Attrib *  int
 do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,  sftp_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
     int quiet)      int quiet, Attrib *a)
 {  {
         u_int id;          u_int id;
   
Line 938 
Line 940 
         send_string_request(conn, id, SSH2_FXP_FSTAT, handle,          send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
             handle_len);              handle_len);
   
         return(get_decode_stat(conn, id, quiet));          return get_decode_stat(conn, id, quiet, a);
 }  }
 #endif  #endif
   
 int  int
 do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)  sftp_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
   
Line 961 
Line 963 
 }  }
   
 int  int
 do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,  sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
     Attrib *a)      Attrib *a)
 {  {
         u_int status, id;          u_int status, id;
Line 981 
Line 983 
   
 /* Implements both the realpath and expand-path operations */  /* Implements both the realpath and expand-path operations */
 static char *  static char *
 do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)  sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int expected_id, count, id;          u_int expected_id, count, id;
Line 1056 
Line 1058 
 }  }
   
 char *  char *
 do_realpath(struct sftp_conn *conn, const char *path)  sftp_realpath(struct sftp_conn *conn, const char *path)
 {  {
         return do_realpath_expand(conn, path, 0);          return sftp_realpath_expand(conn, path, 0);
 }  }
   
 int  int
 can_expand_path(struct sftp_conn *conn)  sftp_can_expand_path(struct sftp_conn *conn)
 {  {
         return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;          return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
 }  }
   
 char *  char *
 do_expand_path(struct sftp_conn *conn, const char *path)  sftp_expand_path(struct sftp_conn *conn, const char *path)
 {  {
         if (!can_expand_path(conn)) {          if (!sftp_can_expand_path(conn)) {
                 debug3_f("no server support, fallback to realpath");                  debug3_f("no server support, fallback to realpath");
                 return do_realpath_expand(conn, path, 0);                  return sftp_realpath_expand(conn, path, 0);
         }          }
         return do_realpath_expand(conn, path, 1);          return sftp_realpath_expand(conn, path, 1);
 }  }
   
 int  int
 do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)  sftp_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
 {  {
         Attrib junk, *a;          Attrib junk, attr;
         struct sshbuf *msg;          struct sshbuf *msg;
         u_char *old_handle, *new_handle;          u_char *old_handle, *new_handle;
         u_int mode, status, id;          u_int mode, status, id;
Line 1094 
Line 1096 
         }          }
   
         /* Make sure the file exists, and we can copy its perms */          /* Make sure the file exists, and we can copy its perms */
         if ((a = do_stat(conn, oldpath, 0)) == NULL)          if (sftp_stat(conn, oldpath, 0, &attr) != 0)
                 return -1;                  return -1;
   
         /* Do not preserve set[ug]id here, as we do not preserve ownership */          /* Do not preserve set[ug]id here, as we do not preserve ownership */
         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {          if (attr.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
                 mode = a->perm & 0777;                  mode = attr.perm & 0777;
   
                 if (!S_ISREG(a->perm)) {                  if (!S_ISREG(attr.perm)) {
                         error("Cannot copy non-regular file: %s", oldpath);                          error("Cannot copy non-regular file: %s", oldpath);
                         return -1;                          return -1;
                 }                  }
Line 1111 
Line 1113 
         }          }
   
         /* Set up the new perms for the new file */          /* Set up the new perms for the new file */
         attrib_clear(a);          attrib_clear(&attr);
         a->perm = mode;          attr.perm = mode;
         a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;          attr.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
   
         if ((msg = sshbuf_new()) == NULL)          if ((msg = sshbuf_new()) == NULL)
                 fatal("%s: sshbuf_new failed", __func__);                  fatal("%s: sshbuf_new failed", __func__);
Line 1147 
Line 1149 
             (r = sshbuf_put_cstring(msg, newpath)) != 0 ||              (r = sshbuf_put_cstring(msg, newpath)) != 0 ||
             (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|              (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
             SSH2_FXF_TRUNC)) != 0 ||              SSH2_FXF_TRUNC)) != 0 ||
             (r = encode_attrib(msg, a)) != 0)              (r = encode_attrib(msg, &attr)) != 0)
                 fatal("%s: buffer error: %s", __func__, ssh_err(r));                  fatal("%s: buffer error: %s", __func__, ssh_err(r));
         send_msg(conn, msg);          send_msg(conn, msg);
         debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath);          debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath);
Line 1184 
Line 1186 
   
         /* Clean up everything */          /* Clean up everything */
         sshbuf_free(msg);          sshbuf_free(msg);
         do_close(conn, old_handle, old_handle_len);          sftp_close(conn, old_handle, old_handle_len);
         do_close(conn, new_handle, new_handle_len);          sftp_close(conn, new_handle, new_handle_len);
         free(old_handle);          free(old_handle);
         free(new_handle);          free(new_handle);
   
Line 1193 
Line 1195 
 }  }
   
 int  int
 do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,  sftp_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
     int force_legacy)      int force_legacy)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
Line 1238 
Line 1240 
 }  }
   
 int  int
 do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)  sftp_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int status, id;          u_int status, id;
Line 1276 
Line 1278 
 }  }
   
 int  int
 do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)  sftp_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int status, id;          u_int status, id;
Line 1312 
Line 1314 
 }  }
   
 int  int
 do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)  sftp_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int status, id;          u_int status, id;
Line 1345 
Line 1347 
   
 #ifdef notyet  #ifdef notyet
 char *  char *
 do_readlink(struct sftp_conn *conn, const char *path)  sftp_readlink(struct sftp_conn *conn, const char *path)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int expected_id, count, id;          u_int expected_id, count, id;
Line 1403 
Line 1405 
 #endif  #endif
   
 int  int
 do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,  sftp_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
     int quiet)      int quiet)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
Line 1434 
Line 1436 
   
 #ifdef notyet  #ifdef notyet
 int  int
 do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,  sftp_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
     struct sftp_statvfs *st, int quiet)      struct sftp_statvfs *st, int quiet)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
Line 1464 
Line 1466 
 #endif  #endif
   
 int  int
 do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)  sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
 {  {
         struct sshbuf *msg;          struct sshbuf *msg;
         u_int status, id;          u_int status, id;
Line 1572 
Line 1574 
 }  }
   
 int  int
 do_download(struct sftp_conn *conn, const char *remote_path,  sftp_download(struct sftp_conn *conn, const char *remote_path,
     const char *local_path, Attrib *a, int preserve_flag, int resume_flag,      const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
     int fsync_flag, int inplace_flag)      int fsync_flag, int inplace_flag)
 {  {
Line 1588 
Line 1590 
         struct requests requests;          struct requests requests;
         struct request *req;          struct request *req;
         u_char type;          u_char type;
           Attrib attr;
   
         debug2_f("download remote \"%s\" to local \"%s\"",          debug2_f("download remote \"%s\" to local \"%s\"",
             remote_path, local_path);              remote_path, local_path);
   
         TAILQ_INIT(&requests);          TAILQ_INIT(&requests);
   
         if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)          if (a == NULL) {
                 return -1;                  if (sftp_stat(conn, remote_path, 0, &attr) != 0)
                           return -1;
                   a = &attr;
           }
   
         /* Do not preserve set[ug]id here, as we do not preserve ownership */          /* Do not preserve set[ug]id here, as we do not preserve ownership */
         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)          if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
Line 1641 
Line 1647 
                         error("Unable to resume download of \"%s\": "                          error("Unable to resume download of \"%s\": "
                             "local file is larger than remote", local_path);                              "local file is larger than remote", local_path);
  fail:   fail:
                         do_close(conn, handle, handle_len);                          sftp_close(conn, handle, handle_len);
                         free(handle);                          free(handle);
                         if (local_fd != -1)                          if (local_fd != -1)
                                 close(local_fd);                                  close(local_fd);
Line 1816 
Line 1822 
         if (read_error) {          if (read_error) {
                 error("read remote \"%s\" : %s", remote_path, fx2txt(status));                  error("read remote \"%s\" : %s", remote_path, fx2txt(status));
                 status = -1;                  status = -1;
                 do_close(conn, handle, handle_len);                  sftp_close(conn, handle, handle_len);
         } else if (write_error) {          } else if (write_error) {
                 error("write local \"%s\": %s", local_path,                  error("write local \"%s\": %s", local_path,
                     strerror(write_errno));                      strerror(write_errno));
                 status = SSH2_FX_FAILURE;                  status = SSH2_FX_FAILURE;
                 do_close(conn, handle, handle_len);                  sftp_close(conn, handle, handle_len);
         } else {          } else {
                 if (do_close(conn, handle, handle_len) != 0 || interrupted)                  if (sftp_close(conn, handle, handle_len) != 0 || interrupted)
                         status = SSH2_FX_FAILURE;                          status = SSH2_FX_FAILURE;
                 else                  else
                         status = SSH2_FX_OK;                          status = SSH2_FX_OK;
Line 1876 
Line 1882 
         debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst);          debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst);
   
         if (dirattrib == NULL) {          if (dirattrib == NULL) {
                 if ((a = do_stat(conn, src, 1)) == NULL) {                  if (sftp_stat(conn, src, 1, &ldirattrib) != 0) {
                         error("stat remote \"%s\" directory failed", src);                          error("stat remote \"%s\" directory failed", src);
                         return -1;                          return -1;
                 }                  }
                 /* Don't let this be clobbered by later do_stat calls */  
                 ldirattrib = *a;  
                 dirattrib = &ldirattrib;                  dirattrib = &ldirattrib;
         }          }
         if (!S_ISDIR(dirattrib->perm)) {          if (!S_ISDIR(dirattrib->perm)) {
Line 1904 
Line 1908 
                 return -1;                  return -1;
         }          }
   
         if (do_readdir(conn, src, &dir_entries) == -1) {          if (sftp_readdir(conn, src, &dir_entries) == -1) {
                 error("remote readdir \"%s\" failed", src);                  error("remote readdir \"%s\" failed", src);
                 return -1;                  return -1;
         }          }
Line 1914 
Line 1918 
                 free(new_src);                  free(new_src);
   
                 filename = dir_entries[i]->filename;                  filename = dir_entries[i]->filename;
                 new_dst = path_append(dst, filename);                  new_dst = sftp_path_append(dst, filename);
                 new_src = path_append(src, filename);                  new_src = sftp_path_append(src, filename);
   
                 a = &dir_entries[i]->a;                  a = &dir_entries[i]->a;
                 if (S_ISLNK(a->perm)) {                  if (S_ISLNK(a->perm)) {
Line 1925 
Line 1929 
                                 continue;                                  continue;
                         }                          }
                         /* Replace the stat contents with the symlink target */                          /* Replace the stat contents with the symlink target */
                         if ((a = do_stat(conn, new_src, 1)) == NULL) {                          if (sftp_stat(conn, new_src, 1, &lsym) != 0) {
                                 logit("remote stat \"%s\" failed", new_src);                                  logit("remote stat \"%s\" failed", new_src);
                                 ret = -1;                                  ret = -1;
                                 continue;                                  continue;
                         }                          }
                         /* Don't let this be clobbered by later do_stat calls */  
                         lsym = *a;  
                         a = &lsym;                          a = &lsym;
                 }                  }
   
Line 1945 
Line 1947 
                             fsync_flag, follow_link_flag, inplace_flag) == -1)                              fsync_flag, follow_link_flag, inplace_flag) == -1)
                                 ret = -1;                                  ret = -1;
                 } else if (S_ISREG(a->perm)) {                  } else if (S_ISREG(a->perm)) {
                         if (do_download(conn, new_src, new_dst, a,                          if (sftp_download(conn, new_src, new_dst, a,
                             preserve_flag, resume_flag, fsync_flag,                              preserve_flag, resume_flag, fsync_flag,
                             inplace_flag) == -1) {                              inplace_flag) == -1) {
                                 error("Download of file %s to %s failed",                                  error("Download of file %s to %s failed",
Line 1977 
Line 1979 
                 error("local chmod directory \"%s\": %s", dst,                  error("local chmod directory \"%s\": %s", dst,
                     strerror(errno));                      strerror(errno));
   
         free_sftp_dirents(dir_entries);          sftp_free_dirents(dir_entries);
   
         return ret;          return ret;
 }  }
   
 int  int
 download_dir(struct sftp_conn *conn, const char *src, const char *dst,  sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst,
     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,      Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
     int fsync_flag, int follow_link_flag, int inplace_flag)      int fsync_flag, int follow_link_flag, int inplace_flag)
 {  {
         char *src_canon;          char *src_canon;
         int ret;          int ret;
   
         if ((src_canon = do_realpath(conn, src)) == NULL) {          if ((src_canon = sftp_realpath(conn, src)) == NULL) {
                 error("download \"%s\": path canonicalization failed", src);                  error("download \"%s\": path canonicalization failed", src);
                 return -1;                  return -1;
         }          }
Line 2003 
Line 2005 
 }  }
   
 int  int
 do_upload(struct sftp_conn *conn, const char *local_path,  sftp_upload(struct sftp_conn *conn, const char *local_path,
     const char *remote_path, int preserve_flag, int resume,      const char *remote_path, int preserve_flag, int resume,
     int fsync_flag, int inplace_flag)      int fsync_flag, int inplace_flag)
 {  {
Line 2013 
Line 2015 
         u_char type, *handle, *data;          u_char type, *handle, *data;
         struct sshbuf *msg;          struct sshbuf *msg;
         struct stat sb;          struct stat sb;
         Attrib a, t, *c = NULL;          Attrib a, t, c;
         u_int32_t startid, ackid;          u_int32_t startid, ackid;
         u_int64_t highwater = 0, maxack = 0;          u_int64_t highwater = 0, maxack = 0;
         struct request *ack = NULL;          struct request *ack = NULL;
Line 2049 
Line 2051 
   
         if (resume) {          if (resume) {
                 /* Get remote file size if it exists */                  /* Get remote file size if it exists */
                 if ((c = do_stat(conn, remote_path, 0)) == NULL) {                  if (sftp_stat(conn, remote_path, 0, &c) != 0) {
                         close(local_fd);                          close(local_fd);
                         return -1;                          return -1;
                 }                  }
   
                 if ((off_t)c->size >= sb.st_size) {                  if ((off_t)c.size >= sb.st_size) {
                         error("resume \"%s\": destination file "                          error("resume \"%s\": destination file "
                             "same size or larger", local_path);                              "same size or larger", local_path);
                         close(local_fd);                          close(local_fd);
                         return -1;                          return -1;
                 }                  }
   
                 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {                  if (lseek(local_fd, (off_t)c.size, SEEK_SET) == -1) {
                         close(local_fd);                          close(local_fd);
                         return -1;                          return -1;
                 }                  }
Line 2085 
Line 2087 
         data = xmalloc(conn->upload_buflen);          data = xmalloc(conn->upload_buflen);
   
         /* Read from local and write to remote */          /* Read from local and write to remote */
         offset = progress_counter = (resume ? c->size : 0);          offset = progress_counter = (resume ? c.size : 0);
         if (showprogress) {          if (showprogress) {
                 start_progress_meter(progress_meter_path(local_path),                  start_progress_meter(progress_meter_path(local_path),
                     sb.st_size, &progress_counter);                      sb.st_size, &progress_counter);
Line 2196 
Line 2198 
                 attrib_clear(&t);                  attrib_clear(&t);
                 t.flags = SSH2_FILEXFER_ATTR_SIZE;                  t.flags = SSH2_FILEXFER_ATTR_SIZE;
                 t.size = highwater;                  t.size = highwater;
                 do_fsetstat(conn, handle, handle_len, &t);                  sftp_fsetstat(conn, handle, handle_len, &t);
         }          }
   
         if (close(local_fd) == -1) {          if (close(local_fd) == -1) {
Line 2206 
Line 2208 
   
         /* Override umask and utimes if asked */          /* Override umask and utimes if asked */
         if (preserve_flag)          if (preserve_flag)
                 do_fsetstat(conn, handle, handle_len, &a);                  sftp_fsetstat(conn, handle, handle_len, &a);
   
         if (fsync_flag)          if (fsync_flag)
                 (void)do_fsync(conn, handle, handle_len);                  (void)sftp_fsync(conn, handle, handle_len);
   
         if (do_close(conn, handle, handle_len) != 0)          if (sftp_close(conn, handle, handle_len) != 0)
                 status = SSH2_FX_FAILURE;                  status = SSH2_FX_FAILURE;
   
         free(handle);          free(handle);
Line 2229 
Line 2231 
         struct dirent *dp;          struct dirent *dp;
         char *filename, *new_src = NULL, *new_dst = NULL;          char *filename, *new_src = NULL, *new_dst = NULL;
         struct stat sb;          struct stat sb;
         Attrib a, *dirattrib;          Attrib a, dirattrib;
         u_int32_t saved_perm;          u_int32_t saved_perm;
   
         debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst);          debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst);
Line 2265 
Line 2267 
          */           */
         saved_perm = a.perm;          saved_perm = a.perm;
         a.perm |= (S_IWUSR|S_IXUSR);          a.perm |= (S_IWUSR|S_IXUSR);
         if (do_mkdir(conn, dst, &a, 0) != 0) {          if (sftp_mkdir(conn, dst, &a, 0) != 0) {
                 if ((dirattrib = do_stat(conn, dst, 0)) == NULL)                  if (sftp_stat(conn, dst, 0, &dirattrib) != 0)
                         return -1;                          return -1;
                 if (!S_ISDIR(dirattrib->perm)) {                  if (!S_ISDIR(dirattrib.perm)) {
                         error("\"%s\" exists but is not a directory", dst);                          error("\"%s\" exists but is not a directory", dst);
                         return -1;                          return -1;
                 }                  }
Line 2286 
Line 2288 
                 free(new_dst);                  free(new_dst);
                 free(new_src);                  free(new_src);
                 filename = dp->d_name;                  filename = dp->d_name;
                 new_dst = path_append(dst, filename);                  new_dst = sftp_path_append(dst, filename);
                 new_src = path_append(src, filename);                  new_src = sftp_path_append(src, filename);
   
                 if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)                  if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
                         continue;                          continue;
Line 2316 
Line 2318 
                             fsync_flag, follow_link_flag, inplace_flag) == -1)                              fsync_flag, follow_link_flag, inplace_flag) == -1)
                                 ret = -1;                                  ret = -1;
                 } else if (S_ISREG(sb.st_mode)) {                  } else if (S_ISREG(sb.st_mode)) {
                         if (do_upload(conn, new_src, new_dst,                          if (sftp_upload(conn, new_src, new_dst,
                             preserve_flag, resume, fsync_flag,                              preserve_flag, resume, fsync_flag,
                             inplace_flag) == -1) {                              inplace_flag) == -1) {
                                 error("upload \"%s\" to \"%s\" failed",                                  error("upload \"%s\" to \"%s\" failed",
Line 2329 
Line 2331 
         free(new_dst);          free(new_dst);
         free(new_src);          free(new_src);
   
         do_setstat(conn, dst, &a);          sftp_setstat(conn, dst, &a);
   
         (void) closedir(dirp);          (void) closedir(dirp);
         return ret;          return ret;
 }  }
   
 int  int
 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,  sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
     int preserve_flag, int print_flag, int resume, int fsync_flag,      int preserve_flag, int print_flag, int resume, int fsync_flag,
     int follow_link_flag, int inplace_flag)      int follow_link_flag, int inplace_flag)
 {  {
         char *dst_canon;          char *dst_canon;
         int ret;          int ret;
   
         if ((dst_canon = do_realpath(conn, dst)) == NULL) {          if ((dst_canon = sftp_realpath(conn, dst)) == NULL) {
                 error("upload \"%s\": path canonicalization failed", dst);                  error("upload \"%s\": path canonicalization failed", dst);
                 return -1;                  return -1;
         }          }
Line 2402 
Line 2404 
                                 *write_errorp = status;                                  *write_errorp = status;
                 }                  }
                 /*                  /*
                  * XXX this doesn't do full reply matching like do_upload and                   * XXX this doesn't do full reply matching like sftp_upload and
                  * so cannot gracefully truncate terminated uploads at a                   * so cannot gracefully truncate terminated uploads at a
                  * high-water mark. ATM the only caller of this function (scp)                   * high-water mark. ATM the only caller of this function (scp)
                  * doesn't support transfer resumption, so this doesn't matter                   * doesn't support transfer resumption, so this doesn't matter
                  * a whole lot.                   * a whole lot.
                  *                   *
                  * To be safe, do_crossload truncates the destination file to                   * To be safe, sftp_crossload truncates the destination file to
                  * zero length on upload failure, since we can't trust the                   * zero length on upload failure, since we can't trust the
                  * server not to have reordered replies that could have                   * server not to have reordered replies that could have
                  * inserted holes where none existed in the source file.                   * inserted holes where none existed in the source file.
Line 2423 
Line 2425 
 }  }
   
 int  int
 do_crossload(struct sftp_conn *from, struct sftp_conn *to,  sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
     const char *from_path, const char *to_path,      const char *from_path, const char *to_path,
     Attrib *a, int preserve_flag)      Attrib *a, int preserve_flag)
 {  {
Line 2438 
Line 2440 
         struct requests requests;          struct requests requests;
         struct request *req;          struct request *req;
         u_char type;          u_char type;
           Attrib attr;
   
         debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);          debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);
   
         TAILQ_INIT(&requests);          TAILQ_INIT(&requests);
   
         if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL)          if (a == NULL) {
                 return -1;                  if (sftp_stat(from, from_path, 0, &attr) != 0)
                           return -1;
                   a = &attr;
           }
   
         if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&          if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
             (!S_ISREG(a->perm))) {              (!S_ISREG(a->perm))) {
Line 2474 
Line 2480 
         if (send_open(to, to_path, "dest",          if (send_open(to, to_path, "dest",
             SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,              SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
             &to_handle, &to_handle_len) != 0) {              &to_handle, &to_handle_len) != 0) {
                 do_close(from, from_handle, from_handle_len);                  sftp_close(from, from_handle, from_handle_len);
                 return -1;                  return -1;
         }          }
   
Line 2624 
Line 2630 
         /* Truncate at 0 length on interrupt or error to avoid holes at dest */          /* Truncate at 0 length on interrupt or error to avoid holes at dest */
         if (read_error || write_error || interrupted) {          if (read_error || write_error || interrupted) {
                 debug("truncating \"%s\" at 0", to_path);                  debug("truncating \"%s\" at 0", to_path);
                 do_close(to, to_handle, to_handle_len);                  sftp_close(to, to_handle, to_handle_len);
                 free(to_handle);                  free(to_handle);
                 if (send_open(to, to_path, "dest",                  if (send_open(to, to_path, "dest",
                     SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,                      SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
Line 2636 
Line 2642 
         if (read_error) {          if (read_error) {
                 error("read origin \"%s\": %s", from_path, fx2txt(status));                  error("read origin \"%s\": %s", from_path, fx2txt(status));
                 status = -1;                  status = -1;
                 do_close(from, from_handle, from_handle_len);                  sftp_close(from, from_handle, from_handle_len);
                 if (to_handle != NULL)                  if (to_handle != NULL)
                         do_close(to, to_handle, to_handle_len);                          sftp_close(to, to_handle, to_handle_len);
         } else if (write_error) {          } else if (write_error) {
                 error("write dest \"%s\": %s", to_path, fx2txt(write_error));                  error("write dest \"%s\": %s", to_path, fx2txt(write_error));
                 status = SSH2_FX_FAILURE;                  status = SSH2_FX_FAILURE;
                 do_close(from, from_handle, from_handle_len);                  sftp_close(from, from_handle, from_handle_len);
                 if (to_handle != NULL)                  if (to_handle != NULL)
                         do_close(to, to_handle, to_handle_len);                          sftp_close(to, to_handle, to_handle_len);
         } else {          } else {
                 if (do_close(from, from_handle, from_handle_len) != 0 ||                  if (sftp_close(from, from_handle, from_handle_len) != 0 ||
                     interrupted)                      interrupted)
                         status = -1;                          status = -1;
                 else                  else
Line 2654 
Line 2660 
                 if (to_handle != NULL) {                  if (to_handle != NULL) {
                         /* Need to resend utimes after write */                          /* Need to resend utimes after write */
                         if (preserve_flag)                          if (preserve_flag)
                                 do_fsetstat(to, to_handle, to_handle_len, a);                                  sftp_fsetstat(to, to_handle, to_handle_len, a);
                         do_close(to, to_handle, to_handle_len);                          sftp_close(to, to_handle, to_handle_len);
                 }                  }
         }          }
         sshbuf_free(msg);          sshbuf_free(msg);
Line 2675 
Line 2681 
         SFTP_DIRENT **dir_entries;          SFTP_DIRENT **dir_entries;
         char *filename, *new_from_path = NULL, *new_to_path = NULL;          char *filename, *new_from_path = NULL, *new_to_path = NULL;
         mode_t mode = 0777;          mode_t mode = 0777;
         Attrib curdir;          Attrib curdir, ldirattrib, newdir;
   
         debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path);          debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path);
   
Line 2684 
Line 2690 
                 return -1;                  return -1;
         }          }
   
         if (dirattrib == NULL &&          if (dirattrib == NULL) {
             (dirattrib = do_stat(from, from_path, 1)) == NULL) {                  if (sftp_stat(from, from_path, 1, &ldirattrib) != 0) {
                 error("stat remote \"%s\" failed", from_path);                          error("stat remote \"%s\" failed", from_path);
                 return -1;                          return -1;
                   }
                   dirattrib = &ldirattrib;
         }          }
         if (!S_ISDIR(dirattrib->perm)) {          if (!S_ISDIR(dirattrib->perm)) {
                 error("\"%s\" is not a directory", from_path);                  error("\"%s\" is not a directory", from_path);
Line 2715 
Line 2723 
          * the path already existed and is a directory.  Ensure we can           * the path already existed and is a directory.  Ensure we can
          * write to the directory we create for the duration of the transfer.           * write to the directory we create for the duration of the transfer.
          */           */
         if (do_mkdir(to, to_path, &curdir, 0) != 0) {          if (sftp_mkdir(to, to_path, &curdir, 0) != 0) {
                 if ((dirattrib = do_stat(to, to_path, 0)) == NULL)                  if (sftp_stat(to, to_path, 0, &newdir) != 0)
                         return -1;                          return -1;
                 if (!S_ISDIR(dirattrib->perm)) {                  if (!S_ISDIR(newdir.perm)) {
                         error("\"%s\" exists but is not a directory", to_path);                          error("\"%s\" exists but is not a directory", to_path);
                         return -1;                          return -1;
                 }                  }
         }          }
         curdir.perm = mode;          curdir.perm = mode;
   
         if (do_readdir(from, from_path, &dir_entries) == -1) {          if (sftp_readdir(from, from_path, &dir_entries) == -1) {
                 error("origin readdir \"%s\" failed", from_path);                  error("origin readdir \"%s\" failed", from_path);
                 return -1;                  return -1;
         }          }
Line 2735 
Line 2743 
                 free(new_to_path);                  free(new_to_path);
   
                 filename = dir_entries[i]->filename;                  filename = dir_entries[i]->filename;
                 new_from_path = path_append(from_path, filename);                  new_from_path = sftp_path_append(from_path, filename);
                 new_to_path = path_append(to_path, filename);                  new_to_path = sftp_path_append(to_path, filename);
   
                 if (S_ISDIR(dir_entries[i]->a.perm)) {                  if (S_ISDIR(dir_entries[i]->a.perm)) {
                         if (strcmp(filename, ".") == 0 ||                          if (strcmp(filename, ".") == 0 ||
Line 2751 
Line 2759 
                     (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {                      (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
                         /*                          /*
                          * If this is a symlink then don't send the link's                           * If this is a symlink then don't send the link's
                          * Attrib. do_download() will do a FXP_STAT operation                           * Attrib. sftp_download() will do a FXP_STAT operation
                          * and get the link target's attributes.                           * and get the link target's attributes.
                          */                           */
                         if (do_crossload(from, to, new_from_path, new_to_path,                          if (sftp_crossload(from, to, new_from_path, new_to_path,
                             S_ISLNK(dir_entries[i]->a.perm) ? NULL :                              S_ISLNK(dir_entries[i]->a.perm) ? NULL :
                             &(dir_entries[i]->a), preserve_flag) == -1) {                              &(dir_entries[i]->a), preserve_flag) == -1) {
                                 error("crossload \"%s\" to \"%s\" failed",                                  error("crossload \"%s\" to \"%s\" failed",
Line 2769 
Line 2777 
         free(new_to_path);          free(new_to_path);
         free(new_from_path);          free(new_from_path);
   
         do_setstat(to, to_path, &curdir);          sftp_setstat(to, to_path, &curdir);
   
         free_sftp_dirents(dir_entries);          sftp_free_dirents(dir_entries);
   
         return ret;          return ret;
 }  }
   
 int  int
 crossload_dir(struct sftp_conn *from, struct sftp_conn *to,  sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
     const char *from_path, const char *to_path,      const char *from_path, const char *to_path,
     Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)      Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
 {  {
         char *from_path_canon;          char *from_path_canon;
         int ret;          int ret;
   
         if ((from_path_canon = do_realpath(from, from_path)) == NULL) {          if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) {
                 error("crossload \"%s\": path canonicalization failed",                  error("crossload \"%s\": path canonicalization failed",
                     from_path);                      from_path);
                 return -1;                  return -1;
Line 2797 
Line 2805 
 }  }
   
 int  int
 can_get_users_groups_by_id(struct sftp_conn *conn)  sftp_can_get_users_groups_by_id(struct sftp_conn *conn)
 {  {
         return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0;          return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0;
 }  }
   
 int  int
 do_get_users_groups_by_id(struct sftp_conn *conn,  sftp_get_users_groups_by_id(struct sftp_conn *conn,
     const u_int *uids, u_int nuids,      const u_int *uids, u_int nuids,
     const u_int *gids, u_int ngids,      const u_int *gids, u_int ngids,
     char ***usernamesp, char ***groupnamesp)      char ***usernamesp, char ***groupnamesp)
Line 2815 
Line 2823 
         int r;          int r;
   
         *usernamesp = *groupnamesp = NULL;          *usernamesp = *groupnamesp = NULL;
         if (!can_get_users_groups_by_id(conn))          if (!sftp_can_get_users_groups_by_id(conn))
                 return SSH_ERR_FEATURE_UNSUPPORTED;                  return SSH_ERR_FEATURE_UNSUPPORTED;
   
         if ((msg = sshbuf_new()) == NULL ||          if ((msg = sshbuf_new()) == NULL ||
Line 2911 
Line 2919 
 }  }
   
 char *  char *
 path_append(const char *p1, const char *p2)  sftp_path_append(const char *p1, const char *p2)
 {  {
         char *ret;          char *ret;
         size_t len = strlen(p1) + strlen(p2) + 2;          size_t len = strlen(p1) + strlen(p2) + 2;
Line 2930 
Line 2938 
  * freed and a replacement allocated.  Caller must free returned string.   * freed and a replacement allocated.  Caller must free returned string.
  */   */
 char *  char *
 make_absolute(char *p, const char *pwd)  sftp_make_absolute(char *p, const char *pwd)
 {  {
         char *abs_str;          char *abs_str;
   
         /* Derelativise */          /* Derelativise */
         if (p && !path_absolute(p)) {          if (p && !path_absolute(p)) {
                 abs_str = path_append(pwd, p);                  abs_str = sftp_path_append(pwd, p);
                 free(p);                  free(p);
                 return(abs_str);                  return(abs_str);
         } else          } else
Line 2944 
Line 2952 
 }  }
   
 int  int
 remote_is_dir(struct sftp_conn *conn, const char *path)  sftp_remote_is_dir(struct sftp_conn *conn, const char *path)
 {  {
         Attrib *a;          Attrib a;
   
         /* XXX: report errors? */          /* XXX: report errors? */
         if ((a = do_stat(conn, path, 1)) == NULL)          if (sftp_stat(conn, path, 1, &a) != 0)
                 return(0);                  return(0);
         if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))          if (!(a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
                 return(0);                  return(0);
         return(S_ISDIR(a->perm));          return S_ISDIR(a.perm);
 }  }
   
   
 int  
 local_is_dir(const char *path)  
 {  
         struct stat sb;  
   
         /* XXX: report errors? */  
         if (stat(path, &sb) == -1)  
                 return(0);  
   
         return(S_ISDIR(sb.st_mode));  
 }  
   
 /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */  /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
 int  int
 globpath_is_dir(const char *pathname)  sftp_globpath_is_dir(const char *pathname)
 {  {
         size_t l = strlen(pathname);          size_t l = strlen(pathname);
   

Legend:
Removed from v.1.172  
changed lines
  Added in v.1.173