summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHauke Mehrtens2026-04-23 22:15:05 +0000
committerHauke Mehrtens2026-06-07 11:23:35 +0000
commit568c447950c1f7265767b954198daff0d8806675 (patch)
tree05287c7b7768134c4e71a8dfe12a2ccd65f4795f
parent5cb19466d076ad6c811a0d9aec016316be34c391 (diff)
downloaduclient-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.c21
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;
}
}
}