These functions will be called to determine whether underlying
file that stream is transferring is currently in a data or hole.
While virStreamRegisterInData is exposed, virStreamInData does
not need to be made a public API as it will be called just
internally.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
include/libvirt/libvirt-stream.h | 23 +++++++++++
src/datatypes.h | 8 ++--
src/libvirt-stream.c | 88 ++++++++++++++++++++++++++++++++++++++++
src/libvirt_internal.h | 3 ++
src/libvirt_private.syms | 1 +
src/libvirt_public.syms | 1 +
6 files changed, 121 insertions(+), 3 deletions(-)
diff --git a/include/libvirt/libvirt-stream.h b/include/libvirt/libvirt-stream.h
index 1a5286a..3a0c986 100644
--- a/include/libvirt/libvirt-stream.h
+++ b/include/libvirt/libvirt-stream.h
@@ -69,6 +69,29 @@ int virStreamRegisterSkip(virStreamPtr stream,
int virStreamSkip(virStreamPtr st,
unsigned long long offset);
+/**
+ * virStreamInDataFunc:
+ * @stream: stream
+ * @data: are we in data or hole
+ * @offset: offset to next section
+ * @opaque: optional application provided data
+ *
+ * This callback is called whenever virStreamInData needs to
+ * check whether @stream is in data section or in hole. Check
+ * description for virStreamInData for more detailed description.
+ *
+ * Returns 0 on success (with @data and @offset updated)
+ * -1 otherwise (with @data and @offset untouched)
+ */
+typedef int (*virStreamInDataFunc)(virStreamPtr stream,
+ int *data,
+ unsigned long long *offset,
+ void *opaque);
+
+int virStreamRegisterInData(virStreamPtr stream,
+ virStreamInDataFunc inDataCb,
+ void *opaque);
+
/**
* virStreamSourceFunc:
diff --git a/src/datatypes.h b/src/datatypes.h
index 169fc46..41f1536 100644
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -569,11 +569,13 @@ struct _virStream {
virStreamDriverPtr driver;
void *privateData;
- /* Unfortunately, this can't go into virStreamDriver because
- * when register function for skipCb is called, @driver
- * is not populated yet. */
+ /* Unfortunately, these can't go into virStreamDriver because
+ * when register function for skipCb or inDataFunc is called,
+ * @driver is not populated yet. */
virStreamSkipFunc skipCb;
void *skipCbOpaque;
+ virStreamInDataFunc inDataCb;
+ void *inDataCbOpaque;
};
/**
diff --git a/src/libvirt-stream.c b/src/libvirt-stream.c
index 58665f1..371efed 100644
--- a/src/libvirt-stream.c
+++ b/src/libvirt-stream.c
@@ -396,6 +396,94 @@ virStreamSkip(virStreamPtr stream,
/**
+ * virStreamRegisterInData:
+ * @stream: stream
+ * @inDataCb: callback function
+ * @opaque: optional application provided data
+ *
+ * This function registers callback that will be called whenever
+ * virStreamInData needs to check whether @stream is currently in
+ * data or in a hole. This is to be used purely with sparse
+ * streams.
+ *
+ * Returns 0 on success,
+ * -1 otherwise.
+ */
+int
+virStreamRegisterInData(virStreamPtr stream,
+ virStreamInDataFunc inDataCb,
+ void *opaque)
+{
+ VIR_DEBUG("stream=%p, inDataCb=%p opaque=%p", stream, inDataCb, opaque);
+
+ virResetLastError();
+
+ virCheckStreamReturn(stream, -1);
+ virCheckNonNullArgReturn(inDataCb, -1);
+
+ if (stream->inDataCb) {
+ virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+ _("A inData callback is already registered"));
+ return -1;
+ }
+
+ stream->inDataCb = inDataCb;
+ stream->inDataCbOpaque = opaque;
+ return 0;
+}
+
+
+/**
+ * virStreamInData:
+ * @stream: stream
+ * @data: are we in data or hole
+ * @offset: offset to next section
+ *
+ * This function will check underlying stream (typically a file)
+ * whether the current position the stream is in lies in a data
+ * section or in a hole. Upon return @data is set to a nonzero
+ * value if former is the case, or to zero if @stream is in a
+ * hole. Moreover, @offset it updated to tell caller how much
+ * bytes can be read from @stream until current section changes
+ * (from data to a hole or vice versa).
+ *
+ * As a special case, there's an implicit hole at EOF. In this
+ * situation this function should set @data = false, @offset = 0
+ * and return 0.
+ *
+ * Returns 0 on success,
+ * -1 otherwise
+ */
+int
+virStreamInData(virStreamPtr stream,
+ int *data,
+ unsigned long long *offset)
+{
+ VIR_DEBUG("stream=%p, data=%p, offset=%p", stream, data, offset);
+
+ virResetLastError();
+
+ virCheckStreamReturn(stream, -1);
+ virCheckNonNullArgReturn(data, -1);
+ virCheckNonNullArgReturn(offset, -1);
+
+ if (stream->inDataCb) {
+ int ret;
+ ret = (stream->inDataCb)(stream, data, offset, stream->inDataCbOpaque);
+ 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_internal.h b/src/libvirt_internal.h
index 7a75491..d20acbc 100644
--- a/src/libvirt_internal.h
+++ b/src/libvirt_internal.h
@@ -298,4 +298,7 @@ int
virStreamSkipCallback(virStreamPtr stream,
unsigned long long offset);
+int virStreamInData(virStreamPtr stream,
+ int *data,
+ unsigned long long *offset);
#endif
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e83d5d6..e506d1c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1015,6 +1015,7 @@ virStateCleanup;
virStateInitialize;
virStateReload;
virStateStop;
+virStreamInData;
virStreamSkipCallback;
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 0b80d27..396fea5 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -736,6 +736,7 @@ LIBVIRT_1.3.5 {
global:
virStreamSkip;
virStreamRegisterSkip;
+ virStreamRegisterInData;
} LIBVIRT_1.3.3;
# .... define new API here using predicted next version number ....
--
2.8.1