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 */ 114*6fb0022bSMarc-André Lureau uncompressed_sectors = DIV_ROUND_UP(s->lengths[chunk], 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 422e2b8247aSJeff Cody ret = bdrv_set_read_only(bs, true, errp); 423e2b8247aSJeff Cody if (ret < 0) { 424e2b8247aSJeff Cody return ret; 425e2b8247aSJeff Cody } 426e2b8247aSJeff Cody 42727685a8dSFam Zheng block_module_load_one("dmg-bz2"); 4283edf1e73SKevin Wolf 42965a1c7c9SPeter Wu s->n_chunks = 0; 43065a1c7c9SPeter Wu s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL; 43165a1c7c9SPeter Wu /* used by dmg_read_mish_block to keep track of the current I/O position */ 432c6d34865SPeter Wu ds.data_fork_offset = 0; 43365a1c7c9SPeter Wu ds.max_compressed_size = 1; 43465a1c7c9SPeter Wu ds.max_sectors_per_chunk = 1; 43565a1c7c9SPeter Wu 43665a1c7c9SPeter Wu /* locate the UDIF trailer */ 437cf2ab8fcSKevin Wolf offset = dmg_find_koly_offset(bs->file, errp); 43865a1c7c9SPeter Wu if (offset < 0) { 43965a1c7c9SPeter Wu ret = offset; 44065a1c7c9SPeter Wu goto fail; 44165a1c7c9SPeter Wu } 44265a1c7c9SPeter Wu 443c6d34865SPeter Wu /* offset of data fork (DataForkOffset) */ 444c6d34865SPeter Wu ret = read_uint64(bs, offset + 0x18, &ds.data_fork_offset); 445c6d34865SPeter Wu if (ret < 0) { 446c6d34865SPeter Wu goto fail; 447c6d34865SPeter Wu } else if (ds.data_fork_offset > offset) { 448c6d34865SPeter Wu ret = -EINVAL; 449c6d34865SPeter Wu goto fail; 450c6d34865SPeter Wu } 451c6d34865SPeter Wu 452b0e8dc5dSPeter Wu /* offset of resource fork (RsrcForkOffset) */ 453b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset); 45465a1c7c9SPeter Wu if (ret < 0) { 45565a1c7c9SPeter Wu goto fail; 456b0e8dc5dSPeter Wu } 457b0e8dc5dSPeter Wu ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length); 458b0e8dc5dSPeter Wu if (ret < 0) { 459b0e8dc5dSPeter Wu goto fail; 460b0e8dc5dSPeter Wu } 461f6e6652dSPeter Wu if (rsrc_fork_offset >= offset || 462f6e6652dSPeter Wu rsrc_fork_length > offset - rsrc_fork_offset) { 463f6e6652dSPeter Wu ret = -EINVAL; 464f6e6652dSPeter Wu goto fail; 465f6e6652dSPeter Wu } 4660599e56eSPeter Wu /* offset of property list (XMLOffset) */ 4670599e56eSPeter Wu ret = read_uint64(bs, offset + 0xd8, &plist_xml_offset); 4680599e56eSPeter Wu if (ret < 0) { 4690599e56eSPeter Wu goto fail; 4700599e56eSPeter Wu } 4710599e56eSPeter Wu ret = read_uint64(bs, offset + 0xe0, &plist_xml_length); 4720599e56eSPeter Wu if (ret < 0) { 4730599e56eSPeter Wu goto fail; 4740599e56eSPeter Wu } 4750599e56eSPeter Wu if (plist_xml_offset >= offset || 4760599e56eSPeter Wu plist_xml_length > offset - plist_xml_offset) { 4770599e56eSPeter Wu ret = -EINVAL; 4780599e56eSPeter Wu goto fail; 4790599e56eSPeter Wu } 4808daf4257SPeter Wu ret = read_uint64(bs, offset + 0x1ec, (uint64_t *)&bs->total_sectors); 4818daf4257SPeter Wu if (ret < 0) { 4828daf4257SPeter Wu goto fail; 4838daf4257SPeter Wu } 4848daf4257SPeter Wu if (bs->total_sectors < 0) { 4858daf4257SPeter Wu ret = -EINVAL; 4868daf4257SPeter Wu goto fail; 4878daf4257SPeter Wu } 488b0e8dc5dSPeter Wu if (rsrc_fork_length != 0) { 489b0e8dc5dSPeter Wu ret = dmg_read_resource_fork(bs, &ds, 490b0e8dc5dSPeter Wu rsrc_fork_offset, rsrc_fork_length); 491b0e8dc5dSPeter Wu if (ret < 0) { 492b0e8dc5dSPeter Wu goto fail; 493b0e8dc5dSPeter Wu } 4940599e56eSPeter Wu } else if (plist_xml_length != 0) { 4950599e56eSPeter Wu ret = dmg_read_plist_xml(bs, &ds, plist_xml_offset, plist_xml_length); 4960599e56eSPeter Wu if (ret < 0) { 4970599e56eSPeter Wu goto fail; 4980599e56eSPeter Wu } 499b0e8dc5dSPeter Wu } else { 50065a1c7c9SPeter Wu ret = -EINVAL; 50165a1c7c9SPeter Wu goto fail; 50265a1c7c9SPeter Wu } 50365a1c7c9SPeter Wu 504019d6b8fSAnthony Liguori /* initialize zlib engine */ 5059a4f4c31SKevin Wolf s->compressed_chunk = qemu_try_blockalign(bs->file->bs, 50665a1c7c9SPeter Wu ds.max_compressed_size + 1); 5079a4f4c31SKevin Wolf s->uncompressed_chunk = qemu_try_blockalign(bs->file->bs, 50865a1c7c9SPeter Wu 512 * ds.max_sectors_per_chunk); 509b546a944SKevin Wolf if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) { 510b546a944SKevin Wolf ret = -ENOMEM; 511b546a944SKevin Wolf goto fail; 512b546a944SKevin Wolf } 513b546a944SKevin Wolf 51469d34a36SKevin Wolf if (inflateInit(&s->zstream) != Z_OK) { 51569d34a36SKevin Wolf ret = -EINVAL; 5161559ca00SChristoph Hellwig goto fail; 51769d34a36SKevin Wolf } 518019d6b8fSAnthony Liguori 519019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 520019d6b8fSAnthony Liguori 521848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 522019d6b8fSAnthony Liguori return 0; 52369d34a36SKevin Wolf 5241559ca00SChristoph Hellwig fail: 52569d34a36SKevin Wolf g_free(s->types); 52669d34a36SKevin Wolf g_free(s->offsets); 52769d34a36SKevin Wolf g_free(s->lengths); 52869d34a36SKevin Wolf g_free(s->sectors); 52969d34a36SKevin Wolf g_free(s->sectorcounts); 530b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 531b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 53269d34a36SKevin Wolf return ret; 533019d6b8fSAnthony Liguori } 534019d6b8fSAnthony Liguori 535a6506481SEric Blake static void dmg_refresh_limits(BlockDriverState *bs, Error **errp) 536a6506481SEric Blake { 537a5b8dd2cSEric Blake bs->bl.request_alignment = BDRV_SECTOR_SIZE; /* No sub-sector I/O */ 538a6506481SEric Blake } 539a6506481SEric Blake 540019d6b8fSAnthony Liguori static inline int is_sector_in_chunk(BDRVDMGState* s, 541686d7148SStefan Hajnoczi uint32_t chunk_num, uint64_t sector_num) 542019d6b8fSAnthony Liguori { 543019d6b8fSAnthony Liguori if (chunk_num >= s->n_chunks || s->sectors[chunk_num] > sector_num || 5442c1885adSStefan Hajnoczi s->sectors[chunk_num] + s->sectorcounts[chunk_num] <= sector_num) { 545019d6b8fSAnthony Liguori return 0; 5462c1885adSStefan Hajnoczi } else { 547019d6b8fSAnthony Liguori return -1; 548019d6b8fSAnthony Liguori } 5492c1885adSStefan Hajnoczi } 550019d6b8fSAnthony Liguori 551686d7148SStefan Hajnoczi static inline uint32_t search_chunk(BDRVDMGState *s, uint64_t sector_num) 552019d6b8fSAnthony Liguori { 553019d6b8fSAnthony Liguori /* binary search */ 554019d6b8fSAnthony Liguori uint32_t chunk1 = 0, chunk2 = s->n_chunks, chunk3; 555019d6b8fSAnthony Liguori while (chunk1 != chunk2) { 556019d6b8fSAnthony Liguori chunk3 = (chunk1 + chunk2) / 2; 5572c1885adSStefan Hajnoczi if (s->sectors[chunk3] > sector_num) { 558019d6b8fSAnthony Liguori chunk2 = chunk3; 5592c1885adSStefan Hajnoczi } else if (s->sectors[chunk3] + s->sectorcounts[chunk3] > sector_num) { 560019d6b8fSAnthony Liguori return chunk3; 5612c1885adSStefan Hajnoczi } else { 562019d6b8fSAnthony Liguori chunk1 = chunk3; 563019d6b8fSAnthony Liguori } 5642c1885adSStefan Hajnoczi } 565019d6b8fSAnthony Liguori return s->n_chunks; /* error */ 566019d6b8fSAnthony Liguori } 567019d6b8fSAnthony Liguori 568686d7148SStefan Hajnoczi static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num) 569019d6b8fSAnthony Liguori { 57064a31d5cSChristoph Hellwig BDRVDMGState *s = bs->opaque; 57164a31d5cSChristoph Hellwig 572019d6b8fSAnthony Liguori if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) { 573019d6b8fSAnthony Liguori int ret; 574019d6b8fSAnthony Liguori uint32_t chunk = search_chunk(s, sector_num); 575019d6b8fSAnthony Liguori 5762c1885adSStefan Hajnoczi if (chunk >= s->n_chunks) { 577019d6b8fSAnthony Liguori return -1; 5782c1885adSStefan Hajnoczi } 579019d6b8fSAnthony Liguori 580019d6b8fSAnthony Liguori s->current_chunk = s->n_chunks; 5816b383c08SPeter Wu switch (s->types[chunk]) { /* block entry type */ 582019d6b8fSAnthony Liguori case 0x80000005: { /* zlib compressed */ 583019d6b8fSAnthony Liguori /* we need to buffer, because only the chunk as whole can be 584019d6b8fSAnthony Liguori * inflated. */ 585cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 586b404bf85SStefan Hajnoczi s->compressed_chunk, s->lengths[chunk]); 5872c1885adSStefan Hajnoczi if (ret != s->lengths[chunk]) { 588019d6b8fSAnthony Liguori return -1; 5892c1885adSStefan Hajnoczi } 590019d6b8fSAnthony Liguori 591019d6b8fSAnthony Liguori s->zstream.next_in = s->compressed_chunk; 592019d6b8fSAnthony Liguori s->zstream.avail_in = s->lengths[chunk]; 593019d6b8fSAnthony Liguori s->zstream.next_out = s->uncompressed_chunk; 594019d6b8fSAnthony Liguori s->zstream.avail_out = 512 * s->sectorcounts[chunk]; 595019d6b8fSAnthony Liguori ret = inflateReset(&s->zstream); 5962c1885adSStefan Hajnoczi if (ret != Z_OK) { 597019d6b8fSAnthony Liguori return -1; 5982c1885adSStefan Hajnoczi } 599019d6b8fSAnthony Liguori ret = inflate(&s->zstream, Z_FINISH); 6002c1885adSStefan Hajnoczi if (ret != Z_STREAM_END || 6012c1885adSStefan Hajnoczi s->zstream.total_out != 512 * s->sectorcounts[chunk]) { 602019d6b8fSAnthony Liguori return -1; 6032c1885adSStefan Hajnoczi } 604019d6b8fSAnthony Liguori break; } 6056b383c08SPeter Wu case 0x80000006: /* bzip2 compressed */ 60627685a8dSFam Zheng if (!dmg_uncompress_bz2) { 60727685a8dSFam Zheng break; 60827685a8dSFam Zheng } 6096b383c08SPeter Wu /* we need to buffer, because only the chunk as whole can be 6106b383c08SPeter Wu * inflated. */ 611cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 6126b383c08SPeter Wu s->compressed_chunk, s->lengths[chunk]); 6136b383c08SPeter Wu if (ret != s->lengths[chunk]) { 6146b383c08SPeter Wu return -1; 6156b383c08SPeter Wu } 6166b383c08SPeter Wu 61727685a8dSFam Zheng ret = dmg_uncompress_bz2((char *)s->compressed_chunk, 61827685a8dSFam Zheng (unsigned int) s->lengths[chunk], 61927685a8dSFam Zheng (char *)s->uncompressed_chunk, 62027685a8dSFam Zheng (unsigned int) 62127685a8dSFam Zheng (512 * s->sectorcounts[chunk])); 62227685a8dSFam Zheng if (ret < 0) { 62327685a8dSFam Zheng return ret; 6246b383c08SPeter Wu } 6256b383c08SPeter Wu break; 626019d6b8fSAnthony Liguori case 1: /* copy */ 627cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->offsets[chunk], 62864a31d5cSChristoph Hellwig s->uncompressed_chunk, s->lengths[chunk]); 6292c1885adSStefan Hajnoczi if (ret != s->lengths[chunk]) { 630019d6b8fSAnthony Liguori return -1; 6312c1885adSStefan Hajnoczi } 632019d6b8fSAnthony Liguori break; 633019d6b8fSAnthony Liguori case 2: /* zero */ 634177b7510SPeter Wu /* see dmg_read, it is treated specially. No buffer needs to be 635177b7510SPeter Wu * pre-filled, the zeroes can be set directly. */ 636019d6b8fSAnthony Liguori break; 637019d6b8fSAnthony Liguori } 638019d6b8fSAnthony Liguori s->current_chunk = chunk; 639019d6b8fSAnthony Liguori } 640019d6b8fSAnthony Liguori return 0; 641019d6b8fSAnthony Liguori } 642019d6b8fSAnthony Liguori 6433edf1e73SKevin Wolf static int coroutine_fn 6443edf1e73SKevin Wolf dmg_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 6453edf1e73SKevin Wolf QEMUIOVector *qiov, int flags) 646019d6b8fSAnthony Liguori { 647019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 6483edf1e73SKevin Wolf uint64_t sector_num = offset >> BDRV_SECTOR_BITS; 6493edf1e73SKevin Wolf int nb_sectors = bytes >> BDRV_SECTOR_BITS; 6503edf1e73SKevin Wolf int ret, i; 6513edf1e73SKevin Wolf 6523edf1e73SKevin Wolf assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0); 6533edf1e73SKevin Wolf assert((bytes & (BDRV_SECTOR_SIZE - 1)) == 0); 6543edf1e73SKevin Wolf 6553edf1e73SKevin Wolf qemu_co_mutex_lock(&s->lock); 656019d6b8fSAnthony Liguori 657019d6b8fSAnthony Liguori for (i = 0; i < nb_sectors; i++) { 658019d6b8fSAnthony Liguori uint32_t sector_offset_in_chunk; 6593edf1e73SKevin Wolf void *data; 6603edf1e73SKevin Wolf 6612c1885adSStefan Hajnoczi if (dmg_read_chunk(bs, sector_num + i) != 0) { 6623edf1e73SKevin Wolf ret = -EIO; 6633edf1e73SKevin Wolf goto fail; 6642c1885adSStefan Hajnoczi } 665177b7510SPeter Wu /* Special case: current chunk is all zeroes. Do not perform a memcpy as 666177b7510SPeter Wu * s->uncompressed_chunk may be too small to cover the large all-zeroes 667177b7510SPeter Wu * section. dmg_read_chunk is called to find s->current_chunk */ 668177b7510SPeter Wu if (s->types[s->current_chunk] == 2) { /* all zeroes block entry */ 6693edf1e73SKevin Wolf qemu_iovec_memset(qiov, i * 512, 0, 512); 670177b7510SPeter Wu continue; 671177b7510SPeter Wu } 672019d6b8fSAnthony Liguori sector_offset_in_chunk = sector_num + i - s->sectors[s->current_chunk]; 6733edf1e73SKevin Wolf data = s->uncompressed_chunk + sector_offset_in_chunk * 512; 6743edf1e73SKevin Wolf qemu_iovec_from_buf(qiov, i * 512, data, 512); 675019d6b8fSAnthony Liguori } 676019d6b8fSAnthony Liguori 6773edf1e73SKevin Wolf ret = 0; 6783edf1e73SKevin Wolf fail: 6792914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 6802914caa0SPaolo Bonzini return ret; 6812914caa0SPaolo Bonzini } 6822914caa0SPaolo Bonzini 683019d6b8fSAnthony Liguori static void dmg_close(BlockDriverState *bs) 684019d6b8fSAnthony Liguori { 685019d6b8fSAnthony Liguori BDRVDMGState *s = bs->opaque; 6864f8aa2e1SKevin Wolf 6874f8aa2e1SKevin Wolf g_free(s->types); 6884f8aa2e1SKevin Wolf g_free(s->offsets); 6894f8aa2e1SKevin Wolf g_free(s->lengths); 6904f8aa2e1SKevin Wolf g_free(s->sectors); 6914f8aa2e1SKevin Wolf g_free(s->sectorcounts); 692b546a944SKevin Wolf qemu_vfree(s->compressed_chunk); 693b546a944SKevin Wolf qemu_vfree(s->uncompressed_chunk); 6944f8aa2e1SKevin Wolf 695019d6b8fSAnthony Liguori inflateEnd(&s->zstream); 696019d6b8fSAnthony Liguori } 697019d6b8fSAnthony Liguori 698019d6b8fSAnthony Liguori static BlockDriver bdrv_dmg = { 699019d6b8fSAnthony Liguori .format_name = "dmg", 700019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVDMGState), 701019d6b8fSAnthony Liguori .bdrv_probe = dmg_probe, 70264a31d5cSChristoph Hellwig .bdrv_open = dmg_open, 703a6506481SEric Blake .bdrv_refresh_limits = dmg_refresh_limits, 704862f215fSKevin Wolf .bdrv_child_perm = bdrv_format_default_perms, 7053edf1e73SKevin Wolf .bdrv_co_preadv = dmg_co_preadv, 706019d6b8fSAnthony Liguori .bdrv_close = dmg_close, 707019d6b8fSAnthony Liguori }; 708019d6b8fSAnthony Liguori 709019d6b8fSAnthony Liguori static void bdrv_dmg_init(void) 710019d6b8fSAnthony Liguori { 711019d6b8fSAnthony Liguori bdrv_register(&bdrv_dmg); 712019d6b8fSAnthony Liguori } 713019d6b8fSAnthony Liguori 714019d6b8fSAnthony Liguori block_init(bdrv_dmg_init); 715