[PATCH v2 09/17] virfile: Introduce virFileInDataDetectZeroes()

Michal Privoznik mprivozn at redhat.com
Tue Jul 7 19:46:27 UTC 2020


For given file descriptor determine if the current position it is
in plus 1MiB (arbitrary chosen value) consists solely from zero
bytes or not. This is a block device friendly version of
virFileInData().

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/libvirt_private.syms |  1 +
 src/util/virfile.c       | 67 ++++++++++++++++++++++++++++++++++++++++
 src/util/virfile.h       |  4 +++
 3 files changed, 72 insertions(+)

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 1d80aeb833..6b5a751788 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -2070,6 +2070,7 @@ virFileGetMountSubtree;
 virFileGetXAttr;
 virFileGetXAttrQuiet;
 virFileInData;
+virFileInDataDetectZeroes;
 virFileIsCDROM;
 virFileIsDir;
 virFileIsExecutable;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index c034df5931..a35d9ccb7a 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -4064,6 +4064,73 @@ virFileInData(int fd G_GNUC_UNUSED,
 #endif /* !HAVE_DECL_SEEK_HOLE */
 
 
+#define DETECT_ZEORES_BLOCK_SIZE (1 * 1024 * 1024)
+
+/*
+ * virFileInDataDetectZeroes:
+ * @fd: file to check
+ * @inData: true if current position in the @fd is in data section
+ * @length: amount of bytes until the end of the current section
+ *
+ * This behaves exactly like virFileInData() except it doesn't use SEEK_DATA
+ * and SEEK_HOLE rather than a buffer into which it reads data from @fd and
+ * detects if the buffer is full of zeroes. Therefore, it is safe to use on
+ * special files (e.g. block devices). On the other hand it sees only
+ * DETECT_ZEORES_BLOCK_SIZE ahead.
+ *
+ * Returns: 0 on success,
+ *         -1 otherwise.
+ */
+int
+virFileInDataDetectZeroes(int fd,
+                          int *inData,
+                          long long *length)
+{
+    const size_t buflen = DETECT_ZEORES_BLOCK_SIZE;
+    g_autofree char *bytes = NULL;
+    off_t cur;
+    ssize_t r;
+    int ret = -1;
+
+    /* Get current position */
+    cur = lseek(fd, 0, SEEK_CUR);
+    if (cur == (off_t) -1) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to get current position in file"));
+        goto cleanup;
+    }
+
+    bytes = g_new0(char, buflen);
+
+    if ((r = saferead(fd, bytes, buflen)) < 0) {
+        virReportSystemError(errno, "%s",
+                             _("Unable to read from file"));
+        goto cleanup;
+    }
+
+    *inData = !virStringIsNull(bytes, r);
+    *length = r;
+    ret = 0;
+
+ cleanup:
+    /* At any rate, reposition back to where we started. */
+    if (cur != (off_t) -1) {
+        int theerrno = errno;
+
+        if (lseek(fd, cur, SEEK_SET) == (off_t) -1) {
+            virReportSystemError(errno, "%s",
+                                 _("unable to restore position in file"));
+            ret = -1;
+            if (theerrno == 0)
+                theerrno = errno;
+        }
+
+        errno = theerrno;
+    }
+    return ret;
+}
+
+
 /**
  * virFileReadValueInt:
  * @value: pointer to int to be filled in with the value
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 7a92364a5c..9a5eade609 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -352,6 +352,10 @@ int virFileInData(int fd,
                   int *inData,
                   long long *length);
 
+int virFileInDataDetectZeroes(int fd,
+                              int *inData,
+                              long long *length);
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(virFileWrapperFd, virFileWrapperFdFree);
 
 int virFileGetXAttr(const char *path,
-- 
2.26.2




More information about the libvir-list mailing list