static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, int64_t offset_in_cluster, QEMUIOVector *qiov, uint64_t qiov_offset, uint64_t n_bytes, uint64_t offset) { int ret; VmdkGrainMarker *data = NULL; uLongf buf_len; QEMUIOVector local_qiov; struct iovec iov; int64_t write_offset; int64_t write_end_sector; if (extent->compressed) { void *compressed_data; if (!extent->has_marker) { ret = -EINVAL; goto out; } buf_len = (extent->cluster_sectors << 9) * 2; data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); compressed_data = g_malloc(n_bytes); qemu_iovec_to_buf(qiov, qiov_offset, compressed_data, n_bytes); ret = compress(data->data, &buf_len, compressed_data, n_bytes); g_free(compressed_data); if (ret != Z_OK || buf_len == 0) { ret = -EINVAL; goto out; } data->lba = offset >> BDRV_SECTOR_BITS; data->size = buf_len; n_bytes = buf_len + sizeof(VmdkGrainMarker); iov = (struct iovec) { .iov_base = data, .iov_len = n_bytes, }; qemu_iovec_init_external(&local_qiov, &iov, 1); } else { qemu_iovec_init(&local_qiov, qiov->niov); qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes); } write_offset = cluster_offset + offset_in_cluster, ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes, &local_qiov, 0); write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE); if (extent->compressed) { extent->next_cluster_sector = write_end_sector; } else { extent->next_cluster_sector = MAX(extent->next_cluster_sector, write_end_sector); } if (ret < 0) { goto out; } ret = 0; out: g_free(data); if (!extent->compressed) { qemu_iovec_destroy(&local_qiov); } return ret; }