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

Collapse All | Expand All

(-)a/PROTOCOL (-1 / +38 lines)
Lines 459-470 This request asks the server to call fsync(2) on an open file handle. Link Here
459
	string		"fsync@openssh.com"
459
	string		"fsync@openssh.com"
460
	string		handle
460
	string		handle
461
461
462
One receiving this request, a server will call fsync(handle_fd) and will
462
On receiving this request, a server will call fsync(handle_fd) and will
463
respond with a SSH_FXP_STATUS message.
463
respond with a SSH_FXP_STATUS message.
464
464
465
This extension is advertised in the SSH_FXP_VERSION hello with version
465
This extension is advertised in the SSH_FXP_VERSION hello with version
466
"1".
466
"1".
467
467
468
3.7. sftp: Extension request "copy-data"
469
470
This request asks the server to copy data from one open file handle and
471
write it to a different open file handle.  This avoids needing to
472
download the data before uploading it across the network twice.
473
474
	byte		SSH_FXP_EXTENDED
475
	uint32		id
476
	string		"copy-data"
477
	string		read-from-handle
478
	uint64		read-from-offset
479
	uint64		read-data-length
480
	string		write-to-handle
481
	uint64		write-to-offset
482
483
The server will copy read-data-length bytes starting from
484
read-from-offset from the read-from-handle and write them to
485
write-to-handle starting from write-to-offset, and then respond with a
486
SSH_FXP_STATUS message.
487
488
It's equivalent to issuing a series of SSH_FXP_READ requests on
489
read-from-handle and a series of requests of SSH_FXP_WRITE on
490
write-to-handle.
491
492
If read-from-handle and write-to-handle are the same, the server will
493
fail the request and respond with a SSH_FX_INVALID_PARAMETER message.
494
495
If read-data-length is 0, then the server will read data from the
496
read-from-handle until EOF is reached.
497
498
This extension is advertised in the SSH_FXP_VERSION hello with version
499
"1".
500
501
This request is identical to the "copy-data" request documented in:
502
503
https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7
504
468
4. Miscellaneous changes
505
4. Miscellaneous changes
469
506
470
4.1 Public key format
507
4.1 Public key format
(-)a/sftp-server.c (+87 lines)
Lines 107-112 static void process_extended_statvfs(u_int32_t id); Link Here
107
static void process_extended_fstatvfs(u_int32_t id);
107
static void process_extended_fstatvfs(u_int32_t id);
108
static void process_extended_hardlink(u_int32_t id);
108
static void process_extended_hardlink(u_int32_t id);
109
static void process_extended_fsync(u_int32_t id);
109
static void process_extended_fsync(u_int32_t id);
110
static void process_extended_copy_data(u_int32_t id);
110
static void process_extended(u_int32_t id);
111
static void process_extended(u_int32_t id);
111
112
112
struct sftp_handler {
113
struct sftp_handler {
Lines 148-153 static const struct sftp_handler extended_handlers[] = { Link Here
148
	{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
149
	{ "fstatvfs", "fstatvfs@openssh.com", 0, process_extended_fstatvfs, 0 },
149
	{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
150
	{ "hardlink", "hardlink@openssh.com", 0, process_extended_hardlink, 1 },
150
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
151
	{ "fsync", "fsync@openssh.com", 0, process_extended_fsync, 1 },
152
	{ "copy-data", "copy-data", 0, process_extended_copy_data, 1 },
151
	{ NULL, NULL, 0, NULL, 0 }
153
	{ NULL, NULL, 0, NULL, 0 }
152
};
154
};
153
155
Lines 666-671 process_init(void) Link Here
666
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
668
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
667
	    /* fsync extension */
669
	    /* fsync extension */
668
	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
670
	    (r = sshbuf_put_cstring(msg, "fsync@openssh.com")) != 0 ||
671
	    (r = sshbuf_put_cstring(msg, "1")) != 0 || /* version */
672
	    /* copy-data extension */
673
	    (r = sshbuf_put_cstring(msg, "copy-data")) != 0 ||
669
	    (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
674
	    (r = sshbuf_put_cstring(msg, "1")) != 0) /* version */
670
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
675
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
671
	send_msg(msg);
676
	send_msg(msg);
Lines 1369-1374 process_extended_fsync(u_int32_t id) Link Here
1369
	send_status(id, status);
1374
	send_status(id, status);
1370
}
1375
}
1371
1376
1377
static void
1378
process_extended_copy_data(u_int32_t id)
1379
{
1380
	u_char buf[64*1024];
1381
	int read_handle, read_fd, write_handle, write_fd;
1382
	u_int64_t len, read_off, read_len, write_off;
1383
	int r, ret, copy_until_eof, status = SSH2_FX_OP_UNSUPPORTED;
1384
1385
	if ((r = get_handle(iqueue, &read_handle)) != 0 ||
1386
	    (r = sshbuf_get_u64(iqueue, &read_off)) != 0 ||
1387
	    (r = sshbuf_get_u64(iqueue, &read_len)) != 0 ||
1388
	    (r = get_handle(iqueue, &write_handle)) != 0 ||
1389
	    (r = sshbuf_get_u64(iqueue, &write_off)) != 0)
1390
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
1391
1392
	debug("request %u: copy-data from \"%s\" (handle %d) off %llu len %llu "
1393
	    "to \"%s\" (handle %d) off %llu",
1394
	    id, handle_to_name(read_handle), read_handle,
1395
	    (unsigned long long)read_off, (unsigned long long)read_len,
1396
	    handle_to_name(write_handle), write_handle,
1397
	    (unsigned long long)write_off);
1398
1399
	/* For read length of 0, we read until EOF. */
1400
	if (read_len == 0) {
1401
		read_len = (u_int64_t)-1 - read_off;
1402
		copy_until_eof = 1;
1403
	} else
1404
		copy_until_eof = 0;
1405
1406
	read_fd = handle_to_fd(read_handle);
1407
	write_fd = handle_to_fd(write_handle);
1408
1409
	/* Disallow reading & writing to the same handle */
1410
	if (read_handle == write_handle || read_fd < 0 || write_fd < 0) {
1411
		status = SSH2_FX_FAILURE;
1412
	} else {
1413
		if (lseek(read_fd, read_off, SEEK_SET) < 0) {
1414
			status = errno_to_portable(errno);
1415
			error("process_extended_copy_data: read_seek failed");
1416
		} else if (!(handle_to_flags(write_handle) & O_APPEND) &&
1417
				lseek(write_fd, write_off, SEEK_SET) < 0) {
1418
			status = errno_to_portable(errno);
1419
			error("process_extended_copy_data: write_seek failed");
1420
		} else {
1421
			/* Process the request in chunks. */
1422
			while (read_len || copy_until_eof) {
1423
				len = MINIMUM(sizeof(buf), read_len);
1424
				read_len -= len;
1425
1426
				ret = read(read_fd, buf, len);
1427
				if (ret < 0) {
1428
					status = errno_to_portable(errno);
1429
					break;
1430
				} else if (ret == 0) {
1431
					status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF;
1432
					break;
1433
				}
1434
				len = ret;
1435
				handle_update_read(read_handle, len);
1436
1437
				ret = write(write_fd, buf, len);
1438
				if (ret < 0) {
1439
					status = errno_to_portable(errno);
1440
					error("process_extended_copy_data: write failed");
1441
					break;
1442
				}
1443
				handle_update_write(write_handle, len);
1444
				if ((size_t)ret != len) {
1445
					debug2("nothing at all written");
1446
					status = SSH2_FX_FAILURE;
1447
					break;
1448
				}
1449
			}
1450
1451
			if (read_len == 0)
1452
				status = SSH2_FX_OK;
1453
		}
1454
	}
1455
1456
	send_status(id, status);
1457
}
1458
1372
static void
1459
static void
1373
process_extended(u_int32_t id)
1460
process_extended(u_int32_t id)
1374
{
1461
{

Return to bug 2948