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; Error *local_err = NULL; 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 \"%511[^\n\r\"]\" %" SCNd64, access, &sectors, 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; } if (sectors <= 0 || (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || (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, NULL, bs->open_flags, &local_err); if (ret) { qerror_report_err(local_err); error_free(local_err); return ret; } /* save to extents array */ if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { /* FLAT extent */ VmdkExtent *extent; ret = vmdk_add_extent(bs, extent_file, true, sectors, 0, 0, 0, 0, sectors, &extent); if (ret < 0) { return ret; } extent->flat_start_offset = flat_offset << 9; } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ ret = vmdk_open_sparse(bs, extent_file, bs->open_flags); if (ret) { bdrv_unref(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; }