mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-28 16:24:39 +02:00
- 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@
This commit is contained in:
parent
51682faa59
commit
f29238e674
@ -23,6 +23,12 @@
|
|||||||
- djm@cvs.openbsd.org 2013/10/16 22:58:01
|
- djm@cvs.openbsd.org 2013/10/16 22:58:01
|
||||||
[ssh.c ssh_config.5]
|
[ssh.c ssh_config.5]
|
||||||
one I missed in previous: s/isation/ization/
|
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
|
20131015
|
||||||
- (djm) OpenBSD CVS Sync
|
- (djm) OpenBSD CVS Sync
|
||||||
|
16
PROTOCOL
16
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
|
This extension is advertised in the SSH_FXP_VERSION hello with version
|
||||||
"1".
|
"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 $
|
||||||
|
@ -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>
|
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
|
||||||
*
|
*
|
||||||
@ -76,6 +76,7 @@ struct sftp_conn {
|
|||||||
#define SFTP_EXT_STATVFS 0x00000002
|
#define SFTP_EXT_STATVFS 0x00000002
|
||||||
#define SFTP_EXT_FSTATVFS 0x00000004
|
#define SFTP_EXT_FSTATVFS 0x00000004
|
||||||
#define SFTP_EXT_HARDLINK 0x00000008
|
#define SFTP_EXT_HARDLINK 0x00000008
|
||||||
|
#define SFTP_EXT_FSYNC 0x00000010
|
||||||
u_int exts;
|
u_int exts;
|
||||||
u_int64_t limit_kbps;
|
u_int64_t limit_kbps;
|
||||||
struct bwlimit bwlimit_in, bwlimit_out;
|
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) {
|
strcmp(value, "1") == 0) {
|
||||||
ret->exts |= SFTP_EXT_HARDLINK;
|
ret->exts |= SFTP_EXT_HARDLINK;
|
||||||
known = 1;
|
known = 1;
|
||||||
|
} else if (strcmp(name, "fsync@openssh.com") == 0 &&
|
||||||
|
strcmp(value, "1") == 0) {
|
||||||
|
ret->exts |= SFTP_EXT_FSYNC;
|
||||||
|
known = 1;
|
||||||
}
|
}
|
||||||
if (known) {
|
if (known) {
|
||||||
debug2("Server supports extension \"%s\" revision %s",
|
debug2("Server supports extension \"%s\" revision %s",
|
||||||
@ -743,7 +748,7 @@ do_realpath(struct sftp_conn *conn, char *path)
|
|||||||
if (type == SSH2_FXP_STATUS) {
|
if (type == SSH2_FXP_STATUS) {
|
||||||
u_int status = buffer_get_int(&msg);
|
u_int status = buffer_get_int(&msg);
|
||||||
|
|
||||||
error("Couldn't canonicalise: %s", fx2txt(status));
|
error("Couldn't canonicalize: %s", fx2txt(status));
|
||||||
buffer_free(&msg);
|
buffer_free(&msg);
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (type != SSH2_FXP_NAME)
|
} else if (type != SSH2_FXP_NAME)
|
||||||
@ -869,6 +874,36 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
|
|||||||
return(status);
|
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
|
#ifdef notyet
|
||||||
char *
|
char *
|
||||||
do_readlink(struct sftp_conn *conn, char *path)
|
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
|
int
|
||||||
do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
|
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;
|
Attrib junk;
|
||||||
Buffer msg;
|
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",
|
error("Can't set times on \"%s\": %s",
|
||||||
local_path, strerror(errno));
|
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);
|
close(local_fd);
|
||||||
buffer_free(&msg);
|
buffer_free(&msg);
|
||||||
@ -1261,7 +1302,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
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;
|
int i, ret = 0;
|
||||||
SFTP_DIRENT **dir_entries;
|
SFTP_DIRENT **dir_entries;
|
||||||
@ -1314,11 +1356,12 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
|||||||
continue;
|
continue;
|
||||||
if (download_dir_internal(conn, new_src, new_dst,
|
if (download_dir_internal(conn, new_src, new_dst,
|
||||||
depth + 1, &(dir_entries[i]->a), preserve_flag,
|
depth + 1, &(dir_entries[i]->a), preserve_flag,
|
||||||
print_flag, resume_flag) == -1)
|
print_flag, resume_flag, fsync_flag) == -1)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
} else if (S_ISREG(dir_entries[i]->a.perm) ) {
|
} else if (S_ISREG(dir_entries[i]->a.perm) ) {
|
||||||
if (do_download(conn, new_src, new_dst,
|
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",
|
error("Download of file %s to %s failed",
|
||||||
new_src, new_dst);
|
new_src, new_dst);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@ -1351,25 +1394,26 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
|||||||
|
|
||||||
int
|
int
|
||||||
download_dir(struct sftp_conn *conn, char *src, char *dst,
|
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;
|
char *src_canon;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((src_canon = do_realpath(conn, src)) == NULL) {
|
if ((src_canon = do_realpath(conn, src)) == NULL) {
|
||||||
error("Unable to canonicalise path \"%s\"", src);
|
error("Unable to canonicalize path \"%s\"", src);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = download_dir_internal(conn, src_canon, dst, 0,
|
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);
|
free(src_canon);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
|
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 local_fd;
|
||||||
int status = SSH2_FX_OK;
|
int status = SSH2_FX_OK;
|
||||||
@ -1545,6 +1589,9 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
|
|||||||
if (preserve_flag)
|
if (preserve_flag)
|
||||||
do_fsetstat(conn, handle, handle_len, &a);
|
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)
|
if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
|
||||||
status = -1;
|
status = -1;
|
||||||
free(handle);
|
free(handle);
|
||||||
@ -1554,7 +1601,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
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;
|
int ret = 0, status;
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
@ -1623,11 +1670,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (upload_dir_internal(conn, new_src, new_dst,
|
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;
|
ret = -1;
|
||||||
} else if (S_ISREG(sb.st_mode)) {
|
} else if (S_ISREG(sb.st_mode)) {
|
||||||
if (do_upload(conn, new_src, new_dst,
|
if (do_upload(conn, new_src, new_dst,
|
||||||
preserve_flag) == -1) {
|
preserve_flag, fsync_flag) == -1) {
|
||||||
error("Uploading of file %s to %s failed!",
|
error("Uploading of file %s to %s failed!",
|
||||||
new_src, new_dst);
|
new_src, new_dst);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@ -1646,18 +1694,19 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
|
|||||||
|
|
||||||
int
|
int
|
||||||
upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
|
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;
|
char *dst_canon;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
|
if ((dst_canon = do_realpath(conn, dst)) == NULL) {
|
||||||
error("Unable to canonicalise path \"%s\"", dst);
|
error("Unable to canonicalize path \"%s\"", dst);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
|
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
|
||||||
print_flag);
|
print_flag, fsync_flag);
|
||||||
|
|
||||||
free(dst_canon);
|
free(dst_canon);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -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>
|
* 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' */
|
/* Rename 'oldpath' to 'newpath' */
|
||||||
int do_symlink(struct sftp_conn *, char *, char *);
|
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
|
* Download 'remote_path' to 'local_path'. Preserve permissions and times
|
||||||
* if 'pflag' is set
|
* 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
|
* Recursively download 'remote_directory' to 'local_directory'. Preserve
|
||||||
* times if 'pflag' is set
|
* 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
|
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
|
||||||
* if 'pflag' is set
|
* 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
|
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
|
||||||
* times if 'pflag' is set
|
* 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. */
|
/* Concatenate paths, taking care of slashes. Caller must free result. */
|
||||||
char *path_append(char *, char *);
|
char *path_append(char *, char *);
|
||||||
|
@ -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.
|
* 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_statvfs(u_int32_t id);
|
||||||
static void process_extended_fstatvfs(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_hardlink(u_int32_t id);
|
||||||
|
static void process_extended_fsync(u_int32_t id);
|
||||||
static void process_extended(u_int32_t id);
|
static void process_extended(u_int32_t id);
|
||||||
|
|
||||||
struct sftp_handler {
|
struct sftp_handler {
|
||||||
@ -152,6 +153,7 @@ struct sftp_handler extended_handlers[] = {
|
|||||||
{ "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
|
{ "statvfs", "statvfs@openssh.com", 0, process_extended_statvfs, 0 },
|
||||||
{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
|
{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
|
||||||
{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
|
{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
|
||||||
|
{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
|
||||||
{ NULL, NULL, 0, NULL, 0 }
|
{ NULL, NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -652,6 +654,9 @@ process_init(void)
|
|||||||
/* hardlink extension */
|
/* hardlink extension */
|
||||||
buffer_put_cstring(&msg, "hardlink@openssh.com");
|
buffer_put_cstring(&msg, "hardlink@openssh.com");
|
||||||
buffer_put_cstring(&msg, "1"); /* version */
|
buffer_put_cstring(&msg, "1"); /* version */
|
||||||
|
/* fsync extension */
|
||||||
|
buffer_put_cstring(&msg, "fsync@openssh.com");
|
||||||
|
buffer_put_cstring(&msg, "1"); /* version */
|
||||||
send_msg(&msg);
|
send_msg(&msg);
|
||||||
buffer_free(&msg);
|
buffer_free(&msg);
|
||||||
}
|
}
|
||||||
@ -1297,6 +1302,23 @@ process_extended_hardlink(u_int32_t id)
|
|||||||
free(newpath);
|
free(newpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
static void
|
||||||
process_extended(u_int32_t id)
|
process_extended(u_int32_t id)
|
||||||
{
|
{
|
||||||
|
29
sftp.1
29
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.
|
.\" 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
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.Dd $Mdocdate: August 7 2013 $
|
.Dd $Mdocdate: October 17 2013 $
|
||||||
.Dt SFTP 1
|
.Dt SFTP 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -31,7 +31,7 @@
|
|||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm sftp
|
.Nm sftp
|
||||||
.Bk -words
|
.Bk -words
|
||||||
.Op Fl 1246aCpqrv
|
.Op Fl 1246aCfpqrv
|
||||||
.Op Fl B Ar buffer_size
|
.Op Fl B Ar buffer_size
|
||||||
.Op Fl b Ar batchfile
|
.Op Fl b Ar batchfile
|
||||||
.Op Fl c Ar cipher
|
.Op Fl c Ar cipher
|
||||||
@ -164,6 +164,10 @@ per-user configuration file for
|
|||||||
.Xr ssh 1 .
|
.Xr ssh 1 .
|
||||||
This option is directly passed to
|
This option is directly passed to
|
||||||
.Xr ssh 1 .
|
.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
|
.It Fl i Ar identity_file
|
||||||
Selects the file from which the identity (private key) for public key
|
Selects the file from which the identity (private key) for public key
|
||||||
authentication is read.
|
authentication is read.
|
||||||
@ -348,7 +352,7 @@ extension.
|
|||||||
Quit
|
Quit
|
||||||
.Nm sftp .
|
.Nm sftp .
|
||||||
.It Xo Ic get
|
.It Xo Ic get
|
||||||
.Op Fl aPpr
|
.Op Fl afPpr
|
||||||
.Ar remote-path
|
.Ar remote-path
|
||||||
.Op Ar local-path
|
.Op Ar local-path
|
||||||
.Xc
|
.Xc
|
||||||
@ -376,6 +380,13 @@ the remote copy.
|
|||||||
If the remote file contents differ from the partial local copy then the
|
If the remote file contents differ from the partial local copy then the
|
||||||
resultant file is likely to be corrupt.
|
resultant file is likely to be corrupt.
|
||||||
.Pp
|
.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
|
If either the
|
||||||
.Fl P
|
.Fl P
|
||||||
or
|
or
|
||||||
@ -479,7 +490,7 @@ Create remote directory specified by
|
|||||||
.It Ic progress
|
.It Ic progress
|
||||||
Toggle display of progress meter.
|
Toggle display of progress meter.
|
||||||
.It Xo Ic put
|
.It Xo Ic put
|
||||||
.Op Fl Ppr
|
.Op Fl fPpr
|
||||||
.Ar local-path
|
.Ar local-path
|
||||||
.Op Ar remote-path
|
.Op Ar remote-path
|
||||||
.Xc
|
.Xc
|
||||||
@ -498,6 +509,14 @@ is specified, then
|
|||||||
.Ar remote-path
|
.Ar remote-path
|
||||||
must specify a directory.
|
must specify a directory.
|
||||||
.Pp
|
.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
|
If either the
|
||||||
.Fl P
|
.Fl P
|
||||||
or
|
or
|
||||||
|
65
sftp.c
65
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>
|
* 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 */
|
/* When this option is set, the file transfers will always preserve times */
|
||||||
int global_pflag = 0;
|
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 */
|
/* SIGINT received during command processing */
|
||||||
volatile sig_atomic_t interrupted = 0;
|
volatile sig_atomic_t interrupted = 0;
|
||||||
|
|
||||||
@ -359,7 +362,7 @@ make_absolute(char *p, char *pwd)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
parse_getput_flags(const char *cmd, char **argv, int argc,
|
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;
|
extern int opterr, optind, optopt, optreset;
|
||||||
int ch;
|
int ch;
|
||||||
@ -367,12 +370,15 @@ parse_getput_flags(const char *cmd, char **argv, int argc,
|
|||||||
optind = optreset = 1;
|
optind = optreset = 1;
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
*aflag = *rflag = *pflag = 0;
|
*aflag = *fflag = *rflag = *pflag = 0;
|
||||||
while ((ch = getopt(argc, argv, "aPpRr")) != -1) {
|
while ((ch = getopt(argc, argv, "afPpRr")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'a':
|
case 'a':
|
||||||
*aflag = 1;
|
*aflag = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
*fflag = 1;
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
case 'P':
|
case 'P':
|
||||||
*pflag = 1;
|
*pflag = 1;
|
||||||
@ -574,7 +580,7 @@ pathname_is_dir(char *pathname)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd,
|
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_src = NULL;
|
||||||
char *abs_dst = 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);
|
printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
|
||||||
if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
|
if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
|
||||||
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
|
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;
|
err = -1;
|
||||||
} else {
|
} else {
|
||||||
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
|
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;
|
err = -1;
|
||||||
}
|
}
|
||||||
free(abs_dst);
|
free(abs_dst);
|
||||||
@ -652,7 +660,7 @@ out:
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd,
|
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 *tmp_dst = NULL;
|
||||||
char *abs_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);
|
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
|
||||||
if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
|
if (pathname_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
|
||||||
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
|
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;
|
err = -1;
|
||||||
} else {
|
} else {
|
||||||
if (do_upload(conn, g.gl_pathv[i], abs_dst,
|
if (do_upload(conn, g.gl_pathv[i], abs_dst,
|
||||||
pflag || global_pflag) == -1)
|
pflag || global_pflag,
|
||||||
|
fflag || global_fflag) == -1)
|
||||||
err = -1;
|
err = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1176,9 +1186,9 @@ makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
|
parse_args(const char **cpp, int *ignore_errors, int *aflag, int *fflag,
|
||||||
int *pflag, int *rflag, int *sflag, unsigned long *n_arg,
|
int *hflag, int *iflag, int *lflag, int *pflag, int *rflag, int *sflag,
|
||||||
char **path1, char **path2)
|
unsigned long *n_arg, char **path1, char **path2)
|
||||||
{
|
{
|
||||||
const char *cmd, *cp = *cpp;
|
const char *cmd, *cp = *cpp;
|
||||||
char *cp2, **argv;
|
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);
|
cp = cp + strspn(cp, WHITESPACE);
|
||||||
|
|
||||||
/* Check for leading '-' (disable error processing) */
|
/* Check for leading '-' (disable error processing) */
|
||||||
*iflag = 0;
|
*ignore_errors = 0;
|
||||||
if (*cp == '-') {
|
if (*cp == '-') {
|
||||||
*iflag = 1;
|
*ignore_errors = 1;
|
||||||
cp++;
|
cp++;
|
||||||
cp = cp + strspn(cp, WHITESPACE);
|
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 */
|
/* 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;
|
*path1 = *path2 = NULL;
|
||||||
optidx = 1;
|
optidx = 1;
|
||||||
switch (cmdnum) {
|
switch (cmdnum) {
|
||||||
@ -1230,7 +1241,7 @@ parse_args(const char **cpp, int *aflag, int *hflag, int *iflag, int *lflag,
|
|||||||
case I_REGET:
|
case I_REGET:
|
||||||
case I_PUT:
|
case I_PUT:
|
||||||
if ((optidx = parse_getput_flags(cmd, argv, argc,
|
if ((optidx = parse_getput_flags(cmd, argv, argc,
|
||||||
aflag, pflag, rflag)) == -1)
|
aflag, fflag, pflag, rflag)) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
/* Get first pathname (mandatory) */
|
/* Get first pathname (mandatory) */
|
||||||
if (argc - optidx < 1) {
|
if (argc - optidx < 1) {
|
||||||
@ -1371,8 +1382,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||||||
int err_abort)
|
int err_abort)
|
||||||
{
|
{
|
||||||
char *path1, *path2, *tmp;
|
char *path1, *path2, *tmp;
|
||||||
int aflag = 0, hflag = 0, iflag = 0, lflag = 0, pflag = 0;
|
int ignore_errors = 0, aflag = 0, fflag = 0, hflag = 0, iflag = 0;
|
||||||
int rflag = 0, sflag = 0;
|
int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
|
||||||
int cmdnum, i;
|
int cmdnum, i;
|
||||||
unsigned long n_arg = 0;
|
unsigned long n_arg = 0;
|
||||||
Attrib a, *aa;
|
Attrib a, *aa;
|
||||||
@ -1381,9 +1392,9 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||||||
glob_t g;
|
glob_t g;
|
||||||
|
|
||||||
path1 = path2 = NULL;
|
path1 = path2 = NULL;
|
||||||
cmdnum = parse_args(&cmd, &aflag, &hflag, &iflag, &lflag, &pflag,
|
cmdnum = parse_args(&cmd, &ignore_errors, &aflag, &fflag, &hflag,
|
||||||
&rflag, &sflag, &n_arg, &path1, &path2);
|
&iflag, &lflag, &pflag, &rflag, &sflag, &n_arg, &path1, &path2);
|
||||||
if (iflag != 0)
|
if (ignore_errors != 0)
|
||||||
err_abort = 0;
|
err_abort = 0;
|
||||||
|
|
||||||
memset(&g, 0, sizeof(g));
|
memset(&g, 0, sizeof(g));
|
||||||
@ -1402,10 +1413,11 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
|
|||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case I_GET:
|
case I_GET:
|
||||||
err = process_get(conn, path1, path2, *pwd, pflag,
|
err = process_get(conn, path1, path2, *pwd, pflag,
|
||||||
rflag, aflag);
|
rflag, aflag, fflag);
|
||||||
break;
|
break;
|
||||||
case I_PUT:
|
case I_PUT:
|
||||||
err = process_put(conn, path1, path2, *pwd, pflag, rflag);
|
err = process_put(conn, path1, path2, *pwd, pflag,
|
||||||
|
rflag, fflag);
|
||||||
break;
|
break;
|
||||||
case I_RENAME:
|
case I_RENAME:
|
||||||
path1 = make_absolute(path1, *pwd);
|
path1 = make_absolute(path1, *pwd);
|
||||||
@ -2231,7 +2243,7 @@ main(int argc, char **argv)
|
|||||||
infile = stdin;
|
infile = stdin;
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv,
|
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) {
|
switch (ch) {
|
||||||
/* Passed through to ssh(1) */
|
/* Passed through to ssh(1) */
|
||||||
case '4':
|
case '4':
|
||||||
@ -2291,6 +2303,9 @@ main(int argc, char **argv)
|
|||||||
quiet = batchmode = 1;
|
quiet = batchmode = 1;
|
||||||
addargs(&args, "-obatchmode yes");
|
addargs(&args, "-obatchmode yes");
|
||||||
break;
|
break;
|
||||||
|
case 'f':
|
||||||
|
global_fflag = 1;
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
global_pflag = 1;
|
global_pflag = 1;
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user