From patchwork Tue Jun 28 01:32:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feiran Zheng X-Patchwork-Id: 102306 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 D692AB6F6F for ; Tue, 28 Jun 2011 11:56:16 +1000 (EST) Received: from localhost ([::1]:57240 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QbNXB-0007xS-5e for incoming@patchwork.ozlabs.org; Mon, 27 Jun 2011 21:56:13 -0400 Received: from eggs.gnu.org ([140.186.70.92]:57801) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QbNBe-0003FH-1Z for qemu-devel@nongnu.org; Mon, 27 Jun 2011 21:34:00 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QbNBb-0004UL-Qb for qemu-devel@nongnu.org; Mon, 27 Jun 2011 21:33:57 -0400 Received: from mail-iw0-f173.google.com ([209.85.214.173]:49984) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QbNBb-0004Lw-ED for qemu-devel@nongnu.org; Mon, 27 Jun 2011 21:33:55 -0400 Received: by mail-iw0-f173.google.com with SMTP id 3so5602687iwn.4 for ; Mon, 27 Jun 2011 18:33:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer :in-reply-to:references; bh=jhFPRVbAvxmv0gzEeQGs5QYXDP7Rwm6RtZKY/Eg4FgI=; b=saPAyf9kw+23CJukQ1j7vSQBpWIh9imx6/FK13qBuX/CUV/H++NlSGcQXEUrb8267r HcuM+FNVJD6sozJgP2C5n1+7BFBKMUoKuR/0OubHyt6vI5PIGPtTzhBMjs3SliGRlXos qH2G/GCv+E0e+olf0S8yL5nqe3Zm06MZ8vwMQ= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; b=AyO3a8pqAce1XfCg2u638l3aDHd0ep+XNMetaEmnDW+UxLnWcz0zGq+aVa/WpznIhN ngxdNcYf+oSgmXhuwJQHT+0Fyu7t6AnieW6HmBTM4YaFYVAVNwZxsziWm8jseket+tDw xgN25aZXesJPA5VooP44gZgyUKMXZ2Diiblv8= Received: by 10.42.71.78 with SMTP id i14mr291215icj.364.1309224834967; Mon, 27 Jun 2011 18:33:54 -0700 (PDT) Received: from localhost.localdomain ([111.187.42.58]) by mx.google.com with ESMTPS id p15sm3341784ibh.12.2011.06.27.18.33.52 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 27 Jun 2011 18:33:54 -0700 (PDT) From: Fam Zheng To: qemu-devel@nongnu.org Date: Tue, 28 Jun 2011 09:32:54 +0800 Message-Id: <1309224777-31024-10-git-send-email-famcool@gmail.com> X-Mailer: git-send-email 1.7.5.2 In-Reply-To: <1309224777-31024-1-git-send-email-famcool@gmail.com> References: <1309224777-31024-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 v5 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 | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 172 insertions(+), 13 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index c84ea90..8083c31 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; @@ -390,9 +391,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; } @@ -588,6 +590,157 @@ 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 = 0; + int r; + char access[11]; + char type[11]; + char fname[512]; + const char *p = desc; + int64_t sectors = 0; + int64_t flat_offset; + + while (*p) { + if (strncmp(p, "RW", strlen("RW"))) { + goto next_line; + } + /* parse extent line: + * RW [size in sectors] FLAT "file-name.vmdk" OFFSET + * or + * RW [size in sectors] SPARSE "file-name.vmdk" + */ + flat_offset = -1; + sscanf(p, "%10s %lld %10s %512s", + access, §ors, type, fname); + if (!strcmp(type, "FLAT")) { + sscanf(p, "%10s %lld %10s %512s %lld", + access, §ors, type, fname, &flat_offset); + if (flat_offset == -1) { + return -EINVAL; + } + } + + /* trim the quotation marks around */ + if (fname[0] == '"') { + memmove(fname, fname + 1, strlen(fname) + 1); + if (fname[strlen(fname) - 1] == '"') { + fname[strlen(fname) - 1] = '\0'; + } + } + if (!(strlen(access) && sectors && strlen(type) && strlen(fname))) { + goto next_line; + } + if (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) { + goto next_line; + } + if (strcmp(access, "RW")) { + goto next_line; + } + ret++; + + /* save to extents array */ + if (!strcmp(type, "FLAT")) { + /* FLAT extent */ + char extent_path[PATH_MAX]; + BlockDriverState *extent_file; + BlockDriver *drv; + VmdkExtent *extent; + + extent_file = bdrv_new(""); + drv = bdrv_find_format("file"); + if (!drv) { + return -EINVAL; + } + path_combine(extent_path, sizeof(extent_path), + desc_file_path, fname); + r = bdrv_open(extent_file, extent_path, + BDRV_O_RDWR | BDRV_O_NO_BACKING, drv); + if (r) { + return -EINVAL; + } + 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; @@ -602,7 +755,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); } } @@ -683,7 +836,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; } @@ -836,16 +989,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 != n * 512) { + return ret; + } } nb_sectors -= n; sector_num += n; @@ -869,7 +1026,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) { @@ -892,16 +1049,18 @@ 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 != n * 512) { + ret = ret < 0 ? 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;