Revision 7fa60fa3
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, §ors, 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