summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-10-17 11:48:52 +1100
committerDamien Miller <djm@mindrot.org>2013-10-17 11:48:52 +1100
commitf29238e67471a7f1088a99c3c3dbafce76b790cf (patch)
tree39ea232a72df52b4adbc3affea0108d8b0f45b42
parent51682faa599550a69d8120e5e2bdbdc0625ef4be (diff)
downloadopenssh-git-f29238e67471a7f1088a99c3c3dbafce76b790cf.tar.gz
- djm@cvs.openbsd.org 2013/10/17 00:30:13
[PROTOCOL sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c] fsync@openssh.com protocol extension for sftp-server client support to allow calling fsync() faster successful transfer patch mostly by imorgan AT nas.nasa.gov; bz#1798 "fine" markus@ "grumble OK" deraadt@ "doesn't sound bad to me" millert@
-rw-r--r--ChangeLog6
-rw-r--r--PROTOCOL16
-rw-r--r--sftp-client.c81
-rw-r--r--sftp-client.h14
-rw-r--r--sftp-server.c24
-rw-r--r--sftp.129
-rw-r--r--sftp.c65
7 files changed, 182 insertions, 53 deletions
diff --git a/ChangeLog b/ChangeLog
index 0accc41e..537f9f56 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,6 +23,12 @@
- djm@cvs.openbsd.org 2013/10/16 22:58:01
[ssh.c ssh_config.5]
one I missed in previous: s/isation/ization/
+ - djm@cvs.openbsd.org 2013/10/17 00:30:13
+ [PROTOCOL sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c]
+ fsync@openssh.com protocol extension for sftp-server
+ client support to allow calling fsync() faster successful transfer
+ patch mostly by imorgan AT nas.nasa.gov; bz#1798
+ "fine" markus@ "grumble OK" deraadt@ "doesn't sound bad to me" millert@
20131015
- (djm) OpenBSD CVS Sync
diff --git a/PROTOCOL b/PROTOCOL
index 48b3a440..0363314c 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -331,4 +331,18 @@ link(oldpath, newpath) and will respond with a SSH_FXP_STATUS message.
This extension is advertised in the SSH_FXP_VERSION hello with version
"1".
-$OpenBSD: PROTOCOL,v 1.20 2013/01/08 18:49:04 markus Exp $
+10. sftp: Extension request "fsync@openssh.com"
+
+This request asks the server to call fsync(2) on an open file handle.
+
+ uint32 id
+ string "fsync@openssh.com"
+ string handle
+
+One receiving this request, a server will call fsync(handle_fd) and will
+respond with a SSH_FXP_STATUS message.
+
+This extension is advertised in the SSH_FXP_VERSION hello with version
+"1".
+
+$OpenBSD: PROTOCOL,v 1.21 2013/10/17 00:30:13 djm Exp $
diff --git a/sftp-client.c b/sftp-client.c
index 573623b9..91955262 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.106 2013/10/11 02:52:23 djm Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.107 2013/10/17 00:30:13 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -76,6 +76,7 @@ struct sftp_conn {
#define SFTP_EXT_STATVFS 0x00000002
#define SFTP_EXT_FSTATVFS 0x00000004
#define SFTP_EXT_HARDLINK 0x00000008
+#define SFTP_EXT_FSYNC 0x00000010
u_int exts;
u_int64_t limit_kbps;
struct bwlimit bwlimit_in, bwlimit_out;
@@ -388,6 +389,10 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
strcmp(value, "1") == 0) {
ret->exts |= SFTP_EXT_HARDLINK;
known = 1;
+ } else if (strcmp(name, "fsync@openssh.com") == 0 &&
+ strcmp(value, "1") == 0) {
+ ret->exts |= SFTP_EXT_FSYNC;
+ known = 1;
}
if (known) {
debug2("Server supports extension \"%s\" revision %s",
@@ -743,7 +748,7 @@ do_realpath(struct sftp_conn *conn, char *path)
if (type == SSH2_FXP_STATUS) {
u_int status = buffer_get_int(&msg);
- error("Couldn't canonicalise: %s", fx2txt(status));
+ error("Couldn't canonicalize: %s", fx2txt(status));
buffer_free(&msg);
return NULL;
} else if (type != SSH2_FXP_NAME)
@@ -869,6 +874,36 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
return(status);
}
+int
+do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len)
+{
+ Buffer msg;
+ u_int status, id;
+
+ /* Silently return if the extension is not supported */
+ if ((conn->exts & SFTP_EXT_FSYNC) == 0)
+ return -1;
+
+ buffer_init(&msg);
+
+ /* Send fsync request */
+ id = conn->msg_id++;
+
+ buffer_put_char(&msg, SSH2_FXP_EXTENDED);
+ buffer_put_int(&msg, id);
+ buffer_put_cstring(&msg, "fsync@openssh.com");
+ buffer_put_string(&msg, handle, handle_len);
+ send_msg(conn, &msg);
+ debug3("Sent message fsync@openssh.com I:%u", id);
+ buffer_free(&msg);
+
+ status = get_status(conn, id);
+ if (status != SSH2_FX_OK)
+ error("Couldn't sync file: %s", fx2txt(status));
+
+ return status;
+}
+
#ifdef notyet
char *
do_readlink(struct sftp_conn *conn, char *path)
@@ -991,7 +1026,7 @@ 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 preserve_flag, int resume_flag)
+ Attrib *a, int preserve_flag, int resume_flag, int fsync_flag)
{
Attrib junk;
Buffer msg;
@@ -1251,6 +1286,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
error("Can't set times on \"%s\": %s",
local_path, strerror(errno));
}
+ if (fsync_flag) {
+ debug("syncing \"%s\"", local_path);
+ if (fsync(local_fd) == -1)
+ error("Couldn't sync file \"%s\": %s",
+ local_path, strerror(errno));
+ }
}
close(local_fd);
buffer_free(&msg);
@@ -1261,7 +1302,8 @@ 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, int depth,
- Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag)
+ Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
+ int fsync_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
@@ -1314,11 +1356,12 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
continue;
if (download_dir_internal(conn, new_src, new_dst,
depth + 1, &(dir_entries[i]->a), preserve_flag,
- print_flag, resume_flag) == -1)
+ print_flag, resume_flag, fsync_flag) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ) {
if (do_download(conn, new_src, new_dst,
- &(dir_entries[i]->a), preserve_flag, resume_flag) == -1) {
+ &(dir_entries[i]->a), preserve_flag,
+ resume_flag, fsync_flag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
@@ -1351,25 +1394,26 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
int
download_dir(struct sftp_conn *conn, char *src, char *dst,
- Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag)
+ Attrib *dirattrib, int preserve_flag, int print_flag,
+ int resume_flag, int fsync_flag)
{
char *src_canon;
int ret;
if ((src_canon = do_realpath(conn, src)) == NULL) {
- error("Unable to canonicalise path \"%s\"", src);
+ error("Unable to canonicalize path \"%s\"", src);
return -1;
}
ret = download_dir_internal(conn, src_canon, dst, 0,
- dirattrib, preserve_flag, print_flag, resume_flag);
+ dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
free(src_canon);
return ret;
}
int
do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
- int preserve_flag)
+ int preserve_flag, int fsync_flag)
{
int local_fd;
int status = SSH2_FX_OK;
@@ -1545,6 +1589,9 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
if (preserve_flag)
do_fsetstat(conn, handle, handle_len, &a);
+ if (fsync_flag)
+ (void)do_fsync(conn, handle, handle_len);
+
if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
status = -1;
free(handle);
@@ -1554,7 +1601,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 preserve_flag, int print_flag, int fsync_flag)
{
int ret = 0, status;
DIR *dirp;
@@ -1623,11 +1670,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) == -1)
+ depth + 1, preserve_flag, print_flag,
+ fsync_flag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode)) {
if (do_upload(conn, new_src, new_dst,
- preserve_flag) == -1) {
+ preserve_flag, fsync_flag) == -1) {
error("Uploading of file %s to %s failed!",
new_src, new_dst);
ret = -1;
@@ -1646,18 +1694,19 @@ 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 print_flag, int fsync_flag)
{
char *dst_canon;
int ret;
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
- error("Unable to canonicalise path \"%s\"", dst);
+ error("Unable to canonicalize path \"%s\"", dst);
return -1;
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
- print_flag);
+ print_flag, fsync_flag);
+
free(dst_canon);
return ret;
}
diff --git a/sftp-client.h b/sftp-client.h
index bcdd407c..ba92ad01 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.h,v 1.23 2013/10/11 02:53:45 djm Exp $ */
+/* $OpenBSD: sftp-client.h,v 1.24 2013/10/17 00:30:13 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@@ -100,29 +100,33 @@ int do_hardlink(struct sftp_conn *, char *, char *);
/* Rename 'oldpath' to 'newpath' */
int do_symlink(struct sftp_conn *, char *, char *);
+/* Call fsync() on open file 'handle' */
+int do_fsync(struct sftp_conn *conn, char *, u_int);
+
/*
* 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);
+int do_download(struct sftp_conn *, char *, char *, Attrib *, int, 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);
+int download_dir(struct sftp_conn *, char *, char *, Attrib *, int,
+ int, int, 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 do_upload(struct sftp_conn *, char *, char *, 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 upload_dir(struct sftp_conn *, char *, char *, int, int, int);
/* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(char *, char *);
diff --git a/sftp-server.c b/sftp-server.c
index 3056c454..ad158f8e 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-server.c,v 1.101 2013/10/14 23:28:23 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.102 2013/10/17 00:30:13 djm Exp $ */
/*
* Copyright (c) 2000-2004 Markus Friedl. All rights reserved.
*
@@ -112,6 +112,7 @@ static void process_extended_posix_rename(u_int32_t id);
static void process_extended_statvfs(u_int32_t id);
static void process_extended_fstatvfs(u_int32_t id);
static void process_extended_hardlink(u_int32_t id);
+static void process_extended_fsync(u_int32_t id);
static void process_extended(u_int32_t id);
struct sftp_handler {
@@ -152,6 +153,7 @@ struct sftp_handler extended_handlers[] = {
{ "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
+ { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
{ NULL, NULL, 0, NULL, 0 }
};
@@ -652,6 +654,9 @@ process_init(void)
/* hardlink extension */
buffer_put_cstring(&msg, "hardlink@openssh.com");
buffer_put_cstring(&msg, "1"); /* version */
+ /* fsync extension */
+ buffer_put_cstring(&msg, "fsync@openssh.com");
+ buffer_put_cstring(&msg, "1"); /* version */
send_msg(&msg);
buffer_free(&msg);
}
@@ -1298,6 +1303,23 @@ process_extended_hardlink(u_int32_t id)
}
static void
+process_extended_fsync(u_int32_t id)
+{
+ int handle, fd, ret, status = SSH2_FX_OP_UNSUPPORTED;
+
+ handle = get_handle();
+ debug3("request %u: fsync (handle %u)", id, handle);
+ verbose("fsync \"%s\"", handle_to_name(handle));
+ if ((fd = handle_to_fd(handle)) < 0)
+ status = SSH2_FX_NO_SUCH_FILE;
+ else if (handle_is_ok(handle, HANDLE_FILE)) {
+ ret = fsync(fd);
+ status = (ret == -1) ? errno_to_portable(errno) : SSH2_FX_OK;
+ }
+ send_status(id, status);
+}
+
+static void
process_extended(u_int32_t id)
{
char *request;
diff --git a/sftp.1 b/sftp.1
index 85d64a7f..9809bec6 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.94 2013/08/07 06:24:51 jmc Exp $
+.\" $OpenBSD: sftp.1,v 1.95 2013/10/17 00:30:13 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: August 7 2013 $
+.Dd $Mdocdate: October 17 2013 $
.Dt SFTP 1
.Os
.Sh NAME
@@ -31,7 +31,7 @@
.Sh SYNOPSIS
.Nm sftp
.Bk -words
-.Op Fl 1246aCpqrv
+.Op Fl 1246aCfpqrv
.Op Fl B Ar buffer_size
.Op Fl b Ar batchfile
.Op Fl c Ar cipher
@@ -164,6 +164,10 @@ per-user configuration file for
.Xr ssh 1 .
This option is directly passed to
.Xr ssh 1 .
+.It Fl f
+Requests that files be flushed to disk immediately after transfer.
+When uploading files, this feature is only enabled if the server
+implements the "fsync@openssh.com" extension.
.It Fl i Ar identity_file
Selects the file from which the identity (private key) for public key
authentication is read.
@@ -348,7 +352,7 @@ extension.
Quit
.Nm sftp .
.It Xo Ic get
-.Op Fl aPpr
+.Op Fl afPpr
.Ar remote-path
.Op Ar local-path
.Xc
@@ -376,6 +380,13 @@ the remote copy.
If the remote file contents differ from the partial local copy then the
resultant file is likely to be corrupt.
.Pp
+If the
+.Fl f
+flag is specified, then
+.Xr fsync 2
+will ba called after the file transfer has completed to flush the file
+to disk.
+.Pp
If either the
.Fl P
or
@@ -479,7 +490,7 @@ Create remote directory specified by
.It Ic progress
Toggle display of progress meter.
.It Xo Ic put
-.Op Fl Ppr
+.Op Fl fPpr
.Ar local-path
.Op Ar remote-path
.Xc
@@ -498,6 +509,14 @@ is specified, then
.Ar remote-path
must specify a directory.
.Pp
+If the
+.Fl f
+flag is specified, then a request will be sent to the server to call
+.Xr fsync 2
+after the file has been transferred.
+Note that this is only supported by servers that implement
+the "fsync@openssh.com" extension.
+.Pp
If either the
.Fl P
or
diff --git a/sftp.c b/sftp.c
index f7b488ae..c316e1ed 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.155 2013/08/31 00:13:54 djm Exp $ */
+/* $OpenBSD: sftp.c,v 1.156 2013/10/17 00:30:13 djm Exp $ */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -94,6 +94,9 @@ int global_aflag = 0;
/* When this option is set, the file transfers will always preserve times */
int global_pflag = 0;
+/* When this option is set, transfers will have fsync() called on each file */
+int global_fflag = 0;
+
/* SIGINT received during command processing */
volatile sig_atomic_t interrupted = 0;
@@ -359,7 +362,7 @@ make_absolute(char *p, char *pwd)
static int
parse_getput_flags(const char *cmd, char **argv, int argc,
- int *aflag, int *pflag, int *rflag)
+ int *aflag, int *fflag, int *pflag, int *rflag)
{
extern int opterr, optind, optopt, optreset;
int ch;
@@ -367,12 +370,15 @@ parse_getput_flags(const char *cmd, char **argv, int argc,
optind = optreset = 1;
opterr = 0;
- *aflag = *rflag = *pflag = 0;
- while ((ch = getopt(argc, argv, "aPpRr")) != -1) {
+ *aflag = *fflag = *rflag = *pflag = 0;
+ while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
switch (ch) {
case 'a':
*aflag = 1;
break;
+ case 'f':
+ *fflag = 1;
+ break;
case 'p':
case 'P':
*pflag = 1;
@@ -574,7 +580,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 resume)
+ int pflag, int rflag, int resume, int fflag)
{
char *abs_src = NULL;
char *abs_dst = NULL;
@@ -633,11 +639,13 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
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, resume) == -1)
+ pflag || global_pflag, 1, resume,
+ fflag || global_fflag) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag || global_pflag, resume) == -1)
+ pflag || global_pflag, resume,
+ fflag || global_fflag) == -1)
err = -1;
}
free(abs_dst);
@@ -652,7 +660,7 @@ out:
static int
process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
- int pflag, int rflag)
+ int pflag, int rflag, int fflag)
{
char *tmp_dst = NULL;
char *abs_dst = NULL;
@@ -719,11 +727,13 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
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) == -1)
+ pflag || global_pflag, 1,
+ fflag || global_fflag) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
- pflag || global_pflag) == -1)
+ pflag || global_pflag,
+ fflag || global_fflag) == -1)
err = -1;
}
}
@@ -1176,9 +1186,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
}
static int
-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)
+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;
char *cp2, **argv;
@@ -1190,9 +1200,9 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
cp = cp + strspn(cp, WHITESPACE);
/* Check for leading '-' (disable error processing) */
- *iflag = 0;
+ *ignore_errors = 0;
if (*cp == '-') {
- *iflag = 1;
+ *ignore_errors = 1;
cp++;
cp = cp + strspn(cp, WHITESPACE);
}
@@ -1222,7 +1232,8 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
}
/* Get arguments and parse flags */
- *aflag = *lflag = *pflag = *rflag = *hflag = *n_arg = 0;
+ *aflag = *fflag = *hflag = *iflag = *lflag = *pflag = 0;
+ *rflag = *sflag = 0;
*path1 = *path2 = NULL;
optidx = 1;
switch (cmdnum) {
@@ -1230,7 +1241,7 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
case I_REGET:
case I_PUT:
if ((optidx = parse_getput_flags(cmd, argv, argc,
- aflag, pflag, rflag)) == -1)
+ aflag, fflag, pflag, rflag)) == -1)
return -1;
/* Get first pathname (mandatory) */
if (argc - optidx < 1) {
@@ -1371,8 +1382,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int err_abort)
{
char *path1, *path2, *tmp;
- int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0;
- int rflag = 0, sflag = 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;
Attrib a, *aa;
@@ -1381,9 +1392,9 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
glob_t g;
path1 = path2 = NULL;
- cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag,
- &rflag, &sflag, &n_arg, &path1, &path2);
- if (iflag != 0)
+ cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
+ &iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
+ if (ignore_errors != 0)
err_abort = 0;
memset(&g, 0, sizeof(g));
@@ -1402,10 +1413,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
/* FALLTHROUGH */
case I_GET:
err = process_get(conn, path1, path2, *pwd, pflag,
- rflag, aflag);
+ rflag, aflag, fflag);
break;
case I_PUT:
- err = process_put(conn, path1, path2, *pwd, pflag, rflag);
+ err = process_put(conn, path1, path2, *pwd, pflag,
+ rflag, fflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
@@ -2231,7 +2243,7 @@ main(int argc, char **argv)
infile = stdin;
while ((ch = getopt(argc, argv,
- "1246ahpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
+ "1246afhpqrvCc:D:i:l:o:s:S:b:B:F:P:R:")) != -1) {
switch (ch) {
/* Passed through to ssh(1) */
case '4':
@@ -2291,6 +2303,9 @@ main(int argc, char **argv)
quiet = batchmode = 1;
addargs(&args, "-obatchmode yes");
break;
+ case 'f':
+ global_fflag = 1;
+ break;
case 'p':
global_pflag = 1;
break;