+++ /dev/null
-This patch allows the creation of vma files without data streams.
-
-Such files only contain configuration data. This is useful if a
-user set backup=no to all VM disks.
-
-Index: new/vma-reader.c
-===================================================================
---- new.orig/vma-reader.c
-+++ new/vma-reader.c
-@@ -334,11 +334,6 @@ static int vma_reader_read_head(VmaReade
- }
- }
-
-- if (!count) {
-- error_setg(errp, "vma does not contain data");
-- return -1;
-- }
--
- for (i = 0; i < VMA_MAX_CONFIGS; i++) {
- uint32_t name_ptr = GUINT32_FROM_BE(h->config_names[i]);
- uint32_t data_ptr = GUINT32_FROM_BE(h->config_data[i]);
-@@ -830,16 +825,20 @@ static int vma_reader_restore_full(VmaRe
- }
-
- if (verbose) {
-- printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
-- vmar->clusters_read*VMA_CLUSTER_SIZE,
-- vmar->zero_cluster_data,
-- (double)(100.0*vmar->zero_cluster_data)/
-- (vmar->clusters_read*VMA_CLUSTER_SIZE));
--
-- int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
-- if (datasize) { // this does not make sense for empty files
-- printf("space reduction due to 4K zero blocks %.3g%%\n",
-- (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
-+ if (vmar->clusters_read) {
-+ printf("total bytes read %zd, sparse bytes %zd (%.3g%%)\n",
-+ vmar->clusters_read*VMA_CLUSTER_SIZE,
-+ vmar->zero_cluster_data,
-+ (double)(100.0*vmar->zero_cluster_data)/
-+ (vmar->clusters_read*VMA_CLUSTER_SIZE));
-+
-+ int64_t datasize = vmar->clusters_read*VMA_CLUSTER_SIZE-vmar->zero_cluster_data;
-+ if (datasize) { // this does not make sense for empty files
-+ printf("space reduction due to 4K zero blocks %.3g%%\n",
-+ (double)(100.0*vmar->partial_zero_cluster_data) / datasize);
-+ }
-+ } else {
-+ printf("vma archive contains no image data\n");
- }
- }
- return ret;
-Index: new/vma-writer.c
-===================================================================
---- new.orig/vma-writer.c
-+++ new/vma-writer.c
-@@ -258,7 +258,7 @@ vma_queue_write(VmaWriter *vmaw, const v
- }
-
- vmaw->co_writer = NULL;
--
-+
- return (done == bytes) ? bytes : -1;
- }
-
-@@ -382,10 +382,6 @@ static int coroutine_fn vma_write_header
- time_t ctime = time(NULL);
- head->ctime = GUINT64_TO_BE(ctime);
-
-- if (!vmaw->stream_count) {
-- return -1;
-- }
--
- for (i = 0; i < VMA_MAX_CONFIGS; i++) {
- head->config_names[i] = GUINT32_TO_BE(vmaw->config_names[i]);
- head->config_data[i] = GUINT32_TO_BE(vmaw->config_data[i]);
-@@ -502,6 +498,23 @@ static int vma_count_open_streams(VmaWri
- return open_drives;
- }
-
-+
-+/**
-+ * You need to call this if the vma archive does not contain
-+ * any data stream.
-+ */
-+int coroutine_fn
-+vma_writer_flush_output(VmaWriter *vmaw)
-+{
-+ qemu_co_mutex_lock(&vmaw->flush_lock);
-+ int ret = vma_writer_flush(vmaw);
-+ qemu_co_mutex_unlock(&vmaw->flush_lock);
-+ if (ret < 0) {
-+ vma_writer_set_error(vmaw, "vma_writer_flush_header failed");
-+ }
-+ return ret;
-+}
-+
- /**
- * all jobs should call this when there is no more data
- * Returns: number of remaining stream (0 ==> finished)
-@@ -529,12 +542,7 @@ vma_writer_close_stream(VmaWriter *vmaw,
-
- if (open_drives <= 0) {
- DPRINTF("vma_writer_set_status all drives completed\n");
-- qemu_co_mutex_lock(&vmaw->flush_lock);
-- int ret = vma_writer_flush(vmaw);
-- qemu_co_mutex_unlock(&vmaw->flush_lock);
-- if (ret < 0) {
-- vma_writer_set_error(vmaw, "vma_writer_close_stream: flush failed");
-- }
-+ vma_writer_flush_output(vmaw);
- }
-
- return open_drives;
-Index: new/vma.c
-===================================================================
---- new.orig/vma.c
-+++ new/vma.c
-@@ -33,7 +33,7 @@ static void help(void)
- "\n"
- "vma list <filename>\n"
- "vma config <filename> [-c config]\n"
-- "vma create <filename> [-c config] <archive> pathname ...\n"
-+ "vma create <filename> [-c config] pathname ...\n"
- "vma extract <filename> [-r <fifo>] <targetdir>\n"
- "vma verify <filename> [-v]\n"
- ;
-@@ -401,6 +401,18 @@ typedef struct BackupJob {
-
- #define BACKUP_SECTORS_PER_CLUSTER (VMA_CLUSTER_SIZE / BDRV_SECTOR_SIZE)
-
-+static void coroutine_fn backup_run_empty(void *opaque)
-+{
-+ VmaWriter *vmaw = (VmaWriter *)opaque;
-+
-+ vma_writer_flush_output(vmaw);
-+
-+ Error *err = NULL;
-+ if (vma_writer_close(vmaw, &err) != 0) {
-+ g_warning("vma_writer_close failed %s", error_get_pretty(err));
-+ }
-+}
-+
- static void coroutine_fn backup_run(void *opaque)
- {
- BackupJob *job = (BackupJob *)opaque;
-@@ -474,8 +486,8 @@ static int create_archive(int argc, char
- }
-
-
-- /* make sure we have archive name and at least one path */
-- if ((optind + 2) > argc) {
-+ /* make sure we an archive name */
-+ if ((optind + 1) > argc) {
- help();
- }
-
-@@ -510,11 +522,11 @@ static int create_archive(int argc, char
- l = g_list_next(l);
- }
-
-- int ind = 0;
-+ int devcount = 0;
- while (optind < argc) {
- const char *path = argv[optind++];
- char *devname = NULL;
-- path = extract_devname(path, &devname, ind++);
-+ path = extract_devname(path, &devname, devcount++);
-
- BlockDriver *drv = NULL;
- Error *errp = NULL;
-@@ -546,37 +558,49 @@ static int create_archive(int argc, char
- int percent = 0;
- int last_percent = -1;
-
-- while (1) {
-- main_loop_wait(false);
-- vma_writer_get_status(vmaw, &vmastat);
--
-- if (verbose) {
--
-- uint64_t total = 0;
-- uint64_t transferred = 0;
-- uint64_t zero_bytes = 0;
--
-- int i;
-- for (i = 0; i < 256; i++) {
-- if (vmastat.stream_info[i].size) {
-- total += vmastat.stream_info[i].size;
-- transferred += vmastat.stream_info[i].transferred;
-- zero_bytes += vmastat.stream_info[i].zero_bytes;
-+ if (devcount) {
-+ while (1) {
-+ main_loop_wait(false);
-+ vma_writer_get_status(vmaw, &vmastat);
-+
-+ if (verbose) {
-+
-+ uint64_t total = 0;
-+ uint64_t transferred = 0;
-+ uint64_t zero_bytes = 0;
-+
-+ int i;
-+ for (i = 0; i < 256; i++) {
-+ if (vmastat.stream_info[i].size) {
-+ total += vmastat.stream_info[i].size;
-+ transferred += vmastat.stream_info[i].transferred;
-+ zero_bytes += vmastat.stream_info[i].zero_bytes;
-+ }
- }
-- }
-- percent = (transferred*100)/total;
-- if (percent != last_percent) {
-- fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
-- transferred, total, zero_bytes);
-- fflush(stderr);
-+ percent = (transferred*100)/total;
-+ if (percent != last_percent) {
-+ fprintf(stderr, "progress %d%% %zd/%zd %zd\n", percent,
-+ transferred, total, zero_bytes);
-+ fflush(stderr);
-
-- last_percent = percent;
-+ last_percent = percent;
-+ }
- }
-- }
-
-- if (vmastat.closed) {
-- break;
-+ if (vmastat.closed) {
-+ break;
-+ }
- }
-+ } else {
-+ Coroutine *co = qemu_coroutine_create(backup_run_empty);
-+ qemu_coroutine_enter(co, vmaw);
-+ while (1) {
-+ main_loop_wait(false);
-+ vma_writer_get_status(vmaw, &vmastat);
-+ if (vmastat.closed) {
-+ break;
-+ }
-+ }
- }
-
- bdrv_drain_all();
-Index: new/vma.h
-===================================================================
---- new.orig/vma.h
-+++ new/vma.h
-@@ -128,6 +128,7 @@ int64_t coroutine_fn vma_writer_write(Vm
- size_t *zero_bytes);
-
- int coroutine_fn vma_writer_close_stream(VmaWriter *vmaw, uint8_t dev_id);
-+int coroutine_fn vma_writer_flush_output(VmaWriter *vmaw);
-
- int vma_writer_get_status(VmaWriter *vmaw, VmaStatus *status);
- void vma_writer_set_error(VmaWriter *vmaw, const char *fmt, ...);