From ed94d3eea7d46dd3979e64c7599f55b7f21ae2f4 Mon Sep 17 00:00:00 2001 From: Kuan-Yi Li Date: Mon, 2 Mar 2026 02:50:24 +0800 Subject: [PATCH] apk: bump to 3.0.5 Several OpenWrt-related fixes are included in this release. Drop upstreamed patches and refresh the rest. Signed-off-by: Kuan-Yi Li Link: https://github.com/openwrt/openwrt/pull/22240 Signed-off-by: Christian Marangi --- package/system/apk/Makefile | 8 +- ...openwrt-move-layer-db-to-temp-folder.patch | 2 +- ...d-fetch-timestamps-with-wget-backend.patch | 33 --- .../0030-defines-align-apk_array.patch | 25 -- ...efines-rework-apk_unaligned_-helpers.patch | 96 ------- ...v3-fix-unaligned-access-of-file-mode.patch | 33 --- ...stream-buffer-alignment-with-file-of.patch | 240 ------------------ ...edge-case-when-refilling-read-buffer.patch | 29 --- 8 files changed, 5 insertions(+), 461 deletions(-) delete mode 100644 package/system/apk/patches/0020-io-fix-invalid-fetch-timestamps-with-wget-backend.patch delete mode 100644 package/system/apk/patches/0030-defines-align-apk_array.patch delete mode 100644 package/system/apk/patches/0031-defines-rework-apk_unaligned_-helpers.patch delete mode 100644 package/system/apk/patches/0032-extract_v3-fix-unaligned-access-of-file-mode.patch delete mode 100644 package/system/apk/patches/0033-io-synchronize-istream-buffer-alignment-with-file-of.patch delete mode 100644 package/system/apk/patches/0034-io-handle-edge-case-when-refilling-read-buffer.patch diff --git a/package/system/apk/Makefile b/package/system/apk/Makefile index 98902565e2..945722c6c0 100644 --- a/package/system/apk/Makefile +++ b/package/system/apk/Makefile @@ -1,14 +1,14 @@ include $(TOPDIR)/rules.mk PKG_NAME:=apk -PKG_RELEASE:=5 +PKG_RELEASE:=1 PKG_SOURCE_URL=https://gitlab.alpinelinux.org/alpine/apk-tools.git PKG_SOURCE_PROTO:=git -PKG_SOURCE_VERSION:=d093f7c198a64bff0cd58afeaf638909fda24ca8 -PKG_MIRROR_HASH:=596dffa2fa019be2755433ed210e30593a6a8708346cf31486d6ad8008e47556 +PKG_SOURCE_VERSION:=b5a31c0d865342ad80be10d68f1bb3d3ad9b0866 +PKG_MIRROR_HASH:=bdb70571302d4baeafd4558522a49ce4c834c2acb51b954a19a3eea7f20b01b7 -PKG_VERSION=3.0.2 +PKG_VERSION=3.0.5 PKG_MAINTAINER:=Paul Spooren PKG_LICENSE:=GPL-2.0-only diff --git a/package/system/apk/patches/0001-openwrt-move-layer-db-to-temp-folder.patch b/package/system/apk/patches/0001-openwrt-move-layer-db-to-temp-folder.patch index 79e94f78b0..56cf1b742b 100644 --- a/package/system/apk/patches/0001-openwrt-move-layer-db-to-temp-folder.patch +++ b/package/system/apk/patches/0001-openwrt-move-layer-db-to-temp-folder.patch @@ -10,7 +10,7 @@ Signed-off-by: Paul Spooren --- a/src/database.c +++ b/src/database.c -@@ -1919,7 +1919,7 @@ const char *apk_db_layer_name(int layer) +@@ -1935,7 +1935,7 @@ const char *apk_db_layer_name(int layer) { switch (layer) { case APK_DB_LAYER_ROOT: return "lib/apk/db"; diff --git a/package/system/apk/patches/0020-io-fix-invalid-fetch-timestamps-with-wget-backend.patch b/package/system/apk/patches/0020-io-fix-invalid-fetch-timestamps-with-wget-backend.patch deleted file mode 100644 index f10f135d20..0000000000 --- a/package/system/apk/patches/0020-io-fix-invalid-fetch-timestamps-with-wget-backend.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 42f159e67bafe1dad16839c0c0a005b5e89487ba Mon Sep 17 00:00:00 2001 -From: Matt Merhar -Date: Sun, 1 Feb 2026 21:16:01 -0500 -Subject: [PATCH] io: fix invalid fetch timestamps with wget backend - -In OpenWrt it was noticed that files downloaded via 'apk fetch' had -huge, invalid timestamps. - -An strace showed utimensat_time64() being called with tv_sec values like --5268223168728060756 and 1167423650789556, causing even an 'ls -l' of -the file afterwards to crash busybox. - -The explanation here is that the process_get_meta() stub in process.c -doesn't set anything, so the struct is filled with garbage. - -To address this, zero init the struct in apk_ostream_copy_meta(). This -leads to the timestamp of the downloaded file being set to the current -time. ---- - src/io.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/src/io.c -+++ b/src/io.c -@@ -1258,7 +1258,7 @@ int apk_ostream_fmt(struct apk_ostream * - - void apk_ostream_copy_meta(struct apk_ostream *os, struct apk_istream *is) - { -- struct apk_file_meta meta; -+ struct apk_file_meta meta = { 0 }; - apk_istream_get_meta(is, &meta); - os->ops->set_meta(os, &meta); - } diff --git a/package/system/apk/patches/0030-defines-align-apk_array.patch b/package/system/apk/patches/0030-defines-align-apk_array.patch deleted file mode 100644 index f024f02af4..0000000000 --- a/package/system/apk/patches/0030-defines-align-apk_array.patch +++ /dev/null @@ -1,25 +0,0 @@ -From fb856c4233202c489be5c6a2335da75bafab0a56 Mon Sep 17 00:00:00 2001 -From: Matt Merhar -Date: Tue, 3 Feb 2026 23:01:41 -0500 -Subject: [PATCH 1/4] defines: align apk_array - --fsanitize=alignment complained about this one, though no issues were -otherwise encountered during runtime. - -While x86-64 wants 8 byte alignment, 32-bit ARM hits SIGILL; so, use -sizeof(void *) to tune it per target. ---- - src/apk_defines.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/src/apk_defines.h -+++ b/src/apk_defines.h -@@ -178,7 +178,7 @@ struct apk_array { - uint32_t num; - uint32_t capacity : 31; - uint32_t allocated : 1; --}; -+} __attribute__((aligned(sizeof(void *)))); - - extern const struct apk_array _apk_array_empty; - diff --git a/package/system/apk/patches/0031-defines-rework-apk_unaligned_-helpers.patch b/package/system/apk/patches/0031-defines-rework-apk_unaligned_-helpers.patch deleted file mode 100644 index e2396f2c0e..0000000000 --- a/package/system/apk/patches/0031-defines-rework-apk_unaligned_-helpers.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 783fbbd591982749714fba784318bf0fac3c9d41 Mon Sep 17 00:00:00 2001 -From: Matt Merhar -Date: Tue, 3 Feb 2026 23:01:41 -0500 -Subject: [PATCH 2/4] defines: rework apk_unaligned_* helpers - -These only work properly on little endian input words, and -apk_unaligned_u64a32 won't work correctly as-is on big endian systems. - -Change the suffixes to explicitly call out this "limitation" and switch -the uint64_t variant to operate on single bytes as the others already do -so it works as expected on big endian hosts. - -And, add a uint16_t variant. ---- - src/adb.c | 2 +- - src/apk_defines.h | 22 ++++++++++++++++------ - src/blob.c | 2 +- - src/database.c | 2 +- - 4 files changed, 19 insertions(+), 9 deletions(-) - ---- a/src/adb.c -+++ b/src/adb.c -@@ -434,7 +434,7 @@ uint64_t adb_r_int(const struct adb *db, - case ADB_TYPE_INT_64: - ptr = adb_r_deref(db, v, 0, sizeof(uint64_t)); - if (!ptr) return 0; -- return le64toh(apk_unaligned_u64a32(ptr)); -+ return apk_unaligned_le64(ptr); - default: - return 0; - } ---- a/src/apk_defines.h -+++ b/src/apk_defines.h -@@ -151,24 +151,34 @@ static inline uint64_t apk_calc_installe - } - - #if defined(__x86_64__) || defined(__i386__) --static inline uint32_t apk_unaligned_u32(const void *ptr) -+static inline uint16_t apk_unaligned_le16(const void *ptr) -+{ -+ return *(const uint16_t *)ptr; -+} -+static inline uint32_t apk_unaligned_le32(const void *ptr) - { - return *(const uint32_t *)ptr; - } --static inline uint64_t apk_unaligned_u64a32(const void *ptr) -+static inline uint64_t apk_unaligned_le64(const void *ptr) - { - return *(const uint64_t *)ptr; - } - #else --static inline uint32_t apk_unaligned_u32(const void *ptr) -+static inline uint16_t apk_unaligned_le16(const void *ptr) -+{ -+ const uint8_t *p = ptr; -+ return p[0] | (uint16_t)p[1] << 8; -+} -+static inline uint32_t apk_unaligned_le32(const void *ptr) - { - const uint8_t *p = ptr; - return p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; - } --static inline uint64_t apk_unaligned_u64a32(const void *ptr) -+static inline uint64_t apk_unaligned_le64(const void *ptr) - { -- const uint32_t *p = ptr; -- return p[0] | (uint64_t)p[1] << 32; -+ const uint8_t *p = ptr; -+ return p[0] | (uint64_t)p[1] << 8 | (uint64_t)p[2] << 16 | (uint64_t)p[3] << 24 | -+ (uint64_t)p[4] << 32 | (uint64_t)p[5] << 40 | (uint64_t)p[6] << 48 | (uint64_t)p[7] << 56; - } - #endif - ---- a/src/blob.c -+++ b/src/blob.c -@@ -98,7 +98,7 @@ static uint32_t murmur3_32(const void *p - int i; - - for (i = 0; i < nblocks; i++, key += 4) { -- k = apk_unaligned_u32(key); -+ k = apk_unaligned_le32(key); - k *= c1; - k = rotl32(k, 15); - k *= c2; ---- a/src/database.c -+++ b/src/database.c -@@ -90,7 +90,7 @@ static unsigned long csum_hash(apk_blob_ - /* Checksum's highest bits have the most "randomness", use that - * directly as hash */ - if (csum.len >= sizeof(uint32_t)) -- return apk_unaligned_u32(csum.ptr); -+ return apk_unaligned_le32(csum.ptr); - return 0; - } - diff --git a/package/system/apk/patches/0032-extract_v3-fix-unaligned-access-of-file-mode.patch b/package/system/apk/patches/0032-extract_v3-fix-unaligned-access-of-file-mode.patch deleted file mode 100644 index 3f72de2a09..0000000000 --- a/package/system/apk/patches/0032-extract_v3-fix-unaligned-access-of-file-mode.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 98da5aa6b2539c28459f303fb06891df86a5b4c7 Mon Sep 17 00:00:00 2001 -From: Matt Merhar -Date: Tue, 3 Feb 2026 23:01:41 -0500 -Subject: [PATCH 3/4] extract_v3: fix unaligned access of file mode - -This is one of a couple places that frequently caused apk operations -to mysteriously fail on the OpenWrt kirkwood target (ARMv5TE); in this -particular case, APKE_ADB_SCHEMA would be returned. - -GDB showed the octal mode value being a nonsensical '022' whereas -referencing the original memory showed the expected 0120000 (S_IFLNK): - - (gdb) p/o *(uint16_t*)(target.ptr - 2) - $67 = 0120000 - (gdb) p/o mode - $68 = 022 - -So, utilize the newly added apk_unaligned_le16() to access it. ---- - src/extract_v3.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - ---- a/src/extract_v3.c -+++ b/src/extract_v3.c -@@ -73,7 +73,7 @@ static int apk_extract_v3_file(struct ap - uint16_t mode; - - if (target.len < 2) goto err_schema; -- mode = le16toh(*(uint16_t*)target.ptr); -+ mode = apk_unaligned_le16(target.ptr); - target.ptr += 2; - target.len -= 2; - switch (mode) { diff --git a/package/system/apk/patches/0033-io-synchronize-istream-buffer-alignment-with-file-of.patch b/package/system/apk/patches/0033-io-synchronize-istream-buffer-alignment-with-file-of.patch deleted file mode 100644 index bac6324d21..0000000000 --- a/package/system/apk/patches/0033-io-synchronize-istream-buffer-alignment-with-file-of.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 2cb386c75518ca4df5348d1f29c75ac923fc847c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Timo=20Ter=C3=A4s?= -Date: Thu, 5 Feb 2026 13:07:04 +0200 -Subject: [PATCH 4/4] io: synchronize istream buffer alignment with file - offset - -To correctly guarantee buffer alignment for apk_istream_get() reads -the buffer needs to be aligned with the file offset. Fixup the -io code to properly synchronize the alignment. - -This removes unaligned memory reads in various places. In practice -this speeds up things and fixes the faults/read errors on platforms -where unaligned access is an error. ---- - src/apk_io.h | 3 ++- - src/io.c | 37 +++++++++++++++++--------- - src/io_gunzip.c | 2 ++ - src/io_url_libfetch.c | 2 ++ - src/process.c | 2 ++ - test/unit/io_test.c | 62 +++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 94 insertions(+), 14 deletions(-) - ---- a/src/apk_io.h -+++ b/src/apk_io.h -@@ -82,7 +82,7 @@ struct apk_istream { - unsigned int flags; - struct apk_progress *prog; - const struct apk_istream_ops *ops; --}; -+} __attribute__((aligned(8))); - - typedef int (*apk_archive_entry_parser)(void *ctx, - const struct apk_file_info *ae, -@@ -144,6 +144,7 @@ struct apk_segment_istream { - struct apk_istream *pis; - uint64_t bytes_left; - time_t mtime; -+ uint8_t align; - }; - struct apk_istream *apk_istream_segment(struct apk_segment_istream *sis, struct apk_istream *is, uint64_t len, time_t mtime); - ---- a/src/io.c -+++ b/src/io.c -@@ -33,6 +33,9 @@ - #define HAVE_O_TMPFILE - #endif - -+// The granularity for the file offset and istream buffer alignment synchronization. -+#define APK_ISTREAM_ALIGN_SYNC 8 -+ - size_t apk_io_bufsize = 128*1024; - - -@@ -111,16 +114,16 @@ ssize_t apk_istream_read_max(struct apk_ - if (left > is->buf_size/4) { - r = is->ops->read(is, ptr, left); - if (r <= 0) break; -+ is->ptr = is->end = &is->buf[(is->ptr - is->buf + r) % APK_ISTREAM_ALIGN_SYNC]; - left -= r; - ptr += r; - continue; - } - -- r = is->ops->read(is, is->buf, is->buf_size); -+ r = is->ops->read(is, is->ptr, is->buf + is->buf_size - is->ptr); - if (r <= 0) break; - -- is->ptr = is->buf; -- is->end = is->buf + r; -+ is->end = is->ptr + r; - } - - if (r < 0) return apk_istream_error(is, r); -@@ -136,19 +139,20 @@ int apk_istream_read(struct apk_istream - - static int __apk_istream_fill(struct apk_istream *is) - { -- ssize_t sz; -- - if (is->err) return is->err; - -- if (is->ptr != is->buf) { -- sz = is->end - is->ptr; -- memmove(is->buf, is->ptr, sz); -- is->ptr = is->buf; -- is->end = is->buf + sz; -- } else if (is->end-is->ptr == is->buf_size) -- return -ENOBUFS; -+ size_t offs = is->ptr - is->buf; -+ if (offs >= APK_ISTREAM_ALIGN_SYNC) { -+ size_t buf_used = is->end - is->ptr; -+ uint8_t *ptr = &is->buf[offs % APK_ISTREAM_ALIGN_SYNC]; -+ memmove(ptr, is->ptr, buf_used); -+ is->ptr = ptr; -+ is->end = ptr + buf_used; -+ } else { -+ if (is->end == is->buf+is->buf_size) return -ENOBUFS; -+ } - -- sz = is->ops->read(is, is->end, is->buf + is->buf_size - is->end); -+ ssize_t sz = is->ops->read(is, is->end, is->buf + is->buf_size - is->end); - if (sz <= 0) return apk_istream_error(is, sz ?: 1); - is->end += sz; - return 0; -@@ -282,6 +286,7 @@ static ssize_t segment_read(struct apk_i - if (r == 0) r = -ECONNABORTED; - } else { - sis->bytes_left -= r; -+ sis->align += r; - } - return r; - } -@@ -290,6 +295,7 @@ static int segment_close(struct apk_istr - { - struct apk_segment_istream *sis = container_of(is, struct apk_segment_istream, is); - -+ if (!sis->pis->ptr) sis->pis->ptr = sis->pis->end = &is->buf[sis->align % APK_ISTREAM_ALIGN_SYNC]; - if (sis->bytes_left) apk_istream_skip(sis->pis, sis->bytes_left); - return is->err < 0 ? is->err : 0; - } -@@ -316,6 +322,9 @@ struct apk_istream *apk_istream_segment( - sis->is.end = sis->is.ptr + len; - is->ptr += len; - } else { -+ // Calculated at segment_closet again, set to null to catch if -+ // the inner istream is used before segment close. -+ sis->align = is->end - is->buf; - is->ptr = is->end = 0; - } - sis->bytes_left -= sis->is.end - sis->is.ptr; -@@ -600,6 +609,8 @@ struct apk_istream *apk_istream_from_fd( - .is.ops = &fd_istream_ops, - .is.buf = (uint8_t *)(fis + 1), - .is.buf_size = apk_io_bufsize, -+ .is.ptr = (uint8_t *)(fis + 1), -+ .is.end = (uint8_t *)(fis + 1), - .fd = fd, - }; - ---- a/src/io_gunzip.c -+++ b/src/io_gunzip.c -@@ -165,6 +165,8 @@ struct apk_istream *apk_istream_zlib(str - .is.ops = &gunzip_istream_ops, - .is.buf = (uint8_t*)(gis + 1), - .is.buf_size = apk_io_bufsize, -+ .is.ptr = (uint8_t*)(gis + 1), -+ .is.end = (uint8_t*)(gis + 1), - .zis = is, - .cb = cb, - .cbctx = ctx, ---- a/src/io_url_libfetch.c -+++ b/src/io_url_libfetch.c -@@ -161,6 +161,8 @@ struct apk_istream *apk_io_url_istream(c - .is.ops = &fetch_istream_ops, - .is.buf = (uint8_t*)(fis+1), - .is.buf_size = apk_io_bufsize, -+ .is.ptr = (uint8_t*)(fis+1), -+ .is.end = (uint8_t*)(fis+1), - .fetchIO = io, - .urlstat = fis->urlstat, - }; ---- a/src/process.c -+++ b/src/process.c -@@ -317,6 +317,8 @@ struct apk_istream *apk_process_istream( - .is.ops = &process_istream_ops, - .is.buf = (uint8_t *)(pis + 1), - .is.buf_size = apk_io_bufsize, -+ .is.ptr = (uint8_t *)(pis + 1), -+ .is.end = (uint8_t *)(pis + 1), - }; - r = apk_process_init(&pis->proc, apk_last_path_segment(argv[0]), logpfx, out, NULL); - if (r != 0) goto err; ---- a/test/unit/io_test.c -+++ b/test/unit/io_test.c -@@ -119,3 +119,65 @@ APK_TEST(io_foreach_config_file) { - - assert_int_equal(0, apk_dir_foreach_config_file(MOCKFD, assert_path_entry, NULL, apk_filename_is_hidden, "a", "b", NULL)); - } -+ -+APK_TEST(io_istream_align) { -+ struct apk_istream *is = apk_istream_from_file(AT_FDCWD, "/dev/zero"); -+ struct apk_segment_istream seg; -+ size_t bufsz = 1024*1024; -+ uint8_t *buf = malloc(bufsz), *ptr; -+ -+ assert_int_equal(0, apk_istream_read(is, buf, 1024)); -+ -+ ptr = apk_istream_get(is, 1024); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ assert_ptr_ok(apk_istream_get(is, 7)); -+ assert_ptr_ok(apk_istream_get(is, apk_io_bufsize - 1024)); -+ assert_ptr_ok(apk_istream_get(is, 1)); -+ -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ assert_int_equal(0, apk_istream_read(is, buf, bufsz - 1)); -+ assert_int_equal(0, apk_istream_read(is, buf, 1)); -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ apk_istream_segment(&seg, is, 1024-1, 0); -+ apk_istream_close(&seg.is); -+ assert_ptr_ok(apk_istream_get(is, 1)); -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ apk_istream_segment(&seg, is, bufsz-1, 0); -+ apk_istream_close(&seg.is); -+ assert_ptr_ok(apk_istream_get(is, 1)); -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ assert_ptr_ok(apk_istream_get(is, 7)); -+ apk_istream_segment(&seg, is, bufsz-7, 0); -+ assert_int_equal(0, apk_istream_read(&seg.is, buf, bufsz-10)); -+ assert_int_equal(0, apk_istream_read(&seg.is, buf, 1)); -+ apk_istream_close(&seg.is); -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ apk_istream_segment(&seg, is, bufsz*2+1, 0); -+ assert_int_equal(0, apk_istream_read(&seg.is, buf, bufsz)); -+ assert_int_equal(0, apk_istream_read(&seg.is, buf, bufsz)); -+ apk_istream_close(&seg.is); -+ assert_int_equal(0, apk_istream_read(is, buf, 7)); -+ ptr = apk_istream_get(is, 64); -+ assert_ptr_ok(ptr); -+ assert_int_equal(0, (uintptr_t)ptr & 7); -+ -+ apk_istream_close(is); -+ free(buf); -+} diff --git a/package/system/apk/patches/0034-io-handle-edge-case-when-refilling-read-buffer.patch b/package/system/apk/patches/0034-io-handle-edge-case-when-refilling-read-buffer.patch deleted file mode 100644 index 9bc143e0e6..0000000000 --- a/package/system/apk/patches/0034-io-handle-edge-case-when-refilling-read-buffer.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 1e985a4444d8c9ab5a0804b555858dcf518b243a Mon Sep 17 00:00:00 2001 -From: Matt Merhar -Date: Wed, 11 Feb 2026 16:04:52 -0500 -Subject: [PATCH] io: handle edge case when refilling read buffer - -This caused failures when processing specific (< 0.1%) .apk files in -the packages feed. - -It affected packages with a header size greater than the read buffer -size of 128KB but less than 160KB (128KB + (128KB / 4)). - -In those cases, we'd attempt a 0 byte read, leading to APKE_EOF. ---- - src/io.c | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/src/io.c -+++ b/src/io.c -@@ -120,6 +120,10 @@ ssize_t apk_istream_read_max(struct apk_ - continue; - } - -+ if (is->ptr - is->buf >= APK_ISTREAM_ALIGN_SYNC) { -+ is->ptr = is->end = is->buf + ((is->ptr - is->buf) % APK_ISTREAM_ALIGN_SYNC); -+ } -+ - r = is->ops->read(is, is->ptr, is->buf + is->buf_size - is->ptr); - if (r <= 0) break; -