View | Details | Raw Unified | Return to bug 2948 | Differences between
and this patch

Collapse All | Expand All

(-)a/PROTOCOL (-1 / +38 lines)
Lines 460-466 This request asks the server to call fsync(2) on an open file handle. Link Here
460
	string		"fsync@openssh.com"
460
	string		"fsync@openssh.com"
461
	string		handle
461
	string		handle
462
462
463
One receiving this request, a server will call fsync(handle_fd) and will
463
On receiving this request, a server will call fsync(handle_fd) and will
464
respond with a SSH_FXP_STATUS message.
464
respond with a SSH_FXP_STATUS message.
465
465
466
This extension is advertised in the SSH_FXP_VERSION hello with version
466
This extension is advertised in the SSH_FXP_VERSION hello with version
Lines 525-530 limits. Link Here
525
This extension is advertised in the SSH_FXP_VERSION hello with version
525
This extension is advertised in the SSH_FXP_VERSION hello with version
526
"1".
526
"1".
527
527
528
3.8. sftp: Extension request "copy-data"
529
530
This request asks the server to copy data from one open file handle and
531
write it to a different open file handle.  This avoids needing to transfer
532
the data across the network twice (a download followed by an upload).
533
534
	byte		SSH_FXP_EXTENDED
535
	uint32		id
536
	string		"copy-data"
537
	string		read-from-handle
538
	uint64		read-from-offset
539
	uint64		read-data-length
540
	string		write-to-handle
541
	uint64		write-to-offset
542
543
The server will copy read-data-length bytes starting from
544
read-from-offset from the read-from-handle and write them to
545
write-to-handle starting from write-to-offset, and then respond with a
546
SSH_FXP_STATUS message.
547
548
It's equivalent to issuing a series of SSH_FXP_READ requests on
549
read-from-handle and a series of requests of SSH_FXP_WRITE on
550
write-to-handle.
551
552
If read-from-handle and write-to-handle are the same, the server will
553
fail the request and respond with a SSH_FX_INVALID_PARAMETER message.
554
555
If read-data-length is 0, then the server will read data from the
556
read-from-handle until EOF is reached.
557
558
This extension is advertised in the SSH_FXP_VERSION hello with version
559
"1".
560
561
This request is identical to the "copy-data" request documented in:
562
563
https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7
564
528
4. Miscellaneous changes
565
4. Miscellaneous changes
529
566
530
4.1 Public key format
567
4.1 Public key format
(-)a/sftp-server.c (-1 / +92 lines)
Lines 41-46 Link Here
41
#include <unistd.h>
41
#include <unistd.h>
42
#include <stdarg.h>
42
#include <stdarg.h>
43
43
44
#include "atomicio.h"
44
#include "xmalloc.h"
45
#include "xmalloc.h"
45
#include "sshbuf.h"
46
#include "sshbuf.h"
46
#include "ssherr.h"
47
#include "ssherr.h"
Lines 115-120 static void process_extended_hardlink(u_int32_t id); Link Here
115
static void process_extended_fsync(u_int32_t id);
116
static void process_extended_fsync(u_int32_t id);
116
static void process_extended_lsetstat(u_int32_t id);
117
static void process_extended_lsetstat(u_int32_t id);
117
static void process_extended_limits(u_int32_t id);
118
static void process_extended_limits(u_int32_t id);
119
static void process_extended_copy_data(u_int32_t id);
118
static void process_extended(u_int32_t id);
120
static void process_extended(u_int32_t id);
119
121
120
struct sftp_handler {
122
struct sftp_handler {
Lines 158-163 static const struct sftp_handler extended_handlers[] = { Link Here
158
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
160
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
159
	{ "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
161
	{ "lsetstat", "lsetstat@openssh.com", 0, process_extended_lsetstat, 1 },
160
	{ "limits", "limits@openssh.com", 0, process_extended_limits, 1 },
162
	{ "limits", "limits@openssh.com", 0, process_extended_limits, 1 },
163
	{ "copy-data", "copy-data", 0, process_extended_copy_data, 1 },
161
	{ NULL, NULL, 0, NULL, 0 }
164
	{ NULL, NULL, 0, NULL, 0 }
162
};
165
};
163
166
Lines 706-711 process_init(void) Link Here
706
	compose_extension(msg, "fsync@openssh.com", "1");
709
	compose_extension(msg, "fsync@openssh.com", "1");
707
	compose_extension(msg, "lsetstat@openssh.com", "1");
710
	compose_extension(msg, "lsetstat@openssh.com", "1");
708
	compose_extension(msg, "limits@openssh.com", "1");
711
	compose_extension(msg, "limits@openssh.com", "1");
712
	compose_extension(msg, "copy-data", "1");
709
713
710
	send_msg(msg);
714
	send_msg(msg);
711
	sshbuf_free(msg);
715
	sshbuf_free(msg);
Lines 1515-1520 process_extended_limits(u_int32_t id) Link Here
1515
	sshbuf_free(msg);
1519
	sshbuf_free(msg);
1516
}
1520
}
1517
1521
1522
static void
1523
process_extended_copy_data(u_int32_t id)
1524
{
1525
	u_char buf[64*1024];
1526
	int read_handle, read_fd, write_handle, write_fd;
1527
	u_int64_t len, read_off, read_len, write_off;
1528
	int r, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED;
1529
	size_t ret;
1530
1531
	if ((r = get_handle(iqueue, &read_handle)) != 0 ||
1532
	    (r = sshbuf_get_u64(iqueue, &read_off)) != 0 ||
1533
	    (r = sshbuf_get_u64(iqueue, &read_len)) != 0 ||
1534
	    (r = get_handle(iqueue, &write_handle)) != 0 ||
1535
	    (r = sshbuf_get_u64(iqueue, &write_off)) != 0)
1536
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1537
1538
	debug("request %u: copy-data from \"%s\" (handle %d) off %llu len %llu "
1539
	    "to \"%s\" (handle %d) off %llu",
1540
	    id, handle_to_name(read_handle), read_handle,
1541
	    (unsigned long long)read_off, (unsigned long long)read_len,
1542
	    handle_to_name(write_handle), write_handle,
1543
	    (unsigned long long)write_off);
1544
1545
	/* For read length of 0, we read until EOF. */
1546
	if (read_len == 0) {
1547
		read_len = (u_int64_t)-1 - read_off;
1548
		copy_until_eof = 1;
1549
	} else
1550
		copy_until_eof = 0;
1551
1552
	read_fd = handle_to_fd(read_handle);
1553
	write_fd = handle_to_fd(write_handle);
1554
1555
	/* Disallow reading & writing to the same handle or same path or dirs */
1556
	if (read_handle == write_handle || read_fd < 0 || write_fd < 0 ||
1557
	    !strcmp(handle_to_name(read_handle), handle_to_name(write_handle))) {
1558
		status = SSH2_FX_FAILURE;
1559
		goto out;
1560
	}
1561
1562
	if (lseek(read_fd, read_off, SEEK_SET) < 0) {
1563
		status = errno_to_portable(errno);
1564
		error("%s: read_seek failed", __func__);
1565
		goto out;
1566
	}
1567
1568
	if (!(handle_to_flags(write_handle) & O_APPEND) &&
1569
			lseek(write_fd, write_off, SEEK_SET) < 0) {
1570
		status = errno_to_portable(errno);
1571
		error("%s: write_seek failed", __func__);
1572
		goto out;
1573
	}
1574
1575
	/* Process the request in chunks. */
1576
	while (read_len > 0 || copy_until_eof) {
1577
		len = MINIMUM(sizeof(buf), read_len);
1578
		read_len -= len;
1579
1580
		ret = atomicio(read, read_fd, buf, len);
1581
		if (ret == 0 && errno == EPIPE) {
1582
			status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF;
1583
			break;
1584
		} else if (ret == 0) {
1585
			status = errno_to_portable(errno);
1586
			error("%s: read failed: %s", __func__, strerror(errno));
1587
			break;
1588
		}
1589
		len = ret;
1590
		handle_update_read(read_handle, len);
1591
1592
		ret = atomicio(vwrite, write_fd, buf, len);
1593
		if (ret != len) {
1594
			status = errno_to_portable(errno);
1595
			error("%s: write failed: %llu != %llu: %s", __func__,
1596
			      (unsigned long long)ret, (unsigned long long)len,
1597
			      strerror(errno));
1598
			break;
1599
		}
1600
		handle_update_write(write_handle, len);
1601
	}
1602
1603
	if (read_len == 0)
1604
		status = SSH2_FX_OK;
1605
1606
 out:
1607
	send_status(id, status);
1608
}
1609
1518
static void
1610
static void
1519
process_extended(u_int32_t id)
1611
process_extended(u_int32_t id)
1520
{
1612
{
1521
- 

Return to bug 2948