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@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list