diff options
Diffstat (limited to 'sftp-client.c')
-rw-r--r-- | sftp-client.c | 193 |
1 files changed, 128 insertions, 65 deletions
diff --git a/sftp-client.c b/sftp-client.c index 2f9793778..fc035f2ef 100644 --- a/sftp-client.c +++ b/sftp-client.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp-client.c,v 1.108 2013/11/08 00:39:15 djm Exp $ */ | 1 | /* $OpenBSD: sftp-client.c,v 1.113 2014/01/17 00:21:06 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 | * |
@@ -42,6 +42,7 @@ | |||
42 | #include <signal.h> | 42 | #include <signal.h> |
43 | #include <stdarg.h> | 43 | #include <stdarg.h> |
44 | #include <stdio.h> | 44 | #include <stdio.h> |
45 | #include <stdlib.h> | ||
45 | #include <string.h> | 46 | #include <string.h> |
46 | #include <unistd.h> | 47 | #include <unistd.h> |
47 | 48 | ||
@@ -76,6 +77,7 @@ struct sftp_conn { | |||
76 | #define SFTP_EXT_STATVFS 0x00000002 | 77 | #define SFTP_EXT_STATVFS 0x00000002 |
77 | #define SFTP_EXT_FSTATVFS 0x00000004 | 78 | #define SFTP_EXT_FSTATVFS 0x00000004 |
78 | #define SFTP_EXT_HARDLINK 0x00000008 | 79 | #define SFTP_EXT_HARDLINK 0x00000008 |
80 | #define SFTP_EXT_FSYNC 0x00000010 | ||
79 | u_int exts; | 81 | u_int exts; |
80 | u_int64_t limit_kbps; | 82 | u_int64_t limit_kbps; |
81 | struct bwlimit bwlimit_in, bwlimit_out; | 83 | struct bwlimit bwlimit_in, bwlimit_out; |
@@ -337,7 +339,8 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, | |||
337 | Buffer msg; | 339 | Buffer msg; |
338 | struct sftp_conn *ret; | 340 | struct sftp_conn *ret; |
339 | 341 | ||
340 | ret = xmalloc(sizeof(*ret)); | 342 | ret = xcalloc(1, sizeof(*ret)); |
343 | ret->msg_id = 1; | ||
341 | ret->fd_in = fd_in; | 344 | ret->fd_in = fd_in; |
342 | ret->fd_out = fd_out; | 345 | ret->fd_out = fd_out; |
343 | ret->transfer_buflen = transfer_buflen; | 346 | ret->transfer_buflen = transfer_buflen; |
@@ -387,6 +390,10 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, | |||
387 | strcmp(value, "1") == 0) { | 390 | strcmp(value, "1") == 0) { |
388 | ret->exts |= SFTP_EXT_HARDLINK; | 391 | ret->exts |= SFTP_EXT_HARDLINK; |
389 | known = 1; | 392 | known = 1; |
393 | } else if (strcmp(name, "fsync@openssh.com") == 0 && | ||
394 | strcmp(value, "1") == 0) { | ||
395 | ret->exts |= SFTP_EXT_FSYNC; | ||
396 | known = 1; | ||
390 | } | 397 | } |
391 | if (known) { | 398 | if (known) { |
392 | debug2("Server supports extension \"%s\" revision %s", | 399 | debug2("Server supports extension \"%s\" revision %s", |
@@ -447,12 +454,16 @@ do_close(struct sftp_conn *conn, char *handle, u_int handle_len) | |||
447 | 454 | ||
448 | 455 | ||
449 | static int | 456 | static int |
450 | do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | 457 | do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag, |
451 | SFTP_DIRENT ***dir) | 458 | SFTP_DIRENT ***dir) |
452 | { | 459 | { |
453 | Buffer msg; | 460 | Buffer msg; |
454 | u_int count, type, id, handle_len, i, expected_id, ents = 0; | 461 | u_int count, type, id, handle_len, i, expected_id, ents = 0; |
455 | char *handle; | 462 | char *handle; |
463 | int status = SSH2_FX_FAILURE; | ||
464 | |||
465 | if (dir) | ||
466 | *dir = NULL; | ||
456 | 467 | ||
457 | id = conn->msg_id++; | 468 | id = conn->msg_id++; |
458 | 469 | ||
@@ -499,20 +510,12 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
499 | fatal("ID mismatch (%u != %u)", id, expected_id); | 510 | fatal("ID mismatch (%u != %u)", id, expected_id); |
500 | 511 | ||
501 | if (type == SSH2_FXP_STATUS) { | 512 | if (type == SSH2_FXP_STATUS) { |
502 | int status = buffer_get_int(&msg); | 513 | status = buffer_get_int(&msg); |
503 | |||
504 | debug3("Received SSH2_FXP_STATUS %d", status); | 514 | debug3("Received SSH2_FXP_STATUS %d", status); |
505 | 515 | if (status == SSH2_FX_EOF) | |
506 | if (status == SSH2_FX_EOF) { | ||
507 | break; | 516 | break; |
508 | } else { | 517 | error("Couldn't read directory: %s", fx2txt(status)); |
509 | error("Couldn't read directory: %s", | 518 | goto out; |
510 | fx2txt(status)); | ||
511 | do_close(conn, handle, handle_len); | ||
512 | free(handle); | ||
513 | buffer_free(&msg); | ||
514 | return(status); | ||
515 | } | ||
516 | } else if (type != SSH2_FXP_NAME) | 519 | } else if (type != SSH2_FXP_NAME) |
517 | fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", | 520 | fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", |
518 | SSH2_FXP_NAME, type); | 521 | SSH2_FXP_NAME, type); |
@@ -529,7 +532,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
529 | longname = buffer_get_string(&msg, NULL); | 532 | longname = buffer_get_string(&msg, NULL); |
530 | a = decode_attrib(&msg); | 533 | a = decode_attrib(&msg); |
531 | 534 | ||
532 | if (printflag) | 535 | if (print_flag) |
533 | printf("%s\n", longname); | 536 | printf("%s\n", longname); |
534 | 537 | ||
535 | /* | 538 | /* |
@@ -540,10 +543,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
540 | if (strchr(filename, '/') != NULL) { | 543 | if (strchr(filename, '/') != NULL) { |
541 | error("Server sent suspect path \"%s\" " | 544 | error("Server sent suspect path \"%s\" " |
542 | "during readdir of \"%s\"", filename, path); | 545 | "during readdir of \"%s\"", filename, path); |
543 | goto next; | 546 | } else if (dir) { |
544 | } | ||
545 | |||
546 | if (dir) { | ||
547 | *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); | 547 | *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); |
548 | (*dir)[ents] = xcalloc(1, sizeof(***dir)); | 548 | (*dir)[ents] = xcalloc(1, sizeof(***dir)); |
549 | (*dir)[ents]->filename = xstrdup(filename); | 549 | (*dir)[ents]->filename = xstrdup(filename); |
@@ -551,24 +551,29 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, | |||
551 | memcpy(&(*dir)[ents]->a, a, sizeof(*a)); | 551 | memcpy(&(*dir)[ents]->a, a, sizeof(*a)); |
552 | (*dir)[++ents] = NULL; | 552 | (*dir)[++ents] = NULL; |
553 | } | 553 | } |
554 | next: | ||
555 | free(filename); | 554 | free(filename); |
556 | free(longname); | 555 | free(longname); |
557 | } | 556 | } |
558 | } | 557 | } |
558 | status = 0; | ||
559 | 559 | ||
560 | out: | ||
560 | buffer_free(&msg); | 561 | buffer_free(&msg); |
561 | do_close(conn, handle, handle_len); | 562 | do_close(conn, handle, handle_len); |
562 | free(handle); | 563 | free(handle); |
563 | 564 | ||
564 | /* Don't return partial matches on interrupt */ | 565 | if (status != 0 && dir != NULL) { |
565 | if (interrupted && dir != NULL && *dir != NULL) { | 566 | /* Don't return results on error */ |
567 | free_sftp_dirents(*dir); | ||
568 | *dir = NULL; | ||
569 | } else if (interrupted && dir != NULL && *dir != NULL) { | ||
570 | /* Don't return partial matches on interrupt */ | ||
566 | free_sftp_dirents(*dir); | 571 | free_sftp_dirents(*dir); |
567 | *dir = xcalloc(1, sizeof(**dir)); | 572 | *dir = xcalloc(1, sizeof(**dir)); |
568 | **dir = NULL; | 573 | **dir = NULL; |
569 | } | 574 | } |
570 | 575 | ||
571 | return 0; | 576 | return status; |
572 | } | 577 | } |
573 | 578 | ||
574 | int | 579 | int |
@@ -581,6 +586,8 @@ void free_sftp_dirents(SFTP_DIRENT **s) | |||
581 | { | 586 | { |
582 | int i; | 587 | int i; |
583 | 588 | ||
589 | if (s == NULL) | ||
590 | return; | ||
584 | for (i = 0; s[i]; i++) { | 591 | for (i = 0; s[i]; i++) { |
585 | free(s[i]->filename); | 592 | free(s[i]->filename); |
586 | free(s[i]->longname); | 593 | free(s[i]->longname); |
@@ -605,7 +612,7 @@ do_rm(struct sftp_conn *conn, char *path) | |||
605 | } | 612 | } |
606 | 613 | ||
607 | int | 614 | int |
608 | do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) | 615 | do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag) |
609 | { | 616 | { |
610 | u_int status, id; | 617 | u_int status, id; |
611 | 618 | ||
@@ -614,7 +621,7 @@ do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) | |||
614 | strlen(path), a); | 621 | strlen(path), a); |
615 | 622 | ||
616 | status = get_status(conn, id); | 623 | status = get_status(conn, id); |
617 | if (status != SSH2_FX_OK && printflag) | 624 | if (status != SSH2_FX_OK && print_flag) |
618 | error("Couldn't create directory: %s", fx2txt(status)); | 625 | error("Couldn't create directory: %s", fx2txt(status)); |
619 | 626 | ||
620 | return(status); | 627 | return(status); |
@@ -742,7 +749,7 @@ do_realpath(struct sftp_conn *conn, char *path) | |||
742 | if (type == SSH2_FXP_STATUS) { | 749 | if (type == SSH2_FXP_STATUS) { |
743 | u_int status = buffer_get_int(&msg); | 750 | u_int status = buffer_get_int(&msg); |
744 | 751 | ||
745 | error("Couldn't canonicalise: %s", fx2txt(status)); | 752 | error("Couldn't canonicalize: %s", fx2txt(status)); |
746 | buffer_free(&msg); | 753 | buffer_free(&msg); |
747 | return NULL; | 754 | return NULL; |
748 | } else if (type != SSH2_FXP_NAME) | 755 | } else if (type != SSH2_FXP_NAME) |
@@ -768,16 +775,18 @@ do_realpath(struct sftp_conn *conn, char *path) | |||
768 | } | 775 | } |
769 | 776 | ||
770 | int | 777 | int |
771 | do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | 778 | do_rename(struct sftp_conn *conn, char *oldpath, char *newpath, |
779 | int force_legacy) | ||
772 | { | 780 | { |
773 | Buffer msg; | 781 | Buffer msg; |
774 | u_int status, id; | 782 | u_int status, id; |
783 | int use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy; | ||
775 | 784 | ||
776 | buffer_init(&msg); | 785 | buffer_init(&msg); |
777 | 786 | ||
778 | /* Send rename request */ | 787 | /* Send rename request */ |
779 | id = conn->msg_id++; | 788 | id = conn->msg_id++; |
780 | if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { | 789 | if (use_ext) { |
781 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | 790 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); |
782 | buffer_put_int(&msg, id); | 791 | buffer_put_int(&msg, id); |
783 | buffer_put_cstring(&msg, "posix-rename@openssh.com"); | 792 | buffer_put_cstring(&msg, "posix-rename@openssh.com"); |
@@ -789,8 +798,8 @@ do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
789 | buffer_put_cstring(&msg, newpath); | 798 | buffer_put_cstring(&msg, newpath); |
790 | send_msg(conn, &msg); | 799 | send_msg(conn, &msg); |
791 | debug3("Sent message %s \"%s\" -> \"%s\"", | 800 | debug3("Sent message %s \"%s\" -> \"%s\"", |
792 | (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : | 801 | use_ext ? "posix-rename@openssh.com" : "SSH2_FXP_RENAME", |
793 | "SSH2_FXP_RENAME", oldpath, newpath); | 802 | oldpath, newpath); |
794 | buffer_free(&msg); | 803 | buffer_free(&msg); |
795 | 804 | ||
796 | status = get_status(conn, id); | 805 | status = get_status(conn, id); |
@@ -866,6 +875,36 @@ do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) | |||
866 | return(status); | 875 | return(status); |
867 | } | 876 | } |
868 | 877 | ||
878 | int | ||
879 | do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len) | ||
880 | { | ||
881 | Buffer msg; | ||
882 | u_int status, id; | ||
883 | |||
884 | /* Silently return if the extension is not supported */ | ||
885 | if ((conn->exts & SFTP_EXT_FSYNC) == 0) | ||
886 | return -1; | ||
887 | |||
888 | buffer_init(&msg); | ||
889 | |||
890 | /* Send fsync request */ | ||
891 | id = conn->msg_id++; | ||
892 | |||
893 | buffer_put_char(&msg, SSH2_FXP_EXTENDED); | ||
894 | buffer_put_int(&msg, id); | ||
895 | buffer_put_cstring(&msg, "fsync@openssh.com"); | ||
896 | buffer_put_string(&msg, handle, handle_len); | ||
897 | send_msg(conn, &msg); | ||
898 | debug3("Sent message fsync@openssh.com I:%u", id); | ||
899 | buffer_free(&msg); | ||
900 | |||
901 | status = get_status(conn, id); | ||
902 | if (status != SSH2_FX_OK) | ||
903 | error("Couldn't sync file: %s", fx2txt(status)); | ||
904 | |||
905 | return status; | ||
906 | } | ||
907 | |||
869 | #ifdef notyet | 908 | #ifdef notyet |
870 | char * | 909 | char * |
871 | do_readlink(struct sftp_conn *conn, char *path) | 910 | do_readlink(struct sftp_conn *conn, char *path) |
@@ -988,7 +1027,7 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, | |||
988 | 1027 | ||
989 | int | 1028 | int |
990 | do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | 1029 | do_download(struct sftp_conn *conn, char *remote_path, char *local_path, |
991 | Attrib *a, int pflag, int resume) | 1030 | Attrib *a, int preserve_flag, int resume_flag, int fsync_flag) |
992 | { | 1031 | { |
993 | Attrib junk; | 1032 | Attrib junk; |
994 | Buffer msg; | 1033 | Buffer msg; |
@@ -1051,27 +1090,33 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1051 | return(-1); | 1090 | return(-1); |
1052 | } | 1091 | } |
1053 | 1092 | ||
1054 | local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? 0 : O_TRUNC), | 1093 | local_fd = open(local_path, |
1055 | mode | S_IWUSR); | 1094 | O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR); |
1056 | if (local_fd == -1) { | 1095 | if (local_fd == -1) { |
1057 | error("Couldn't open local file \"%s\" for writing: %s", | 1096 | error("Couldn't open local file \"%s\" for writing: %s", |
1058 | local_path, strerror(errno)); | 1097 | local_path, strerror(errno)); |
1059 | goto fail; | 1098 | goto fail; |
1060 | } | 1099 | } |
1061 | offset = highwater = 0; | 1100 | offset = highwater = 0; |
1062 | if (resume) { | 1101 | if (resume_flag) { |
1063 | if (fstat(local_fd, &st) == -1) { | 1102 | if (fstat(local_fd, &st) == -1) { |
1064 | error("Unable to stat local file \"%s\": %s", | 1103 | error("Unable to stat local file \"%s\": %s", |
1065 | local_path, strerror(errno)); | 1104 | local_path, strerror(errno)); |
1066 | goto fail; | 1105 | goto fail; |
1067 | } | 1106 | } |
1068 | if ((size_t)st.st_size > size) { | 1107 | if (st.st_size < 0) { |
1108 | error("\"%s\" has negative size", local_path); | ||
1109 | goto fail; | ||
1110 | } | ||
1111 | if ((u_int64_t)st.st_size > size) { | ||
1069 | error("Unable to resume download of \"%s\": " | 1112 | error("Unable to resume download of \"%s\": " |
1070 | "local file is larger than remote", local_path); | 1113 | "local file is larger than remote", local_path); |
1071 | fail: | 1114 | fail: |
1072 | do_close(conn, handle, handle_len); | 1115 | do_close(conn, handle, handle_len); |
1073 | buffer_free(&msg); | 1116 | buffer_free(&msg); |
1074 | free(handle); | 1117 | free(handle); |
1118 | if (local_fd != -1) | ||
1119 | close(local_fd); | ||
1075 | return -1; | 1120 | return -1; |
1076 | } | 1121 | } |
1077 | offset = highwater = st.st_size; | 1122 | offset = highwater = st.st_size; |
@@ -1209,7 +1254,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1209 | fatal("Transfer complete, but requests still in queue"); | 1254 | fatal("Transfer complete, but requests still in queue"); |
1210 | /* Truncate at highest contiguous point to avoid holes on interrupt */ | 1255 | /* Truncate at highest contiguous point to avoid holes on interrupt */ |
1211 | if (read_error || write_error || interrupted) { | 1256 | if (read_error || write_error || interrupted) { |
1212 | if (reordered && resume) { | 1257 | if (reordered && resume_flag) { |
1213 | error("Unable to resume download of \"%s\": " | 1258 | error("Unable to resume download of \"%s\": " |
1214 | "server reordered requests", local_path); | 1259 | "server reordered requests", local_path); |
1215 | } | 1260 | } |
@@ -1219,6 +1264,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1219 | if (read_error) { | 1264 | if (read_error) { |
1220 | error("Couldn't read from remote file \"%s\" : %s", | 1265 | error("Couldn't read from remote file \"%s\" : %s", |
1221 | remote_path, fx2txt(status)); | 1266 | remote_path, fx2txt(status)); |
1267 | status = -1; | ||
1222 | do_close(conn, handle, handle_len); | 1268 | do_close(conn, handle, handle_len); |
1223 | } else if (write_error) { | 1269 | } else if (write_error) { |
1224 | error("Couldn't write to \"%s\": %s", local_path, | 1270 | error("Couldn't write to \"%s\": %s", local_path, |
@@ -1227,17 +1273,18 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1227 | do_close(conn, handle, handle_len); | 1273 | do_close(conn, handle, handle_len); |
1228 | } else { | 1274 | } else { |
1229 | status = do_close(conn, handle, handle_len); | 1275 | status = do_close(conn, handle, handle_len); |
1230 | if (interrupted) | 1276 | if (interrupted || status != SSH2_FX_OK) |
1231 | status = -1; | 1277 | status = -1; |
1232 | /* Override umask and utimes if asked */ | 1278 | /* Override umask and utimes if asked */ |
1233 | #ifdef HAVE_FCHMOD | 1279 | #ifdef HAVE_FCHMOD |
1234 | if (pflag && fchmod(local_fd, mode) == -1) | 1280 | if (preserve_flag && fchmod(local_fd, mode) == -1) |
1235 | #else | 1281 | #else |
1236 | if (pflag && chmod(local_path, mode) == -1) | 1282 | if (preserve_flag && chmod(local_path, mode) == -1) |
1237 | #endif /* HAVE_FCHMOD */ | 1283 | #endif /* HAVE_FCHMOD */ |
1238 | error("Couldn't set mode on \"%s\": %s", local_path, | 1284 | error("Couldn't set mode on \"%s\": %s", local_path, |
1239 | strerror(errno)); | 1285 | strerror(errno)); |
1240 | if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { | 1286 | if (preserve_flag && |
1287 | (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { | ||
1241 | struct timeval tv[2]; | 1288 | struct timeval tv[2]; |
1242 | tv[0].tv_sec = a->atime; | 1289 | tv[0].tv_sec = a->atime; |
1243 | tv[1].tv_sec = a->mtime; | 1290 | tv[1].tv_sec = a->mtime; |
@@ -1246,6 +1293,12 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1246 | error("Can't set times on \"%s\": %s", | 1293 | error("Can't set times on \"%s\": %s", |
1247 | local_path, strerror(errno)); | 1294 | local_path, strerror(errno)); |
1248 | } | 1295 | } |
1296 | if (fsync_flag) { | ||
1297 | debug("syncing \"%s\"", local_path); | ||
1298 | if (fsync(local_fd) == -1) | ||
1299 | error("Couldn't sync file \"%s\": %s", | ||
1300 | local_path, strerror(errno)); | ||
1301 | } | ||
1249 | } | 1302 | } |
1250 | close(local_fd); | 1303 | close(local_fd); |
1251 | buffer_free(&msg); | 1304 | buffer_free(&msg); |
@@ -1255,8 +1308,9 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path, | |||
1255 | } | 1308 | } |
1256 | 1309 | ||
1257 | static int | 1310 | static int |
1258 | download_dir_internal(struct sftp_conn *conn, char *src, char *dst, | 1311 | download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, |
1259 | Attrib *dirattrib, int pflag, int printflag, int depth, int resume) | 1312 | Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, |
1313 | int fsync_flag) | ||
1260 | { | 1314 | { |
1261 | int i, ret = 0; | 1315 | int i, ret = 0; |
1262 | SFTP_DIRENT **dir_entries; | 1316 | SFTP_DIRENT **dir_entries; |
@@ -1277,7 +1331,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1277 | error("\"%s\" is not a directory", src); | 1331 | error("\"%s\" is not a directory", src); |
1278 | return -1; | 1332 | return -1; |
1279 | } | 1333 | } |
1280 | if (printflag) | 1334 | if (print_flag) |
1281 | printf("Retrieving %s\n", src); | 1335 | printf("Retrieving %s\n", src); |
1282 | 1336 | ||
1283 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) | 1337 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) |
@@ -1308,12 +1362,13 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1308 | strcmp(filename, "..") == 0) | 1362 | strcmp(filename, "..") == 0) |
1309 | continue; | 1363 | continue; |
1310 | if (download_dir_internal(conn, new_src, new_dst, | 1364 | if (download_dir_internal(conn, new_src, new_dst, |
1311 | &(dir_entries[i]->a), pflag, printflag, | 1365 | depth + 1, &(dir_entries[i]->a), preserve_flag, |
1312 | depth + 1, resume) == -1) | 1366 | print_flag, resume_flag, fsync_flag) == -1) |
1313 | ret = -1; | 1367 | ret = -1; |
1314 | } else if (S_ISREG(dir_entries[i]->a.perm) ) { | 1368 | } else if (S_ISREG(dir_entries[i]->a.perm) ) { |
1315 | if (do_download(conn, new_src, new_dst, | 1369 | if (do_download(conn, new_src, new_dst, |
1316 | &(dir_entries[i]->a), pflag, resume) == -1) { | 1370 | &(dir_entries[i]->a), preserve_flag, |
1371 | resume_flag, fsync_flag) == -1) { | ||
1317 | error("Download of file %s to %s failed", | 1372 | error("Download of file %s to %s failed", |
1318 | new_src, new_dst); | 1373 | new_src, new_dst); |
1319 | ret = -1; | 1374 | ret = -1; |
@@ -1325,7 +1380,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1325 | free(new_src); | 1380 | free(new_src); |
1326 | } | 1381 | } |
1327 | 1382 | ||
1328 | if (pflag) { | 1383 | if (preserve_flag) { |
1329 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { | 1384 | if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { |
1330 | struct timeval tv[2]; | 1385 | struct timeval tv[2]; |
1331 | tv[0].tv_sec = dirattrib->atime; | 1386 | tv[0].tv_sec = dirattrib->atime; |
@@ -1346,25 +1401,26 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1346 | 1401 | ||
1347 | int | 1402 | int |
1348 | download_dir(struct sftp_conn *conn, char *src, char *dst, | 1403 | download_dir(struct sftp_conn *conn, char *src, char *dst, |
1349 | Attrib *dirattrib, int pflag, int printflag, int resume) | 1404 | Attrib *dirattrib, int preserve_flag, int print_flag, |
1405 | int resume_flag, int fsync_flag) | ||
1350 | { | 1406 | { |
1351 | char *src_canon; | 1407 | char *src_canon; |
1352 | int ret; | 1408 | int ret; |
1353 | 1409 | ||
1354 | if ((src_canon = do_realpath(conn, src)) == NULL) { | 1410 | if ((src_canon = do_realpath(conn, src)) == NULL) { |
1355 | error("Unable to canonicalise path \"%s\"", src); | 1411 | error("Unable to canonicalize path \"%s\"", src); |
1356 | return -1; | 1412 | return -1; |
1357 | } | 1413 | } |
1358 | 1414 | ||
1359 | ret = download_dir_internal(conn, src_canon, dst, | 1415 | ret = download_dir_internal(conn, src_canon, dst, 0, |
1360 | dirattrib, pflag, printflag, 0, resume); | 1416 | dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag); |
1361 | free(src_canon); | 1417 | free(src_canon); |
1362 | return ret; | 1418 | return ret; |
1363 | } | 1419 | } |
1364 | 1420 | ||
1365 | int | 1421 | int |
1366 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | 1422 | do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, |
1367 | int pflag) | 1423 | int preserve_flag, int fsync_flag) |
1368 | { | 1424 | { |
1369 | int local_fd; | 1425 | int local_fd; |
1370 | int status = SSH2_FX_OK; | 1426 | int status = SSH2_FX_OK; |
@@ -1408,7 +1464,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1408 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; | 1464 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; |
1409 | a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; | 1465 | a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; |
1410 | a.perm &= 0777; | 1466 | a.perm &= 0777; |
1411 | if (!pflag) | 1467 | if (!preserve_flag) |
1412 | a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; | 1468 | a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; |
1413 | 1469 | ||
1414 | buffer_init(&msg); | 1470 | buffer_init(&msg); |
@@ -1537,9 +1593,12 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1537 | } | 1593 | } |
1538 | 1594 | ||
1539 | /* Override umask and utimes if asked */ | 1595 | /* Override umask and utimes if asked */ |
1540 | if (pflag) | 1596 | if (preserve_flag) |
1541 | do_fsetstat(conn, handle, handle_len, &a); | 1597 | do_fsetstat(conn, handle, handle_len, &a); |
1542 | 1598 | ||
1599 | if (fsync_flag) | ||
1600 | (void)do_fsync(conn, handle, handle_len); | ||
1601 | |||
1543 | if (do_close(conn, handle, handle_len) != SSH2_FX_OK) | 1602 | if (do_close(conn, handle, handle_len) != SSH2_FX_OK) |
1544 | status = -1; | 1603 | status = -1; |
1545 | free(handle); | 1604 | free(handle); |
@@ -1548,8 +1607,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, | |||
1548 | } | 1607 | } |
1549 | 1608 | ||
1550 | static int | 1609 | static int |
1551 | upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, | 1610 | upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth, |
1552 | int pflag, int printflag, int depth) | 1611 | int preserve_flag, int print_flag, int fsync_flag) |
1553 | { | 1612 | { |
1554 | int ret = 0, status; | 1613 | int ret = 0, status; |
1555 | DIR *dirp; | 1614 | DIR *dirp; |
@@ -1572,7 +1631,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1572 | error("\"%s\" is not a directory", src); | 1631 | error("\"%s\" is not a directory", src); |
1573 | return -1; | 1632 | return -1; |
1574 | } | 1633 | } |
1575 | if (printflag) | 1634 | if (print_flag) |
1576 | printf("Entering %s\n", src); | 1635 | printf("Entering %s\n", src); |
1577 | 1636 | ||
1578 | attrib_clear(&a); | 1637 | attrib_clear(&a); |
@@ -1580,7 +1639,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1580 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; | 1639 | a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; |
1581 | a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; | 1640 | a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; |
1582 | a.perm &= 01777; | 1641 | a.perm &= 01777; |
1583 | if (!pflag) | 1642 | if (!preserve_flag) |
1584 | a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; | 1643 | a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; |
1585 | 1644 | ||
1586 | status = do_mkdir(conn, dst, &a, 0); | 1645 | status = do_mkdir(conn, dst, &a, 0); |
@@ -1618,10 +1677,12 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1618 | continue; | 1677 | continue; |
1619 | 1678 | ||
1620 | if (upload_dir_internal(conn, new_src, new_dst, | 1679 | if (upload_dir_internal(conn, new_src, new_dst, |
1621 | pflag, printflag, depth + 1) == -1) | 1680 | depth + 1, preserve_flag, print_flag, |
1681 | fsync_flag) == -1) | ||
1622 | ret = -1; | 1682 | ret = -1; |
1623 | } else if (S_ISREG(sb.st_mode)) { | 1683 | } else if (S_ISREG(sb.st_mode)) { |
1624 | if (do_upload(conn, new_src, new_dst, pflag) == -1) { | 1684 | if (do_upload(conn, new_src, new_dst, |
1685 | preserve_flag, fsync_flag) == -1) { | ||
1625 | error("Uploading of file %s to %s failed!", | 1686 | error("Uploading of file %s to %s failed!", |
1626 | new_src, new_dst); | 1687 | new_src, new_dst); |
1627 | ret = -1; | 1688 | ret = -1; |
@@ -1639,18 +1700,20 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, | |||
1639 | } | 1700 | } |
1640 | 1701 | ||
1641 | int | 1702 | int |
1642 | upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, | 1703 | upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag, |
1643 | int pflag) | 1704 | int print_flag, int fsync_flag) |
1644 | { | 1705 | { |
1645 | char *dst_canon; | 1706 | char *dst_canon; |
1646 | int ret; | 1707 | int ret; |
1647 | 1708 | ||
1648 | if ((dst_canon = do_realpath(conn, dst)) == NULL) { | 1709 | if ((dst_canon = do_realpath(conn, dst)) == NULL) { |
1649 | error("Unable to canonicalise path \"%s\"", dst); | 1710 | error("Unable to canonicalize path \"%s\"", dst); |
1650 | return -1; | 1711 | return -1; |
1651 | } | 1712 | } |
1652 | 1713 | ||
1653 | ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); | 1714 | ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag, |
1715 | print_flag, fsync_flag); | ||
1716 | |||
1654 | free(dst_canon); | 1717 | free(dst_canon); |
1655 | return ret; | 1718 | return ret; |
1656 | } | 1719 | } |