Piotr Jurkiewicz
2016-Apr-07 01:45 UTC
[PATCH 1/2] Implement recursive upload resume support in sftp client
This patch adds support for recursive upload resume (`reput -r`, `put -a -r` commands) in sftp client. Now this combination (-a -r), despite being valid and accepted by sftp client, does not do anything useful: it always results in errors. Apparently possibility of recursive upload was overlooked when upload resume support was being implemented in 2014. I tried to make its logic similar to the already existing recursive download resume behavior, that is: when target file doesn't exists on the remote end: upload the whole file when remote file is smaller than local one: upload the remaining part when remote file size is equal the local one: skip this file when remote file is larger than local one: skip this file with an error message Signed-off-by: Piotr Jurkiewicz <piotr.jerzy.jurkiewicz at gmail.com> --- sftp-client.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/sftp-client.c b/sftp-client.c index d49bfaa..ee4d131 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1598,23 +1598,24 @@ do_upload(struct sftp_conn *conn, const char *local_path, if (!preserve_flag) a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; + offset = 0; if (resume) { /* Get remote file size if it exists */ - if ((c = do_stat(conn, remote_path, 0)) == NULL) { - close(local_fd); - return -1; - } + if ((c = do_stat(conn, remote_path, 1)) != NULL) { + if ((off_t)c->size > sb.st_size) { + error("Unable to resume upload of \"%s\": " + "remote file is larger than local", + remote_path); + close(local_fd); + return -1; + } - if ((off_t)c->size >= sb.st_size) { - error("destination file bigger or same size as " - "source file"); - close(local_fd); - return -1; - } + offset = c->size; - if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { - close(local_fd); - return -1; + if (lseek(local_fd, offset, SEEK_SET) == -1) { + close(local_fd); + return -1; + } } } @@ -1627,7 +1628,7 @@ do_upload(struct sftp_conn *conn, const char *local_path, (r = sshbuf_put_u32(msg, id)) != 0 || (r = sshbuf_put_cstring(msg, remote_path)) != 0 || (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| - (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 || + (offset > 0 ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC))) != 0 || (r = encode_attrib(msg, &a)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); send_msg(conn, msg); @@ -1647,7 +1648,7 @@ do_upload(struct sftp_conn *conn, const char *local_path, data = xmalloc(conn->transfer_buflen); /* Read from local and write to remote */ - offset = progress_counter = (resume ? c->size : 0); + progress_counter = offset; if (showprogress) start_progress_meter(local_path, sb.st_size, &progress_counter); -- 2.1.4