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