diff --git a/po/POTFILES.in b/po/POTFILES.in index ea99f616778e60be7d32abc745745eeda5deac4e..28595546905c167a76bee3a0028ce2ce41be18d6 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -186,8 +186,6 @@ src/storage/storage_backend_sheepdog.c 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 @@ -263,6 +261,7 @@ src/util/virsexpr.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 diff --git a/src/Makefile.am b/src/Makefile.am index 99f9bfb6f21871650fc313b2a48157132eae3b37..54ef81d1ab90e0a78ad79b6bbb7b2b7ba0cb4699 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -178,6 +178,7 @@ UTIL_SOURCES = \ 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 \ @@ -1064,8 +1065,6 @@ STORAGE_DRIVER_BACKEND_SOURCES = \ 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 diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0bce0bbfb2757b9064a7bd83faa79ed3e3212dd0..3ec510bd322c8b3eec73fc490a8bf0093f987d3d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2720,24 +2720,39 @@ virStorageAuthDefCopy; 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; @@ -2776,6 +2791,10 @@ virStorageTypeFromString; virStorageTypeToString; +# util/virstoragefilebackend.h +virStorageFileBackendRegister; + + # util/virstring.h virArgvToString; virAsprintfInternal; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index aa652959ed4d44bae4df4dcb3a0a29f37891145c..db8586360fc88e776b4ef5dda13465b5462b2357 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -56,7 +56,6 @@ #include "locking/domain_lock.h" #include "storage/storage_driver.h" -#include "storage/storage_source.h" #ifdef MAJOR_IN_MKDEV # include diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8d77d8913a965403326d3904eae5fb2d56fd62f7..2990c354848847d3f5c81cb730d65b3910b7334e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -100,7 +100,6 @@ #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" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 29a459da20af01b13a979da65c52cbd82445c6f0..ff0068cecdfd9ed669364f17e06ba112c6ec8e60 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -57,8 +57,6 @@ #include "virgettext.h" #include "virhostdev.h" -#include "storage/storage_source.h" - #define VIR_FROM_THIS VIR_FROM_SECURITY static char *progname; diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index c528c1dae53d821d6d4fc244fab202a41c181cbe..9b0fcf92c5cd4d018d9c3b11ca24c953240b6035 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -37,10 +37,9 @@ #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" diff --git a/src/storage/storage_backend_gluster.c b/src/storage/storage_backend_gluster.c index 68d9c726e9cd1f96778fea9ef9a4d6a83d8b58ae..c6cc531e2ff6337c56447b602ee4cefaa73bb384 100644 --- a/src/storage/storage_backend_gluster.c +++ b/src/storage/storage_backend_gluster.c @@ -24,12 +24,11 @@ #include #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" diff --git a/src/storage/storage_source.c b/src/storage/storage_source.c deleted file mode 100644 index a5eefe503280f70809ab4b07180a50ad9fcca61c..0000000000000000000000000000000000000000 --- a/src/storage/storage_source.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * 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 - * . - */ - -#include - -#include -#include - -#include -#include - -#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; -} diff --git a/src/storage/storage_source.h b/src/storage/storage_source.h deleted file mode 100644 index 0640c138edab4496d6036ff5d0ddbb50e0cbabac..0000000000000000000000000000000000000000 --- a/src/storage/storage_source.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 - * . - */ - -#ifndef __VIR_STORAGE_SOURCE_H__ -# define __VIR_STORAGE_SOURCE_H__ - -# include - -# 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__ */ diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 5f661c956cfee022e61262f8d1e891130ec0d938..7f878039ba762b6fefb1919bdc89af9250324d2d 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -22,7 +22,7 @@ */ #include -#include "virstoragefile.h" +#include "virstoragefilebackend.h" #include #include @@ -4103,3 +4103,610 @@ virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src, 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; +} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index ecd806c93f842150baea4676cb5611fd2a7e7438..9e8afa49326b8bd22b4c6bfab8ff77b89c34efba 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -448,5 +448,37 @@ int 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__ */ diff --git a/src/storage/storage_source_backend.c b/src/util/virstoragefilebackend.c similarity index 96% rename from src/storage/storage_source_backend.c rename to src/util/virstoragefilebackend.c index e093c04989c871899d8e8168c92a56776c392f23..df86ee39c2e1f657a9a6a8698119368d02bb1a70 100644 --- a/src/storage/storage_source_backend.c +++ b/src/util/virstoragefilebackend.c @@ -1,5 +1,5 @@ /* - * 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 @@ -30,7 +30,7 @@ #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" diff --git a/src/storage/storage_source_backend.h b/src/util/virstoragefilebackend.h similarity index 94% rename from src/storage/storage_source_backend.h rename to src/util/virstoragefilebackend.h index 3af2a5f3801c1d6ac1dc2f606f93ecdd36cadb7e..6cd51750eea0343248ca39a2bbdf33345afd2b12 100644 --- a/src/storage/storage_source_backend.h +++ b/src/util/virstoragefilebackend.h @@ -1,5 +1,5 @@ /* - * storage_source_backend.h: internal storage source backend contract + * virstoragefilebackend.h: internal storage source backend contract * * Copyright (C) 2007-2018 Red Hat, Inc. * @@ -18,8 +18,8 @@ * . */ -#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 @@ -101,4 +101,4 @@ struct _virStorageFileBackend { int virStorageFileBackendRegister(virStorageFileBackendPtr backend); -#endif /* __VIR_STORAGE_SOURCE_BACKEND_H__ */ +#endif /* __VIR_STORAGE_FILE_BACKEND_H__ */ diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c index 1dc7608cee02dc3333d348fe566b8367334b526e..6eed7134ed8cb2e669e83df0f829f32fdc0ae59b 100644 --- a/tests/virstoragetest.c +++ b/tests/virstoragetest.c @@ -32,7 +32,6 @@ #include "dirname.h" #include "storage/storage_driver.h" -#include "storage/storage_source.h" #define VIR_FROM_THIS VIR_FROM_NONE