diff options
Diffstat (limited to 'libbb/copyfd.c')
-rw-r--r-- | libbb/copyfd.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/libbb/copyfd.c b/libbb/copyfd.c index f42eb7623..82622c06f 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c | |||
@@ -9,19 +9,29 @@ | |||
9 | 9 | ||
10 | #include "libbb.h" | 10 | #include "libbb.h" |
11 | 11 | ||
12 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */ | 12 | /* Used by NOFORK applets (e.g. cat) - must not use xmalloc. |
13 | 13 | * size < 0 means "ignore write errors", used by tar --to-command | |
14 | * size = 0 means "copy till EOF" | ||
15 | */ | ||
14 | static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | 16 | static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) |
15 | { | 17 | { |
16 | int status = -1; | 18 | int status = -1; |
17 | off_t total = 0; | 19 | off_t total = 0; |
20 | bool continue_on_write_error = 0; | ||
18 | #if CONFIG_FEATURE_COPYBUF_KB <= 4 | 21 | #if CONFIG_FEATURE_COPYBUF_KB <= 4 |
19 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; | 22 | char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; |
20 | enum { buffer_size = sizeof(buffer) }; | 23 | enum { buffer_size = sizeof(buffer) }; |
21 | #else | 24 | #else |
22 | char *buffer; | 25 | char *buffer; |
23 | int buffer_size; | 26 | int buffer_size; |
27 | #endif | ||
24 | 28 | ||
29 | if (size < 0) { | ||
30 | size = -size; | ||
31 | continue_on_write_error = 1; | ||
32 | } | ||
33 | |||
34 | #if CONFIG_FEATURE_COPYBUF_KB > 4 | ||
25 | if (size > 0 && size <= 4 * 1024) | 35 | if (size > 0 && size <= 4 * 1024) |
26 | goto use_small_buf; | 36 | goto use_small_buf; |
27 | /* We want page-aligned buffer, just in case kernel is clever | 37 | /* We want page-aligned buffer, just in case kernel is clever |
@@ -63,8 +73,11 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) | |||
63 | if (dst_fd >= 0) { | 73 | if (dst_fd >= 0) { |
64 | ssize_t wr = full_write(dst_fd, buffer, rd); | 74 | ssize_t wr = full_write(dst_fd, buffer, rd); |
65 | if (wr < rd) { | 75 | if (wr < rd) { |
66 | bb_perror_msg(bb_msg_write_error); | 76 | if (!continue_on_write_error) { |
67 | break; | 77 | bb_perror_msg(bb_msg_write_error); |
78 | break; | ||
79 | } | ||
80 | dst_fd = -1; | ||
68 | } | 81 | } |
69 | } | 82 | } |
70 | total += rd; | 83 | total += rd; |
@@ -108,7 +121,7 @@ off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size) | |||
108 | void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) | 121 | void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) |
109 | { | 122 | { |
110 | off_t sz = bb_copyfd_size(fd1, fd2, size); | 123 | off_t sz = bb_copyfd_size(fd1, fd2, size); |
111 | if (sz == size) | 124 | if (sz == (size >= 0 ? size : -size)) |
112 | return; | 125 | return; |
113 | if (sz != -1) | 126 | if (sz != -1) |
114 | bb_error_msg_and_die("short read"); | 127 | bb_error_msg_and_die("short read"); |