summaryrefslogtreecommitdiff
path: root/sftp-client.c
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2013-10-17 11:48:52 +1100
committerDamien Miller <djm@mindrot.org>2013-10-17 11:48:52 +1100
commitf29238e67471a7f1088a99c3c3dbafce76b790cf (patch)
tree39ea232a72df52b4adbc3affea0108d8b0f45b42 /sftp-client.c
parent51682faa599550a69d8120e5e2bdbdc0625ef4be (diff)
- djm@cvs.openbsd.org 2013/10/17 00:30:13
[PROTOCOL sftp-client.c sftp-client.h sftp-server.c sftp.1 sftp.c] fsync@openssh.com protocol extension for sftp-server client support to allow calling fsync() faster successful transfer patch mostly by imorgan AT nas.nasa.gov; bz#1798 "fine" markus@ "grumble OK" deraadt@ "doesn't sound bad to me" millert@
Diffstat (limited to 'sftp-client.c')
-rw-r--r--sftp-client.c81
1 files changed, 65 insertions, 16 deletions
diff --git a/sftp-client.c b/sftp-client.c
index 573623b9d..91955262c 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.c,v 1.106 2013/10/11 02:52:23 djm Exp $ */ 1/* $OpenBSD: sftp-client.c,v 1.107 2013/10/17 00:30:13 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -76,6 +76,7 @@ struct sftp_conn {
76#define SFTP_EXT_STATVFS 0x00000002 76#define SFTP_EXT_STATVFS 0x00000002
77#define SFTP_EXT_FSTATVFS 0x00000004 77#define SFTP_EXT_FSTATVFS 0x00000004
78#define SFTP_EXT_HARDLINK 0x00000008 78#define SFTP_EXT_HARDLINK 0x00000008
79#define SFTP_EXT_FSYNC 0x00000010
79 u_int exts; 80 u_int exts;
80 u_int64_t limit_kbps; 81 u_int64_t limit_kbps;
81 struct bwlimit bwlimit_in, bwlimit_out; 82 struct bwlimit bwlimit_in, bwlimit_out;
@@ -388,6 +389,10 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
388 strcmp(value, "1") == 0) { 389 strcmp(value, "1") == 0) {
389 ret->exts |= SFTP_EXT_HARDLINK; 390 ret->exts |= SFTP_EXT_HARDLINK;
390 known = 1; 391 known = 1;
392 } else if (strcmp(name, "fsync@openssh.com") == 0 &&
393 strcmp(value, "1") == 0) {
394 ret->exts |= SFTP_EXT_FSYNC;
395 known = 1;
391 } 396 }
392 if (known) { 397 if (known) {
393 debug2("Server supports extension \"%s\" revision %s", 398 debug2("Server supports extension \"%s\" revision %s",
@@ -743,7 +748,7 @@ do_realpath(struct sftp_conn *conn, char *path)
743 if (type == SSH2_FXP_STATUS) { 748 if (type == SSH2_FXP_STATUS) {
744 u_int status = buffer_get_int(&msg); 749 u_int status = buffer_get_int(&msg);
745 750
746 error("Couldn't canonicalise: %s", fx2txt(status)); 751 error("Couldn't canonicalize: %s", fx2txt(status));
747 buffer_free(&msg); 752 buffer_free(&msg);
748 return NULL; 753 return NULL;
749 } else if (type != SSH2_FXP_NAME) 754 } else if (type != SSH2_FXP_NAME)
@@ -869,6 +874,36 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
869 return(status); 874 return(status);
870} 875}
871 876
877int
878do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len)
879{
880 Buffer msg;
881 u_int status, id;
882
883 /* Silently return if the extension is not supported */
884 if ((conn->exts & SFTP_EXT_FSYNC) == 0)
885 return -1;
886
887 buffer_init(&msg);
888
889 /* Send fsync request */
890 id = conn->msg_id++;
891
892 buffer_put_char(&msg, SSH2_FXP_EXTENDED);
893 buffer_put_int(&msg, id);
894 buffer_put_cstring(&msg, "fsync@openssh.com");
895 buffer_put_string(&msg, handle, handle_len);
896 send_msg(conn, &msg);
897 debug3("Sent message fsync@openssh.com I:%u", id);
898 buffer_free(&msg);
899
900 status = get_status(conn, id);
901 if (status != SSH2_FX_OK)
902 error("Couldn't sync file: %s", fx2txt(status));
903
904 return status;
905}
906
872#ifdef notyet 907#ifdef notyet
873char * 908char *
874do_readlink(struct sftp_conn *conn, char *path) 909do_readlink(struct sftp_conn *conn, char *path)
@@ -991,7 +1026,7 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
991 1026
992int 1027int
993do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 1028do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
994 Attrib *a, int preserve_flag, int resume_flag) 1029 Attrib *a, int preserve_flag, int resume_flag, int fsync_flag)
995{ 1030{
996 Attrib junk; 1031 Attrib junk;
997 Buffer msg; 1032 Buffer msg;
@@ -1251,6 +1286,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1251 error("Can't set times on \"%s\": %s", 1286 error("Can't set times on \"%s\": %s",
1252 local_path, strerror(errno)); 1287 local_path, strerror(errno));
1253 } 1288 }
1289 if (fsync_flag) {
1290 debug("syncing \"%s\"", local_path);
1291 if (fsync(local_fd) == -1)
1292 error("Couldn't sync file \"%s\": %s",
1293 local_path, strerror(errno));
1294 }
1254 } 1295 }
1255 close(local_fd); 1296 close(local_fd);
1256 buffer_free(&msg); 1297 buffer_free(&msg);
@@ -1261,7 +1302,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1261 1302
1262static int 1303static int
1263download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1304download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1264 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag) 1305 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
1306 int fsync_flag)
1265{ 1307{
1266 int i, ret = 0; 1308 int i, ret = 0;
1267 SFTP_DIRENT **dir_entries; 1309 SFTP_DIRENT **dir_entries;
@@ -1314,11 +1356,12 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1314 continue; 1356 continue;
1315 if (download_dir_internal(conn, new_src, new_dst, 1357 if (download_dir_internal(conn, new_src, new_dst,
1316 depth + 1, &(dir_entries[i]->a), preserve_flag, 1358 depth + 1, &(dir_entries[i]->a), preserve_flag,
1317 print_flag, resume_flag) == -1) 1359 print_flag, resume_flag, fsync_flag) == -1)
1318 ret = -1; 1360 ret = -1;
1319 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1361 } else if (S_ISREG(dir_entries[i]->a.perm) ) {
1320 if (do_download(conn, new_src, new_dst, 1362 if (do_download(conn, new_src, new_dst,
1321 &(dir_entries[i]->a), preserve_flag, resume_flag) == -1) { 1363 &(dir_entries[i]->a), preserve_flag,
1364 resume_flag, fsync_flag) == -1) {
1322 error("Download of file %s to %s failed", 1365 error("Download of file %s to %s failed",
1323 new_src, new_dst); 1366 new_src, new_dst);
1324 ret = -1; 1367 ret = -1;
@@ -1351,25 +1394,26 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1351 1394
1352int 1395int
1353download_dir(struct sftp_conn *conn, char *src, char *dst, 1396download_dir(struct sftp_conn *conn, char *src, char *dst,
1354 Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag) 1397 Attrib *dirattrib, int preserve_flag, int print_flag,
1398 int resume_flag, int fsync_flag)
1355{ 1399{
1356 char *src_canon; 1400 char *src_canon;
1357 int ret; 1401 int ret;
1358 1402
1359 if ((src_canon = do_realpath(conn, src)) == NULL) { 1403 if ((src_canon = do_realpath(conn, src)) == NULL) {
1360 error("Unable to canonicalise path \"%s\"", src); 1404 error("Unable to canonicalize path \"%s\"", src);
1361 return -1; 1405 return -1;
1362 } 1406 }
1363 1407
1364 ret = download_dir_internal(conn, src_canon, dst, 0, 1408 ret = download_dir_internal(conn, src_canon, dst, 0,
1365 dirattrib, preserve_flag, print_flag, resume_flag); 1409 dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
1366 free(src_canon); 1410 free(src_canon);
1367 return ret; 1411 return ret;
1368} 1412}
1369 1413
1370int 1414int
1371do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1415do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1372 int preserve_flag) 1416 int preserve_flag, int fsync_flag)
1373{ 1417{
1374 int local_fd; 1418 int local_fd;
1375 int status = SSH2_FX_OK; 1419 int status = SSH2_FX_OK;
@@ -1545,6 +1589,9 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1545 if (preserve_flag) 1589 if (preserve_flag)
1546 do_fsetstat(conn, handle, handle_len, &a); 1590 do_fsetstat(conn, handle, handle_len, &a);
1547 1591
1592 if (fsync_flag)
1593 (void)do_fsync(conn, handle, handle_len);
1594
1548 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1595 if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1549 status = -1; 1596 status = -1;
1550 free(handle); 1597 free(handle);
@@ -1554,7 +1601,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1554 1601
1555static int 1602static int
1556upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, 1603upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1557 int preserve_flag, int print_flag) 1604 int preserve_flag, int print_flag, int fsync_flag)
1558{ 1605{
1559 int ret = 0, status; 1606 int ret = 0, status;
1560 DIR *dirp; 1607 DIR *dirp;
@@ -1623,11 +1670,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1623 continue; 1670 continue;
1624 1671
1625 if (upload_dir_internal(conn, new_src, new_dst, 1672 if (upload_dir_internal(conn, new_src, new_dst,
1626 depth + 1, preserve_flag, print_flag) == -1) 1673 depth + 1, preserve_flag, print_flag,
1674 fsync_flag) == -1)
1627 ret = -1; 1675 ret = -1;
1628 } else if (S_ISREG(sb.st_mode)) { 1676 } else if (S_ISREG(sb.st_mode)) {
1629 if (do_upload(conn, new_src, new_dst, 1677 if (do_upload(conn, new_src, new_dst,
1630 preserve_flag) == -1) { 1678 preserve_flag, fsync_flag) == -1) {
1631 error("Uploading of file %s to %s failed!", 1679 error("Uploading of file %s to %s failed!",
1632 new_src, new_dst); 1680 new_src, new_dst);
1633 ret = -1; 1681 ret = -1;
@@ -1646,18 +1694,19 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
1646 1694
1647int 1695int
1648upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, 1696upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
1649 int print_flag) 1697 int print_flag, int fsync_flag)
1650{ 1698{
1651 char *dst_canon; 1699 char *dst_canon;
1652 int ret; 1700 int ret;
1653 1701
1654 if ((dst_canon = do_realpath(conn, dst)) == NULL) { 1702 if ((dst_canon = do_realpath(conn, dst)) == NULL) {
1655 error("Unable to canonicalise path \"%s\"", dst); 1703 error("Unable to canonicalize path \"%s\"", dst);
1656 return -1; 1704 return -1;
1657 } 1705 }
1658 1706
1659 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, 1707 ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
1660 print_flag); 1708 print_flag, fsync_flag);
1709
1661 free(dst_canon); 1710 free(dst_canon);
1662 return ret; 1711 return ret;
1663} 1712}