When dealing with sparse files we need to be able to jump over
holes as there's no added value in reading/writing them. For
that, we need new set of send and receive APIs that will have
@offset argument. Sending data to a stream would be easy - just
say from which offset we are sending data. Reading is a bit
tricky - we need read function which can detect holes and thus
when requested to read from one it will set @offset to new value
that contains data.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
include/libvirt/libvirt-stream.h | 8 +++
src/driver-stream.h | 13 +++++
src/libvirt-stream.c | 113 +++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 6 +++
4 files changed, 140 insertions(+)
diff --git a/include/libvirt/libvirt-stream.h b/include/libvirt/libvirt-stream.h
index 831640d..5a2bde3 100644
--- a/include/libvirt/libvirt-stream.h
+++ b/include/libvirt/libvirt-stream.h
@@ -40,11 +40,19 @@ int virStreamRef(virStreamPtr st);
int virStreamSend(virStreamPtr st,
const char *data,
size_t nbytes);
+int virStreamSendOffset(virStreamPtr stream,
+ unsigned long long offset,
+ const char *data,
+ size_t nbytes);
int virStreamRecv(virStreamPtr st,
char *data,
size_t nbytes);
+int virStreamRecvOffset(virStreamPtr stream,
+ unsigned long long *offset,
+ char *data,
+ size_t nbytes);
/**
* virStreamSourceFunc:
diff --git a/src/driver-stream.h b/src/driver-stream.h
index 85b4e3b..5419b85 100644
--- a/src/driver-stream.h
+++ b/src/driver-stream.h
@@ -31,9 +31,20 @@ typedef int
size_t nbytes);
typedef int
+(*virDrvStreamSendOffset)(virStreamPtr st,
+ unsigned long long offset,
+ const char *data,
+ size_t nbytes);
+
+typedef int
(*virDrvStreamRecv)(virStreamPtr st,
char *data,
size_t nbytes);
+typedef int
+(*virDrvStreamRecvOffset)(virStreamPtr st,
+ unsigned long long *offset,
+ char *data,
+ size_t nbytes);
typedef int
(*virDrvStreamEventAddCallback)(virStreamPtr stream,
@@ -60,7 +71,9 @@ typedef virStreamDriver *virStreamDriverPtr;
struct _virStreamDriver {
virDrvStreamSend streamSend;
+ virDrvStreamSendOffset streamSendOffset;
virDrvStreamRecv streamRecv;
+ virDrvStreamRecvOffset streamRecvOffset;
virDrvStreamEventAddCallback streamEventAddCallback;
virDrvStreamEventUpdateCallback streamEventUpdateCallback;
virDrvStreamEventRemoveCallback streamEventRemoveCallback;
diff --git a/src/libvirt-stream.c b/src/libvirt-stream.c
index c16f586..1df188c 100644
--- a/src/libvirt-stream.c
+++ b/src/libvirt-stream.c
@@ -192,6 +192,58 @@ virStreamSend(virStreamPtr stream,
/**
+ * virStreamSendOffset:
+ * @stream: pointer to the stream object
+ * @offset: <something>
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Sends some data down the pipe.
+ *
+ * Returns the number of bytes written, which may be less
+ * than requested.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if the outgoing transmit buffers are full &
+ * the stream is marked as non-blocking.
+ */
+int
+virStreamSendOffset(virStreamPtr stream,
+ unsigned long long offset,
+ const char *data,
+ size_t nbytes)
+{
+ VIR_DEBUG("stream=%p, offset=%llu, data=%p, nbytes=%zu",
+ stream, offset, data, nbytes);
+
+ virResetLastError();
+
+ virCheckStreamReturn(stream, -1);
+ virCheckNonNullArgGoto(data, error);
+
+ if (stream->driver &&
+ stream->driver->streamSendOffset) {
+ int ret;
+ ret = (stream->driver->streamSendOffset)(stream, offset, data, nbytes);
+ if (ret == -2)
+ return -2;
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virReportUnsupportedError();
+
+ error:
+ virDispatchError(stream->conn);
+ return -1;
+}
+
+
+/**
* virStreamRecv:
* @stream: pointer to the stream object
* @data: buffer to read into from stream
@@ -285,6 +337,67 @@ virStreamRecv(virStreamPtr stream,
/**
+ * virStreamRecvOffset:
+ * @stream: pointer to the stream object
+ * @offset: <something>
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Recieve some data from stream. On return set offset to next location.
+ *
+ * Returns the number of bytes read, which may be less
+ * than requested.
+ *
+ * Returns 0 when either the end of the stream is reached, or
+ * there are no data to be sent at current @offset. In case of
+ * the former, the stream should be finished by calling
+ * virStreamFinish(). However, in case of the latter, @offset
+ * should be set to new position where interesting data is.
+ * Failing to do so will result in assumption that there is no
+ * data left.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if there is no data pending to be read & the
+ * stream is marked as non-blocking.
+ */
+int
+virStreamRecvOffset(virStreamPtr stream,
+ unsigned long long *offset,
+ char *data,
+ size_t nbytes)
+{
+ VIR_DEBUG("stream=%p, offset=%p, data=%p, nbytes=%zu",
+ stream, offset, data, nbytes);
+
+ virResetLastError();
+
+ virCheckStreamReturn(stream, -1);
+ virCheckNonNullArgGoto(offset, error);
+ virCheckNonNullArgGoto(data, error);
+
+ if (stream->driver &&
+ stream->driver->streamRecvOffset) {
+ int ret;
+ ret = (stream->driver->streamRecvOffset)(stream, offset, data, nbytes);
+ if (ret == -2)
+ return -2;
+ 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 dd94191..4229df9 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -725,4 +725,10 @@ LIBVIRT_1.2.19 {
virDomainRename;
} LIBVIRT_1.2.17;
+LIBVIRT_1.3.1 {
+ global:
+ virStreamRecvOffset;
+ virStreamSendOffset;
+} LIBVIRT_1.2.19;
+
# .... define new API here using predicted next version number ....
--
2.4.10