summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <eblake@redhat.com>2013-11-05 10:30:56 -0700
committerDaniel P. Berrange <berrange@redhat.com>2014-02-18 15:52:22 +0000
commitaaba652d2ba2a3a258c6b36d109ada59824cedce (patch)
tree8dd6d265be44524f6a56af5f3dc4429d1d68183a
parent5daffc54b0815c49146cb6174c28954252542247 (diff)
downloadlibvirt-aaba652d2ba2a3a258c6b36d109ada59824cedce.tar.gz
storage: avoid short reads while chasing backing chain
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: buffer signedness
-rw-r--r--src/libvirt_private.syms1
-rw-r--r--src/util/virfile.c21
-rw-r--r--src/util/virfile.h9
-rw-r--r--src/util/virstoragefile.c10
4 files changed, 30 insertions, 11 deletions
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index e49ee718e2..49d2639c27 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1383,6 +1383,7 @@ virFileOpenAs;
virFileOpenTty;
virFilePrintf;
virFileReadAll;
+virFileReadHeaderFD;
virFileReadLimFD;
virFileResolveAllLinks;
virFileResolveLink;
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 18246a2a3d..4189c9cb99 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -1149,6 +1149,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
diff --git a/src/util/virfile.h b/src/util/virfile.h
index 72d35ce4eb..e2e708acca 100644
--- a/src/util/virfile.h
+++ b/src/util/virfile.h
@@ -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;
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
index cb6df91642..53762dc09d 100644
--- a/src/util/virstoragefile.c
+++ b/src/util/virstoragefile.c
@@ -781,10 +781,7 @@ virStorageFileGetMetadataInternal(const char *path,
goto cleanup;
}
- if (VIR_ALLOC_N(buf, len) < 0)
- 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;
}
@@ -927,15 +924,12 @@ virStorageFileProbeFormatFromFD(const char *path, int fd)
return VIR_STORAGE_FILE_DIR;
}
- if (VIR_ALLOC_N(head, len) < 0)
- 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;
}