[sftp-client.c sftp-client.h sftp.c]
     Implement sftp upload resume support.
     OK from djm@, with input from guenther@, mlarkin@ and
     okan@
This commit is contained in:
Damien Miller 2014-05-15 13:46:25 +10:00
parent 16cd3928a8
commit d8accc0aa7
4 changed files with 62 additions and 28 deletions

View File

@ -6,6 +6,11 @@
[dns.c dns.h ssh-keygen.c]
Add support for SSHFP DNS records for ED25519 key types.
OK from djm@
- 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@
20140430
- (dtucker) [defines.h] Define __GNUC_PREREQ__ macro if we don't already

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.114 2014/01/31 16:39:19 tedu Exp $ */
/* $OpenBSD: sftp-client.c,v 1.115 2014/04/21 14:36:16 logan Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -1420,7 +1420,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst,
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;
@ -1429,7 +1429,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
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 {
@ -1467,6 +1467,26 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
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) {
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 */
@ -1474,7 +1494,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
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);
@ -1493,7 +1514,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
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);
@ -1608,7 +1629,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
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;
@ -1677,12 +1698,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
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;
@ -1701,7 +1722,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
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;
@ -1712,7 +1733,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
}
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;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.24 2013/10/17 00:30:13 djm Exp $ */
/* $OpenBSD: sftp-client.h,v 1.25 2014/04/21 14:36:16 logan Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@ -120,13 +120,13 @@ int download_dir(struct sftp_conn *, char *, char *, Attrib *, int,
* 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 *);

38
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.158 2013/11/20 20:54:10 deraadt Exp $ */
/* $OpenBSD: sftp.c,v 1.159 2014/04/21 14:36:16 logan Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@ -88,7 +88,7 @@ int showprogress = 1;
/* When this option is set, we always recursively download/upload directories */
int global_rflag = 0;
/* When this option is set, we resume download if possible */
/* When this option is set, we resume download or upload if possible */
int global_aflag = 0;
/* When this option is set, the file transfers will always preserve times */
@ -159,6 +159,7 @@ enum sftp_command {
I_VERSION,
I_PROGRESS,
I_REGET,
I_REPUT
};
struct CMD {
@ -201,6 +202,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 },
@ -250,6 +252,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"
@ -660,7 +663,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;
@ -723,16 +726,20 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
}
free(tmp);
if (!quiet)
resume |= global_aflag;
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;
}
@ -1186,8 +1193,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
}
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 *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;
@ -1239,6 +1247,7 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
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)
@ -1256,11 +1265,6 @@ parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
/* 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)
@ -1382,7 +1386,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
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, fflag = 0, hflag = 0,
iflag = 0;
int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
int cmdnum, i;
unsigned long n_arg = 0;
@ -1415,9 +1420,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
err = process_get(conn, path1, path2, *pwd, pflag,
rflag, aflag, fflag);
break;
case I_REPUT:
aflag = 1;
/* FALLTHROUGH */
case I_PUT:
err = process_put(conn, path1, path2, *pwd, pflag,
rflag, fflag);
rflag, aflag, fflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);