|
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 |
- |
|
|