mirror of
git://anongit.mindrot.org/openssh.git
synced 2024-11-23 18:23:25 +08:00
- 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@
This commit is contained in:
parent
16cd3928a8
commit
d8accc0aa7
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
38
sftp.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user