Commit f16f509d authored by Fam Zheng's avatar Fam Zheng Committed by Kevin Wolf
Browse files

VMDK: bugfix, open Haiku vmdk image



Haiku provides a specially formed vmdk image, which let qemu abort. It a
combination of sparse header and flat data (i.e. with not l1/l2 table at
all). The fix is turn to descriptor when sparse header is zero in field
'capacity'.

Signed-off-by: default avatarFam Zheng <famcool@gmail.com>
Reviewed-by: default avatarStefan Hajnoczi <stefanha@linux.vnet.ibm.com>
Signed-off-by: default avatarKevin Wolf <kwolf@redhat.com>
parent 6c031aac
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -408,6 +408,9 @@ static int vmdk_open_vmdk3(BlockDriverState *bs,
    return ret;
}

static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
                               int64_t desc_offset);

static int vmdk_open_vmdk4(BlockDriverState *bs,
                           BlockDriverState *file,
                           int flags)
@@ -422,6 +425,9 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
    if (ret < 0) {
        return ret;
    }
    if (header.capacity == 0 && header.desc_offset) {
        return vmdk_open_desc_file(bs, flags, header.desc_offset << 9);
    }
    l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte)
                        * le64_to_cpu(header.granularity);
    if (l1_entry_sectors <= 0) {
@@ -559,7 +565,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,

            extent = vmdk_add_extent(bs, extent_file, true, sectors,
                            0, 0, 0, 0, sectors);
            extent->flat_start_offset = flat_offset;
            extent->flat_start_offset = flat_offset << 9;
        } else if (!strcmp(type, "SPARSE")) {
            /* SPARSE extent */
            ret = vmdk_open_sparse(bs, extent_file, bs->open_flags);
@@ -582,14 +588,15 @@ next_line:
    return 0;
}

static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
static int vmdk_open_desc_file(BlockDriverState *bs, int flags,
                               int64_t desc_offset)
{
    int ret;
    char buf[2048];
    char ct[128];
    BDRVVmdkState *s = bs->opaque;

    ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
    ret = bdrv_pread(bs->file, desc_offset, buf, sizeof(buf));
    if (ret < 0) {
        return ret;
    }
@@ -635,7 +642,7 @@ static int vmdk_open(BlockDriverState *bs, int flags)
        s->parent_cid = vmdk_read_cid(bs, 1);
        return 0;
    } else {
        return vmdk_open_desc_file(bs, flags);
        return vmdk_open_desc_file(bs, flags, 0);
    }
}