Rework the wording for uploading resume as suggested by Mike Larkin.
(More tweaks coming up soon)
Index: sftp-client.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sftp-client.c,v
retrieving revision 1.114
diff -u -p -u -p -r1.114 sftp-client.c
--- sftp-client.c 31 Jan 2014 16:39:19 -0000 1.114
+++ sftp-client.c 16 Apr 2014 14:14:34 -0000
@@ -1409,7 +1409,7 @@ download_dir(struct sftp_conn *conn, cha
int
do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
- int preserve_flag, int fsync_flag)
+ int preserve_flag, int resume, int fsync_flag)
{
int local_fd;
int status = SSH2_FX_OK;
@@ -1418,7 +1418,7 @@ do_upload(struct sftp_conn *conn, char *
char *handle, *data;
Buffer msg;
struct stat sb;
- Attrib a;
+ Attrib a, *c = NULL;
u_int32_t startid;
u_int32_t ackid;
struct outstanding_ack {
@@ -1456,6 +1456,27 @@ do_upload(struct sftp_conn *conn, char *
if (!preserve_flag)
a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
+ if (resume) {
+ /* Get remote file size if it exists */
+ if ((c = do_stat(conn, remote_path, 0)) == NULL) {
+ close(local_fd);
+ return -1;
+ }
+
+ if ((off_t)c->size > sb.st_size ||
+ (off_t)c->size == sb.st_size) {
+ error("destination file bigger or same size as "
+ "source file");
+ close(local_fd);
+ return -1;
+ }
+
+ if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) {
+ close(local_fd);
+ return -1;
+ }
+ }
+
buffer_init(&msg);
/* Send open request */
@@ -1463,7 +1484,8 @@ do_upload(struct sftp_conn *conn, char *
buffer_put_char(&msg, SSH2_FXP_OPEN);
buffer_put_int(&msg, id);
buffer_put_cstring(&msg, remote_path);
- buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
+ buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
+ (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC));
encode_attrib(&msg, &a);
send_msg(conn, &msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
@@ -1482,7 +1504,7 @@ do_upload(struct sftp_conn *conn, char *
data = xmalloc(conn->transfer_buflen);
/* Read from local and write to remote */
- offset = progress_counter = 0;
+ offset = progress_counter = (resume ? c->size : 0);
if (showprogress)
start_progress_meter(local_path, sb.st_size,
&progress_counter);
@@ -1596,7 +1618,7 @@ do_upload(struct sftp_conn *conn, char *
static int
upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
- int preserve_flag, int print_flag, int fsync_flag)
+ int preserve_flag, int print_flag, int resume, int fsync_flag)
{
int ret = 0, status;
DIR *dirp;
@@ -1665,12 +1687,12 @@ upload_dir_internal(struct sftp_conn *co
continue;
if (upload_dir_internal(conn, new_src, new_dst,
- depth + 1, preserve_flag, print_flag,
+ depth + 1, preserve_flag, print_flag, resume,
fsync_flag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode)) {
if (do_upload(conn, new_src, new_dst,
- preserve_flag, fsync_flag) == -1) {
+ preserve_flag, resume, fsync_flag) == -1) {
error("Uploading of file %s to %s failed!",
new_src, new_dst);
ret = -1;
@@ -1689,7 +1711,7 @@ upload_dir_internal(struct sftp_conn *co
int
upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
- int print_flag, int fsync_flag)
+ int print_flag, int resume, int fsync_flag)
{
char *dst_canon;
int ret;
@@ -1700,7 +1722,7 @@ upload_dir(struct sftp_conn *conn, char
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
- print_flag, fsync_flag);
+ print_flag, resume, fsync_flag);
free(dst_canon);
return ret;
Index: sftp-client.h
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sftp-client.h,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 sftp-client.h
--- sftp-client.h 17 Oct 2013 00:30:13 -0000 1.24
+++ sftp-client.h 16 Apr 2014 14:14:34 -0000
@@ -120,13 +120,13 @@ int download_dir(struct sftp_conn *, cha
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
-int do_upload(struct sftp_conn *, char *, char *, int, int);
+int do_upload(struct sftp_conn *, char *, char *, int, int, int);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set
*/
-int upload_dir(struct sftp_conn *, char *, char *, int, int, int);
+int upload_dir(struct sftp_conn *, char *, char *, int, int, int, int);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(char *, char *);
Index: sftp.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sftp.c,v
retrieving revision 1.158
diff -u -p -u -p -r1.158 sftp.c
--- sftp.c 20 Nov 2013 20:54:10 -0000 1.158
+++ sftp.c 16 Apr 2014 14:14:37 -0000
@@ -72,6 +72,9 @@ int global_rflag = 0;
/* When this option is set, we resume download if possible */
int global_aflag = 0;
+/* When this option is set, we resume upload if possible */
+int global_ruflag = 0;
+
/* When this option is set, the file transfers will always preserve times */
int global_pflag = 0;
@@ -138,6 +141,7 @@ enum sftp_command {
I_VERSION,
I_PROGRESS,
I_REGET,
+ I_REPUT
};
struct CMD {
@@ -180,6 +184,7 @@ static const struct CMD cmds[] = {
{ "quit", I_QUIT, NOARGS },
{ "reget", I_REGET, REMOTE },
{ "rename", I_RENAME, REMOTE },
+ { "reput", I_REPUT, LOCAL },
{ "rm", I_RM, REMOTE },
{ "rmdir", I_RMDIR, REMOTE },
{ "symlink", I_SYMLINK, REMOTE },
@@ -229,6 +234,7 @@ help(void)
"exit Quit sftp\n"
"get [-Ppr] remote [local] Download file\n"
"reget remote [local] Resume download file\n"
+ "reput [local] remote Resume upload file\n"
"help Display this help text\n"
"lcd path Change local directory to
'path'\n"
"lls [ls-options [path]] Display local directory
listing\n"
@@ -341,7 +347,7 @@ make_absolute(char *p, char *pwd)
static int
parse_getput_flags(const char *cmd, char **argv, int argc,
- int *aflag, int *fflag, int *pflag, int *rflag)
+ int *aflag, int *ruflag, int *fflag, int *pflag, int *rflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
@@ -349,8 +355,8 @@ parse_getput_flags(const char *cmd, char
optind = optreset = 1;
opterr = 0;
- *aflag = *fflag = *rflag = *pflag = 0;
- while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
+ *aflag = *ruflag = *fflag = *rflag = *pflag = 0;
+ while ((ch = getopt(argc, argv, "afPpuRr")) != -1) {
switch (ch) {
case 'a':
*aflag = 1;
@@ -366,6 +372,9 @@ parse_getput_flags(const char *cmd, char
case 'R':
*rflag = 1;
break;
+ case 'u':
+ *ruflag = 1;
+ break;
default:
error("%s: Invalid flag -%c", cmd, optopt);
return -1;
@@ -639,7 +648,7 @@ out:
static int
process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
- int pflag, int rflag, int fflag)
+ int pflag, int rflag, int resume, int fflag)
{
char *tmp_dst = NULL;
char *abs_dst = NULL;
@@ -702,16 +711,19 @@ process_put(struct sftp_conn *conn, char
}
free(tmp);
- if (!quiet)
+ if (!quiet && resume)
+ printf("Resuming upload of %s to %s\n", g.gl_pathv[i],
+ abs_dst);
+ else if (!quiet && !resume)
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
- pflag || global_pflag, 1,
+ pflag || global_pflag, 1, resume,
fflag || global_fflag) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
- pflag || global_pflag,
+ pflag || global_pflag, resume,
fflag || global_fflag) == -1)
err = -1;
}
@@ -1165,8 +1177,9 @@ makeargv(const char *arg, int *argcp, in
}
static int
-parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
- int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag,
+parse_args(const char **cpp, int *ignore_errors, int *aflag, int *ruflag,
+ int *fflag, int *hflag, int *iflag, int *lflag, int *pflag,
+ int *rflag, int *sflag,
unsigned long *n_arg, char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
@@ -1212,15 +1225,16 @@ parse_args(const char **cpp, int *ignore
/* Get arguments and parse flags */
*aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
- *rflag = *sflag = 0;
+ *rflag = *ruflag = *sflag = 0;
*path1 = *path2 = NULL;
optidx = 1;
switch (cmdnum) {
case I_GET:
case I_REGET:
+ case I_REPUT:
case I_PUT:
if ((optidx = parse_getput_flags(cmd, argv, argc,
- aflag, fflag, pflag, rflag)) == -1)
+ aflag, ruflag, fflag, pflag, rflag)) == -1)
return -1;
/* Get first pathname (mandatory) */
if (argc - optidx < 1) {
@@ -1235,11 +1249,6 @@ parse_args(const char **cpp, int *ignore
/* Destination is not globbed */
undo_glob_escape(*path2);
}
- if (*aflag && cmdnum == I_PUT) {
- /* XXX implement resume for uploads */
- error("Resume is not supported for uploads");
- return -1;
- }
break;
case I_LINK:
if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
@@ -1361,7 +1370,8 @@ parse_dispatch_command(struct sftp_conn
int err_abort)
{
char *path1, *path2, *tmp;
- int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0;
+ int ignore_errors = 0, aflag = 0, ruflag = 0, fflag = 0, hflag = 0,
+ iflag = 0;
int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
int cmdnum, i;
unsigned long n_arg = 0;
@@ -1371,7 +1381,8 @@ parse_dispatch_command(struct sftp_conn
glob_t g;
path1 = path2 = NULL;
- cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
+ cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &ruflag, &fflag,
+ &hflag,
&iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
if (ignore_errors != 0)
err_abort = 0;
@@ -1394,9 +1405,12 @@ parse_dispatch_command(struct sftp_conn
err = process_get(conn, path1, path2, *pwd, pflag,
rflag, aflag, fflag);
break;
+ case I_REPUT:
+ ruflag = 1;
+ /* FALLTHROUGH */
case I_PUT:
err = process_put(conn, path1, path2, *pwd, pflag,
- rflag, fflag);
+ rflag, ruflag, fflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
@@ -2201,7 +2215,7 @@ main(int argc, char **argv)
infile = stdin;
while ((ch = getopt(argc, argv,
- "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
+ "1246afhpqruvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
switch (ch) {
/* Passed through to ssh(1) */
case '4':
@@ -2292,6 +2306,9 @@ main(int argc, char **argv)
case 'S':
ssh_program = optarg;
replacearg(&args, 0, "%s", ssh_program);
+ break;
+ case 'u':
+ global_ruflag = 1;
break;
case 'h':
default: