[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH v2 25/32] fdstream: Implement seek



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 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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]