Revision 7fa60fa3 block/vmdk.c

b/block/vmdk.c
65 65
    bool flat;
66 66
    int64_t sectors;
67 67
    int64_t end_sector;
68
    int64_t flat_start_offset;
68 69
    int64_t l1_table_offset;
69 70
    int64_t l1_backup_table_offset;
70 71
    uint32_t *l1_table;
......
407 408
static int vmdk_parent_open(BlockDriverState *bs)
408 409
{
409 410
    char *p_name;
410
    char desc[DESC_SIZE];
411
    char desc[DESC_SIZE + 1];
411 412
    BDRVVmdkState *s = bs->opaque;
412 413

  
414
    desc[DESC_SIZE] = '\0';
413 415
    if (bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE) != DESC_SIZE) {
414 416
        return -1;
415 417
    }
......
584 586
    return ret;
585 587
}
586 588

  
589
/* find an option value out of descriptor file */
590
static int vmdk_parse_description(const char *desc, const char *opt_name,
591
        char *buf, int buf_size)
592
{
593
    char *opt_pos, *opt_end;
594
    const char *end = desc + strlen(desc);
595

  
596
    opt_pos = strstr(desc, opt_name);
597
    if (!opt_pos) {
598
        return -1;
599
    }
600
    /* Skip "=\"" following opt_name */
601
    opt_pos += strlen(opt_name) + 2;
602
    if (opt_pos >= end) {
603
        return -1;
604
    }
605
    opt_end = opt_pos;
606
    while (opt_end < end && *opt_end != '"') {
607
        opt_end++;
608
    }
609
    if (opt_end == end || buf_size < opt_end - opt_pos + 1) {
610
        return -1;
611
    }
612
    pstrcpy(buf, opt_end - opt_pos + 1, opt_pos);
613
    return 0;
614
}
615

  
616
static int vmdk_parse_extents(const char *desc, BlockDriverState *bs,
617
        const char *desc_file_path)
618
{
619
    int ret;
620
    char access[11];
621
    char type[11];
622
    char fname[512];
623
    const char *p = desc;
624
    int64_t sectors = 0;
625
    int64_t flat_offset;
626

  
627
    while (*p) {
628
        /* parse extent line:
629
         * RW [size in sectors] FLAT "file-name.vmdk" OFFSET
630
         * or
631
         * RW [size in sectors] SPARSE "file-name.vmdk"
632
         */
633
        flat_offset = -1;
634
        ret = sscanf(p, "%10s %" SCNd64 " %10s %511s %" SCNd64,
635
                access, &sectors, type, fname, &flat_offset);
636
        if (ret < 4 || strcmp(access, "RW")) {
637
            goto next_line;
638
        } else if (!strcmp(type, "FLAT")) {
639
            if (ret != 5 || flat_offset < 0) {
640
                return -EINVAL;
641
            }
642
        } else if (ret != 4) {
643
            return -EINVAL;
644
        }
645

  
646
        /* trim the quotation marks around */
647
        if (fname[0] == '"') {
648
            memmove(fname, fname + 1, strlen(fname));
649
            if (strlen(fname) <= 1 || fname[strlen(fname) - 1] != '"') {
650
                return -EINVAL;
651
            }
652
            fname[strlen(fname) - 1] = '\0';
653
        }
654
        if (sectors <= 0 ||
655
            (strcmp(type, "FLAT") && strcmp(type, "SPARSE")) ||
656
            (strcmp(access, "RW"))) {
657
            goto next_line;
658
        }
659

  
660
        /* save to extents array */
661
        if (!strcmp(type, "FLAT")) {
662
            /* FLAT extent */
663
            char extent_path[PATH_MAX];
664
            BlockDriverState *extent_file;
665
            VmdkExtent *extent;
666

  
667
            path_combine(extent_path, sizeof(extent_path),
668
                    desc_file_path, fname);
669
            ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags);
670
            if (ret) {
671
                return ret;
672
            }
673
            extent = vmdk_add_extent(bs, extent_file, true, sectors,
674
                            0, 0, 0, 0, sectors);
675
            extent->flat_start_offset = flat_offset;
676
        } else {
677
            /* SPARSE extent, not supported for now */
678
            fprintf(stderr,
679
                "VMDK: Not supported extent type \"%s\""".\n", type);
680
            return -ENOTSUP;
681
        }
682
next_line:
683
        /* move to next line */
684
        while (*p && *p != '\n') {
685
            p++;
686
        }
687
        p++;
688
    }
689
    return 0;
690
}
691

  
692
static int vmdk_open_desc_file(BlockDriverState *bs, int flags)
693
{
694
    int ret;
695
    char buf[2048];
696
    char ct[128];
697
    BDRVVmdkState *s = bs->opaque;
698

  
699
    ret = bdrv_pread(bs->file, 0, buf, sizeof(buf));
700
    if (ret < 0) {
701
        return ret;
702
    }
703
    buf[2047] = '\0';
704
    if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) {
705
        return -EINVAL;
706
    }
707
    if (strcmp(ct, "monolithicFlat")) {
708
        fprintf(stderr,
709
                "VMDK: Not supported image type \"%s\""".\n", ct);
710
        return -ENOTSUP;
711
    }
712
    s->desc_offset = 0;
713
    ret = vmdk_parse_extents(buf, bs, bs->file->filename);
714
    if (ret) {
715
        return ret;
716
    }
717

  
718
    /* try to open parent images, if exist */
719
    if (vmdk_parent_open(bs)) {
720
        qemu_free(s->extents);
721
        return -EINVAL;
722
    }
723
    s->parent_cid = vmdk_read_cid(bs, 1);
724
    return 0;
725
}
726

  
587 727
static int vmdk_open(BlockDriverState *bs, int flags)
588 728
{
589 729
    uint32_t magic;
......
598 738
    } else if (magic == VMDK4_MAGIC) {
599 739
        return vmdk_open_vmdk4(bs, flags);
600 740
    } else {
601
        return -EINVAL;
741
        return vmdk_open_desc_file(bs, flags);
602 742
    }
603 743
}
604 744

  
......
679 819
    if (m_data)
680 820
        m_data->valid = 0;
681 821
    if (extent->flat) {
682
        *cluster_offset = 0;
822
        *cluster_offset = extent->flat_start_offset;
683 823
        return 0;
684 824
    }
685 825

  
......
832 972
            /* if not allocated, try to read from parent image, if exist */
833 973
            if (bs->backing_hd) {
834 974
                if (!vmdk_is_cid_valid(bs))
835
                    return -1;
975
                    return -EINVAL;
836 976
                ret = bdrv_read(bs->backing_hd, sector_num, buf, n);
837 977
                if (ret < 0)
838
                    return -1;
978
                    return ret;
839 979
            } else {
840 980
                memset(buf, 0, 512 * n);
841 981
            }
842 982
        } else {
843
            if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
844
                return -1;
983
            ret = bdrv_pread(extent->file,
984
                            cluster_offset + index_in_cluster * 512,
985
                            buf, n * 512);
986
            if (ret < 0) {
987
                return ret;
988
            }
845 989
        }
846 990
        nb_sectors -= n;
847 991
        sector_num += n;
......
865 1009
                "(VMDK) Wrong offset: sector_num=0x%" PRIx64
866 1010
                " total_sectors=0x%" PRIx64 "\n",
867 1011
                sector_num, bs->total_sectors);
868
        return -1;
1012
        return -EIO;
869 1013
    }
870 1014

  
871 1015
    while (nb_sectors > 0) {
......
888 1032
            n = nb_sectors;
889 1033
        }
890 1034

  
891
        if (bdrv_pwrite(bs->file,
1035
        ret = bdrv_pwrite(extent->file,
892 1036
                        cluster_offset + index_in_cluster * 512,
893
                        buf, n * 512)
894
                != n * 512) {
895
            return -1;
1037
                        buf,
1038
                        n * 512);
1039
        if (ret < 0) {
1040
            return ret;
896 1041
        }
897 1042
        if (m_data.valid) {
898 1043
            /* update L2 tables */
899 1044
            if (vmdk_L2update(extent, &m_data) == -1) {
900
                return -1;
1045
                return -EIO;
901 1046
            }
902 1047
        }
903 1048
        nb_sectors -= n;

Also available in: Unified diff