static int vmdk_open_vmdk3(BlockDriverState *bs, BlockDriverState *file, int flags) { int ret; uint32_t magic; VMDK3Header header; VmdkExtent *extent; ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { return ret; } extent = vmdk_add_extent(bs, bs->file, false, le32_to_cpu(header.disk_sectors), le32_to_cpu(header.l1dir_offset) << 9, 0, 1 << 6, 1 << 9, le32_to_cpu(header.granularity)); ret = vmdk_init_tables(bs, extent); if (ret) { /* free extent allocated by vmdk_add_extent */ vmdk_free_last_extent(bs); } return ret; }
static int vmdk_open_vmdk4(BlockDriverState *bs, BlockDriverState *file, int flags) { int ret; uint32_t magic; uint32_t l1_size, l1_entry_sectors; VMDK4Header header; VmdkExtent *extent; int64_t l1_backup_offset = 0; ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { return ret; } if (header.capacity == 0 && header.desc_offset) { return vmdk_open_desc_file(bs, flags, header.desc_offset << 9); } l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte) * le64_to_cpu(header.granularity); if (l1_entry_sectors <= 0) { return -EINVAL; } l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) / l1_entry_sectors; if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; } extent = vmdk_add_extent(bs, file, false, le64_to_cpu(header.capacity), le64_to_cpu(header.gd_offset) << 9, l1_backup_offset, l1_size, le32_to_cpu(header.num_gtes_per_gte), le64_to_cpu(header.granularity)); extent->compressed = le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; ret = vmdk_init_tables(bs, extent); if (ret) { /* free extent allocated by vmdk_add_extent */ vmdk_free_last_extent(bs); } return ret; }
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; char extent_path[PATH_MAX]; BlockDriverState *extent_file; 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 %" SCNd64 " %10s %511s %" SCNd64, access, §ors, type, fname, &flat_offset); if (ret < 4 || strcmp(access, "RW")) { goto next_line; } else if (!strcmp(type, "FLAT")) { if (ret != 5 || flat_offset < 0) { return -EINVAL; } } else if (ret != 4) { 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; } path_combine(extent_path, sizeof(extent_path), desc_file_path, fname); ret = bdrv_file_open(&extent_file, extent_path, bs->open_flags); if (ret) { return ret; } /* save to extents array */ if (!strcmp(type, "FLAT")) { /* FLAT extent */ VmdkExtent *extent; extent = vmdk_add_extent(bs, extent_file, true, sectors, 0, 0, 0, 0, sectors); extent->flat_start_offset = flat_offset << 9; } else if (!strcmp(type, "SPARSE")) { /* SPARSE extent */ ret = vmdk_open_sparse(bs, extent_file, bs->open_flags); if (ret) { bdrv_delete(extent_file); return ret; } } else { 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_vmdk4(BlockDriverState *bs, BlockDriverState *file, int flags) { int ret; uint32_t magic; uint32_t l1_size, l1_entry_sectors; VMDK4Header header; VmdkExtent *extent; int64_t l1_backup_offset = 0; ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); if (ret < 0) { return ret; } if (header.capacity == 0 && header.desc_offset) { return vmdk_open_desc_file(bs, flags, header.desc_offset << 9); } if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { /* * The footer takes precedence over the header, so read it in. The * footer starts at offset -1024 from the end: One sector for the * footer, and another one for the end-of-stream marker. */ struct { struct { uint64_t val; uint32_t size; uint32_t type; uint8_t pad[512 - 16]; } QEMU_PACKED footer_marker; uint32_t magic; VMDK4Header header; uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; struct { uint64_t val; uint32_t size; uint32_t type; uint8_t pad[512 - 16]; } QEMU_PACKED eos_marker; } QEMU_PACKED footer; ret = bdrv_pread(file, bs->file->total_sectors * 512 - 1536, &footer, sizeof(footer)); if (ret < 0) { return ret; } /* Some sanity checks for the footer */ if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || le32_to_cpu(footer.footer_marker.size) != 0 || le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || le64_to_cpu(footer.eos_marker.val) != 0 || le32_to_cpu(footer.eos_marker.size) != 0 || le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) { return -EINVAL; } header = footer.header; } l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gte) * le64_to_cpu(header.granularity); if (l1_entry_sectors == 0) { return -EINVAL; } l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) / l1_entry_sectors; if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; } extent = vmdk_add_extent(bs, file, false, le64_to_cpu(header.capacity), le64_to_cpu(header.gd_offset) << 9, l1_backup_offset, l1_size, le32_to_cpu(header.num_gtes_per_gte), le64_to_cpu(header.granularity)); extent->compressed = le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; ret = vmdk_init_tables(bs, extent); if (ret) { /* free extent allocated by vmdk_add_extent */ vmdk_free_last_extent(bs); } return ret; }