1019d6b8fSAnthony Liguori /* 2019d6b8fSAnthony Liguori * QEMU Block driver for DMG images 3019d6b8fSAnthony Liguori * 4019d6b8fSAnthony Liguori * Copyright (c) 2004 Johannes E. Schindelin 5019d6b8fSAnthony Liguori * 6019d6b8fSAnthony Liguori * Permission is hereby granted, free of charge, to any person obtaining a copy 7019d6b8fSAnthony Liguori * of this software and associated documentation files (the "Software"), to deal 8019d6b8fSAnthony Liguori * in the Software without restriction, including without limitation the rights 9019d6b8fSAnthony Liguori * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10019d6b8fSAnthony Liguori * copies of the Software, and to permit persons to whom the Software is 11019d6b8fSAnthony Liguori * furnished to do so, subject to the following conditions: 12019d6b8fSAnthony Liguori * 13019d6b8fSAnthony Liguori * The above copyright notice and this permission notice shall be included in 14019d6b8fSAnthony Liguori * all copies or substantial portions of the Software. 15019d6b8fSAnthony Liguori * 16019d6b8fSAnthony Liguori * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17019d6b8fSAnthony Liguori * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18019d6b8fSAnthony Liguori * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19019d6b8fSAnthony Liguori * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20019d6b8fSAnthony Liguori * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21019d6b8fSAnthony Liguori * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22019d6b8fSAnthony Liguori * THE SOFTWARE. 23019d6b8fSAnthony Liguori */ 2480c71a24SPeter Maydell #include "qemu/osdep.h" 25da34e65cSMarkus Armbruster #include "qapi/error.h" 26e2c1c34fSMarkus Armbruster #include "block/block-io.h" 27737e150eSPaolo Bonzini #include "block/block_int.h" 281de7afc9SPaolo Bonzini #include "qemu/bswap.h" 29d49b6836SMarkus Armbruster #include "qemu/error-report.h" 301de7afc9SPaolo Bonzini #include "qemu/module.h" 315df022cfSPeter Maydell #include "qemu/memalign.h" 3227685a8dSFam Zheng #include "dmg.h" 3327685a8dSFam Zheng 34fdd5e90fSPhilippe Mathieu-Daudé BdrvDmgUncompressFunc *dmg_uncompress_bz2; 35fdd5e90fSPhilippe Mathieu-Daudé BdrvDmgUncompressFunc *dmg_uncompress_lzfse; 367a40b418SJulio Faracco 37c165f775SStefan Hajnoczi enum { 38c165f775SStefan Hajnoczi /* Limit chunk sizes to prevent unreasonable amounts of memory being used 39c165f775SStefan Hajnoczi * or truncating when converting to 32-bit types 40c165f775SStefan Hajnoczi */ 41c165f775SStefan Hajnoczi DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */ 42c165f775SStefan Hajnoczi DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512, 43c165f775SStefan Hajnoczi }; 44c165f775SStefan Hajnoczi 4595a156f6SJulio Faracco enum { 4695a156f6SJulio Faracco /* DMG Block Type */ 4795a156f6SJulio Faracco UDZE = 0, /* Zeroes */ 4895a156f6SJulio Faracco UDRW, /* RAW type */ 4995a156f6SJulio Faracco UDIG, /* Ignore */ 5095a156f6SJulio Faracco UDCO = 0x80000004, 5195a156f6SJulio Faracco UDZO, 5295a156f6SJulio Faracco UDBZ, 5395a156f6SJulio Faracco ULFO, 5495a156f6SJulio Faracco UDCM = 0x7ffffffe, /* Comments */ 55b47c7d53SJulio Faracco UDLE = 0xffffffff /* Last Entry */ 5695a156f6SJulio Faracco }; 5795a156f6SJulio Faracco 58019d6b8fSAnthony Liguori static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) 59019d6b8fSAnthony Liguori { 60f5866fa4SKevin Wolf int len; 61f5866fa4SKevin Wolf 62f5866fa4SKevin Wolf if (!filename) { 63f5866fa4SKevin Wolf return 0; 64f5866fa4SKevin Wolf } 65f5866fa4SKevin Wolf 66f5866fa4SKevin Wolf len = strlen(filename); 67f5866fa4SKevin Wolf if (len > 4 && !strcmp(filename + len - 4, ".dmg")) { 68019d6b8fSAnthony Liguori return 2; 69f5866fa4SKevin Wolf } 70019d6b8fSAnthony Liguori return 0; 71019d6b8fSAnthony Liguori } 72019d6b8fSAnthony Liguori 7369d34a36SKevin Wolf static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result) 74019d6b8fSAnthony Liguori { 75019d6b8fSAnthony Liguori uint64_t buffer; 7669d34a36SKevin Wolf int ret; 7769d34a36SKevin Wolf 7832cc71deSAlberto Faria ret = bdrv_pread(bs->file, offset, 8, &buffer, 0); 7969d34a36SKevin Wolf if (ret < 0) { 8069d34a36SKevin Wolf return ret; 81019d6b8fSAnthony Liguori } 82019d6b8fSAnthony Liguori 8369d34a36SKevin Wolf *result = be64_to_cpu(buffer); 8469d34a36SKevin Wolf return 0; 8569d34a36SKevin Wolf } 8669d34a36SKevin Wolf 8769d34a36SKevin Wolf static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) 88019d6b8fSAnthony Liguori { 89019d6b8fSAnthony Liguori uint32_t buffer; 9069d34a36SKevin Wolf int ret; 9169d34a36SKevin Wolf 9232cc71deSAlberto Faria ret = bdrv_pread(bs->file, offset, 4, &buffer, 0); 9369d34a36SKevin Wolf if (ret < 0) { 9469d34a36SKevin Wolf return ret; 9569d34a36SKevin Wolf } 9669d34a36SKevin Wolf 9769d34a36SKevin Wolf *result = be32_to_cpu(buffer); 98019d6b8fSAnthony Liguori return 0; 99019d6b8fSAnthony Liguori } 100019d6b8fSAnthony Liguori 1017aee37b9SPeter Wu static inline uint64_t buff_read_uint64(const uint8_t *buffer, int64_t offset) 1027aee37b9SPeter Wu { 1037aee37b9SPeter Wu return be64_to_cpu(*(uint64_t *)&buffer[offset]); 1047aee37b9SPeter Wu } 1057aee37b9SPeter Wu 1067aee37b9SPeter Wu static inline uint32_t buff_read_uint32(const uint8_t *buffer, int64_t offset) 1077aee37b9SPeter Wu { 1087aee37b9SPeter Wu return be32_to_cpu(*(uint32_t *)&buffer[offset]); 1097aee37b9SPeter Wu } 1107aee37b9SPeter Wu 111f0dce234SStefan Hajnoczi /* Increase max chunk sizes, if necessary. This function is used to calculate 112f0dce234SStefan Hajnoczi * the buffer sizes needed for compressed/uncompressed chunk I/O. 113f0dce234SStefan Hajnoczi */ 114f0dce234SStefan Hajnoczi static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk, 115f0dce234SStefan Hajnoczi uint32_t *max_compressed_size, 116f0dce234SStefan Hajnoczi uint32_t *max_sectors_per_chunk) 117f0dce234SStefan Hajnoczi { 118f0dce234SStefan Hajnoczi uint32_t compressed_size = 0; 119f0dce234SStefan Hajnoczi uint32_t uncompressed_sectors = 0; 120f0dce234SStefan Hajnoczi 121f0dce234SStefan Hajnoczi switch (s->types[chunk]) { 12295a156f6SJulio Faracco case UDZO: /* zlib compressed */ 12395a156f6SJulio Faracco case UDBZ: /* bzip2 compressed */ 12495a156f6SJulio Faracco case ULFO: /* lzfse compressed */ 125f0dce234SStefan Hajnoczi compressed_size = s->lengths[chunk]; 126f0dce234SStefan Hajnoczi uncompressed_sectors = s->sectorcounts[chunk]; 127f0dce234SStefan Hajnoczi break; 12895a156f6SJulio Faracco case UDRW: /* copy */ 1296fb0022bSMarc-André Lureau uncompressed_sectors = DIV_ROUND_UP(s->lengths[chunk], 512); 130f0dce234SStefan Hajnoczi break; 13139a0408eSyuchenlin case UDZE: /* zero */ 13239a0408eSyuchenlin case UDIG: /* ignore */ 133177b7510SPeter Wu /* as the all-zeroes block may be large, it is treated specially: the 134177b7510SPeter Wu * sector is not copied from a large buffer, a simple memset is used 135177b7510SPeter Wu * instead. Therefore uncompressed_sectors does not need to be set. */ 136f0dce234SStefan Hajnoczi break; 137f0dce234SStefan Hajnoczi } 138f0dce234SStefan Hajnoczi 139f0dce234SStefan Hajnoczi if (compressed_size > *max_compressed_size) { 140f0dce234SStefan Hajnoczi *max_compressed_size = compressed_size; 141f0dce234SStefan Hajnoczi } 142f0dce234SStefan Hajnoczi if (uncompressed_sectors > *max_sectors_per_chunk) { 143f0dce234SStefan Hajnoczi *max_sectors_per_chunk = uncompressed_sectors; 144f0dce234SStefan Hajnoczi } 145f0dce234SStefan Hajnoczi } 146f0dce234SStefan Hajnoczi 147cf2ab8fcSKevin Wolf static int64_t dmg_find_koly_offset(BdrvChild *file, Error **errp) 148fa8354bdSPeter Wu { 149cf2ab8fcSKevin Wolf BlockDriverState *file_bs = file->bs; 150fa8354bdSPeter Wu int64_t length; 151fa8354bdSPeter Wu int64_t offset = 0; 152fa8354bdSPeter Wu uint8_t buffer[515]; 153fa8354bdSPeter Wu int i, ret; 154fa8354bdSPeter Wu 155fa8354bdSPeter Wu /* bdrv_getlength returns a multiple of block size (512), rounded up. Since 156fa8354bdSPeter Wu * dmg images can have odd sizes, try to look for the "koly" magic which 157fa8354bdSPeter Wu * marks the begin of the UDIF trailer (512 bytes). This magic can be found 158fa8354bdSPeter Wu * in the last 511 bytes of the second-last sector or the first 4 bytes of 159fa8354bdSPeter Wu * the last sector (search space: 515 bytes) */ 160fa8354bdSPeter Wu length = bdrv_getlength(file_bs); 161fa8354bdSPeter Wu if (length < 0) { 162fa8354bdSPeter Wu error_setg_errno(errp, -length, 163fa8354bdSPeter Wu "Failed to get file size while reading UDIF trailer"); 164fa8354bdSPeter Wu return length; 165fa8354bdSPeter Wu } else if (length < 512) { 166fa8354bdSPeter Wu error_setg(errp, "dmg file must be at least 512 bytes long"); 167fa8354bdSPeter Wu return -EINVAL; 168fa8354bdSPeter Wu } 169fa8354bdSPeter Wu if (length > 511 + 512) { 170fa8354bdSPeter Wu offset = length - 511 - 512; 171fa8354bdSPeter Wu } 172fa8354bdSPeter Wu length = length < 515 ? length : 515; 17332cc71deSAlberto Faria ret = bdrv_pread(file, offset, length, buffer, 0); 174fa8354bdSPeter Wu if (ret < 0) { 175fa8354bdSPeter Wu error_setg_errno(errp, -ret, "Failed while reading UDIF trailer"); 176fa8354bdSPeter Wu return ret; 177fa8354bdSPeter Wu } 178fa8354bdSPeter Wu for (i = 0; i < length - 3; i++) { 179fa8354bdSPeter Wu if (buffer[i] == 'k' && buffer[i+1] == 'o' && 180fa8354bdSPeter Wu buffer[i+2] == 'l' && buffer[i+3] == 'y') { 181fa8354bdSPeter Wu return offset + i; 182fa8354bdSPeter Wu } 183fa8354bdSPeter Wu } 184fa8354bdSPeter Wu error_setg(errp, "Could not locate UDIF trailer in dmg file"); 185fa8354bdSPeter Wu return -EINVAL; 186fa8354bdSPeter Wu } 187fa8354bdSPeter Wu 18865a1c7c9SPeter Wu /* used when building the sector table */ 18965a1c7c9SPeter Wu typedef struct DmgHeaderState { 19065a1c7c9SPeter Wu /* used internally by dmg_read_mish_block to remember offsets of blocks 19165a1c7c9SPeter Wu * across calls */ 192c6d34865SPeter Wu uint64_t data_fork_offset; 19365a1c7c9SPeter Wu /* exported for dmg_open */ 19465a1c7c9SPeter Wu uint32_t max_compressed_size; 19565a1c7c9SPeter Wu uint32_t max_sectors_per_chunk; 19665a1c7c9SPeter Wu } DmgHeaderState; 19765a1c7c9SPeter Wu 198a8b10c6eSPeter Wu static bool dmg_is_known_block_type(uint32_t entry_type) 199a8b10c6eSPeter Wu { 200a8b10c6eSPeter Wu switch (entry_type) { 20139a0408eSyuchenlin case UDZE: /* zeros */ 20295a156f6SJulio Faracco case UDRW: /* uncompressed */ 20339a0408eSyuchenlin case UDIG: /* ignore */ 20495a156f6SJulio Faracco case UDZO: /* zlib */ 205a8b10c6eSPeter Wu return true; 20695a156f6SJulio Faracco case UDBZ: /* bzip2 */ 20727685a8dSFam Zheng return !!dmg_uncompress_bz2; 20895a156f6SJulio Faracco case ULFO: /* lzfse */ 2097a40b418SJulio Faracco return !!dmg_uncompress_lzfse; 210a8b10c6eSPeter Wu default: 211a8b10c6eSPeter Wu return false; 212a8b10c6eSPeter Wu } 213a8b10c6eSPeter Wu } 214a8b10c6eSPeter Wu 2157aee37b9SPeter Wu static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds, 2167aee37b9SPeter Wu uint8_t *buffer, uint32_t count) 217019d6b8fSAnthony Liguori { 21865a1c7c9SPeter Wu uint32_t type, i; 21969d34a36SKevin Wolf int ret; 22065a1c7c9SPeter Wu size_t new_size; 22165a1c7c9SPeter Wu uint32_t chunk_count; 2227aee37b9SPeter Wu int64_t offset = 0; 223c6d34865SPeter Wu uint64_t data_offset; 224c6d34865SPeter Wu uint64_t in_offset = ds->data_fork_offset; 22566ec3bbaSPeter Wu uint64_t out_offset; 22616cdf7ceSChristoph Hellwig 2277aee37b9SPeter Wu type = buff_read_uint32(buffer, offset); 22865a1c7c9SPeter Wu /* skip data that is not a valid MISH block (invalid magic or too small) */ 22965a1c7c9SPeter Wu if (type != 0x6d697368 || count < 244) { 23065a1c7c9SPeter Wu /* assume success for now */ 23165a1c7c9SPeter Wu return 0; 23265a1c7c9SPeter Wu } 23316cdf7ceSChristoph Hellwig 23466ec3bbaSPeter Wu /* chunk offsets are relative to this sector number */ 23566ec3bbaSPeter Wu out_offset = buff_read_uint64(buffer, offset + 8); 23666ec3bbaSPeter Wu 237c6d34865SPeter Wu /* location in data fork for (compressed) blob (in bytes) */ 238c6d34865SPeter Wu data_offset = buff_read_uint64(buffer, offset + 0x18); 239c6d34865SPeter Wu in_offset += data_offset; 240c6d34865SPeter Wu 241c6d34865SPeter Wu /* move to begin of chunk entries */ 242c6d34865SPeter Wu offset += 204; 24316cdf7ceSChristoph Hellwig 244019d6b8fSAnthony Liguori chunk_count = (count - 204) / 40; 245019d6b8fSAnthony Liguori new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); 2467267c094SAnthony Liguori s->types = g_realloc(s->types, new_size / 2); 2477267c094SAnthony Liguori s->offsets = g_realloc(s->offsets, new_size); 2487267c094SAnthony Liguori s->lengths = g_realloc(s->lengths, new_size); 2497267c094SAnthony Liguori s->sectors = g_realloc(s->sectors, new_size); 2507267c094SAnthony Liguori s->sectorcounts = g_realloc(s->sectorcounts, new_size); 251019d6b8fSAnthony Liguori 252019d6b8fSAnthony Liguori for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { 2537aee37b9SPeter Wu s->types[i] = buff_read_uint32(buffer, offset); 254a8b10c6eSPeter Wu if (!dmg_is_known_block_type(s->types[i])) { 255971974f0SKevin Wolf switch (s->types[i]) { 256971974f0SKevin Wolf case UDBZ: 257971974f0SKevin Wolf warn_report_once("dmg-bzip2 module is missing, accessing bzip2 " 258971974f0SKevin Wolf "compressed blocks will result in I/O errors"); 259971974f0SKevin Wolf break; 260971974f0SKevin Wolf case ULFO: 261971974f0SKevin Wolf warn_report_once("dmg-lzfse module is missing, accessing lzfse " 262971974f0SKevin Wolf "compressed blocks will result in I/O errors"); 263971974f0SKevin Wolf break; 264971974f0SKevin Wolf case UDCM: 265971974f0SKevin Wolf case UDLE: 266971974f0SKevin Wolf /* Comments and last entry can be ignored without problems */ 267971974f0SKevin Wolf break; 268971974f0SKevin Wolf default: 269971974f0SKevin Wolf warn_report_once("Image contains chunks of unknown type %x, " 270971974f0SKevin Wolf "accessing them will result in I/O errors", 271971974f0SKevin Wolf s->types[i]); 272971974f0SKevin Wolf break; 273971974f0SKevin Wolf } 274019d6b8fSAnthony Liguori chunk_count--; 275019d6b8fSAnthony Liguori i--; 276a8b10c6eSPeter Wu offset += 40; 277019d6b8fSAnthony Liguori continue; 278019d6b8fSAnthony Liguori } 27916cdf7ceSChristoph Hellwig 280a8b10c6eSPeter Wu /* sector number */ 281a8b10c6eSPeter Wu s->sectors[i] = buff_read_uint64(buffer, offset + 8); 28266ec3bbaSPeter Wu s->sectors[i] += out_offset; 28316cdf7ceSChristoph Hellwig 284a8b10c6eSPeter Wu /* sector count */ 285a8b10c6eSPeter Wu s->sectorcounts[i] = buff_read_uint64(buffer, offset + 0x10); 28616cdf7ceSChristoph Hellwig 28739a0408eSyuchenlin /* all-zeroes sector (type UDZE and UDIG) does not need to be 28839a0408eSyuchenlin * "uncompressed" and can therefore be unbounded. */ 28939a0408eSyuchenlin if (s->types[i] != UDZE && s->types[i] != UDIG 29039a0408eSyuchenlin && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) { 291521b2b5dSMax Reitz error_report("sector count %" PRIu64 " for chunk %" PRIu32 292521b2b5dSMax Reitz " is larger than max (%u)", 293c165f775SStefan Hajnoczi s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX); 294c165f775SStefan Hajnoczi ret = -EINVAL; 295c165f775SStefan Hajnoczi goto fail; 296c165f775SStefan Hajnoczi } 297c165f775SStefan Hajnoczi 298a8b10c6eSPeter Wu /* offset in (compressed) data fork */ 299a8b10c6eSPeter Wu s->offsets[i] = buff_read_uint64(buffer, offset + 0x18); 300c6d34865SPeter Wu s->offsets[i] += in_offset; 30116cdf7ceSChristoph Hellwig 302a8b10c6eSPeter Wu /* length in (compressed) data fork */ 303a8b10c6eSPeter Wu s->lengths[i] = buff_read_uint64(buffer, offset + 0x20); 30416cdf7ceSChristoph Hellwig 305c165f775SStefan Hajnoczi if (s->lengths[i] > DMG_LENGTHS_MAX) { 306521b2b5dSMax Reitz error_report("length %" PRIu64 " for chunk %" PRIu32 307521b2b5dSMax Reitz " is larger than max (%u)", 308c165f775SStefan Hajnoczi s->lengths[i], i, DMG_LENGTHS_MAX); 309c165f775SStefan Hajnoczi ret = -EINVAL; 310c165f775SStefan Hajnoczi goto fail; 311c165f775SStefan Hajnoczi } 312c165f775SStefan Hajnoczi 31365a1c7c9SPeter Wu update_max_chunk_size(s, i, &ds->max_compressed_size, 31465a1c7c9SPeter Wu &ds->max_sectors_per_chunk); 315a8b10c6eSPeter Wu offset += 40; 3162c1885adSStefan Hajnoczi } 317019d6b8fSAnthony Liguori s->n_chunks += chunk_count; 31865a1c7c9SPeter Wu return 0; 31965a1c7c9SPeter Wu 32065a1c7c9SPeter Wu fail: 32165a1c7c9SPeter Wu return ret; 322019d6b8fSAnthony Liguori } 32365a1c7c9SPeter Wu 324b0e8dc5dSPeter Wu static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds, 325b0e8dc5dSPeter Wu uint64_t info_begin, uint64_t info_length) 326b0e8dc5dSPeter Wu { 3277aee37b9SPeter Wu BDRVDMGState *s = bs->opaque; 328b0e8dc5dSPeter Wu int ret; 329b0e8dc5dSPeter Wu uint32_t count, rsrc_data_offset; 3307aee37b9SPeter Wu uint8_t *buffer = NULL; 331b0e8dc5dSPeter Wu uint64_t info_end; 332b0e8dc5dSPeter Wu uint64_t offset; 333b0e8dc5dSPeter Wu 334b0e8dc5dSPeter Wu /* read offset from begin of resource fork (info_begin) to resource data */ 335b0e8dc5dSPeter Wu ret = read_uint32(bs, info_begin, &rsrc_data_offset); 336b0e8dc5dSPeter Wu if (ret < 0) { 337b0e8dc5dSPeter Wu goto fail; 338b0e8dc5dSPeter Wu } else if (rsrc_data_offset > info_length) { 339b0e8dc5dSPeter Wu ret = -EINVAL; 340b0e8dc5dSPeter Wu goto fail; 341b0e8dc5dSPeter Wu } 342b0e8dc5dSPeter Wu 343b0e8dc5dSPeter Wu /* read length of resource data */ 344b0e8dc5dSPeter Wu ret = read_uint32(bs, info_begin + 8, &count); 345b0e8dc5dSPeter Wu if (ret < 0) { 346b0e8dc5dSPeter Wu goto fail; 347b0e8dc5dSPeter Wu } else if (count == 0 || rsrc_data_offset + count > info_length) { 348b0e8dc5dSPeter Wu ret = -EINVAL; 349b0e8dc5dSPeter Wu goto fail; 350b0e8dc5dSPeter Wu } 351b0e8dc5dSPeter Wu 352b0e8dc5dSPeter Wu /* begin of resource data (consisting of one or more resources) */ 353b0e8dc5dSPeter Wu offset = info_begin + rsrc_data_offset; 354b0e8dc5dSPeter Wu 355b0e8dc5dSPeter Wu /* end of resource data (there is possibly a following resource map 356b0e8dc5dSPeter Wu * which will be ignored). */ 357b0e8dc5dSPeter Wu info_end = offset + count; 358b0e8dc5dSPeter Wu 359b0e8dc5dSPeter Wu /* read offsets (mish blocks) from one or more resources in resource data */ 360b0e8dc5dSPeter Wu while (offset < info_end) { 361b0e8dc5dSPeter Wu /* size of following resource */ 362b0e8dc5dSPeter Wu ret = read_uint32(bs, offset, &count); 363b0e8dc5dSPeter Wu if (ret < 0) { 364b0e8dc5dSPeter Wu goto fail; 365f6e6652dSPeter Wu } else if (count == 0 || count > info_end - offset) { 366b0e8dc5dSPeter Wu ret = -EINVAL; 367b0e8dc5dSPeter Wu goto fail; 368b0e8dc5dSPeter Wu } 369b0e8dc5dSPeter Wu offset += 4; 370b0e8dc5dSPeter Wu 3717aee37b9SPeter Wu buffer = g_realloc(buffer, count); 37232cc71deSAlberto Faria ret = bdrv_pread(bs->file, offset, count, buffer, 0); 3737aee37b9SPeter Wu if (ret < 0) { 3747aee37b9SPeter Wu goto fail; 3757aee37b9SPeter Wu } 3767aee37b9SPeter Wu 3777aee37b9SPeter Wu ret = dmg_read_mish_block(s, ds, buffer, count); 378b0e8dc5dSPeter Wu if (ret < 0) { 379b0e8dc5dSPeter Wu goto fail; 380b0e8dc5dSPeter Wu } 381b0e8dc5dSPeter Wu /* advance offset by size of resource */ 382b0e8dc5dSPeter Wu offset += count; 383b0e8dc5dSPeter Wu } 3847aee37b9SPeter Wu ret = 0; 385b0e8dc5dSPeter Wu 386b0e8dc5dSPeter Wu fail: 3877aee37b9SPeter Wu g_free(buffer); 388b0e8dc5dSPeter Wu return ret; 389b0e8dc5dSPeter Wu } 390b0e8dc5dSPeter Wu 3910599e56eSPeter Wu static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds, 3920599e56eSPeter Wu uint64_t info_begin, uint64_t info_length) 3930599e56eSPeter Wu { 3940599e56eSPeter Wu BDRVDMGState *s = bs->opaque; 3950599e56eSPeter Wu int ret; 3960599e56eSPeter Wu uint8_t *buffer = NULL; 3970599e56eSPeter Wu char *data_begin, *data_end; 3980599e56eSPeter Wu 3990599e56eSPeter Wu /* Have at least some length to avoid NULL for g_malloc. Attempt to set a 4000599e56eSPeter Wu * safe upper cap on the data length. A test sample had a XML length of 4010599e56eSPeter Wu * about 1 MiB. */ 4020599e56eSPeter Wu if (info_length == 0 || info_length > 16 * 1024 * 1024) { 4030599e56eSPeter Wu ret = -EINVAL; 4040599e56eSPeter Wu goto fail; 4050599e56eSPeter Wu } 4060599e56eSPeter Wu 4070599e56eSPeter Wu buffer = g_malloc(info_length + 1); 4080599e56eSPeter Wu buffer[info_length] = '\0'; 40932cc71deSAlberto Faria ret = bdrv_pread(bs->file, info_begin, info_length, buffer, 0); 410353a5d84SAlberto Faria if (ret < 0) { 4110599e56eSPeter Wu ret = -EINVAL; 4120599e56eSPeter Wu goto fail; 4130599e56eSPeter Wu } 4140599e56eSPeter Wu 4150599e56eSPeter Wu /* look for <data>...</data>. The data is 284 (0x11c) bytes after base64 4160599e56eSPeter Wu * decode. The actual data element has 431 (0x1af) bytes which includes tabs 4170599e56eSPeter Wu * and line feeds. */ 4180599e56eSPeter Wu data_end = (char *)buffer; 4190599e56eSPeter Wu while ((data_begin = strstr(data_end, "<data>")) != NULL) { 4200599e56eSPeter Wu guchar *mish; 4210599e56eSPeter Wu gsize out_len = 0; 4220599e56eSPeter Wu 4230599e56eSPeter Wu data_begin += 6; 4240599e56eSPeter Wu data_end = strstr(data_begin, "</data>"); 4250599e56eSPeter Wu /* malformed XML? */ 4260599e56eSPeter Wu if (data_end == NULL) { 4270599e56eSPeter Wu ret = -EINVAL; 4280599e56eSPeter Wu goto fail; 4290599e56eSPeter Wu } 4300599e56eSPeter Wu *data_end++ = '\0'; 4310599e56eSPeter Wu mish = g_base64_decode(data_begin, &out_len); 4320599e56eSPeter Wu ret = dmg_read_mish_block(s, ds, mish, (uint32_t)out_len); 4330599e56eSPeter Wu g_free(mish); 4340599e56eSPeter Wu if (ret < 0) { 4350599e56eSPeter Wu goto fail; 4360599e56eSPeter Wu } 4370599e56eSPeter Wu } 4380599e56eSPeter Wu ret = 0; 4390599e56eSPeter Wu 4400599e56eSPeter Wu fail: 4410599e56eSPeter Wu g_free(buffer); 4420599e56eSPeter Wu return ret; 4430599e56eSPeter Wu } 4440599e56eSPeter Wu 44565a1c7c9SPeter Wu static int dmg_open(BlockDriverState *bs, QDict *options, int flags, 44665a1c7c9SPeter Wu Error **errp) 44765a1c7c9SPeter Wu { 44865a1c7c9SPeter Wu BDRVDMGState *s = bs->opaque; 44965a1c7c9SPeter Wu DmgHeaderState ds; 450b0e8dc5dSPeter Wu uint64_t rsrc_fork_offset, rsrc_fork_length; 4510599e56eSPeter Wu uint64_t plist_xml_offset, plist_xml_length; 45265a1c7c9SPeter Wu int64_t offset; 45365a1c7c9SPeter Wu int ret; 45465a1c7c9SPeter Wu 455018f9deaSKevin Wolf bdrv_graph_rdlock_main_loop(); 456eaa2410fSKevin Wolf ret = bdrv_apply_auto_read_only(bs, NULL, errp); 457018f9deaSKevin Wolf bdrv_graph_rdunlock_main_loop(); 458eaa2410fSKevin Wolf if (ret < 0) { 459eaa2410fSKevin Wolf return ret; 460eaa2410fSKevin Wolf } 461eaa2410fSKevin Wolf 46283930780SVladimir Sementsov-Ogievskiy ret = bdrv_open_file_child(NULL, options, "file", bs, errp); 46383930780SVladimir Sementsov-Ogievskiy if (ret < 0) { 46483930780SVladimir Sementsov-Ogievskiy return ret; 4654e4bf5c4SKevin Wolf } 466c551fb0bSClaudio Fontana /* 467c551fb0bSClaudio Fontana * NB: if uncompress submodules are absent, 468c551fb0bSClaudio Fontana * ie block_module_load return value == 0, the function pointers 469c551fb0bSClaudio Fontana * dmg_uncompress_bz2 and dmg_uncompress_lzfse will be NULL. 470c551fb0bSClaudio Fontana */ 471c551fb0bSClaudio Fontana if (block_module_load("dmg-bz2", errp) < 0) { 472c551fb0bSClaudio Fontana return -EINVAL; 473c551fb0bSClaudio Fontana } 474c551fb0bSClaudio Fontana if (block_module_load("dmg-lzfse", errp) < 0) { 475c551fb0bSClaudio Fontana return -EINVAL; 476c551fb0bSClaudio Fontana } 4773edf1e73SKevin Wolf 47865a1c7c9SPeter Wu s->n_chunks = 0; 47965a1c7c9SPeter Wu s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; 48065a1c7c9SPeter Wu /* used by dmg_read_mish_block to keep track of the current I/O position */ 481c6d34865SPeter Wu ds.data_fork_offset = 0; 48265a1c7c9SPeter Wu ds.max_compressed_size = 1; 48365a1c7c9SPeter Wu ds.max_sectors_per_chunk = 1; 48465a1c7c9SPeter Wu 48565a1c7c9SPeter Wu /* locate the UDIF trailer */ 486cf2ab8fcSKevin Wolf offset = dmg_find_koly_offset(bs->file, errp); 48765a1c7c9SPeter Wu if (offset < 0) { 48865a1c7c9SPeter Wu ret = offset; 48965a1c7c9SPeter Wu goto fail; 49065a1c7c9SPeter Wu } 49165a1c7c9SPeter Wu 492c6d34865SPeter Wu /* offset of data fork (DataForkOffset) */ 493c6d34865SPeter Wu ret = read_uint64(bs, offset + 0x18, &ds.data_fork_offset); 494c6d34865SPeter Wu if (ret < 0) { 495c6d34865SPeter Wu goto fail; 496c6d34865SPeter Wu } else if (ds.data_fork_offset > offset) { 497c6d34865SPeter Wu ret = -EINVAL; 498c6d34865SPeter Wu goto fail; 499c6d34865SPeter Wu } 500c6d34865SPeter Wu 501b0e8dc5dSPeter Wu /* offset of resource fork (RsrcForkOffset) */ 502b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset); 50365a1c7c9SPeter Wu if (ret < 0) { 50465a1c7c9SPeter Wu goto fail; 505b0e8dc5dSPeter Wu } 506b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length); 507b0e8dc5dSPeter Wu if (ret < 0) { 508b0e8dc5dSPeter Wu goto fail; 509b0e8dc5dSPeter Wu } 510f6e6652dSPeter Wu if (rsrc_fork_offset >= offset || 511f6e6652dSPeter Wu rsrc_fork_length > offset - rsrc_fork_offset) { 512f6e6652dSPeter Wu ret = -EINVAL; 513f6e6652dSPeter Wu goto fail; 514f6e6652dSPeter Wu } 5150599e56eSPeter Wu /* offset of property list (XMLOffset) */ 5160599e56eSPeter Wu ret = read_uint64(bs, offset + 0xd8, &plist_xml_offset); 5170599e56eSPeter Wu if (ret < 0) { 5180599e56eSPeter Wu goto fail; 5190599e56eSPeter Wu } 5200599e56eSPeter Wu ret = read_uint64(bs, offset + 0xe0, &plist_xml_length); 5210599e56eSPeter Wu if (ret < 0) { 5220599e56eSPeter Wu goto fail; 5230599e56eSPeter Wu } 5240599e56eSPeter Wu if (plist_xml_offset >= offset || 5250599e56eSPeter Wu plist_xml_length > offset - plist_xml_offset) { 5260599e56eSPeter Wu ret = -EINVAL; 5270599e56eSPeter Wu goto fail; 5280599e56eSPeter Wu } 5298daf4257SPeter Wu ret = read_uint64(bs, offset + 0x1ec, (uint64_t *)&bs->total_sectors); 5308daf4257SPeter Wu if (ret < 0) { 5318daf4257SPeter Wu goto fail; 5328daf4257SPeter Wu } 5338daf4257SPeter Wu if (bs->total_sectors < 0) { 5348daf4257SPeter Wu ret = -EINVAL; 5358daf4257SPeter Wu goto fail; 5368daf4257SPeter Wu } 537b0e8dc5dSPeter Wu if (rsrc_fork_length != 0) { 538b0e8dc5dSPeter Wu ret = dmg_read_resource_fork(bs, &ds, 539b0e8dc5dSPeter Wu rsrc_fork_offset, rsrc_fork_length); 540b0e8dc5dSPeter Wu if (ret < 0) { 541b0e8dc5dSPeter Wu goto fail; 542b0e8dc5dSPeter Wu } 5430599e56eSPeter Wu } else if (plist_xml_length != 0) { 5440599e56eSPeter Wu ret = dmg_read_plist_xml(bs, &ds, plist_xml_offset, plist_xml_length); 5450599e56eSPeter Wu if (ret < 0) { 5460599e56eSPeter Wu goto fail; 5470599e56eSPeter Wu } 548b0e8dc5dSPeter Wu } else { 54965a1c7c9SPeter Wu ret = -EINVAL; 55065a1c7c9SPeter Wu goto fail; 55165a1c7c9SPeter Wu } 55265a1c7c9SPeter Wu 553019d6b8fSAnthony Liguori /* initialize zlib engine */ 5549a4f4c31SKevin Wolf s->compressed_chunk = qemu_try_blockalign(bs->file->bs, 55565a1c7c9SPeter Wu ds.max_compressed_size + 1); 5569a4f4c31SKevin Wolf s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs, 55765a1c7c9SPeter Wu 512 * ds.max_sectors_per_chunk); 558b546a944SKevin Wolf if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { 559b546a944SKevin Wolf ret = -ENOMEM; 560b546a944SKevin Wolf goto fail; 561b546a944SKevin Wolf } 562b546a944SKevin Wolf 56369d34a36SKevin Wolf if (inflateInit(&s->zstream) != Z_OK) { 56469d34a36SKevin Wolf ret = -EINVAL; 5651559ca00SChristoph Hellwig goto fail; 56669d34a36SKevin Wolf } 567019d6b8fSAnthony Liguori 568019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 569019d6b8fSAnthony Liguori 570848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 571019d6b8fSAnthony Liguori return 0; 57269d34a36SKevin Wolf 5731559ca00SChristoph Hellwig fail: 57469d34a36SKevin Wolf g_free(s->types); 57569d34a36SKevin Wolf g_free(s->offsets); 57669d34a36SKevin Wolf g_free(s->lengths); 57769d34a36SKevin Wolf g_free(s->sectors); 57869d34a36SKevin Wolf g_free(s->sectorcounts); 579b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 580b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 58169d34a36SKevin Wolf return ret; 582019d6b8fSAnthony Liguori } 583019d6b8fSAnthony Liguori 584a6506481SEric Blake static void dmg_refresh_limits(BlockDriverState *bs, Error **errp) 585a6506481SEric Blake { 586a5b8dd2cSEric Blake bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */ 587a6506481SEric Blake } 588a6506481SEric Blake 589019d6b8fSAnthony Liguori static inline int is_sector_in_chunk(BDRVDMGState *s, 590686d7148SStefan Hajnoczi uint32_t chunk_num, uint64_t sector_num) 591019d6b8fSAnthony Liguori { 592019d6b8fSAnthony Liguori if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num || 5932c1885adSStefan Hajnoczi s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) { 594019d6b8fSAnthony Liguori return 0; 5952c1885adSStefan Hajnoczi } else { 596019d6b8fSAnthony Liguori return -1; 597019d6b8fSAnthony Liguori } 5982c1885adSStefan Hajnoczi } 599019d6b8fSAnthony Liguori 600686d7148SStefan Hajnoczi static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num) 601019d6b8fSAnthony Liguori { 602019d6b8fSAnthony Liguori /* binary search */ 603019d6b8fSAnthony Liguori uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3; 6045ef40828Syuchenlin while (chunk1 <= chunk2) { 605019d6b8fSAnthony Liguori chunk3 = (chunk1 + chunk2) / 2; 6062c1885adSStefan Hajnoczi if (s->sectors[chunk3] > sector_num) { 6075ef40828Syuchenlin if (chunk3 == 0) { 6085ef40828Syuchenlin goto err; 6095ef40828Syuchenlin } 6105ef40828Syuchenlin chunk2 = chunk3 - 1; 6112c1885adSStefan Hajnoczi } else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) { 612019d6b8fSAnthony Liguori return chunk3; 6132c1885adSStefan Hajnoczi } else { 6145ef40828Syuchenlin chunk1 = chunk3 + 1; 615019d6b8fSAnthony Liguori } 6162c1885adSStefan Hajnoczi } 6175ef40828Syuchenlin err: 618019d6b8fSAnthony Liguori return s->n_chunks; /* error */ 619019d6b8fSAnthony Liguori } 620019d6b8fSAnthony Liguori 621688dc49dSPaolo Bonzini static int coroutine_fn GRAPH_RDLOCK 622688dc49dSPaolo Bonzini dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) 623019d6b8fSAnthony Liguori { 62464a31d5cSChristoph Hellwig BDRVDMGState *s = bs->opaque; 62564a31d5cSChristoph Hellwig 626019d6b8fSAnthony Liguori if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) { 627019d6b8fSAnthony Liguori int ret; 628019d6b8fSAnthony Liguori uint32_t chunk = search_chunk(s, sector_num); 629019d6b8fSAnthony Liguori 6302c1885adSStefan Hajnoczi if (chunk >= s->n_chunks) { 631019d6b8fSAnthony Liguori return -1; 6322c1885adSStefan Hajnoczi } 633019d6b8fSAnthony Liguori 634019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 6356b383c08SPeter Wu switch (s->types[chunk]) { /* block entry type */ 63695a156f6SJulio Faracco case UDZO: { /* zlib compressed */ 637019d6b8fSAnthony Liguori /* we need to buffer, because only the chunk as whole can be 638019d6b8fSAnthony Liguori * inflated. */ 639688dc49dSPaolo Bonzini ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk], 64032cc71deSAlberto Faria s->compressed_chunk, 0); 641353a5d84SAlberto Faria if (ret < 0) { 642019d6b8fSAnthony Liguori return -1; 6432c1885adSStefan Hajnoczi } 644019d6b8fSAnthony Liguori 645019d6b8fSAnthony Liguori s->zstream.next_in = s->compressed_chunk; 646019d6b8fSAnthony Liguori s->zstream.avail_in = s->lengths[chunk]; 647019d6b8fSAnthony Liguori s->zstream.next_out = s->uncompressed_chunk; 648019d6b8fSAnthony Liguori s->zstream.avail_out = 512 * s->sectorcounts[chunk]; 649019d6b8fSAnthony Liguori ret = inflateReset(&s->zstream); 6502c1885adSStefan Hajnoczi if (ret != Z_OK) { 651019d6b8fSAnthony Liguori return -1; 6522c1885adSStefan Hajnoczi } 653019d6b8fSAnthony Liguori ret = inflate(&s->zstream, Z_FINISH); 6542c1885adSStefan Hajnoczi if (ret != Z_STREAM_END || 6552c1885adSStefan Hajnoczi s->zstream.total_out != 512 * s->sectorcounts[chunk]) { 656019d6b8fSAnthony Liguori return -1; 6572c1885adSStefan Hajnoczi } 658019d6b8fSAnthony Liguori break; } 65995a156f6SJulio Faracco case UDBZ: /* bzip2 compressed */ 66027685a8dSFam Zheng if (!dmg_uncompress_bz2) { 66127685a8dSFam Zheng break; 66227685a8dSFam Zheng } 6636b383c08SPeter Wu /* we need to buffer, because only the chunk as whole can be 6646b383c08SPeter Wu * inflated. */ 665688dc49dSPaolo Bonzini ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk], 66632cc71deSAlberto Faria s->compressed_chunk, 0); 667353a5d84SAlberto Faria if (ret < 0) { 6686b383c08SPeter Wu return -1; 6696b383c08SPeter Wu } 6706b383c08SPeter Wu 67127685a8dSFam Zheng ret = dmg_uncompress_bz2((char *)s->compressed_chunk, 67227685a8dSFam Zheng (unsigned int) s->lengths[chunk], 67327685a8dSFam Zheng (char *)s->uncompressed_chunk, 67427685a8dSFam Zheng (unsigned int) 67527685a8dSFam Zheng (512 * s->sectorcounts[chunk])); 67627685a8dSFam Zheng if (ret < 0) { 67727685a8dSFam Zheng return ret; 6786b383c08SPeter Wu } 6796b383c08SPeter Wu break; 68095a156f6SJulio Faracco case ULFO: 6817a40b418SJulio Faracco if (!dmg_uncompress_lzfse) { 6827a40b418SJulio Faracco break; 6837a40b418SJulio Faracco } 6847a40b418SJulio Faracco /* we need to buffer, because only the chunk as whole can be 6857a40b418SJulio Faracco * inflated. */ 686688dc49dSPaolo Bonzini ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk], 68732cc71deSAlberto Faria s->compressed_chunk, 0); 688353a5d84SAlberto Faria if (ret < 0) { 6897a40b418SJulio Faracco return -1; 6907a40b418SJulio Faracco } 6917a40b418SJulio Faracco 6927a40b418SJulio Faracco ret = dmg_uncompress_lzfse((char *)s->compressed_chunk, 6937a40b418SJulio Faracco (unsigned int) s->lengths[chunk], 6947a40b418SJulio Faracco (char *)s->uncompressed_chunk, 6957a40b418SJulio Faracco (unsigned int) 6967a40b418SJulio Faracco (512 * s->sectorcounts[chunk])); 6977a40b418SJulio Faracco if (ret < 0) { 6987a40b418SJulio Faracco return ret; 6997a40b418SJulio Faracco } 7007a40b418SJulio Faracco break; 70195a156f6SJulio Faracco case UDRW: /* copy */ 702688dc49dSPaolo Bonzini ret = bdrv_co_pread(bs->file, s->offsets[chunk], s->lengths[chunk], 70332cc71deSAlberto Faria s->uncompressed_chunk, 0); 704353a5d84SAlberto Faria if (ret < 0) { 705019d6b8fSAnthony Liguori return -1; 7062c1885adSStefan Hajnoczi } 707019d6b8fSAnthony Liguori break; 70839a0408eSyuchenlin case UDZE: /* zeros */ 70939a0408eSyuchenlin case UDIG: /* ignore */ 710177b7510SPeter Wu /* see dmg_read, it is treated specially. No buffer needs to be 711177b7510SPeter Wu * pre-filled, the zeroes can be set directly. */ 712019d6b8fSAnthony Liguori break; 713019d6b8fSAnthony Liguori } 714019d6b8fSAnthony Liguori s->current_chunk = chunk; 715019d6b8fSAnthony Liguori } 716019d6b8fSAnthony Liguori return 0; 717019d6b8fSAnthony Liguori } 718019d6b8fSAnthony Liguori 719688dc49dSPaolo Bonzini static int coroutine_fn GRAPH_RDLOCK 720f7ef38ddSVladimir Sementsov-Ogievskiy dmg_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes, 721f7ef38ddSVladimir Sementsov-Ogievskiy QEMUIOVector *qiov, BdrvRequestFlags flags) 722019d6b8fSAnthony Liguori { 723019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 7243edf1e73SKevin Wolf uint64_t sector_num = offset >> BDRV_SECTOR_BITS; 7253edf1e73SKevin Wolf int nb_sectors = bytes >> BDRV_SECTOR_BITS; 7263edf1e73SKevin Wolf int ret, i; 7273edf1e73SKevin Wolf 7281bbbf32dSNir Soffer assert(QEMU_IS_ALIGNED(offset, BDRV_SECTOR_SIZE)); 7291bbbf32dSNir Soffer assert(QEMU_IS_ALIGNED(bytes, BDRV_SECTOR_SIZE)); 7303edf1e73SKevin Wolf 7313edf1e73SKevin Wolf qemu_co_mutex_lock(&s->lock); 732019d6b8fSAnthony Liguori 733019d6b8fSAnthony Liguori for (i = 0; i < nb_sectors; i++) { 734019d6b8fSAnthony Liguori uint32_t sector_offset_in_chunk; 7353edf1e73SKevin Wolf void *data; 7363edf1e73SKevin Wolf 7372c1885adSStefan Hajnoczi if (dmg_read_chunk(bs, sector_num + i) != 0) { 7383edf1e73SKevin Wolf ret = -EIO; 7393edf1e73SKevin Wolf goto fail; 7402c1885adSStefan Hajnoczi } 741177b7510SPeter Wu /* Special case: current chunk is all zeroes. Do not perform a memcpy as 742177b7510SPeter Wu * s->uncompressed_chunk may be too small to cover the large all-zeroes 743177b7510SPeter Wu * section. dmg_read_chunk is called to find s->current_chunk */ 74439a0408eSyuchenlin if (s->types[s->current_chunk] == UDZE 74539a0408eSyuchenlin || s->types[s->current_chunk] == UDIG) { /* all zeroes block entry */ 7463edf1e73SKevin Wolf qemu_iovec_memset(qiov, i * 512, 0, 512); 747177b7510SPeter Wu continue; 748177b7510SPeter Wu } 749019d6b8fSAnthony Liguori sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk]; 7503edf1e73SKevin Wolf data = s->uncompressed_chunk + sector_offset_in_chunk * 512; 7513edf1e73SKevin Wolf qemu_iovec_from_buf(qiov, i * 512, data, 512); 752019d6b8fSAnthony Liguori } 753019d6b8fSAnthony Liguori 7543edf1e73SKevin Wolf ret = 0; 7553edf1e73SKevin Wolf fail: 7562914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 7572914caa0SPaolo Bonzini return ret; 7582914caa0SPaolo Bonzini } 7592914caa0SPaolo Bonzini 760019d6b8fSAnthony Liguori static void dmg_close(BlockDriverState *bs) 761019d6b8fSAnthony Liguori { 762019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 7634f8aa2e1SKevin Wolf 7644f8aa2e1SKevin Wolf g_free(s->types); 7654f8aa2e1SKevin Wolf g_free(s->offsets); 7664f8aa2e1SKevin Wolf g_free(s->lengths); 7674f8aa2e1SKevin Wolf g_free(s->sectors); 7684f8aa2e1SKevin Wolf g_free(s->sectorcounts); 769b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 770b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 7714f8aa2e1SKevin Wolf 772019d6b8fSAnthony Liguori inflateEnd(&s->zstream); 773019d6b8fSAnthony Liguori } 774019d6b8fSAnthony Liguori 775019d6b8fSAnthony Liguori static BlockDriver bdrv_dmg = { 776019d6b8fSAnthony Liguori .format_name = "dmg", 777019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVDMGState), 778019d6b8fSAnthony Liguori .bdrv_probe = dmg_probe, 77964a31d5cSChristoph Hellwig .bdrv_open = dmg_open, 780a6506481SEric Blake .bdrv_refresh_limits = dmg_refresh_limits, 78169dca43dSMax Reitz .bdrv_child_perm = bdrv_default_perms, 7823edf1e73SKevin Wolf .bdrv_co_preadv = dmg_co_preadv, 783019d6b8fSAnthony Liguori .bdrv_close = dmg_close, 784d67066d8SMax Reitz .is_format = true, 785019d6b8fSAnthony Liguori }; 786019d6b8fSAnthony Liguori 787019d6b8fSAnthony Liguori static void bdrv_dmg_init(void) 788019d6b8fSAnthony Liguori { 789019d6b8fSAnthony Liguori bdrv_register(&bdrv_dmg); 790019d6b8fSAnthony Liguori } 791019d6b8fSAnthony Liguori 792019d6b8fSAnthony Liguori block_init(bdrv_dmg_init); 793