{"id":21399739,"url":"https://github.com/balena-io-modules/blockmap","last_synced_at":"2025-07-13T20:33:54.424Z","repository":{"id":56022445,"uuid":"80110056","full_name":"balena-io-modules/blockmap","owner":"balena-io-modules","description":"Tizen's block map format","archived":false,"fork":false,"pushed_at":"2020-11-30T18:01:00.000Z","size":266,"stargazers_count":6,"open_issues_count":2,"forks_count":0,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-07-03T01:05:15.450Z","etag":null,"topics":["blockmap","bmap","disk-image","tizen"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/balena-io-modules.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-01-26T11:46:02.000Z","updated_at":"2023-02-21T20:52:50.000Z","dependencies_parsed_at":"2022-08-15T11:40:14.812Z","dependency_job_id":null,"html_url":"https://github.com/balena-io-modules/blockmap","commit_stats":null,"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/balena-io-modules/blockmap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena-io-modules%2Fblockmap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena-io-modules%2Fblockmap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena-io-modules%2Fblockmap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena-io-modules%2Fblockmap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/balena-io-modules","download_url":"https://codeload.github.com/balena-io-modules/blockmap/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/balena-io-modules%2Fblockmap/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265200153,"owners_count":23726781,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockmap","bmap","disk-image","tizen"],"created_at":"2024-11-22T15:16:28.088Z","updated_at":"2025-07-13T20:33:54.115Z","avatar_url":"https://github.com/balena-io-modules.png","language":"TypeScript","readme":"# Blockmap\n[![npm](https://img.shields.io/npm/v/blockmap.svg?style=flat-square)](https://npmjs.com/package/blockmap)\n[![npm license](https://img.shields.io/npm/l/blockmap.svg?style=flat-square)](https://npmjs.com/package/blockmap)\n[![npm downloads](https://img.shields.io/npm/dm/blockmap.svg?style=flat-square)](https://npmjs.com/package/blockmap)\n\nThis module implements [Tizen's block map format](https://source.tizen.org/documentation/reference/bmaptool/introduction),\nwhich maps non-empty blocks or block ranges from a raw image file,\nmaking it possible to quickly \u0026 efficiently flash the image to the target block device\nby only reading \u0026 writing the necessary blocks.\n\n## Install via [npm](https://npmjs.com)\n\n```sh\n$ npm install --save blockmap\n```\n\n## Usage\n\nFor detailed API documentation, see [`/doc`](https://github.com/balena-io-modules/blockmap/tree/master/doc).\n\n```js\nconst { BlockMap } = require('blockmap')\n```\n\n### Parsing a Block Map\n\n```\nconst blockMap = BlockMap.parse(xml)\n```\n\n```js\nBlockMap {\n  version: '2.0',\n  imageSize: 821752,\n  blockSize: 4096,\n  blocksCount: 201,\n  mappedBlocksCount: 117,\n  checksum: '44e9d58de533d5eb94f8232cff22b2e6d71b15d369c2ac2af461c63164cce324',\n  checksumType: 'sha256',\n  ranges: [{\n    checksum: '9eaf19215d55d23de1be1fe4bed4a95bfe620a404352fd06e782738fff58e500',\n    start: 0,\n    end: 1\n  }, {\n    checksum: 'e8a26f49a71262870f8294a73f40f122d622fd70fb82bef01c0322785e9fd6b2',\n    start: 3,\n    end: 5\n  },\n  // More ranges omitted for brevity\n  {\n    checksum: 'cb732fc3f3a0f81f6a761a534201c05549c8efe4a92630ccd24241f72d7d618c',\n    start: 198,\n    end: 199\n  }]\n}\n```\n\n### Creating a Block Map\n\nRender a `.bmap` file from a parsed or otherwise constructed `BlockMap`:\n\n```js\nconst blockMap = BlockMap.parse(value)\nconst xml = blockMap.toString()\n```\n\nWhere `xml` would look like the following, given the block map from above:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003cbmap version=\"2.0\"\u003e\n  \u003cImageSize\u003e821752\u003c/ImageSize\u003e\n  \u003cBlockSize\u003e4096\u003c/BlockSize\u003e\n  \u003cBlocksCount\u003e201\u003c/BlocksCount\u003e\n  \u003cMappedBlocksCount\u003e117\u003c/MappedBlocksCount\u003e\n  \u003cChecksumType\u003esha256\u003c/ChecksumType\u003e\n  \u003cBmapFileChecksum\u003e44e9d58de533d5eb94f8232cff22b2e6d71b15d369c2ac2af461c63164cce324\u003c/BmapFileChecksum\u003e\n  \u003cBlockMap\u003e\n    \u003cRange chksum=\"9eaf19215d55d23de1be1fe4bed4a95bfe620a404352fd06e782738fff58e500\"\u003e0-1\u003c/Range\u003e\n    \u003cRange chksum=\"e8a26f49a71262870f8294a73f40f122d622fd70fb82bef01c0322785e9fd6b2\"\u003e3-5\u003c/Range\u003e\n    \u003c!-- More ranges omitted for brevity --\u003e\n    \u003cRange chksum=\"cb732fc3f3a0f81f6a761a534201c05549c8efe4a92630ccd24241f72d7d618c\"\u003e198-199\u003c/Range\u003e\n  \u003c/BlockMap\u003e\n\u003c/bmap\u003e\n```\n\n---\n\n**NOTE:** Regardless of input version, `blockMap.toString()` will always\ncreate a `.bmap` in the format of the latest version (currently `2.0`).\n\n---\n\n### Block Map Checksum Verification\n\nBy default, checksums for mapped ranges and the bmap file itself (only version 1.3+)\nwill be verified when parsing or streaming. If you need to disable verification,\npass `false` as `verify` parameter.\n\n```js\n// Disable verification of the bmap file checksum:\nconst blockMap = BlockMap.parse(bmap, false)\n```\n\n```js\nconst { ReadStream } = require('blockmap')\n// Disable range checksum verification:\nconst blockReadStream = new ReadStream(fileDescriptor, blockMap, false)\n```\n\n```js\nconst { FilterStream } = require('blockmap')\n// Same for filter streams:\nconst filterStream = new FilterStream(blockMap, false)\n```\n\n### Reading Mapped Blocks\n\n---\n\n**NOTE:** These examples just use `fs.writeSync()` in `.on('readable')` for brevity;\nof course this should be implemented properly in a writable stream, which the readable\nside (i.e. the `ReadStream` or `FilterStream`) is piped to.\n\n---\n\nUse a parsed block map to read only mapped regions:\n\n```js\nconst blockMap = BlockMap.parse(fs.readFileSync('/path/to/balena-os.bmap'))\nconst blockReadStream = new ReadStream(fileDescriptor, blockMap)\n\n// The chunk emitted will have two properties set;\n// 1) chunk.buffer – the data buffer\n// 2) chunk.position – the chunk's offset (or address) in bytes\n// Which can then be used to write only those blocks to the target:\nblockReadStream.on('readable', function() {\n  len chunk = null\n  while(chunk = this.read()) {\n    fs.writeSync(fd, chunk.buffer, 0, chunk.buffer.length, chunk.position)\n  }\n})\n\nblockReadStream.once('end', function() {\n  console.log('Read', blockReadStream.blocksRead, 'mapped blocks')\n  console.log('Read', blockReadStream.bytesRead, 'mapped bytes')\n  console.log('Read', blockReadStream.rangesRead, 'mapped ranges')\n})\n```\n\n### Filtering Unmapped Blocks\n\nUse a filter transform to filter out unmapped blocks from a stream:\n\n```js\nconst blockMap = BlockMap.parse(fs.readFileSync('/path/to/balena-os.bmap'))\nconst readStream = fs.createReadStream('/path/to/balena-os.img')\nconst filterStream = new FilterStream(blockMap)\n\n// The chunk emitted will have two properties set;\n// 1) chunk.buffer – the data buffer\n// 2) chunk.position – the chunk's offset (or address) in bytes\n// Which can then be used to write only those blocks to the target:\nfilterStream.on('readable', function() {\n  let buffer = null\n  while(chunk = this.read()) {\n    fs.writeSync(fd, chunk.buffer, 0, chunk.buffer.length, chunk.position)\n  }\n})\n\n// Pipe the readable stream into the block filter:\nreadStream.pipe(filterStream)\n```\n\n## Verifying a Flashed Device\n\nUse a `ReadStream` to verify a flashed device image:\n\n```js\nconst { ReadStream } = require('blockmap');\n\nfunction verify(fileDescriptor, blockMap, callback) {\n  new ReadStream(fileDescriptor, blockMap).resume()\n    .once('error', callback)\n    .once('end', callback)\n}\n\nconst blockMap = BlockMap.parse(fs.readFileSync('/path/to/balena-os.bmap'))\n\nverify(fileDescriptor, blockMap, function(error) {\n  if(error != null) {\n    // The image didn't verify...\n  }\n})\n```\n\n### Handling Errors\n\n#### Parsing\n\n`BlockMap.parse()` and `blockMap.parse()` will throw when\nencountering invalid input, or if the checksum doesn't verify:\n\n```js\ntry {\n  blockMap = BlockMap.parse(value)\n} catch(error) {\n  // ...\n}\n```\n\n#### Streams\n\nIf the error is due to a checksum mismatch,\nthe error will have a `.checksum` and `.range` property,\ndenoting the calculated checksum, and the range for which it occured:\n\n```js\nconst blockReadStream = new ReadStream(fileDescriptor, blockMap)\n\nblockReadStream.on('error', function(error) {\n  if(error.checksum) {\n    console.log(`Checksum mismatch for range [${error.range.start},${error.range.end}]:`)\n    console.log(`${error.checksum} != ${error.range.checksum}`)\n  }\n  // ...\n})\n```\n\n## References\n\n- [Tizen's block map format](https://source.tizen.org/documentation/reference/bmaptool/introduction)\n- [intel/bmap-tools](https://github.com/intel/bmap-tools)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbalena-io-modules%2Fblockmap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbalena-io-modules%2Fblockmap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbalena-io-modules%2Fblockmap/lists"}