[PATCH 1/2] Implement recursive upload resume support in sftp client

Piotr Jurkiewicz piotr.jerzy.jurkiewicz at gmail.com
Thu Apr 7 11:45:48 AEST 2016


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



More information about the openssh-unix-dev mailing list