From patchwork Sun Jul 3 15:06:49 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feiran Zheng X-Patchwork-Id: 103020 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 96E9DB6F57 for ; Mon, 4 Jul 2011 01:39:45 +1000 (EST) Received: from localhost ([::1]:34278 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QdOlq-000486-1a for incoming@patchwork.ozlabs.org; Sun, 03 Jul 2011 11:39:42 -0400 Received: from eggs.gnu.org ([140.186.70.92]:59373) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QdOHQ-0004wh-MB for qemu-devel@nongnu.org; Sun, 03 Jul 2011 11:08:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QdOHN-0004t4-Rq for qemu-devel@nongnu.org; Sun, 03 Jul 2011 11:08:16 -0400 Received: from mail-iw0-f173.google.com ([209.85.214.173]:46065) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QdOHN-0004qh-Fk for qemu-devel@nongnu.org; Sun, 03 Jul 2011 11:08:13 -0400 Received: by mail-iw0-f173.google.com with SMTP id 3so4509959iwn.4 for ; Sun, 03 Jul 2011 08:08:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=oby1n0m/lypffyqNuJwYJlQVDspDmgFhgDfMvSdox/s=; b=Gkwt58V9B6mx1ZmVrjQgQg/wD0smnjLVW5pIJw6mVIbqjosiKkXq/ZO3Ua0g57y3lR tiTyZo5RAmGqFANYWjbEa64ZtSDcEifb7BTvlBnjUjUcuZX1D29tVlNnzgOMlDgkGDDX Qe9x57i/pD/nXEASO3jqaK/4i+SfKl1FbV270= Received: by 10.42.163.10 with SMTP id a10mr6228251icy.493.1309705693060; Sun, 03 Jul 2011 08:08:13 -0700 (PDT) Received: from localhost.localdomain ([111.187.70.55]) by mx.google.com with ESMTPS id d6sm5419466icx.13.2011.07.03.08.08.10 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 03 Jul 2011 08:08:12 -0700 (PDT) From: Fam Zheng To: qemu-devel@nongnu.org Date: Sun, 3 Jul 2011 23:06:49 +0800 Message-Id: <1309705612-27079-10-git-send-email-famcool@gmail.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1309705612-27079-1-git-send-email-famcool@gmail.com> References: <1309705612-27079-1-git-send-email-famcool@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.214.173 Cc: kwolf@redhat.com, Fam Zheng , hch@lst.de, stefanha@gmail.com Subject: [Qemu-devel] [PATCH v7 09/12] VMDK: open/read/write for monolithicFlat image X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Parse vmdk decriptor file and open mono flat image. Read/write the flat extent. Signed-off-by: Fam Zheng --- block/vmdk.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 159 insertions(+), 13 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 5bb6392..9ea00ce 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -65,6 +65,7 @@ typedef struct VmdkExtent { bool flat; int64_t sectors; int64_t end_sector; + int64_t flat_start_offset; int64_t l1_table_offset; int64_t l1_backup_table_offset; uint32_t *l1_table; @@ -406,9 +407,10 @@ fail: static int vmdk_parent_open(BlockDriverState *bs) { char *p_name; - char desc[DESC_SIZE]; + char desc[DESC_SIZE + 1]; BDRVVmdkState *s = bs->opaque; + desc[DESC_SIZE] = '\0'; if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) { return -1; } @@ -583,6 +585,145 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, int flags) return ret; } +/* 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, *opt_end; + const char *end = desc + strlen(desc); + + opt_pos = strstr(desc, opt_name); + if (!opt_pos) { + return -1; + } + /* Skip "=\"" following opt_name */ + opt_pos += strlen(opt_name) + 2; + if (opt_pos >= end) { + return -1; + } + opt_end = opt_pos; + while (opt_end < end && *opt_end != '"') { + opt_end++; + } + if (opt_end == end || buf_size < opt_end - opt_pos + 1) { + return -1; + } + pstrcpy(buf, opt_end - opt_pos + 1, opt_pos); + return 0; +} + +static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, + const char *desc_file_path) +{ + int ret; + char access[11]; + char type[11]; + char fname[512]; + const char *p = desc; + int64_t sectors = 0; + int64_t flat_offset; + + while (*p) { + /* parse extent line: + * RW [size in sectors] FLAT "file-name.vmdk" OFFSET + * or + * RW [size in sectors] SPARSE "file-name.vmdk" + */ + flat_offset = -1; + ret = sscanf(p, "%10s %lld %10s %512s", + access, §ors, type, fname); + if (ret != 4) { + goto next_line; + } + if (!strcmp(type, "FLAT")) { + ret = sscanf(p, "%10s %lld %10s %511s %lld", + access, §ors, type, fname, &flat_offset); + if (ret != 5 || flat_offset < 0) { + return -EINVAL; + } + } + + /* trim the quotation marks around */ + if (fname[0] == '"') { + memmove(fname, fname + 1, strlen(fname)); + if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') { + return -EINVAL; + } + fname[strlen(fname) - 1] = '\0'; + } + if (sectors <= 0 || + (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) || + (strcmp(access, "RW"))) { + goto next_line; + } + + /* save to extents array */ + if (!strcmp(type, "FLAT")) { + /* FLAT extent */ + char extent_path[PATH_MAX]; + BlockDriverState *extent_file; + VmdkExtent *extent; + + path_combine(extent_path, sizeof(extent_path), + desc_file_path, fname); + ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags); + if (ret) { + return ret; + } + extent = vmdk_add_extent(bs, extent_file, true, sectors, + 0, 0, 0, 0, sectors); + extent->flat_start_offset = flat_offset; + } else { + /* SPARSE extent, not supported for now */ + fprintf(stderr, + "VMDK: Not supported extent type \"%s\""".\n", type); + return -ENOTSUP; + } +next_line: + /* move to next line */ + while (*p && *p != '\n') { + p++; + } + p++; + } + return 0; +} + +static int vmdk_open_desc_file(BlockDriverState *bs, int flags) +{ + int ret; + char buf[2048]; + char ct[128]; + BDRVVmdkState *s = bs->opaque; + + ret = bdrv_pread(bs->file, 0, buf, sizeof(buf)); + if (ret < 0) { + return ret; + } + buf[2047] = '\0'; + if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { + return -EINVAL; + } + if (strcmp(ct, "monolithicFlat")) { + fprintf(stderr, + "VMDK: Not supported image type \"%s\""".\n", ct); + return -ENOTSUP; + } + s->desc_offset = 0; + ret = vmdk_parse_extents(buf, bs, bs->file->filename); + if (ret) { + return ret; + } + + /* try to open parent images, if exist */ + if (vmdk_parent_open(bs)) { + qemu_free(s->extents); + return -EINVAL; + } + s->parent_cid = vmdk_read_cid(bs, 1); + return 0; +} + static int vmdk_open(BlockDriverState *bs, int flags) { uint32_t magic; @@ -597,7 +738,7 @@ static int vmdk_open(BlockDriverState *bs, int flags) } else if (magic == VMDK4_MAGIC) { return vmdk_open_vmdk4(bs, flags); } else { - return -EINVAL; + return vmdk_open_desc_file(bs, flags); } } @@ -678,7 +819,7 @@ static int get_cluster_offset(BlockDriverState *bs, if (m_data) m_data->valid = 0; if (extent->flat) { - *cluster_offset = 0; + *cluster_offset = extent->flat_start_offset; return 0; } @@ -831,16 +972,20 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, /* if not allocated, try to read from parent image, if exist */ if (bs->backing_hd) { if (!vmdk_is_cid_valid(bs)) - return -1; + return -EINVAL; ret = bdrv_read(bs->backing_hd, sector_num, buf, n); if (ret < 0) - return -1; + return ret; } else { memset(buf, 0, 512 * n); } } else { - if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) - return -1; + ret = bdrv_pread(extent->file, + cluster_offset + index_in_cluster * 512, + buf, n * 512); + if (ret < 0) { + return ret; + } } nb_sectors -= n; sector_num += n; @@ -864,7 +1009,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, "(VMDK) Wrong offset: sector_num=0x%" PRIx64 " total_sectors=0x%" PRIx64 "\n", sector_num, bs->total_sectors); - return -1; + return -EIO; } while (nb_sectors > 0) { @@ -887,16 +1032,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, n = nb_sectors; } - if (bdrv_pwrite(bs->file, + ret = bdrv_pwrite(extent->file, cluster_offset + index_in_cluster * 512, - buf, n * 512) - != n * 512) { - return -1; + buf, + n * 512); + if (ret < 0) { + return ret; } if (m_data.valid) { /* update L2 tables */ if (vmdk_L2update(extent, &m_data) == -1) { - return -1; + return -EIO; } } nb_sectors -= n;