summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block/dmg.c104
1 files changed, 66 insertions, 38 deletions
diff --git a/block/dmg.c b/block/dmg.c
index c571ac9121..04bae729a4 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -285,60 +285,38 @@ fail:
return ret;
}
-static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
- Error **errp)
+static int dmg_read_resource_fork(BlockDriverState *bs, DmgHeaderState *ds,
+ uint64_t info_begin, uint64_t info_length)
{
- BDRVDMGState *s = bs->opaque;
- DmgHeaderState ds;
- uint64_t info_begin, info_end;
- uint32_t count, rsrc_data_offset;
- int64_t offset;
int ret;
+ uint32_t count, rsrc_data_offset;
+ uint64_t info_end;
+ uint64_t offset;
- bs->read_only = 1;
- s->n_chunks = 0;
- s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
- /* used by dmg_read_mish_block to keep track of the current I/O position */
- ds.last_in_offset = 0;
- ds.last_out_offset = 0;
- ds.max_compressed_size = 1;
- ds.max_sectors_per_chunk = 1;
-
- /* locate the UDIF trailer */
- offset = dmg_find_koly_offset(bs->file, errp);
- if (offset < 0) {
- ret = offset;
- goto fail;
- }
-
- ret = read_uint64(bs, offset + 0x28, &info_begin);
- if (ret < 0) {
- goto fail;
- } else if (info_begin == 0) {
- ret = -EINVAL;
- goto fail;
- }
-
+ /* read offset from begin of resource fork (info_begin) to resource data */
ret = read_uint32(bs, info_begin, &rsrc_data_offset);
if (ret < 0) {
goto fail;
- } else if (rsrc_data_offset != 0x100) {
+ } else if (rsrc_data_offset > info_length) {
ret = -EINVAL;
goto fail;
}
- ret = read_uint32(bs, info_begin + 4, &count);
+ /* read length of resource data */
+ ret = read_uint32(bs, info_begin + 8, &count);
if (ret < 0) {
goto fail;
- } else if (count == 0) {
+ } else if (count == 0 || rsrc_data_offset + count > info_length) {
ret = -EINVAL;
goto fail;
}
- /* end of resource data, ignoring the following resource map */
- info_end = info_begin + count;
/* begin of resource data (consisting of one or more resources) */
- offset = info_begin + 0x100;
+ offset = info_begin + rsrc_data_offset;
+
+ /* end of resource data (there is possibly a following resource map
+ * which will be ignored). */
+ info_end = offset + count;
/* read offsets (mish blocks) from one or more resources in resource data */
while (offset < info_end) {
@@ -352,13 +330,63 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
}
offset += 4;
- ret = dmg_read_mish_block(bs, &ds, offset, count);
+ ret = dmg_read_mish_block(bs, ds, offset, count);
if (ret < 0) {
goto fail;
}
/* advance offset by size of resource */
offset += count;
}
+ return 0;
+
+fail:
+ return ret;
+}
+
+static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
+ Error **errp)
+{
+ BDRVDMGState *s = bs->opaque;
+ DmgHeaderState ds;
+ uint64_t rsrc_fork_offset, rsrc_fork_length;
+ int64_t offset;
+ int ret;
+
+ bs->read_only = 1;
+ s->n_chunks = 0;
+ s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
+ /* used by dmg_read_mish_block to keep track of the current I/O position */
+ ds.last_in_offset = 0;
+ ds.last_out_offset = 0;
+ ds.max_compressed_size = 1;
+ ds.max_sectors_per_chunk = 1;
+
+ /* locate the UDIF trailer */
+ offset = dmg_find_koly_offset(bs->file, errp);
+ if (offset < 0) {
+ ret = offset;
+ goto fail;
+ }
+
+ /* offset of resource fork (RsrcForkOffset) */
+ ret = read_uint64(bs, offset + 0x28, &rsrc_fork_offset);
+ if (ret < 0) {
+ goto fail;
+ }
+ ret = read_uint64(bs, offset + 0x30, &rsrc_fork_length);
+ if (ret < 0) {
+ goto fail;
+ }
+ if (rsrc_fork_length != 0) {
+ ret = dmg_read_resource_fork(bs, &ds,
+ rsrc_fork_offset, rsrc_fork_length);
+ if (ret < 0) {
+ goto fail;
+ }
+ } else {
+ ret = -EINVAL;
+ goto fail;
+ }
/* initialize zlib engine */
s->compressed_chunk = qemu_try_blockalign(bs->file,