diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-13 15:27:23 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-02-13 15:27:23 +0100 |
commit | adc540f0dbcd640b37f39364aa4a1c6857a96a96 (patch) | |
tree | 400e54e15e2320ba443205152146634857b1f1c0 | |
parent | 0c4e5977dfc32b54e452cd88a9cf14afde29c89d (diff) | |
download | busybox-w32-adc540f0dbcd640b37f39364aa4a1c6857a96a96.tar.gz busybox-w32-adc540f0dbcd640b37f39364aa4a1c6857a96a96.tar.bz2 busybox-w32-adc540f0dbcd640b37f39364aa4a1c6857a96a96.zip |
tftp: on download, open local file only when first bit of data arrived
No reason to potentially clobber existing file before absolutely necessary.
function old new delta
tftp_protocol 1947 2020 +73
tftp_main 393 376 -17
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 73/-17) Total: 56 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/tftp.c | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/networking/tftp.c b/networking/tftp.c index 043747d0d..60fdff232 100644 --- a/networking/tftp.c +++ b/networking/tftp.c | |||
@@ -319,7 +319,7 @@ static int tftp_protocol( | |||
319 | uint16_t opcode; | 319 | uint16_t opcode; |
320 | uint16_t block_nr; | 320 | uint16_t block_nr; |
321 | uint16_t recv_blk; | 321 | uint16_t recv_blk; |
322 | int open_mode, local_fd; | 322 | int local_fd = -1; |
323 | int retries, waittime_ms; | 323 | int retries, waittime_ms; |
324 | int io_bufsize = blksize + 4; | 324 | int io_bufsize = blksize + 4; |
325 | char *cp; | 325 | char *cp; |
@@ -354,19 +354,6 @@ static int tftp_protocol( | |||
354 | } | 354 | } |
355 | } | 355 | } |
356 | 356 | ||
357 | /* Prepare open mode */ | ||
358 | if (CMD_PUT(option_mask32)) { | ||
359 | open_mode = O_RDONLY; | ||
360 | } else { | ||
361 | open_mode = O_WRONLY | O_TRUNC | O_CREAT; | ||
362 | #if ENABLE_TFTPD | ||
363 | if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) { | ||
364 | /* tftpd without -c */ | ||
365 | open_mode = O_WRONLY | O_TRUNC; | ||
366 | } | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | /* Examples of network traffic. | 357 | /* Examples of network traffic. |
371 | * Note two cases when ACKs with block# of 0 are sent. | 358 | * Note two cases when ACKs with block# of 0 are sent. |
372 | * | 359 | * |
@@ -400,6 +387,14 @@ static int tftp_protocol( | |||
400 | 387 | ||
401 | if (!ENABLE_TFTP || our_lsa) { /* tftpd */ | 388 | if (!ENABLE_TFTP || our_lsa) { /* tftpd */ |
402 | /* Open file (must be after changing user) */ | 389 | /* Open file (must be after changing user) */ |
390 | int open_mode = O_RDONLY; | ||
391 | if (CMD_GET(option_mask32)) { | ||
392 | open_mode = O_WRONLY | O_TRUNC | O_CREAT; | ||
393 | if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) { | ||
394 | /* tftpd without -c */ | ||
395 | open_mode = O_WRONLY | O_TRUNC; | ||
396 | } | ||
397 | } | ||
403 | local_fd = open(local_file, open_mode, 0666); | 398 | local_fd = open(local_file, open_mode, 0666); |
404 | if (local_fd < 0) { | 399 | if (local_fd < 0) { |
405 | /* sanitize name, it came from untrusted remote side */ | 400 | /* sanitize name, it came from untrusted remote side */ |
@@ -414,6 +409,7 @@ static int tftp_protocol( | |||
414 | strcpy(G_error_pkt_str, "can't open file"); | 409 | strcpy(G_error_pkt_str, "can't open file"); |
415 | goto send_err_pkt_nomsg; | 410 | goto send_err_pkt_nomsg; |
416 | } | 411 | } |
412 | |||
417 | /* gcc 4.3.1 would NOT optimize it out as it should! */ | 413 | /* gcc 4.3.1 would NOT optimize it out as it should! */ |
418 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE | 414 | #if ENABLE_FEATURE_TFTP_BLOCKSIZE |
419 | if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) { | 415 | if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) { |
@@ -432,10 +428,11 @@ static int tftp_protocol( | |||
432 | block_nr = 0; | 428 | block_nr = 0; |
433 | } | 429 | } |
434 | } else { /* tftp */ | 430 | } else { /* tftp */ |
435 | /* Open file (must be after changing user) */ | 431 | if (CMD_PUT(option_mask32)) { |
436 | local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO; | 432 | local_fd = STDIN_FILENO; |
437 | if (NOT_LONE_DASH(local_file)) | 433 | if (local_file) |
438 | local_fd = xopen(local_file, open_mode); | 434 | local_fd = xopen(local_file, O_RDONLY); |
435 | } | ||
439 | /* Removing #if, or using if() statement instead of #if may lead to | 436 | /* Removing #if, or using if() statement instead of #if may lead to |
440 | * "warning: null argument where non-null required": */ | 437 | * "warning: null argument where non-null required": */ |
441 | #if ENABLE_TFTP | 438 | #if ENABLE_TFTP |
@@ -491,7 +488,7 @@ static int tftp_protocol( | |||
491 | } | 488 | } |
492 | if (want_transfer_size) { | 489 | if (want_transfer_size) { |
493 | /* add "tsize", <nul>, size, <nul> (see RFC2349) */ | 490 | /* add "tsize", <nul>, size, <nul> (see RFC2349) */ |
494 | /* if tftp and downloading, we send "0" (since we opened local_fd with O_TRUNC) | 491 | /* if tftp and downloading, we send "0" (local_fd is not open yet) |
495 | * and this makes server to send "tsize" option with the size */ | 492 | * and this makes server to send "tsize" option with the size */ |
496 | /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */ | 493 | /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */ |
497 | /* if tftpd and downloading, we are answering to client's request */ | 494 | /* if tftpd and downloading, we are answering to client's request */ |
@@ -500,7 +497,8 @@ static int tftp_protocol( | |||
500 | strcpy(cp, "tsize"); | 497 | strcpy(cp, "tsize"); |
501 | cp += sizeof("tsize"); | 498 | cp += sizeof("tsize"); |
502 | st.st_size = 0; | 499 | st.st_size = 0; |
503 | fstat(local_fd, &st); | 500 | if (local_fd >= 0) |
501 | fstat(local_fd, &st); | ||
504 | cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1; | 502 | cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1; |
505 | # if ENABLE_FEATURE_TFTP_PROGRESS_BAR | 503 | # if ENABLE_FEATURE_TFTP_PROGRESS_BAR |
506 | /* Save for progress bar. If 0 (tftp downloading), | 504 | /* Save for progress bar. If 0 (tftp downloading), |
@@ -690,7 +688,13 @@ static int tftp_protocol( | |||
690 | 688 | ||
691 | if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) { | 689 | if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) { |
692 | if (recv_blk == block_nr) { | 690 | if (recv_blk == block_nr) { |
693 | int sz = full_write(local_fd, &rbuf[4], len - 4); | 691 | int sz; |
692 | if (local_fd == -1) { | ||
693 | local_fd = STDOUT_FILENO; | ||
694 | if (local_file) | ||
695 | local_fd = xopen(local_file, O_WRONLY | O_TRUNC | O_CREAT); | ||
696 | } | ||
697 | sz = full_write(local_fd, &rbuf[4], len - 4); | ||
694 | if (sz != len - 4) { | 698 | if (sz != len - 4) { |
695 | strcpy(G_error_pkt_str, bb_msg_write_error); | 699 | strcpy(G_error_pkt_str, bb_msg_write_error); |
696 | G_error_pkt_reason = ERR_WRITE; | 700 | G_error_pkt_reason = ERR_WRITE; |
@@ -739,7 +743,9 @@ static int tftp_protocol( | |||
739 | free(xbuf); | 743 | free(xbuf); |
740 | free(rbuf); | 744 | free(rbuf); |
741 | } | 745 | } |
742 | return finished == 0; /* returns 1 on failure */ | 746 | if (!finished) |
747 | goto err; | ||
748 | return EXIT_SUCCESS; | ||
743 | 749 | ||
744 | send_read_err_pkt: | 750 | send_read_err_pkt: |
745 | strcpy(G_error_pkt_str, bb_msg_read_error); | 751 | strcpy(G_error_pkt_str, bb_msg_read_error); |
@@ -750,6 +756,9 @@ static int tftp_protocol( | |||
750 | G.error_pkt[1] = TFTP_ERROR; | 756 | G.error_pkt[1] = TFTP_ERROR; |
751 | xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), | 757 | xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), |
752 | &peer_lsa->u.sa, peer_lsa->len); | 758 | &peer_lsa->u.sa, peer_lsa->len); |
759 | err: | ||
760 | if (local_fd >= 0 && CMD_GET(option_mask32) && local_file) | ||
761 | unlink(local_file); | ||
753 | return EXIT_FAILURE; | 762 | return EXIT_FAILURE; |
754 | #undef remote_file | 763 | #undef remote_file |
755 | } | 764 | } |
@@ -767,7 +776,6 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) | |||
767 | # endif | 776 | # endif |
768 | int result; | 777 | int result; |
769 | int port; | 778 | int port; |
770 | IF_GETPUT(int opt;) | ||
771 | 779 | ||
772 | INIT_G(); | 780 | INIT_G(); |
773 | 781 | ||
@@ -808,7 +816,7 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) | |||
808 | } | 816 | } |
809 | } | 817 | } |
810 | 818 | ||
811 | IF_GETPUT(opt =) getopt32(argv, "^" | 819 | getopt32(argv, "^" |
812 | IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p") | 820 | IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p") |
813 | "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:") | 821 | "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:") |
814 | IF_FEATURE_TFTP_HPA_COMPAT("m:") | 822 | IF_FEATURE_TFTP_HPA_COMPAT("m:") |
@@ -859,15 +867,12 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) | |||
859 | # endif | 867 | # endif |
860 | result = tftp_protocol( | 868 | result = tftp_protocol( |
861 | NULL /*our_lsa*/, peer_lsa, | 869 | NULL /*our_lsa*/, peer_lsa, |
862 | local_file, remote_file | 870 | (LONE_DASH(local_file) ? NULL : local_file), remote_file |
863 | IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */) | 871 | IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */) |
864 | IF_FEATURE_TFTP_BLOCKSIZE(, blksize) | 872 | IF_FEATURE_TFTP_BLOCKSIZE(, blksize) |
865 | ); | 873 | ); |
866 | tftp_progress_done(); | 874 | tftp_progress_done(); |
867 | 875 | ||
868 | if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) { | ||
869 | unlink(local_file); | ||
870 | } | ||
871 | return result; | 876 | return result; |
872 | } | 877 | } |
873 | #endif /* ENABLE_TFTP */ | 878 | #endif /* ENABLE_TFTP */ |