diff options
| author | Hauke Mehrtens | 2026-04-23 22:15:05 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-06-07 11:23:35 +0000 |
| commit | 568c447950c1f7265767b954198daff0d8806675 (patch) | |
| tree | 05287c7b7768134c4e71a8dfe12a2ccd65f4795f | |
| parent | 5cb19466d076ad6c811a0d9aec016316be34c391 (diff) | |
| download | uclient-568c447950c1f7265767b954198daff0d8806675.tar.gz | |
uclient-fetch: retry short writes and surface errors
write(2) is permitted to return fewer bytes than requested. The data
callback silently dropped the unwritten tail, resulting in truncated
output files whose out_bytes counter disagreed with the actual file
size. A write error was also treated as success and left the partial
file in place.
Loop until all bytes from the current chunk are persisted, retry on
EINTR, and abort the download on a real write failure.
Assisted-by: Claude:claude-opus-4-7
Link: https://github.com/openwrt/uclient/pull/16
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
| -rw-r--r-- | uclient-fetch.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/uclient-fetch.c b/uclient-fetch.c index 1ca2732..39347e4 100644 --- a/uclient-fetch.c +++ b/uclient-fetch.c @@ -28,6 +28,7 @@ #include <stdint.h> #include <inttypes.h> #include <signal.h> +#include <errno.h> #include <libubox/blobmsg.h> #include <libubox/list.h> @@ -272,7 +273,7 @@ static void read_data_cb(struct uclient *cl) { char buf[256]; ssize_t n; - int len; + int len, offset; if (!no_output && output_fd < 0) return; @@ -283,10 +284,22 @@ static void read_data_cb(struct uclient *cl) return; out_bytes += len; - if (!no_output) { - n = write(output_fd, buf, len); - if (n < 0) + if (no_output) + continue; + + offset = 0; + while (offset < len) { + n = write(output_fd, buf + offset, len - offset); + if (n < 0) { + if (errno == EINTR) + continue; + if (!quiet) + perror("Write to output file failed"); + error_ret = 2; + request_done(cl); return; + } + offset += n; } } } |