render / rpms / libvirt

Forked from rpms/libvirt 8 months ago
Clone
c401cc
From fd7349166af834cd954fed04091611f91e312a25 Mon Sep 17 00:00:00 2001
c401cc
Message-Id: <fd7349166af834cd954fed04091611f91e312a25@dist-git>
c401cc
From: Eric Blake <eblake@redhat.com>
c401cc
Date: Wed, 26 Feb 2014 14:54:34 +0100
c401cc
Subject: [PATCH] storage: refactor backing chain division of labor
c401cc
c401cc
https://bugzilla.redhat.com/show_bug.cgi?id=1032370
c401cc
c401cc
Future patches will want to learn metadata about a file using
c401cc
a buffer that was already parsed in order to probe the file's
c401cc
format.  Rather than reopening and re-reading the file, it makes
c401cc
sense to separate getting file contents from actually parsing
c401cc
those contents.
c401cc
c401cc
* src/util/virstoragefile.c (virStorageFileGetMetadataFromBuf)
c401cc
(virStorageFileGetMetadataFromFDInternal): New functions.
c401cc
(virStorageFileGetMetadataInternal): Hoist fstat() and read() into
c401cc
callers.
c401cc
(virStorageFileGetMetadataFromFD)
c401cc
(virStorageFileGetMetadataRecurse): Rework clients.
c401cc
* src/util/virstoragefile.h (virStorageFileGetMetadataFromBuf):
c401cc
New prototype.
c401cc
* src/libvirt_private.syms (virstoragefile.h): Export it.
c401cc
c401cc
Signed-off-by: Eric Blake <eblake@redhat.com>
c401cc
(cherry picked from commit 3ead2e7dedab7d9380496798ef0201be2b0047b5)
c401cc
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
c401cc
---
c401cc
 src/libvirt_private.syms  |   1 +
c401cc
 src/util/virstoragefile.c | 118 +++++++++++++++++++++++++++++++++-------------
c401cc
 src/util/virstoragefile.h |   4 ++
c401cc
 3 files changed, 91 insertions(+), 32 deletions(-)
c401cc
c401cc
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
c401cc
index e239aba..4d74d46 100644
c401cc
--- a/src/libvirt_private.syms
c401cc
+++ b/src/libvirt_private.syms
c401cc
@@ -1924,6 +1924,7 @@ virStorageFileFormatTypeToString;
c401cc
 virStorageFileFreeMetadata;
c401cc
 virStorageFileGetLVMKey;
c401cc
 virStorageFileGetMetadata;
c401cc
+virStorageFileGetMetadataFromBuf;
c401cc
 virStorageFileGetMetadataFromFD;
c401cc
 virStorageFileGetSCSIKey;
c401cc
 virStorageFileIsClusterFS;
c401cc
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
c401cc
index bb27461..8b89db1 100644
c401cc
--- a/src/util/virstoragefile.c
c401cc
+++ b/src/util/virstoragefile.c
c401cc
@@ -752,47 +752,26 @@ qcow2GetFeatures(virBitmapPtr *features,
c401cc
 }
c401cc
 
c401cc
 
c401cc
-/* Given a file descriptor FD open on PATH, and optionally opened from
c401cc
- * a given DIRECTORY, return metadata about that file, assuming it has
c401cc
- * the given FORMAT. */
c401cc
+/* Given a header in BUF with length LEN, as parsed from the file
c401cc
+ * located at PATH, and optionally opened from a given DIRECTORY,
c401cc
+ * return metadata about that file, assuming it has the given
c401cc
+ * FORMAT. */
c401cc
 static virStorageFileMetadataPtr
c401cc
 virStorageFileGetMetadataInternal(const char *path,
c401cc
-                                  int fd,
c401cc
+                                  char *buf,
c401cc
+                                  size_t len,
c401cc
                                   const char *directory,
c401cc
                                   int format)
c401cc
 {
c401cc
     virStorageFileMetadata *meta = NULL;
c401cc
-    char *buf = NULL;
c401cc
-    ssize_t len = STORAGE_MAX_HEAD;
c401cc
     virStorageFileMetadata *ret = NULL;
c401cc
-    struct stat sb;
c401cc
 
c401cc
-    VIR_DEBUG("path=%s, fd=%d, format=%d", path, fd, format);
c401cc
+    VIR_DEBUG("path=%s, buf=%p, len=%zu, directory=%s, format=%d",
c401cc
+              path, buf, len, NULLSTR(directory), format);
c401cc
 
c401cc
     if (VIR_ALLOC(meta) < 0)
c401cc
         return NULL;
c401cc
 
c401cc
-    if (fstat(fd, &sb) < 0) {
c401cc
-        virReportSystemError(errno,
c401cc
-                             _("cannot stat file '%s'"),
c401cc
-                             path);
c401cc
-        goto cleanup;
c401cc
-    }
c401cc
-
c401cc
-    /* No header to probe for directories, but also no backing file */
c401cc
-    if (S_ISDIR(sb.st_mode))
c401cc
-        return meta;
c401cc
-
c401cc
-    if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
c401cc
-        virReportSystemError(errno, _("cannot seek to start of '%s'"), path);
c401cc
-        goto cleanup;
c401cc
-    }
c401cc
-
c401cc
-    if ((len = virFileReadHeaderFD(fd, len, (char **)&buf)) < 0) {
c401cc
-        virReportSystemError(errno, _("cannot read header '%s'"), path);
c401cc
-        goto cleanup;
c401cc
-    }
c401cc
-
c401cc
     if (format == VIR_STORAGE_FILE_AUTO)
c401cc
         format = virStorageFileProbeFormatFromBuf(path, buf, len);
c401cc
 
c401cc
@@ -893,7 +872,6 @@ done:
c401cc
 
c401cc
 cleanup:
c401cc
     virStorageFileFreeMetadata(meta);
c401cc
-    VIR_FREE(buf);
c401cc
     return ret;
c401cc
 }
c401cc
 
c401cc
@@ -979,6 +957,81 @@ virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid)
c401cc
     return ret;
c401cc
 }
c401cc
 
c401cc
+
c401cc
+/**
c401cc
+ * virStorageFileGetMetadataFromBuf:
c401cc
+ * @path: name of file, for error messages
c401cc
+ * @buf: header bytes from @path
c401cc
+ * @len: length of @buf
c401cc
+ * @format: expected image format
c401cc
+ *
c401cc
+ * Extract metadata about the storage volume with the specified
c401cc
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
c401cc
+ * will probe to automatically identify the format.  Does not recurse.
c401cc
+ *
c401cc
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
c401cc
+ * format, since a malicious guest can turn a raw file into any
c401cc
+ * other non-raw format at will.
c401cc
+ *
c401cc
+ * If the returned meta.backingStoreFormat is VIR_STORAGE_FILE_AUTO
c401cc
+ * it indicates the image didn't specify an explicit format for its
c401cc
+ * backing store. Callers are advised against probing for the
c401cc
+ * backing store format in this case.
c401cc
+ *
c401cc
+ * Caller MUST free the result after use via virStorageFileFreeMetadata.
c401cc
+ */
c401cc
+virStorageFileMetadataPtr
c401cc
+virStorageFileGetMetadataFromBuf(const char *path,
c401cc
+                                 char *buf,
c401cc
+                                 size_t len,
c401cc
+                                 int format)
c401cc
+{
c401cc
+    return virStorageFileGetMetadataInternal(path, buf, len, NULL, format);
c401cc
+}
c401cc
+
c401cc
+
c401cc
+/* Internal version that also supports a containing directory name.  */
c401cc
+static virStorageFileMetadataPtr
c401cc
+virStorageFileGetMetadataFromFDInternal(const char *path,
c401cc
+                                        int fd,
c401cc
+                                        const char *directory,
c401cc
+                                        int format)
c401cc
+{
c401cc
+    char *buf = NULL;
c401cc
+    ssize_t len = STORAGE_MAX_HEAD;
c401cc
+    struct stat sb;
c401cc
+    virStorageFileMetadataPtr ret = NULL;
c401cc
+
c401cc
+    if (fstat(fd, &sb) < 0) {
c401cc
+        virReportSystemError(errno,
c401cc
+                             _("cannot stat file '%s'"),
c401cc
+                             path);
c401cc
+        return NULL;
c401cc
+    }
c401cc
+
c401cc
+    /* No header to probe for directories, but also no backing file */
c401cc
+    if (S_ISDIR(sb.st_mode)) {
c401cc
+        ignore_value(VIR_ALLOC(ret));
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    if (lseek(fd, 0, SEEK_SET) == (off_t)-1) {
c401cc
+        virReportSystemError(errno, _("cannot seek to start of '%s'"), path);
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) {
c401cc
+        virReportSystemError(errno, _("cannot read header '%s'"), path);
c401cc
+        goto cleanup;
c401cc
+    }
c401cc
+
c401cc
+    ret = virStorageFileGetMetadataInternal(path, buf, len, directory, format);
c401cc
+cleanup:
c401cc
+    VIR_FREE(buf);
c401cc
+    return ret;
c401cc
+}
c401cc
+
c401cc
+
c401cc
 /**
c401cc
  * virStorageFileGetMetadataFromFD:
c401cc
  *
c401cc
@@ -1002,9 +1055,10 @@ virStorageFileGetMetadataFromFD(const char *path,
c401cc
                                 int fd,
c401cc
                                 int format)
c401cc
 {
c401cc
-    return virStorageFileGetMetadataInternal(path, fd, NULL, format);
c401cc
+    return virStorageFileGetMetadataFromFDInternal(path, fd, NULL, format);
c401cc
 }
c401cc
 
c401cc
+
c401cc
 /* Recursive workhorse for virStorageFileGetMetadata.  */
c401cc
 static virStorageFileMetadataPtr
c401cc
 virStorageFileGetMetadataRecurse(const char *path, const char *directory,
c401cc
@@ -1031,7 +1085,7 @@ virStorageFileGetMetadataRecurse(const char *path, const char *directory,
c401cc
         return NULL;
c401cc
     }
c401cc
 
c401cc
-    ret = virStorageFileGetMetadataInternal(path, fd, directory, format);
c401cc
+    ret = virStorageFileGetMetadataFromFDInternal(path, fd, directory, format);
c401cc
 
c401cc
     if (VIR_CLOSE(fd) < 0)
c401cc
         VIR_WARN("could not close file %s", path);
c401cc
diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h
c401cc
index 1f89839..5fc8832 100644
c401cc
--- a/src/util/virstoragefile.h
c401cc
+++ b/src/util/virstoragefile.h
c401cc
@@ -90,6 +90,10 @@ virStorageFileMetadataPtr virStorageFileGetMetadata(const char *path,
c401cc
 virStorageFileMetadataPtr virStorageFileGetMetadataFromFD(const char *path,
c401cc
                                                           int fd,
c401cc
                                                           int format);
c401cc
+virStorageFileMetadataPtr virStorageFileGetMetadataFromBuf(const char *path,
c401cc
+                                                           char *buf,
c401cc
+                                                           size_t len,
c401cc
+                                                           int format);
c401cc
 int virStorageFileChainGetBroken(virStorageFileMetadataPtr chain,
c401cc
                                  char **broken_file);
c401cc
 
c401cc
-- 
c401cc
1.9.0
c401cc