]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
storage: avoid short reads while chasing backing chain
authorEric Blake <eblake@redhat.com>
Tue, 5 Nov 2013 17:30:56 +0000 (10:30 -0700)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 18 Feb 2014 15:53:08 +0000 (15:53 +0000)
Our backing file chain code was not very robust to an ill-timed
EINTR, which could lead to a short read causing us to randomly
treat metadata differently than usual.  But the existing
virFileReadLimFD forces an error if we don't read the entire
file, even though we only care about the header of the file.
So add a new virFile function that does what we want.

* src/util/virfile.h (virFileReadHeaderFD): New prototype.
* src/util/virfile.c (virFileReadHeaderFD): New function.
* src/libvirt_private.syms (virfile.h): Export it.
* src/util/virstoragefile.c (virStorageFileGetMetadataInternal)
(virStorageFileProbeFormatFromFD): Use it.

Signed-off-by: Eric Blake <eblake@redhat.com>
(cherry picked from commit 5327fad4f292e4f3f84884ffe158c492bf00519c)

Conflicts:
src/util/virstoragefile.c: OOM error reporting & buffer signedness

src/libvirt_private.syms
src/util/virfile.c
src/util/virfile.h
src/util/virstoragefile.c

index 753c698d4b7f3bdea153ff472bf494cb71d10409..ba3906b3485682394441fdf434f15a0f953aa974 100644 (file)
@@ -1351,6 +1351,7 @@ virFileOpenAs;
 virFileOpenTty;
 virFilePrintf;
 virFileReadAll;
+virFileReadHeaderFD;
 virFileReadLimFD;
 virFileResolveAllLinks;
 virFileResolveLink;
index e0b71ed57842a452e4d9e4606aacb80ca2c8cd5d..058bb290b3af5733a617971b32f69b0db5d7fca2 100644 (file)
@@ -1161,6 +1161,27 @@ saferead_lim(int fd, size_t max_len, size_t *length)
     return NULL;
 }
 
+
+/* A wrapper around saferead_lim that merely stops reading at the
+ * specified maximum size.  */
+int
+virFileReadHeaderFD(int fd, int maxlen, char **buf)
+{
+    size_t len;
+    char *s;
+
+    if (maxlen <= 0) {
+        errno = EINVAL;
+        return -1;
+    }
+    s = saferead_lim(fd, maxlen, &len);
+    if (s == NULL)
+        return -1;
+    *buf = s;
+    return len;
+}
+
+
 /* A wrapper around saferead_lim that maps a failure due to
    exceeding the maximum size limitation to EOVERFLOW.  */
 int
index 72d35ce4ebe9b76d9ddc489838c9f98b291119bb..e2e708acca965fc36a5f39aa27f112141471f5ab 100644 (file)
@@ -122,9 +122,12 @@ int virFileNBDDeviceAssociate(const char *file,
 
 int virFileDeleteTree(const char *dir);
 
-int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
-
-int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
+int virFileReadHeaderFD(int fd, int maxlen, char **buf)
+    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(3);
+int virFileReadLimFD(int fd, int maxlen, char **buf)
+    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(3);
+int virFileReadAll(const char *path, int maxlen, char **buf)
+    ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3);
 
 int virFileWriteStr(const char *path, const char *str, mode_t mode)
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
index 27aa4febee8b0803e8cf615e06d0054e53dc4b37..af7836880aedc1f16b9881951ca9b88e375bf3b2 100644 (file)
@@ -792,12 +792,7 @@ virStorageFileGetMetadataInternal(const char *path,
         goto cleanup;
     }
 
-    if (VIR_ALLOC_N(buf, len) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if ((len = read(fd, buf, len)) < 0) {
+    if ((len = virFileReadHeaderFD(fd, len, (char **)&buf)) < 0) {
         virReportSystemError(errno, _("cannot read header '%s'"), path);
         goto cleanup;
     }
@@ -940,17 +935,12 @@ virStorageFileProbeFormatFromFD(const char *path, int fd)
         return VIR_STORAGE_FILE_DIR;
     }
 
-    if (VIR_ALLOC_N(head, len) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
     if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
         virReportSystemError(errno, _("cannot set to start of '%s'"), path);
         goto cleanup;
     }
 
-    if ((len = read(fd, head, len)) < 0) {
+    if ((len = virFileReadHeaderFD(fd, len, (char **)&head)) < 0) {
         virReportSystemError(errno, _("cannot read header '%s'"), path);
         goto cleanup;
     }