| Message ID | 20260929173728.6952-1-f_l_k@t-online.de |
|---|---|
| State | New |
| Headers | show |
| Series | [meta-oe] bmap-writer: honour ImageSize for the last block | expand |
/quiltrc push', 1, 'stdout: Applying patch 0001-Honour-ImageSize-for-the-last-block.patch patch: **** Only garbage was found in the patch input. Patch 0001-Honour-ImageSize-for-the-last-block.patch does not apply (enforce with -f) stderr: ') Also rebase it on master-next when you send fixed v2 On Tue, Sep 29, 2026 at 10:37 AM Markus Volk via lists.openembedded.org <f_l_k=t-online.de@lists.openembedded.org> wrote: > Writing an image whose size is not a multiple of the bmap block size > failed at its last block with "Image ended before the block map did", > because every range was taken to end at (endBlock + 1) * BlockSize. > Add a patch that reads ImageSize from the bmap and clamps the ranges to > it. > > Tested by writing a wic image whose size ends 2048 bytes into its > last 4 KiB block to an NVMe disk. > > AI-Generated: Uses Claude Code (Claude Fable 5.1) > Signed-off-by: Markus Volk <f_l_k@t-online.de> > --- > ...-Honour-ImageSize-for-the-last-block.patch | 85 +++++++++++++++++++ > .../bmap-writer/bmap-writer_1.0.5.bb | 4 +- > 2 files changed, 88 insertions(+), 1 deletion(-) > create mode 100644 > meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch > > diff --git > a/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch > b/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch > new file mode 100644 > index 0000000000..1943256d71 > --- /dev/null > +++ > b/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch > @@ -0,0 +1,85 @@ > +From e63a11dedcdece8b9b285485a86405fd258b37d8 Mon Sep 17 00:00:00 2001 > +From: Markus Volk <f_l_k@t-online.de> > +Date: Tue, 29 Sep 2026 17:29:52 +0200 > +Subject: [PATCH] Honour ImageSize for the last block > + > +bmaptool records the exact image size in ImageSize, and the last block > +of an image whose size is not a multiple of BlockSize is only partly > +filled. Writing and verifying used (endBlock + 1) * BlockSize as the end > +of every range, so the range containing that block asked for more bytes > +than the image has and the write failed with "Image ended before the > +block map did". Read ImageSize and clamp the end of each range to it. > + > +AI-Generated: Uses Claude Code (Claude Fable 5.1) > +Upstream-Status: Pending > +--- > + src/bmap.cpp | 5 +++++ > + src/bmap.h | 1 + > + src/image_writer.cpp | 2 +- > + src/main.cpp | 2 +- > + 4 files changed, 8 insertions(+), 2 deletions(-) > + > +diff --git a/src/bmap.cpp b/src/bmap.cpp > +index fabf2c2..0162ac0 100644 > +--- a/src/bmap.cpp > ++++ b/src/bmap.cpp > +@@ -135,6 +135,7 @@ int parseBMap(const std::string &filename, bmap_t& > bmapData) { > + bmapData.bmapVersion = (version != nullptr) ? > trimWhitespace(version) : "unknown"; > + > + // Parse image information > ++ bmapData.imageSize = requireChildUnsigned(p_root, "ImageSize"); > + bmapData.blocksTotal = requireChildUnsigned(p_root, > "BlocksCount"); > + bmapData.blocksMapped = requireChildUnsigned(p_root, > "MappedBlocksCount"); > + bmapData.blockSize = requireChildUnsigned(p_root, "BlockSize"); > +@@ -200,6 +201,10 @@ int validateBmap(const bmap_t& bmap, uint64_t > deviceSize) { > + if (bmap.blocksTotal == 0) { > + throw BmapError("BMAP: BlocksCount must not be zero"); > + } > ++ if (bmap.imageSize > bmap.blocksTotal * bmap.blockSize || > ++ bmap.imageSize <= (bmap.blocksTotal - 1) * bmap.blockSize) { > ++ throw BmapError("BMAP: ImageSize does not match BlocksCount > and BlockSize"); > ++ } > + if (bmap.blocksMapped > bmap.blocksTotal) { > + throw BmapError("BMAP: MappedBlocksCount exceeds > BlocksCount"); > + } > +diff --git a/src/bmap.h b/src/bmap.h > +index cf6ff9d..98cb969 100644 > +--- a/src/bmap.h > ++++ b/src/bmap.h > +@@ -38,6 +38,7 @@ struct bmap_t { > + std::string checksumType; > + size_t blockSize = 0; > + size_t blocksTotal = 0; > ++ size_t imageSize = 0; > + size_t blocksMapped = 0; > + std::string bmapVersion; > + std::string bmapChecksum; > +diff --git a/src/image_writer.cpp b/src/image_writer.cpp > +index bb802ea..f864151 100644 > +--- a/src/image_writer.cpp > ++++ b/src/image_writer.cpp > +@@ -177,7 +177,7 @@ int BmapWriteImage(int fd, const bmap_t &bmap, int > dev_fd, const std::string &de > + for (const auto &range : bmap.ranges) { > + // validateBmap() has already proven that none of this can > overflow. > + const size_t outStart = range.startBlock * bmap.blockSize; > +- const size_t outEnd = (range.endBlock + 1) * bmap.blockSize; > ++ const size_t outEnd = std::min((range.endBlock + 1) * > bmap.blockSize, bmap.imageSize); > + const size_t rangeSize = outEnd - outStart; > + const off_t writeOffset = static_cast<off_t>(outStart); > + size_t writtenSize = 0; > +diff --git a/src/main.cpp b/src/main.cpp > +index ca42c12..b8cbbc5 100644 > +--- a/src/main.cpp > ++++ b/src/main.cpp > +@@ -166,7 +166,7 @@ int main(int argc, char *argv[]) { > + FdGuard imageGuard(image_fd); > + > + std::cout << "BMAP format version: " << bmap.bmapVersion << > std::endl; > +- std::cout << "Image size: " << (bmap.blocksTotal * bmap.blockSize) > << " bytes" << std::endl; > ++ std::cout << "Image size: " << bmap.imageSize << " bytes" << > std::endl; > + std::cout << "Block size: " << bmap.blockSize << " bytes" << > std::endl; > + std::cout << "Mapped blocks: " << bmap.blocksMapped << " out of " << > bmap.blocksTotal > + << " (" << std::fixed << std::setprecision(1) > +-- > +2.55.0 > + > diff --git a/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb > b/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb > index 160d1b7112..5d493f3122 100644 > --- a/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb > +++ b/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb > @@ -8,7 +8,9 @@ SECTION = "console/utils" > LICENSE = "GPL-3.0-only" > LIC_FILES_CHKSUM = "file://LICENSE;md5=e49f4652534af377a713df3d9dec60cb" > > -SRC_URI = "git:// > github.com/embetrix/${BPN};branch=master;protocol=https;tag=${PV} > <http://github.com/embetrix/$%7BBPN%7D;branch=master;protocol=https;tag=$%7BPV%7D> > " > +SRC_URI = "git:// > github.com/embetrix/${BPN};branch=master;protocol=https;tag=${PV} > <http://github.com/embetrix/$%7BBPN%7D;branch=master;protocol=https;tag=$%7BPV%7D> > \ > + file://0001-Honour-ImageSize-for-the-last-block.patch \ > + " > SRCREV = "c7b1bec0f40217d17e315226552e461a4a816abc" > > DEPENDS = "libtinyxml2 libarchive" > -- > 2.55.0 > > > -=-=-=-=-=-=-=-=-=-=-=- > Links: You receive all messages sent to this group. > View/Reply Online (#130486): > https://lists.openembedded.org/g/openembedded-devel/message/130486 > Mute This Topic: https://lists.openembedded.org/mt/121494426/1997914 > Group Owner: openembedded-devel+owner@lists.openembedded.org > Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [ > raj.khem@gmail.com] > -=-=-=-=-=-=-=-=-=-=-=- > >
diff --git a/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch b/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch new file mode 100644 index 0000000000..1943256d71 --- /dev/null +++ b/meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch @@ -0,0 +1,85 @@ +From e63a11dedcdece8b9b285485a86405fd258b37d8 Mon Sep 17 00:00:00 2001 +From: Markus Volk <f_l_k@t-online.de> +Date: Tue, 29 Sep 2026 17:29:52 +0200 +Subject: [PATCH] Honour ImageSize for the last block + +bmaptool records the exact image size in ImageSize, and the last block +of an image whose size is not a multiple of BlockSize is only partly +filled. Writing and verifying used (endBlock + 1) * BlockSize as the end +of every range, so the range containing that block asked for more bytes +than the image has and the write failed with "Image ended before the +block map did". Read ImageSize and clamp the end of each range to it. + +AI-Generated: Uses Claude Code (Claude Fable 5.1) +Upstream-Status: Pending +--- + src/bmap.cpp | 5 +++++ + src/bmap.h | 1 + + src/image_writer.cpp | 2 +- + src/main.cpp | 2 +- + 4 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/bmap.cpp b/src/bmap.cpp +index fabf2c2..0162ac0 100644 +--- a/src/bmap.cpp ++++ b/src/bmap.cpp +@@ -135,6 +135,7 @@ int parseBMap(const std::string &filename, bmap_t& bmapData) { + bmapData.bmapVersion = (version != nullptr) ? trimWhitespace(version) : "unknown"; + + // Parse image information ++ bmapData.imageSize = requireChildUnsigned(p_root, "ImageSize"); + bmapData.blocksTotal = requireChildUnsigned(p_root, "BlocksCount"); + bmapData.blocksMapped = requireChildUnsigned(p_root, "MappedBlocksCount"); + bmapData.blockSize = requireChildUnsigned(p_root, "BlockSize"); +@@ -200,6 +201,10 @@ int validateBmap(const bmap_t& bmap, uint64_t deviceSize) { + if (bmap.blocksTotal == 0) { + throw BmapError("BMAP: BlocksCount must not be zero"); + } ++ if (bmap.imageSize > bmap.blocksTotal * bmap.blockSize || ++ bmap.imageSize <= (bmap.blocksTotal - 1) * bmap.blockSize) { ++ throw BmapError("BMAP: ImageSize does not match BlocksCount and BlockSize"); ++ } + if (bmap.blocksMapped > bmap.blocksTotal) { + throw BmapError("BMAP: MappedBlocksCount exceeds BlocksCount"); + } +diff --git a/src/bmap.h b/src/bmap.h +index cf6ff9d..98cb969 100644 +--- a/src/bmap.h ++++ b/src/bmap.h +@@ -38,6 +38,7 @@ struct bmap_t { + std::string checksumType; + size_t blockSize = 0; + size_t blocksTotal = 0; ++ size_t imageSize = 0; + size_t blocksMapped = 0; + std::string bmapVersion; + std::string bmapChecksum; +diff --git a/src/image_writer.cpp b/src/image_writer.cpp +index bb802ea..f864151 100644 +--- a/src/image_writer.cpp ++++ b/src/image_writer.cpp +@@ -177,7 +177,7 @@ int BmapWriteImage(int fd, const bmap_t &bmap, int dev_fd, const std::string &de + for (const auto &range : bmap.ranges) { + // validateBmap() has already proven that none of this can overflow. + const size_t outStart = range.startBlock * bmap.blockSize; +- const size_t outEnd = (range.endBlock + 1) * bmap.blockSize; ++ const size_t outEnd = std::min((range.endBlock + 1) * bmap.blockSize, bmap.imageSize); + const size_t rangeSize = outEnd - outStart; + const off_t writeOffset = static_cast<off_t>(outStart); + size_t writtenSize = 0; +diff --git a/src/main.cpp b/src/main.cpp +index ca42c12..b8cbbc5 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -166,7 +166,7 @@ int main(int argc, char *argv[]) { + FdGuard imageGuard(image_fd); + + std::cout << "BMAP format version: " << bmap.bmapVersion << std::endl; +- std::cout << "Image size: " << (bmap.blocksTotal * bmap.blockSize) << " bytes" << std::endl; ++ std::cout << "Image size: " << bmap.imageSize << " bytes" << std::endl; + std::cout << "Block size: " << bmap.blockSize << " bytes" << std::endl; + std::cout << "Mapped blocks: " << bmap.blocksMapped << " out of " << bmap.blocksTotal + << " (" << std::fixed << std::setprecision(1) +-- +2.55.0 + diff --git a/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb b/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb index 160d1b7112..5d493f3122 100644 --- a/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb +++ b/meta-oe/recipes-support/bmap-writer/bmap-writer_1.0.5.bb @@ -8,7 +8,9 @@ SECTION = "console/utils" LICENSE = "GPL-3.0-only" LIC_FILES_CHKSUM = "file://LICENSE;md5=e49f4652534af377a713df3d9dec60cb" -SRC_URI = "git://github.com/embetrix/${BPN};branch=master;protocol=https;tag=${PV}" +SRC_URI = "git://github.com/embetrix/${BPN};branch=master;protocol=https;tag=${PV} \ + file://0001-Honour-ImageSize-for-the-last-block.patch \ + " SRCREV = "c7b1bec0f40217d17e315226552e461a4a816abc" DEPENDS = "libtinyxml2 libarchive"
Writing an image whose size is not a multiple of the bmap block size failed at its last block with "Image ended before the block map did", because every range was taken to end at (endBlock + 1) * BlockSize. Add a patch that reads ImageSize from the bmap and clamps the ranges to it. Tested by writing a wic image whose size ends 2048 bytes into its last 4 KiB block to an NVMe disk. AI-Generated: Uses Claude Code (Claude Fable 5.1) Signed-off-by: Markus Volk <f_l_k@t-online.de> --- ...-Honour-ImageSize-for-the-last-block.patch | 85 +++++++++++++++++++ .../bmap-writer/bmap-writer_1.0.5.bb | 4 +- 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 meta-oe/recipes-support/bmap-writer/bmap-writer/0001-Honour-ImageSize-for-the-last-block.patch