diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | sftp-client.c | 41 | ||||
-rw-r--r-- | sftp-client.h | 6 | ||||
-rw-r--r-- | sftp.c | 38 |
4 files changed, 62 insertions, 28 deletions
@@ -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 | ||
10 | 20140430 | 15 | 20140430 |
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 | ||
1421 | int | 1421 | int |
1422 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | 1422 | do_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 | ||
1609 | static int | 1630 | static int |
1610 | upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, | 1631 | upload_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 | ||
1702 | int | 1723 | int |
1703 | upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, | 1724 | upload_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 | */ |
123 | int do_upload(struct sftp_conn *, char *, char *, int, int); | 123 | int 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 | */ |
129 | int upload_dir(struct sftp_conn *, char *, char *, int, int, int); | 129 | int 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. */ |
132 | char *path_append(char *, char *); | 132 | char *path_append(char *, char *); |
@@ -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 */ |
89 | int global_rflag = 0; | 89 | int 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 */ |
92 | int global_aflag = 0; | 92 | int 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 | ||
164 | struct CMD { | 165 | struct 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 | ||
661 | static int | 664 | static int |
662 | process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, | 665 | process_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 | ||
1188 | static int | 1195 | static int |
1189 | parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag, | 1196 | parse_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); |