summaryrefslogtreecommitdiff
path: root/sftp-client.c
diff options
context:
space:
mode:
Diffstat (limited to 'sftp-client.c')
-rw-r--r--sftp-client.c193
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
449static int 456static int
450do_lsreaddir(struct sftp_conn *conn, char *path, int printflag, 457do_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
574int 579int
@@ -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
607int 614int
608do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) 615do_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
770int 777int
771do_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 778do_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
878int
879do_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
870char * 909char *
871do_readlink(struct sftp_conn *conn, char *path) 910do_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
989int 1028int
990do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 1029do_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
1257static int 1310static int
1258download_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1311download_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
1347int 1402int
1348download_dir(struct sftp_conn *conn, char *src, char *dst, 1403download_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
1365int 1421int
1366do_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 1422do_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
1550static int 1609static int
1551upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1610upload_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
1641int 1702int
1642upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, 1703upload_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}