From a627d42e51ffa71e014d7b2d2c07118122fd3ec3 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Jun 2013 07:31:17 +1000 Subject: - djm@cvs.openbsd.org 2013/05/17 00:13:13 [xmalloc.h cipher.c sftp-glob.c ssh-keyscan.c ssh.c sftp-common.c ssh-ecdsa.c auth2-chall.c compat.c readconf.c kexgexs.c monitor.c gss-genr.c cipher-3des1.c kex.c monitor_wrap.c ssh-pkcs11-client.c auth-options.c rsa.c auth2-pubkey.c sftp.c hostfile.c auth2.c servconf.c auth.c authfile.c xmalloc.c uuencode.c sftp-client.c auth2-gss.c sftp-server.c bufaux.c mac.c session.c jpake.c kexgexc.c sshconnect.c auth-chall.c auth2-passwd.c sshconnect1.c buffer.c kexecdhs.c kexdhs.c ssh-rsa.c auth1.c ssh-pkcs11.c auth2-kbdint.c kexdhc.c sshd.c umac.c ssh-dss.c auth2-jpake.c bufbn.c clientloop.c monitor_mm.c scp.c roaming_client.c serverloop.c key.c auth-rsa.c ssh-pkcs11-helper.c ssh-keysign.c ssh-keygen.c match.c channels.c sshconnect2.c addrmatch.c mux.c canohost.c kexecdhc.c schnorr.c ssh-add.c misc.c auth2-hostbased.c ssh-agent.c bufec.c groupaccess.c dns.c packet.c readpass.c authfd.c moduli.c] bye, bye xfree(); ok markus@ --- sftp-client.c | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'sftp-client.c') diff --git a/sftp-client.c b/sftp-client.c index 85f2bd444..038e1c347 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.97 2012/07/02 12:13:26 dtucker Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.98 2013/05/17 00:13:14 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -394,8 +394,8 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, } else { debug2("Unrecognised server extension \"%s\"", name); } - xfree(name); - xfree(value); + free(name); + free(value); } buffer_free(&msg); @@ -509,7 +509,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, error("Couldn't read directory: %s", fx2txt(status)); do_close(conn, handle, handle_len); - xfree(handle); + free(handle); buffer_free(&msg); return(status); } @@ -552,14 +552,14 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, (*dir)[++ents] = NULL; } next: - xfree(filename); - xfree(longname); + free(filename); + free(longname); } } buffer_free(&msg); do_close(conn, handle, handle_len); - xfree(handle); + free(handle); /* Don't return partial matches on interrupt */ if (interrupted && dir != NULL && *dir != NULL) { @@ -582,11 +582,11 @@ void free_sftp_dirents(SFTP_DIRENT **s) int i; for (i = 0; s[i]; i++) { - xfree(s[i]->filename); - xfree(s[i]->longname); - xfree(s[i]); + free(s[i]->filename); + free(s[i]->longname); + free(s[i]); } - xfree(s); + free(s); } int @@ -760,7 +760,7 @@ do_realpath(struct sftp_conn *conn, char *path) debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename, (unsigned long)a->size); - xfree(longname); + free(longname); buffer_free(&msg); @@ -907,7 +907,7 @@ do_readlink(struct sftp_conn *conn, char *path) debug3("SSH_FXP_READLINK %s -> %s", path, filename); - xfree(longname); + free(longname); buffer_free(&msg); @@ -1057,7 +1057,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, local_path, strerror(errno)); do_close(conn, handle, handle_len); buffer_free(&msg); - xfree(handle); + free(handle); return(-1); } @@ -1121,7 +1121,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, read_error = 1; max_req = 0; TAILQ_REMOVE(&requests, req, tq); - xfree(req); + free(req); num_req--; break; case SSH2_FXP_DATA: @@ -1140,11 +1140,11 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, max_req = 0; } progress_counter += len; - xfree(data); + free(data); if (len == req->len) { TAILQ_REMOVE(&requests, req, tq); - xfree(req); + free(req); num_req--; } else { /* Resend the request for the missing data */ @@ -1220,7 +1220,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, } close(local_fd); buffer_free(&msg); - xfree(handle); + free(handle); return(status); } @@ -1292,8 +1292,8 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, } else logit("%s: not a regular file\n", new_src); - xfree(new_dst); - xfree(new_src); + free(new_dst); + free(new_src); } if (pflag) { @@ -1329,7 +1329,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst, ret = download_dir_internal(conn, src_canon, dst, dirattrib, pflag, printflag, 0); - xfree(src_canon); + free(src_canon); return ret; } @@ -1481,7 +1481,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, debug3("In write loop, ack for %u %u bytes at %lld", ack->id, ack->len, (long long)ack->offset); ++ackid; - xfree(ack); + free(ack); } offset += len; if (offset < 0) @@ -1491,7 +1491,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (showprogress) stop_progress_meter(); - xfree(data); + free(data); if (status != SSH2_FX_OK) { error("Couldn't write to remote file \"%s\": %s", @@ -1511,7 +1511,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, if (do_close(conn, handle, handle_len) != SSH2_FX_OK) status = -1; - xfree(handle); + free(handle); return status; } @@ -1597,8 +1597,8 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, } } else logit("%s: not a regular file\n", filename); - xfree(new_dst); - xfree(new_src); + free(new_dst); + free(new_src); } do_setstat(conn, dst, &a); @@ -1620,7 +1620,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, } ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); - xfree(dst_canon); + free(dst_canon); return ret; } -- cgit v1.2.3 From 3750fce6ac6b287f62584ac55a4406df95c71b92 Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Jun 2013 07:52:21 +1000 Subject: - dtucker@cvs.openbsd.org 2013/06/01 20:59:25 [scp.c sftp-client.c] Replace S_IWRITE, which isn't standardized, with S_IWUSR, which is. Patch from Nathan Osman via bz#2113. ok deraadt. (note: corrected bug number from 2085) --- ChangeLog | 4 ++++ scp.c | 4 ++-- sftp-client.c | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index 891db12a6..c64a40468 100644 --- a/ChangeLog +++ b/ChangeLog @@ -44,6 +44,10 @@ Use clock_gettime(CLOCK_MONOTONIC ...) for ssh timers so that things like keepalives and rekeying will work properly over clock steps. Suggested by markus@, "looks good" djm@. + - dtucker@cvs.openbsd.org 2013/06/01 20:59:25 + [scp.c sftp-client.c] + Replace S_IWRITE, which isn't standardized, with S_IWUSR, which is. Patch + from Nathan Osman via bz#2085. ok deraadt. 20130529 - (dtucker) [configure.ac openbsd-compat/bsd-misc.h] bz#2087: Add a null diff --git a/scp.c b/scp.c index 32e9d00b2..b75d97bb9 100644 --- a/scp.c +++ b/scp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scp.c,v 1.173 2013/05/17 00:13:14 djm Exp $ */ +/* $OpenBSD: scp.c,v 1.174 2013/06/01 20:59:25 dtucker Exp $ */ /* * scp - secure remote copy. This is basically patched BSD rcp which * uses ssh to do the data transfer (instead of using rcmd). @@ -1066,7 +1066,7 @@ sink(int argc, char **argv) continue; } omode = mode; - mode |= S_IWRITE; + mode |= S_IWUSR; if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { bad: run_err("%s: %s", np, strerror(errno)); continue; diff --git a/sftp-client.c b/sftp-client.c index 038e1c347..fc60dd80d 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.98 2013/05/17 00:13:14 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.99 2013/06/01 20:59:25 dtucker Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -1051,7 +1051,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, } local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, - mode | S_IWRITE); + mode | S_IWUSR); if (local_fd == -1) { error("Couldn't open local file \"%s\" for writing: %s", local_path, strerror(errno)); -- cgit v1.2.3 From c9a1991b95a4c9f04f9dcef299a8110d2ec80d3e Mon Sep 17 00:00:00 2001 From: Darren Tucker Date: Sun, 2 Jun 2013 08:37:05 +1000 Subject: - dtucker@cvs.openbsd.org 2013/06/01 22:34:50 [sftp-client.c] Update progressmeter when data is acked, not when it's sent. bz#2108, from Debian via Colin Watson, ok djm@ --- ChangeLog | 4 ++++ sftp-client.c | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index 50ce1b736..cfb38233d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -48,6 +48,10 @@ [scp.c sftp-client.c] Replace S_IWRITE, which isn't standardized, with S_IWUSR, which is. Patch from Nathan Osman via bz#2085. ok deraadt. + - dtucker@cvs.openbsd.org 2013/06/01 22:34:50 + [sftp-client.c] + Update progressmeter when data is acked, not when it's sent. bz#2108, from + Debian via Colin Watson, ok djm@ - (dtucker) [M auth-chall.c auth-krb5.c auth-pam.c cipher-aes.c cipher-ctr.c groupaccess.c loginrec.c monitor.c monitor_wrap.c session.c sshd.c sshlogin.c uidswap.c openbsd-compat/bsd-cygwin_util.c diff --git a/sftp-client.c b/sftp-client.c index fc60dd80d..ab035c713 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.99 2013/06/01 20:59:25 dtucker Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.100 2013/06/01 22:34:50 dtucker Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -1340,7 +1340,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, int local_fd; int status = SSH2_FX_OK; u_int handle_len, id, type; - off_t offset; + off_t offset, progress_counter; char *handle, *data; Buffer msg; struct stat sb; @@ -1408,9 +1408,10 @@ 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 = 0; + offset = progress_counter = 0; if (showprogress) - start_progress_meter(local_path, sb.st_size, &offset); + start_progress_meter(local_path, sb.st_size, + &progress_counter); for (;;) { int len; @@ -1481,6 +1482,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, debug3("In write loop, ack for %u %u bytes at %lld", ack->id, ack->len, (long long)ack->offset); ++ackid; + progress_counter += ack->len; free(ack); } offset += len; -- cgit v1.2.3 From 0d032419ee6e1968fc1cb187af63bf3b77b506ea Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Thu, 25 Jul 2013 11:56:52 +1000 Subject: - djm@cvs.openbsd.org 2013/07/25 00:56:52 [sftp-client.c sftp-client.h sftp.1 sftp.c] sftp support for resuming partial downloads; patch mostly by Loganaden Velvindron/AfriNIC with some tweaks by me; feedback and ok dtucker@ --- ChangeLog | 4 ++++ sftp-client.c | 75 ++++++++++++++++++++++++++++++++++++++++------------------ sftp-client.h | 6 ++--- sftp.1 | 28 ++++++++++++++++++---- sftp.c | 76 +++++++++++++++++++++++++++++++++++++++-------------------- 5 files changed, 133 insertions(+), 56 deletions(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index f799663fd..9552a9b81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,10 @@ [ssh.c] daemonise backgrounded (ControlPersist'ed) multiplexing master to ensure it is fully detached from its controlling terminal. based on debugging + - djm@cvs.openbsd.org 2013/07/25 00:56:52 + [sftp-client.c sftp-client.h sftp.1 sftp.c] + sftp support for resuming partial downloads; patch mostly by Loganaden + Velvindron/AfriNIC with some tweaks by me; feedback and ok dtucker@ 20130720 - (djm) OpenBSD CVS Sync diff --git a/sftp-client.c b/sftp-client.c index ab035c713..cb4efd3ea 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.100 2013/06/01 22:34:50 dtucker Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.101 2013/07/25 00:56:51 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -112,7 +112,7 @@ send_msg(struct sftp_conn *conn, Buffer *m) iov[1].iov_len = buffer_len(m); if (atomiciov6(writev, conn->fd_out, iov, 2, - conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != + conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != buffer_len(m) + sizeof(mlen)) fatal("Couldn't send packet: %s", strerror(errno)); @@ -988,16 +988,17 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, int do_download(struct sftp_conn *conn, char *remote_path, char *local_path, - Attrib *a, int pflag) + Attrib *a, int pflag, int resume) { Attrib junk; Buffer msg; char *handle; - int local_fd, status = 0, write_error; - int read_error, write_errno; - u_int64_t offset, size; + int local_fd = -1, status = 0, write_error; + int read_error, write_errno, reordered = 0; + u_int64_t offset = 0, size, highwater; u_int handle_len, mode, type, id, buflen, num_req, max_req; off_t progress_counter; + struct stat st; struct request { u_int id; u_int len; @@ -1050,21 +1051,36 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, return(-1); } - local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, + local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? : O_TRUNC), mode | S_IWUSR); if (local_fd == -1) { error("Couldn't open local file \"%s\" for writing: %s", local_path, strerror(errno)); - do_close(conn, handle, handle_len); - buffer_free(&msg); - free(handle); - return(-1); + goto fail; + } + offset = highwater = 0; + if (resume) { + if (fstat(local_fd, &st) == -1) { + error("Unable to stat local file \"%s\": %s", + local_path, strerror(errno)); + goto fail; + } + if ((size_t)st.st_size > size) { + error("Unable to resume download of \"%s\": " + "local file is larger than remote", local_path); + fail: + do_close(conn, handle, handle_len); + buffer_free(&msg); + free(handle); + return -1; + } + offset = highwater = st.st_size; } /* Read from remote and write to local */ - write_error = read_error = write_errno = num_req = offset = 0; + write_error = read_error = write_errno = num_req = 0; max_req = 1; - progress_counter = 0; + progress_counter = offset; if (showprogress && size != 0) start_progress_meter(remote_path, size, &progress_counter); @@ -1139,6 +1155,10 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, write_error = 1; max_req = 0; } + else if (!reordered && req->offset <= highwater) + highwater = req->offset + len; + else if (!reordered && req->offset > highwater) + reordered = 1; progress_counter += len; free(data); @@ -1187,7 +1207,15 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, /* Sanity check */ if (TAILQ_FIRST(&requests) != NULL) fatal("Transfer complete, but requests still in queue"); - + /* Truncate at highest contiguous point to avoid holes on interrupt */ + if (read_error || write_error || interrupted) { + if (reordered && resume) { + error("Unable to resume download of \"%s\": " + "server reordered requests", local_path); + } + debug("truncating at %llu", (unsigned long long)highwater); + ftruncate(local_fd, highwater); + } if (read_error) { error("Couldn't read from remote file \"%s\" : %s", remote_path, fx2txt(status)); @@ -1199,7 +1227,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, do_close(conn, handle, handle_len); } else { status = do_close(conn, handle, handle_len); - + if (interrupted) + status = -1; /* Override umask and utimes if asked */ #ifdef HAVE_FCHMOD if (pflag && fchmod(local_fd, mode) == -1) @@ -1227,7 +1256,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, static int download_dir_internal(struct sftp_conn *conn, char *src, char *dst, - Attrib *dirattrib, int pflag, int printflag, int depth) + Attrib *dirattrib, int pflag, int printflag, int depth, int resume) { int i, ret = 0; SFTP_DIRENT **dir_entries; @@ -1280,11 +1309,11 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, continue; if (download_dir_internal(conn, new_src, new_dst, &(dir_entries[i]->a), pflag, printflag, - depth + 1) == -1) + depth + 1, resume) == -1) ret = -1; } else if (S_ISREG(dir_entries[i]->a.perm) ) { if (do_download(conn, new_src, new_dst, - &(dir_entries[i]->a), pflag) == -1) { + &(dir_entries[i]->a), pflag, resume) == -1) { error("Download of file %s to %s failed", new_src, new_dst); ret = -1; @@ -1317,7 +1346,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int download_dir(struct sftp_conn *conn, char *src, char *dst, - Attrib *dirattrib, int pflag, int printflag) + Attrib *dirattrib, int pflag, int printflag, int resume) { char *src_canon; int ret; @@ -1328,7 +1357,7 @@ download_dir(struct sftp_conn *conn, char *src, char *dst, } ret = download_dir_internal(conn, src_canon, dst, - dirattrib, pflag, printflag, 0); + dirattrib, pflag, printflag, 0, resume); free(src_canon); return ret; } @@ -1553,7 +1582,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, a.perm &= 01777; if (!pflag) a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; - + status = do_mkdir(conn, dst, &a, 0); /* * we lack a portable status for errno EEXIST, @@ -1563,7 +1592,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, if (status != SSH2_FX_OK) { if (status != SSH2_FX_FAILURE) return -1; - if (do_stat(conn, dst, 0) == NULL) + if (do_stat(conn, dst, 0) == NULL) return -1; } @@ -1571,7 +1600,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, error("Failed to open dir \"%s\": %s", src, strerror(errno)); return -1; } - + while (((dp = readdir(dirp)) != NULL) && !interrupted) { if (dp->d_ino == 0) continue; diff --git a/sftp-client.h b/sftp-client.h index aef54ef49..111a998c8 100644 --- a/sftp-client.h +++ b/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.20 2010/12/04 00:18:01 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.21 2013/07/25 00:56:51 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -106,13 +106,13 @@ int do_symlink(struct sftp_conn *, char *, char *); * Download 'remote_path' to 'local_path'. Preserve permissions and times * if 'pflag' is set */ -int do_download(struct sftp_conn *, char *, char *, Attrib *, int); +int do_download(struct sftp_conn *, char *, char *, Attrib *, int, int); /* * Recursively download 'remote_directory' to 'local_directory'. Preserve * times if 'pflag' is set */ -int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int); +int download_dir(struct sftp_conn *, char *, char *, Attrib *, int, int, int); /* * Upload 'local_path' to 'remote_path'. Preserve permissions and times diff --git a/sftp.1 b/sftp.1 index bcb472144..2577fe875 100644 --- a/sftp.1 +++ b/sftp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: sftp.1,v 1.91 2011/09/05 05:56:13 djm Exp $ +.\" $OpenBSD: sftp.1,v 1.92 2013/07/25 00:56:51 djm Exp $ .\" .\" Copyright (c) 2001 Damien Miller. All rights reserved. .\" @@ -22,7 +22,7 @@ .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd $Mdocdate: September 5 2011 $ +.Dd $Mdocdate: July 25 2013 $ .Dt SFTP 1 .Os .Sh NAME @@ -129,7 +129,7 @@ may be used to indicate standard input. .Nm will abort if any of the following commands fail: -.Ic get , put , rename , ln , +.Ic get , put , reget , rename , ln , .Ic rm , mkdir , chdir , ls , .Ic lchdir , chmod , chown , .Ic chgrp , lpwd , df , symlink , @@ -343,7 +343,7 @@ extension. Quit .Nm sftp . .It Xo Ic get -.Op Fl Ppr +.Op Fl aPpr .Ar remote-path .Op Ar local-path .Xc @@ -363,6 +363,14 @@ is specified, then .Ar local-path must specify a directory. .Pp +If the +.Fl a +flag is specified, then attempt to resume partial transfers of existing files. +Note that resumption assumes that any partial copy of the local file matches +the remote copy. +If the remote file differs from the partial local copy then the resultant file +is likely to be corrupt. +.Pp If either the .Fl P or @@ -503,6 +511,18 @@ Display remote working directory. .It Ic quit Quit .Nm sftp . +.It Xo Ic reget +.Op Fl Ppr +.Ar remote-path +.Op Ar local-path +.Xc +Resume download of +.Ar remote-path . +Equivalent to +.Ic get +with the +.Fl a +flag set. .It Ic rename Ar oldpath Ar newpath Rename remote file from .Ar oldpath diff --git a/sftp.c b/sftp.c index f0daaefa4..969328de4 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.147 2013/07/12 00:20:00 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.148 2013/07/25 00:56:52 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -88,6 +88,9 @@ 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 */ +int global_aflag = 0; + /* When this option is set, the file transfers will always preserve times */ int global_pflag = 0; @@ -151,6 +154,7 @@ extern char *__progname; #define I_SYMLINK 21 #define I_VERSION 22 #define I_PROGRESS 23 +#define I_REGET 26 struct CMD { const char *c; @@ -190,6 +194,7 @@ static const struct CMD cmds[] = { { "put", I_PUT, LOCAL }, { "pwd", I_PWD, REMOTE }, { "quit", I_QUIT, NOARGS }, + { "reget", I_REGET, REMOTE }, { "rename", I_RENAME, REMOTE }, { "rm", I_RM, REMOTE }, { "rmdir", I_RMDIR, REMOTE }, @@ -239,6 +244,7 @@ help(void) " filesystem containing 'path'\n" "exit Quit sftp\n" "get [-Ppr] remote [local] Download file\n" + "reget remote [local] Resume download 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" @@ -350,8 +356,8 @@ make_absolute(char *p, char *pwd) } static int -parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, - int *rflag) +parse_getput_flags(const char *cmd, char **argv, int argc, + int *aflag, int *pflag, int *rflag) { extern int opterr, optind, optopt, optreset; int ch; @@ -359,9 +365,12 @@ parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag, optind = optreset = 1; opterr = 0; - *rflag = *pflag = 0; - while ((ch = getopt(argc, argv, "PpRr")) != -1) { + *aflag = *rflag = *pflag = 0; + while ((ch = getopt(argc, argv, "aPpRr")) != -1) { switch (ch) { + case 'a': + *aflag = 1; + break; case 'p': case 'P': *pflag = 1; @@ -519,7 +528,7 @@ pathname_is_dir(char *pathname) static int process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, - int pflag, int rflag) + int pflag, int rflag, int resume) { char *abs_src = NULL; char *abs_dst = NULL; @@ -571,15 +580,18 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, } free(tmp); - if (!quiet) + resume |= global_aflag; + if (!quiet && resume) + printf("Resuming %s to %s\n", g.gl_pathv[i], abs_dst); + else if (!quiet && !resume) printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { - if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, - pflag || global_pflag, 1) == -1) + if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, + pflag || global_pflag, 1, resume) == -1) err = -1; } else { if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, - pflag || global_pflag) == -1) + pflag || global_pflag, resume) == -1) err = -1; } free(abs_dst); @@ -1118,8 +1130,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote, } static int -parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, - int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2) +parse_args(const char **cpp, int *aflag, 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; char *cp2, **argv; @@ -1163,14 +1176,15 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, } /* Get arguments and parse flags */ - *lflag = *pflag = *rflag = *hflag = *n_arg = 0; + *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0; *path1 = *path2 = NULL; optidx = 1; switch (cmdnum) { case I_GET: + case I_REGET: case I_PUT: if ((optidx = parse_getput_flags(cmd, argv, argc, - pflag, rflag)) == -1) + aflag, pflag, rflag)) == -1) return -1; /* Get first pathname (mandatory) */ if (argc - optidx < 1) { @@ -1185,6 +1199,11 @@ parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag, /* 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) @@ -1293,7 +1312,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, int err_abort) { char *path1, *path2, *tmp; - int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0; + int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0; + int rflag = 0, sflag = 0; int cmdnum, i; unsigned long n_arg = 0; Attrib a, *aa; @@ -1302,9 +1322,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, glob_t g; path1 = path2 = NULL; - cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag, - &sflag, &n_arg, &path1, &path2); - + cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag, + &rflag, &sflag, &n_arg, &path1, &path2); if (iflag != 0) err_abort = 0; @@ -1319,8 +1338,12 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, /* Unrecognized command */ err = -1; break; + case I_REGET: + aflag = 1; + /* FALLTHROUGH */ case I_GET: - err = process_get(conn, path1, path2, *pwd, pflag, rflag); + err = process_get(conn, path1, path2, *pwd, pflag, + rflag, aflag); break; case I_PUT: err = process_put(conn, path1, path2, *pwd, pflag, rflag); @@ -1949,12 +1972,10 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) } } else { /* XXX this is wrong wrt quoting */ - if (file2 == NULL) - snprintf(cmd, sizeof cmd, "get %s", dir); - else - snprintf(cmd, sizeof cmd, "get %s %s", dir, - file2); - + snprintf(cmd, sizeof cmd, "get%s %s%s%s", + global_aflag ? " -a" : "", dir, + file2 == NULL ? "" : " ", + file2 == NULL ? "" : file2); err = parse_dispatch_command(conn, cmd, &remote_path, 1); free(dir); @@ -2143,7 +2164,7 @@ main(int argc, char **argv) infile = stdin; while ((ch = getopt(argc, argv, - "1246hpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { + "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) { switch (ch) { /* Passed through to ssh(1) */ case '4': @@ -2183,6 +2204,9 @@ main(int argc, char **argv) case '2': sshver = 2; break; + case 'a': + global_aflag = 1; + break; case 'B': copy_buffer_len = strtol(optarg, &cp, 10); if (copy_buffer_len == 0 || *cp != '\0') -- cgit v1.2.3 From ed899eb597a8901ff7322cba809660515ec0d601 Mon Sep 17 00:00:00 2001 From: Tim Rice Date: Thu, 25 Jul 2013 15:40:00 -0700 Subject: - (tim) [sftp-client.c] Use of a gcc extension trips up native compilers on Solaris and UnixWare. Feedback and OK djm@ --- ChangeLog | 2 ++ sftp-client.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index 9ba325874..741fe7cf5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,8 @@ - djm@cvs.openbsd.org 2013/06/21 02:26:26 [regress/sftp-cmds.sh regress/test-exec.sh] unbreak sftp-cmds for renamed test data (s/ls/data/) + - (tim) [sftp-client.c] Use of a gcc extension trips up native compilers on + Solaris and UnixWare. Feedback and OK djm@ 20130720 - (djm) OpenBSD CVS Sync diff --git a/sftp-client.c b/sftp-client.c index cb4efd3ea..f4f1970b6 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1051,7 +1051,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, return(-1); } - local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? : O_TRUNC), + local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? 0 : O_TRUNC), mode | S_IWUSR); if (local_fd == -1) { error("Couldn't open local file \"%s\" for writing: %s", -- cgit v1.2.3 From c7dba12bf95eb1d69711881a153cc286c1987663 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 21 Aug 2013 02:41:15 +1000 Subject: - djm@cvs.openbsd.org 2013/08/08 05:04:03 [sftp-client.c sftp-client.h sftp.c] add a "-l" flag for the rename command to force it to use the silly standard SSH_FXP_RENAME command instead of the POSIX-rename- like posix-rename@openssh.com extension. intended for use in regress tests, so no documentation. --- ChangeLog | 6 ++++++ sftp-client.c | 12 +++++++----- sftp-client.h | 4 ++-- sftp.c | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 47 insertions(+), 10 deletions(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index 16bb10b4f..cd46b83aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,7 +19,13 @@ [sftp.c] fix two year old regression: symlinking a file would incorrectly canonicalise the target path. bz#2129 report from delphij AT freebsd.org + - djm@cvs.openbsd.org 2013/08/08 05:04:03 + [sftp-client.c sftp-client.h sftp.c] + add a "-l" flag for the rename command to force it to use the silly + standard SSH_FXP_RENAME command instead of the POSIX-rename- like + posix-rename@openssh.com extension. + intended for use in regress tests, so no documentation. 20130808 - (dtucker) [regress/Makefile regress/test-exec.sh] Don't try to use test -nt since some platforms (eg really old FreeBSD) don't have it. Instead, diff --git a/sftp-client.c b/sftp-client.c index f4f1970b6..0eeb73c8b 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.101 2013/07/25 00:56:51 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.102 2013/08/08 05:04:03 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -768,16 +768,18 @@ do_realpath(struct sftp_conn *conn, char *path) } int -do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) +do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, + int force_legacy) { Buffer msg; u_int status, id; + int use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; buffer_init(&msg); /* Send rename request */ id = conn->msg_id++; - if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { + if (use_ext) { buffer_put_char(&msg, SSH2_FXP_EXTENDED); buffer_put_int(&msg, id); buffer_put_cstring(&msg, "posix-rename@openssh.com"); @@ -789,8 +791,8 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) buffer_put_cstring(&msg, newpath); send_msg(conn, &msg); debug3("Sent message %s \"%s\" -> \"%s\"", - (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : - "SSH2_FXP_RENAME", oldpath, newpath); + use_ext ? "posix-rename@openssh.com" : "SSH2_FXP_RENAME", + oldpath, newpath); buffer_free(&msg); status = get_status(conn, id); diff --git a/sftp-client.h b/sftp-client.h index 111a998c8..dc54cfe3b 100644 --- a/sftp-client.h +++ b/sftp-client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.h,v 1.21 2013/07/25 00:56:51 djm Exp $ */ +/* $OpenBSD: sftp-client.h,v 1.22 2013/08/08 05:04:03 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller @@ -92,7 +92,7 @@ char *do_realpath(struct sftp_conn *, char *); int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); /* Rename 'oldpath' to 'newpath' */ -int do_rename(struct sftp_conn *, char *, char *); +int do_rename(struct sftp_conn *, char *, char *m, int force_legacy); /* Link 'oldpath' to 'newpath' */ int do_hardlink(struct sftp_conn *, char *, char *); diff --git a/sftp.c b/sftp.c index 6f16f7cc6..66ab2b0d4 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.151 2013/08/08 04:52:04 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.152 2013/08/08 05:04:03 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -414,6 +414,30 @@ parse_link_flags(const char *cmd, char **argv, int argc, int *sflag) return optind; } +static int +parse_rename_flags(const char *cmd, char **argv, int argc, int *lflag) +{ + extern int opterr, optind, optopt, optreset; + int ch; + + optind = optreset = 1; + opterr = 0; + + *lflag = 0; + while ((ch = getopt(argc, argv, "l")) != -1) { + switch (ch) { + case 'l': + *lflag = 1; + break; + default: + error("%s: Invalid flag -%c", cmd, optopt); + return -1; + } + } + + return optind; +} + static int parse_ls_flags(char **argv, int argc, int *lflag) { @@ -1210,8 +1234,13 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag, case I_LINK: if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1) return -1; - case I_SYMLINK: + goto parse_two_paths; case I_RENAME: + if ((optidx = parse_rename_flags(cmd, argv, argc, lflag)) == -1) + return -1; + goto parse_two_paths; + case I_SYMLINK: + parse_two_paths: if (argc - optidx < 2) { error("You must specify two paths after a %s " "command.", cmd); @@ -1353,7 +1382,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, case I_RENAME: path1 = make_absolute(path1, *pwd); path2 = make_absolute(path2, *pwd); - err = do_rename(conn, path1, path2); + err = do_rename(conn, path1, path2, lflag); break; case I_SYMLINK: sflag = 1; -- cgit v1.2.3 From fec029f1dc2c338f3fae3fa82aabc988dc07868c Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Wed, 21 Aug 2013 02:42:12 +1000 Subject: - djm@cvs.openbsd.org 2013/08/09 03:39:13 [sftp-client.c] two problems found by a to-be-committed regress test: 1) msg_id was not being initialised so was starting at a random value from the heap (harmless, but confusing). 2) some error conditions were not being propagated back to the caller --- ChangeLog | 6 ++++++ sftp-client.c | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'sftp-client.c') diff --git a/ChangeLog b/ChangeLog index f78dce6ef..7e4863029 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,6 +30,12 @@ [sftp.c] do getopt parsing for all sftp commands (with an empty optstring for commands without arguments) to ensure consistent behaviour + - djm@cvs.openbsd.org 2013/08/09 03:39:13 + [sftp-client.c] + two problems found by a to-be-committed regress test: 1) msg_id was not + being initialised so was starting at a random value from the heap + (harmless, but confusing). 2) some error conditions were not being + propagated back to the caller 20130808 - (dtucker) [regress/Makefile regress/test-exec.sh] Don't try to use test -nt diff --git a/sftp-client.c b/sftp-client.c index 0eeb73c8b..f2ce9deb7 100644 --- a/sftp-client.c +++ b/sftp-client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp-client.c,v 1.102 2013/08/08 05:04:03 djm Exp $ */ +/* $OpenBSD: sftp-client.c,v 1.103 2013/08/09 03:39:13 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -337,7 +337,8 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, Buffer msg; struct sftp_conn *ret; - ret = xmalloc(sizeof(*ret)); + ret = xcalloc(1, sizeof(*ret)); + ret->msg_id = 1; ret->fd_in = fd_in; ret->fd_out = fd_out; ret->transfer_buflen = transfer_buflen; @@ -1221,6 +1222,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, if (read_error) { error("Couldn't read from remote file \"%s\" : %s", remote_path, fx2txt(status)); + status = -1; do_close(conn, handle, handle_len); } else if (write_error) { error("Couldn't write to \"%s\": %s", local_path, @@ -1229,7 +1231,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, do_close(conn, handle, handle_len); } else { status = do_close(conn, handle, handle_len); - if (interrupted) + if (interrupted || status != SSH2_FX_OK) status = -1; /* Override umask and utimes if asked */ #ifdef HAVE_FCHMOD -- cgit v1.2.3