summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2014-05-15 13:46:25 +1000
committerDamien Miller <djm@mindrot.org>2014-05-15 13:46:25 +1000
commitd8accc0aa72656ba63d50937165c5ae49db1dcd6 (patch)
tree95e22a55fc9c75952f3fdc684cd96b8c0538871d
parent16cd3928a87d20c77b13592a74b60b08621d3ce6 (diff)
- logan@cvs.openbsd.org 2014/04/21 14:36:16
[sftp-client.c sftp-client.h sftp.c] Implement sftp upload resume support. OK from djm@, with input from guenther@, mlarkin@ and okan@
-rw-r--r--ChangeLog5
-rw-r--r--sftp-client.c41
-rw-r--r--sftp-client.h6
-rw-r--r--sftp.c38
4 files changed, 62 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index ff9c3cb46..011e8f995 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,11 @@
6 [dns.c dns.h ssh-keygen.c] 6 [dns.c dns.h ssh-keygen.c]
7 Add support for SSHFP DNS records for ED25519 key types. 7 Add support for SSHFP DNS records for ED25519 key types.
8 OK from djm@ 8 OK from djm@
9 - logan@cvs.openbsd.org 2014/04/21 14:36:16
10 [sftp-client.c sftp-client.h sftp.c]
11 Implement sftp upload resume support.
12 OK from djm@, with input from guenther@, mlarkin@ and
13 okan@
9 14
1020140430 1520140430
11 - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already 16 - (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already
diff --git a/sftp-client.c b/sftp-client.c
index 2f5907c85..990b58d14 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.c,v 1.114 2014/01/31 16:39:19 tedu Exp $ */ 1/* $OpenBSD: sftp-client.c,v 1.115 2014/04/21 14:36:16 logan Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -1420,7 +1420,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst,
1420 1420
1421int 1421int
1422do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1422do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1423 int preserve_flag, int fsync_flag) 1423 int preserve_flag, int resume, int fsync_flag)
1424{ 1424{
1425 int local_fd; 1425 int local_fd;
1426 int status = SSH2_FX_OK; 1426 int status = SSH2_FX_OK;
@@ -1429,7 +1429,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1429 char *handle, *data; 1429 char *handle, *data;
1430 Buffer msg; 1430 Buffer msg;
1431 struct stat sb; 1431 struct stat sb;
1432 Attrib a; 1432 Attrib a, *c = NULL;
1433 u_int32_t startid; 1433 u_int32_t startid;
1434 u_int32_t ackid; 1434 u_int32_t ackid;
1435 struct outstanding_ack { 1435 struct outstanding_ack {
@@ -1467,6 +1467,26 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1467 if (!preserve_flag) 1467 if (!preserve_flag)
1468 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1468 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1469 1469
1470 if (resume) {
1471 /* Get remote file size if it exists */
1472 if ((c = do_stat(conn, remote_path, 0)) == NULL) {
1473 close(local_fd);
1474 return -1;
1475 }
1476
1477 if ((off_t)c->size >= sb.st_size) {
1478 error("destination file bigger or same size as "
1479 "source file");
1480 close(local_fd);
1481 return -1;
1482 }
1483
1484 if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
1485 close(local_fd);
1486 return -1;
1487 }
1488 }
1489
1470 buffer_init(&msg); 1490 buffer_init(&msg);
1471 1491
1472 /* Send open request */ 1492 /* Send open request */
@@ -1474,7 +1494,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1474 buffer_put_char(&msg, SSH2_FXP_OPEN); 1494 buffer_put_char(&msg, SSH2_FXP_OPEN);
1475 buffer_put_int(&msg, id); 1495 buffer_put_int(&msg, id);
1476 buffer_put_cstring(&msg, remote_path); 1496 buffer_put_cstring(&msg, remote_path);
1477 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 1497 buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
1498 (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC));
1478 encode_attrib(&msg, &a); 1499 encode_attrib(&msg, &a);
1479 send_msg(conn, &msg); 1500 send_msg(conn, &msg);
1480 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 1501 debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
@@ -1493,7 +1514,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1493 data = xmalloc(conn->transfer_buflen); 1514 data = xmalloc(conn->transfer_buflen);
1494 1515
1495 /* Read from local and write to remote */ 1516 /* Read from local and write to remote */
1496 offset = progress_counter = 0; 1517 offset = progress_counter = (resume ? c->size : 0);
1497 if (showprogress) 1518 if (showprogress)
1498 start_progress_meter(local_path, sb.st_size, 1519 start_progress_meter(local_path, sb.st_size,
1499 &progress_counter); 1520 &progress_counter);
@@ -1608,7 +1629,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1608 1629
1609static int 1630static int
1610upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1631upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1611 int preserve_flag, int print_flag, int fsync_flag) 1632 int preserve_flag, int print_flag, int resume, int fsync_flag)
1612{ 1633{
1613 int ret = 0, status; 1634 int ret = 0, status;
1614 DIR *dirp; 1635 DIR *dirp;
@@ -1677,12 +1698,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1677 continue; 1698 continue;
1678 1699
1679 if (upload_dir_internal(conn, new_src, new_dst, 1700 if (upload_dir_internal(conn, new_src, new_dst,
1680 depth + 1, preserve_flag, print_flag, 1701 depth + 1, preserve_flag, print_flag, resume,
1681 fsync_flag) == -1) 1702 fsync_flag) == -1)
1682 ret = -1; 1703 ret = -1;
1683 } else if (S_ISREG(sb.st_mode)) { 1704 } else if (S_ISREG(sb.st_mode)) {
1684 if (do_upload(conn, new_src, new_dst, 1705 if (do_upload(conn, new_src, new_dst,
1685 preserve_flag, fsync_flag) == -1) { 1706 preserve_flag, resume, fsync_flag) == -1) {
1686 error("Uploading of file %s to %s failed!", 1707 error("Uploading of file %s to %s failed!",
1687 new_src, new_dst); 1708 new_src, new_dst);
1688 ret = -1; 1709 ret = -1;
@@ -1701,7 +1722,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1701 1722
1702int 1723int
1703upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, 1724upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
1704 int print_flag, int fsync_flag) 1725 int print_flag, int resume, int fsync_flag)
1705{ 1726{
1706 char *dst_canon; 1727 char *dst_canon;
1707 int ret; 1728 int ret;
@@ -1712,7 +1733,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
1712 } 1733 }
1713 1734
1714 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 1735 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1715 print_flag, fsync_flag); 1736 print_flag, resume, fsync_flag);
1716 1737
1717 free(dst_canon); 1738 free(dst_canon);
1718 return ret; 1739 return ret;
diff --git a/sftp-client.h b/sftp-client.h
index ba92ad01a..967840b9c 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.h,v 1.24 2013/10/17 00:30:13 djm Exp $ */ 1/* $OpenBSD: sftp-client.h,v 1.25 2014/04/21 14:36:16 logan Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 4 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -120,13 +120,13 @@ int download_dir(struct sftp_conn *, char *, char *, Attrib *, int,
120 * Upload 'local_path' to 'remote_path'. Preserve permissions and times 120 * Upload 'local_path' to 'remote_path'. Preserve permissions and times
121 * if 'pflag' is set 121 * if 'pflag' is set
122 */ 122 */
123int do_upload(struct sftp_conn *, char *, char *, int, int); 123int do_upload(struct sftp_conn *, char *, char *, int, int, int);
124 124
125/* 125/*
126 * Recursively upload 'local_directory' to 'remote_directory'. Preserve 126 * Recursively upload 'local_directory' to 'remote_directory'. Preserve
127 * times if 'pflag' is set 127 * times if 'pflag' is set
128 */ 128 */
129int upload_dir(struct sftp_conn *, char *, char *, int, int, int); 129int upload_dir(struct sftp_conn *, char *, char *, int, int, int, int);
130 130
131/* Concatenate paths, taking care of slashes. Caller must free result. */ 131/* Concatenate paths, taking care of slashes. Caller must free result. */
132char *path_append(char *, char *); 132char *path_append(char *, char *);
diff --git a/sftp.c b/sftp.c
index ad1f8c84d..e74bed5e0 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp.c,v 1.158 2013/11/20 20:54:10 deraadt Exp $ */ 1/* $OpenBSD: sftp.c,v 1.159 2014/04/21 14:36:16 logan Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -88,7 +88,7 @@ int showprogress = 1;
88/* When this option is set, we always recursively download/upload directories */ 88/* When this option is set, we always recursively download/upload directories */
89int global_rflag = 0; 89int global_rflag = 0;
90 90
91/* When this option is set, we resume download if possible */ 91/* When this option is set, we resume download or upload if possible */
92int global_aflag = 0; 92int global_aflag = 0;
93 93
94/* When this option is set, the file transfers will always preserve times */ 94/* When this option is set, the file transfers will always preserve times */
@@ -159,6 +159,7 @@ enum sftp_command {
159 I_VERSION, 159 I_VERSION,
160 I_PROGRESS, 160 I_PROGRESS,
161 I_REGET, 161 I_REGET,
162 I_REPUT
162}; 163};
163 164
164struct CMD { 165struct CMD {
@@ -201,6 +202,7 @@ static const struct CMD cmds[] = {
201 { "quit", I_QUIT, NOARGS }, 202 { "quit", I_QUIT, NOARGS },
202 { "reget", I_REGET, REMOTE }, 203 { "reget", I_REGET, REMOTE },
203 { "rename", I_RENAME, REMOTE }, 204 { "rename", I_RENAME, REMOTE },
205 { "reput", I_REPUT, LOCAL },
204 { "rm", I_RM, REMOTE }, 206 { "rm", I_RM, REMOTE },
205 { "rmdir", I_RMDIR, REMOTE }, 207 { "rmdir", I_RMDIR, REMOTE },
206 { "symlink", I_SYMLINK, REMOTE }, 208 { "symlink", I_SYMLINK, REMOTE },
@@ -250,6 +252,7 @@ help(void)
250 "exit Quit sftp\n" 252 "exit Quit sftp\n"
251 "get [-Ppr] remote [local] Download file\n" 253 "get [-Ppr] remote [local] Download file\n"
252 "reget remote [local] Resume download file\n" 254 "reget remote [local] Resume download file\n"
255 "reput [local] remote Resume upload file\n"
253 "help Display this help text\n" 256 "help Display this help text\n"
254 "lcd path Change local directory to 'path'\n" 257 "lcd path Change local directory to 'path'\n"
255 "lls [ls-options [path]] Display local directory listing\n" 258 "lls [ls-options [path]] Display local directory listing\n"
@@ -660,7 +663,7 @@ out:
660 663
661static int 664static int
662process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, 665process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
663 int pflag, int rflag, int fflag) 666 int pflag, int rflag, int resume, int fflag)
664{ 667{
665 char *tmp_dst = NULL; 668 char *tmp_dst = NULL;
666 char *abs_dst = NULL; 669 char *abs_dst = NULL;
@@ -723,16 +726,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
723 } 726 }
724 free(tmp); 727 free(tmp);
725 728
726 if (!quiet) 729 resume |= global_aflag;
730 if (!quiet && resume)
731 printf("Resuming upload of %s to %s\n", g.gl_pathv[i],
732 abs_dst);
733 else if (!quiet && !resume)
727 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst); 734 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
728 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { 735 if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
729 if (upload_dir(conn, g.gl_pathv[i], abs_dst, 736 if (upload_dir(conn, g.gl_pathv[i], abs_dst,
730 pflag || global_pflag, 1, 737 pflag || global_pflag, 1, resume,
731 fflag || global_fflag) == -1) 738 fflag || global_fflag) == -1)
732 err = -1; 739 err = -1;
733 } else { 740 } else {
734 if (do_upload(conn, g.gl_pathv[i], abs_dst, 741 if (do_upload(conn, g.gl_pathv[i], abs_dst,
735 pflag || global_pflag, 742 pflag || global_pflag, resume,
736 fflag || global_fflag) == -1) 743 fflag || global_fflag) == -1)
737 err = -1; 744 err = -1;
738 } 745 }
@@ -1186,8 +1193,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
1186} 1193}
1187 1194
1188static int 1195static int
1189parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, 1196parse_args(const char **cpp, int *ignore_errors, int *aflag,
1190 int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag, 1197 int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
1198 int *rflag, int *sflag,
1191 unsigned long *n_arg, char **path1, char **path2) 1199 unsigned long *n_arg, char **path1, char **path2)
1192{ 1200{
1193 const char *cmd, *cp = *cpp; 1201 const char *cmd, *cp = *cpp;
@@ -1239,6 +1247,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
1239 switch (cmdnum) { 1247 switch (cmdnum) {
1240 case I_GET: 1248 case I_GET:
1241 case I_REGET: 1249 case I_REGET:
1250 case I_REPUT:
1242 case I_PUT: 1251 case I_PUT:
1243 if ((optidx = parse_getput_flags(cmd, argv, argc, 1252 if ((optidx = parse_getput_flags(cmd, argv, argc,
1244 aflag, fflag, pflag, rflag)) == -1) 1253 aflag, fflag, pflag, rflag)) == -1)
@@ -1256,11 +1265,6 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
1256 /* Destination is not globbed */ 1265 /* Destination is not globbed */
1257 undo_glob_escape(*path2); 1266 undo_glob_escape(*path2);
1258 } 1267 }
1259 if (*aflag && cmdnum == I_PUT) {
1260 /* XXX implement resume for uploads */
1261 error("Resume is not supported for uploads");
1262 return -1;
1263 }
1264 break; 1268 break;
1265 case I_LINK: 1269 case I_LINK:
1266 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) 1270 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
@@ -1382,7 +1386,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1382 int err_abort) 1386 int err_abort)
1383{ 1387{
1384 char *path1, *path2, *tmp; 1388 char *path1, *path2, *tmp;
1385 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0; 1389 int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0,
1390 iflag = 0;
1386 int lflag = 0, pflag = 0, rflag = 0, sflag = 0; 1391 int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
1387 int cmdnum, i; 1392 int cmdnum, i;
1388 unsigned long n_arg = 0; 1393 unsigned long n_arg = 0;
@@ -1415,9 +1420,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
1415 err = process_get(conn, path1, path2, *pwd, pflag, 1420 err = process_get(conn, path1, path2, *pwd, pflag,
1416 rflag, aflag, fflag); 1421 rflag, aflag, fflag);
1417 break; 1422 break;
1423 case I_REPUT:
1424 aflag = 1;
1425 /* FALLTHROUGH */
1418 case I_PUT: 1426 case I_PUT:
1419 err = process_put(conn, path1, path2, *pwd, pflag, 1427 err = process_put(conn, path1, path2, *pwd, pflag,
1420 rflag, fflag); 1428 rflag, aflag, fflag);
1421 break; 1429 break;
1422 case I_RENAME: 1430 case I_RENAME:
1423 path1 = make_absolute(path1, *pwd); 1431 path1 = make_absolute(path1, *pwd);