summaryrefslogtreecommitdiff
path: root/sftp-client.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2013-09-14 15:43:03 +0100
committerColin Watson <cjwatson@debian.org>2013-09-14 15:43:03 +0100
commit8faf8c84430cf3c19705b1d9f8889d256e7fd1fd (patch)
treee6cb74192adb00fda5e4d1457547851d7e0d86af /sftp-client.c
parent328b60656f29db6306994d7498dede386ec2d1c3 (diff)
parentc41345ad7ee5a22689e2c009595e85fa27b4b39a (diff)
merge 6.3p1
Diffstat (limited to 'sftp-client.c')
-rw-r--r--sftp-client.c135
1 files changed, 83 insertions, 52 deletions
diff --git a/sftp-client.c b/sftp-client.c
index 85f2bd444..f4f1970b6 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.c,v 1.97 2012/07/02 12:13:26 dtucker Exp $ */ 1/* $OpenBSD: sftp-client.c,v 1.101 2013/07/25 00:56:51 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 *
@@ -112,7 +112,7 @@ send_msg(struct sftp_conn *conn, Buffer *m)
112 iov[1].iov_len = buffer_len(m); 112 iov[1].iov_len = buffer_len(m);
113 113
114 if (atomiciov6(writev, conn->fd_out, iov, 2, 114 if (atomiciov6(writev, conn->fd_out, iov, 2,
115 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 115 conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
116 buffer_len(m) + sizeof(mlen)) 116 buffer_len(m) + sizeof(mlen))
117 fatal("Couldn't send packet: %s", strerror(errno)); 117 fatal("Couldn't send packet: %s", strerror(errno));
118 118
@@ -394,8 +394,8 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
394 } else { 394 } else {
395 debug2("Unrecognised server extension \"%s\"", name); 395 debug2("Unrecognised server extension \"%s\"", name);
396 } 396 }
397 xfree(name); 397 free(name);
398 xfree(value); 398 free(value);
399 } 399 }
400 400
401 buffer_free(&msg); 401 buffer_free(&msg);
@@ -509,7 +509,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
509 error("Couldn't read directory: %s", 509 error("Couldn't read directory: %s",
510 fx2txt(status)); 510 fx2txt(status));
511 do_close(conn, handle, handle_len); 511 do_close(conn, handle, handle_len);
512 xfree(handle); 512 free(handle);
513 buffer_free(&msg); 513 buffer_free(&msg);
514 return(status); 514 return(status);
515 } 515 }
@@ -552,14 +552,14 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
552 (*dir)[++ents] = NULL; 552 (*dir)[++ents] = NULL;
553 } 553 }
554 next: 554 next:
555 xfree(filename); 555 free(filename);
556 xfree(longname); 556 free(longname);
557 } 557 }
558 } 558 }
559 559
560 buffer_free(&msg); 560 buffer_free(&msg);
561 do_close(conn, handle, handle_len); 561 do_close(conn, handle, handle_len);
562 xfree(handle); 562 free(handle);
563 563
564 /* Don't return partial matches on interrupt */ 564 /* Don't return partial matches on interrupt */
565 if (interrupted && dir != NULL && *dir != NULL) { 565 if (interrupted && dir != NULL && *dir != NULL) {
@@ -582,11 +582,11 @@ void free_sftp_dirents(SFTP_DIRENT **s)
582 int i; 582 int i;
583 583
584 for (i = 0; s[i]; i++) { 584 for (i = 0; s[i]; i++) {
585 xfree(s[i]->filename); 585 free(s[i]->filename);
586 xfree(s[i]->longname); 586 free(s[i]->longname);
587 xfree(s[i]); 587 free(s[i]);
588 } 588 }
589 xfree(s); 589 free(s);
590} 590}
591 591
592int 592int
@@ -760,7 +760,7 @@ do_realpath(struct sftp_conn *conn, char *path)
760 debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename, 760 debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
761 (unsigned long)a->size); 761 (unsigned long)a->size);
762 762
763 xfree(longname); 763 free(longname);
764 764
765 buffer_free(&msg); 765 buffer_free(&msg);
766 766
@@ -907,7 +907,7 @@ do_readlink(struct sftp_conn *conn, char *path)
907 907
908 debug3("SSH_FXP_READLINK %s -> %s", path, filename); 908 debug3("SSH_FXP_READLINK %s -> %s", path, filename);
909 909
910 xfree(longname); 910 free(longname);
911 911
912 buffer_free(&msg); 912 buffer_free(&msg);
913 913
@@ -988,16 +988,17 @@ send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
988 988
989int 989int
990do_download(struct sftp_conn *conn, char *remote_path, char *local_path, 990do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
991 Attrib *a, int pflag) 991 Attrib *a, int pflag, int resume)
992{ 992{
993 Attrib junk; 993 Attrib junk;
994 Buffer msg; 994 Buffer msg;
995 char *handle; 995 char *handle;
996 int local_fd, status = 0, write_error; 996 int local_fd = -1, status = 0, write_error;
997 int read_error, write_errno; 997 int read_error, write_errno, reordered = 0;
998 u_int64_t offset, size; 998 u_int64_t offset = 0, size, highwater;
999 u_int handle_len, mode, type, id, buflen, num_req, max_req; 999 u_int handle_len, mode, type, id, buflen, num_req, max_req;
1000 off_t progress_counter; 1000 off_t progress_counter;
1001 struct stat st;
1001 struct request { 1002 struct request {
1002 u_int id; 1003 u_int id;
1003 u_int len; 1004 u_int len;
@@ -1050,21 +1051,36 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1050 return(-1); 1051 return(-1);
1051 } 1052 }
1052 1053
1053 local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 1054 local_fd = open(local_path, O_WRONLY | O_CREAT | (resume ? 0 : O_TRUNC),
1054 mode | S_IWRITE); 1055 mode | S_IWUSR);
1055 if (local_fd == -1) { 1056 if (local_fd == -1) {
1056 error("Couldn't open local file \"%s\" for writing: %s", 1057 error("Couldn't open local file \"%s\" for writing: %s",
1057 local_path, strerror(errno)); 1058 local_path, strerror(errno));
1058 do_close(conn, handle, handle_len); 1059 goto fail;
1059 buffer_free(&msg); 1060 }
1060 xfree(handle); 1061 offset = highwater = 0;
1061 return(-1); 1062 if (resume) {
1063 if (fstat(local_fd, &st) == -1) {
1064 error("Unable to stat local file \"%s\": %s",
1065 local_path, strerror(errno));
1066 goto fail;
1067 }
1068 if ((size_t)st.st_size > size) {
1069 error("Unable to resume download of \"%s\": "
1070 "local file is larger than remote", local_path);
1071 fail:
1072 do_close(conn, handle, handle_len);
1073 buffer_free(&msg);
1074 free(handle);
1075 return -1;
1076 }
1077 offset = highwater = st.st_size;
1062 } 1078 }
1063 1079
1064 /* Read from remote and write to local */ 1080 /* Read from remote and write to local */
1065 write_error = read_error = write_errno = num_req = offset = 0; 1081 write_error = read_error = write_errno = num_req = 0;
1066 max_req = 1; 1082 max_req = 1;
1067 progress_counter = 0; 1083 progress_counter = offset;
1068 1084
1069 if (showprogress && size != 0) 1085 if (showprogress && size != 0)
1070 start_progress_meter(remote_path, size, &progress_counter); 1086 start_progress_meter(remote_path, size, &progress_counter);
@@ -1121,7 +1137,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1121 read_error = 1; 1137 read_error = 1;
1122 max_req = 0; 1138 max_req = 0;
1123 TAILQ_REMOVE(&requests, req, tq); 1139 TAILQ_REMOVE(&requests, req, tq);
1124 xfree(req); 1140 free(req);
1125 num_req--; 1141 num_req--;
1126 break; 1142 break;
1127 case SSH2_FXP_DATA: 1143 case SSH2_FXP_DATA:
@@ -1139,12 +1155,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1139 write_error = 1; 1155 write_error = 1;
1140 max_req = 0; 1156 max_req = 0;
1141 } 1157 }
1158 else if (!reordered && req->offset <= highwater)
1159 highwater = req->offset + len;
1160 else if (!reordered && req->offset > highwater)
1161 reordered = 1;
1142 progress_counter += len; 1162 progress_counter += len;
1143 xfree(data); 1163 free(data);
1144 1164
1145 if (len == req->len) { 1165 if (len == req->len) {
1146 TAILQ_REMOVE(&requests, req, tq); 1166 TAILQ_REMOVE(&requests, req, tq);
1147 xfree(req); 1167 free(req);
1148 num_req--; 1168 num_req--;
1149 } else { 1169 } else {
1150 /* Resend the request for the missing data */ 1170 /* Resend the request for the missing data */
@@ -1187,7 +1207,15 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1187 /* Sanity check */ 1207 /* Sanity check */
1188 if (TAILQ_FIRST(&requests) != NULL) 1208 if (TAILQ_FIRST(&requests) != NULL)
1189 fatal("Transfer complete, but requests still in queue"); 1209 fatal("Transfer complete, but requests still in queue");
1190 1210 /* Truncate at highest contiguous point to avoid holes on interrupt */
1211 if (read_error || write_error || interrupted) {
1212 if (reordered && resume) {
1213 error("Unable to resume download of \"%s\": "
1214 "server reordered requests", local_path);
1215 }
1216 debug("truncating at %llu", (unsigned long long)highwater);
1217 ftruncate(local_fd, highwater);
1218 }
1191 if (read_error) { 1219 if (read_error) {
1192 error("Couldn't read from remote file \"%s\" : %s", 1220 error("Couldn't read from remote file \"%s\" : %s",
1193 remote_path, fx2txt(status)); 1221 remote_path, fx2txt(status));
@@ -1199,7 +1227,8 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1199 do_close(conn, handle, handle_len); 1227 do_close(conn, handle, handle_len);
1200 } else { 1228 } else {
1201 status = do_close(conn, handle, handle_len); 1229 status = do_close(conn, handle, handle_len);
1202 1230 if (interrupted)
1231 status = -1;
1203 /* Override umask and utimes if asked */ 1232 /* Override umask and utimes if asked */
1204#ifdef HAVE_FCHMOD 1233#ifdef HAVE_FCHMOD
1205 if (pflag && fchmod(local_fd, mode) == -1) 1234 if (pflag && fchmod(local_fd, mode) == -1)
@@ -1220,14 +1249,14 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
1220 } 1249 }
1221 close(local_fd); 1250 close(local_fd);
1222 buffer_free(&msg); 1251 buffer_free(&msg);
1223 xfree(handle); 1252 free(handle);
1224 1253
1225 return(status); 1254 return(status);
1226} 1255}
1227 1256
1228static int 1257static int
1229download_dir_internal(struct sftp_conn *conn, char *src, char *dst, 1258download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1230 Attrib *dirattrib, int pflag, int printflag, int depth) 1259 Attrib *dirattrib, int pflag, int printflag, int depth, int resume)
1231{ 1260{
1232 int i, ret = 0; 1261 int i, ret = 0;
1233 SFTP_DIRENT **dir_entries; 1262 SFTP_DIRENT **dir_entries;
@@ -1280,11 +1309,11 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1280 continue; 1309 continue;
1281 if (download_dir_internal(conn, new_src, new_dst, 1310 if (download_dir_internal(conn, new_src, new_dst,
1282 &(dir_entries[i]->a), pflag, printflag, 1311 &(dir_entries[i]->a), pflag, printflag,
1283 depth + 1) == -1) 1312 depth + 1, resume) == -1)
1284 ret = -1; 1313 ret = -1;
1285 } else if (S_ISREG(dir_entries[i]->a.perm) ) { 1314 } else if (S_ISREG(dir_entries[i]->a.perm) ) {
1286 if (do_download(conn, new_src, new_dst, 1315 if (do_download(conn, new_src, new_dst,
1287 &(dir_entries[i]->a), pflag) == -1) { 1316 &(dir_entries[i]->a), pflag, resume) == -1) {
1288 error("Download of file %s to %s failed", 1317 error("Download of file %s to %s failed",
1289 new_src, new_dst); 1318 new_src, new_dst);
1290 ret = -1; 1319 ret = -1;
@@ -1292,8 +1321,8 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1292 } else 1321 } else
1293 logit("%s: not a regular file\n", new_src); 1322 logit("%s: not a regular file\n", new_src);
1294 1323
1295 xfree(new_dst); 1324 free(new_dst);
1296 xfree(new_src); 1325 free(new_src);
1297 } 1326 }
1298 1327
1299 if (pflag) { 1328 if (pflag) {
@@ -1317,7 +1346,7 @@ download_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1317 1346
1318int 1347int
1319download_dir(struct sftp_conn *conn, char *src, char *dst, 1348download_dir(struct sftp_conn *conn, char *src, char *dst,
1320 Attrib *dirattrib, int pflag, int printflag) 1349 Attrib *dirattrib, int pflag, int printflag, int resume)
1321{ 1350{
1322 char *src_canon; 1351 char *src_canon;
1323 int ret; 1352 int ret;
@@ -1328,8 +1357,8 @@ download_dir(struct sftp_conn *conn, char *src, char *dst,
1328 } 1357 }
1329 1358
1330 ret = download_dir_internal(conn, src_canon, dst, 1359 ret = download_dir_internal(conn, src_canon, dst,
1331 dirattrib, pflag, printflag, 0); 1360 dirattrib, pflag, printflag, 0, resume);
1332 xfree(src_canon); 1361 free(src_canon);
1333 return ret; 1362 return ret;
1334} 1363}
1335 1364
@@ -1340,7 +1369,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1340 int local_fd; 1369 int local_fd;
1341 int status = SSH2_FX_OK; 1370 int status = SSH2_FX_OK;
1342 u_int handle_len, id, type; 1371 u_int handle_len, id, type;
1343 off_t offset; 1372 off_t offset, progress_counter;
1344 char *handle, *data; 1373 char *handle, *data;
1345 Buffer msg; 1374 Buffer msg;
1346 struct stat sb; 1375 struct stat sb;
@@ -1408,9 +1437,10 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1408 data = xmalloc(conn->transfer_buflen); 1437 data = xmalloc(conn->transfer_buflen);
1409 1438
1410 /* Read from local and write to remote */ 1439 /* Read from local and write to remote */
1411 offset = 0; 1440 offset = progress_counter = 0;
1412 if (showprogress) 1441 if (showprogress)
1413 start_progress_meter(local_path, sb.st_size, &offset); 1442 start_progress_meter(local_path, sb.st_size,
1443 &progress_counter);
1414 1444
1415 for (;;) { 1445 for (;;) {
1416 int len; 1446 int len;
@@ -1481,7 +1511,8 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1481 debug3("In write loop, ack for %u %u bytes at %lld", 1511 debug3("In write loop, ack for %u %u bytes at %lld",
1482 ack->id, ack->len, (long long)ack->offset); 1512 ack->id, ack->len, (long long)ack->offset);
1483 ++ackid; 1513 ++ackid;
1484 xfree(ack); 1514 progress_counter += ack->len;
1515 free(ack);
1485 } 1516 }
1486 offset += len; 1517 offset += len;
1487 if (offset < 0) 1518 if (offset < 0)
@@ -1491,7 +1522,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1491 1522
1492 if (showprogress) 1523 if (showprogress)
1493 stop_progress_meter(); 1524 stop_progress_meter();
1494 xfree(data); 1525 free(data);
1495 1526
1496 if (status != SSH2_FX_OK) { 1527 if (status != SSH2_FX_OK) {
1497 error("Couldn't write to remote file \"%s\": %s", 1528 error("Couldn't write to remote file \"%s\": %s",
@@ -1511,7 +1542,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
1511 1542
1512 if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 1543 if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
1513 status = -1; 1544 status = -1;
1514 xfree(handle); 1545 free(handle);
1515 1546
1516 return status; 1547 return status;
1517} 1548}
@@ -1551,7 +1582,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1551 a.perm &= 01777; 1582 a.perm &= 01777;
1552 if (!pflag) 1583 if (!pflag)
1553 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 1584 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
1554 1585
1555 status = do_mkdir(conn, dst, &a, 0); 1586 status = do_mkdir(conn, dst, &a, 0);
1556 /* 1587 /*
1557 * we lack a portable status for errno EEXIST, 1588 * we lack a portable status for errno EEXIST,
@@ -1561,7 +1592,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1561 if (status != SSH2_FX_OK) { 1592 if (status != SSH2_FX_OK) {
1562 if (status != SSH2_FX_FAILURE) 1593 if (status != SSH2_FX_FAILURE)
1563 return -1; 1594 return -1;
1564 if (do_stat(conn, dst, 0) == NULL) 1595 if (do_stat(conn, dst, 0) == NULL)
1565 return -1; 1596 return -1;
1566 } 1597 }
1567 1598
@@ -1569,7 +1600,7 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1569 error("Failed to open dir \"%s\": %s", src, strerror(errno)); 1600 error("Failed to open dir \"%s\": %s", src, strerror(errno));
1570 return -1; 1601 return -1;
1571 } 1602 }
1572 1603
1573 while (((dp = readdir(dirp)) != NULL) && !interrupted) { 1604 while (((dp = readdir(dirp)) != NULL) && !interrupted) {
1574 if (dp->d_ino == 0) 1605 if (dp->d_ino == 0)
1575 continue; 1606 continue;
@@ -1597,8 +1628,8 @@ upload_dir_internal(struct sftp_conn *conn, char *src, char *dst,
1597 } 1628 }
1598 } else 1629 } else
1599 logit("%s: not a regular file\n", filename); 1630 logit("%s: not a regular file\n", filename);
1600 xfree(new_dst); 1631 free(new_dst);
1601 xfree(new_src); 1632 free(new_src);
1602 } 1633 }
1603 1634
1604 do_setstat(conn, dst, &a); 1635 do_setstat(conn, dst, &a);
@@ -1620,7 +1651,7 @@ upload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag,
1620 } 1651 }
1621 1652
1622 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); 1653 ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0);
1623 xfree(dst_canon); 1654 free(dst_canon);
1624 return ret; 1655 return ret;
1625} 1656}
1626 1657