src/storage/storage_backend_vstorage.c
src/storage/storage_backend_zfs.c
src/storage/storage_driver.c
-src/storage/storage_source.c
-src/storage/storage_source_backend.c
src/storage/storage_util.c
src/test/test_driver.c
src/uml/uml_conf.c
src/util/virsocketaddr.c
src/util/virstorageencryption.c
src/util/virstoragefile.c
+src/util/virstoragefilebackend.c
src/util/virstring.c
src/util/virsysinfo.c
src/util/virthreadjob.c
util/virsocketaddr.h util/virsocketaddr.c \
util/virstorageencryption.c util/virstorageencryption.h \
util/virstoragefile.c util/virstoragefile.h \
+ util/virstoragefilebackend.c util/virstoragefilebackend.h \
util/virstring.h util/virstring.c \
util/virsysinfo.c util/virsysinfo.h util/virsysinfopriv.h \
util/virsystemd.c util/virsystemd.h util/virsystemdpriv.h \
STORAGE_DRIVER_SOURCES = \
storage/storage_driver.h storage/storage_driver.c \
- storage/storage_source.h storage/storage_source.c \
- storage/storage_source_backend.h storage/storage_source_backend.c \
$(STORAGE_DRIVER_BACKEND_SOURCES) \
storage/storage_util.h storage/storage_util.c
virStorageAuthDefFormat;
virStorageAuthDefFree;
virStorageAuthDefParse;
+virStorageFileAccess;
virStorageFileCanonicalizePath;
virStorageFileChainGetBroken;
virStorageFileChainLookup;
+virStorageFileChown;
+virStorageFileCreate;
+virStorageFileDeinit;
virStorageFileFeatureTypeFromString;
virStorageFileFeatureTypeToString;
virStorageFileFormatTypeFromString;
virStorageFileFormatTypeToString;
+virStorageFileGetBackingStoreStr;
virStorageFileGetLVMKey;
+virStorageFileGetMetadata;
virStorageFileGetMetadataFromBuf;
virStorageFileGetMetadataFromFD;
virStorageFileGetMetadataInternal;
virStorageFileGetRelativeBackingPath;
virStorageFileGetSCSIKey;
+virStorageFileGetUniqueIdentifier;
+virStorageFileInit;
+virStorageFileInitAs;
virStorageFileIsClusterFS;
virStorageFileParseBackingStoreStr;
virStorageFileParseChainIndex;
virStorageFileProbeFormat;
+virStorageFileRead;
+virStorageFileReportBrokenChain;
virStorageFileResize;
+virStorageFileStat;
+virStorageFileSupportsAccess;
+virStorageFileSupportsSecurityDriver;
+virStorageFileUnlink;
virStorageIsFile;
virStorageIsRelative;
virStorageNetHostDefClear;
virStorageTypeToString;
+# util/virstoragefilebackend.h
+virStorageFileBackendRegister;
+
+
# util/virstring.h
virArgvToString;
virAsprintfInternal;
#include "locking/domain_lock.h"
#include "storage/storage_driver.h"
-#include "storage/storage_source.h"
#ifdef MAJOR_IN_MKDEV
# include <sys/mkdev.h>
#include "viraccessapicheck.h"
#include "viraccessapicheckqemu.h"
#include "storage/storage_driver.h"
-#include "storage/storage_source.h"
#include "virhostdev.h"
#include "domain_capabilities.h"
#include "vircgroup.h"
#include "virgettext.h"
#include "virhostdev.h"
-#include "storage/storage_source.h"
-
#define VIR_FROM_THIS VIR_FROM_SECURITY
static char *progname;
#include "virerror.h"
#include "storage_backend_fs.h"
-#include "storage_source_backend.h"
#include "storage_util.h"
#include "storage_conf.h"
-#include "virstoragefile.h"
+#include "virstoragefilebackend.h"
#include "vircommand.h"
#include "viralloc.h"
#include "virxml.h"
#include <glusterfs/api/glfs.h>
#include "storage_backend_gluster.h"
-#include "storage_source_backend.h"
#include "storage_conf.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
-#include "virstoragefile.h"
+#include "virstoragefilebackend.h"
#include "virstring.h"
#include "viruri.h"
#include "storage_util.h"
+++ /dev/null
-/*
- * storage_source.c: Storage source object accessors to real storage
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-#include <config.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <string.h>
-
-#include "virerror.h"
-#include "storage_source.h"
-#include "storage_source_backend.h"
-#include "viralloc.h"
-#include "virlog.h"
-#include "virstring.h"
-#include "virhash.h"
-
-#define VIR_FROM_THIS VIR_FROM_STORAGE
-
-VIR_LOG_INIT("storage.storage_source");
-
-
-static bool
-virStorageFileIsInitialized(const virStorageSource *src)
-{
- return src && src->drv;
-}
-
-
-static virStorageFileBackendPtr
-virStorageFileGetBackendForSupportCheck(const virStorageSource *src)
-{
- int actualType;
-
- if (!src)
- return NULL;
-
- if (src->drv)
- return src->drv->backend;
-
- actualType = virStorageSourceGetActualType(src);
-
- return virStorageFileBackendForTypeInternal(actualType, src->protocol, false);
-}
-
-
-static bool
-virStorageFileSupportsBackingChainTraversal(virStorageSourcePtr src)
-{
- virStorageFileBackendPtr backend;
-
- if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
- return false;
-
- return backend->storageFileGetUniqueIdentifier &&
- backend->storageFileRead &&
- backend->storageFileAccess;
-}
-
-
-/**
- * virStorageFileSupportsSecurityDriver:
- *
- * @src: a storage file structure
- *
- * Check if a storage file supports operations needed by the security
- * driver to perform labelling
- */
-bool
-virStorageFileSupportsSecurityDriver(const virStorageSource *src)
-{
- virStorageFileBackendPtr backend;
-
- if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
- return false;
-
- return !!backend->storageFileChown;
-}
-
-
-/**
- * virStorageFileSupportsAccess:
- *
- * @src: a storage file structure
- *
- * Check if a storage file supports checking if the storage source is accessible
- * for the given vm.
- */
-bool
-virStorageFileSupportsAccess(const virStorageSource *src)
-{
- virStorageFileBackendPtr backend;
-
- if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
- return false;
-
- return !!backend->storageFileAccess;
-}
-
-
-void
-virStorageFileDeinit(virStorageSourcePtr src)
-{
- if (!virStorageFileIsInitialized(src))
- return;
-
- if (src->drv->backend &&
- src->drv->backend->backendDeinit)
- src->drv->backend->backendDeinit(src);
-
- VIR_FREE(src->drv);
-}
-
-
-/**
- * virStorageFileInitAs:
- *
- * @src: storage source definition
- * @uid: uid used to access the file, or -1 for current uid
- * @gid: gid used to access the file, or -1 for current gid
- *
- * Initialize a storage source to be used with storage driver. Use the provided
- * uid and gid if possible for the operations.
- *
- * Returns 0 if the storage file was successfully initialized, -1 if the
- * initialization failed. Libvirt error is reported.
- */
-int
-virStorageFileInitAs(virStorageSourcePtr src,
- uid_t uid, gid_t gid)
-{
- int actualType = virStorageSourceGetActualType(src);
- if (VIR_ALLOC(src->drv) < 0)
- return -1;
-
- if (uid == (uid_t) -1)
- src->drv->uid = geteuid();
- else
- src->drv->uid = uid;
-
- if (gid == (gid_t) -1)
- src->drv->gid = getegid();
- else
- src->drv->gid = gid;
-
- if (!(src->drv->backend = virStorageFileBackendForType(actualType,
- src->protocol)))
- goto error;
-
- if (src->drv->backend->backendInit &&
- src->drv->backend->backendInit(src) < 0)
- goto error;
-
- return 0;
-
- error:
- VIR_FREE(src->drv);
- return -1;
-}
-
-
-/**
- * virStorageFileInit:
- *
- * See virStorageFileInitAs. The file is initialized to be accessed by the
- * current user.
- */
-int
-virStorageFileInit(virStorageSourcePtr src)
-{
- return virStorageFileInitAs(src, -1, -1);
-}
-
-
-/**
- * virStorageFileCreate: Creates an empty storage file via storage driver
- *
- * @src: file structure pointing to the file
- *
- * Returns 0 on success, -2 if the function isn't supported by the backend,
- * -1 on other failure. Errno is set in case of failure.
- */
-int
-virStorageFileCreate(virStorageSourcePtr src)
-{
- int ret;
-
- if (!virStorageFileIsInitialized(src) ||
- !src->drv->backend->storageFileCreate) {
- errno = ENOSYS;
- return -2;
- }
-
- ret = src->drv->backend->storageFileCreate(src);
-
- VIR_DEBUG("created storage file %p: ret=%d, errno=%d",
- src, ret, errno);
-
- return ret;
-}
-
-
-/**
- * virStorageFileUnlink: Unlink storage file via storage driver
- *
- * @src: file structure pointing to the file
- *
- * Unlinks the file described by the @file structure.
- *
- * Returns 0 on success, -2 if the function isn't supported by the backend,
- * -1 on other failure. Errno is set in case of failure.
- */
-int
-virStorageFileUnlink(virStorageSourcePtr src)
-{
- int ret;
-
- if (!virStorageFileIsInitialized(src) ||
- !src->drv->backend->storageFileUnlink) {
- errno = ENOSYS;
- return -2;
- }
-
- ret = src->drv->backend->storageFileUnlink(src);
-
- VIR_DEBUG("unlinked storage file %p: ret=%d, errno=%d",
- src, ret, errno);
-
- return ret;
-}
-
-
-/**
- * virStorageFileStat: returns stat struct of a file via storage driver
- *
- * @src: file structure pointing to the file
- * @stat: stat structure to return data
- *
- * Returns 0 on success, -2 if the function isn't supported by the backend,
- * -1 on other failure. Errno is set in case of failure.
-*/
-int
-virStorageFileStat(virStorageSourcePtr src,
- struct stat *st)
-{
- int ret;
-
- if (!virStorageFileIsInitialized(src) ||
- !src->drv->backend->storageFileStat) {
- errno = ENOSYS;
- return -2;
- }
-
- ret = src->drv->backend->storageFileStat(src, st);
-
- VIR_DEBUG("stat of storage file %p: ret=%d, errno=%d",
- src, ret, errno);
-
- return ret;
-}
-
-
-/**
- * virStorageFileRead: read bytes from a file into a buffer
- *
- * @src: file structure pointing to the file
- * @offset: number of bytes to skip in the storage file
- * @len: maximum number of bytes read from the storage file
- * @buf: buffer to read the data into. (buffer shall be freed by caller)
- *
- * Returns the count of bytes read on success and -1 on failure, -2 if the
- * function isn't supported by the backend.
- * Libvirt error is reported on failure.
- */
-ssize_t
-virStorageFileRead(virStorageSourcePtr src,
- size_t offset,
- size_t len,
- char **buf)
-{
- ssize_t ret;
-
- if (!virStorageFileIsInitialized(src)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("storage file backend not initialized"));
- return -1;
- }
-
- if (!src->drv->backend->storageFileRead) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("storage file reading is not supported for "
- "storage type %s (protocol: %s)"),
- virStorageTypeToString(src->type),
- virStorageNetProtocolTypeToString(src->protocol));
- return -2;
- }
-
- ret = src->drv->backend->storageFileRead(src, offset, len, buf);
-
- VIR_DEBUG("read '%zd' bytes from storage '%p' starting at offset '%zu'",
- ret, src, offset);
-
- return ret;
-}
-
-
-/*
- * virStorageFileGetUniqueIdentifier: Get a unique string describing the volume
- *
- * @src: file structure pointing to the file
- *
- * Returns a string uniquely describing a single volume (canonical path).
- * The string shall not be freed and is valid until the storage file is
- * deinitialized. Returns NULL on error and sets a libvirt error code */
-const char *
-virStorageFileGetUniqueIdentifier(virStorageSourcePtr src)
-{
- if (!virStorageFileIsInitialized(src)) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("storage file backend not initialized"));
- return NULL;
- }
-
- if (!src->drv->backend->storageFileGetUniqueIdentifier) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unique storage file identifier not implemented for "
- "storage type %s (protocol: %s)'"),
- virStorageTypeToString(src->type),
- virStorageNetProtocolTypeToString(src->protocol));
- return NULL;
- }
-
- return src->drv->backend->storageFileGetUniqueIdentifier(src);
-}
-
-
-/**
- * virStorageFileAccess: Check accessibility of a storage file
- *
- * @src: storage file to check access permissions
- * @mode: accessibility check options (see man 2 access)
- *
- * Returns 0 on success, -1 on error and sets errno. No libvirt
- * error is reported. Returns -2 if the operation isn't supported
- * by libvirt storage backend.
- */
-int
-virStorageFileAccess(virStorageSourcePtr src,
- int mode)
-{
- if (!virStorageFileIsInitialized(src) ||
- !src->drv->backend->storageFileAccess) {
- errno = ENOSYS;
- return -2;
- }
-
- return src->drv->backend->storageFileAccess(src, mode);
-}
-
-
-/**
- * virStorageFileChown: Change owner of a storage file
- *
- * @src: storage file to change owner of
- * @uid: new owner id
- * @gid: new group id
- *
- * Returns 0 on success, -1 on error and sets errno. No libvirt
- * error is reported. Returns -2 if the operation isn't supported
- * by libvirt storage backend.
- */
-int
-virStorageFileChown(const virStorageSource *src,
- uid_t uid,
- gid_t gid)
-{
- if (!virStorageFileIsInitialized(src) ||
- !src->drv->backend->storageFileChown) {
- errno = ENOSYS;
- return -2;
- }
-
- VIR_DEBUG("chown of storage file %p to %u:%u",
- src, (unsigned int)uid, (unsigned int)gid);
-
- return src->drv->backend->storageFileChown(src, uid, gid);
-}
-
-
-/**
- * virStorageFileReportBrokenChain:
- *
- * @errcode: errno when accessing @src
- * @src: inaccessible file in the backing chain of @parent
- * @parent: root virStorageSource being checked
- *
- * Reports the correct error message if @src is missing in the backing chain
- * for @parent.
- */
-void
-virStorageFileReportBrokenChain(int errcode,
- virStorageSourcePtr src,
- virStorageSourcePtr parent)
-{
-
- if (src->drv) {
- unsigned int access_user = src->drv->uid;
- unsigned int access_group = src->drv->gid;
-
- if (src == parent) {
- virReportSystemError(errcode,
- _("Cannot access storage file '%s' "
- "(as uid:%u, gid:%u)"),
- src->path, access_user, access_group);
- } else {
- virReportSystemError(errcode,
- _("Cannot access backing file '%s' "
- "of storage file '%s' (as uid:%u, gid:%u)"),
- src->path, parent->path, access_user, access_group);
- }
- } else {
- if (src == parent) {
- virReportSystemError(errcode,
- _("Cannot access storage file '%s'"),
- src->path);
- } else {
- virReportSystemError(errcode,
- _("Cannot access backing file '%s' "
- "of storage file '%s'"),
- src->path, parent->path);
- }
- }
-}
-
-
-/* Recursive workhorse for virStorageFileGetMetadata. */
-static int
-virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
- virStorageSourcePtr parent,
- uid_t uid, gid_t gid,
- bool allow_probe,
- bool report_broken,
- virHashTablePtr cycle,
- unsigned int depth)
-{
- int ret = -1;
- const char *uniqueName;
- char *buf = NULL;
- ssize_t headerLen;
- virStorageSourcePtr backingStore = NULL;
- int backingFormat;
-
- VIR_DEBUG("path=%s format=%d uid=%u gid=%u probe=%d",
- src->path, src->format,
- (unsigned int)uid, (unsigned int)gid, allow_probe);
-
- /* exit if we can't load information about the current image */
- if (!virStorageFileSupportsBackingChainTraversal(src))
- return 0;
-
- if (virStorageFileInitAs(src, uid, gid) < 0)
- return -1;
-
- if (virStorageFileAccess(src, F_OK) < 0) {
- virStorageFileReportBrokenChain(errno, src, parent);
- goto cleanup;
- }
-
- if (!(uniqueName = virStorageFileGetUniqueIdentifier(src)))
- goto cleanup;
-
- if (virHashLookup(cycle, uniqueName)) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("backing store for %s (%s) is self-referential"),
- src->path, uniqueName);
- goto cleanup;
- }
-
- if (virHashAddEntry(cycle, uniqueName, (void *)1) < 0)
- goto cleanup;
-
- if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER,
- &buf)) < 0)
- goto cleanup;
-
- if (virStorageFileGetMetadataInternal(src, buf, headerLen,
- &backingFormat) < 0)
- goto cleanup;
-
- if (src->backingStoreRaw) {
- if (!(backingStore = virStorageSourceNewFromBacking(src)))
- goto cleanup;
-
- if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
- backingStore->format = VIR_STORAGE_FILE_RAW;
- else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
- backingStore->format = VIR_STORAGE_FILE_AUTO;
- else
- backingStore->format = backingFormat;
-
- if ((ret = virStorageFileGetMetadataRecurse(backingStore, parent,
- uid, gid,
- allow_probe, report_broken,
- cycle, depth + 1)) < 0) {
- if (report_broken)
- goto cleanup;
-
- /* if we fail somewhere midway, just accept and return a
- * broken chain */
- ret = 0;
- goto cleanup;
- }
- } else {
- /* add terminator */
- if (VIR_ALLOC(backingStore) < 0)
- goto cleanup;
- }
-
- src->backingStore = backingStore;
- backingStore = NULL;
- ret = 0;
-
- cleanup:
- if (virStorageSourceHasBacking(src))
- src->backingStore->id = depth;
- VIR_FREE(buf);
- virStorageFileDeinit(src);
- virStorageSourceFree(backingStore);
- return ret;
-}
-
-
-/**
- * virStorageFileGetMetadata:
- *
- * Extract metadata about the storage volume with the specified
- * image format. If image format is VIR_STORAGE_FILE_AUTO, it
- * will probe to automatically identify the format. Recurses through
- * the entire chain.
- *
- * Open files using UID and GID (or pass -1 for the current user/group).
- * Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
- *
- * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
- * format, since a malicious guest can turn a raw file into any
- * other non-raw format at will.
- *
- * If @report_broken is true, the whole function fails with a possibly sane
- * error instead of just returning a broken chain.
- *
- * Caller MUST free result after use via virStorageSourceFree.
- */
-int
-virStorageFileGetMetadata(virStorageSourcePtr src,
- uid_t uid, gid_t gid,
- bool allow_probe,
- bool report_broken)
-{
- VIR_DEBUG("path=%s format=%d uid=%u gid=%u probe=%d, report_broken=%d",
- src->path, src->format, (unsigned int)uid, (unsigned int)gid,
- allow_probe, report_broken);
-
- virHashTablePtr cycle = NULL;
- virStorageType actualType = virStorageSourceGetActualType(src);
- int ret = -1;
-
- if (!(cycle = virHashCreate(5, NULL)))
- return -1;
-
- if (src->format <= VIR_STORAGE_FILE_NONE) {
- if (actualType == VIR_STORAGE_TYPE_DIR)
- src->format = VIR_STORAGE_FILE_DIR;
- else if (allow_probe)
- src->format = VIR_STORAGE_FILE_AUTO;
- else
- src->format = VIR_STORAGE_FILE_RAW;
- }
-
- ret = virStorageFileGetMetadataRecurse(src, src, uid, gid,
- allow_probe, report_broken, cycle, 1);
-
- virHashFree(cycle);
- return ret;
-}
-
-
-/**
- * virStorageFileGetBackingStoreStr:
- * @src: storage object
- *
- * Extracts the backing store string as stored in the storage volume described
- * by @src and returns it to the user. Caller is responsible for freeing it.
- * In case when the string can't be retrieved or does not exist NULL is
- * returned.
- */
-char *
-virStorageFileGetBackingStoreStr(virStorageSourcePtr src)
-{
- virStorageSourcePtr tmp = NULL;
- char *buf = NULL;
- ssize_t headerLen;
- char *ret = NULL;
-
- /* exit if we can't load information about the current image */
- if (!virStorageFileSupportsBackingChainTraversal(src))
- return NULL;
-
- if (virStorageFileAccess(src, F_OK) < 0)
- return NULL;
-
- if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER,
- &buf)) < 0)
- return NULL;
-
- if (!(tmp = virStorageSourceCopy(src, false)))
- goto cleanup;
-
- if (virStorageFileGetMetadataInternal(tmp, buf, headerLen, NULL) < 0)
- goto cleanup;
-
- VIR_STEAL_PTR(ret, tmp->backingStoreRaw);
-
- cleanup:
- VIR_FREE(buf);
- virStorageSourceFree(tmp);
-
- return ret;
-}
+++ /dev/null
-/*
- * storage_source.h: Storage source accessors to real storaget
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see
- * <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __VIR_STORAGE_SOURCE_H__
-# define __VIR_STORAGE_SOURCE_H__
-
-# include <sys/stat.h>
-
-# include "virstoragefile.h"
-
-int virStorageFileInit(virStorageSourcePtr src);
-int virStorageFileInitAs(virStorageSourcePtr src,
- uid_t uid, gid_t gid);
-void virStorageFileDeinit(virStorageSourcePtr src);
-
-int virStorageFileCreate(virStorageSourcePtr src);
-int virStorageFileUnlink(virStorageSourcePtr src);
-int virStorageFileStat(virStorageSourcePtr src,
- struct stat *stat);
-ssize_t virStorageFileRead(virStorageSourcePtr src,
- size_t offset,
- size_t len,
- char **buf);
-const char *virStorageFileGetUniqueIdentifier(virStorageSourcePtr src);
-int virStorageFileAccess(virStorageSourcePtr src, int mode);
-int virStorageFileChown(const virStorageSource *src, uid_t uid, gid_t gid);
-
-bool virStorageFileSupportsSecurityDriver(const virStorageSource *src);
-bool virStorageFileSupportsAccess(const virStorageSource *src);
-
-int virStorageFileGetMetadata(virStorageSourcePtr src,
- uid_t uid, gid_t gid,
- bool allow_probe,
- bool report_broken)
- ATTRIBUTE_NONNULL(1);
-
-char *virStorageFileGetBackingStoreStr(virStorageSourcePtr src)
- ATTRIBUTE_NONNULL(1);
-
-void virStorageFileReportBrokenChain(int errcode,
- virStorageSourcePtr src,
- virStorageSourcePtr parent);
-
-#endif /* __VIR_STORAGE_SOURCE_H__ */
*/
#include <config.h>
-#include "virstoragefile.h"
+#include "virstoragefilebackend.h"
#include <unistd.h>
#include <fcntl.h>
return 0;
}
+
+static bool
+virStorageFileIsInitialized(const virStorageSource *src)
+{
+ return src && src->drv;
+}
+
+
+static virStorageFileBackendPtr
+virStorageFileGetBackendForSupportCheck(const virStorageSource *src)
+{
+ int actualType;
+
+ if (!src)
+ return NULL;
+
+ if (src->drv)
+ return src->drv->backend;
+
+ actualType = virStorageSourceGetActualType(src);
+
+ return virStorageFileBackendForTypeInternal(actualType, src->protocol, false);
+}
+
+
+static bool
+virStorageFileSupportsBackingChainTraversal(virStorageSourcePtr src)
+{
+ virStorageFileBackendPtr backend;
+
+ if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
+ return false;
+
+ return backend->storageFileGetUniqueIdentifier &&
+ backend->storageFileRead &&
+ backend->storageFileAccess;
+}
+
+
+/**
+ * virStorageFileSupportsSecurityDriver:
+ *
+ * @src: a storage file structure
+ *
+ * Check if a storage file supports operations needed by the security
+ * driver to perform labelling
+ */
+bool
+virStorageFileSupportsSecurityDriver(const virStorageSource *src)
+{
+ virStorageFileBackendPtr backend;
+
+ if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
+ return false;
+
+ return !!backend->storageFileChown;
+}
+
+
+/**
+ * virStorageFileSupportsAccess:
+ *
+ * @src: a storage file structure
+ *
+ * Check if a storage file supports checking if the storage source is accessible
+ * for the given vm.
+ */
+bool
+virStorageFileSupportsAccess(const virStorageSource *src)
+{
+ virStorageFileBackendPtr backend;
+
+ if (!(backend = virStorageFileGetBackendForSupportCheck(src)))
+ return false;
+
+ return !!backend->storageFileAccess;
+}
+
+
+void
+virStorageFileDeinit(virStorageSourcePtr src)
+{
+ if (!virStorageFileIsInitialized(src))
+ return;
+
+ if (src->drv->backend &&
+ src->drv->backend->backendDeinit)
+ src->drv->backend->backendDeinit(src);
+
+ VIR_FREE(src->drv);
+}
+
+
+/**
+ * virStorageFileInitAs:
+ *
+ * @src: storage source definition
+ * @uid: uid used to access the file, or -1 for current uid
+ * @gid: gid used to access the file, or -1 for current gid
+ *
+ * Initialize a storage source to be used with storage driver. Use the provided
+ * uid and gid if possible for the operations.
+ *
+ * Returns 0 if the storage file was successfully initialized, -1 if the
+ * initialization failed. Libvirt error is reported.
+ */
+int
+virStorageFileInitAs(virStorageSourcePtr src,
+ uid_t uid, gid_t gid)
+{
+ int actualType = virStorageSourceGetActualType(src);
+ if (VIR_ALLOC(src->drv) < 0)
+ return -1;
+
+ if (uid == (uid_t) -1)
+ src->drv->uid = geteuid();
+ else
+ src->drv->uid = uid;
+
+ if (gid == (gid_t) -1)
+ src->drv->gid = getegid();
+ else
+ src->drv->gid = gid;
+
+ if (!(src->drv->backend = virStorageFileBackendForType(actualType,
+ src->protocol)))
+ goto error;
+
+ if (src->drv->backend->backendInit &&
+ src->drv->backend->backendInit(src) < 0)
+ goto error;
+
+ return 0;
+
+ error:
+ VIR_FREE(src->drv);
+ return -1;
+}
+
+
+/**
+ * virStorageFileInit:
+ *
+ * See virStorageFileInitAs. The file is initialized to be accessed by the
+ * current user.
+ */
+int
+virStorageFileInit(virStorageSourcePtr src)
+{
+ return virStorageFileInitAs(src, -1, -1);
+}
+
+
+/**
+ * virStorageFileCreate: Creates an empty storage file via storage driver
+ *
+ * @src: file structure pointing to the file
+ *
+ * Returns 0 on success, -2 if the function isn't supported by the backend,
+ * -1 on other failure. Errno is set in case of failure.
+ */
+int
+virStorageFileCreate(virStorageSourcePtr src)
+{
+ int ret;
+
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileCreate) {
+ errno = ENOSYS;
+ return -2;
+ }
+
+ ret = src->drv->backend->storageFileCreate(src);
+
+ VIR_DEBUG("created storage file %p: ret=%d, errno=%d",
+ src, ret, errno);
+
+ return ret;
+}
+
+
+/**
+ * virStorageFileUnlink: Unlink storage file via storage driver
+ *
+ * @src: file structure pointing to the file
+ *
+ * Unlinks the file described by the @file structure.
+ *
+ * Returns 0 on success, -2 if the function isn't supported by the backend,
+ * -1 on other failure. Errno is set in case of failure.
+ */
+int
+virStorageFileUnlink(virStorageSourcePtr src)
+{
+ int ret;
+
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileUnlink) {
+ errno = ENOSYS;
+ return -2;
+ }
+
+ ret = src->drv->backend->storageFileUnlink(src);
+
+ VIR_DEBUG("unlinked storage file %p: ret=%d, errno=%d",
+ src, ret, errno);
+
+ return ret;
+}
+
+
+/**
+ * virStorageFileStat: returns stat struct of a file via storage driver
+ *
+ * @src: file structure pointing to the file
+ * @stat: stat structure to return data
+ *
+ * Returns 0 on success, -2 if the function isn't supported by the backend,
+ * -1 on other failure. Errno is set in case of failure.
+*/
+int
+virStorageFileStat(virStorageSourcePtr src,
+ struct stat *st)
+{
+ int ret;
+
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileStat) {
+ errno = ENOSYS;
+ return -2;
+ }
+
+ ret = src->drv->backend->storageFileStat(src, st);
+
+ VIR_DEBUG("stat of storage file %p: ret=%d, errno=%d",
+ src, ret, errno);
+
+ return ret;
+}
+
+
+/**
+ * virStorageFileRead: read bytes from a file into a buffer
+ *
+ * @src: file structure pointing to the file
+ * @offset: number of bytes to skip in the storage file
+ * @len: maximum number of bytes read from the storage file
+ * @buf: buffer to read the data into. (buffer shall be freed by caller)
+ *
+ * Returns the count of bytes read on success and -1 on failure, -2 if the
+ * function isn't supported by the backend.
+ * Libvirt error is reported on failure.
+ */
+ssize_t
+virStorageFileRead(virStorageSourcePtr src,
+ size_t offset,
+ size_t len,
+ char **buf)
+{
+ ssize_t ret;
+
+ if (!virStorageFileIsInitialized(src)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("storage file backend not initialized"));
+ return -1;
+ }
+
+ if (!src->drv->backend->storageFileRead) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("storage file reading is not supported for "
+ "storage type %s (protocol: %s)"),
+ virStorageTypeToString(src->type),
+ virStorageNetProtocolTypeToString(src->protocol));
+ return -2;
+ }
+
+ ret = src->drv->backend->storageFileRead(src, offset, len, buf);
+
+ VIR_DEBUG("read '%zd' bytes from storage '%p' starting at offset '%zu'",
+ ret, src, offset);
+
+ return ret;
+}
+
+
+/*
+ * virStorageFileGetUniqueIdentifier: Get a unique string describing the volume
+ *
+ * @src: file structure pointing to the file
+ *
+ * Returns a string uniquely describing a single volume (canonical path).
+ * The string shall not be freed and is valid until the storage file is
+ * deinitialized. Returns NULL on error and sets a libvirt error code */
+const char *
+virStorageFileGetUniqueIdentifier(virStorageSourcePtr src)
+{
+ if (!virStorageFileIsInitialized(src)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("storage file backend not initialized"));
+ return NULL;
+ }
+
+ if (!src->drv->backend->storageFileGetUniqueIdentifier) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unique storage file identifier not implemented for "
+ "storage type %s (protocol: %s)'"),
+ virStorageTypeToString(src->type),
+ virStorageNetProtocolTypeToString(src->protocol));
+ return NULL;
+ }
+
+ return src->drv->backend->storageFileGetUniqueIdentifier(src);
+}
+
+
+/**
+ * virStorageFileAccess: Check accessibility of a storage file
+ *
+ * @src: storage file to check access permissions
+ * @mode: accessibility check options (see man 2 access)
+ *
+ * Returns 0 on success, -1 on error and sets errno. No libvirt
+ * error is reported. Returns -2 if the operation isn't supported
+ * by libvirt storage backend.
+ */
+int
+virStorageFileAccess(virStorageSourcePtr src,
+ int mode)
+{
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileAccess) {
+ errno = ENOSYS;
+ return -2;
+ }
+
+ return src->drv->backend->storageFileAccess(src, mode);
+}
+
+
+/**
+ * virStorageFileChown: Change owner of a storage file
+ *
+ * @src: storage file to change owner of
+ * @uid: new owner id
+ * @gid: new group id
+ *
+ * Returns 0 on success, -1 on error and sets errno. No libvirt
+ * error is reported. Returns -2 if the operation isn't supported
+ * by libvirt storage backend.
+ */
+int
+virStorageFileChown(const virStorageSource *src,
+ uid_t uid,
+ gid_t gid)
+{
+ if (!virStorageFileIsInitialized(src) ||
+ !src->drv->backend->storageFileChown) {
+ errno = ENOSYS;
+ return -2;
+ }
+
+ VIR_DEBUG("chown of storage file %p to %u:%u",
+ src, (unsigned int)uid, (unsigned int)gid);
+
+ return src->drv->backend->storageFileChown(src, uid, gid);
+}
+
+
+/**
+ * virStorageFileReportBrokenChain:
+ *
+ * @errcode: errno when accessing @src
+ * @src: inaccessible file in the backing chain of @parent
+ * @parent: root virStorageSource being checked
+ *
+ * Reports the correct error message if @src is missing in the backing chain
+ * for @parent.
+ */
+void
+virStorageFileReportBrokenChain(int errcode,
+ virStorageSourcePtr src,
+ virStorageSourcePtr parent)
+{
+
+ if (src->drv) {
+ unsigned int access_user = src->drv->uid;
+ unsigned int access_group = src->drv->gid;
+
+ if (src == parent) {
+ virReportSystemError(errcode,
+ _("Cannot access storage file '%s' "
+ "(as uid:%u, gid:%u)"),
+ src->path, access_user, access_group);
+ } else {
+ virReportSystemError(errcode,
+ _("Cannot access backing file '%s' "
+ "of storage file '%s' (as uid:%u, gid:%u)"),
+ src->path, parent->path, access_user, access_group);
+ }
+ } else {
+ if (src == parent) {
+ virReportSystemError(errcode,
+ _("Cannot access storage file '%s'"),
+ src->path);
+ } else {
+ virReportSystemError(errcode,
+ _("Cannot access backing file '%s' "
+ "of storage file '%s'"),
+ src->path, parent->path);
+ }
+ }
+}
+
+
+/* Recursive workhorse for virStorageFileGetMetadata. */
+static int
+virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
+ virStorageSourcePtr parent,
+ uid_t uid, gid_t gid,
+ bool allow_probe,
+ bool report_broken,
+ virHashTablePtr cycle,
+ unsigned int depth)
+{
+ int ret = -1;
+ const char *uniqueName;
+ char *buf = NULL;
+ ssize_t headerLen;
+ virStorageSourcePtr backingStore = NULL;
+ int backingFormat;
+
+ VIR_DEBUG("path=%s format=%d uid=%u gid=%u probe=%d",
+ src->path, src->format,
+ (unsigned int)uid, (unsigned int)gid, allow_probe);
+
+ /* exit if we can't load information about the current image */
+ if (!virStorageFileSupportsBackingChainTraversal(src))
+ return 0;
+
+ if (virStorageFileInitAs(src, uid, gid) < 0)
+ return -1;
+
+ if (virStorageFileAccess(src, F_OK) < 0) {
+ virStorageFileReportBrokenChain(errno, src, parent);
+ goto cleanup;
+ }
+
+ if (!(uniqueName = virStorageFileGetUniqueIdentifier(src)))
+ goto cleanup;
+
+ if (virHashLookup(cycle, uniqueName)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("backing store for %s (%s) is self-referential"),
+ src->path, uniqueName);
+ goto cleanup;
+ }
+
+ if (virHashAddEntry(cycle, uniqueName, (void *)1) < 0)
+ goto cleanup;
+
+ if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER,
+ &buf)) < 0)
+ goto cleanup;
+
+ if (virStorageFileGetMetadataInternal(src, buf, headerLen,
+ &backingFormat) < 0)
+ goto cleanup;
+
+ if (src->backingStoreRaw) {
+ if (!(backingStore = virStorageSourceNewFromBacking(src)))
+ goto cleanup;
+
+ if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
+ backingStore->format = VIR_STORAGE_FILE_RAW;
+ else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
+ backingStore->format = VIR_STORAGE_FILE_AUTO;
+ else
+ backingStore->format = backingFormat;
+
+ if ((ret = virStorageFileGetMetadataRecurse(backingStore, parent,
+ uid, gid,
+ allow_probe, report_broken,
+ cycle, depth + 1)) < 0) {
+ if (report_broken)
+ goto cleanup;
+
+ /* if we fail somewhere midway, just accept and return a
+ * broken chain */
+ ret = 0;
+ goto cleanup;
+ }
+ } else {
+ /* add terminator */
+ if (VIR_ALLOC(backingStore) < 0)
+ goto cleanup;
+ }
+
+ src->backingStore = backingStore;
+ backingStore = NULL;
+ ret = 0;
+
+ cleanup:
+ if (virStorageSourceHasBacking(src))
+ src->backingStore->id = depth;
+ VIR_FREE(buf);
+ virStorageFileDeinit(src);
+ virStorageSourceFree(backingStore);
+ return ret;
+}
+
+
+/**
+ * virStorageFileGetMetadata:
+ *
+ * Extract metadata about the storage volume with the specified
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
+ * will probe to automatically identify the format. Recurses through
+ * the entire chain.
+ *
+ * Open files using UID and GID (or pass -1 for the current user/group).
+ * Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
+ *
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
+ * format, since a malicious guest can turn a raw file into any
+ * other non-raw format at will.
+ *
+ * If @report_broken is true, the whole function fails with a possibly sane
+ * error instead of just returning a broken chain.
+ *
+ * Caller MUST free result after use via virStorageSourceFree.
+ */
+int
+virStorageFileGetMetadata(virStorageSourcePtr src,
+ uid_t uid, gid_t gid,
+ bool allow_probe,
+ bool report_broken)
+{
+ VIR_DEBUG("path=%s format=%d uid=%u gid=%u probe=%d, report_broken=%d",
+ src->path, src->format, (unsigned int)uid, (unsigned int)gid,
+ allow_probe, report_broken);
+
+ virHashTablePtr cycle = NULL;
+ virStorageType actualType = virStorageSourceGetActualType(src);
+ int ret = -1;
+
+ if (!(cycle = virHashCreate(5, NULL)))
+ return -1;
+
+ if (src->format <= VIR_STORAGE_FILE_NONE) {
+ if (actualType == VIR_STORAGE_TYPE_DIR)
+ src->format = VIR_STORAGE_FILE_DIR;
+ else if (allow_probe)
+ src->format = VIR_STORAGE_FILE_AUTO;
+ else
+ src->format = VIR_STORAGE_FILE_RAW;
+ }
+
+ ret = virStorageFileGetMetadataRecurse(src, src, uid, gid,
+ allow_probe, report_broken, cycle, 1);
+
+ virHashFree(cycle);
+ return ret;
+}
+
+
+/**
+ * virStorageFileGetBackingStoreStr:
+ * @src: storage object
+ *
+ * Extracts the backing store string as stored in the storage volume described
+ * by @src and returns it to the user. Caller is responsible for freeing it.
+ * In case when the string can't be retrieved or does not exist NULL is
+ * returned.
+ */
+char *
+virStorageFileGetBackingStoreStr(virStorageSourcePtr src)
+{
+ virStorageSourcePtr tmp = NULL;
+ char *buf = NULL;
+ ssize_t headerLen;
+ char *ret = NULL;
+
+ /* exit if we can't load information about the current image */
+ if (!virStorageFileSupportsBackingChainTraversal(src))
+ return NULL;
+
+ if (virStorageFileAccess(src, F_OK) < 0)
+ return NULL;
+
+ if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER,
+ &buf)) < 0)
+ return NULL;
+
+ if (!(tmp = virStorageSourceCopy(src, false)))
+ goto cleanup;
+
+ if (virStorageFileGetMetadataInternal(tmp, buf, headerLen, NULL) < 0)
+ goto cleanup;
+
+ VIR_STEAL_PTR(ret, tmp->backingStoreRaw);
+
+ cleanup:
+ VIR_FREE(buf);
+ virStorageSourceFree(tmp);
+
+ return ret;
+}
virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src,
virBufferPtr buf);
+int virStorageFileInit(virStorageSourcePtr src);
+int virStorageFileInitAs(virStorageSourcePtr src,
+ uid_t uid, gid_t gid);
+void virStorageFileDeinit(virStorageSourcePtr src);
+
+int virStorageFileCreate(virStorageSourcePtr src);
+int virStorageFileUnlink(virStorageSourcePtr src);
+int virStorageFileStat(virStorageSourcePtr src,
+ struct stat *stat);
+ssize_t virStorageFileRead(virStorageSourcePtr src,
+ size_t offset,
+ size_t len,
+ char **buf);
+const char *virStorageFileGetUniqueIdentifier(virStorageSourcePtr src);
+int virStorageFileAccess(virStorageSourcePtr src, int mode);
+int virStorageFileChown(const virStorageSource *src, uid_t uid, gid_t gid);
+
+bool virStorageFileSupportsSecurityDriver(const virStorageSource *src);
+bool virStorageFileSupportsAccess(const virStorageSource *src);
+
+int virStorageFileGetMetadata(virStorageSourcePtr src,
+ uid_t uid, gid_t gid,
+ bool allow_probe,
+ bool report_broken)
+ ATTRIBUTE_NONNULL(1);
+
+char *virStorageFileGetBackingStoreStr(virStorageSourcePtr src)
+ ATTRIBUTE_NONNULL(1);
+
+void virStorageFileReportBrokenChain(int errcode,
+ virStorageSourcePtr src,
+ virStorageSourcePtr parent);
#endif /* __VIR_STORAGE_FILE_H__ */
/*
- * storage_source_backend.c: internal storage source backend contract
+ * virstoragefilebackend.c: internal storage source backend contract
*
* Copyright (C) 2007-2018 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
#include "virerror.h"
#include "viralloc.h"
#include "internal.h"
-#include "storage_source_backend.h"
+#include "virstoragefilebackend.h"
#include "virlog.h"
#include "virfile.h"
#include "configmake.h"
/*
- * storage_source_backend.h: internal storage source backend contract
+ * virstoragefilebackend.h: internal storage source backend contract
*
* Copyright (C) 2007-2018 Red Hat, Inc.
*
* <http://www.gnu.org/licenses/>.
*/
-#ifndef __VIR_STORAGE_SOURCE_BACKEND_H__
-# define __VIR_STORAGE_SOURCE_BACKEND_H__
+#ifndef __VIR_STORAGE_FILE_BACKEND_H__
+# define __VIR_STORAGE_FILE_BACKEND_H__
# include <sys/stat.h>
int virStorageFileBackendRegister(virStorageFileBackendPtr backend);
-#endif /* __VIR_STORAGE_SOURCE_BACKEND_H__ */
+#endif /* __VIR_STORAGE_FILE_BACKEND_H__ */
#include "dirname.h"
#include "storage/storage_driver.h"
-#include "storage/storage_source.h"
#define VIR_FROM_THIS VIR_FROM_NONE