1 | {"version":3,"sources":["../src/vhd.js"],"names":["VHD_UTIL_DEBUG","debug","console","log","str","VHD_FOOTER_SIZE","VHD_HEADER_SIZE","VHD_SECTOR_SIZE","VHD_ENTRY_SIZE","VHD_PARENT_LOCATOR_ENTRIES","VHD_PLATFORM_CODE_NONE","HARD_DISK_TYPE_DYNAMIC","HARD_DISK_TYPE_DIFFERENCING","BLOCK_UNUSED","BIT_MASK","fuFooter","struct","char","uint32","uint16","uint8","fuHeader","char16be","SIZE_OF_32_BITS","Math","pow","uint32ToUint64","fu","high","low","getVhdVersion","major","minor","sectorsRoundUp","floor","bytes","sectorsRoundUpNoZero","sectorsToBytes","sectors","mapTestBit","map","bit","mapSetBit","packField","field","value","buf","offset","pack","bits","unpackField","unpack","checksumStruct","rawStruct","checksumField","sum","i","getParentLocatorSize","parentLocatorEntry","platformDataSpace","Vhd","handler","path","_handler","_path","header","end","footer","dataOffset","blockAllocationTableSize","maxTableEntries","max","tableOffset","entry","platformCode","platformDataOffset","getEndOfHeaders","blockAddr","readAllocationTableEntry","sectorsPerBlock","sectorsOfBitmap","getSize","stats","size","createReadStream","start","streamToBuffer","fields","checksum","sumToTest","Error","toString","slice","blockSize","fullBlockSize","bitmapSize","fileFormatVersion","blockTable","readUInt32BE","blockDataAddr","getFooterStart","footerStart","isPadded","Buffer","concat","fill","buffer","createOutputStream","flags","then","resolve","reject","stream","on","write","writeUInt32BE","blockId","getEndOfData","writeAllocationTableEntry","_write","bitmap","length","block","beginSectorId","n","id","createBlock","endSectorId","data","readBlockBitmap","writeBlockBitmap","child","readBlockData","blockData","blockBitmap","writeBlockSectors","rawFooter","rawHeader"],"mappings":"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","file":"vhd.js","sourcesContent":["import fu from '@nraynaud/struct-fu'\n\nconst VHD_UTIL_DEBUG = 0\nconst debug = VHD_UTIL_DEBUG ? str => console.log(`[vhd-util]${str}`) : () =>{}\n\n// ===================================================================\n//\n// Spec:\n// https://www.microsoft.com/en-us/download/details.aspx?id=23850\n//\n// C implementation:\n// https://github.com/rubiojr/vhd-util-convert\n//\n// ===================================================================\n\n// Sizes in bytes.\nconst VHD_FOOTER_SIZE = 512\nconst VHD_HEADER_SIZE = 1024\nconst VHD_SECTOR_SIZE = 512\n\n// Block allocation table entry size. (Block addr)\nconst VHD_ENTRY_SIZE = 4\n\nconst VHD_PARENT_LOCATOR_ENTRIES = 8\nconst VHD_PLATFORM_CODE_NONE = 0\n\n// Types of backup treated. Others are not supported.\nconst HARD_DISK_TYPE_DYNAMIC = 3 // Full backup.\nconst HARD_DISK_TYPE_DIFFERENCING = 4 // Delta backup.\n\n// Other.\nconst BLOCK_UNUSED = 0xFFFFFFFF\nconst BIT_MASK = 0x80\n\n// ===================================================================\n\nconst fuFooter = fu.struct([\n fu.char('cookie', 8), // 0\n fu.uint32('features'), // 8\n fu.uint32('fileFormatVersion'), // 12\n fu.struct('dataOffset', [\n fu.uint32('high'), // 16\n fu.uint32('low') // 20\n ]),\n fu.uint32('timestamp'), // 24\n fu.char('creatorApplication', 4), // 28\n fu.uint32('creatorVersion'), // 32\n fu.uint32('creatorHostOs'), // 36\n fu.struct('originalSize', [ // At the creation, current size of the hard disk.\n fu.uint32('high'), // 40\n fu.uint32('low') // 44\n ]),\n fu.struct('currentSize', [ // Current size of the virtual disk. At the creation: currentSize = originalSize.\n fu.uint32('high'), // 48\n fu.uint32('low') // 52\n ]),\n fu.struct('diskGeometry', [\n fu.uint16('cylinders'), // 56\n fu.uint8('heads'), // 58\n fu.uint8('sectorsPerTrackCylinder') // 59\n ]),\n fu.uint32('diskType'), // 60 Disk type, must be equal to HARD_DISK_TYPE_DYNAMIC/HARD_DISK_TYPE_DIFFERENCING.\n fu.uint32('checksum'), // 64\n fu.uint8('uuid', 16), // 68\n fu.char('saved'), // 84\n fu.char('hidden'), // 85\n fu.char('reserved', 426) // 86\n])\n\nconst fuHeader = fu.struct([\n fu.char('cookie', 8),\n fu.struct('dataOffset', [\n fu.uint32('high'),\n fu.uint32('low')\n ]),\n fu.struct('tableOffset', [ // Absolute byte offset of the Block Allocation Table.\n fu.uint32('high'),\n fu.uint32('low')\n ]),\n fu.uint32('headerVersion'),\n fu.uint32('maxTableEntries'), // Max entries in the Block Allocation Table.\n fu.uint32('blockSize'), // Block size in bytes. Default (2097152 => 2MB)\n fu.uint32('checksum'),\n fu.uint8('parentUuid', 16),\n fu.uint32('parentTimestamp'),\n fu.uint32('reserved1'),\n fu.char16be('parentUnicodeName', 512),\n fu.struct('parentLocatorEntry', [\n fu.uint32('platformCode'),\n fu.uint32('platformDataSpace'),\n fu.uint32('platformDataLength'),\n fu.uint32('reserved'),\n fu.struct('platformDataOffset', [ // Absolute byte offset of the locator data.\n fu.uint32('high'),\n fu.uint32('low')\n ])\n ], VHD_PARENT_LOCATOR_ENTRIES),\n fu.char('reserved2', 256)\n])\n\n// ===================================================================\n// Helpers\n// ===================================================================\n\nconst SIZE_OF_32_BITS = Math.pow(2, 32)\nconst uint32ToUint64 = (fu) => fu.high * SIZE_OF_32_BITS + fu.low\n\n// Returns a 32 bits integer corresponding to a Vhd version.\nconst getVhdVersion = (major, minor) => (major << 16) | (minor & 0x0000FFFF)\n\n// Sectors conversions.\nconst sectorsRoundUp = bytes => Math.floor((bytes + VHD_SECTOR_SIZE - 1) / VHD_SECTOR_SIZE)\nconst sectorsRoundUpNoZero = bytes => sectorsRoundUp(bytes) || 1\nconst sectorsToBytes = sectors => sectors * VHD_SECTOR_SIZE\n\n// Check/Set a bit on a vhd map.\nconst mapTestBit = (map, bit) => ((map[bit >> 3] << (bit & 7)) & BIT_MASK) !== 0\nconst mapSetBit = (map, bit) => { map[bit >> 3] |= (BIT_MASK >> (bit & 7)) }\n\nconst packField = (field, value, buf) => {\n const { offset } = field\n\n field.pack(\n value,\n buf,\n (typeof offset !== 'object') ? { bytes: offset, bits: 0 } : offset\n )\n}\n\nconst unpackField = (field, buf) => {\n const { offset } = field\n\n return field.unpack(\n buf,\n (typeof offset !== 'object') ? { bytes: offset, bits: 0 } : offset\n )\n}\n// ===================================================================\n\n// Returns the checksum of a raw struct.\n// The raw struct (footer or header) is altered with the new sum.\nfunction checksumStruct (rawStruct, checksumField) {\n let sum = 0\n\n // Reset current sum.\n packField(checksumField, 0, rawStruct)\n\n for (let i = 0; i < VHD_FOOTER_SIZE; i++) {\n sum = (sum + rawStruct[i]) & 0xFFFFFFFF\n }\n\n sum = 0xFFFFFFFF - sum\n\n // Write new sum.\n packField(checksumField, sum, rawStruct)\n\n return sum\n}\n\nfunction getParentLocatorSize (parentLocatorEntry) {\n const { platformDataSpace } = parentLocatorEntry\n\n if (platformDataSpace < VHD_SECTOR_SIZE) {\n return sectorsToBytes(platformDataSpace)\n }\n\n return (platformDataSpace % VHD_SECTOR_SIZE === 0)\n ? platformDataSpace\n : 0\n}\n\n// ===================================================================\n\nclass Vhd {\n constructor (handler, path) {\n this._handler = handler\n this._path = path\n }\n\n // =================================================================\n // Read functions.\n // =================================================================\n\n // Returns the first address after metadata. (In bytes)\n getEndOfHeaders () {\n const { header } = this\n\n let end = uint32ToUint64(this.footer.dataOffset) + VHD_HEADER_SIZE\n\n const blockAllocationTableSize = sectorsToBytes(\n sectorsRoundUpNoZero(header.maxTableEntries * VHD_ENTRY_SIZE)\n )\n\n // Max(end, block allocation table end)\n end = Math.max(end, uint32ToUint64(header.tableOffset) + blockAllocationTableSize)\n\n for (let i = 0; i < VHD_PARENT_LOCATOR_ENTRIES; i++) {\n const entry = header.parentLocatorEntry[i]\n\n if (entry.platformCode !== VHD_PLATFORM_CODE_NONE) {\n const dataOffset = uint32ToUint64(entry.platformDataOffset)\n\n // Max(end, locator end)\n end = Math.max(end, dataOffset + getParentLocatorSize(entry))\n }\n }\n\n debug(`End of headers: ${end}.`)\n\n return end\n }\n\n // Returns the first sector after data.\n getEndOfData () {\n let end = Math.floor(this.getEndOfHeaders() / VHD_SECTOR_SIZE)\n\n const { maxTableEntries } = this.header\n for (let i = 0; i < maxTableEntries; i++) {\n let blockAddr = this.readAllocationTableEntry(i)\n\n if (blockAddr !== BLOCK_UNUSED) {\n // Compute next block address.\n blockAddr += this.sectorsPerBlock + this.sectorsOfBitmap\n\n end = Math.max(end, blockAddr)\n }\n }\n\n debug(`End of data: ${end}.`)\n\n return sectorsToBytes(end)\n }\n\n // Returns the start position of the vhd footer.\n // The real footer, not the copy at the beginning of the vhd file.\n async getFooterStart () {\n const stats = await this._handler.getSize(this._path)\n return stats.size - VHD_FOOTER_SIZE\n }\n\n // Get the beginning (footer + header) of a vhd file.\n async readHeaderAndFooter () {\n const buf = await streamToBuffer(\n await this._handler.createReadStream(this._path, {\n start: 0,\n end: VHD_FOOTER_SIZE + VHD_HEADER_SIZE - 1\n })\n )\n\n const sum = unpackField(fuFooter.fields.checksum, buf)\n const sumToTest = checksumStruct(buf, fuFooter.fields.checksum)\n\n // Checksum child & parent.\n if (sumToTest !== sum) {\n throw new Error(`Bad checksum in vhd. Expected: ${sum}. Given: ${sumToTest}. (data=${buf.toString('hex')})`)\n }\n\n const header = this.header = fuHeader.unpack(buf.slice(VHD_FOOTER_SIZE))\n this.footer = fuFooter.unpack(buf)\n\n // Compute the number of sectors in one block.\n // Default: One block contains 4096 sectors of 512 bytes.\n const sectorsPerBlock = this.sectorsPerBlock = Math.floor(header.blockSize / VHD_SECTOR_SIZE)\n\n // Compute bitmap size in sectors.\n // Default: 1.\n const sectorsOfBitmap = this.sectorsOfBitmap = sectorsRoundUpNoZero(sectorsPerBlock >> 3)\n\n // Full block size => data block size + bitmap size.\n this.fullBlockSize = sectorsToBytes(sectorsPerBlock + sectorsOfBitmap)\n\n // In bytes.\n // Default: 512.\n this.bitmapSize = sectorsToBytes(sectorsOfBitmap)\n }\n\n // Check if a vhd object has a block allocation table.\n hasBlockAllocationTableMap () {\n return this.footer.fileFormatVersion > getVhdVersion(1, 0)\n }\n\n // Returns a buffer that contains the block allocation table of a vhd file.\n async readBlockTable () {\n const { header } = this\n\n const offset = uint32ToUint64(header.tableOffset)\n const size = sectorsToBytes(\n sectorsRoundUpNoZero(header.maxTableEntries * VHD_ENTRY_SIZE)\n )\n\n this.blockTable = await streamToBuffer(\n await this._handler.createReadStream(this._path, {\n start: offset,\n end: offset + size - 1\n })\n )\n }\n\n // Returns the address block at the entry location of one table.\n readAllocationTableEntry (entry) {\n return this.blockTable.readUInt32BE(entry * VHD_ENTRY_SIZE)\n }\n\n // Returns the data content of a block. (Not the bitmap !)\n async readBlockData (blockAddr) {\n const { blockSize } = this.header\n\n const handler = this._handler\n const path = this._path\n\n const blockDataAddr = sectorsToBytes(blockAddr + this.sectorsOfBitmap)\n const footerStart = await this.getFooterStart()\n const isPadded = footerStart < (blockDataAddr + blockSize)\n\n // Size ot the current block in the vhd file.\n const size = isPadded ? (footerStart - blockDataAddr) : sectorsToBytes(this.sectorsPerBlock)\n\n debug(`Read block data at: ${blockDataAddr}. (size=${size})`)\n\n const buf = await streamToBuffer(\n await handler.createReadStream(path, {\n start: blockDataAddr,\n end: blockDataAddr + size - 1\n })\n )\n\n // Padded by zero !\n if (isPadded) {\n return Buffer.concat([buf, new Buffer(blockSize - size).fill(0)])\n }\n\n return buf\n }\n\n // Returns a buffer that contains the bitmap of a block.\n //\n // TODO: merge with readBlockData().\n async readBlockBitmap (blockAddr) {\n const { bitmapSize } = this\n const offset = sectorsToBytes(blockAddr)\n\n debug(`Read bitmap at: ${offset}. (size=${bitmapSize})`)\n\n return streamToBuffer(\n await this._handler.createReadStream(this._path, {\n start: offset,\n end: offset + bitmapSize - 1\n })\n )\n }\n\n // =================================================================\n // Write functions.\n // =================================================================\n\n // Write a buffer at a given position in a vhd file.\n async _write (buffer, offset) {\n // TODO: could probably be merged in remote handlers.\n return this._handler.createOutputStream(this._path, {\n start: offset,\n flags: 'r+'\n }).then(stream => new Promise((resolve, reject) => {\n stream.on('error', reject)\n stream.write(buffer, () => {\n stream.end()\n resolve()\n })\n }))\n }\n\n // Write an entry in the allocation table.\n writeAllocationTableEntry (entry, value) {\n this.blockTable.writeUInt32BE(value, entry * VHD_ENTRY_SIZE)\n }\n\n // Make a new empty block at vhd end.\n // Update block allocation table in context and in file.\n async createBlock (blockId) {\n // End of file !\n let offset = this.getEndOfData()\n\n // Padded on bound sector.\n if (offset % VHD_SECTOR_SIZE) {\n offset += (VHD_SECTOR_SIZE - (offset % VHD_SECTOR_SIZE))\n }\n\n const blockAddr = Math.floor(offset / VHD_SECTOR_SIZE)\n\n const {\n blockTable,\n fullBlockSize\n } = this\n debug(`Create block at ${blockAddr}. (size=${fullBlockSize}, offset=${offset})`)\n\n // New entry in block allocation table.\n this.writeAllocationTableEntry(blockId, blockAddr)\n\n const tableOffset = uint32ToUint64(this.header.tableOffset)\n const entry = blockId * VHD_ENTRY_SIZE\n\n // Write an empty block and addr in vhd file.\n await this._write(new Buffer(fullBlockSize).fill(0), offset)\n await this._write(blockTable.slice(entry, entry + VHD_ENTRY_SIZE), tableOffset + entry)\n\n return blockAddr\n }\n\n // Write a bitmap at a block address.\n async writeBlockBitmap (blockAddr, bitmap) {\n const { bitmapSize } = this\n\n if (bitmap.length !== bitmapSize) {\n throw new Error(`Bitmap length is not correct ! ${bitmap.length}`)\n }\n\n const offset = sectorsToBytes(blockAddr)\n\n debug(`Write bitmap at: ${offset}. (size=${bitmapSize}, data=${bitmap.toString('hex')})`)\n await this._write(bitmap, sectorsToBytes(blockAddr))\n }\n\n async writeBlockSectors (block, beginSectorId, n) {\n let blockAddr = this.readAllocationTableEntry(block.id)\n\n if (blockAddr === BLOCK_UNUSED) {\n blockAddr = await this.createBlock(block.id)\n }\n\n const endSectorId = beginSectorId + n\n const offset = blockAddr + this.sectorsOfBitmap + beginSectorId\n\n debug(`Write block data at: ${offset}. (counter=${n}, blockId=${block.id}, blockSector=${beginSectorId})`)\n\n await this._write(\n block.data.slice(\n sectorsToBytes(beginSectorId),\n sectorsToBytes(endSectorId)\n ),\n sectorsToBytes(offset)\n )\n\n const bitmap = await this.readBlockBitmap(this.bitmapSize, blockAddr)\n\n for (let i = beginSectorId; i < endSectorId; ++i) {\n mapSetBit(bitmap, i)\n }\n\n await this.writeBlockBitmap(blockAddr, bitmap)\n }\n\n // Merge block id (of vhd child) into vhd parent.\n async coalesceBlock (child, blockAddr, blockId) {\n // Get block data and bitmap of block id.\n const blockData = await child.readBlockData(blockAddr)\n const blockBitmap = await child.readBlockBitmap(blockAddr)\n\n debug(`Coalesce block ${blockId} at ${blockAddr}.`)\n\n // For each sector of block data...\n const { sectorsPerBlock } = child\n for (let i = 0; i < sectorsPerBlock; i++) {\n // If no changes on one sector, skip.\n if (!mapTestBit(blockBitmap, i)) {\n continue\n }\n\n let sectors = 0\n\n // Count changed sectors.\n for (; sectors + i < sectorsPerBlock; sectors++) {\n if (!mapTestBit(blockBitmap, sectors + i)) {\n break\n }\n }\n\n // Write n sectors into parent.\n debug(`Coalesce block: write. (offset=${i}, sectors=${sectors})`)\n await this.writeBlockSectors(\n { id: blockId, data: blockData },\n i,\n sectors\n )\n\n i += sectors\n }\n }\n\n // Write a context footer. (At the end and beginning of a vhd file.)\n async writeFooter () {\n const { footer } = this\n\n const offset = this.getEndOfData()\n const rawFooter = fuFooter.pack(footer)\n\n footer.checksum = checksumStruct(rawFooter, fuFooter.fields.checksum)\n debug(`Write footer at: ${offset} (checksum=${footer.checksum}). (data=${rawFooter.toString('hex')})`)\n\n await this._write(rawFooter, 0)\n await this._write(rawFooter, offset)\n }\n\n async writeHeader () {\n const { header } = this\n const rawHeader = fuHeader.pack(header)\n header.checksum = checksumStruct(rawHeader, fuHeader.fields.checksum)\n const offset = VHD_FOOTER_SIZE\n debug(`Write header at: ${offset} (checksum=${header.checksum}). (data=${rawHeader.toString('hex')})`)\n await this._write(rawHeader, offset)\n }\n}\n"]} |