Implement virStreamSkip and virStreamInData callbacks. These
callbacks do no magic, just skip a hole or detect whether we are
in a data section of a file or in a hole and how much bytes can
we read until section changes.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
src/fdstream.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/src/fdstream.c b/src/fdstream.c
index 3e92577..18a2bc0 100644
--- a/src/fdstream.c
+++ b/src/fdstream.c
@@ -482,11 +482,122 @@ static int virFDStreamRead(virStreamPtr st, char *bytes, size_t
nbytes)
}
+static int
+virFDStreamSkip(virStreamPtr st,
+ unsigned long long length)
+{
+ struct virFDStreamData *fdst = st->privateData;
+ off_t off;
+ int ret = -1;
+
+ virMutexLock(&fdst->lock);
+ if (fdst->length) {
+ if (fdst->offset + length > fdst->length) {
+ virReportSystemError(ENOSPC, "%s",
+ _("cannot write to stream"));
+ goto cleanup;
+ }
+ fdst->offset += length;
+ }
+
+ off = lseek(fdst->fd, length, SEEK_CUR);
+ if (off == (off_t) -1) {
+ virReportSystemError(errno, "%s",
+ _("unable to seek"));
+ goto cleanup;
+ }
+ ret = 0;
+ cleanup:
+ virMutexUnlock(&fdst->lock);
+ return ret;
+}
+
+
+static int
+virFDStreamInData(virStreamPtr st,
+ int *inData,
+ unsigned long long *length)
+{
+ struct virFDStreamData *fdst = st->privateData;
+ int fd;
+ off_t cur, data, hole;
+ int ret = -1;
+
+ virMutexLock(&fdst->lock);
+
+ fd = fdst->fd;
+
+ /* Get current position */
+ cur = lseek(fd, 0, SEEK_CUR);
+ if (cur == (off_t) -1) {
+ virReportSystemError(errno, "%s",
+ _("Unable to get current position in stream"));
+ goto cleanup;
+ }
+
+ /* Now try to get data and hole offsets */
+ data = lseek(fd, cur, SEEK_DATA);
+
+ /* There are four options:
+ * 1) data == cur; @cur is in data
+ * 2) data > cur; @cur is in a hole, next data at @data
+ * 3) data < 0, errno = ENXIO; either @cur is in trailing hole, or @cur is beyond
EOF.
+ * 4) data < 0, errno != ENXIO; we learned nothing
+ */
+
+ if (data == (off_t) -1) {
+ /* cases 3 and 4 */
+ if (errno != ENXIO) {
+ virReportSystemError(errno, "%s",
+ _("Unable to seek to data"));
+ goto cleanup;
+ }
+ *inData = 0;
+ *length = 0;
+ } else if (data > cur) {
+ /* case 2 */
+ *inData = 0;
+ *length = data - cur;
+ } else {
+ /* case 1 */
+ *inData = 1;
+
+ /* We don't know where does the next hole start. Let's
+ * find out. Here we get the same 4 possibilities as
+ * described above.*/
+ hole = lseek(fd, data, SEEK_HOLE);
+ if (hole == (off_t) -1 || hole == data) {
+ /* cases 1, 3 and 4 */
+ /* Wait a second. The reason why we are here is
+ * because we are in data. But at the same time we
+ * are in a trailing hole? Wut!? Do the best what we
+ * can do here. */
+ virReportSystemError(errno, "%s",
+ _("unable to seek to hole"));
+ goto cleanup;
+ } else {
+ /* case 2 */
+ *length = (hole - data);
+ }
+ }
+
+ ret = 0;
+ cleanup:
+ /* At any rate, reposition back to where we started. */
+ if (cur != (off_t) -1)
+ ignore_value(lseek(fd, cur, SEEK_SET));
+ virMutexUnlock(&fdst->lock);
+ return ret;
+}
+
+
static virStreamDriver virFDStreamDrv = {
.streamSend = virFDStreamWrite,
.streamRecv = virFDStreamRead,
.streamFinish = virFDStreamClose,
.streamAbort = virFDStreamAbort,
+ .streamSkip = virFDStreamSkip,
+ .streamInData = virFDStreamInData,
.streamEventAddCallback = virFDStreamAddCallback,
.streamEventUpdateCallback = virFDStreamUpdateCallback,
.streamEventRemoveCallback = virFDStreamRemoveCallback
--
2.8.3