The command grew new --sparse switch that does nothing more than
enables the sparse streams feature for this command. Among with
the switch new helper function is introduced: virshStreamSkip().
This is the callback that is called whenever daemon sends us a
hole. In the callback we reflect the hole in underlying file by
seeking as many bytes as told.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
tools/virsh-volume.c | 12 ++++++++++--
tools/virsh.c | 8 ++++++++
tools/virsh.h | 3 +++
tools/virsh.pod | 3 ++-
4 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c
index d35fee1..27744c7 100644
--- a/tools/virsh-volume.c
+++ b/tools/virsh-volume.c
@@ -762,6 +762,10 @@ static const vshCmdOptDef opts_vol_download[] = {
.type = VSH_OT_INT,
.help = N_("amount of data to download")
},
+ {.name = "sparse",
+ .type = VSH_OT_BOOL,
+ .help = N_("preserve sparseness of volume")
+ },
{.name = NULL}
};
@@ -777,6 +781,7 @@ cmdVolDownload(vshControl *ctl, const vshCmd *cmd)
unsigned long long offset = 0, length = 0;
bool created = false;
virshControlPtr priv = ctl->privData;
+ unsigned int flags = 0;
if (vshCommandOptULongLong(ctl, cmd, "offset", &offset) < 0)
return false;
@@ -790,6 +795,9 @@ cmdVolDownload(vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptStringReq(ctl, cmd, "file", &file) < 0)
goto cleanup;
+ if (vshCommandOptBool(cmd, "sparse"))
+ flags |= VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM;
+
if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) {
if (errno != EEXIST ||
(fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) {
@@ -805,12 +813,12 @@ cmdVolDownload(vshControl *ctl, const vshCmd *cmd)
goto cleanup;
}
- if (virStorageVolDownload(vol, st, offset, length, 0) < 0) {
+ if (virStorageVolDownload(vol, st, offset, length, flags) < 0) {
vshError(ctl, _("cannot download from volume %s"), name);
goto cleanup;
}
- if (virStreamRecvAll(st, virshStreamSink, &fd) < 0) {
+ if (virStreamSparseRecvAll(st, virshStreamSink, virshStreamSkip, &fd) < 0) {
vshError(ctl, _("cannot receive data from volume %s"), name);
goto cleanup;
}
diff --git a/tools/virsh.c b/tools/virsh.c
index 2a807d9..2f0f46a 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -263,6 +263,14 @@ int virshStreamSink(virStreamPtr st ATTRIBUTE_UNUSED,
return safewrite(*fd, bytes, nbytes);
}
+int virshStreamSkip(virStreamPtr st ATTRIBUTE_UNUSED,
+ unsigned long long offset, void *opaque)
+{
+ int *fd = opaque;
+
+ return lseek(*fd, offset, SEEK_CUR) == (off_t) -1 ? -1 : 0;
+}
+
/* ---------------
* Command Connect
* ---------------
diff --git a/tools/virsh.h b/tools/virsh.h
index fd552bb..5c382ef 100644
--- a/tools/virsh.h
+++ b/tools/virsh.h
@@ -150,4 +150,7 @@ int virshDomainState(vshControl *ctl, virDomainPtr dom, int *reason);
int virshStreamSink(virStreamPtr st, const char *bytes, size_t nbytes,
void *opaque);
+int virshStreamSkip(virStreamPtr st,
+ unsigned long long offset, void *opaque);
+
#endif /* VIRSH_H */
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 6844823..36a15f8 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -3581,12 +3581,13 @@ regarding possible target volume and pool changes as a result of
the
pool refresh when the upload is attempted.
=item B<vol-download> [I<--pool> I<pool-or-uuid>] [I<--offset>
I<bytes>]
-[I<--length> I<bytes>] I<vol-name-or-key-or-path> I<local-file>
+[I<--length> I<bytes>] [I<--sparse>] I<vol-name-or-key-or-path>
I<local-file>
Download the contents of a storage volume to I<local-file>.
I<--pool> I<pool-or-uuid> is the name or UUID of the storage pool the volume
is in.
I<vol-name-or-key-or-path> is the name or key or path of the volume to download.
+If I<--sparse> is specified, this command will preserve volume sparseness.
I<--offset> is the position in the storage volume at which to start reading
the data. The value must be 0 or larger. I<--length> is an upper bound of
the amount of data to be downloaded. A negative value is interpreted as
--
2.8.3