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