Bugzilla – Attachment 3494 Details for
Bug 2948
implement "copy-data" sftp extension
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
sftp server copy-data extension v2
0001-sftp-server-support-copy-data-request.patch (text/plain), 6.86 KB, created by
Mike Frysinger
on 2021-04-05 00:57:55 AEST
(
hide
)
Description:
sftp server copy-data extension v2
Filename:
MIME Type:
Creator:
Mike Frysinger
Created:
2021-04-05 00:57:55 AEST
Size:
6.86 KB
patch
obsolete
>From b0be085aa727dad8b806e41217f4a319a5a24ff9 Mon Sep 17 00:00:00 2001 >From: Mike Frysinger <vapier@chromium.org> >Date: Wed, 24 Oct 2018 23:20:34 -0400 >Subject: [PATCH 1/2] sftp-server: support copy-data request > >Add support to the sftp-server for the copy-data extension defined in >[1]. This provides for efficient copying on the server side otherwise >clients have to emulate it by downloading the file before uploading it >to the new path. For large files or slow networks, this can be >prohibitively slow. Now doing a file copy is limited only by the server >I/O. > >For clients that provide virtual file systems on top of SFTP, this can >provide significant performance gains. > >[1] https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7 >--- > PROTOCOL | 39 +++++++++++++++++++++- > sftp-server.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 130 insertions(+), 1 deletion(-) > >diff --git a/PROTOCOL b/PROTOCOL >index 0b2ea60a74ba..47b69078cc64 100644 >--- a/PROTOCOL >+++ b/PROTOCOL >@@ -460,7 +460,7 @@ This request asks the server to call fsync(2) on an open file handle. > string "fsync@openssh.com" > string handle > >-One receiving this request, a server will call fsync(handle_fd) and will >+On 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 >@@ -525,6 +525,43 @@ limits. > This extension is advertised in the SSH_FXP_VERSION hello with version > "1". > >+3.8. sftp: Extension request "copy-data" >+ >+This request asks the server to copy data from one open file handle and >+write it to a different open file handle. This avoids needing to transfer >+the data across the network twice (a download followed by an upload). >+ >+ byte SSH_FXP_EXTENDED >+ uint32 id >+ string "copy-data" >+ string read-from-handle >+ uint64 read-from-offset >+ uint64 read-data-length >+ string write-to-handle >+ uint64 write-to-offset >+ >+The server will copy read-data-length bytes starting from >+read-from-offset from the read-from-handle and write them to >+write-to-handle starting from write-to-offset, and then respond with a >+SSH_FXP_STATUS message. >+ >+It's equivalent to issuing a series of SSH_FXP_READ requests on >+read-from-handle and a series of requests of SSH_FXP_WRITE on >+write-to-handle. >+ >+If read-from-handle and write-to-handle are the same, the server will >+fail the request and respond with a SSH_FX_INVALID_PARAMETER message. >+ >+If read-data-length is 0, then the server will read data from the >+read-from-handle until EOF is reached. >+ >+This extension is advertised in the SSH_FXP_VERSION hello with version >+"1". >+ >+This request is identical to the "copy-data" request documented in: >+ >+https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7 >+ > 4. Miscellaneous changes > > 4.1 Public key format >diff --git a/sftp-server.c b/sftp-server.c >index cce52dbc2f11..06e10a23a8e7 100644 >--- a/sftp-server.c >+++ b/sftp-server.c >@@ -41,6 +41,7 @@ > #include <unistd.h> > #include <stdarg.h> > >+#include "atomicio.h" > #include "xmalloc.h" > #include "sshbuf.h" > #include "ssherr.h" >@@ -115,6 +116,7 @@ static void process_extended_hardlink(u_int32_t id); > static void process_extended_fsync(u_int32_t id); > static void process_extended_lsetstat(u_int32_t id); > static void process_extended_limits(u_int32_t id); >+static void process_extended_copy_data(u_int32_t id); > static void process_extended(u_int32_t id); > > struct sftp_handler { >@@ -158,6 +160,7 @@ static const struct sftp_handler extended_handlers[] = { > { "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 }, > { "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 }, > { "limits", "limits@openssh.com", 0, process_extended_limits, 1 }, >+ { "copy-data", "copy-data", 0, process_extended_copy_data, 1 }, > { NULL, NULL, 0, NULL, 0 } > }; > >@@ -706,6 +709,7 @@ process_init(void) > compose_extension(msg, "fsync@openssh.com", "1"); > compose_extension(msg, "lsetstat@openssh.com", "1"); > compose_extension(msg, "limits@openssh.com", "1"); >+ compose_extension(msg, "copy-data", "1"); > > send_msg(msg); > sshbuf_free(msg); >@@ -1515,6 +1519,94 @@ process_extended_limits(u_int32_t id) > sshbuf_free(msg); > } > >+static void >+process_extended_copy_data(u_int32_t id) >+{ >+ u_char buf[64*1024]; >+ int read_handle, read_fd, write_handle, write_fd; >+ u_int64_t len, read_off, read_len, write_off; >+ int r, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED; >+ size_t ret; >+ >+ if ((r = get_handle(iqueue, &read_handle)) != 0 || >+ (r = sshbuf_get_u64(iqueue, &read_off)) != 0 || >+ (r = sshbuf_get_u64(iqueue, &read_len)) != 0 || >+ (r = get_handle(iqueue, &write_handle)) != 0 || >+ (r = sshbuf_get_u64(iqueue, &write_off)) != 0) >+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); >+ >+ debug("request %u: copy-data from \"%s\" (handle %d) off %llu len %llu " >+ "to \"%s\" (handle %d) off %llu", >+ id, handle_to_name(read_handle), read_handle, >+ (unsigned long long)read_off, (unsigned long long)read_len, >+ handle_to_name(write_handle), write_handle, >+ (unsigned long long)write_off); >+ >+ /* For read length of 0, we read until EOF. */ >+ if (read_len == 0) { >+ read_len = (u_int64_t)-1 - read_off; >+ copy_until_eof = 1; >+ } else >+ copy_until_eof = 0; >+ >+ read_fd = handle_to_fd(read_handle); >+ write_fd = handle_to_fd(write_handle); >+ >+ /* Disallow reading & writing to the same handle or same path or dirs */ >+ if (read_handle == write_handle || read_fd < 0 || write_fd < 0 || >+ !strcmp(handle_to_name(read_handle), handle_to_name(write_handle))) { >+ status = SSH2_FX_FAILURE; >+ goto out; >+ } >+ >+ if (lseek(read_fd, read_off, SEEK_SET) < 0) { >+ status = errno_to_portable(errno); >+ error("%s: read_seek failed", __func__); >+ goto out; >+ } >+ >+ if (!(handle_to_flags(write_handle) & O_APPEND) && >+ lseek(write_fd, write_off, SEEK_SET) < 0) { >+ status = errno_to_portable(errno); >+ error("%s: write_seek failed", __func__); >+ goto out; >+ } >+ >+ /* Process the request in chunks. */ >+ while (read_len > 0 || copy_until_eof) { >+ len = MINIMUM(sizeof(buf), read_len); >+ read_len -= len; >+ >+ ret = atomicio(read, read_fd, buf, len); >+ if (ret == 0 && errno == EPIPE) { >+ status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF; >+ break; >+ } else if (ret == 0) { >+ status = errno_to_portable(errno); >+ error("%s: read failed: %s", __func__, strerror(errno)); >+ break; >+ } >+ len = ret; >+ handle_update_read(read_handle, len); >+ >+ ret = atomicio(vwrite, write_fd, buf, len); >+ if (ret != len) { >+ status = errno_to_portable(errno); >+ error("%s: write failed: %llu != %llu: %s", __func__, >+ (unsigned long long)ret, (unsigned long long)len, >+ strerror(errno)); >+ break; >+ } >+ handle_update_write(write_handle, len); >+ } >+ >+ if (read_len == 0) >+ status = SSH2_FX_OK; >+ >+ out: >+ send_status(id, status); >+} >+ > static void > process_extended(u_int32_t id) > { >-- >2.30.2 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2948
:
3344
|
3345
| 3494 |
3495