From patchwork Fri Jul 1 04:55:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feiran Zheng X-Patchwork-Id: 102866 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 C1F95B6F5F for ; Fri, 1 Jul 2011 15:22:02 +1000 (EST) Received: from localhost ([::1]:56757 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QcWAv-0000r0-FD for incoming@patchwork.ozlabs.org; Fri, 01 Jul 2011 01:21:57 -0400 Received: from eggs.gnu.org ([140.186.70.92]:44623) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QcVmX-0003g5-9q for qemu-devel@nongnu.org; Fri, 01 Jul 2011 00:56:47 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QcVmV-0002Fv-Ac for qemu-devel@nongnu.org; Fri, 01 Jul 2011 00:56:44 -0400 Received: from mail-iy0-f173.google.com ([209.85.210.173]:57907) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QcVmU-000241-V3 for qemu-devel@nongnu.org; Fri, 01 Jul 2011 00:56:43 -0400 Received: by mail-iy0-f173.google.com with SMTP id 3so2857641iyb.4 for ; Thu, 30 Jun 2011 21:56:42 -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=VATwaK+a/FtdDGGaA3uikGK8f1A3y9Yk6pz2UoA4wEI=; b=Q43fo9taPdTWGwba3HTPr7uBN8FWF49ziY5We9IeWIUEggPUibbwgAcNlx12YQiGSs i40G6jBKtf+w8maReQm5xhjUro1nSDqe19TMqbh1hDcGvGCcZPIGcpkznEk2MuESXk3E fcGd/+nWRcYRe7rORURSCCh0tPN6xMJfWPOK8= Received: by 10.231.82.19 with SMTP id z19mr2490993ibk.68.1309496202280; Thu, 30 Jun 2011 21:56:42 -0700 (PDT) Received: from localhost.localdomain ([111.187.42.58]) by mx.google.com with ESMTPS id v16sm1638855ibe.0.2011.06.30.21.56.38 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 30 Jun 2011 21:56:41 -0700 (PDT) From: Fam Zheng To: qemu-devel@nongnu.org Date: Fri, 1 Jul 2011 12:55:39 +0800 Message-Id: <1309496142-14228-10-git-send-email-famcool@gmail.com> X-Mailer: git-send-email 1.7.6 In-Reply-To: <1309496142-14228-1-git-send-email-famcool@gmail.com> References: <1309496142-14228-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.210.173 Cc: kwolf@redhat.com, Fam Zheng , hch@lst.de, stefanha@gmail.com Subject: [Qemu-devel] [PATCH v6 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 | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 170 insertions(+), 14 deletions(-) diff --git a/block/vmdk.c b/block/vmdk.c index 40e4464..940c63f 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; @@ -403,9 +404,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; } @@ -600,10 +602,158 @@ static int vmdk_open_vmdk4(BlockDriverState *bs, int flags) } return 0; fail: - qemu_free(s->extents); + vmdk_free_extents(bs); 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; + BlockDriver *drv; + VmdkExtent *extent; + + extent_file = bdrv_new(""); + drv = bdrv_find_format("file"); + if (!drv) { + bdrv_delete(extent_file); + return -EINVAL; + } + path_combine(extent_path, sizeof(extent_path), + desc_file_path, fname); + ret = bdrv_open(extent_file, extent_path, + bs->open_flags | BDRV_O_RDWR | BDRV_O_NO_BACKING, drv); + if (ret) { + bdrv_delete(extent_file); + 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; @@ -618,7 +768,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); } } @@ -699,7 +849,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; } @@ -852,16 +1002,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; @@ -885,7 +1039,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) { @@ -908,16 +1062,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 : -EIO; + return ret; } if (m_data.valid) { /* update L2 tables */ if (vmdk_L2update(extent, &m_data) == -1) { - return -1; + return -EIO; } } nb_sectors -= n;