qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 06/12] VMDK: vmdk_open for mono flat
@ 2011-06-04  0:42 Fam Zheng
  2011-06-18 16:42 ` Stefan Hajnoczi
  0 siblings, 1 reply; 2+ messages in thread
From: Fam Zheng @ 2011-06-04  0:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Stefan Hajnoczi, Christoph Hellwig

Vmdk_open for mono flat image.

Signed-off-by: Fam Zheng <famcool@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, &sectors, 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);
     }
 }

^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [Qemu-devel] [PATCH 06/12] VMDK: vmdk_open for mono flat
  2011-06-04  0:42 [Qemu-devel] [PATCH 06/12] VMDK: vmdk_open for mono flat Fam Zheng
@ 2011-06-18 16:42 ` Stefan Hajnoczi
  0 siblings, 0 replies; 2+ messages in thread
From: Stefan Hajnoczi @ 2011-06-18 16:42 UTC (permalink / raw)
  To: Fam Zheng; +Cc: Kevin Wolf, qemu-devel, Christoph Hellwig

On Sat, Jun 4, 2011 at 1:42 AM, Fam Zheng <famcool@gmail.com> wrote:
> Vmdk_open for mono flat image.
>
> Signed-off-by: Fam Zheng <famcool@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) {

Same strstr(3) issue here in the existing vmdk code.

I suggest increasing the size by one, desc[DESC_SIZE + 1], and setting
the last char to '\0' so that strstr(3) never runs off the end of the
desc[] buffer.

>         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;

Couldn't the opt_name match at the end of the descriptor?  This would
jump beyond the NUL terminator!

> +    r = sscanf(opt_pos, "%[^\"]s", buf);
> +    assert(r <= buf_size);

You cannot use assert for input validation.  File format parsing needs
to be bulletproof, there can be no crashes or asserts.

> +    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, &sectors, type, fname);

You can combine the "RW" strncmp into the format string and then check
the sscanf(3) return value to see if the line matched.  Then you can
also avoid the big if statement.

> +            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];

There is a constant for this: PATH_MAX

> +                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");

For troubleshooting purposes it would be useful to print the
unsupported extent type.

> +                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)

I think extent creation would be simpler if you introduced:
int vmdk_add_extent(BDRVVmdkState *s, const char *filename, bool flat, ...);

This function adds a new extent (perhaps use a linked list instead of
an array) and can be used from vmdk_parse_extents() so you don't need
to call it twice to figure out the number of extents and then to parse
it.

This function should also be used by the monolithic open functions
instead of assiging extent fields manually.

> +{
> +    char buf[2048];
> +    char ct[128];
> +    VmdkExtent *extent;
> +    BDRVVmdkState *s = bs->opaque;
> +
> +    if (bdrv_pread(bs->file, 0, buf, sizeof(buf)) == 0) {

bdrv_pread() returns negative on error.

> +        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;

Coding style {}.  Please run scripts/checkpatch.pl before submitting patches.

Stefan

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-06-18 16:42 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-04  0:42 [Qemu-devel] [PATCH 06/12] VMDK: vmdk_open for mono flat Fam Zheng
2011-06-18 16:42 ` Stefan Hajnoczi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).