Vmdk_open for mono flat image. Signed-off-by: Fam Zheng <famc...@gmail.com> --- block/vmdk.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 128 insertions(+), 6 deletions(-)
diff --git a/block/vmdk.c b/block/vmdk.c index b02a7b7..f1233cf 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -355,24 +355,110 @@ static int vmdk_parent_open(BlockDriverState *bs) char desc[DESC_SIZE]; BDRVVmdkState *s = bs->opaque; - if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) + if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) { return -1; + } if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) { char *end_name; p_name += sizeof("parentFileNameHint") + 1; - if ((end_name = strchr(p_name,'\"')) == NULL) + if ((end_name = strchr(p_name,'\"')) == NULL) { return -1; - if ((end_name - p_name) > sizeof (bs->backing_file) - 1) + } + if ((end_name - p_name) > sizeof (bs->backing_file) - 1) { return -1; - + } pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); } - return 0; } +/* find an option value out of descriptor file */ +static int vmdk_parse_description(const char *desc, const char *opt_name, + char *buf, int buf_size) +{ + char *opt_pos = strstr(desc, opt_name); + int r; + if (!opt_pos) { + return -1; + } + opt_pos += strlen(opt_name) + 2; + r = sscanf(opt_pos, "%[^\"]s", buf); + assert(r <= buf_size); + return r <= 0; +} + + +static int vmdk_parse_extents(const char *desc, VmdkExtent extents[], + const char *desc_file_path) +{ + int ret = 0; + int r; + char access[11]; + char type[11]; + char fname[512]; + VmdkExtent *extent; + const char *p = desc; + int64_t sectors = 0; + + while (*p) { + if (strncmp(p, "RW", strlen("RW")) == 0) { + /* parse extent line: + * RW [size in sectors] FLAT "file-name.vmdk" OFFSET + * or + * RW [size in sectors] SPARSE "file-name.vmdk" + */ + + sscanf(p, "%10s %lld %10s \"%[^\"]512s\"", + access, §ors, type, fname); + if (!(strlen(access) && sectors && strlen(type) && strlen(fname))) { + goto cont; + } + if (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) { + goto cont; + } + if (strcmp(access, "RW")) { + goto cont; + } + ret++; + if (!extents) { + goto cont; + } + + /* save to extents array */ + if (!strcmp(type, "FLAT")) { + /* FLAT extent */ + char extent_path[1024]; + path_combine(extent_path, sizeof(extent_path), + desc_file_path, fname); + extent = &extents[ret - 1]; + extent->flat = true; + extent->sectors = sectors; + extent->cluster_sectors = sectors; + extent->file = bdrv_new(""); + if (!extent->file) { + return -1; + } + r = bdrv_open(extent->file, extent_path, + BDRV_O_RDWR | BDRV_O_NO_BACKING, NULL); + if (r) { + return -1; + } + } else { + /* SPARSE extent, should not be here */ + fprintf(stderr, "VMDK: Not supported extent type.\n"); + return -1; + } + } +cont: + /* move to next line */ + while (*p && *p != '\n') p++; + p++; + } + return ret; +} + static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent) { int l1_size, i; @@ -496,6 +582,42 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, int flags) return -1; } +static int vmdk_open_desc_file(BlockDriverState *bs, int flags) +{ + char buf[2048]; + char ct[128]; + VmdkExtent *extent; + BDRVVmdkState *s = bs->opaque; + + if (bdrv_pread(bs->file, 0, buf, sizeof(buf)) == 0) { + goto fail; + } + if (0 != vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { + goto fail; + } + if (0 != strcmp(ct, "monolithicFlat")) { + goto fail; + } + s->desc_offset = 0; + s->num_extents = vmdk_parse_extents(buf, NULL, NULL); + if (!s->num_extents) + goto fail; + s->extents = qemu_mallocz(s->num_extents * sizeof(VmdkExtent)); + extent = s->extents; + vmdk_parse_extents(buf, s->extents, bs->file->filename); + bs->total_sectors = extent->sectors; + + // try to open parent images, if exist + if (vmdk_parent_open(bs) != 0) { + goto fail; + } + extent->parent_cid = vmdk_read_cid(bs, 1); + return 0; + fail: + qemu_free(s->extents); + return -1; +} + static int vmdk_open(BlockDriverState *bs, int flags) { uint32_t magic; @@ -510,7 +632,7 @@ static int vmdk_open(BlockDriverState *bs, int flags) } else if (magic == VMDK4_MAGIC) { return vmdk_open_vmdk4(bs, flags); } else { - return -1; + return vmdk_open_desc_file(bs, flags); } }