This API can be used to tell the other side of the stream to skip
some bytes in the stream. This can be used to create a sparse
file on the receiving side of a stream.
It takes just one argument @length, which says how big the hole
is. Since our streams are not rewindable like regular files, we
don't need @whence argument like seek(2) has.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
include/libvirt/libvirt-stream.h | 3 +++
src/driver-stream.h | 5 ++++
src/libvirt-stream.c | 57 ++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 1 +
4 files changed, 66 insertions(+)
diff --git a/include/libvirt/libvirt-stream.h b/include/libvirt/libvirt-stream.h
index bee2516..4e0a599 100644
--- a/include/libvirt/libvirt-stream.h
+++ b/include/libvirt/libvirt-stream.h
@@ -50,6 +50,9 @@ int virStreamRecvFlags(virStreamPtr st,
size_t nbytes,
unsigned int flags);
+int virStreamSkip(virStreamPtr st,
+ unsigned long long length);
+
/**
* virStreamSourceFunc:
diff --git a/src/driver-stream.h b/src/driver-stream.h
index d4b0480..20ea13f 100644
--- a/src/driver-stream.h
+++ b/src/driver-stream.h
@@ -42,6 +42,10 @@ typedef int
unsigned int flags);
typedef int
+(*virDrvStreamSkip)(virStreamPtr st,
+ unsigned long long length);
+
+typedef int
(*virDrvStreamEventAddCallback)(virStreamPtr stream,
int events,
virStreamEventCallback cb,
@@ -68,6 +72,7 @@ struct _virStreamDriver {
virDrvStreamSend streamSend;
virDrvStreamRecv streamRecv;
virDrvStreamRecvFlags streamRecvFlags;
+ virDrvStreamSkip streamSkip;
virDrvStreamEventAddCallback streamEventAddCallback;
virDrvStreamEventUpdateCallback streamEventUpdateCallback;
virDrvStreamEventRemoveCallback streamEventRemoveCallback;
diff --git a/src/libvirt-stream.c b/src/libvirt-stream.c
index 80b2d47..55f3ef5 100644
--- a/src/libvirt-stream.c
+++ b/src/libvirt-stream.c
@@ -346,6 +346,63 @@ virStreamRecvFlags(virStreamPtr stream,
/**
+ * virStreamSkip:
+ * @stream: pointer to the stream object
+ * @length: number of bytes to skip
+ *
+ * Skip @length bytes in the stream. This is useful when there's
+ * no actual data in the stream, just a hole. If that's the case,
+ * this API can be used to skip the hole properly instead of
+ * transmitting zeroes to the other side.
+ *
+ * An example using this with a hypothetical file upload API
+ * looks like:
+ *
+ * virStream st;
+ *
+ * while (1) {
+ * char buf[4096];
+ * size_t len;
+ * if (..in hole...) {
+ * ..get hole size...
+ * virStreamSkip(st, len);
+ * } else {
+ * ...read len bytes...
+ * virStreamSend(st, buf, len);
+ * }
+ * }
+ *
+ * Returns 0 on success,
+ * -1 error
+ */
+int
+virStreamSkip(virStreamPtr stream,
+ unsigned long long length)
+{
+ VIR_DEBUG("stream=%p, length=%llu", stream, length);
+
+ virResetLastError();
+
+ virCheckStreamReturn(stream, -1);
+
+ if (stream->driver &&
+ stream->driver->streamSkip) {
+ int ret;
+ ret = (stream->driver->streamSkip)(stream, length);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(stream->conn);
+ return -1;
+}
+
+
+/**
* virStreamSendAll:
* @stream: pointer to the stream object
* @handler: source callback for reading data from application
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index d013d9f..5b536eb 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -739,6 +739,7 @@ LIBVIRT_2.0.0 {
virDomainSetGuestVcpus;
virConnectStoragePoolEventRegisterAny;
virStreamRecvFlags;
+ virStreamSkip;
} LIBVIRT_1.3.3;
--
2.8.4