--- /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 2014-04-14 08:40:47.000000000 +0200
++++ new/vma-reader.c 2014-04-14 10:33:00.000000000 +0200
+@@ -334,11 +334,6 @@
+ }
+ }
+
+- 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 @@
+ }
+
+ 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 bocks %.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 bocks %.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 2014-04-14 08:40:47.000000000 +0200
++++ new/vma-writer.c 2014-04-14 11:00:45.000000000 +0200
+@@ -257,7 +257,7 @@
+ }
+
+ vmaw->co_writer = NULL;
+-
++
+ return (done == bytes) ? bytes : -1;
+ }
+
+@@ -381,10 +381,6 @@
+ 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]);
+@@ -501,6 +497,23 @@
+ 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)
+@@ -528,12 +541,7 @@
+
+ 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 2014-04-14 08:40:47.000000000 +0200
++++ new/vma.c 2014-04-14 10:50:24.000000000 +0200
+@@ -33,7 +33,7 @@
+ "\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 @@
+
+ #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 @@
+ }
+
+
+- /* 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 @@
+ 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;
+ BlockDriverState *bs = bdrv_new(devname);
+@@ -546,37 +558,42 @@
+ 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);
+ }
+
+ bdrv_drain_all();
+Index: new/vma.h
+===================================================================
+--- new.orig/vma.h 2014-04-14 08:40:47.000000000 +0200
++++ new/vma.h 2014-04-14 10:50:00.000000000 +0200
+@@ -128,6 +128,7 @@
+ 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, ...);