diff options
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 81 |
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 | ||
877 | int | ||
878 | do_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 |
873 | char * | 908 | char * |
874 | do_readlink(struct sftp_conn *conn, char *path) | 909 | do_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 | ||
992 | int | 1027 | int |
993 | do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | 1028 | do_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 | ||
1262 | static int | 1303 | static int |
1263 | download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, | 1304 | download_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 | ||
1352 | int | 1395 | int |
1353 | download_dir(struct sftp_conn *conn, char *src, char *dst, | 1396 | download_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 | ||
1370 | int | 1414 | int |
1371 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | 1415 | do_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 | ||
1555 | static int | 1602 | static int |
1556 | upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, | 1603 | upload_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 | ||
1647 | int | 1695 | int |
1648 | upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, | 1696 | upload_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 | } |