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" 26019d6b8fSAnthony Liguori #include "qemu-common.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" 3127685a8dSFam Zheng #include "dmg.h" 3227685a8dSFam Zheng 3327685a8dSFam Zheng int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in, 3427685a8dSFam Zheng char *next_out, unsigned int avail_out); 35019d6b8fSAnthony Liguori 36c165f775SStefan Hajnoczi enum { 37c165f775SStefan Hajnoczi /* Limit chunk sizes to prevent unreasonable amounts of memory being used 38c165f775SStefan Hajnoczi * or truncating when converting to 32-bit types 39c165f775SStefan Hajnoczi */ 40c165f775SStefan Hajnoczi DMG_LENGTHS_MAX = 64 * 1024 * 1024, /* 64 MB */ 41c165f775SStefan Hajnoczi DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512, 42c165f775SStefan Hajnoczi }; 43c165f775SStefan Hajnoczi 44019d6b8fSAnthony Liguori static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename) 45019d6b8fSAnthony Liguori { 46f5866fa4SKevin Wolf int len; 47f5866fa4SKevin Wolf 48f5866fa4SKevin Wolf if (!filename) { 49f5866fa4SKevin Wolf return 0; 50f5866fa4SKevin Wolf } 51f5866fa4SKevin Wolf 52f5866fa4SKevin Wolf len = strlen(filename); 53f5866fa4SKevin Wolf if (len > 4 && !strcmp(filename + len - 4, ".dmg")) { 54019d6b8fSAnthony Liguori return 2; 55f5866fa4SKevin Wolf } 56019d6b8fSAnthony Liguori return 0; 57019d6b8fSAnthony Liguori } 58019d6b8fSAnthony Liguori 5969d34a36SKevin Wolf static int read_uint64(BlockDriverState *bs, int64_t offset, uint64_t *result) 60019d6b8fSAnthony Liguori { 61019d6b8fSAnthony Liguori uint64_t buffer; 6269d34a36SKevin Wolf int ret; 6369d34a36SKevin Wolf 64cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, offset, &buffer, 8); 6569d34a36SKevin Wolf if (ret < 0) { 6669d34a36SKevin Wolf return ret; 67019d6b8fSAnthony Liguori } 68019d6b8fSAnthony Liguori 6969d34a36SKevin Wolf *result = be64_to_cpu(buffer); 7069d34a36SKevin Wolf return 0; 7169d34a36SKevin Wolf } 7269d34a36SKevin Wolf 7369d34a36SKevin Wolf static int read_uint32(BlockDriverState *bs, int64_t offset, uint32_t *result) 74019d6b8fSAnthony Liguori { 75019d6b8fSAnthony Liguori uint32_t buffer; 7669d34a36SKevin Wolf int ret; 7769d34a36SKevin Wolf 78cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, offset, &buffer, 4); 7969d34a36SKevin Wolf if (ret < 0) { 8069d34a36SKevin Wolf return ret; 8169d34a36SKevin Wolf } 8269d34a36SKevin Wolf 8369d34a36SKevin Wolf *result = be32_to_cpu(buffer); 84019d6b8fSAnthony Liguori return 0; 85019d6b8fSAnthony Liguori } 86019d6b8fSAnthony Liguori 877aee37b9SPeter Wu static inline uint64_t buff_read_uint64(const uint8_t *buffer, int64_t offset) 887aee37b9SPeter Wu { 897aee37b9SPeter Wu return be64_to_cpu(*(uint64_t *)&buffer[offset]); 907aee37b9SPeter Wu } 917aee37b9SPeter Wu 927aee37b9SPeter Wu static inline uint32_t buff_read_uint32(const uint8_t *buffer, int64_t offset) 937aee37b9SPeter Wu { 947aee37b9SPeter Wu return be32_to_cpu(*(uint32_t *)&buffer[offset]); 957aee37b9SPeter Wu } 967aee37b9SPeter Wu 97f0dce234SStefan Hajnoczi /* Increase max chunk sizes, if necessary. This function is used to calculate 98f0dce234SStefan Hajnoczi * the buffer sizes needed for compressed/uncompressed chunk I/O. 99f0dce234SStefan Hajnoczi */ 100f0dce234SStefan Hajnoczi static void update_max_chunk_size(BDRVDMGState *s, uint32_t chunk, 101f0dce234SStefan Hajnoczi uint32_t *max_compressed_size, 102f0dce234SStefan Hajnoczi uint32_t *max_sectors_per_chunk) 103f0dce234SStefan Hajnoczi { 104f0dce234SStefan Hajnoczi uint32_t compressed_size = 0; 105f0dce234SStefan Hajnoczi uint32_t uncompressed_sectors = 0; 106f0dce234SStefan Hajnoczi 107f0dce234SStefan Hajnoczi switch (s->types[chunk]) { 108f0dce234SStefan Hajnoczi case 0x80000005: /* zlib compressed */ 1096b383c08SPeter Wu case 0x80000006: /* bzip2 compressed */ 110f0dce234SStefan Hajnoczi compressed_size = s->lengths[chunk]; 111f0dce234SStefan Hajnoczi uncompressed_sectors = s->sectorcounts[chunk]; 112f0dce234SStefan Hajnoczi break; 113f0dce234SStefan Hajnoczi case 1: /* copy */ 114f0dce234SStefan Hajnoczi uncompressed_sectors = (s->lengths[chunk] + 511) / 512; 115f0dce234SStefan Hajnoczi break; 116f0dce234SStefan Hajnoczi case 2: /* zero */ 117177b7510SPeter Wu /* as the all-zeroes block may be large, it is treated specially: the 118177b7510SPeter Wu * sector is not copied from a large buffer, a simple memset is used 119177b7510SPeter Wu * instead. Therefore uncompressed_sectors does not need to be set. */ 120f0dce234SStefan Hajnoczi break; 121f0dce234SStefan Hajnoczi } 122f0dce234SStefan Hajnoczi 123f0dce234SStefan Hajnoczi if (compressed_size > *max_compressed_size) { 124f0dce234SStefan Hajnoczi *max_compressed_size = compressed_size; 125f0dce234SStefan Hajnoczi } 126f0dce234SStefan Hajnoczi if (uncompressed_sectors > *max_sectors_per_chunk) { 127f0dce234SStefan Hajnoczi *max_sectors_per_chunk = uncompressed_sectors; 128f0dce234SStefan Hajnoczi } 129f0dce234SStefan Hajnoczi } 130f0dce234SStefan Hajnoczi 131cf2ab8fcSKevin Wolf static int64_t dmg_find_koly_offset(BdrvChild *file, Error **errp) 132fa8354bdSPeter Wu { 133cf2ab8fcSKevin Wolf BlockDriverState *file_bs = file->bs; 134fa8354bdSPeter Wu int64_t length; 135fa8354bdSPeter Wu int64_t offset = 0; 136fa8354bdSPeter Wu uint8_t buffer[515]; 137fa8354bdSPeter Wu int i, ret; 138fa8354bdSPeter Wu 139fa8354bdSPeter Wu /* bdrv_getlength returns a multiple of block size (512), rounded up. Since 140fa8354bdSPeter Wu * dmg images can have odd sizes, try to look for the "koly" magic which 141fa8354bdSPeter Wu * marks the begin of the UDIF trailer (512 bytes). This magic can be found 142fa8354bdSPeter Wu * in the last 511 bytes of the second-last sector or the first 4 bytes of 143fa8354bdSPeter Wu * the last sector (search space: 515 bytes) */ 144fa8354bdSPeter Wu length = bdrv_getlength(file_bs); 145fa8354bdSPeter Wu if (length < 0) { 146fa8354bdSPeter Wu error_setg_errno(errp, -length, 147fa8354bdSPeter Wu "Failed to get file size while reading UDIF trailer"); 148fa8354bdSPeter Wu return length; 149fa8354bdSPeter Wu } else if (length < 512) { 150fa8354bdSPeter Wu error_setg(errp, "dmg file must be at least 512 bytes long"); 151fa8354bdSPeter Wu return -EINVAL; 152fa8354bdSPeter Wu } 153fa8354bdSPeter Wu if (length > 511 + 512) { 154fa8354bdSPeter Wu offset = length - 511 - 512; 155fa8354bdSPeter Wu } 156fa8354bdSPeter Wu length = length < 515 ? length : 515; 157cf2ab8fcSKevin Wolf ret = bdrv_pread(file, offset, buffer, length); 158fa8354bdSPeter Wu if (ret < 0) { 159fa8354bdSPeter Wu error_setg_errno(errp, -ret, "Failed while reading UDIF trailer"); 160fa8354bdSPeter Wu return ret; 161fa8354bdSPeter Wu } 162fa8354bdSPeter Wu for (i = 0; i < length - 3; i++) { 163fa8354bdSPeter Wu if (buffer[i] == 'k' && buffer[i+1] == 'o' && 164fa8354bdSPeter Wu buffer[i+2] == 'l' && buffer[i+3] == 'y') { 165fa8354bdSPeter Wu return offset + i; 166fa8354bdSPeter Wu } 167fa8354bdSPeter Wu } 168fa8354bdSPeter Wu error_setg(errp, "Could not locate UDIF trailer in dmg file"); 169fa8354bdSPeter Wu return -EINVAL; 170fa8354bdSPeter Wu } 171fa8354bdSPeter Wu 17265a1c7c9SPeter Wu /* used when building the sector table */ 17365a1c7c9SPeter Wu typedef struct DmgHeaderState { 17465a1c7c9SPeter Wu /* used internally by dmg_read_mish_block to remember offsets of blocks 17565a1c7c9SPeter Wu * across calls */ 176c6d34865SPeter Wu uint64_t data_fork_offset; 17765a1c7c9SPeter Wu /* exported for dmg_open */ 17865a1c7c9SPeter Wu uint32_t max_compressed_size; 17965a1c7c9SPeter Wu uint32_t max_sectors_per_chunk; 18065a1c7c9SPeter Wu } DmgHeaderState; 18165a1c7c9SPeter Wu 182a8b10c6eSPeter Wu static bool dmg_is_known_block_type(uint32_t entry_type) 183a8b10c6eSPeter Wu { 184a8b10c6eSPeter Wu switch (entry_type) { 185a8b10c6eSPeter Wu case 0x00000001: /* uncompressed */ 186a8b10c6eSPeter Wu case 0x00000002: /* zeroes */ 187a8b10c6eSPeter Wu case 0x80000005: /* zlib */ 188a8b10c6eSPeter Wu return true; 18927685a8dSFam Zheng case 0x80000006: /* bzip2 */ 19027685a8dSFam Zheng return !!dmg_uncompress_bz2; 191a8b10c6eSPeter Wu default: 192a8b10c6eSPeter Wu return false; 193a8b10c6eSPeter Wu } 194a8b10c6eSPeter Wu } 195a8b10c6eSPeter Wu 1967aee37b9SPeter Wu static int dmg_read_mish_block(BDRVDMGState *s, DmgHeaderState *ds, 1977aee37b9SPeter Wu uint8_t *buffer, uint32_t count) 198019d6b8fSAnthony Liguori { 19965a1c7c9SPeter Wu uint32_t type, i; 20069d34a36SKevin Wolf int ret; 20165a1c7c9SPeter Wu size_t new_size; 20265a1c7c9SPeter Wu uint32_t chunk_count; 2037aee37b9SPeter Wu int64_t offset = 0; 204c6d34865SPeter Wu uint64_t data_offset; 205c6d34865SPeter Wu uint64_t in_offset = ds->data_fork_offset; 20666ec3bbaSPeter Wu uint64_t out_offset; 20716cdf7ceSChristoph Hellwig 2087aee37b9SPeter Wu type = buff_read_uint32(buffer, offset); 20965a1c7c9SPeter Wu /* skip data that is not a valid MISH block (invalid magic or too small) */ 21065a1c7c9SPeter Wu if (type != 0x6d697368 || count < 244) { 21165a1c7c9SPeter Wu /* assume success for now */ 21265a1c7c9SPeter Wu return 0; 21365a1c7c9SPeter Wu } 21416cdf7ceSChristoph Hellwig 21566ec3bbaSPeter Wu /* chunk offsets are relative to this sector number */ 21666ec3bbaSPeter Wu out_offset = buff_read_uint64(buffer, offset + 8); 21766ec3bbaSPeter Wu 218c6d34865SPeter Wu /* location in data fork for (compressed) blob (in bytes) */ 219c6d34865SPeter Wu data_offset = buff_read_uint64(buffer, offset + 0x18); 220c6d34865SPeter Wu in_offset += data_offset; 221c6d34865SPeter Wu 222c6d34865SPeter Wu /* move to begin of chunk entries */ 223c6d34865SPeter Wu offset += 204; 22416cdf7ceSChristoph Hellwig 225019d6b8fSAnthony Liguori chunk_count = (count - 204) / 40; 226019d6b8fSAnthony Liguori new_size = sizeof(uint64_t) * (s->n_chunks + chunk_count); 2277267c094SAnthony Liguori s->types = g_realloc(s->types, new_size / 2); 2287267c094SAnthony Liguori s->offsets = g_realloc(s->offsets, new_size); 2297267c094SAnthony Liguori s->lengths = g_realloc(s->lengths, new_size); 2307267c094SAnthony Liguori s->sectors = g_realloc(s->sectors, new_size); 2317267c094SAnthony Liguori s->sectorcounts = g_realloc(s->sectorcounts, new_size); 232019d6b8fSAnthony Liguori 233019d6b8fSAnthony Liguori for (i = s->n_chunks; i < s->n_chunks + chunk_count; i++) { 2347aee37b9SPeter Wu s->types[i] = buff_read_uint32(buffer, offset); 235a8b10c6eSPeter Wu if (!dmg_is_known_block_type(s->types[i])) { 236019d6b8fSAnthony Liguori chunk_count--; 237019d6b8fSAnthony Liguori i--; 238a8b10c6eSPeter Wu offset += 40; 239019d6b8fSAnthony Liguori continue; 240019d6b8fSAnthony Liguori } 24116cdf7ceSChristoph Hellwig 242a8b10c6eSPeter Wu /* sector number */ 243a8b10c6eSPeter Wu s->sectors[i] = buff_read_uint64(buffer, offset + 8); 24466ec3bbaSPeter Wu s->sectors[i] += out_offset; 24516cdf7ceSChristoph Hellwig 246a8b10c6eSPeter Wu /* sector count */ 247a8b10c6eSPeter Wu s->sectorcounts[i] = buff_read_uint64(buffer, offset + 0x10); 24816cdf7ceSChristoph Hellwig 249177b7510SPeter Wu /* all-zeroes sector (type 2) does not need to be "uncompressed" and can 250177b7510SPeter Wu * therefore be unbounded. */ 251177b7510SPeter Wu if (s->types[i] != 2 && s->sectorcounts[i] > DMG_SECTORCOUNTS_MAX) { 252521b2b5dSMax Reitz error_report("sector count %" PRIu64 " for chunk %" PRIu32 253521b2b5dSMax Reitz " is larger than max (%u)", 254c165f775SStefan Hajnoczi s->sectorcounts[i], i, DMG_SECTORCOUNTS_MAX); 255c165f775SStefan Hajnoczi ret = -EINVAL; 256c165f775SStefan Hajnoczi goto fail; 257c165f775SStefan Hajnoczi } 258c165f775SStefan Hajnoczi 259a8b10c6eSPeter Wu /* offset in (compressed) data fork */ 260a8b10c6eSPeter Wu s->offsets[i] = buff_read_uint64(buffer, offset + 0x18); 261c6d34865SPeter Wu s->offsets[i] += in_offset; 26216cdf7ceSChristoph Hellwig 263a8b10c6eSPeter Wu /* length in (compressed) data fork */ 264a8b10c6eSPeter Wu s->lengths[i] = buff_read_uint64(buffer, offset + 0x20); 26516cdf7ceSChristoph Hellwig 266c165f775SStefan Hajnoczi if (s->lengths[i] > DMG_LENGTHS_MAX) { 267521b2b5dSMax Reitz error_report("length %" PRIu64 " for chunk %" PRIu32 268521b2b5dSMax Reitz " is larger than max (%u)", 269c165f775SStefan Hajnoczi s->lengths[i], i, DMG_LENGTHS_MAX); 270c165f775SStefan Hajnoczi ret = -EINVAL; 271c165f775SStefan Hajnoczi goto fail; 272c165f775SStefan Hajnoczi } 273c165f775SStefan Hajnoczi 27465a1c7c9SPeter Wu update_max_chunk_size(s, i, &ds->max_compressed_size, 27565a1c7c9SPeter Wu &ds->max_sectors_per_chunk); 276a8b10c6eSPeter Wu offset += 40; 2772c1885adSStefan Hajnoczi } 278019d6b8fSAnthony Liguori s->n_chunks += chunk_count; 27965a1c7c9SPeter Wu return 0; 28065a1c7c9SPeter Wu 28165a1c7c9SPeter Wu fail: 28265a1c7c9SPeter Wu return ret; 283019d6b8fSAnthony Liguori } 28465a1c7c9SPeter Wu 285b0e8dc5dSPeter Wu static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds, 286b0e8dc5dSPeter Wu uint64_t info_begin, uint64_t info_length) 287b0e8dc5dSPeter Wu { 2887aee37b9SPeter Wu BDRVDMGState *s = bs->opaque; 289b0e8dc5dSPeter Wu int ret; 290b0e8dc5dSPeter Wu uint32_t count, rsrc_data_offset; 2917aee37b9SPeter Wu uint8_t *buffer = NULL; 292b0e8dc5dSPeter Wu uint64_t info_end; 293b0e8dc5dSPeter Wu uint64_t offset; 294b0e8dc5dSPeter Wu 295b0e8dc5dSPeter Wu /* read offset from begin of resource fork (info_begin) to resource data */ 296b0e8dc5dSPeter Wu ret = read_uint32(bs, info_begin, &rsrc_data_offset); 297b0e8dc5dSPeter Wu if (ret < 0) { 298b0e8dc5dSPeter Wu goto fail; 299b0e8dc5dSPeter Wu } else if (rsrc_data_offset > info_length) { 300b0e8dc5dSPeter Wu ret = -EINVAL; 301b0e8dc5dSPeter Wu goto fail; 302b0e8dc5dSPeter Wu } 303b0e8dc5dSPeter Wu 304b0e8dc5dSPeter Wu /* read length of resource data */ 305b0e8dc5dSPeter Wu ret = read_uint32(bs, info_begin + 8, &count); 306b0e8dc5dSPeter Wu if (ret < 0) { 307b0e8dc5dSPeter Wu goto fail; 308b0e8dc5dSPeter Wu } else if (count == 0 || rsrc_data_offset + count > info_length) { 309b0e8dc5dSPeter Wu ret = -EINVAL; 310b0e8dc5dSPeter Wu goto fail; 311b0e8dc5dSPeter Wu } 312b0e8dc5dSPeter Wu 313b0e8dc5dSPeter Wu /* begin of resource data (consisting of one or more resources) */ 314b0e8dc5dSPeter Wu offset = info_begin + rsrc_data_offset; 315b0e8dc5dSPeter Wu 316b0e8dc5dSPeter Wu /* end of resource data (there is possibly a following resource map 317b0e8dc5dSPeter Wu * which will be ignored). */ 318b0e8dc5dSPeter Wu info_end = offset + count; 319b0e8dc5dSPeter Wu 320b0e8dc5dSPeter Wu /* read offsets (mish blocks) from one or more resources in resource data */ 321b0e8dc5dSPeter Wu while (offset < info_end) { 322b0e8dc5dSPeter Wu /* size of following resource */ 323b0e8dc5dSPeter Wu ret = read_uint32(bs, offset, &count); 324b0e8dc5dSPeter Wu if (ret < 0) { 325b0e8dc5dSPeter Wu goto fail; 326f6e6652dSPeter Wu } else if (count == 0 || count > info_end - offset) { 327b0e8dc5dSPeter Wu ret = -EINVAL; 328b0e8dc5dSPeter Wu goto fail; 329b0e8dc5dSPeter Wu } 330b0e8dc5dSPeter Wu offset += 4; 331b0e8dc5dSPeter Wu 3327aee37b9SPeter Wu buffer = g_realloc(buffer, count); 333cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, offset, buffer, count); 3347aee37b9SPeter Wu if (ret < 0) { 3357aee37b9SPeter Wu goto fail; 3367aee37b9SPeter Wu } 3377aee37b9SPeter Wu 3387aee37b9SPeter Wu ret = dmg_read_mish_block(s, ds, buffer, count); 339b0e8dc5dSPeter Wu if (ret < 0) { 340b0e8dc5dSPeter Wu goto fail; 341b0e8dc5dSPeter Wu } 342b0e8dc5dSPeter Wu /* advance offset by size of resource */ 343b0e8dc5dSPeter Wu offset += count; 344b0e8dc5dSPeter Wu } 3457aee37b9SPeter Wu ret = 0; 346b0e8dc5dSPeter Wu 347b0e8dc5dSPeter Wu fail: 3487aee37b9SPeter Wu g_free(buffer); 349b0e8dc5dSPeter Wu return ret; 350b0e8dc5dSPeter Wu } 351b0e8dc5dSPeter Wu 3520599e56eSPeter Wu static int dmg_read_plist_xml(BlockDriverState *bs, DmgHeaderState *ds, 3530599e56eSPeter Wu uint64_t info_begin, uint64_t info_length) 3540599e56eSPeter Wu { 3550599e56eSPeter Wu BDRVDMGState *s = bs->opaque; 3560599e56eSPeter Wu int ret; 3570599e56eSPeter Wu uint8_t *buffer = NULL; 3580599e56eSPeter Wu char *data_begin, *data_end; 3590599e56eSPeter Wu 3600599e56eSPeter Wu /* Have at least some length to avoid NULL for g_malloc. Attempt to set a 3610599e56eSPeter Wu * safe upper cap on the data length. A test sample had a XML length of 3620599e56eSPeter Wu * about 1 MiB. */ 3630599e56eSPeter Wu if (info_length == 0 || info_length > 16 * 1024 * 1024) { 3640599e56eSPeter Wu ret = -EINVAL; 3650599e56eSPeter Wu goto fail; 3660599e56eSPeter Wu } 3670599e56eSPeter Wu 3680599e56eSPeter Wu buffer = g_malloc(info_length + 1); 3690599e56eSPeter Wu buffer[info_length] = '\0'; 370cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, info_begin, buffer, info_length); 3710599e56eSPeter Wu if (ret != info_length) { 3720599e56eSPeter Wu ret = -EINVAL; 3730599e56eSPeter Wu goto fail; 3740599e56eSPeter Wu } 3750599e56eSPeter Wu 3760599e56eSPeter Wu /* look for <data>...</data>. The data is 284 (0x11c) bytes after base64 3770599e56eSPeter Wu * decode. The actual data element has 431 (0x1af) bytes which includes tabs 3780599e56eSPeter Wu * and line feeds. */ 3790599e56eSPeter Wu data_end = (char *)buffer; 3800599e56eSPeter Wu while ((data_begin = strstr(data_end, "<data>")) != NULL) { 3810599e56eSPeter Wu guchar *mish; 3820599e56eSPeter Wu gsize out_len = 0; 3830599e56eSPeter Wu 3840599e56eSPeter Wu data_begin += 6; 3850599e56eSPeter Wu data_end = strstr(data_begin, "</data>"); 3860599e56eSPeter Wu /* malformed XML? */ 3870599e56eSPeter Wu if (data_end == NULL) { 3880599e56eSPeter Wu ret = -EINVAL; 3890599e56eSPeter Wu goto fail; 3900599e56eSPeter Wu } 3910599e56eSPeter Wu *data_end++ = '\0'; 3920599e56eSPeter Wu mish = g_base64_decode(data_begin, &out_len); 3930599e56eSPeter Wu ret = dmg_read_mish_block(s, ds, mish, (uint32_t)out_len); 3940599e56eSPeter Wu g_free(mish); 3950599e56eSPeter Wu if (ret < 0) { 3960599e56eSPeter Wu goto fail; 3970599e56eSPeter Wu } 3980599e56eSPeter Wu } 3990599e56eSPeter Wu ret = 0; 4000599e56eSPeter Wu 4010599e56eSPeter Wu fail: 4020599e56eSPeter Wu g_free(buffer); 4030599e56eSPeter Wu return ret; 4040599e56eSPeter Wu } 4050599e56eSPeter Wu 40665a1c7c9SPeter Wu static int dmg_open(BlockDriverState *bs, QDict *options, int flags, 40765a1c7c9SPeter Wu Error **errp) 40865a1c7c9SPeter Wu { 40965a1c7c9SPeter Wu BDRVDMGState *s = bs->opaque; 41065a1c7c9SPeter Wu DmgHeaderState ds; 411b0e8dc5dSPeter Wu uint64_t rsrc_fork_offset, rsrc_fork_length; 4120599e56eSPeter Wu uint64_t plist_xml_offset, plist_xml_length; 41365a1c7c9SPeter Wu int64_t offset; 41465a1c7c9SPeter Wu int ret; 41565a1c7c9SPeter Wu 4164e4bf5c4SKevin Wolf bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 4174e4bf5c4SKevin Wolf false, errp); 4184e4bf5c4SKevin Wolf if (!bs->file) { 4194e4bf5c4SKevin Wolf return -EINVAL; 4204e4bf5c4SKevin Wolf } 4214e4bf5c4SKevin Wolf 42227685a8dSFam Zheng block_module_load_one("dmg-bz2"); 42354115412SEric Blake bs->read_only = true; 4243edf1e73SKevin Wolf 42565a1c7c9SPeter Wu s->n_chunks = 0; 42665a1c7c9SPeter Wu s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; 42765a1c7c9SPeter Wu /* used by dmg_read_mish_block to keep track of the current I/O position */ 428c6d34865SPeter Wu ds.data_fork_offset = 0; 42965a1c7c9SPeter Wu ds.max_compressed_size = 1; 43065a1c7c9SPeter Wu ds.max_sectors_per_chunk = 1; 43165a1c7c9SPeter Wu 43265a1c7c9SPeter Wu /* locate the UDIF trailer */ 433cf2ab8fcSKevin Wolf offset = dmg_find_koly_offset(bs->file, errp); 43465a1c7c9SPeter Wu if (offset < 0) { 43565a1c7c9SPeter Wu ret = offset; 43665a1c7c9SPeter Wu goto fail; 43765a1c7c9SPeter Wu } 43865a1c7c9SPeter Wu 439c6d34865SPeter Wu /* offset of data fork (DataForkOffset) */ 440c6d34865SPeter Wu ret = read_uint64(bs, offset + 0x18, &ds.data_fork_offset); 441c6d34865SPeter Wu if (ret < 0) { 442c6d34865SPeter Wu goto fail; 443c6d34865SPeter Wu } else if (ds.data_fork_offset > offset) { 444c6d34865SPeter Wu ret = -EINVAL; 445c6d34865SPeter Wu goto fail; 446c6d34865SPeter Wu } 447c6d34865SPeter Wu 448b0e8dc5dSPeter Wu /* offset of resource fork (RsrcForkOffset) */ 449b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset); 45065a1c7c9SPeter Wu if (ret < 0) { 45165a1c7c9SPeter Wu goto fail; 452b0e8dc5dSPeter Wu } 453b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length); 454b0e8dc5dSPeter Wu if (ret < 0) { 455b0e8dc5dSPeter Wu goto fail; 456b0e8dc5dSPeter Wu } 457f6e6652dSPeter Wu if (rsrc_fork_offset >= offset || 458f6e6652dSPeter Wu rsrc_fork_length > offset - rsrc_fork_offset) { 459f6e6652dSPeter Wu ret = -EINVAL; 460f6e6652dSPeter Wu goto fail; 461f6e6652dSPeter Wu } 4620599e56eSPeter Wu /* offset of property list (XMLOffset) */ 4630599e56eSPeter Wu ret = read_uint64(bs, offset + 0xd8, &plist_xml_offset); 4640599e56eSPeter Wu if (ret < 0) { 4650599e56eSPeter Wu goto fail; 4660599e56eSPeter Wu } 4670599e56eSPeter Wu ret = read_uint64(bs, offset + 0xe0, &plist_xml_length); 4680599e56eSPeter Wu if (ret < 0) { 4690599e56eSPeter Wu goto fail; 4700599e56eSPeter Wu } 4710599e56eSPeter Wu if (plist_xml_offset >= offset || 4720599e56eSPeter Wu plist_xml_length > offset - plist_xml_offset) { 4730599e56eSPeter Wu ret = -EINVAL; 4740599e56eSPeter Wu goto fail; 4750599e56eSPeter Wu } 4768daf4257SPeter Wu ret = read_uint64(bs, offset + 0x1ec, (uint64_t *)&bs->total_sectors); 4778daf4257SPeter Wu if (ret < 0) { 4788daf4257SPeter Wu goto fail; 4798daf4257SPeter Wu } 4808daf4257SPeter Wu if (bs->total_sectors < 0) { 4818daf4257SPeter Wu ret = -EINVAL; 4828daf4257SPeter Wu goto fail; 4838daf4257SPeter Wu } 484b0e8dc5dSPeter Wu if (rsrc_fork_length != 0) { 485b0e8dc5dSPeter Wu ret = dmg_read_resource_fork(bs, &ds, 486b0e8dc5dSPeter Wu rsrc_fork_offset, rsrc_fork_length); 487b0e8dc5dSPeter Wu if (ret < 0) { 488b0e8dc5dSPeter Wu goto fail; 489b0e8dc5dSPeter Wu } 4900599e56eSPeter Wu } else if (plist_xml_length != 0) { 4910599e56eSPeter Wu ret = dmg_read_plist_xml(bs, &ds, plist_xml_offset, plist_xml_length); 4920599e56eSPeter Wu if (ret < 0) { 4930599e56eSPeter Wu goto fail; 4940599e56eSPeter Wu } 495b0e8dc5dSPeter Wu } else { 49665a1c7c9SPeter Wu ret = -EINVAL; 49765a1c7c9SPeter Wu goto fail; 49865a1c7c9SPeter Wu } 49965a1c7c9SPeter Wu 500019d6b8fSAnthony Liguori /* initialize zlib engine */ 5019a4f4c31SKevin Wolf s->compressed_chunk = qemu_try_blockalign(bs->file->bs, 50265a1c7c9SPeter Wu ds.max_compressed_size + 1); 5039a4f4c31SKevin Wolf s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs, 50465a1c7c9SPeter Wu 512 * ds.max_sectors_per_chunk); 505b546a944SKevin Wolf if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { 506b546a944SKevin Wolf ret = -ENOMEM; 507b546a944SKevin Wolf goto fail; 508b546a944SKevin Wolf } 509b546a944SKevin Wolf 51069d34a36SKevin Wolf if (inflateInit(&s->zstream) != Z_OK) { 51169d34a36SKevin Wolf ret = -EINVAL; 5121559ca00SChristoph Hellwig goto fail; 51369d34a36SKevin Wolf } 514019d6b8fSAnthony Liguori 515019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 516019d6b8fSAnthony Liguori 517848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 518019d6b8fSAnthony Liguori return 0; 51969d34a36SKevin Wolf 5201559ca00SChristoph Hellwig fail: 52169d34a36SKevin Wolf g_free(s->types); 52269d34a36SKevin Wolf g_free(s->offsets); 52369d34a36SKevin Wolf g_free(s->lengths); 52469d34a36SKevin Wolf g_free(s->sectors); 52569d34a36SKevin Wolf g_free(s->sectorcounts); 526b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 527b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 52869d34a36SKevin Wolf return ret; 529019d6b8fSAnthony Liguori } 530019d6b8fSAnthony Liguori 531a6506481SEric Blake static void dmg_refresh_limits(BlockDriverState *bs, Error **errp) 532a6506481SEric Blake { 533a5b8dd2cSEric Blake bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */ 534a6506481SEric Blake } 535a6506481SEric Blake 536019d6b8fSAnthony Liguori static inline int is_sector_in_chunk(BDRVDMGState* s, 537686d7148SStefan Hajnoczi uint32_t chunk_num, uint64_t sector_num) 538019d6b8fSAnthony Liguori { 539019d6b8fSAnthony Liguori if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num || 5402c1885adSStefan Hajnoczi s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) { 541019d6b8fSAnthony Liguori return 0; 5422c1885adSStefan Hajnoczi } else { 543019d6b8fSAnthony Liguori return -1; 544019d6b8fSAnthony Liguori } 5452c1885adSStefan Hajnoczi } 546019d6b8fSAnthony Liguori 547686d7148SStefan Hajnoczi static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num) 548019d6b8fSAnthony Liguori { 549019d6b8fSAnthony Liguori /* binary search */ 550019d6b8fSAnthony Liguori uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3; 551019d6b8fSAnthony Liguori while (chunk1 != chunk2) { 552019d6b8fSAnthony Liguori chunk3 = (chunk1 + chunk2) / 2; 5532c1885adSStefan Hajnoczi if (s->sectors[chunk3] > sector_num) { 554019d6b8fSAnthony Liguori chunk2 = chunk3; 5552c1885adSStefan Hajnoczi } else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) { 556019d6b8fSAnthony Liguori return chunk3; 5572c1885adSStefan Hajnoczi } else { 558019d6b8fSAnthony Liguori chunk1 = chunk3; 559019d6b8fSAnthony Liguori } 5602c1885adSStefan Hajnoczi } 561019d6b8fSAnthony Liguori return s->n_chunks; /* error */ 562019d6b8fSAnthony Liguori } 563019d6b8fSAnthony Liguori 564686d7148SStefan Hajnoczi static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) 565019d6b8fSAnthony Liguori { 56664a31d5cSChristoph Hellwig BDRVDMGState *s = bs->opaque; 56764a31d5cSChristoph Hellwig 568019d6b8fSAnthony Liguori if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) { 569019d6b8fSAnthony Liguori int ret; 570019d6b8fSAnthony Liguori uint32_t chunk = search_chunk(s, sector_num); 571019d6b8fSAnthony Liguori 5722c1885adSStefan Hajnoczi if (chunk >= s->n_chunks) { 573019d6b8fSAnthony Liguori return -1; 5742c1885adSStefan Hajnoczi } 575019d6b8fSAnthony Liguori 576019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 5776b383c08SPeter Wu switch (s->types[chunk]) { /* block entry type */ 578019d6b8fSAnthony Liguori case 0x80000005: { /* zlib compressed */ 579019d6b8fSAnthony Liguori /* we need to buffer, because only the chunk as whole can be 580019d6b8fSAnthony Liguori * inflated. */ 581cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 582b404bf85SStefan Hajnoczi s->compressed_chunk, s->lengths[chunk]); 5832c1885adSStefan Hajnoczi if (ret != s->lengths[chunk]) { 584019d6b8fSAnthony Liguori return -1; 5852c1885adSStefan Hajnoczi } 586019d6b8fSAnthony Liguori 587019d6b8fSAnthony Liguori s->zstream.next_in = s->compressed_chunk; 588019d6b8fSAnthony Liguori s->zstream.avail_in = s->lengths[chunk]; 589019d6b8fSAnthony Liguori s->zstream.next_out = s->uncompressed_chunk; 590019d6b8fSAnthony Liguori s->zstream.avail_out = 512 * s->sectorcounts[chunk]; 591019d6b8fSAnthony Liguori ret = inflateReset(&s->zstream); 5922c1885adSStefan Hajnoczi if (ret != Z_OK) { 593019d6b8fSAnthony Liguori return -1; 5942c1885adSStefan Hajnoczi } 595019d6b8fSAnthony Liguori ret = inflate(&s->zstream, Z_FINISH); 5962c1885adSStefan Hajnoczi if (ret != Z_STREAM_END || 5972c1885adSStefan Hajnoczi s->zstream.total_out != 512 * s->sectorcounts[chunk]) { 598019d6b8fSAnthony Liguori return -1; 5992c1885adSStefan Hajnoczi } 600019d6b8fSAnthony Liguori break; } 6016b383c08SPeter Wu case 0x80000006: /* bzip2 compressed */ 60227685a8dSFam Zheng if (!dmg_uncompress_bz2) { 60327685a8dSFam Zheng break; 60427685a8dSFam Zheng } 6056b383c08SPeter Wu /* we need to buffer, because only the chunk as whole can be 6066b383c08SPeter Wu * inflated. */ 607cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 6086b383c08SPeter Wu s->compressed_chunk, s->lengths[chunk]); 6096b383c08SPeter Wu if (ret != s->lengths[chunk]) { 6106b383c08SPeter Wu return -1; 6116b383c08SPeter Wu } 6126b383c08SPeter Wu 61327685a8dSFam Zheng ret = dmg_uncompress_bz2((char *)s->compressed_chunk, 61427685a8dSFam Zheng (unsigned int) s->lengths[chunk], 61527685a8dSFam Zheng (char *)s->uncompressed_chunk, 61627685a8dSFam Zheng (unsigned int) 61727685a8dSFam Zheng (512 * s->sectorcounts[chunk])); 61827685a8dSFam Zheng if (ret < 0) { 61927685a8dSFam Zheng return ret; 6206b383c08SPeter Wu } 6216b383c08SPeter Wu break; 622019d6b8fSAnthony Liguori case 1: /* copy */ 623cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 62464a31d5cSChristoph Hellwig s->uncompressed_chunk, s->lengths[chunk]); 6252c1885adSStefan Hajnoczi if (ret != s->lengths[chunk]) { 626019d6b8fSAnthony Liguori return -1; 6272c1885adSStefan Hajnoczi } 628019d6b8fSAnthony Liguori break; 629019d6b8fSAnthony Liguori case 2: /* zero */ 630177b7510SPeter Wu /* see dmg_read, it is treated specially. No buffer needs to be 631177b7510SPeter Wu * pre-filled, the zeroes can be set directly. */ 632019d6b8fSAnthony Liguori break; 633019d6b8fSAnthony Liguori } 634019d6b8fSAnthony Liguori s->current_chunk = chunk; 635019d6b8fSAnthony Liguori } 636019d6b8fSAnthony Liguori return 0; 637019d6b8fSAnthony Liguori } 638019d6b8fSAnthony Liguori 6393edf1e73SKevin Wolf static int coroutine_fn 6403edf1e73SKevin Wolf dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 6413edf1e73SKevin Wolf QEMUIOVector *qiov, int flags) 642019d6b8fSAnthony Liguori { 643019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 6443edf1e73SKevin Wolf uint64_t sector_num = offset >> BDRV_SECTOR_BITS; 6453edf1e73SKevin Wolf int nb_sectors = bytes >> BDRV_SECTOR_BITS; 6463edf1e73SKevin Wolf int ret, i; 6473edf1e73SKevin Wolf 6483edf1e73SKevin Wolf assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); 6493edf1e73SKevin Wolf assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); 6503edf1e73SKevin Wolf 6513edf1e73SKevin Wolf qemu_co_mutex_lock(&s->lock); 652019d6b8fSAnthony Liguori 653019d6b8fSAnthony Liguori for (i = 0; i < nb_sectors; i++) { 654019d6b8fSAnthony Liguori uint32_t sector_offset_in_chunk; 6553edf1e73SKevin Wolf void *data; 6563edf1e73SKevin Wolf 6572c1885adSStefan Hajnoczi if (dmg_read_chunk(bs, sector_num + i) != 0) { 6583edf1e73SKevin Wolf ret = -EIO; 6593edf1e73SKevin Wolf goto fail; 6602c1885adSStefan Hajnoczi } 661177b7510SPeter Wu /* Special case: current chunk is all zeroes. Do not perform a memcpy as 662177b7510SPeter Wu * s->uncompressed_chunk may be too small to cover the large all-zeroes 663177b7510SPeter Wu * section. dmg_read_chunk is called to find s->current_chunk */ 664177b7510SPeter Wu if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */ 6653edf1e73SKevin Wolf qemu_iovec_memset(qiov, i * 512, 0, 512); 666177b7510SPeter Wu continue; 667177b7510SPeter Wu } 668019d6b8fSAnthony Liguori sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk]; 6693edf1e73SKevin Wolf data = s->uncompressed_chunk + sector_offset_in_chunk * 512; 6703edf1e73SKevin Wolf qemu_iovec_from_buf(qiov, i * 512, data, 512); 671019d6b8fSAnthony Liguori } 672019d6b8fSAnthony Liguori 6733edf1e73SKevin Wolf ret = 0; 6743edf1e73SKevin Wolf fail: 6752914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 6762914caa0SPaolo Bonzini return ret; 6772914caa0SPaolo Bonzini } 6782914caa0SPaolo Bonzini 679019d6b8fSAnthony Liguori static void dmg_close(BlockDriverState *bs) 680019d6b8fSAnthony Liguori { 681019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 6824f8aa2e1SKevin Wolf 6834f8aa2e1SKevin Wolf g_free(s->types); 6844f8aa2e1SKevin Wolf g_free(s->offsets); 6854f8aa2e1SKevin Wolf g_free(s->lengths); 6864f8aa2e1SKevin Wolf g_free(s->sectors); 6874f8aa2e1SKevin Wolf g_free(s->sectorcounts); 688b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 689b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 6904f8aa2e1SKevin Wolf 691019d6b8fSAnthony Liguori inflateEnd(&s->zstream); 692019d6b8fSAnthony Liguori } 693019d6b8fSAnthony Liguori 694019d6b8fSAnthony Liguori static BlockDriver bdrv_dmg = { 695019d6b8fSAnthony Liguori .format_name = "dmg", 696019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVDMGState), 697019d6b8fSAnthony Liguori .bdrv_probe = dmg_probe, 69864a31d5cSChristoph Hellwig .bdrv_open = dmg_open, 699a6506481SEric Blake .bdrv_refresh_limits = dmg_refresh_limits, 700*862f215fSKevin Wolf .bdrv_child_perm = bdrv_format_default_perms, 7013edf1e73SKevin Wolf .bdrv_co_preadv = dmg_co_preadv, 702019d6b8fSAnthony Liguori .bdrv_close = dmg_close, 703019d6b8fSAnthony Liguori }; 704019d6b8fSAnthony Liguori 705019d6b8fSAnthony Liguori static void bdrv_dmg_init(void) 706019d6b8fSAnthony Liguori { 707019d6b8fSAnthony Liguori bdrv_register(&bdrv_dmg); 708019d6b8fSAnthony Liguori } 709019d6b8fSAnthony Liguori 710019d6b8fSAnthony Liguori block_init(bdrv_dmg_init); 711