[libvirt PATCH v2 00/13] second part of cleanup storage source related code

Pavel Hrdina (13): src: add missing virstoragefile.h includes virstoragefile: properly include virstoragefile.h header virstoragefile: change virStorageSource->drv to void pointer storage: move storage file sources to separate directory util: move virStorageSourceFindByNodeName into qemu_domain util: extract storage file probe code into virtstoragefileprobe.c util: extract virStorageFile code into storage_source util: move virStorageFileBackend code into storage_file util: move virStorageFileProbe code into storage_file util: move virStorageSource code into conf util: move virStorageEncryption code into conf virstoragefile: use virStorageFile prefix for all functions storage_source: use virStorageSource prefix for all functions po/POTFILES.in | 11 +- src/conf/backup_conf.c | 2 +- src/conf/checkpoint_conf.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 6 +- src/conf/meson.build | 2 + src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_conf.h | 4 +- .../storage_encryption_conf.c} | 4 +- .../storage_encryption_conf.h} | 2 +- src/conf/storage_source_conf.c | 1350 +++++ src/conf/storage_source_conf.h | 537 ++ src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/libvirt_private.syms | 189 +- src/libxl/meson.build | 1 + src/libxl/xen_xl.c | 2 +- src/locking/lock_driver_lockd.c | 1 + src/meson.build | 1 + src/qemu/meson.build | 1 + src/qemu/qemu_backup.c | 11 +- src/qemu/qemu_block.c | 10 +- src/qemu/qemu_blockjob.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_domain.c | 55 +- src/qemu/qemu_driver.c | 69 +- src/qemu/qemu_hotplug.c | 7 +- src/qemu/qemu_migration.c | 2 +- src/qemu/qemu_process.c | 5 +- src/qemu/qemu_snapshot.c | 24 +- src/security/meson.build | 1 + src/security/virt-aa-helper.c | 3 +- src/storage/meson.build | 34 +- src/storage/storage_backend.c | 2 +- src/storage/storage_backend_gluster.c | 6 +- src/storage/storage_util.c | 9 +- src/storage_file/meson.build | 61 + .../storage_file_backend.c} | 4 +- .../storage_file_backend.h} | 6 +- .../storage_file_fs.c | 23 +- .../storage_file_fs.h | 0 .../storage_file_gluster.c | 34 +- .../storage_file_gluster.h | 0 src/storage_file/storage_file_probe.c | 967 ++++ src/storage_file/storage_file_probe.h | 44 + src/storage_file/storage_source.c | 2614 +++++++++ src/storage_file/storage_source.h | 148 + src/util/meson.build | 2 - src/util/virstoragefile.c | 4790 +---------------- src/util/virstoragefile.h | 554 +- tests/meson.build | 4 +- tests/qemublocktest.c | 1 + tests/virstoragetest.c | 19 +- 54 files changed, 6045 insertions(+), 5593 deletions(-) rename src/{util/virstorageencryption.c => conf/storage_encryption_conf.c} (99%) rename src/{util/virstorageencryption.h => conf/storage_encryption_conf.h} (98%) create mode 100644 src/conf/storage_source_conf.c create mode 100644 src/conf/storage_source_conf.h create mode 100644 src/storage_file/meson.build rename src/{util/virstoragefilebackend.c => storage_file/storage_file_backend.c} (97%) rename src/{util/virstoragefilebackend.h => storage_file/storage_file_backend.h} (93%) rename src/{storage => storage_file}/storage_file_fs.c (90%) rename src/{storage => storage_file}/storage_file_fs.h (100%) rename src/{storage => storage_file}/storage_file_gluster.c (89%) rename src/{storage => storage_file}/storage_file_gluster.h (100%) create mode 100644 src/storage_file/storage_file_probe.c create mode 100644 src/storage_file/storage_file_probe.h create mode 100644 src/storage_file/storage_source.c create mode 100644 src/storage_file/storage_source.h -- 2.29.2

These files are using functions from virstoragefile.h but are missing explicit include. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/locking/lock_driver_lockd.c | 1 + src/qemu/qemu_block.c | 1 + src/qemu/qemu_snapshot.c | 1 + src/security/virt-aa-helper.c | 1 + src/storage/storage_file_gluster.c | 1 + 5 files changed, 5 insertions(+) diff --git a/src/locking/lock_driver_lockd.c b/src/locking/lock_driver_lockd.c index d459c1668c..5ebefa48d0 100644 --- a/src/locking/lock_driver_lockd.c +++ b/src/locking/lock_driver_lockd.c @@ -33,6 +33,7 @@ #include "rpc/virnetclient.h" #include "lock_protocol.h" #include "configmake.h" +#include "virstoragefile.h" #include "virstring.h" #include "virutil.h" diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index f9c6da2cee..c98094e746 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -25,6 +25,7 @@ #include "qemu_security.h" #include "viralloc.h" +#include "virstoragefile.h" #include "virstring.h" #include "virlog.h" diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index ee333c35bb..c2fa54f5ab 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -38,6 +38,7 @@ #include "locking/domain_lock.h" #include "libvirt_internal.h" #include "virxml.h" +#include "virstoragefile.h" #include "virstring.h" #include "virdomainsnapshotobjlist.h" #include "virqemu.h" diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 5a6f4a5f7d..18af175655 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -46,6 +46,7 @@ #include "virfile.h" #include "configmake.h" #include "virrandom.h" +#include "virstoragefile.h" #include "virstring.h" #include "virgettext.h" #include "virhostdev.h" diff --git a/src/storage/storage_file_gluster.c b/src/storage/storage_file_gluster.c index c84af8a4e8..0fc6835f11 100644 --- a/src/storage/storage_file_gluster.c +++ b/src/storage/storage_file_gluster.c @@ -27,6 +27,7 @@ #include "viralloc.h" #include "virerror.h" #include "virlog.h" +#include "virstoragefile.h" #include "virstoragefilebackend.h" #include "virstring.h" -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:15 +0100, Pavel Hrdina wrote:
These files are using functions from virstoragefile.h but are missing explicit include.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/locking/lock_driver_lockd.c | 1 + src/qemu/qemu_block.c | 1 + src/qemu/qemu_snapshot.c | 1 + src/security/virt-aa-helper.c | 1 + src/storage/storage_file_gluster.c | 1 + 5 files changed, 5 insertions(+)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

It was indirectly included by virstoragefilebackend.h. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util/virstoragefile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 0d3c2af94f..17579126b0 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -20,7 +20,7 @@ */ #include <config.h> -#include "virstoragefilebackend.h" +#include "virstoragefile.h" #include <unistd.h> #include <fcntl.h> @@ -38,6 +38,7 @@ #include "virbuffer.h" #include "virjson.h" #include "virstorageencryption.h" +#include "virstoragefilebackend.h" #include "virsecret.h" #include "virutil.h" -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:16 +0100, Pavel Hrdina wrote:
It was indirectly included by virstoragefilebackend.h.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/util/virstoragefile.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

This will allow following patches to move virStorageSource into conf directory and virStorageDriverData into a new storage_file directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com> --- src/storage/storage_file_fs.c | 21 +++-- src/storage/storage_file_gluster.c | 31 +++++--- src/util/virstoragefile.c | 118 +++++++++++++++++++++-------- src/util/virstoragefile.h | 5 +- src/util/virstoragefilebackend.h | 2 + 5 files changed, 122 insertions(+), 55 deletions(-) diff --git a/src/storage/storage_file_fs.c b/src/storage/storage_file_fs.c index b379a8ca8e..5a44ef8c2d 100644 --- a/src/storage/storage_file_fs.c +++ b/src/storage/storage_file_fs.c @@ -51,7 +51,8 @@ struct _virStorageFileBackendFsPriv { static void virStorageFileBackendFileDeinit(virStorageSourcePtr src) { - virStorageFileBackendFsPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendFsPrivPtr priv = drv->priv; VIR_DEBUG("deinitializing FS storage file %p (%s:%s)", src, virStorageTypeToString(virStorageSourceGetActualType(src)), @@ -66,16 +67,17 @@ virStorageFileBackendFileDeinit(virStorageSourcePtr src) static int virStorageFileBackendFileInit(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = src->drv; virStorageFileBackendFsPrivPtr priv = NULL; VIR_DEBUG("initializing FS storage file %p (%s:%s)[%u:%u]", src, virStorageTypeToString(virStorageSourceGetActualType(src)), src->path, - (unsigned int)src->drv->uid, (unsigned int)src->drv->gid); + (unsigned int)drv->uid, (unsigned int)drv->gid); priv = g_new0(virStorageFileBackendFsPriv, 1); - src->drv->priv = priv; + drv->priv = priv; return 0; } @@ -84,10 +86,11 @@ virStorageFileBackendFileInit(virStorageSourcePtr src) static int virStorageFileBackendFileCreate(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = src->drv; VIR_AUTOCLOSE fd = -1; if ((fd = virFileOpenAs(src->path, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR, - src->drv->uid, src->drv->gid, 0)) < 0) { + drv->uid, drv->gid, 0)) < 0) { errno = -fd; return -1; } @@ -117,11 +120,12 @@ virStorageFileBackendFileRead(virStorageSourcePtr src, size_t len, char **buf) { + virStorageDriverDataPtr drv = src->drv; ssize_t ret = -1; VIR_AUTOCLOSE fd = -1; if ((fd = virFileOpenAs(src->path, O_RDONLY, 0, - src->drv->uid, src->drv->gid, 0)) < 0) { + drv->uid, drv->gid, 0)) < 0) { virReportSystemError(-fd, _("Failed to open file '%s'"), src->path); return -1; @@ -146,7 +150,8 @@ virStorageFileBackendFileRead(virStorageSourcePtr src, static const char * virStorageFileBackendFileGetUniqueIdentifier(virStorageSourcePtr src) { - virStorageFileBackendFsPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendFsPrivPtr priv = drv->priv; if (!priv->canonpath) { if (!(priv->canonpath = virFileCanonicalizePath(src->path))) { @@ -164,8 +169,10 @@ static int virStorageFileBackendFileAccess(virStorageSourcePtr src, int mode) { + virStorageDriverDataPtr drv = src->drv; + return virFileAccessibleAs(src->path, mode, - src->drv->uid, src->drv->gid); + drv->uid, drv->gid); } diff --git a/src/storage/storage_file_gluster.c b/src/storage/storage_file_gluster.c index 0fc6835f11..2560e10d37 100644 --- a/src/storage/storage_file_gluster.c +++ b/src/storage/storage_file_gluster.c @@ -47,7 +47,8 @@ struct _virStorageFileBackendGlusterPriv { static void virStorageFileBackendGlusterDeinit(virStorageSourcePtr src) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; VIR_DEBUG("deinitializing gluster storage file %p (gluster://%s:%u/%s%s)", src, src->hosts->name, src->hosts->port, src->volume, src->path); @@ -57,7 +58,7 @@ virStorageFileBackendGlusterDeinit(virStorageSourcePtr src) VIR_FREE(priv->canonpath); VIR_FREE(priv); - src->drv->priv = NULL; + drv->priv = NULL; } static int @@ -100,6 +101,7 @@ virStorageFileBackendGlusterInitServer(virStorageFileBackendGlusterPrivPtr priv, static int virStorageFileBackendGlusterInit(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = src->drv; virStorageFileBackendGlusterPrivPtr priv = NULL; size_t i; @@ -115,7 +117,7 @@ virStorageFileBackendGlusterInit(virStorageSourcePtr src) VIR_DEBUG("initializing gluster storage file %p " "(priv='%p' volume='%s' path='%s') as [%u:%u]", src, priv, src->volume, src->path, - (unsigned int)src->drv->uid, (unsigned int)src->drv->gid); + (unsigned int)drv->uid, (unsigned int)drv->gid); if (!(priv->vol = glfs_new(src->volume))) { virReportOOMError(); @@ -134,7 +136,7 @@ virStorageFileBackendGlusterInit(virStorageSourcePtr src) goto error; } - src->drv->priv = priv; + drv->priv = priv; return 0; @@ -150,7 +152,8 @@ virStorageFileBackendGlusterInit(virStorageSourcePtr src) static int virStorageFileBackendGlusterCreate(virStorageSourcePtr src) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; glfs_fd_t *fd = NULL; if (!(fd = glfs_creat(priv->vol, src->path, @@ -165,7 +168,8 @@ virStorageFileBackendGlusterCreate(virStorageSourcePtr src) static int virStorageFileBackendGlusterUnlink(virStorageSourcePtr src) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; return glfs_unlink(priv->vol, src->path); } @@ -175,7 +179,8 @@ static int virStorageFileBackendGlusterStat(virStorageSourcePtr src, struct stat *st) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; return glfs_stat(priv->vol, src->path, st); } @@ -187,7 +192,8 @@ virStorageFileBackendGlusterRead(virStorageSourcePtr src, size_t len, char **buf) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; glfs_fd_t *fd = NULL; ssize_t ret = -1; char *s; @@ -242,7 +248,8 @@ static int virStorageFileBackendGlusterAccess(virStorageSourcePtr src, int mode) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; return glfs_access(priv->vol, src->path, mode); } @@ -295,7 +302,8 @@ virStorageFileBackendGlusterReadlinkCallback(const char *path, static const char * virStorageFileBackendGlusterGetUniqueIdentifier(virStorageSourcePtr src) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; g_autofree char *filePath = NULL; if (priv->canonpath) @@ -321,7 +329,8 @@ virStorageFileBackendGlusterChown(const virStorageSource *src, uid_t uid, gid_t gid) { - virStorageFileBackendGlusterPrivPtr priv = src->drv->priv; + virStorageDriverDataPtr drv = src->drv; + virStorageFileBackendGlusterPrivPtr priv = drv->priv; return glfs_chown(priv->vol, src->path, uid, gid); } diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 17579126b0..24b47fc788 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -4619,7 +4619,8 @@ virStorageFileGetBackendForSupportCheck(const virStorageSource *src, } if (src->drv) { - *backend = src->drv->backend; + virStorageDriverDataPtr drv = src->drv; + *backend = drv->backend; return 1; } @@ -4715,12 +4716,16 @@ virStorageFileSupportsCreate(const virStorageSource *src) void virStorageFileDeinit(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = NULL; + if (!virStorageFileIsInitialized(src)) return; - if (src->drv->backend && - src->drv->backend->backendDeinit) - src->drv->backend->backendDeinit(src); + drv = src->drv; + + if (drv->backend && + drv->backend->backendDeinit) + drv->backend->backendDeinit(src); VIR_FREE(src->drv); } @@ -4744,26 +4749,28 @@ virStorageFileInitAs(virStorageSourcePtr src, uid_t uid, gid_t gid) { int actualType = virStorageSourceGetActualType(src); - src->drv = g_new0(virStorageDriverData, 1); + virStorageDriverDataPtr drv = g_new0(virStorageDriverData, 1); + + src->drv = drv; if (uid == (uid_t) -1) - src->drv->uid = geteuid(); + drv->uid = geteuid(); else - src->drv->uid = uid; + drv->uid = uid; if (gid == (gid_t) -1) - src->drv->gid = getegid(); + drv->gid = getegid(); else - src->drv->gid = gid; + drv->gid = gid; if (virStorageFileBackendForType(actualType, src->protocol, true, - &src->drv->backend) < 0) + &drv->backend) < 0) goto error; - if (src->drv->backend->backendInit && - src->drv->backend->backendInit(src) < 0) + if (drv->backend->backendInit && + drv->backend->backendInit(src) < 0) goto error; return 0; @@ -4798,15 +4805,22 @@ virStorageFileInit(virStorageSourcePtr src) int virStorageFileCreate(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src) || - !src->drv->backend->storageFileCreate) { + if (!virStorageFileIsInitialized(src)) { errno = ENOSYS; return -2; } - ret = src->drv->backend->storageFileCreate(src); + drv = src->drv; + + if (!drv->backend->storageFileCreate) { + errno = ENOSYS; + return -2; + } + + ret = drv->backend->storageFileCreate(src); VIR_DEBUG("created storage file %p: ret=%d, errno=%d", src, ret, errno); @@ -4828,15 +4842,22 @@ virStorageFileCreate(virStorageSourcePtr src) int virStorageFileUnlink(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src) || - !src->drv->backend->storageFileUnlink) { + if (!virStorageFileIsInitialized(src)) { errno = ENOSYS; return -2; } - ret = src->drv->backend->storageFileUnlink(src); + drv = src->drv; + + if (!drv->backend->storageFileUnlink) { + errno = ENOSYS; + return -2; + } + + ret = drv->backend->storageFileUnlink(src); VIR_DEBUG("unlinked storage file %p: ret=%d, errno=%d", src, ret, errno); @@ -4858,15 +4879,22 @@ int virStorageFileStat(virStorageSourcePtr src, struct stat *st) { + virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src) || - !src->drv->backend->storageFileStat) { + if (!virStorageFileIsInitialized(src)) { errno = ENOSYS; return -2; } - ret = src->drv->backend->storageFileStat(src, st); + drv = src->drv; + + if (!drv->backend->storageFileStat) { + errno = ENOSYS; + return -2; + } + + ret = drv->backend->storageFileStat(src, st); VIR_DEBUG("stat of storage file %p: ret=%d, errno=%d", src, ret, errno); @@ -4893,6 +4921,7 @@ virStorageFileRead(virStorageSourcePtr src, size_t len, char **buf) { + virStorageDriverDataPtr drv = NULL; ssize_t ret; if (!virStorageFileIsInitialized(src)) { @@ -4901,10 +4930,12 @@ virStorageFileRead(virStorageSourcePtr src, return -1; } - if (!src->drv->backend->storageFileRead) + drv = src->drv; + + if (!drv->backend->storageFileRead) return -2; - ret = src->drv->backend->storageFileRead(src, offset, len, buf); + ret = drv->backend->storageFileRead(src, offset, len, buf); VIR_DEBUG("read '%zd' bytes from storage '%p' starting at offset '%zu'", ret, src, offset); @@ -4924,13 +4955,17 @@ virStorageFileRead(virStorageSourcePtr src, const char * virStorageFileGetUniqueIdentifier(virStorageSourcePtr src) { + virStorageDriverDataPtr drv = NULL; + if (!virStorageFileIsInitialized(src)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("storage file backend not initialized")); return NULL; } - if (!src->drv->backend->storageFileGetUniqueIdentifier) { + drv = src->drv; + + if (!drv->backend->storageFileGetUniqueIdentifier) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unique storage file identifier not implemented for " "storage type %s (protocol: %s)'"), @@ -4939,7 +4974,7 @@ virStorageFileGetUniqueIdentifier(virStorageSourcePtr src) return NULL; } - return src->drv->backend->storageFileGetUniqueIdentifier(src); + return drv->backend->storageFileGetUniqueIdentifier(src); } @@ -4957,13 +4992,21 @@ int virStorageFileAccess(virStorageSourcePtr src, int mode) { - if (!virStorageFileIsInitialized(src) || - !src->drv->backend->storageFileAccess) { + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileAccess) { errno = ENOSYS; return -2; } - return src->drv->backend->storageFileAccess(src, mode); + return drv->backend->storageFileAccess(src, mode); } @@ -4983,8 +5026,16 @@ virStorageFileChown(const virStorageSource *src, uid_t uid, gid_t gid) { - if (!virStorageFileIsInitialized(src) || - !src->drv->backend->storageFileChown) { + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileChown) { errno = ENOSYS; return -2; } @@ -4992,7 +5043,7 @@ virStorageFileChown(const virStorageSource *src, 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); + return drv->backend->storageFileChown(src, uid, gid); } @@ -5012,8 +5063,9 @@ virStorageFileReportBrokenChain(int errcode, virStorageSourcePtr parent) { if (src->drv) { - unsigned int access_user = src->drv->uid; - unsigned int access_group = src->drv->gid; + virStorageDriverDataPtr drv = src->drv; + unsigned int access_user = drv->uid; + unsigned int access_group = drv->gid; if (src == parent) { virReportSystemError(errcode, diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 5689c39092..1a722e1fa4 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -263,9 +263,6 @@ struct _virStorageSourceSlice { }; -typedef struct _virStorageDriverData virStorageDriverData; -typedef virStorageDriverData *virStorageDriverDataPtr; - typedef struct _virStorageSource virStorageSource; typedef virStorageSource *virStorageSourcePtr; @@ -337,7 +334,7 @@ struct _virStorageSource { virStorageSourcePtr backingStore; /* metadata for storage driver access to remote and local volumes */ - virStorageDriverDataPtr drv; + void *drv; /* metadata about storage image which need separate fields */ /* Relative name by which this image was opened from its parent, or NULL diff --git a/src/util/virstoragefilebackend.h b/src/util/virstoragefilebackend.h index c7af77bf8f..43b36e95bc 100644 --- a/src/util/virstoragefilebackend.h +++ b/src/util/virstoragefilebackend.h @@ -28,6 +28,8 @@ typedef struct _virStorageFileBackend virStorageFileBackend; typedef virStorageFileBackend *virStorageFileBackendPtr; +typedef struct _virStorageDriverData virStorageDriverData; +typedef virStorageDriverData *virStorageDriverDataPtr; struct _virStorageDriverData { virStorageFileBackendPtr backend; void *priv; -- 2.29.2

Introduce a new storage_file directory where we will keep storage file related code. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 4 +- src/meson.build | 1 + src/storage/meson.build | 30 +-------------- src/storage_file/meson.build | 38 +++++++++++++++++++ .../storage_file_fs.c | 0 .../storage_file_fs.h | 0 .../storage_file_gluster.c | 0 .../storage_file_gluster.h | 0 8 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 src/storage_file/meson.build rename src/{storage => storage_file}/storage_file_fs.c (100%) rename src/{storage => storage_file}/storage_file_fs.h (100%) rename src/{storage => storage_file}/storage_file_gluster.c (100%) rename src/{storage => storage_file}/storage_file_gluster.h (100%) diff --git a/po/POTFILES.in b/po/POTFILES.in index 14636d4b93..e9fc3991f1 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -222,9 +222,9 @@ @SRCDIR@src/storage/storage_backend_vstorage.c @SRCDIR@src/storage/storage_backend_zfs.c @SRCDIR@src/storage/storage_driver.c -@SRCDIR@src/storage/storage_file_fs.c -@SRCDIR@src/storage/storage_file_gluster.c @SRCDIR@src/storage/storage_util.c +@SRCDIR@src/storage_file/storage_file_fs.c +@SRCDIR@src/storage_file/storage_file_gluster.c @SRCDIR@src/test/test_driver.c @SRCDIR@src/util/iohelper.c @SRCDIR@src/util/viralloc.c diff --git a/src/meson.build b/src/meson.build index 7c478219d6..3aa9498b98 100644 --- a/src/meson.build +++ b/src/meson.build @@ -266,6 +266,7 @@ subdir('nwfilter') subdir('secret') subdir('security') subdir('storage') +subdir('storage_file') subdir('bhyve') subdir('esx') diff --git a/src/storage/meson.build b/src/storage/meson.build index b4cefe9a89..8537359e93 100644 --- a/src/storage/meson.build +++ b/src/storage/meson.build @@ -15,10 +15,6 @@ storage_backend_fs_sources = [ 'storage_backend_fs.c', ] -stoarge_file_fs_sources = [ - 'storage_file_fs.c', -] - storage_backend_disk_sources = [ 'storage_backend_disk.c', ] @@ -31,10 +27,6 @@ storage_backend_gluster_sources = [ 'storage_backend_gluster.c', ] -storage_file_gluster_sources = [ - 'storage_file_gluster.c', -] - storage_backend_iscsi_sources = [ 'storage_backend_iscsi.c', ] @@ -72,7 +64,6 @@ storage_backend_zfs_sources = [ ] storage_backend_install_dir = libdir / 'libvirt' / 'storage-backend' -storage_file_install_dir = libdir / 'libvirt' / 'storage-file' if conf.has('WITH_STORAGE') storage_driver_impl_lib = static_library( @@ -109,14 +100,6 @@ if conf.has('WITH_STORAGE') 'install_dir': storage_backend_install_dir, } - virt_modules += { - 'name': 'virt_storage_file_fs', - 'sources': [ - files(stoarge_file_fs_sources), - ], - 'install_dir': storage_file_install_dir, - } - virt_daemons += { 'name': 'virtstoraged', 'c_args': [ @@ -181,17 +164,6 @@ if conf.has('WITH_STORAGE_GLUSTER') ], 'install_dir': storage_backend_install_dir, } - - virt_modules += { - 'name': 'virt_storage_file_gluster', - 'sources': [ - files(storage_file_gluster_sources), - ], - 'deps': [ - glusterfs_dep, - ], - 'install_dir': storage_file_install_dir, - } endif if conf.has('WITH_STORAGE_ISCSI') @@ -303,3 +275,5 @@ if conf.has('WITH_STORAGE_ZFS') 'install_dir': storage_backend_install_dir, } endif + +storage_inc_dir = include_directories('.') diff --git a/src/storage_file/meson.build b/src/storage_file/meson.build new file mode 100644 index 0000000000..20eb0176fc --- /dev/null +++ b/src/storage_file/meson.build @@ -0,0 +1,38 @@ +stoarge_file_fs_sources = [ + 'storage_file_fs.c', +] + +storage_file_gluster_sources = [ + 'storage_file_gluster.c', +] + +storage_file_install_dir = libdir / 'libvirt' / 'storage-file' + +if conf.has('WITH_STORAGE') + virt_modules += { + 'name': 'virt_storage_file_fs', + 'sources': [ + files(stoarge_file_fs_sources), + ], + 'include': [ + storage_inc_dir, + ], + 'install_dir': storage_file_install_dir, + } +endif + +if conf.has('WITH_STORAGE_GLUSTER') + virt_modules += { + 'name': 'virt_storage_file_gluster', + 'sources': [ + files(storage_file_gluster_sources), + ], + 'include': [ + storage_inc_dir, + ], + 'deps': [ + glusterfs_dep, + ], + 'install_dir': storage_file_install_dir, + } +endif diff --git a/src/storage/storage_file_fs.c b/src/storage_file/storage_file_fs.c similarity index 100% rename from src/storage/storage_file_fs.c rename to src/storage_file/storage_file_fs.c diff --git a/src/storage/storage_file_fs.h b/src/storage_file/storage_file_fs.h similarity index 100% rename from src/storage/storage_file_fs.h rename to src/storage_file/storage_file_fs.h diff --git a/src/storage/storage_file_gluster.c b/src/storage_file/storage_file_gluster.c similarity index 100% rename from src/storage/storage_file_gluster.c rename to src/storage_file/storage_file_gluster.c diff --git a/src/storage/storage_file_gluster.h b/src/storage_file/storage_file_gluster.h similarity index 100% rename from src/storage/storage_file_gluster.h rename to src/storage_file/storage_file_gluster.h -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:18 +0100, Pavel Hrdina wrote:
Introduce a new storage_file directory where we will keep storage file related code.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 4 +- src/meson.build | 1 + src/storage/meson.build | 30 +-------------- src/storage_file/meson.build | 38 +++++++++++++++++++ .../storage_file_fs.c | 0 .../storage_file_fs.h | 0 .../storage_file_gluster.c | 0 .../storage_file_gluster.h | 0 8 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 src/storage_file/meson.build rename src/{storage => storage_file}/storage_file_fs.c (100%) rename src/{storage => storage_file}/storage_file_fs.h (100%) rename src/{storage => storage_file}/storage_file_gluster.c (100%) rename src/{storage => storage_file}/storage_file_gluster.h (100%)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

It's only relevant for QEMU driver. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/libvirt_private.syms | 1 - src/qemu/qemu_domain.c | 38 ++++++++++++++++++++++++++++++++------ src/util/virstoragefile.c | 25 ------------------------- src/util/virstoragefile.h | 5 ----- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c325040b60..84b650cb86 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3175,7 +3175,6 @@ virStorageSourceChainHasManagedPR; virStorageSourceChainHasNVMe; virStorageSourceClear; virStorageSourceCopy; -virStorageSourceFindByNodeName; virStorageSourceGetActualType; virStorageSourceGetSecurityLabelDef; virStorageSourceHasBacking; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index dd79cfd9d9..966608882f 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -2582,6 +2582,32 @@ qemuDomainObjPrivateXMLParseBlockjobChain(xmlNodePtr node, } +/** + * qemuDomainVirStorageSourceFindByNodeName: + * @top: backing chain top + * @nodeName: node name to find in backing chain + * + * Looks up the given storage source in the backing chain and returns the + * pointer to it. + * On failure NULL is returned and no error is reported. + */ +static virStorageSourcePtr +qemuDomainVirStorageSourceFindByNodeName(virStorageSourcePtr top, + const char *nodeName) +{ + virStorageSourcePtr tmp; + + for (tmp = top; virStorageSourceIsBacking(tmp); tmp = tmp->backingStore) { + if ((tmp->nodeformat && STREQ(tmp->nodeformat, nodeName)) || + (tmp->nodestorage && STREQ(tmp->nodestorage, nodeName))) + return tmp; + } + + return NULL; +} + + + static void qemuDomainObjPrivateXMLParseBlockjobNodename(qemuBlockJobDataPtr job, const char *xpath, @@ -2596,15 +2622,15 @@ qemuDomainObjPrivateXMLParseBlockjobNodename(qemuBlockJobDataPtr job, return; if (job->disk && - (*src = virStorageSourceFindByNodeName(job->disk->src, nodename))) + (*src = qemuDomainVirStorageSourceFindByNodeName(job->disk->src, nodename))) return; if (job->chain && - (*src = virStorageSourceFindByNodeName(job->chain, nodename))) + (*src = qemuDomainVirStorageSourceFindByNodeName(job->chain, nodename))) return; if (job->mirrorChain && - (*src = virStorageSourceFindByNodeName(job->mirrorChain, nodename))) + (*src = qemuDomainVirStorageSourceFindByNodeName(job->mirrorChain, nodename))) return; /* the node was in the XML but was not found in the job definitions */ @@ -10028,11 +10054,11 @@ qemuDomainDiskLookupByNodename(virDomainDefPtr def, for (i = 0; i < def->ndisks; i++) { virDomainDiskDefPtr domdisk = def->disks[i]; - if ((*src = virStorageSourceFindByNodeName(domdisk->src, nodename))) + if ((*src = qemuDomainVirStorageSourceFindByNodeName(domdisk->src, nodename))) return domdisk; if (domdisk->mirror && - (*src = virStorageSourceFindByNodeName(domdisk->mirror, nodename))) + (*src = qemuDomainVirStorageSourceFindByNodeName(domdisk->mirror, nodename))) return domdisk; } @@ -10041,7 +10067,7 @@ qemuDomainDiskLookupByNodename(virDomainDefPtr def, virDomainBackupDiskDefPtr backupdisk = backupdef->disks + i; if (backupdisk->store && - (*src = virStorageSourceFindByNodeName(backupdisk->store, nodename))) + (*src = qemuDomainVirStorageSourceFindByNodeName(backupdisk->store, nodename))) return virDomainDiskByTarget(def, backupdisk->name); } } diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 24b47fc788..13a86f34e5 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -4445,31 +4445,6 @@ virStorageSourceIsRelative(virStorageSourcePtr src) } -/** - * virStorageSourceFindByNodeName: - * @top: backing chain top - * @nodeName: node name to find in backing chain - * - * Looks up the given storage source in the backing chain and returns the - * pointer to it. - * On failure NULL is returned and no error is reported. - */ -virStorageSourcePtr -virStorageSourceFindByNodeName(virStorageSourcePtr top, - const char *nodeName) -{ - virStorageSourcePtr tmp; - - for (tmp = top; virStorageSourceIsBacking(tmp); tmp = tmp->backingStore) { - if ((tmp->nodeformat && STREQ(tmp->nodeformat, nodeName)) || - (tmp->nodestorage && STREQ(tmp->nodestorage, nodeName))) - return tmp; - } - - return NULL; -} - - static unsigned int virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol) { diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 1a722e1fa4..46da6a8a18 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -521,11 +521,6 @@ int virStorageSourceNewFromBackingAbsolute(const char *path, bool virStorageSourceIsRelative(virStorageSourcePtr src); -virStorageSourcePtr -virStorageSourceFindByNodeName(virStorageSourcePtr top, - const char *nodeName) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - void virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src) ATTRIBUTE_NONNULL(1); -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:19 +0100, Pavel Hrdina wrote:
It's only relevant for QEMU driver.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/libvirt_private.syms | 1 - src/qemu/qemu_domain.c | 38 ++++++++++++++++++++++++++++++++------ src/util/virstoragefile.c | 25 ------------------------- src/util/virstoragefile.h | 5 ----- 4 files changed, 32 insertions(+), 37 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

This code is not directly relevant to virStorageSource so move it to separate file. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 6 +- src/qemu/qemu_driver.c | 1 + src/storage/storage_backend_gluster.c | 1 + src/storage/storage_util.c | 1 + src/util/meson.build | 1 + src/util/virstoragefile.c | 939 +------------------------ src/util/virstoragefile.h | 11 - src/util/virstoragefileprobe.c | 967 ++++++++++++++++++++++++++ src/util/virstoragefileprobe.h | 44 ++ 10 files changed, 1026 insertions(+), 946 deletions(-) create mode 100644 src/util/virstoragefileprobe.c create mode 100644 src/util/virstoragefileprobe.h diff --git a/po/POTFILES.in b/po/POTFILES.in index e9fc3991f1..19eb15ada0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -306,6 +306,7 @@ @SRCDIR@src/util/virstorageencryption.c @SRCDIR@src/util/virstoragefile.c @SRCDIR@src/util/virstoragefilebackend.c +@SRCDIR@src/util/virstoragefileprobe.c @SRCDIR@src/util/virstring.c @SRCDIR@src/util/virsysinfo.c @SRCDIR@src/util/virsystemd.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 84b650cb86..2dfc7e32d5 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3148,7 +3148,6 @@ virStorageFileInit; virStorageFileInitAs; virStorageFileParseBackingStoreStr; virStorageFileParseChainIndex; -virStorageFileProbeFormat; virStorageFileRead; virStorageFileReportBrokenChain; virStorageFileStat; @@ -3212,6 +3211,11 @@ virStorageTypeToString; virStorageFileBackendRegister; +# util/virstoragefileprobe.h +virStorageFileProbeFormat; +virStorageFileProbeGetMetadata; + + # util/virstring.h virSkipSpaces; virSkipSpacesAndBackslash; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 027617deef..34a8fbe233 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -83,6 +83,7 @@ #include "domain_nwfilter.h" #include "virhook.h" #include "virstoragefile.h" +#include "virstoragefileprobe.h" #include "virfile.h" #include "virfdstream.h" #include "configmake.h" diff --git a/src/storage/storage_backend_gluster.c b/src/storage/storage_backend_gluster.c index 6c99c270da..205a707a17 100644 --- a/src/storage/storage_backend_gluster.c +++ b/src/storage/storage_backend_gluster.c @@ -28,6 +28,7 @@ #include "viralloc.h" #include "virerror.h" #include "virlog.h" +#include "virstoragefileprobe.h" #include "virstring.h" #include "viruri.h" #include "storage_util.h" diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 2e2c7dc68a..4117127d65 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -62,6 +62,7 @@ #include "vircrypto.h" #include "viruuid.h" #include "virstoragefile.h" +#include "virstoragefileprobe.h" #include "storage_util.h" #include "virlog.h" #include "virfile.h" diff --git a/src/util/meson.build b/src/util/meson.build index 395e70fd38..9fb270fadd 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -91,6 +91,7 @@ util_sources = [ 'virstorageencryption.c', 'virstoragefile.c', 'virstoragefilebackend.c', + 'virstoragefileprobe.c', 'virstring.c', 'virsysinfo.c', 'virsystemd.c', diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 13a86f34e5..98a3222d09 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -22,8 +22,6 @@ #include <config.h> #include "virstoragefile.h" -#include <unistd.h> -#include <fcntl.h> #include "viralloc.h" #include "virxml.h" #include "viruuid.h" @@ -32,13 +30,13 @@ #include "virfile.h" #include "vircommand.h" #include "virhash.h" -#include "virendian.h" #include "virstring.h" #include "viruri.h" #include "virbuffer.h" #include "virjson.h" #include "virstorageencryption.h" #include "virstoragefilebackend.h" +#include "virstoragefileprobe.h" #include "virsecret.h" #include "virutil.h" @@ -113,650 +111,6 @@ VIR_ENUM_IMPL(virStorageAuth, "none", "chap", "ceph", ); -enum lv_endian { - LV_LITTLE_ENDIAN = 1, /* 1234 */ - LV_BIG_ENDIAN /* 4321 */ -}; - -enum { - BACKING_STORE_OK, - BACKING_STORE_INVALID, - BACKING_STORE_ERROR, -}; - -#define FILE_TYPE_VERSIONS_LAST 3 - -struct FileEncryptionInfo { - int format; /* Encryption format to assign */ - - int magicOffset; /* Byte offset of the magic */ - const char *magic; /* Optional string of magic */ - - enum lv_endian endian; /* Endianness of file format */ - - int versionOffset; /* Byte offset from start of file - * where we find version number, - * -1 to always fail the version test, - * -2 to always pass the version test */ - int versionSize; /* Size in bytes of version data (0, 2, or 4) */ - int versionNumbers[FILE_TYPE_VERSIONS_LAST]; - /* Version numbers to validate. Zeroes are ignored. */ - - int modeOffset; /* Byte offset of the format native encryption mode */ - char modeValue; /* Value expected at offset */ - - int payloadOffset; /* start offset of the volume data (in 512 byte sectors) */ -}; - -struct FileTypeInfo { - int magicOffset; /* Byte offset of the magic */ - const char *magic; /* Optional string of file magic - * to check at head of file */ - enum lv_endian endian; /* Endianness of file format */ - - int versionOffset; /* Byte offset from start of file - * where we find version number, - * -1 to always fail the version test, - * -2 to always pass the version test */ - int versionSize; /* Size in bytes of version data (0, 2, or 4) */ - int versionNumbers[FILE_TYPE_VERSIONS_LAST]; - /* Version numbers to validate. Zeroes are ignored. */ - int sizeOffset; /* Byte offset from start of file - * where we find capacity info, - * -1 to use st_size as capacity */ - int sizeBytes; /* Number of bytes for size field */ - int sizeMultiplier; /* A scaling factor if size is not in bytes */ - /* Store a COW base image path (possibly relative), - * or NULL if there is no COW base image, to RES; - * return BACKING_STORE_* */ - const struct FileEncryptionInfo *cryptInfo; /* Encryption info */ - int (*getBackingStore)(char **res, int *format, - const char *buf, size_t buf_size); - int (*getFeatures)(virBitmapPtr *features, int format, - char *buf, ssize_t len); -}; - - -static int cowGetBackingStore(char **, int *, - const char *, size_t); -static int qcowXGetBackingStore(char **, int *, - const char *, size_t); -static int qcow2GetFeatures(virBitmapPtr *features, int format, - char *buf, ssize_t len); -static int vmdk4GetBackingStore(char **, int *, - const char *, size_t); -static int -qedGetBackingStore(char **, int *, const char *, size_t); - -#define QCOWX_HDR_VERSION (4) -#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) -#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) -#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) - -#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1+2) -#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) - -#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) -#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) - -#define QCOW2_HDR_EXTENSION_END 0 -#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA - -#define QCOW2v3_HDR_FEATURES_INCOMPATIBLE (QCOW2_HDR_TOTAL_SIZE) -#define QCOW2v3_HDR_FEATURES_COMPATIBLE (QCOW2v3_HDR_FEATURES_INCOMPATIBLE+8) -#define QCOW2v3_HDR_FEATURES_AUTOCLEAR (QCOW2v3_HDR_FEATURES_COMPATIBLE+8) - -/* The location of the header size [4 bytes] */ -#define QCOW2v3_HDR_SIZE (QCOW2_HDR_TOTAL_SIZE+8+8+8+4) - -#define QED_HDR_FEATURES_OFFSET (4+4+4+4) -#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8) -#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8) -#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4) -#define QED_F_BACKING_FILE 0x01 -#define QED_F_BACKING_FORMAT_NO_PROBE 0x04 - -#define PLOOP_IMAGE_SIZE_OFFSET 36 -#define PLOOP_SIZE_MULTIPLIER 512 - -#define LUKS_HDR_MAGIC_LEN 6 -#define LUKS_HDR_VERSION_LEN 2 -#define LUKS_HDR_CIPHER_NAME_LEN 32 -#define LUKS_HDR_CIPHER_MODE_LEN 32 -#define LUKS_HDR_HASH_SPEC_LEN 32 -#define LUKS_HDR_PAYLOAD_LEN 4 - -/* Format described by qemu commit id '3e308f20e' */ -#define LUKS_HDR_VERSION_OFFSET LUKS_HDR_MAGIC_LEN -#define LUKS_HDR_PAYLOAD_OFFSET (LUKS_HDR_MAGIC_LEN+\ - LUKS_HDR_VERSION_LEN+\ - LUKS_HDR_CIPHER_NAME_LEN+\ - LUKS_HDR_CIPHER_MODE_LEN+\ - LUKS_HDR_HASH_SPEC_LEN) - -static struct FileEncryptionInfo const luksEncryptionInfo[] = { - { - .format = VIR_STORAGE_ENCRYPTION_FORMAT_LUKS, - - /* Magic is 'L','U','K','S', 0xBA, 0xBE */ - .magicOffset = 0, - .magic = "\x4c\x55\x4b\x53\xba\xbe", - .endian = LV_BIG_ENDIAN, - - .versionOffset = LUKS_HDR_VERSION_OFFSET, - .versionSize = LUKS_HDR_VERSION_LEN, - .versionNumbers = {1}, - - .modeOffset = -1, - .modeValue = -1, - - .payloadOffset = LUKS_HDR_PAYLOAD_OFFSET, - }, - { 0 } -}; - -static struct FileEncryptionInfo const qcow1EncryptionInfo[] = { - { - .format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, - - .magicOffset = 0, - .magic = NULL, - .endian = LV_BIG_ENDIAN, - - .versionOffset = -1, - .versionSize = 0, - .versionNumbers = {}, - - .modeOffset = QCOW1_HDR_CRYPT, - .modeValue = 1, - - .payloadOffset = -1, - }, - { 0 } -}; - -static struct FileEncryptionInfo const qcow2EncryptionInfo[] = { - { - .format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, - - .magicOffset = 0, - .magic = NULL, - .endian = LV_BIG_ENDIAN, - - .versionOffset = -1, - .versionSize = 0, - .versionNumbers = {}, - - .modeOffset = QCOW2_HDR_CRYPT, - .modeValue = 1, - - .payloadOffset = -1, - }, - { - .format = VIR_STORAGE_ENCRYPTION_FORMAT_LUKS, - - .magicOffset = 0, - .magic = NULL, - .endian = LV_BIG_ENDIAN, - - .versionOffset = -1, - .versionSize = 0, - .versionNumbers = {}, - - .modeOffset = QCOW2_HDR_CRYPT, - .modeValue = 2, - - .payloadOffset = -1, - }, - { 0 } -}; - -static struct FileTypeInfo const fileTypeInfo[] = { - [VIR_STORAGE_FILE_NONE] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, - [VIR_STORAGE_FILE_RAW] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, - luksEncryptionInfo, - NULL, NULL }, - [VIR_STORAGE_FILE_DIR] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, - [VIR_STORAGE_FILE_BOCHS] = { - /*"Bochs Virtual HD Image", */ /* Untested */ - 0, NULL, - LV_LITTLE_ENDIAN, 64, 4, {0x20000}, - 32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL - }, - [VIR_STORAGE_FILE_CLOOP] = { - /* #!/bin/sh - #V2.0 Format - modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1 - */ /* Untested */ - 0, NULL, - LV_LITTLE_ENDIAN, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL - }, - [VIR_STORAGE_FILE_DMG] = { - /* XXX QEMU says there's no magic for dmg, - * /usr/share/misc/magic lists double magic (both offsets - * would have to match) but then disables that check. */ - 0, NULL, - 0, -1, 0, {0}, - -1, 0, 0, NULL, NULL, NULL - }, - [VIR_STORAGE_FILE_ISO] = { - 32769, "CD001", - LV_LITTLE_ENDIAN, -2, 0, {0}, - -1, 0, 0, NULL, NULL, NULL - }, - [VIR_STORAGE_FILE_VPC] = { - 0, "conectix", - LV_BIG_ENDIAN, 12, 4, {0x10000}, - 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL - }, - /* TODO: add getBackingStore function */ - [VIR_STORAGE_FILE_VDI] = { - 64, "\x7f\x10\xda\xbe", - LV_LITTLE_ENDIAN, 68, 4, {0x00010001}, - 64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL}, - - /* Not direct file formats, but used for various drivers */ - [VIR_STORAGE_FILE_FAT] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, - [VIR_STORAGE_FILE_VHD] = { 0, NULL, LV_LITTLE_ENDIAN, - -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, - [VIR_STORAGE_FILE_PLOOP] = { 0, "WithouFreSpacExt", LV_LITTLE_ENDIAN, - -2, 0, {0}, PLOOP_IMAGE_SIZE_OFFSET, 0, - PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL }, - - /* All formats with a backing store probe below here */ - [VIR_STORAGE_FILE_COW] = { - 0, "OOOM", - LV_BIG_ENDIAN, 4, 4, {2}, - 4+4+1024+4, 8, 1, NULL, cowGetBackingStore, NULL - }, - [VIR_STORAGE_FILE_QCOW] = { - 0, "QFI", - LV_BIG_ENDIAN, 4, 4, {1}, - QCOWX_HDR_IMAGE_SIZE, 8, 1, - qcow1EncryptionInfo, - qcowXGetBackingStore, NULL - }, - [VIR_STORAGE_FILE_QCOW2] = { - 0, "QFI", - LV_BIG_ENDIAN, 4, 4, {2, 3}, - QCOWX_HDR_IMAGE_SIZE, 8, 1, - qcow2EncryptionInfo, - qcowXGetBackingStore, - qcow2GetFeatures - }, - [VIR_STORAGE_FILE_QED] = { - /* https://wiki.qemu.org/Features/QED */ - 0, "QED", - LV_LITTLE_ENDIAN, -2, 0, {0}, - QED_HDR_IMAGE_SIZE, 8, 1, NULL, qedGetBackingStore, NULL - }, - [VIR_STORAGE_FILE_VMDK] = { - 0, "KDMV", - LV_LITTLE_ENDIAN, 4, 4, {1, 2, 3}, - 4+4+4, 8, 512, NULL, vmdk4GetBackingStore, NULL - }, -}; -G_STATIC_ASSERT(G_N_ELEMENTS(fileTypeInfo) == VIR_STORAGE_FILE_LAST); - - -/* qcow2 compatible features in the order they appear on-disk */ -enum qcow2CompatibleFeature { - QCOW2_COMPATIBLE_FEATURE_LAZY_REFCOUNTS = 0, - - QCOW2_COMPATIBLE_FEATURE_LAST -}; - -/* conversion to virStorageFileFeature */ -static const int qcow2CompatibleFeatureArray[] = { - VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS, -}; -G_STATIC_ASSERT(G_N_ELEMENTS(qcow2CompatibleFeatureArray) == - QCOW2_COMPATIBLE_FEATURE_LAST); - -static int -cowGetBackingStore(char **res, - int *format, - const char *buf, - size_t buf_size) -{ -#define COW_FILENAME_MAXLEN 1024 - *res = NULL; - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size < 4+4+ COW_FILENAME_MAXLEN) - return BACKING_STORE_INVALID; - if (buf[4+4] == '\0') { /* cow_header_v2.backing_file[0] */ - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - - *res = g_strndup((const char *)buf + 4 + 4, COW_FILENAME_MAXLEN); - return BACKING_STORE_OK; -} - - -static int -qcow2GetExtensions(const char *buf, - size_t buf_size, - int *backingFormat) -{ - size_t offset; - size_t extension_start; - size_t extension_end; - int version = virReadBufInt32BE(buf + QCOWX_HDR_VERSION); - - if (version < 2) { - /* QCow1 doesn't have the extensions capability - * used to store backing format */ - return 0; - } - - if (version == 2) - extension_start = QCOW2_HDR_TOTAL_SIZE; - else - extension_start = virReadBufInt32BE(buf + QCOW2v3_HDR_SIZE); - - /* - * Traditionally QCow2 files had a layout of - * - * [header] - * [backingStoreName] - * - * Although the backingStoreName typically followed - * the header immediately, this was not required by - * the format. By specifying a higher byte offset for - * the backing file offset in the header, it was - * possible to leave space between the header and - * start of backingStore. - * - * This hack is now used to store extensions to the - * qcow2 format: - * - * [header] - * [extensions] - * [backingStoreName] - * - * Thus the file region to search for extensions is - * between the end of the header (QCOW2_HDR_TOTAL_SIZE) - * and the start of the backingStoreName (offset) - * - * for qcow2 v3 images, the length of the header - * is stored at QCOW2v3_HDR_SIZE - */ - extension_end = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET); - if (extension_end > buf_size) - return -1; - - /* - * The extensions take format of - * - * int32: magic - * int32: length - * byte[length]: payload - * - * Unknown extensions can be ignored by skipping - * over "length" bytes in the data stream. - */ - offset = extension_start; - while (offset < (buf_size-8) && - offset < (extension_end-8)) { - unsigned int magic = virReadBufInt32BE(buf + offset); - unsigned int len = virReadBufInt32BE(buf + offset + 4); - - offset += 8; - - if ((offset + len) < offset) - break; - - if ((offset + len) > buf_size) - break; - - switch (magic) { - case QCOW2_HDR_EXTENSION_BACKING_FORMAT: { - g_autofree char *tmp = NULL; - if (!backingFormat) - break; - - tmp = g_new0(char, len + 1); - memcpy(tmp, buf + offset, len); - tmp[len] = '\0'; - - *backingFormat = virStorageFileFormatTypeFromString(tmp); - if (*backingFormat <= VIR_STORAGE_FILE_NONE) - return -1; - break; - } - - case QCOW2_HDR_EXTENSION_END: - return 0; - } - - offset += len; - } - - return 0; -} - - -static int -qcowXGetBackingStore(char **res, - int *format, - const char *buf, - size_t buf_size) -{ - unsigned long long offset; - unsigned int size; - - *res = NULL; - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) - return BACKING_STORE_INVALID; - - offset = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET); - if (offset > buf_size) - return BACKING_STORE_INVALID; - - if (offset == 0) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - - size = virReadBufInt32BE(buf + QCOWX_HDR_BACKING_FILE_SIZE); - if (size == 0) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - if (size > 1023) - return BACKING_STORE_INVALID; - if (offset + size > buf_size || offset + size < offset) - return BACKING_STORE_INVALID; - *res = g_new0(char, size + 1); - memcpy(*res, buf + offset, size); - (*res)[size] = '\0'; - - if (qcow2GetExtensions(buf, buf_size, format) < 0) - return BACKING_STORE_INVALID; - - return BACKING_STORE_OK; -} - - -static int -vmdk4GetBackingStore(char **res, - int *format, - const char *buf, - size_t buf_size) -{ - static const char prefix[] = "parentFileNameHint=\""; - char *start, *end; - size_t len; - g_autofree char *desc = NULL; - - desc = g_new0(char, VIR_STORAGE_MAX_HEADER); - - *res = NULL; - /* - * Technically this should have been VMDK, since - * VMDK spec / VMware impl only support VMDK backed - * by VMDK. QEMU isn't following this though and - * does probing on VMDK backing files, hence we set - * AUTO - */ - *format = VIR_STORAGE_FILE_AUTO; - - if (buf_size <= 0x200) - return BACKING_STORE_INVALID; - - len = buf_size - 0x200; - if (len > VIR_STORAGE_MAX_HEADER) - len = VIR_STORAGE_MAX_HEADER; - memcpy(desc, buf + 0x200, len); - desc[len] = '\0'; - start = strstr(desc, prefix); - if (start == NULL) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - start += strlen(prefix); - end = strchr(start, '"'); - if (end == NULL) - return BACKING_STORE_INVALID; - - if (end == start) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - *end = '\0'; - *res = g_strdup(start); - - return BACKING_STORE_OK; -} - -static int -qedGetBackingStore(char **res, - int *format, - const char *buf, - size_t buf_size) -{ - unsigned long long flags; - unsigned long offset, size; - - *res = NULL; - /* Check if this image has a backing file */ - if (buf_size < QED_HDR_FEATURES_OFFSET+8) - return BACKING_STORE_INVALID; - flags = virReadBufInt64LE(buf + QED_HDR_FEATURES_OFFSET); - if (!(flags & QED_F_BACKING_FILE)) { - *format = VIR_STORAGE_FILE_NONE; - return BACKING_STORE_OK; - } - - /* Parse the backing file */ - if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8) - return BACKING_STORE_INVALID; - offset = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_OFFSET); - if (offset > buf_size) - return BACKING_STORE_INVALID; - size = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_SIZE); - if (size == 0) - return BACKING_STORE_OK; - if (offset + size > buf_size || offset + size < offset) - return BACKING_STORE_INVALID; - *res = g_new0(char, size + 1); - memcpy(*res, buf + offset, size); - (*res)[size] = '\0'; - - if (flags & QED_F_BACKING_FORMAT_NO_PROBE) - *format = VIR_STORAGE_FILE_RAW; - else - *format = VIR_STORAGE_FILE_AUTO_SAFE; - - return BACKING_STORE_OK; -} - - -static bool -virStorageFileMatchesMagic(int magicOffset, - const char *magic, - char *buf, - size_t buflen) -{ - int mlen; - - if (magic == NULL) - return false; - - /* Validate magic data */ - mlen = strlen(magic); - if (magicOffset + mlen > buflen) - return false; - - if (memcmp(buf + magicOffset, magic, mlen) != 0) - return false; - - return true; -} - - -static bool -virStorageFileMatchesVersion(int versionOffset, - int versionSize, - const int *versionNumbers, - int endian, - char *buf, - size_t buflen) -{ - int version; - size_t i; - - /* Validate version number info */ - if (versionOffset == -1) - return false; - - /* -2 == non-versioned file format, so trivially match */ - if (versionOffset == -2) - return true; - - /* A positive versionOffset, requires using a valid versionSize */ - if (versionSize != 2 && versionSize != 4) - return false; - - if ((versionOffset + versionSize) > buflen) - return false; - - if (endian == LV_LITTLE_ENDIAN) { - if (versionSize == 4) - version = virReadBufInt32LE(buf + - versionOffset); - else - version = virReadBufInt16LE(buf + - versionOffset); - } else { - if (versionSize == 4) - version = virReadBufInt32BE(buf + - versionOffset); - else - version = virReadBufInt16BE(buf + - versionOffset); - } - - for (i = 0; - i < FILE_TYPE_VERSIONS_LAST && versionNumbers[i]; - i++) { - VIR_DEBUG("Compare detected version %d vs one of the expected versions %d", - version, versionNumbers[i]); - if (version == versionNumbers[i]) - return true; - } - - return false; -} bool virStorageIsFile(const char *backing) @@ -792,289 +146,6 @@ virStorageIsRelative(const char *backing) } -static int -virStorageFileProbeFormatFromBuf(const char *path, - char *buf, - size_t buflen) -{ - int format = VIR_STORAGE_FILE_RAW; - size_t i; - int possibleFormat = VIR_STORAGE_FILE_RAW; - VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen); - - /* First check file magic */ - for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) { - if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset, - fileTypeInfo[i].magic, - buf, buflen)) { - if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset, - fileTypeInfo[i].versionSize, - fileTypeInfo[i].versionNumbers, - fileTypeInfo[i].endian, - buf, buflen)) { - possibleFormat = i; - continue; - } - format = i; - goto cleanup; - } - } - - if (possibleFormat != VIR_STORAGE_FILE_RAW) - VIR_WARN("File %s matches %s magic, but version is wrong. " - "Please report new version to libvir-list@redhat.com", - path, virStorageFileFormatTypeToString(possibleFormat)); - - cleanup: - VIR_DEBUG("format=%d", format); - return format; -} - - -static int -qcow2GetFeatures(virBitmapPtr *features, - int format, - char *buf, - ssize_t len) -{ - int version = -1; - virBitmapPtr feat = NULL; - uint64_t bits; - size_t i; - - version = virReadBufInt32BE(buf + fileTypeInfo[format].versionOffset); - - if (version == 2) - return 0; - - if (len < QCOW2v3_HDR_SIZE) - return -1; - - feat = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST); - - /* todo: check for incompatible or autoclear features? */ - bits = virReadBufInt64BE(buf + QCOW2v3_HDR_FEATURES_COMPATIBLE); - for (i = 0; i < QCOW2_COMPATIBLE_FEATURE_LAST; i++) { - if (bits & ((uint64_t) 1 << i)) - ignore_value(virBitmapSetBit(feat, qcow2CompatibleFeatureArray[i])); - } - - *features = feat; - return 0; -} - - -static bool -virStorageFileHasEncryptionFormat(const struct FileEncryptionInfo *info, - char *buf, - size_t len) -{ - if (!info->magic && info->modeOffset == -1) - return false; /* Shouldn't happen - expect at least one */ - - if (info->magic) { - if (!virStorageFileMatchesMagic(info->magicOffset, - info->magic, - buf, len)) - return false; - - if (info->versionOffset != -1 && - !virStorageFileMatchesVersion(info->versionOffset, - info->versionSize, - info->versionNumbers, - info->endian, - buf, len)) - return false; - - return true; - } else if (info->modeOffset != -1) { - int crypt_format; - - if (info->modeOffset >= len) - return false; - - crypt_format = virReadBufInt32BE(buf + info->modeOffset); - if (crypt_format != info->modeValue) - return false; - - return true; - } else { - return false; - } -} - - -static int -virStorageFileGetEncryptionPayloadOffset(const struct FileEncryptionInfo *info, - char *buf) -{ - int payload_offset = -1; - - if (info->payloadOffset != -1) { - if (info->endian == LV_LITTLE_ENDIAN) - payload_offset = virReadBufInt32LE(buf + info->payloadOffset); - else - payload_offset = virReadBufInt32BE(buf + info->payloadOffset); - } - - return payload_offset; -} - - -/* Given a header in BUF with length LEN, as parsed from the storage file - * assuming it has the given FORMAT, populate information into META - * with information about the file and its backing store. Return format - * of the backing store as BACKING_FORMAT. PATH and FORMAT have to be - * pre-populated in META. - * - * Note that this function may be called repeatedly on @meta, so it must - * clean up any existing allocated memory which would be overwritten. - */ -static int -virStorageFileGetMetadataInternal(virStorageSourcePtr meta, - char *buf, - size_t len) -{ - int format; - size_t i; - - VIR_DEBUG("path=%s, buf=%p, len=%zu, meta->format=%d", - meta->path, buf, len, meta->format); - - if (meta->format == VIR_STORAGE_FILE_AUTO) - meta->format = virStorageFileProbeFormatFromBuf(meta->path, buf, len); - - if (meta->format <= VIR_STORAGE_FILE_NONE || - meta->format >= VIR_STORAGE_FILE_LAST) { - virReportSystemError(EINVAL, _("unknown storage file meta->format %d"), - meta->format); - return -1; - } - - if (fileTypeInfo[meta->format].cryptInfo != NULL) { - for (i = 0; fileTypeInfo[meta->format].cryptInfo[i].format != 0; i++) { - if (virStorageFileHasEncryptionFormat(&fileTypeInfo[meta->format].cryptInfo[i], - buf, len)) { - int expt_fmt = fileTypeInfo[meta->format].cryptInfo[i].format; - if (!meta->encryption) { - meta->encryption = g_new0(virStorageEncryption, 1); - meta->encryption->format = expt_fmt; - } else { - if (meta->encryption->format != expt_fmt) { - virReportError(VIR_ERR_XML_ERROR, - _("encryption format %d doesn't match " - "expected format %d"), - meta->encryption->format, expt_fmt); - return -1; - } - } - meta->encryption->payload_offset = - virStorageFileGetEncryptionPayloadOffset(&fileTypeInfo[meta->format].cryptInfo[i], buf); - } - } - } - - /* XXX we should consider moving virStorageBackendUpdateVolInfo - * code into this method, for non-magic files - */ - if (!fileTypeInfo[meta->format].magic) - return 0; - - /* Optionally extract capacity from file */ - if (fileTypeInfo[meta->format].sizeOffset != -1) { - if ((fileTypeInfo[meta->format].sizeOffset + 8) > len) - return 0; - - if (fileTypeInfo[meta->format].endian == LV_LITTLE_ENDIAN) - meta->capacity = virReadBufInt64LE(buf + - fileTypeInfo[meta->format].sizeOffset); - else - meta->capacity = virReadBufInt64BE(buf + - fileTypeInfo[meta->format].sizeOffset); - /* Avoid unlikely, but theoretically possible overflow */ - if (meta->capacity > (ULLONG_MAX / - fileTypeInfo[meta->format].sizeMultiplier)) - return 0; - meta->capacity *= fileTypeInfo[meta->format].sizeMultiplier; - } - - VIR_FREE(meta->backingStoreRaw); - if (fileTypeInfo[meta->format].getBackingStore != NULL) { - int store = fileTypeInfo[meta->format].getBackingStore(&meta->backingStoreRaw, - &format, - buf, len); - meta->backingStoreRawFormat = format; - - if (store == BACKING_STORE_INVALID) - return 0; - - if (store == BACKING_STORE_ERROR) - return -1; - } - - virBitmapFree(meta->features); - meta->features = NULL; - if (fileTypeInfo[meta->format].getFeatures != NULL && - fileTypeInfo[meta->format].getFeatures(&meta->features, meta->format, buf, len) < 0) - return -1; - - VIR_FREE(meta->compat); - if (meta->format == VIR_STORAGE_FILE_QCOW2 && meta->features) - meta->compat = g_strdup("1.1"); - - return 0; -} - - -/** - * virStorageFileProbeFormat: - * - * Probe for the format of 'path', returning the detected - * disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a raw file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) -{ - struct stat sb; - ssize_t len = VIR_STORAGE_MAX_HEADER; - VIR_AUTOCLOSE fd = -1; - g_autofree char *header = NULL; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { - virReportSystemError(-fd, _("Failed to open file '%s'"), path); - return -1; - } - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, _("cannot stat file '%s'"), path); - return -1; - } - - /* No header to probe for directories */ - if (S_ISDIR(sb.st_mode)) - return VIR_STORAGE_FILE_DIR; - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot set to start of '%s'"), path); - return -1; - } - - if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - return -1; - } - - return virStorageFileProbeFormatFromBuf(path, header, len); -} - - static virStorageSourcePtr virStorageFileMetadataNew(const char *path, int format) @@ -1123,7 +194,7 @@ virStorageFileGetMetadataFromBuf(const char *path, if (!(ret = virStorageFileMetadataNew(path, format))) return NULL; - if (virStorageFileGetMetadataInternal(ret, buf, len) < 0) { + if (virStorageFileProbeGetMetadata(ret, buf, len) < 0) { virObjectUnref(ret); return NULL; } @@ -1183,7 +254,7 @@ virStorageFileGetMetadataFromFD(const char *path, return NULL; } - if (virStorageFileGetMetadataInternal(meta, buf, len) < 0) + if (virStorageFileProbeGetMetadata(meta, buf, len) < 0) return NULL; if (S_ISREG(sb.st_mode)) @@ -5149,7 +4220,7 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, &buf, &headerLen, cycle) < 0) return -1; - if (virStorageFileGetMetadataInternal(src, buf, headerLen) < 0) + if (virStorageFileProbeGetMetadata(src, buf, headerLen) < 0) return -1; /* If we probed the format we MUST ensure that nothing else than the current @@ -5292,7 +4363,7 @@ virStorageFileGetBackingStoreStr(virStorageSourcePtr src, if (!(tmp = virStorageSourceCopy(src, false))) return -1; - if (virStorageFileGetMetadataInternal(tmp, buf, headerLen) < 0) + if (virStorageFileProbeGetMetadata(tmp, buf, headerLen) < 0) return -1; *backing = g_steal_pointer(&tmp->backingStoreRaw); diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 46da6a8a18..27ac6a493f 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -31,15 +31,6 @@ #include "virenum.h" #include "virpci.h" -/* Minimum header size required to probe all known formats with - * virStorageFileProbeFormat, or obtain metadata from a known format. - * Rounded to multiple of 512 (ISO has a 5-byte magic at offset - * 32769). Some formats can be probed with fewer bytes. Although - * some formats theoretically permit metadata that can rely on offsets - * beyond this size, in practice that doesn't matter. */ -#define VIR_STORAGE_MAX_HEADER 0x8200 - - /* Types of disk backends (host resource). Comparable to the public * virStorageVolType, except we have an undetermined state, don't have * a netdir type, and add a volume type for reference through a @@ -401,8 +392,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); # define DEV_BSIZE 512 #endif -int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid); - virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path, int fd, int format); diff --git a/src/util/virstoragefileprobe.c b/src/util/virstoragefileprobe.c new file mode 100644 index 0000000000..bca098cd35 --- /dev/null +++ b/src/util/virstoragefileprobe.c @@ -0,0 +1,967 @@ +/* + * virstoragefileprobe.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2017 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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 <unistd.h> +#include <fcntl.h> + +#include "internal.h" +#include "viralloc.h" +#include "virbitmap.h" +#include "virendian.h" +#include "virfile.h" +#include "virlog.h" +#include "virstoragefile.h" +#include "virstoragefileprobe.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("util.storagefileprobe"); + +enum lv_endian { + LV_LITTLE_ENDIAN = 1, /* 1234 */ + LV_BIG_ENDIAN /* 4321 */ +}; + +enum { + BACKING_STORE_OK, + BACKING_STORE_INVALID, + BACKING_STORE_ERROR, +}; + +#define FILE_TYPE_VERSIONS_LAST 3 + +struct FileEncryptionInfo { + int format; /* Encryption format to assign */ + + int magicOffset; /* Byte offset of the magic */ + const char *magic; /* Optional string of magic */ + + enum lv_endian endian; /* Endianness of file format */ + + int versionOffset; /* Byte offset from start of file + * where we find version number, + * -1 to always fail the version test, + * -2 to always pass the version test */ + int versionSize; /* Size in bytes of version data (0, 2, or 4) */ + int versionNumbers[FILE_TYPE_VERSIONS_LAST]; + /* Version numbers to validate. Zeroes are ignored. */ + + int modeOffset; /* Byte offset of the format native encryption mode */ + char modeValue; /* Value expected at offset */ + + int payloadOffset; /* start offset of the volume data (in 512 byte sectors) */ +}; + +struct FileTypeInfo { + int magicOffset; /* Byte offset of the magic */ + const char *magic; /* Optional string of file magic + * to check at head of file */ + enum lv_endian endian; /* Endianness of file format */ + + int versionOffset; /* Byte offset from start of file + * where we find version number, + * -1 to always fail the version test, + * -2 to always pass the version test */ + int versionSize; /* Size in bytes of version data (0, 2, or 4) */ + int versionNumbers[FILE_TYPE_VERSIONS_LAST]; + /* Version numbers to validate. Zeroes are ignored. */ + int sizeOffset; /* Byte offset from start of file + * where we find capacity info, + * -1 to use st_size as capacity */ + int sizeBytes; /* Number of bytes for size field */ + int sizeMultiplier; /* A scaling factor if size is not in bytes */ + /* Store a COW base image path (possibly relative), + * or NULL if there is no COW base image, to RES; + * return BACKING_STORE_* */ + const struct FileEncryptionInfo *cryptInfo; /* Encryption info */ + int (*getBackingStore)(char **res, int *format, + const char *buf, size_t buf_size); + int (*getFeatures)(virBitmapPtr *features, int format, + char *buf, ssize_t len); +}; + + +static int cowGetBackingStore(char **, int *, + const char *, size_t); +static int qcowXGetBackingStore(char **, int *, + const char *, size_t); +static int qcow2GetFeatures(virBitmapPtr *features, int format, + char *buf, ssize_t len); +static int vmdk4GetBackingStore(char **, int *, + const char *, size_t); +static int +qedGetBackingStore(char **, int *, const char *, size_t); + +#define QCOWX_HDR_VERSION (4) +#define QCOWX_HDR_BACKING_FILE_OFFSET (QCOWX_HDR_VERSION+4) +#define QCOWX_HDR_BACKING_FILE_SIZE (QCOWX_HDR_BACKING_FILE_OFFSET+8) +#define QCOWX_HDR_IMAGE_SIZE (QCOWX_HDR_BACKING_FILE_SIZE+4+4) + +#define QCOW1_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8+1+1+2) +#define QCOW2_HDR_CRYPT (QCOWX_HDR_IMAGE_SIZE+8) + +#define QCOW1_HDR_TOTAL_SIZE (QCOW1_HDR_CRYPT+4+8) +#define QCOW2_HDR_TOTAL_SIZE (QCOW2_HDR_CRYPT+4+4+8+8+4+4+8) + +#define QCOW2_HDR_EXTENSION_END 0 +#define QCOW2_HDR_EXTENSION_BACKING_FORMAT 0xE2792ACA + +#define QCOW2v3_HDR_FEATURES_INCOMPATIBLE (QCOW2_HDR_TOTAL_SIZE) +#define QCOW2v3_HDR_FEATURES_COMPATIBLE (QCOW2v3_HDR_FEATURES_INCOMPATIBLE+8) +#define QCOW2v3_HDR_FEATURES_AUTOCLEAR (QCOW2v3_HDR_FEATURES_COMPATIBLE+8) + +/* The location of the header size [4 bytes] */ +#define QCOW2v3_HDR_SIZE (QCOW2_HDR_TOTAL_SIZE+8+8+8+4) + +#define QED_HDR_FEATURES_OFFSET (4+4+4+4) +#define QED_HDR_IMAGE_SIZE (QED_HDR_FEATURES_OFFSET+8+8+8+8) +#define QED_HDR_BACKING_FILE_OFFSET (QED_HDR_IMAGE_SIZE+8) +#define QED_HDR_BACKING_FILE_SIZE (QED_HDR_BACKING_FILE_OFFSET+4) +#define QED_F_BACKING_FILE 0x01 +#define QED_F_BACKING_FORMAT_NO_PROBE 0x04 + +#define PLOOP_IMAGE_SIZE_OFFSET 36 +#define PLOOP_SIZE_MULTIPLIER 512 + +#define LUKS_HDR_MAGIC_LEN 6 +#define LUKS_HDR_VERSION_LEN 2 +#define LUKS_HDR_CIPHER_NAME_LEN 32 +#define LUKS_HDR_CIPHER_MODE_LEN 32 +#define LUKS_HDR_HASH_SPEC_LEN 32 +#define LUKS_HDR_PAYLOAD_LEN 4 + +/* Format described by qemu commit id '3e308f20e' */ +#define LUKS_HDR_VERSION_OFFSET LUKS_HDR_MAGIC_LEN +#define LUKS_HDR_PAYLOAD_OFFSET (LUKS_HDR_MAGIC_LEN+\ + LUKS_HDR_VERSION_LEN+\ + LUKS_HDR_CIPHER_NAME_LEN+\ + LUKS_HDR_CIPHER_MODE_LEN+\ + LUKS_HDR_HASH_SPEC_LEN) + +static struct FileEncryptionInfo const luksEncryptionInfo[] = { + { + .format = VIR_STORAGE_ENCRYPTION_FORMAT_LUKS, + + /* Magic is 'L','U','K','S', 0xBA, 0xBE */ + .magicOffset = 0, + .magic = "\x4c\x55\x4b\x53\xba\xbe", + .endian = LV_BIG_ENDIAN, + + .versionOffset = LUKS_HDR_VERSION_OFFSET, + .versionSize = LUKS_HDR_VERSION_LEN, + .versionNumbers = {1}, + + .modeOffset = -1, + .modeValue = -1, + + .payloadOffset = LUKS_HDR_PAYLOAD_OFFSET, + }, + { 0 } +}; + +static struct FileEncryptionInfo const qcow1EncryptionInfo[] = { + { + .format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, + + .magicOffset = 0, + .magic = NULL, + .endian = LV_BIG_ENDIAN, + + .versionOffset = -1, + .versionSize = 0, + .versionNumbers = {}, + + .modeOffset = QCOW1_HDR_CRYPT, + .modeValue = 1, + + .payloadOffset = -1, + }, + { 0 } +}; + +static struct FileEncryptionInfo const qcow2EncryptionInfo[] = { + { + .format = VIR_STORAGE_ENCRYPTION_FORMAT_QCOW, + + .magicOffset = 0, + .magic = NULL, + .endian = LV_BIG_ENDIAN, + + .versionOffset = -1, + .versionSize = 0, + .versionNumbers = {}, + + .modeOffset = QCOW2_HDR_CRYPT, + .modeValue = 1, + + .payloadOffset = -1, + }, + { + .format = VIR_STORAGE_ENCRYPTION_FORMAT_LUKS, + + .magicOffset = 0, + .magic = NULL, + .endian = LV_BIG_ENDIAN, + + .versionOffset = -1, + .versionSize = 0, + .versionNumbers = {}, + + .modeOffset = QCOW2_HDR_CRYPT, + .modeValue = 2, + + .payloadOffset = -1, + }, + { 0 } +}; + +static struct FileTypeInfo const fileTypeInfo[] = { + [VIR_STORAGE_FILE_NONE] = { 0, NULL, LV_LITTLE_ENDIAN, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + [VIR_STORAGE_FILE_RAW] = { 0, NULL, LV_LITTLE_ENDIAN, + -1, 0, {0}, 0, 0, 0, + luksEncryptionInfo, + NULL, NULL }, + [VIR_STORAGE_FILE_DIR] = { 0, NULL, LV_LITTLE_ENDIAN, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + [VIR_STORAGE_FILE_BOCHS] = { + /*"Bochs Virtual HD Image", */ /* Untested */ + 0, NULL, + LV_LITTLE_ENDIAN, 64, 4, {0x20000}, + 32+16+16+4+4+4+4+4, 8, 1, NULL, NULL, NULL + }, + [VIR_STORAGE_FILE_CLOOP] = { + /* #!/bin/sh + #V2.0 Format + modprobe cloop file=$0 && mount -r -t iso9660 /dev/cloop $1 + */ /* Untested */ + 0, NULL, + LV_LITTLE_ENDIAN, -1, 0, {0}, + -1, 0, 0, NULL, NULL, NULL + }, + [VIR_STORAGE_FILE_DMG] = { + /* XXX QEMU says there's no magic for dmg, + * /usr/share/misc/magic lists double magic (both offsets + * would have to match) but then disables that check. */ + 0, NULL, + 0, -1, 0, {0}, + -1, 0, 0, NULL, NULL, NULL + }, + [VIR_STORAGE_FILE_ISO] = { + 32769, "CD001", + LV_LITTLE_ENDIAN, -2, 0, {0}, + -1, 0, 0, NULL, NULL, NULL + }, + [VIR_STORAGE_FILE_VPC] = { + 0, "conectix", + LV_BIG_ENDIAN, 12, 4, {0x10000}, + 8 + 4 + 4 + 8 + 4 + 4 + 2 + 2 + 4, 8, 1, NULL, NULL, NULL + }, + /* TODO: add getBackingStore function */ + [VIR_STORAGE_FILE_VDI] = { + 64, "\x7f\x10\xda\xbe", + LV_LITTLE_ENDIAN, 68, 4, {0x00010001}, + 64 + 5 * 4 + 256 + 7 * 4, 8, 1, NULL, NULL, NULL}, + + /* Not direct file formats, but used for various drivers */ + [VIR_STORAGE_FILE_FAT] = { 0, NULL, LV_LITTLE_ENDIAN, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + [VIR_STORAGE_FILE_VHD] = { 0, NULL, LV_LITTLE_ENDIAN, + -1, 0, {0}, 0, 0, 0, NULL, NULL, NULL }, + [VIR_STORAGE_FILE_PLOOP] = { 0, "WithouFreSpacExt", LV_LITTLE_ENDIAN, + -2, 0, {0}, PLOOP_IMAGE_SIZE_OFFSET, 0, + PLOOP_SIZE_MULTIPLIER, NULL, NULL, NULL }, + + /* All formats with a backing store probe below here */ + [VIR_STORAGE_FILE_COW] = { + 0, "OOOM", + LV_BIG_ENDIAN, 4, 4, {2}, + 4+4+1024+4, 8, 1, NULL, cowGetBackingStore, NULL + }, + [VIR_STORAGE_FILE_QCOW] = { + 0, "QFI", + LV_BIG_ENDIAN, 4, 4, {1}, + QCOWX_HDR_IMAGE_SIZE, 8, 1, + qcow1EncryptionInfo, + qcowXGetBackingStore, NULL + }, + [VIR_STORAGE_FILE_QCOW2] = { + 0, "QFI", + LV_BIG_ENDIAN, 4, 4, {2, 3}, + QCOWX_HDR_IMAGE_SIZE, 8, 1, + qcow2EncryptionInfo, + qcowXGetBackingStore, + qcow2GetFeatures + }, + [VIR_STORAGE_FILE_QED] = { + /* https://wiki.qemu.org/Features/QED */ + 0, "QED", + LV_LITTLE_ENDIAN, -2, 0, {0}, + QED_HDR_IMAGE_SIZE, 8, 1, NULL, qedGetBackingStore, NULL + }, + [VIR_STORAGE_FILE_VMDK] = { + 0, "KDMV", + LV_LITTLE_ENDIAN, 4, 4, {1, 2, 3}, + 4+4+4, 8, 512, NULL, vmdk4GetBackingStore, NULL + }, +}; +G_STATIC_ASSERT(G_N_ELEMENTS(fileTypeInfo) == VIR_STORAGE_FILE_LAST); + + +/* qcow2 compatible features in the order they appear on-disk */ +enum qcow2CompatibleFeature { + QCOW2_COMPATIBLE_FEATURE_LAZY_REFCOUNTS = 0, + + QCOW2_COMPATIBLE_FEATURE_LAST +}; + +/* conversion to virStorageFileFeature */ +static const int qcow2CompatibleFeatureArray[] = { + VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS, +}; +G_STATIC_ASSERT(G_N_ELEMENTS(qcow2CompatibleFeatureArray) == + QCOW2_COMPATIBLE_FEATURE_LAST); + +static int +cowGetBackingStore(char **res, + int *format, + const char *buf, + size_t buf_size) +{ +#define COW_FILENAME_MAXLEN 1024 + *res = NULL; + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < 4+4+ COW_FILENAME_MAXLEN) + return BACKING_STORE_INVALID; + if (buf[4+4] == '\0') { /* cow_header_v2.backing_file[0] */ + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + + *res = g_strndup((const char *)buf + 4 + 4, COW_FILENAME_MAXLEN); + return BACKING_STORE_OK; +} + + +static int +qcow2GetExtensions(const char *buf, + size_t buf_size, + int *backingFormat) +{ + size_t offset; + size_t extension_start; + size_t extension_end; + int version = virReadBufInt32BE(buf + QCOWX_HDR_VERSION); + + if (version < 2) { + /* QCow1 doesn't have the extensions capability + * used to store backing format */ + return 0; + } + + if (version == 2) + extension_start = QCOW2_HDR_TOTAL_SIZE; + else + extension_start = virReadBufInt32BE(buf + QCOW2v3_HDR_SIZE); + + /* + * Traditionally QCow2 files had a layout of + * + * [header] + * [backingStoreName] + * + * Although the backingStoreName typically followed + * the header immediately, this was not required by + * the format. By specifying a higher byte offset for + * the backing file offset in the header, it was + * possible to leave space between the header and + * start of backingStore. + * + * This hack is now used to store extensions to the + * qcow2 format: + * + * [header] + * [extensions] + * [backingStoreName] + * + * Thus the file region to search for extensions is + * between the end of the header (QCOW2_HDR_TOTAL_SIZE) + * and the start of the backingStoreName (offset) + * + * for qcow2 v3 images, the length of the header + * is stored at QCOW2v3_HDR_SIZE + */ + extension_end = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET); + if (extension_end > buf_size) + return -1; + + /* + * The extensions take format of + * + * int32: magic + * int32: length + * byte[length]: payload + * + * Unknown extensions can be ignored by skipping + * over "length" bytes in the data stream. + */ + offset = extension_start; + while (offset < (buf_size-8) && + offset < (extension_end-8)) { + unsigned int magic = virReadBufInt32BE(buf + offset); + unsigned int len = virReadBufInt32BE(buf + offset + 4); + + offset += 8; + + if ((offset + len) < offset) + break; + + if ((offset + len) > buf_size) + break; + + switch (magic) { + case QCOW2_HDR_EXTENSION_BACKING_FORMAT: { + g_autofree char *tmp = NULL; + if (!backingFormat) + break; + + tmp = g_new0(char, len + 1); + memcpy(tmp, buf + offset, len); + tmp[len] = '\0'; + + *backingFormat = virStorageFileFormatTypeFromString(tmp); + if (*backingFormat <= VIR_STORAGE_FILE_NONE) + return -1; + break; + } + + case QCOW2_HDR_EXTENSION_END: + return 0; + } + + offset += len; + } + + return 0; +} + + +static int +qcowXGetBackingStore(char **res, + int *format, + const char *buf, + size_t buf_size) +{ + unsigned long long offset; + unsigned int size; + + *res = NULL; + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size < QCOWX_HDR_BACKING_FILE_OFFSET+8+4) + return BACKING_STORE_INVALID; + + offset = virReadBufInt64BE(buf + QCOWX_HDR_BACKING_FILE_OFFSET); + if (offset > buf_size) + return BACKING_STORE_INVALID; + + if (offset == 0) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + + size = virReadBufInt32BE(buf + QCOWX_HDR_BACKING_FILE_SIZE); + if (size == 0) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + if (size > 1023) + return BACKING_STORE_INVALID; + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + *res = g_new0(char, size + 1); + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + + if (qcow2GetExtensions(buf, buf_size, format) < 0) + return BACKING_STORE_INVALID; + + return BACKING_STORE_OK; +} + + +static int +vmdk4GetBackingStore(char **res, + int *format, + const char *buf, + size_t buf_size) +{ + static const char prefix[] = "parentFileNameHint=\""; + char *start, *end; + size_t len; + g_autofree char *desc = NULL; + + desc = g_new0(char, VIR_STORAGE_MAX_HEADER); + + *res = NULL; + /* + * Technically this should have been VMDK, since + * VMDK spec / VMware impl only support VMDK backed + * by VMDK. QEMU isn't following this though and + * does probing on VMDK backing files, hence we set + * AUTO + */ + *format = VIR_STORAGE_FILE_AUTO; + + if (buf_size <= 0x200) + return BACKING_STORE_INVALID; + + len = buf_size - 0x200; + if (len > VIR_STORAGE_MAX_HEADER) + len = VIR_STORAGE_MAX_HEADER; + memcpy(desc, buf + 0x200, len); + desc[len] = '\0'; + start = strstr(desc, prefix); + if (start == NULL) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + start += strlen(prefix); + end = strchr(start, '"'); + if (end == NULL) + return BACKING_STORE_INVALID; + + if (end == start) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + *end = '\0'; + *res = g_strdup(start); + + return BACKING_STORE_OK; +} + +static int +qedGetBackingStore(char **res, + int *format, + const char *buf, + size_t buf_size) +{ + unsigned long long flags; + unsigned long offset, size; + + *res = NULL; + /* Check if this image has a backing file */ + if (buf_size < QED_HDR_FEATURES_OFFSET+8) + return BACKING_STORE_INVALID; + flags = virReadBufInt64LE(buf + QED_HDR_FEATURES_OFFSET); + if (!(flags & QED_F_BACKING_FILE)) { + *format = VIR_STORAGE_FILE_NONE; + return BACKING_STORE_OK; + } + + /* Parse the backing file */ + if (buf_size < QED_HDR_BACKING_FILE_OFFSET+8) + return BACKING_STORE_INVALID; + offset = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_OFFSET); + if (offset > buf_size) + return BACKING_STORE_INVALID; + size = virReadBufInt32LE(buf + QED_HDR_BACKING_FILE_SIZE); + if (size == 0) + return BACKING_STORE_OK; + if (offset + size > buf_size || offset + size < offset) + return BACKING_STORE_INVALID; + *res = g_new0(char, size + 1); + memcpy(*res, buf + offset, size); + (*res)[size] = '\0'; + + if (flags & QED_F_BACKING_FORMAT_NO_PROBE) + *format = VIR_STORAGE_FILE_RAW; + else + *format = VIR_STORAGE_FILE_AUTO_SAFE; + + return BACKING_STORE_OK; +} + + +static bool +virStorageFileMatchesMagic(int magicOffset, + const char *magic, + char *buf, + size_t buflen) +{ + int mlen; + + if (magic == NULL) + return false; + + /* Validate magic data */ + mlen = strlen(magic); + if (magicOffset + mlen > buflen) + return false; + + if (memcmp(buf + magicOffset, magic, mlen) != 0) + return false; + + return true; +} + + +static bool +virStorageFileMatchesVersion(int versionOffset, + int versionSize, + const int *versionNumbers, + int endian, + char *buf, + size_t buflen) +{ + int version; + size_t i; + + /* Validate version number info */ + if (versionOffset == -1) + return false; + + /* -2 == non-versioned file format, so trivially match */ + if (versionOffset == -2) + return true; + + /* A positive versionOffset, requires using a valid versionSize */ + if (versionSize != 2 && versionSize != 4) + return false; + + if ((versionOffset + versionSize) > buflen) + return false; + + if (endian == LV_LITTLE_ENDIAN) { + if (versionSize == 4) + version = virReadBufInt32LE(buf + + versionOffset); + else + version = virReadBufInt16LE(buf + + versionOffset); + } else { + if (versionSize == 4) + version = virReadBufInt32BE(buf + + versionOffset); + else + version = virReadBufInt16BE(buf + + versionOffset); + } + + for (i = 0; + i < FILE_TYPE_VERSIONS_LAST && versionNumbers[i]; + i++) { + VIR_DEBUG("Compare detected version %d vs one of the expected versions %d", + version, versionNumbers[i]); + if (version == versionNumbers[i]) + return true; + } + + return false; +} + + +static int +virStorageFileProbeFormatFromBuf(const char *path, + char *buf, + size_t buflen) +{ + int format = VIR_STORAGE_FILE_RAW; + size_t i; + int possibleFormat = VIR_STORAGE_FILE_RAW; + VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen); + + /* First check file magic */ + for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) { + if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset, + fileTypeInfo[i].magic, + buf, buflen)) { + if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset, + fileTypeInfo[i].versionSize, + fileTypeInfo[i].versionNumbers, + fileTypeInfo[i].endian, + buf, buflen)) { + possibleFormat = i; + continue; + } + format = i; + goto cleanup; + } + } + + if (possibleFormat != VIR_STORAGE_FILE_RAW) + VIR_WARN("File %s matches %s magic, but version is wrong. " + "Please report new version to libvir-list@redhat.com", + path, virStorageFileFormatTypeToString(possibleFormat)); + + cleanup: + VIR_DEBUG("format=%d", format); + return format; +} + + +static int +qcow2GetFeatures(virBitmapPtr *features, + int format, + char *buf, + ssize_t len) +{ + int version = -1; + virBitmapPtr feat = NULL; + uint64_t bits; + size_t i; + + version = virReadBufInt32BE(buf + fileTypeInfo[format].versionOffset); + + if (version == 2) + return 0; + + if (len < QCOW2v3_HDR_SIZE) + return -1; + + feat = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST); + + /* todo: check for incompatible or autoclear features? */ + bits = virReadBufInt64BE(buf + QCOW2v3_HDR_FEATURES_COMPATIBLE); + for (i = 0; i < QCOW2_COMPATIBLE_FEATURE_LAST; i++) { + if (bits & ((uint64_t) 1 << i)) + ignore_value(virBitmapSetBit(feat, qcow2CompatibleFeatureArray[i])); + } + + *features = feat; + return 0; +} + + +static bool +virStorageFileHasEncryptionFormat(const struct FileEncryptionInfo *info, + char *buf, + size_t len) +{ + if (!info->magic && info->modeOffset == -1) + return false; /* Shouldn't happen - expect at least one */ + + if (info->magic) { + if (!virStorageFileMatchesMagic(info->magicOffset, + info->magic, + buf, len)) + return false; + + if (info->versionOffset != -1 && + !virStorageFileMatchesVersion(info->versionOffset, + info->versionSize, + info->versionNumbers, + info->endian, + buf, len)) + return false; + + return true; + } else if (info->modeOffset != -1) { + int crypt_format; + + if (info->modeOffset >= len) + return false; + + crypt_format = virReadBufInt32BE(buf + info->modeOffset); + if (crypt_format != info->modeValue) + return false; + + return true; + } else { + return false; + } +} + + +static int +virStorageFileGetEncryptionPayloadOffset(const struct FileEncryptionInfo *info, + char *buf) +{ + int payload_offset = -1; + + if (info->payloadOffset != -1) { + if (info->endian == LV_LITTLE_ENDIAN) + payload_offset = virReadBufInt32LE(buf + info->payloadOffset); + else + payload_offset = virReadBufInt32BE(buf + info->payloadOffset); + } + + return payload_offset; +} + + +/* Given a header in BUF with length LEN, as parsed from the storage file + * assuming it has the given FORMAT, populate information into META + * with information about the file and its backing store. Return format + * of the backing store as BACKING_FORMAT. PATH and FORMAT have to be + * pre-populated in META. + * + * Note that this function may be called repeatedly on @meta, so it must + * clean up any existing allocated memory which would be overwritten. + */ +int +virStorageFileProbeGetMetadata(virStorageSourcePtr meta, + char *buf, + size_t len) +{ + int format; + size_t i; + + VIR_DEBUG("path=%s, buf=%p, len=%zu, meta->format=%d", + meta->path, buf, len, meta->format); + + if (meta->format == VIR_STORAGE_FILE_AUTO) + meta->format = virStorageFileProbeFormatFromBuf(meta->path, buf, len); + + if (meta->format <= VIR_STORAGE_FILE_NONE || + meta->format >= VIR_STORAGE_FILE_LAST) { + virReportSystemError(EINVAL, _("unknown storage file meta->format %d"), + meta->format); + return -1; + } + + if (fileTypeInfo[meta->format].cryptInfo != NULL) { + for (i = 0; fileTypeInfo[meta->format].cryptInfo[i].format != 0; i++) { + if (virStorageFileHasEncryptionFormat(&fileTypeInfo[meta->format].cryptInfo[i], + buf, len)) { + int expt_fmt = fileTypeInfo[meta->format].cryptInfo[i].format; + if (!meta->encryption) { + meta->encryption = g_new0(virStorageEncryption, 1); + meta->encryption->format = expt_fmt; + } else { + if (meta->encryption->format != expt_fmt) { + virReportError(VIR_ERR_XML_ERROR, + _("encryption format %d doesn't match " + "expected format %d"), + meta->encryption->format, expt_fmt); + return -1; + } + } + meta->encryption->payload_offset = + virStorageFileGetEncryptionPayloadOffset(&fileTypeInfo[meta->format].cryptInfo[i], buf); + } + } + } + + /* XXX we should consider moving virStorageBackendUpdateVolInfo + * code into this method, for non-magic files + */ + if (!fileTypeInfo[meta->format].magic) + return 0; + + /* Optionally extract capacity from file */ + if (fileTypeInfo[meta->format].sizeOffset != -1) { + if ((fileTypeInfo[meta->format].sizeOffset + 8) > len) + return 0; + + if (fileTypeInfo[meta->format].endian == LV_LITTLE_ENDIAN) + meta->capacity = virReadBufInt64LE(buf + + fileTypeInfo[meta->format].sizeOffset); + else + meta->capacity = virReadBufInt64BE(buf + + fileTypeInfo[meta->format].sizeOffset); + /* Avoid unlikely, but theoretically possible overflow */ + if (meta->capacity > (ULLONG_MAX / + fileTypeInfo[meta->format].sizeMultiplier)) + return 0; + meta->capacity *= fileTypeInfo[meta->format].sizeMultiplier; + } + + VIR_FREE(meta->backingStoreRaw); + if (fileTypeInfo[meta->format].getBackingStore != NULL) { + int store = fileTypeInfo[meta->format].getBackingStore(&meta->backingStoreRaw, + &format, + buf, len); + meta->backingStoreRawFormat = format; + + if (store == BACKING_STORE_INVALID) + return 0; + + if (store == BACKING_STORE_ERROR) + return -1; + } + + virBitmapFree(meta->features); + meta->features = NULL; + if (fileTypeInfo[meta->format].getFeatures != NULL && + fileTypeInfo[meta->format].getFeatures(&meta->features, meta->format, buf, len) < 0) + return -1; + + VIR_FREE(meta->compat); + if (meta->format == VIR_STORAGE_FILE_QCOW2 && meta->features) + meta->compat = g_strdup("1.1"); + + return 0; +} + + +/** + * virStorageFileProbeFormat: + * + * Probe for the format of 'path', returning the detected + * disk format. + * + * Callers are advised never to trust the returned 'format' + * unless it is listed as VIR_STORAGE_FILE_RAW, since a + * malicious guest can turn a raw file into any other non-raw + * format at will. + * + * Best option: Don't use this function + */ +int +virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) +{ + struct stat sb; + ssize_t len = VIR_STORAGE_MAX_HEADER; + VIR_AUTOCLOSE fd = -1; + g_autofree char *header = NULL; + + if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) { + virReportSystemError(-fd, _("Failed to open file '%s'"), path); + return -1; + } + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, _("cannot stat file '%s'"), path); + return -1; + } + + /* No header to probe for directories */ + if (S_ISDIR(sb.st_mode)) + return VIR_STORAGE_FILE_DIR; + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot set to start of '%s'"), path); + return -1; + } + + if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), path); + return -1; + } + + return virStorageFileProbeFormatFromBuf(path, header, len); +} diff --git a/src/util/virstoragefileprobe.h b/src/util/virstoragefileprobe.h new file mode 100644 index 0000000000..2b94a4ae51 --- /dev/null +++ b/src/util/virstoragefileprobe.h @@ -0,0 +1,44 @@ +/* + * virstoragefileprobe.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include <sys/stat.h> + +#include "virstoragefile.h" + +/* Minimum header size required to probe all known formats with + * virStorageFileProbeFormat, or obtain metadata from a known format. + * Rounded to multiple of 512 (ISO has a 5-byte magic at offset + * 32769). Some formats can be probed with fewer bytes. Although + * some formats theoretically permit metadata that can rely on offsets + * beyond this size, in practice that doesn't matter. */ +#define VIR_STORAGE_MAX_HEADER 0x8200 + +int +virStorageFileProbeGetMetadata(virStorageSourcePtr meta, + char *buf, + size_t len); + +int +virStorageFileProbeFormat(const char *path, + uid_t uid, + gid_t gid); -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:20 +0100, Pavel Hrdina wrote:
This code is not directly relevant to virStorageSource so move it to separate file.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 6 +- src/qemu/qemu_driver.c | 1 + src/storage/storage_backend_gluster.c | 1 + src/storage/storage_util.c | 1 + src/util/meson.build | 1 + src/util/virstoragefile.c | 939 +------------------------ src/util/virstoragefile.h | 11 - src/util/virstoragefileprobe.c | 967 ++++++++++++++++++++++++++ src/util/virstoragefileprobe.h | 44 ++ 10 files changed, 1026 insertions(+), 946 deletions(-) create mode 100644 src/util/virstoragefileprobe.c create mode 100644 src/util/virstoragefileprobe.h
[...]
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 13a86f34e5..98a3222d09 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c
[...]
@@ -792,289 +146,6 @@ virStorageIsRelative(const char *backing) }
-static int -virStorageFileProbeFormatFromBuf(const char *path, - char *buf, - size_t buflen)
I'd prefer if this is the function exported from the new module ...
-{ - int format = VIR_STORAGE_FILE_RAW; - size_t i; - int possibleFormat = VIR_STORAGE_FILE_RAW; - VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen); - - /* First check file magic */ - for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) { - if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset, - fileTypeInfo[i].magic, - buf, buflen)) { - if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset, - fileTypeInfo[i].versionSize, - fileTypeInfo[i].versionNumbers, - fileTypeInfo[i].endian, - buf, buflen)) { - possibleFormat = i; - continue; - } - format = i; - goto cleanup; - } - } - - if (possibleFormat != VIR_STORAGE_FILE_RAW) - VIR_WARN("File %s matches %s magic, but version is wrong. " - "Please report new version to libvir-list@redhat.com", - path, virStorageFileFormatTypeToString(possibleFormat)); - - cleanup: - VIR_DEBUG("format=%d", format); - return format; -}
[...]
-/** - * virStorageFileProbeFormat: - * - * Probe for the format of 'path', returning the detected - * disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a raw file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) -{
... and not this.
- struct stat sb; - ssize_t len = VIR_STORAGE_MAX_HEADER; - VIR_AUTOCLOSE fd = -1; - g_autofree char *header = NULL; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
Specifically the new module should not ever touch any real storage and should just be a self-contained prober of metadata froma buffer.
- virReportSystemError(-fd, _("Failed to open file '%s'"), path); - return -1; - } - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, _("cannot stat file '%s'"), path); - return -1; - } - - /* No header to probe for directories */ - if (S_ISDIR(sb.st_mode)) - return VIR_STORAGE_FILE_DIR; - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot set to start of '%s'"), path); - return -1; - } - - if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - return -1; - } - - return virStorageFileProbeFormatFromBuf(path, header, len); -}
[...]
diff --git a/src/util/virstoragefileprobe.h b/src/util/virstoragefileprobe.h new file mode 100644 index 0000000000..2b94a4ae51 --- /dev/null +++ b/src/util/virstoragefileprobe.h @@ -0,0 +1,44 @@ +/* + * virstoragefileprobe.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include <sys/stat.h>
#include <sys/types.h> for uid_t/gid_t instead, there's no use of the stat struct in the header, but that shouldn't be necessary at all if the format is probed fromt he buffer directly.
+ +#include "virstoragefile.h" + +/* Minimum header size required to probe all known formats with + * virStorageFileProbeFormat, or obtain metadata from a known format. + * Rounded to multiple of 512 (ISO has a 5-byte magic at offset + * 32769). Some formats can be probed with fewer bytes. Although + * some formats theoretically permit metadata that can rely on offsets + * beyond this size, in practice that doesn't matter. */ +#define VIR_STORAGE_MAX_HEADER 0x8200 + +int +virStorageFileProbeGetMetadata(virStorageSourcePtr meta, + char *buf, + size_t len); + +int +virStorageFileProbeFormat(const char *path, + uid_t uid, + gid_t gid);
Reviewed-by: Peter Krempa <pkrempa@redhat.com> If you decide that it's too much hassle to shuffle this around, you can return the code opening the file back to the appropriate file later. (Or I'll do it, if you don't, but virstoragefileprobe.c will not 'open()' anything in the end)

On Fri, Jan 22, 2021 at 09:23:00AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:20 +0100, Pavel Hrdina wrote:
This code is not directly relevant to virStorageSource so move it to separate file.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 6 +- src/qemu/qemu_driver.c | 1 + src/storage/storage_backend_gluster.c | 1 + src/storage/storage_util.c | 1 + src/util/meson.build | 1 + src/util/virstoragefile.c | 939 +------------------------ src/util/virstoragefile.h | 11 - src/util/virstoragefileprobe.c | 967 ++++++++++++++++++++++++++ src/util/virstoragefileprobe.h | 44 ++ 10 files changed, 1026 insertions(+), 946 deletions(-) create mode 100644 src/util/virstoragefileprobe.c create mode 100644 src/util/virstoragefileprobe.h
[...]
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 13a86f34e5..98a3222d09 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c
[...]
@@ -792,289 +146,6 @@ virStorageIsRelative(const char *backing) }
-static int -virStorageFileProbeFormatFromBuf(const char *path, - char *buf, - size_t buflen)
I'd prefer if this is the function exported from the new module ...
-{ - int format = VIR_STORAGE_FILE_RAW; - size_t i; - int possibleFormat = VIR_STORAGE_FILE_RAW; - VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen); - - /* First check file magic */ - for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) { - if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset, - fileTypeInfo[i].magic, - buf, buflen)) { - if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset, - fileTypeInfo[i].versionSize, - fileTypeInfo[i].versionNumbers, - fileTypeInfo[i].endian, - buf, buflen)) { - possibleFormat = i; - continue; - } - format = i; - goto cleanup; - } - } - - if (possibleFormat != VIR_STORAGE_FILE_RAW) - VIR_WARN("File %s matches %s magic, but version is wrong. " - "Please report new version to libvir-list@redhat.com", - path, virStorageFileFormatTypeToString(possibleFormat)); - - cleanup: - VIR_DEBUG("format=%d", format); - return format; -}
[...]
-/** - * virStorageFileProbeFormat: - * - * Probe for the format of 'path', returning the detected - * disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a raw file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) -{
... and not this.
- struct stat sb; - ssize_t len = VIR_STORAGE_MAX_HEADER; - VIR_AUTOCLOSE fd = -1; - g_autofree char *header = NULL; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
Specifically the new module should not ever touch any real storage and should just be a self-contained prober of metadata froma buffer.
- virReportSystemError(-fd, _("Failed to open file '%s'"), path); - return -1; - } - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, _("cannot stat file '%s'"), path); - return -1; - } - - /* No header to probe for directories */ - if (S_ISDIR(sb.st_mode)) - return VIR_STORAGE_FILE_DIR; - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot set to start of '%s'"), path); - return -1; - } - - if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - return -1; - } - - return virStorageFileProbeFormatFromBuf(path, header, len); -}
[...]
diff --git a/src/util/virstoragefileprobe.h b/src/util/virstoragefileprobe.h new file mode 100644 index 0000000000..2b94a4ae51 --- /dev/null +++ b/src/util/virstoragefileprobe.h @@ -0,0 +1,44 @@ +/* + * virstoragefileprobe.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include <sys/stat.h>
#include <sys/types.h> for uid_t/gid_t instead, there's no use of the stat struct in the header, but that shouldn't be necessary at all if the format is probed fromt he buffer directly.
+ +#include "virstoragefile.h" + +/* Minimum header size required to probe all known formats with + * virStorageFileProbeFormat, or obtain metadata from a known format. + * Rounded to multiple of 512 (ISO has a 5-byte magic at offset + * 32769). Some formats can be probed with fewer bytes. Although + * some formats theoretically permit metadata that can rely on offsets + * beyond this size, in practice that doesn't matter. */ +#define VIR_STORAGE_MAX_HEADER 0x8200 + +int +virStorageFileProbeGetMetadata(virStorageSourcePtr meta, + char *buf, + size_t len); + +int +virStorageFileProbeFormat(const char *path, + uid_t uid, + gid_t gid);
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
If you decide that it's too much hassle to shuffle this around, you can return the code opening the file back to the appropriate file later.
(Or I'll do it, if you don't, but virstoragefileprobe.c will not 'open()' anything in the end)
Make sense, I'll look into it and post v3. Thanks, Pavel

On Fri, Jan 22, 2021 at 10:09:27AM +0100, Pavel Hrdina wrote:
On Fri, Jan 22, 2021 at 09:23:00AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:20 +0100, Pavel Hrdina wrote:
This code is not directly relevant to virStorageSource so move it to separate file.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 6 +- src/qemu/qemu_driver.c | 1 + src/storage/storage_backend_gluster.c | 1 + src/storage/storage_util.c | 1 + src/util/meson.build | 1 + src/util/virstoragefile.c | 939 +------------------------ src/util/virstoragefile.h | 11 - src/util/virstoragefileprobe.c | 967 ++++++++++++++++++++++++++ src/util/virstoragefileprobe.h | 44 ++ 10 files changed, 1026 insertions(+), 946 deletions(-) create mode 100644 src/util/virstoragefileprobe.c create mode 100644 src/util/virstoragefileprobe.h
[...]
diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 13a86f34e5..98a3222d09 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c
[...]
@@ -792,289 +146,6 @@ virStorageIsRelative(const char *backing) }
-static int -virStorageFileProbeFormatFromBuf(const char *path, - char *buf, - size_t buflen)
I'd prefer if this is the function exported from the new module ...
-{ - int format = VIR_STORAGE_FILE_RAW; - size_t i; - int possibleFormat = VIR_STORAGE_FILE_RAW; - VIR_DEBUG("path=%s, buf=%p, buflen=%zu", path, buf, buflen); - - /* First check file magic */ - for (i = 0; i < VIR_STORAGE_FILE_LAST; i++) { - if (virStorageFileMatchesMagic(fileTypeInfo[i].magicOffset, - fileTypeInfo[i].magic, - buf, buflen)) { - if (!virStorageFileMatchesVersion(fileTypeInfo[i].versionOffset, - fileTypeInfo[i].versionSize, - fileTypeInfo[i].versionNumbers, - fileTypeInfo[i].endian, - buf, buflen)) { - possibleFormat = i; - continue; - } - format = i; - goto cleanup; - } - } - - if (possibleFormat != VIR_STORAGE_FILE_RAW) - VIR_WARN("File %s matches %s magic, but version is wrong. " - "Please report new version to libvir-list@redhat.com", - path, virStorageFileFormatTypeToString(possibleFormat)); - - cleanup: - VIR_DEBUG("format=%d", format); - return format; -}
[...]
-/** - * virStorageFileProbeFormat: - * - * Probe for the format of 'path', returning the detected - * disk format. - * - * Callers are advised never to trust the returned 'format' - * unless it is listed as VIR_STORAGE_FILE_RAW, since a - * malicious guest can turn a raw file into any other non-raw - * format at will. - * - * Best option: Don't use this function - */ -int -virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid) -{
... and not this.
- struct stat sb; - ssize_t len = VIR_STORAGE_MAX_HEADER; - VIR_AUTOCLOSE fd = -1; - g_autofree char *header = NULL; - - if ((fd = virFileOpenAs(path, O_RDONLY, 0, uid, gid, 0)) < 0) {
Specifically the new module should not ever touch any real storage and should just be a self-contained prober of metadata froma buffer.
- virReportSystemError(-fd, _("Failed to open file '%s'"), path); - return -1; - } - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, _("cannot stat file '%s'"), path); - return -1; - } - - /* No header to probe for directories */ - if (S_ISDIR(sb.st_mode)) - return VIR_STORAGE_FILE_DIR; - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot set to start of '%s'"), path); - return -1; - } - - if ((len = virFileReadHeaderFD(fd, len, &header)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), path); - return -1; - } - - return virStorageFileProbeFormatFromBuf(path, header, len); -}
[...]
diff --git a/src/util/virstoragefileprobe.h b/src/util/virstoragefileprobe.h new file mode 100644 index 0000000000..2b94a4ae51 --- /dev/null +++ b/src/util/virstoragefileprobe.h @@ -0,0 +1,44 @@ +/* + * virstoragefileprobe.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include <sys/stat.h>
#include <sys/types.h> for uid_t/gid_t instead, there's no use of the stat struct in the header, but that shouldn't be necessary at all if the format is probed fromt he buffer directly.
+ +#include "virstoragefile.h" + +/* Minimum header size required to probe all known formats with + * virStorageFileProbeFormat, or obtain metadata from a known format. + * Rounded to multiple of 512 (ISO has a 5-byte magic at offset + * 32769). Some formats can be probed with fewer bytes. Although + * some formats theoretically permit metadata that can rely on offsets + * beyond this size, in practice that doesn't matter. */ +#define VIR_STORAGE_MAX_HEADER 0x8200 + +int +virStorageFileProbeGetMetadata(virStorageSourcePtr meta, + char *buf, + size_t len); + +int +virStorageFileProbeFormat(const char *path, + uid_t uid, + gid_t gid);
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
If you decide that it's too much hassle to shuffle this around, you can return the code opening the file back to the appropriate file later.
(Or I'll do it, if you don't, but virstoragefileprobe.c will not 'open()' anything in the end)
Make sense, I'll look into it and post v3.
So I looked into it and the best what we can do is remove virStorageFileProbeFormat completely. I've discussed it with Peter and it will be done as followup so I'll take your RB for now. Thanks for the review, I'll push this series shortly. Pavel

Up until now we had a runtime code and XML related code in the same source file inside util directory. This patch takes the runtime part and extracts it into the new storage_file directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/libvirt_private.syms | 57 +- src/libxl/meson.build | 1 + src/libxl/xen_xl.c | 2 +- src/qemu/meson.build | 1 + src/qemu/qemu_backup.c | 1 + src/qemu/qemu_block.c | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_driver.c | 1 + src/qemu/qemu_hotplug.c | 1 + src/qemu/qemu_process.c | 1 + src/qemu/qemu_snapshot.c | 1 + src/security/meson.build | 1 + src/security/virt-aa-helper.c | 2 +- src/storage/meson.build | 4 + src/storage/storage_backend_gluster.c | 1 + src/storage/storage_util.c | 1 + src/storage_file/meson.build | 18 + src/storage_file/storage_source.c | 2614 +++++++++++++++++++++++++ src/storage_file/storage_source.h | 148 ++ src/util/virstoragefile.c | 2573 ------------------------ src/util/virstoragefile.h | 75 - tests/meson.build | 4 +- tests/qemublocktest.c | 1 + tests/virstoragetest.c | 1 + 25 files changed, 2833 insertions(+), 2679 deletions(-) create mode 100644 src/storage_file/storage_source.c create mode 100644 src/storage_file/storage_source.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 19eb15ada0..1e47af987d 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -225,6 +225,7 @@ @SRCDIR@src/storage/storage_util.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c +@SRCDIR@src/storage_file/storage_source.c @SRCDIR@src/test/test_driver.c @SRCDIR@src/util/iohelper.c @SRCDIR@src/util/viralloc.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 2dfc7e32d5..67a863467d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1618,6 +1618,36 @@ virSecurityManagerVerify; virSecurityXATTRNamespaceDefined; +# storage_file/storage_source.h +virStorageFileAccess; +virStorageFileChainLookup; +virStorageFileChown; +virStorageFileCreate; +virStorageFileDeinit; +virStorageFileGetBackingStoreStr; +virStorageFileGetMetadata; +virStorageFileGetMetadataFromBuf; +virStorageFileGetMetadataFromFD; +virStorageFileGetRelativeBackingPath; +virStorageFileGetUniqueIdentifier; +virStorageFileInit; +virStorageFileInitAs; +virStorageFileRead; +virStorageFileReportBrokenChain; +virStorageFileStat; +virStorageFileSupportsAccess; +virStorageFileSupportsBackingChainTraversal; +virStorageFileSupportsCreate; +virStorageFileSupportsSecurityDriver; +virStorageFileUnlink; +virStorageSourceNewFromBacking; +virStorageSourceNewFromBackingAbsolute; +virStorageSourceParseRBDColonString; +virStorageSourceUpdateBackingSizes; +virStorageSourceUpdateCapacity; +virStorageSourceUpdatePhysicalSize; + + # util/glibcompat.h vir_g_canonicalize_filename; vir_g_fsync; @@ -3126,36 +3156,15 @@ virStorageAuthDefCopy; virStorageAuthDefFormat; virStorageAuthDefFree; virStorageAuthDefParse; -virStorageFileAccess; virStorageFileCanonicalizePath; -virStorageFileChainLookup; -virStorageFileChown; -virStorageFileCreate; -virStorageFileDeinit; virStorageFileFeatureTypeFromString; virStorageFileFeatureTypeToString; virStorageFileFormatTypeFromString; virStorageFileFormatTypeToString; -virStorageFileGetBackingStoreStr; -virStorageFileGetMetadata; -virStorageFileGetMetadataFromBuf; -virStorageFileGetMetadataFromFD; virStorageFileGetNPIVKey; -virStorageFileGetRelativeBackingPath; virStorageFileGetSCSIKey; -virStorageFileGetUniqueIdentifier; -virStorageFileInit; -virStorageFileInitAs; virStorageFileParseBackingStoreStr; virStorageFileParseChainIndex; -virStorageFileRead; -virStorageFileReportBrokenChain; -virStorageFileStat; -virStorageFileSupportsAccess; -virStorageFileSupportsBackingChainTraversal; -virStorageFileSupportsCreate; -virStorageFileSupportsSecurityDriver; -virStorageFileUnlink; virStorageIsFile; virStorageIsRelative; virStorageNetHostDefClear; @@ -3191,18 +3200,12 @@ virStorageSourceIsSameLocation; virStorageSourceNetCookiesValidate; virStorageSourceNetworkAssignDefaultPorts; virStorageSourceNew; -virStorageSourceNewFromBacking; -virStorageSourceNewFromBackingAbsolute; virStorageSourceNVMeDefFree; -virStorageSourceParseRBDColonString; virStorageSourcePoolDefFree; virStorageSourcePoolModeTypeFromString; virStorageSourcePoolModeTypeToString; virStorageSourcePrivateDataFormatRelPath; virStorageSourcePrivateDataParseRelPath; -virStorageSourceUpdateBackingSizes; -virStorageSourceUpdateCapacity; -virStorageSourceUpdatePhysicalSize; virStorageTypeFromString; virStorageTypeToString; diff --git a/src/libxl/meson.build b/src/libxl/meson.build index 3bb6cc5f2e..783af6c667 100644 --- a/src/libxl/meson.build +++ b/src/libxl/meson.build @@ -27,6 +27,7 @@ if conf.has('WITH_LIBXL') include_directories: [ conf_inc_dir, hypervisor_inc_dir, + storage_file_inc_dir, ], ) diff --git a/src/libxl/xen_xl.c b/src/libxl/xen_xl.c index 17b93d0f5c..621ee63a99 100644 --- a/src/libxl/xen_xl.c +++ b/src/libxl/xen_xl.c @@ -29,7 +29,7 @@ #include "domain_conf.h" #include "viralloc.h" #include "virstring.h" -#include "virstoragefile.h" +#include "storage_source.h" #include "xen_xl.h" #include "libxl_capabilities.h" #include "libxl_conf.h" diff --git a/src/qemu/meson.build b/src/qemu/meson.build index 90640b03c6..7ab591d040 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -104,6 +104,7 @@ if conf.has('WITH_QEMU') include_directories: [ conf_inc_dir, hypervisor_inc_dir, + storage_file_inc_dir, ], ) diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index c444f8aaba..72ca781d8b 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -29,6 +29,7 @@ #include "qemu_checkpoint.h" #include "qemu_command.h" +#include "storage_source.h" #include "virerror.h" #include "virlog.h" #include "virbuffer.h" diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index c98094e746..ca23466b22 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -24,6 +24,7 @@ #include "qemu_alias.h" #include "qemu_security.h" +#include "storage_source.h" #include "viralloc.h" #include "virstoragefile.h" #include "virstring.h" diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 966608882f..165321858e 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -52,6 +52,7 @@ #include "virtime.h" #include "virnetdevopenvswitch.h" #include "virstoragefile.h" +#include "storage_source.h" #include "virstring.h" #include "virthreadjob.h" #include "virprocess.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 34a8fbe233..a5c2488f2c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -84,6 +84,7 @@ #include "virhook.h" #include "virstoragefile.h" #include "virstoragefileprobe.h" +#include "storage_source.h" #include "virfile.h" #include "virfdstream.h" #include "configmake.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index d016fe09a4..f1fa5986e1 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -53,6 +53,7 @@ #include "virnetdevmidonet.h" #include "device_conf.h" #include "virstoragefile.h" +#include "storage_source.h" #include "virstring.h" #include "virtime.h" #include "virqemu.h" diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 202d867289..14e1f5d962 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -95,6 +95,7 @@ #include "viridentity.h" #include "virthreadjob.h" #include "virutil.h" +#include "storage_source.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index c2fa54f5ab..994c7dc60b 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -42,6 +42,7 @@ #include "virstring.h" #include "virdomainsnapshotobjlist.h" #include "virqemu.h" +#include "storage_source.h" #define VIR_FROM_THIS VIR_FROM_QEMU diff --git a/src/security/meson.build b/src/security/meson.build index 4f876c03c2..416fec7900 100644 --- a/src/security/meson.build +++ b/src/security/meson.build @@ -48,6 +48,7 @@ if conf.has('WITH_LIBVIRTD') and conf.has('WITH_APPARMOR') conf_inc_dir, hypervisor_inc_dir, include_directories('.'), + include_directories('../storage_file'), ], } endif diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 18af175655..6525baf193 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -37,6 +37,7 @@ #include "security_driver.h" #include "security_apparmor.h" +#include "storage_source.h" #include "domain_conf.h" #include "virxml.h" #include "viruuid.h" @@ -46,7 +47,6 @@ #include "virfile.h" #include "configmake.h" #include "virrandom.h" -#include "virstoragefile.h" #include "virstring.h" #include "virgettext.h" #include "virhostdev.h" diff --git a/src/storage/meson.build b/src/storage/meson.build index 8537359e93..153ff6f846 100644 --- a/src/storage/meson.build +++ b/src/storage/meson.build @@ -79,6 +79,7 @@ if conf.has('WITH_STORAGE') ], include_directories: [ conf_inc_dir, + include_directories('../storage_file'), ], ) @@ -162,6 +163,9 @@ if conf.has('WITH_STORAGE_GLUSTER') 'deps': [ glusterfs_dep, ], + 'include': [ + include_directories('../storage_file'), + ], 'install_dir': storage_backend_install_dir, } endif diff --git a/src/storage/storage_backend_gluster.c b/src/storage/storage_backend_gluster.c index 205a707a17..782f8eb611 100644 --- a/src/storage/storage_backend_gluster.c +++ b/src/storage/storage_backend_gluster.c @@ -32,6 +32,7 @@ #include "virstring.h" #include "viruri.h" #include "storage_util.h" +#include "storage_source.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 4117127d65..d51fa2b4c0 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -64,6 +64,7 @@ #include "virstoragefile.h" #include "virstoragefileprobe.h" #include "storage_util.h" +#include "storage_source.h" #include "virlog.h" #include "virfile.h" #include "virjson.h" diff --git a/src/storage_file/meson.build b/src/storage_file/meson.build index 20eb0176fc..bae018feac 100644 --- a/src/storage_file/meson.build +++ b/src/storage_file/meson.build @@ -1,3 +1,7 @@ +storage_file_sources = [ + 'storage_source.c', +] + stoarge_file_fs_sources = [ 'storage_file_fs.c', ] @@ -8,6 +12,18 @@ storage_file_gluster_sources = [ storage_file_install_dir = libdir / 'libvirt' / 'storage-file' +virt_storage_file_lib = static_library( + 'virt_storage_file', + [ + storage_file_sources, + ], + dependencies: [ + src_dep, + ], +) + +libvirt_libs += virt_storage_file_lib + if conf.has('WITH_STORAGE') virt_modules += { 'name': 'virt_storage_file_fs', @@ -36,3 +52,5 @@ if conf.has('WITH_STORAGE_GLUSTER') 'install_dir': storage_file_install_dir, } endif + +storage_file_inc_dir = include_directories('.') diff --git a/src/storage_file/storage_source.c b/src/storage_file/storage_source.c new file mode 100644 index 0000000000..b5e0bc5040 --- /dev/null +++ b/src/storage_file/storage_source.c @@ -0,0 +1,2614 @@ +/* + * storage_source.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2017 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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 <unistd.h> + +#include "internal.h" +#include "storage_source.h" +#include "viralloc.h" +#include "virerror.h" +#include "virfile.h" +#include "virhash.h" +#include "virjson.h" +#include "virlog.h" +#include "virobject.h" +#include "virstoragefile.h" +#include "virstoragefilebackend.h" +#include "virstoragefileprobe.h" +#include "virstring.h" +#include "viruri.h" +#include "virutil.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("storage_source"); + + +static virStorageSourcePtr +virStorageFileMetadataNew(const char *path, + int format) +{ + g_autoptr(virStorageSource) def = virStorageSourceNew(); + + def->format = format; + def->type = VIR_STORAGE_TYPE_FILE; + + def->path = g_strdup(path); + + return g_steal_pointer(&def); +} + + +/** + * virStorageFileGetMetadataFromBuf: + * @path: name of file, for error messages + * @buf: header bytes from @path + * @len: length of @buf + * @format: format of the storage file + * + * 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. Does not recurse. + * + * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a format on a file + * that might be raw if that file will then be passed to a guest, since a + * malicious guest can turn a raw file into any other non-raw format at will. + * + * If the 'backingStoreRawFormat' field of the returned structure is + * VIR_STORAGE_FILE_AUTO it indicates the image didn't specify an explicit + * format for its backing store. Callers are advised against probing for the + * backing store format in this case. + * + * Caller MUST free the result after use via virObjectUnref. + */ +virStorageSourcePtr +virStorageFileGetMetadataFromBuf(const char *path, + char *buf, + size_t len, + int format) +{ + virStorageSourcePtr ret = NULL; + + if (!(ret = virStorageFileMetadataNew(path, format))) + return NULL; + + if (virStorageFileProbeGetMetadata(ret, buf, len) < 0) { + virObjectUnref(ret); + return NULL; + } + + return ret; +} + + +/** + * virStorageFileGetMetadataFromFD: + * + * 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. Does not recurse. + * + * 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. + * + * Caller MUST free the result after use via virObjectUnref. + */ +virStorageSourcePtr +virStorageFileGetMetadataFromFD(const char *path, + int fd, + int format) + +{ + ssize_t len = VIR_STORAGE_MAX_HEADER; + struct stat sb; + g_autofree char *buf = NULL; + g_autoptr(virStorageSource) meta = NULL; + + if (fstat(fd, &sb) < 0) { + virReportSystemError(errno, + _("cannot stat file '%s'"), path); + return NULL; + } + + if (!(meta = virStorageFileMetadataNew(path, format))) + return NULL; + + if (S_ISDIR(sb.st_mode)) { + /* No header to probe for directories, but also no backing file. Just + * update the metadata.*/ + meta->type = VIR_STORAGE_TYPE_DIR; + meta->format = VIR_STORAGE_FILE_DIR; + return g_steal_pointer(&meta); + } + + if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { + virReportSystemError(errno, _("cannot seek to start of '%s'"), meta->path); + return NULL; + } + + if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) { + virReportSystemError(errno, _("cannot read header '%s'"), meta->path); + return NULL; + } + + if (virStorageFileProbeGetMetadata(meta, buf, len) < 0) + return NULL; + + if (S_ISREG(sb.st_mode)) + meta->type = VIR_STORAGE_TYPE_FILE; + else if (S_ISBLK(sb.st_mode)) + meta->type = VIR_STORAGE_TYPE_BLOCK; + + return g_steal_pointer(&meta); +} + + +/* Given a @chain, look for the backing store @name that is a backing file + * of @startFrom (or any member of @chain if @startFrom is NULL) and return + * that location within the chain. @chain must always point to the top of + * the chain. Pass NULL for @name and 0 for @idx to find the base of the + * chain. Pass nonzero @idx to find the backing source according to its + * position in the backing chain. If @parent is not NULL, set *@parent to + * the preferred name of the parent (or to NULL if @name matches the start + * of the chain). Since the results point within @chain, they must not be + * independently freed. Reports an error and returns NULL if @name is not + * found. + */ +virStorageSourcePtr +virStorageFileChainLookup(virStorageSourcePtr chain, + virStorageSourcePtr startFrom, + const char *name, + unsigned int idx, + virStorageSourcePtr *parent) +{ + virStorageSourcePtr prev; + const char *start = chain->path; + bool nameIsFile = virStorageIsFile(name); + + if (!parent) + parent = &prev; + *parent = NULL; + + if (startFrom) { + while (virStorageSourceIsBacking(chain) && + chain != startFrom->backingStore) + chain = chain->backingStore; + + *parent = startFrom; + } + + while (virStorageSourceIsBacking(chain)) { + if (!name && !idx) { + if (!virStorageSourceHasBacking(chain)) + break; + } else if (idx) { + VIR_DEBUG("%u: %s", chain->id, chain->path); + if (idx == chain->id) + break; + } else { + if (STREQ_NULLABLE(name, chain->relPath) || + STREQ_NULLABLE(name, chain->path)) + break; + + if (nameIsFile && virStorageSourceIsLocalStorage(chain)) { + g_autofree char *parentDir = NULL; + int result; + + if (*parent && virStorageSourceIsLocalStorage(*parent)) + parentDir = g_path_get_dirname((*parent)->path); + else + parentDir = g_strdup("."); + + result = virFileRelLinkPointsTo(parentDir, name, + chain->path); + + if (result < 0) + goto error; + + if (result > 0) + break; + } + } + *parent = chain; + chain = chain->backingStore; + } + + if (!virStorageSourceIsBacking(chain)) + goto error; + + return chain; + + error: + if (idx) { + virReportError(VIR_ERR_INVALID_ARG, + _("could not find backing store index %u in chain " + "for '%s'"), + idx, NULLSTR(start)); + } else if (name) { + if (startFrom) + virReportError(VIR_ERR_INVALID_ARG, + _("could not find image '%s' beneath '%s' in " + "chain for '%s'"), name, NULLSTR(startFrom->path), + NULLSTR(start)); + else + virReportError(VIR_ERR_INVALID_ARG, + _("could not find image '%s' in chain for '%s'"), + name, NULLSTR(start)); + } else { + virReportError(VIR_ERR_INVALID_ARG, + _("could not find base image in chain for '%s'"), + NULLSTR(start)); + } + *parent = NULL; + return NULL; +} + + +static virStorageSourcePtr +virStorageSourceNewFromBackingRelative(virStorageSourcePtr parent, + const char *rel) +{ + g_autofree char *dirname = NULL; + g_autoptr(virStorageSource) def = virStorageSourceNew(); + + /* store relative name */ + def->relPath = g_strdup(rel); + + dirname = g_path_get_dirname(parent->path); + + if (STRNEQ(dirname, "/")) { + def->path = g_strdup_printf("%s/%s", dirname, rel); + } else { + def->path = g_strdup_printf("/%s", rel); + } + + if (virStorageSourceGetActualType(parent) == VIR_STORAGE_TYPE_NETWORK) { + def->type = VIR_STORAGE_TYPE_NETWORK; + + /* copy the host network part */ + def->protocol = parent->protocol; + if (parent->nhosts) { + if (!(def->hosts = virStorageNetHostDefCopy(parent->nhosts, + parent->hosts))) + return NULL; + + def->nhosts = parent->nhosts; + } + + def->volume = g_strdup(parent->volume); + } else { + /* set the type to _FILE, the caller shall update it to the actual type */ + def->type = VIR_STORAGE_TYPE_FILE; + } + + return g_steal_pointer(&def); +} + + +static int +virStorageSourceParseBackingURI(virStorageSourcePtr src, + const char *uristr) +{ + g_autoptr(virURI) uri = NULL; + const char *path = NULL; + g_auto(GStrv) scheme = NULL; + + if (!(uri = virURIParse(uristr))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("failed to parse backing file location '%s'"), + uristr); + return -1; + } + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (!(scheme = virStringSplit(uri->scheme, "+", 2))) + return -1; + + if (!scheme[0] || + (src->protocol = virStorageNetProtocolTypeFromString(scheme[0])) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid backing protocol '%s'"), + NULLSTR(scheme[0])); + return -1; + } + + if (scheme[1] && + (src->hosts->transport = virStorageNetHostTransportTypeFromString(scheme[1])) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid protocol transport type '%s'"), + scheme[1]); + return -1; + } + + if (uri->query) { + if (src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTP || + src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS) { + src->query = g_strdup(uri->query); + } else { + /* handle socket stored as a query */ + if (STRPREFIX(uri->query, "socket=")) + src->hosts->socket = g_strdup(STRSKIP(uri->query, "socket=")); + } + } + + /* uri->path is NULL if the URI does not contain slash after host: + * transport://host:port */ + if (uri->path) + path = uri->path; + else + path = ""; + + /* possibly skip the leading slash */ + if (path[0] == '/') + path++; + + /* NBD allows empty export name (path) */ + if (src->protocol == VIR_STORAGE_NET_PROTOCOL_NBD && + path[0] == '\0') + path = NULL; + + src->path = g_strdup(path); + + if (src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) { + char *tmp; + + if (!src->path) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("missing volume name and path for gluster volume")); + return -1; + } + + if (!(tmp = strchr(src->path, '/')) || + tmp == src->path) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("missing volume name or file name in " + "gluster source path '%s'"), src->path); + return -1; + } + + src->volume = src->path; + + src->path = g_strdup(tmp + 1); + + tmp[0] = '\0'; + } + + src->hosts->port = uri->port; + + src->hosts->name = g_strdup(uri->server); + + /* Libvirt doesn't handle inline authentication. Make the caller aware. */ + if (uri->user) + return 1; + + return 0; +} + + +static int +virStorageSourceRBDAddHost(virStorageSourcePtr src, + char *hostport) +{ + char *port; + size_t skip; + g_auto(GStrv) parts = NULL; + + if (VIR_EXPAND_N(src->hosts, src->nhosts, 1) < 0) + return -1; + + if ((port = strchr(hostport, ']'))) { + /* ipv6, strip brackets */ + hostport += 1; + skip = 3; + } else { + port = strstr(hostport, "\\:"); + skip = 2; + } + + if (port) { + *port = '\0'; + port += skip; + if (virStringParsePort(port, &src->hosts[src->nhosts - 1].port) < 0) + goto error; + } + + parts = virStringSplit(hostport, "\\:", 0); + if (!parts) + goto error; + src->hosts[src->nhosts-1].name = virStringListJoin((const char **)parts, ":"); + if (!src->hosts[src->nhosts-1].name) + goto error; + + src->hosts[src->nhosts-1].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + src->hosts[src->nhosts-1].socket = NULL; + + return 0; + + error: + VIR_FREE(src->hosts[src->nhosts-1].name); + return -1; +} + + +int +virStorageSourceParseRBDColonString(const char *rbdstr, + virStorageSourcePtr src) +{ + char *p, *e, *next; + g_autofree char *options = NULL; + g_autoptr(virStorageAuthDef) authdef = NULL; + + /* optionally skip the "rbd:" prefix if provided */ + if (STRPREFIX(rbdstr, "rbd:")) + rbdstr += strlen("rbd:"); + + src->path = g_strdup(rbdstr); + + p = strchr(src->path, ':'); + if (p) { + options = g_strdup(p + 1); + *p = '\0'; + } + + /* snapshot name */ + if ((p = strchr(src->path, '@'))) { + src->snapshot = g_strdup(p + 1); + *p = '\0'; + } + + /* pool vs. image name */ + if ((p = strchr(src->path, '/'))) { + src->volume = g_steal_pointer(&src->path); + src->path = g_strdup(p + 1); + *p = '\0'; + } + + /* options */ + if (!options) + return 0; /* all done */ + + p = options; + while (*p) { + /* find : delimiter or end of string */ + for (e = p; *e && *e != ':'; ++e) { + if (*e == '\\') { + e++; + if (*e == '\0') + break; + } + } + if (*e == '\0') { + next = e; /* last kv pair */ + } else { + next = e + 1; + *e = '\0'; + } + + if (STRPREFIX(p, "id=")) { + /* formulate authdef for src->auth */ + if (src->auth) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("duplicate 'id' found in '%s'"), src->path); + return -1; + } + + authdef = g_new0(virStorageAuthDef, 1); + + authdef->username = g_strdup(p + strlen("id=")); + + authdef->secrettype = g_strdup(virSecretUsageTypeToString(VIR_SECRET_USAGE_TYPE_CEPH)); + src->auth = g_steal_pointer(&authdef); + + /* Cannot formulate a secretType (eg, usage or uuid) given + * what is provided. + */ + } + if (STRPREFIX(p, "mon_host=")) { + char *h, *sep; + + h = p + strlen("mon_host="); + while (h < e) { + for (sep = h; sep < e; ++sep) { + if (*sep == '\\' && (sep[1] == ',' || + sep[1] == ';' || + sep[1] == ' ')) { + *sep = '\0'; + sep += 2; + break; + } + } + + if (virStorageSourceRBDAddHost(src, h) < 0) + return -1; + + h = sep; + } + } + + if (STRPREFIX(p, "conf=")) + src->configFile = g_strdup(p + strlen("conf=")); + + p = next; + } + return 0; +} + + +static int +virStorageSourceParseNBDColonString(const char *nbdstr, + virStorageSourcePtr src) +{ + g_autofree char *nbd = g_strdup(nbdstr); + char *export_name; + char *host_spec; + char *unixpath; + char *port; + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + /* We extract the parameters in a similar way qemu does it */ + + /* format: [] denotes optional sections, uppercase are variable strings + * nbd:unix:/PATH/TO/SOCKET[:exportname=EXPORTNAME] + * nbd:HOSTNAME:PORT[:exportname=EXPORTNAME] + */ + + /* first look for ':exportname=' and cut it off */ + if ((export_name = strstr(nbd, ":exportname="))) { + src->path = g_strdup(export_name + strlen(":exportname=")); + export_name[0] = '\0'; + } + + /* Verify the prefix and contents. Note that we require a + * "host_spec" part to be present. */ + if (!(host_spec = STRSKIP(nbd, "nbd:")) || host_spec[0] == '\0') + goto malformed; + + if ((unixpath = STRSKIP(host_spec, "unix:"))) { + src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; + + if (unixpath[0] == '\0') + goto malformed; + + src->hosts->socket = g_strdup(unixpath); + } else { + src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + + if (host_spec[0] == ':') { + /* no host given */ + goto malformed; + } else if (host_spec[0] == '[') { + host_spec++; + /* IPv6 addr */ + if (!(port = strstr(host_spec, "]:"))) + goto malformed; + + port[0] = '\0'; + port += 2; + + if (host_spec[0] == '\0') + goto malformed; + } else { + if (!(port = strchr(host_spec, ':'))) + goto malformed; + + port[0] = '\0'; + port++; + } + + if (virStringParsePort(port, &src->hosts->port) < 0) + return -1; + + src->hosts->name = g_strdup(host_spec); + } + + return 0; + + malformed: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("malformed nbd string '%s'"), nbdstr); + return -1; +} + + +static int +virStorageSourceParseBackingColon(virStorageSourcePtr src, + const char *path) +{ + const char *p; + g_autofree char *protocol = NULL; + + if (!(p = strchr(path, ':'))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid backing protocol string '%s'"), + path); + return -1; + } + + protocol = g_strndup(path, p - path); + + if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("invalid backing protocol '%s'"), + protocol); + return -1; + } + + switch ((virStorageNetProtocol) src->protocol) { + case VIR_STORAGE_NET_PROTOCOL_NBD: + if (virStorageSourceParseNBDColonString(path, src) < 0) + return -1; + break; + + case VIR_STORAGE_NET_PROTOCOL_RBD: + if (virStorageSourceParseRBDColonString(path, src) < 0) + return -1; + break; + + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_LAST: + case VIR_STORAGE_NET_PROTOCOL_NONE: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("backing store parser is not implemented for protocol %s"), + protocol); + return -1; + + case VIR_STORAGE_NET_PROTOCOL_HTTP: + case VIR_STORAGE_NET_PROTOCOL_HTTPS: + case VIR_STORAGE_NET_PROTOCOL_FTP: + case VIR_STORAGE_NET_PROTOCOL_FTPS: + case VIR_STORAGE_NET_PROTOCOL_TFTP: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_SSH: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("malformed backing store path for protocol %s"), + protocol); + return -1; + } + + return 0; +} + + +static int +virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr, + bool allowformat); + + +static int +virStorageSourceParseBackingJSONPath(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int type) +{ + const char *path; + + if (!(path = virJSONValueObjectGetString(json, "filename"))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'filename' field in JSON backing volume " + "definition")); + return -1; + } + + src->path = g_strdup(path); + + src->type = type; + return 0; +} + + +static int +virStorageSourceParseBackingJSONUriStr(virStorageSourcePtr src, + const char *uri, + int protocol) +{ + int rc; + + if ((rc = virStorageSourceParseBackingURI(src, uri)) < 0) + return -1; + + if (src->protocol != protocol) { + virReportError(VIR_ERR_INVALID_ARG, + _("expected protocol '%s' but got '%s' in URI JSON volume " + "definition"), + virStorageNetProtocolTypeToString(protocol), + virStorageNetProtocolTypeToString(src->protocol)); + return -1; + } + + return rc; +} + + +static int +virStorageSourceParseBackingJSONUriCookies(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr) +{ + const char *cookiestr; + g_auto(GStrv) cookies = NULL; + size_t ncookies = 0; + size_t i; + + if (!virJSONValueObjectHasKey(json, "cookie")) + return 0; + + if (!(cookiestr = virJSONValueObjectGetString(json, "cookie"))) { + virReportError(VIR_ERR_INVALID_ARG, + _("wrong format of 'cookie' field in backing store definition '%s'"), + jsonstr); + return -1; + } + + if (!(cookies = virStringSplitCount(cookiestr, ";", 0, &ncookies))) + return -1; + + src->cookies = g_new0(virStorageNetCookieDefPtr, ncookies); + src->ncookies = ncookies; + + for (i = 0; i < ncookies; i++) { + char *cookiename = cookies[i]; + char *cookievalue; + + virSkipSpaces((const char **) &cookiename); + + if (!(cookievalue = strchr(cookiename, '='))) { + virReportError(VIR_ERR_INVALID_ARG, + _("malformed http cookie '%s' in backing store definition '%s'"), + cookies[i], jsonstr); + return -1; + } + + *cookievalue = '\0'; + cookievalue++; + + src->cookies[i] = g_new0(virStorageNetCookieDef, 1); + src->cookies[i]->name = g_strdup(cookiename); + src->cookies[i]->value = g_strdup(cookievalue); + } + + return 0; +} + + +static int +virStorageSourceParseBackingJSONUri(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr, + int protocol) +{ + const char *uri; + + if (!(uri = virJSONValueObjectGetString(json, "url"))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'url' in JSON backing volume definition")); + return -1; + } + + if (protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS || + protocol == VIR_STORAGE_NET_PROTOCOL_FTPS) { + if (virJSONValueObjectHasKey(json, "sslverify")) { + const char *tmpstr; + bool tmp; + + /* libguestfs still uses undocumented legacy value of 'off' */ + if ((tmpstr = virJSONValueObjectGetString(json, "sslverify")) && + STREQ(tmpstr, "off")) { + src->sslverify = VIR_TRISTATE_BOOL_NO; + } else { + if (virJSONValueObjectGetBoolean(json, "sslverify", &tmp) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("malformed 'sslverify' field in backing store definition '%s'"), + jsonstr); + return -1; + } + + src->sslverify = virTristateBoolFromBool(tmp); + } + } + } + + if (protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS || + protocol == VIR_STORAGE_NET_PROTOCOL_HTTP) { + if (virStorageSourceParseBackingJSONUriCookies(src, json, jsonstr) < 0) + return -1; + } + + if (virJSONValueObjectHasKey(json, "readahead") && + virJSONValueObjectGetNumberUlong(json, "readahead", &src->readahead) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("malformed 'readahead' field in backing store definition '%s'"), + jsonstr); + return -1; + } + + if (virJSONValueObjectHasKey(json, "timeout") && + virJSONValueObjectGetNumberUlong(json, "timeout", &src->timeout) < 0) { + virReportError(VIR_ERR_INVALID_ARG, + _("malformed 'timeout' field in backing store definition '%s'"), + jsonstr); + return -1; + } + + return virStorageSourceParseBackingJSONUriStr(src, uri, protocol); +} + + +static int +virStorageSourceParseBackingJSONInetSocketAddress(virStorageNetHostDefPtr host, + virJSONValuePtr json) +{ + const char *hostname; + const char *port; + + if (!json) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing remote server specification in JSON " + "backing volume definition")); + return -1; + } + + hostname = virJSONValueObjectGetString(json, "host"); + port = virJSONValueObjectGetString(json, "port"); + + if (!hostname) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing hostname for tcp backing server in " + "JSON backing volume definition")); + return -1; + } + + host->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + host->name = g_strdup(hostname); + + if (virStringParsePort(port, &host->port) < 0) + return -1; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONSocketAddress(virStorageNetHostDefPtr host, + virJSONValuePtr json) +{ + const char *type; + const char *socket; + + if (!json) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing remote server specification in JSON " + "backing volume definition")); + return -1; + } + + if (!(type = virJSONValueObjectGetString(json, "type"))) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing socket address type in " + "JSON backing volume definition")); + return -1; + } + + if (STREQ(type, "tcp") || STREQ(type, "inet")) { + return virStorageSourceParseBackingJSONInetSocketAddress(host, json); + + } else if (STREQ(type, "unix")) { + host->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; + + socket = virJSONValueObjectGetString(json, "path"); + + /* check for old spelling for gluster protocol */ + if (!socket) + socket = virJSONValueObjectGetString(json, "socket"); + + if (!socket) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing socket path for udp backing server in " + "JSON backing volume definition")); + return -1; + } + + host->socket = g_strdup(socket); + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("backing store protocol '%s' is not yet supported"), + type); + return -1; + } + + return 0; +} + + +static int +virStorageSourceParseBackingJSONGluster(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *uri = virJSONValueObjectGetString(json, "filename"); + const char *volume = virJSONValueObjectGetString(json, "volume"); + const char *path = virJSONValueObjectGetString(json, "path"); + virJSONValuePtr server = virJSONValueObjectGetArray(json, "server"); + size_t nservers; + size_t i; + + /* legacy URI based syntax passed via 'filename' option */ + if (uri) + return virStorageSourceParseBackingJSONUriStr(src, uri, + VIR_STORAGE_NET_PROTOCOL_GLUSTER); + + if (!volume || !path || !server) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'volume', 'path' or 'server' attribute in " + "JSON backing definition for gluster volume")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_GLUSTER; + + src->volume = g_strdup(volume); + src->path = g_strdup(path); + + nservers = virJSONValueArraySize(server); + if (nservers == 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("at least 1 server is necessary in " + "JSON backing definition for gluster volume")); + + return -1; + } + + src->hosts = g_new0(virStorageNetHostDef, nservers); + src->nhosts = nservers; + + for (i = 0; i < nservers; i++) { + if (virStorageSourceParseBackingJSONSocketAddress(src->hosts + i, + virJSONValueArrayGet(server, i)) < 0) + return -1; + } + + return 0; +} + + +static int +virStorageSourceParseBackingJSONiSCSI(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *transport = virJSONValueObjectGetString(json, "transport"); + const char *portal = virJSONValueObjectGetString(json, "portal"); + const char *target = virJSONValueObjectGetString(json, "target"); + const char *lun = virJSONValueObjectGetStringOrNumber(json, "lun"); + const char *uri; + char *port; + + /* legacy URI based syntax passed via 'filename' option */ + if ((uri = virJSONValueObjectGetString(json, "filename"))) + return virStorageSourceParseBackingJSONUriStr(src, uri, + VIR_STORAGE_NET_PROTOCOL_ISCSI); + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_ISCSI; + + if (!lun) + lun = "0"; + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (STRNEQ_NULLABLE(transport, "tcp")) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("only TCP transport is supported for iSCSI volumes")); + return -1; + } + + src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + + if (!portal) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'portal' address in iSCSI backing definition")); + return -1; + } + + if (!target) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'target' in iSCSI backing definition")); + return -1; + } + + src->hosts->name = g_strdup(portal); + + if ((port = strrchr(src->hosts->name, ':')) && + !strchr(port, ']')) { + if (virStringParsePort(port + 1, &src->hosts->port) < 0) + return -1; + + *port = '\0'; + } + + src->path = g_strdup_printf("%s/%s", target, lun); + + /* Libvirt doesn't handle inline authentication. Make the caller aware. */ + if (virJSONValueObjectGetString(json, "user") || + virJSONValueObjectGetString(json, "password")) + return 1; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONNbd(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *path = virJSONValueObjectGetString(json, "path"); + const char *host = virJSONValueObjectGetString(json, "host"); + const char *port = virJSONValueObjectGetString(json, "port"); + const char *export = virJSONValueObjectGetString(json, "export"); + virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); + + if (!path && !host && !server) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing host specification of NBD server in JSON " + "backing volume definition")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_NBD; + + src->path = g_strdup(export); + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (server) { + if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0) + return -1; + } else { + if (path) { + src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; + src->hosts[0].socket = g_strdup(path); + } else { + src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + src->hosts[0].name = g_strdup(host); + + if (virStringParsePort(port, &src->hosts[0].port) < 0) + return -1; + } + } + + return 0; +} + + +static int +virStorageSourceParseBackingJSONSheepdog(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *filename; + const char *vdi = virJSONValueObjectGetString(json, "vdi"); + virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); + + /* legacy URI based syntax passed via 'filename' option */ + if ((filename = virJSONValueObjectGetString(json, "filename"))) { + if (strstr(filename, "://")) + return virStorageSourceParseBackingJSONUriStr(src, filename, + VIR_STORAGE_NET_PROTOCOL_SHEEPDOG); + + /* libvirt doesn't implement a parser for the legacy non-URI syntax */ + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing sheepdog URI in JSON backing volume definition")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_SHEEPDOG; + + if (!vdi) { + virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing sheepdog vdi name")); + return -1; + } + + src->path = g_strdup(vdi); + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0) + return -1; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONSSH(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *path = virJSONValueObjectGetString(json, "path"); + const char *host = virJSONValueObjectGetString(json, "host"); + const char *port = virJSONValueObjectGetString(json, "port"); + const char *user = virJSONValueObjectGetString(json, "user"); + const char *host_key_check = virJSONValueObjectGetString(json, "host_key_check"); + virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); + + if (!(host || server) || !path) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing host/server or path of SSH JSON backing " + "volume definition")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_SSH; + + src->path = g_strdup(path); + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (server) { + if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, + server) < 0) + return -1; + } else { + src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; + src->hosts[0].name = g_strdup(host); + + if (virStringParsePort(port, &src->hosts[0].port) < 0) + return -1; + } + + /* these two are parsed just to be passed back as we don't model them yet */ + src->ssh_user = g_strdup(user); + if (STREQ_NULLABLE(host_key_check, "no")) + src->ssh_host_key_check_disabled = true; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONRBD(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *filename; + const char *pool = virJSONValueObjectGetString(json, "pool"); + const char *image = virJSONValueObjectGetString(json, "image"); + const char *conf = virJSONValueObjectGetString(json, "conf"); + const char *snapshot = virJSONValueObjectGetString(json, "snapshot"); + virJSONValuePtr servers = virJSONValueObjectGetArray(json, "server"); + size_t nservers; + size_t i; + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_RBD; + + /* legacy syntax passed via 'filename' option */ + if ((filename = virJSONValueObjectGetString(json, "filename"))) + return virStorageSourceParseRBDColonString(filename, src); + + if (!pool || !image) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing pool or image name in ceph backing volume " + "JSON specification")); + return -1; + } + + src->volume = g_strdup(pool); + src->path = g_strdup(image); + src->snapshot = g_strdup(snapshot); + src->configFile = g_strdup(conf); + + if (servers) { + nservers = virJSONValueArraySize(servers); + + src->hosts = g_new0(virStorageNetHostDef, nservers); + src->nhosts = nservers; + + for (i = 0; i < nservers; i++) { + if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i, + virJSONValueArrayGet(servers, i)) < 0) + return -1; + } + } + + return 0; +} + +static int +virStorageSourceParseBackingJSONRaw(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr, + int opaque G_GNUC_UNUSED) +{ + bool has_offset = virJSONValueObjectHasKey(json, "offset"); + bool has_size = virJSONValueObjectHasKey(json, "size"); + virJSONValuePtr file; + + if (has_offset || has_size) { + src->sliceStorage = g_new0(virStorageSourceSlice, 1); + + if (has_offset && + virJSONValueObjectGetNumberUlong(json, "offset", &src->sliceStorage->offset) < 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("malformed 'offset' property of 'raw' driver")); + return -1; + } + + if (has_size && + virJSONValueObjectGetNumberUlong(json, "size", &src->sliceStorage->size) < 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("malformed 'size' property of 'raw' driver")); + return -1; + } + } + + /* 'raw' is a format driver so it can have protocol driver children */ + if (!(file = virJSONValueObjectGetObject(json, "file"))) { + virReportError(VIR_ERR_INVALID_ARG, + _("JSON backing volume definition '%s' lacks 'file' object"), + jsonstr); + return -1; + } + + return virStorageSourceParseBackingJSONInternal(src, file, jsonstr, false); +} + + +static int +virStorageSourceParseBackingJSONVxHS(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + const char *vdisk_id = virJSONValueObjectGetString(json, "vdisk-id"); + virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); + + if (!vdisk_id || !server) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'vdisk-id' or 'server' attribute in " + "JSON backing definition for VxHS volume")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_VXHS; + + src->path = g_strdup(vdisk_id); + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, + server) < 0) + return -1; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONNFS(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); + int uidStore = -1; + int gidStore = -1; + int gotUID = virJSONValueObjectGetNumberInt(json, "user", &uidStore); + int gotGID = virJSONValueObjectGetNumberInt(json, "group", &gidStore); + + if (!server) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'server' attribute in JSON backing definition for NFS volume")); + return -1; + } + + if (gotUID < 0 || gotGID < 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'user' or 'group' attribute in JSON backing definition for NFS volume")); + return -1; + } + + src->path = g_strdup(virJSONValueObjectGetString(json, "path")); + if (!src->path) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing 'path' attribute in JSON backing definition for NFS volume")); + return -1; + } + + src->nfs_user = g_strdup_printf("+%d", uidStore); + src->nfs_group = g_strdup_printf("+%d", gidStore); + + src->type = VIR_STORAGE_TYPE_NETWORK; + src->protocol = VIR_STORAGE_NET_PROTOCOL_NFS; + + src->hosts = g_new0(virStorageNetHostDef, 1); + src->nhosts = 1; + + if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, + server) < 0) + return -1; + + return 0; +} + + +static int +virStorageSourceParseBackingJSONNVMe(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr G_GNUC_UNUSED, + int opaque G_GNUC_UNUSED) +{ + g_autoptr(virStorageSourceNVMeDef) nvme = g_new0(virStorageSourceNVMeDef, 1); + const char *device = virJSONValueObjectGetString(json, "device"); + + if (!device || virPCIDeviceAddressParse((char *) device, &nvme->pciAddr) < 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing or malformed 'device' field of 'nvme' storage")); + return -1; + } + + if (virJSONValueObjectGetNumberUlong(json, "namespace", &nvme->namespc) < 0 || + nvme->namespc == 0) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("missing or malformed 'namespace' field of 'nvme' storage")); + return -1; + } + + src->type = VIR_STORAGE_TYPE_NVME; + src->nvme = g_steal_pointer(&nvme); + + return 0; +} + + +struct virStorageSourceJSONDriverParser { + const char *drvname; + bool formatdriver; + /** + * The callback gets a pre-allocated storage source @src and the JSON + * object to parse. The callback shall return -1 on error and report error + * 0 on success and 1 in cases when the configuration itself is valid, but + * can't be converted to libvirt's configuration (e.g. inline authentication + * credentials are present). + */ + int (*func)(virStorageSourcePtr src, virJSONValuePtr json, const char *jsonstr, int opaque); + int opaque; +}; + +static const struct virStorageSourceJSONDriverParser jsonParsers[] = { + {"file", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_FILE}, + {"host_device", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK}, + {"host_cdrom", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK}, + {"http", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTP}, + {"https", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTPS}, + {"ftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTP}, + {"ftps", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTPS}, + {"tftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_TFTP}, + {"gluster", false, virStorageSourceParseBackingJSONGluster, 0}, + {"iscsi", false, virStorageSourceParseBackingJSONiSCSI, 0}, + {"nbd", false, virStorageSourceParseBackingJSONNbd, 0}, + {"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0}, + {"ssh", false, virStorageSourceParseBackingJSONSSH, 0}, + {"rbd", false, virStorageSourceParseBackingJSONRBD, 0}, + {"raw", true, virStorageSourceParseBackingJSONRaw, 0}, + {"nfs", false, virStorageSourceParseBackingJSONNFS, 0}, + {"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0}, + {"nvme", false, virStorageSourceParseBackingJSONNVMe, 0}, +}; + + + +static int +virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, + virJSONValuePtr json, + const char *jsonstr, + bool allowformat) +{ + const char *drvname; + size_t i; + + if (!(drvname = virJSONValueObjectGetString(json, "driver"))) { + virReportError(VIR_ERR_INVALID_ARG, + _("JSON backing volume definition '%s' lacks driver name"), + jsonstr); + return -1; + } + + for (i = 0; i < G_N_ELEMENTS(jsonParsers); i++) { + if (STRNEQ(drvname, jsonParsers[i].drvname)) + continue; + + if (jsonParsers[i].formatdriver && !allowformat) { + virReportError(VIR_ERR_INVALID_ARG, + _("JSON backing volume definition '%s' must not have nested format drivers"), + jsonstr); + return -1; + } + + return jsonParsers[i].func(src, json, jsonstr, jsonParsers[i].opaque); + } + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("missing parser implementation for JSON backing volume " + "driver '%s'"), drvname); + return -1; +} + + +static int +virStorageSourceParseBackingJSON(virStorageSourcePtr src, + const char *json) +{ + g_autoptr(virJSONValue) root = NULL; + g_autoptr(virJSONValue) deflattened = NULL; + virJSONValuePtr file = NULL; + + if (!(root = virJSONValueFromString(json))) + return -1; + + if (!(deflattened = virJSONValueObjectDeflatten(root))) + return -1; + + /* There are 2 possible syntaxes: + * 1) json:{"file":{"driver":...}} + * 2) json:{"driver":...} + * Remove the 'file' wrapper object in case 1. + */ + if (!virJSONValueObjectHasKey(deflattened, "driver")) + file = virJSONValueObjectGetObject(deflattened, "file"); + + if (!file) + file = deflattened; + + return virStorageSourceParseBackingJSONInternal(src, file, json, true); +} + + +/** + * virStorageSourceNewFromBackingAbsolute + * @path: string representing absolute location of a storage source + * @src: filled with virStorageSource object representing @path + * + * Returns 0 on success, 1 if we could parse all location data but @path + * specified other data unrepresentable by libvirt (e.g. inline authentication). + * In both cases @src is filled. On error -1 is returned @src is NULL and an + * error is reported. + */ +int +virStorageSourceNewFromBackingAbsolute(const char *path, + virStorageSourcePtr *src) +{ + const char *json; + const char *dirpath; + int rc = 0; + g_autoptr(virStorageSource) def = virStorageSourceNew(); + + *src = NULL; + + if (virStorageIsFile(path)) { + def->type = VIR_STORAGE_TYPE_FILE; + + def->path = g_strdup(path); + } else { + if ((dirpath = STRSKIP(path, "fat:"))) { + def->type = VIR_STORAGE_TYPE_DIR; + def->format = VIR_STORAGE_FILE_FAT; + def->path = g_strdup(dirpath); + *src = g_steal_pointer(&def); + return 0; + } + + def->type = VIR_STORAGE_TYPE_NETWORK; + + VIR_DEBUG("parsing backing store string: '%s'", path); + + /* handle URI formatted backing stores */ + if ((json = STRSKIP(path, "json:"))) + rc = virStorageSourceParseBackingJSON(def, json); + else if (strstr(path, "://")) + rc = virStorageSourceParseBackingURI(def, path); + else + rc = virStorageSourceParseBackingColon(def, path); + + if (rc < 0) + return -1; + + virStorageSourceNetworkAssignDefaultPorts(def); + + /* Some of the legacy parsers parse authentication data since they are + * also used in other places. For backing store detection the + * authentication data would be invalid anyways, so we clear it */ + if (def->auth) { + virStorageAuthDefFree(def->auth); + def->auth = NULL; + } + } + + *src = g_steal_pointer(&def); + return rc; +} + + +/** + * virStorageSourceNewFromChild: + * @parent: storage source parent + * @child: returned child/backing store definition + * @parentRaw: raw child string (backingStoreRaw) + * + * Creates a storage source which describes the backing image of @parent and + * fills it into @backing depending on the passed parentRaw (backingStoreRaw) + * and other data. Note that for local storage this function accesses the file + * to update the actual type of the child store. + * + * Returns 0 on success, 1 if we could parse all location data but the child + * store specification contained other data unrepresentable by libvirt (e.g. + * inline authentication). + * In both cases @src is filled. On error -1 is returned @src is NULL and an + * error is reported. + */ +static int +virStorageSourceNewFromChild(virStorageSourcePtr parent, + const char *parentRaw, + virStorageSourcePtr *child) +{ + struct stat st; + g_autoptr(virStorageSource) def = NULL; + int rc = 0; + + *child = NULL; + + if (virStorageIsRelative(parentRaw)) { + if (!(def = virStorageSourceNewFromBackingRelative(parent, parentRaw))) + return -1; + } else { + if ((rc = virStorageSourceNewFromBackingAbsolute(parentRaw, &def)) < 0) + return -1; + } + + /* possibly update local type */ + if (def->type == VIR_STORAGE_TYPE_FILE) { + if (stat(def->path, &st) == 0) { + if (S_ISDIR(st.st_mode)) { + def->type = VIR_STORAGE_TYPE_DIR; + def->format = VIR_STORAGE_FILE_DIR; + } else if (S_ISBLK(st.st_mode)) { + def->type = VIR_STORAGE_TYPE_BLOCK; + } + } + } + + /* copy parent's labelling and other top level stuff */ + if (virStorageSourceInitChainElement(def, parent, true) < 0) + return -1; + + def->detected = true; + + *child = g_steal_pointer(&def); + return rc; +} + + +int +virStorageSourceNewFromBacking(virStorageSourcePtr parent, + virStorageSourcePtr *backing) +{ + int rc; + + if ((rc = virStorageSourceNewFromChild(parent, + parent->backingStoreRaw, + backing)) < 0) + return rc; + + (*backing)->format = parent->backingStoreRawFormat; + (*backing)->readonly = true; + return rc; +} + + +/** + * @src: disk source definition structure + * @fd: file descriptor + * @sb: stat buffer + * + * Updates src->physical depending on the actual type of storage being used. + * To be called for domain storage source reporting as the volume code does + * not set/use the 'type' field for the voldef->source.target + * + * Returns 0 on success, -1 on error. No libvirt errors are reported. + */ +int +virStorageSourceUpdatePhysicalSize(virStorageSourcePtr src, + int fd, + struct stat const *sb) +{ + off_t end; + virStorageType actual_type = virStorageSourceGetActualType(src); + + switch (actual_type) { + case VIR_STORAGE_TYPE_FILE: + case VIR_STORAGE_TYPE_NETWORK: + src->physical = sb->st_size; + break; + + case VIR_STORAGE_TYPE_BLOCK: + if ((end = lseek(fd, 0, SEEK_END)) == (off_t) -1) + return -1; + + src->physical = end; + break; + + case VIR_STORAGE_TYPE_DIR: + src->physical = 0; + break; + + /* We shouldn't get VOLUME, but the switch requires all cases */ + case VIR_STORAGE_TYPE_VOLUME: + case VIR_STORAGE_TYPE_NVME: + case VIR_STORAGE_TYPE_NONE: + case VIR_STORAGE_TYPE_LAST: + return -1; + } + + return 0; +} + + +/** + * @src: disk source definition structure + * @fd: file descriptor + * @sb: stat buffer + * + * Update the capacity, allocation, physical values for the storage @src + * Shared between the domain storage source for an inactive domain and the + * voldef source target as the result is not affected by the 'type' field. + * + * Returns 0 on success, -1 on error. + */ +int +virStorageSourceUpdateBackingSizes(virStorageSourcePtr src, + int fd, + struct stat const *sb) +{ + /* Get info for normal formats */ + if (S_ISREG(sb->st_mode) || fd == -1) { +#ifndef WIN32 + src->allocation = (unsigned long long)sb->st_blocks * + (unsigned long long)DEV_BSIZE; +#else + src->allocation = sb->st_size; +#endif + /* Regular files may be sparse, so logical size (capacity) is not same + * as actual allocation above + */ + src->capacity = sb->st_size; + + /* Allocation tracks when the file is sparse, physical is the + * last offset of the file. */ + src->physical = sb->st_size; + } else if (S_ISDIR(sb->st_mode)) { + src->allocation = 0; + src->capacity = 0; + src->physical = 0; + } else if (fd >= 0) { + off_t end; + + /* XXX this is POSIX compliant, but doesn't work for CHAR files, + * only BLOCK. There is a Linux specific ioctl() for getting + * size of both CHAR / BLOCK devices we should check for in + * configure + * + * NB. Because we configure with AC_SYS_LARGEFILE, off_t + * should be 64 bits on all platforms. For block devices, we + * have to seek (safe even if someone else is writing) to + * determine physical size, and assume that allocation is the + * same as physical (but can refine that assumption later if + * qemu is still running). + */ + if ((end = lseek(fd, 0, SEEK_END)) == (off_t)-1) { + virReportSystemError(errno, + _("failed to seek to end of %s"), src->path); + return -1; + } + src->physical = end; + src->allocation = end; + src->capacity = end; + } + + return 0; +} + + +/** + * @src: disk source definition structure + * @buf: buffer to the storage file header + * @len: length of the storage file header + * + * Update the storage @src capacity. + * + * Returns 0 on success, -1 on error. + */ +int +virStorageSourceUpdateCapacity(virStorageSourcePtr src, + char *buf, + ssize_t len) +{ + int format = src->format; + g_autoptr(virStorageSource) meta = NULL; + + /* Raw files: capacity is physical size. For all other files: if + * the metadata has a capacity, use that, otherwise fall back to + * physical size. */ + if (format == VIR_STORAGE_FILE_NONE) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no disk format for %s was specified"), + src->path); + return -1; + } + + if (format == VIR_STORAGE_FILE_RAW && !src->encryption) { + src->capacity = src->physical; + } else if ((meta = virStorageFileGetMetadataFromBuf(src->path, buf, + len, format))) { + src->capacity = meta->capacity ? meta->capacity : src->physical; + if (src->encryption && meta->encryption) + src->encryption->payload_offset = meta->encryption->payload_offset; + } else { + return -1; + } + + if (src->encryption && src->encryption->payload_offset != -1) + src->capacity -= src->encryption->payload_offset * 512; + + return 0; +} + + +/** + * virStorageFileRemoveLastPathComponent: + * + * @path: Path string to remove the last component from + * + * Removes the last path component of a path. This function is designed to be + * called on file paths only (no trailing slashes in @path). Caller is + * responsible to free the returned string. + */ +static char * +virStorageFileRemoveLastPathComponent(const char *path) +{ + char *ret; + + ret = g_strdup(NULLSTR_EMPTY(path)); + + virFileRemoveLastComponent(ret); + + return ret; +} + + +/* + * virStorageFileGetRelativeBackingPath: + * + * Resolve relative path to be written to the overlay of @top image when + * collapsing the backing chain between @top and @base. + * + * Returns 0 on success; 1 if backing chain isn't relative and -1 on error. + */ +int +virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, + virStorageSourcePtr base, + char **relpath) +{ + virStorageSourcePtr next; + g_autofree char *tmp = NULL; + g_autofree char *path = NULL; + + *relpath = NULL; + + for (next = top; virStorageSourceIsBacking(next); next = next->backingStore) { + if (!next->relPath) + return 1; + + if (!(tmp = virStorageFileRemoveLastPathComponent(path))) + return -1; + + VIR_FREE(path); + + path = g_strdup_printf("%s%s", tmp, next->relPath); + + VIR_FREE(tmp); + + if (next == base) + break; + } + + if (next != base) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to resolve relative backing name: " + "base image is not in backing chain")); + return -1; + } + + *relpath = g_steal_pointer(&path); + return 0; +} + + +static bool +virStorageFileIsInitialized(const virStorageSource *src) +{ + return src && src->drv; +} + + +/** + * virStorageFileGetBackendForSupportCheck: + * @src: storage source to check support for + * @backend: pointer to the storage backend for @src if it's supported + * + * Returns 0 if @src is not supported by any storage backend currently linked + * 1 if it is supported and -1 on error with an error reported. + */ +static int +virStorageFileGetBackendForSupportCheck(const virStorageSource *src, + virStorageFileBackendPtr *backend) +{ + int actualType; + + + if (!src) { + *backend = NULL; + return 0; + } + + if (src->drv) { + virStorageDriverDataPtr drv = src->drv; + *backend = drv->backend; + return 1; + } + + actualType = virStorageSourceGetActualType(src); + + if (virStorageFileBackendForType(actualType, src->protocol, false, backend) < 0) + return -1; + + if (!*backend) + return 0; + + return 1; +} + + +int +virStorageFileSupportsBackingChainTraversal(const virStorageSource *src) +{ + virStorageFileBackendPtr backend; + int rv; + + if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + return rv; + + return backend->storageFileGetUniqueIdentifier && + backend->storageFileRead && + backend->storageFileAccess ? 1 : 0; +} + + +/** + * virStorageFileSupportsSecurityDriver: + * + * @src: a storage file structure + * + * Check if a storage file supports operations needed by the security + * driver to perform labelling + */ +int +virStorageFileSupportsSecurityDriver(const virStorageSource *src) +{ + virStorageFileBackendPtr backend; + int rv; + + if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + return rv; + + return backend->storageFileChown ? 1 : 0; +} + + +/** + * virStorageFileSupportsAccess: + * + * @src: a storage file structure + * + * Check if a storage file supports checking if the storage source is accessible + * for the given vm. + */ +int +virStorageFileSupportsAccess(const virStorageSource *src) +{ + virStorageFileBackendPtr backend; + int rv; + + if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + return rv; + + return backend->storageFileAccess ? 1 : 0; +} + + +/** + * virStorageFileSupportsCreate: + * @src: a storage file structure + * + * Check if the storage driver supports creating storage described by @src + * via virStorageFileCreate. + */ +int +virStorageFileSupportsCreate(const virStorageSource *src) +{ + virStorageFileBackendPtr backend; + int rv; + + if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + return rv; + + return backend->storageFileCreate ? 1 : 0; +} + + +void +virStorageFileDeinit(virStorageSourcePtr src) +{ + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) + return; + + drv = src->drv; + + if (drv->backend && + drv->backend->backendDeinit) + 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); + virStorageDriverDataPtr drv = g_new0(virStorageDriverData, 1); + + src->drv = drv; + + if (uid == (uid_t) -1) + drv->uid = geteuid(); + else + drv->uid = uid; + + if (gid == (gid_t) -1) + drv->gid = getegid(); + else + drv->gid = gid; + + if (virStorageFileBackendForType(actualType, + src->protocol, + true, + &drv->backend) < 0) + goto error; + + if (drv->backend->backendInit && + 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) +{ + virStorageDriverDataPtr drv = NULL; + int ret; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileCreate) { + errno = ENOSYS; + return -2; + } + + ret = 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) +{ + virStorageDriverDataPtr drv = NULL; + int ret; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileUnlink) { + errno = ENOSYS; + return -2; + } + + ret = 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) +{ + virStorageDriverDataPtr drv = NULL; + int ret; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileStat) { + errno = ENOSYS; + return -2; + } + + ret = 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) +{ + virStorageDriverDataPtr drv = NULL; + ssize_t ret; + + if (!virStorageFileIsInitialized(src)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("storage file backend not initialized")); + return -1; + } + + drv = src->drv; + + if (!drv->backend->storageFileRead) + return -2; + + ret = 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) +{ + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("storage file backend not initialized")); + return NULL; + } + + drv = src->drv; + + if (!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 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) +{ + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!drv->backend->storageFileAccess) { + errno = ENOSYS; + return -2; + } + + return 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) +{ + virStorageDriverDataPtr drv = NULL; + + if (!virStorageFileIsInitialized(src)) { + errno = ENOSYS; + return -2; + } + + drv = src->drv; + + if (!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 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) { + virStorageDriverDataPtr drv = src->drv; + unsigned int access_user = drv->uid; + unsigned int access_group = 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); + } + } +} + + +static int +virStorageFileGetMetadataRecurseReadHeader(virStorageSourcePtr src, + virStorageSourcePtr parent, + uid_t uid, + gid_t gid, + char **buf, + size_t *headerLen, + GHashTable *cycle) +{ + int ret = -1; + const char *uniqueName; + ssize_t len; + + 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 (virHashHasEntry(cycle, uniqueName)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("backing store for %s (%s) is self-referential"), + NULLSTR(src->path), uniqueName); + goto cleanup; + } + + if (virHashAddEntry(cycle, uniqueName, NULL) < 0) + goto cleanup; + + if ((len = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, buf)) < 0) + goto cleanup; + + *headerLen = len; + ret = 0; + + cleanup: + virStorageFileDeinit(src); + return ret; +} + + +/* Recursive workhorse for virStorageFileGetMetadata. */ +static int +virStorageFileGetMetadataRecurse(virStorageSourcePtr src, + virStorageSourcePtr parent, + uid_t uid, gid_t gid, + bool report_broken, + GHashTable *cycle, + unsigned int depth) +{ + virStorageFileFormat orig_format = src->format; + size_t headerLen; + int rv; + g_autofree char *buf = NULL; + g_autoptr(virStorageSource) backingStore = NULL; + + VIR_DEBUG("path=%s format=%d uid=%u gid=%u", + NULLSTR(src->path), src->format, + (unsigned int)uid, (unsigned int)gid); + + if (src->format == VIR_STORAGE_FILE_AUTO_SAFE) + src->format = VIR_STORAGE_FILE_AUTO; + + /* exit if we can't load information about the current image */ + rv = virStorageFileSupportsBackingChainTraversal(src); + if (rv <= 0) { + if (orig_format == VIR_STORAGE_FILE_AUTO) + return -2; + + return rv; + } + + if (virStorageFileGetMetadataRecurseReadHeader(src, parent, uid, gid, + &buf, &headerLen, cycle) < 0) + return -1; + + if (virStorageFileProbeGetMetadata(src, buf, headerLen) < 0) + return -1; + + /* If we probed the format we MUST ensure that nothing else than the current + * image is considered for security labelling and/or recursion. */ + if (orig_format == VIR_STORAGE_FILE_AUTO) { + if (src->backingStoreRaw) { + src->format = VIR_STORAGE_FILE_RAW; + VIR_FREE(src->backingStoreRaw); + return -2; + } + } + + if (src->backingStoreRaw) { + if ((rv = virStorageSourceNewFromBacking(src, &backingStore)) < 0) + return -1; + + /* the backing file would not be usable for VM usage */ + if (rv == 1) + return 0; + + if ((rv = virStorageFileGetMetadataRecurse(backingStore, parent, + uid, gid, + report_broken, + cycle, depth + 1)) < 0) { + if (!report_broken) + return 0; + + if (rv == -2) { + virReportError(VIR_ERR_OPERATION_INVALID, + _("format of backing image '%s' of image '%s' was not specified in the image metadata " + "(See https://libvirt.org/kbase/backing_chains.html for troubleshooting)"), + src->backingStoreRaw, NULLSTR(src->path)); + } + + return -1; + } + + backingStore->id = depth; + src->backingStore = g_steal_pointer(&backingStore); + } else { + /* add terminator */ + src->backingStore = virStorageSourceNew(); + } + + return 0; +} + + +/** + * 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. Note that the inability for + * libvirt to traverse a given source is not considered an error. + * + * Caller MUST free result after use via virObjectUnref. + */ +int +virStorageFileGetMetadata(virStorageSourcePtr src, + uid_t uid, gid_t gid, + bool report_broken) +{ + GHashTable *cycle = NULL; + virStorageType actualType = virStorageSourceGetActualType(src); + int ret = -1; + + VIR_DEBUG("path=%s format=%d uid=%u gid=%u report_broken=%d", + src->path, src->format, (unsigned int)uid, (unsigned int)gid, + report_broken); + + if (!(cycle = virHashNew(NULL))) + return -1; + + if (src->format <= VIR_STORAGE_FILE_NONE) { + if (actualType == VIR_STORAGE_TYPE_DIR) + src->format = VIR_STORAGE_FILE_DIR; + else + src->format = VIR_STORAGE_FILE_RAW; + } + + ret = virStorageFileGetMetadataRecurse(src, src, uid, gid, + 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. + */ +int +virStorageFileGetBackingStoreStr(virStorageSourcePtr src, + char **backing) +{ + ssize_t headerLen; + int rv; + g_autofree char *buf = NULL; + g_autoptr(virStorageSource) tmp = NULL; + + *backing = NULL; + + /* exit if we can't load information about the current image */ + if (!virStorageFileSupportsBackingChainTraversal(src)) + return 0; + + rv = virStorageFileAccess(src, F_OK); + if (rv == -2) + return 0; + if (rv < 0) { + virStorageFileReportBrokenChain(errno, src, src); + return -1; + } + + if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, + &buf)) < 0) { + if (headerLen == -2) + return 0; + return -1; + } + + if (!(tmp = virStorageSourceCopy(src, false))) + return -1; + + if (virStorageFileProbeGetMetadata(tmp, buf, headerLen) < 0) + return -1; + + *backing = g_steal_pointer(&tmp->backingStoreRaw); + return 0; +} diff --git a/src/storage_file/storage_source.h b/src/storage_file/storage_source.h new file mode 100644 index 0000000000..23f56417a8 --- /dev/null +++ b/src/storage_file/storage_source.h @@ -0,0 +1,148 @@ +/* + * storage_source.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include "virstoragefile.h" + +#ifndef DEV_BSIZE +# define DEV_BSIZE 512 +#endif + +virStorageSourcePtr +virStorageFileGetMetadataFromFD(const char *path, + int fd, + int format); + +virStorageSourcePtr +virStorageFileGetMetadataFromBuf(const char *path, + char *buf, + size_t len, + int format) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +virStorageSourcePtr +virStorageFileChainLookup(virStorageSourcePtr chain, + virStorageSourcePtr startFrom, + const char *name, + unsigned int idx, + virStorageSourcePtr *parent) + ATTRIBUTE_NONNULL(1); + +int +virStorageSourceUpdatePhysicalSize(virStorageSourcePtr src, + int fd, + struct stat const *sb); + +int +virStorageSourceUpdateBackingSizes(virStorageSourcePtr src, + int fd, + struct stat const *sb); + +int +virStorageSourceUpdateCapacity(virStorageSourcePtr src, + char *buf, + ssize_t len); + +int +virStorageSourceNewFromBacking(virStorageSourcePtr parent, + virStorageSourcePtr *backing); + +int +virStorageSourceParseRBDColonString(const char *rbdstr, + virStorageSourcePtr src) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int +virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, + virStorageSourcePtr base, + char **relpath) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +int +virStorageSourceNewFromBackingAbsolute(const char *path, + virStorageSourcePtr *src); + +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 *st); + +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); + +int +virStorageFileSupportsSecurityDriver(const virStorageSource *src); + +int +virStorageFileSupportsAccess(const virStorageSource *src); + +int +virStorageFileSupportsCreate(const virStorageSource *src); + +int +virStorageFileSupportsBackingChainTraversal(const virStorageSource *src); + +int +virStorageFileGetMetadata(virStorageSourcePtr src, + uid_t uid, gid_t gid, + bool report_broken) + ATTRIBUTE_NONNULL(1); + +int +virStorageFileGetBackingStoreStr(virStorageSourcePtr src, + char **backing) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +void +virStorageFileReportBrokenChain(int errcode, + virStorageSourcePtr src, + virStorageSourcePtr parent); diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 98a3222d09..c70d5713de 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -31,14 +31,9 @@ #include "vircommand.h" #include "virhash.h" #include "virstring.h" -#include "viruri.h" #include "virbuffer.h" -#include "virjson.h" #include "virstorageencryption.h" -#include "virstoragefilebackend.h" -#include "virstoragefileprobe.h" #include "virsecret.h" -#include "virutil.h" #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -146,126 +141,6 @@ virStorageIsRelative(const char *backing) } -static virStorageSourcePtr -virStorageFileMetadataNew(const char *path, - int format) -{ - g_autoptr(virStorageSource) def = virStorageSourceNew(); - - def->format = format; - def->type = VIR_STORAGE_TYPE_FILE; - - def->path = g_strdup(path); - - return g_steal_pointer(&def); -} - - -/** - * virStorageFileGetMetadataFromBuf: - * @path: name of file, for error messages - * @buf: header bytes from @path - * @len: length of @buf - * @format: format of the storage file - * - * 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. Does not recurse. - * - * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a format on a file - * that might be raw if that file will then be passed to a guest, since a - * malicious guest can turn a raw file into any other non-raw format at will. - * - * If the 'backingStoreRawFormat' field of the returned structure is - * VIR_STORAGE_FILE_AUTO it indicates the image didn't specify an explicit - * format for its backing store. Callers are advised against probing for the - * backing store format in this case. - * - * Caller MUST free the result after use via virObjectUnref. - */ -virStorageSourcePtr -virStorageFileGetMetadataFromBuf(const char *path, - char *buf, - size_t len, - int format) -{ - virStorageSourcePtr ret = NULL; - - if (!(ret = virStorageFileMetadataNew(path, format))) - return NULL; - - if (virStorageFileProbeGetMetadata(ret, buf, len) < 0) { - virObjectUnref(ret); - return NULL; - } - - return ret; -} - - -/** - * virStorageFileGetMetadataFromFD: - * - * 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. Does not recurse. - * - * 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. - * - * Caller MUST free the result after use via virObjectUnref. - */ -virStorageSourcePtr -virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format) - -{ - ssize_t len = VIR_STORAGE_MAX_HEADER; - struct stat sb; - g_autofree char *buf = NULL; - g_autoptr(virStorageSource) meta = NULL; - - if (fstat(fd, &sb) < 0) { - virReportSystemError(errno, - _("cannot stat file '%s'"), path); - return NULL; - } - - if (!(meta = virStorageFileMetadataNew(path, format))) - return NULL; - - if (S_ISDIR(sb.st_mode)) { - /* No header to probe for directories, but also no backing file. Just - * update the metadata.*/ - meta->type = VIR_STORAGE_TYPE_DIR; - meta->format = VIR_STORAGE_FILE_DIR; - return g_steal_pointer(&meta); - } - - if (lseek(fd, 0, SEEK_SET) == (off_t)-1) { - virReportSystemError(errno, _("cannot seek to start of '%s'"), meta->path); - return NULL; - } - - if ((len = virFileReadHeaderFD(fd, len, &buf)) < 0) { - virReportSystemError(errno, _("cannot read header '%s'"), meta->path); - return NULL; - } - - if (virStorageFileProbeGetMetadata(meta, buf, len) < 0) - return NULL; - - if (S_ISREG(sb.st_mode)) - meta->type = VIR_STORAGE_TYPE_FILE; - else if (S_ISBLK(sb.st_mode)) - meta->type = VIR_STORAGE_TYPE_BLOCK; - - return g_steal_pointer(&meta); -} - - #ifdef WITH_UDEV /* virStorageFileGetSCSIKey * @path: Path to the SCSI device @@ -503,107 +378,6 @@ virStorageSourceHasBacking(const virStorageSource *src) } -/* Given a @chain, look for the backing store @name that is a backing file - * of @startFrom (or any member of @chain if @startFrom is NULL) and return - * that location within the chain. @chain must always point to the top of - * the chain. Pass NULL for @name and 0 for @idx to find the base of the - * chain. Pass nonzero @idx to find the backing source according to its - * position in the backing chain. If @parent is not NULL, set *@parent to - * the preferred name of the parent (or to NULL if @name matches the start - * of the chain). Since the results point within @chain, they must not be - * independently freed. Reports an error and returns NULL if @name is not - * found. - */ -virStorageSourcePtr -virStorageFileChainLookup(virStorageSourcePtr chain, - virStorageSourcePtr startFrom, - const char *name, - unsigned int idx, - virStorageSourcePtr *parent) -{ - virStorageSourcePtr prev; - const char *start = chain->path; - bool nameIsFile = virStorageIsFile(name); - - if (!parent) - parent = &prev; - *parent = NULL; - - if (startFrom) { - while (virStorageSourceIsBacking(chain) && - chain != startFrom->backingStore) - chain = chain->backingStore; - - *parent = startFrom; - } - - while (virStorageSourceIsBacking(chain)) { - if (!name && !idx) { - if (!virStorageSourceHasBacking(chain)) - break; - } else if (idx) { - VIR_DEBUG("%u: %s", chain->id, chain->path); - if (idx == chain->id) - break; - } else { - if (STREQ_NULLABLE(name, chain->relPath) || - STREQ_NULLABLE(name, chain->path)) - break; - - if (nameIsFile && virStorageSourceIsLocalStorage(chain)) { - g_autofree char *parentDir = NULL; - int result; - - if (*parent && virStorageSourceIsLocalStorage(*parent)) - parentDir = g_path_get_dirname((*parent)->path); - else - parentDir = g_strdup("."); - - result = virFileRelLinkPointsTo(parentDir, name, - chain->path); - - if (result < 0) - goto error; - - if (result > 0) - break; - } - } - *parent = chain; - chain = chain->backingStore; - } - - if (!virStorageSourceIsBacking(chain)) - goto error; - - return chain; - - error: - if (idx) { - virReportError(VIR_ERR_INVALID_ARG, - _("could not find backing store index %u in chain " - "for '%s'"), - idx, NULLSTR(start)); - } else if (name) { - if (startFrom) - virReportError(VIR_ERR_INVALID_ARG, - _("could not find image '%s' beneath '%s' in " - "chain for '%s'"), name, NULLSTR(startFrom->path), - NULLSTR(start)); - else - virReportError(VIR_ERR_INVALID_ARG, - _("could not find image '%s' in chain for '%s'"), - name, NULLSTR(start)); - } else { - virReportError(VIR_ERR_INVALID_ARG, - _("could not find base image in chain for '%s'"), - NULLSTR(start)); - } - *parent = NULL; - return NULL; -} - - void virStorageNetHostDefClear(virStorageNetHostDefPtr def) { @@ -1660,1550 +1434,6 @@ virStorageSourceNew(void) } -static virStorageSourcePtr -virStorageSourceNewFromBackingRelative(virStorageSourcePtr parent, - const char *rel) -{ - g_autofree char *dirname = NULL; - g_autoptr(virStorageSource) def = virStorageSourceNew(); - - /* store relative name */ - def->relPath = g_strdup(rel); - - dirname = g_path_get_dirname(parent->path); - - if (STRNEQ(dirname, "/")) { - def->path = g_strdup_printf("%s/%s", dirname, rel); - } else { - def->path = g_strdup_printf("/%s", rel); - } - - if (virStorageSourceGetActualType(parent) == VIR_STORAGE_TYPE_NETWORK) { - def->type = VIR_STORAGE_TYPE_NETWORK; - - /* copy the host network part */ - def->protocol = parent->protocol; - if (parent->nhosts) { - if (!(def->hosts = virStorageNetHostDefCopy(parent->nhosts, - parent->hosts))) - return NULL; - - def->nhosts = parent->nhosts; - } - - def->volume = g_strdup(parent->volume); - } else { - /* set the type to _FILE, the caller shall update it to the actual type */ - def->type = VIR_STORAGE_TYPE_FILE; - } - - return g_steal_pointer(&def); -} - - -static int -virStorageSourceParseBackingURI(virStorageSourcePtr src, - const char *uristr) -{ - g_autoptr(virURI) uri = NULL; - const char *path = NULL; - g_auto(GStrv) scheme = NULL; - - if (!(uri = virURIParse(uristr))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("failed to parse backing file location '%s'"), - uristr); - return -1; - } - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (!(scheme = virStringSplit(uri->scheme, "+", 2))) - return -1; - - if (!scheme[0] || - (src->protocol = virStorageNetProtocolTypeFromString(scheme[0])) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid backing protocol '%s'"), - NULLSTR(scheme[0])); - return -1; - } - - if (scheme[1] && - (src->hosts->transport = virStorageNetHostTransportTypeFromString(scheme[1])) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid protocol transport type '%s'"), - scheme[1]); - return -1; - } - - if (uri->query) { - if (src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTP || - src->protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS) { - src->query = g_strdup(uri->query); - } else { - /* handle socket stored as a query */ - if (STRPREFIX(uri->query, "socket=")) - src->hosts->socket = g_strdup(STRSKIP(uri->query, "socket=")); - } - } - - /* uri->path is NULL if the URI does not contain slash after host: - * transport://host:port */ - if (uri->path) - path = uri->path; - else - path = ""; - - /* possibly skip the leading slash */ - if (path[0] == '/') - path++; - - /* NBD allows empty export name (path) */ - if (src->protocol == VIR_STORAGE_NET_PROTOCOL_NBD && - path[0] == '\0') - path = NULL; - - src->path = g_strdup(path); - - if (src->protocol == VIR_STORAGE_NET_PROTOCOL_GLUSTER) { - char *tmp; - - if (!src->path) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", - _("missing volume name and path for gluster volume")); - return -1; - } - - if (!(tmp = strchr(src->path, '/')) || - tmp == src->path) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("missing volume name or file name in " - "gluster source path '%s'"), src->path); - return -1; - } - - src->volume = src->path; - - src->path = g_strdup(tmp + 1); - - tmp[0] = '\0'; - } - - src->hosts->port = uri->port; - - src->hosts->name = g_strdup(uri->server); - - /* Libvirt doesn't handle inline authentication. Make the caller aware. */ - if (uri->user) - return 1; - - return 0; -} - - -static int -virStorageSourceRBDAddHost(virStorageSourcePtr src, - char *hostport) -{ - char *port; - size_t skip; - g_auto(GStrv) parts = NULL; - - if (VIR_EXPAND_N(src->hosts, src->nhosts, 1) < 0) - return -1; - - if ((port = strchr(hostport, ']'))) { - /* ipv6, strip brackets */ - hostport += 1; - skip = 3; - } else { - port = strstr(hostport, "\\:"); - skip = 2; - } - - if (port) { - *port = '\0'; - port += skip; - if (virStringParsePort(port, &src->hosts[src->nhosts - 1].port) < 0) - goto error; - } - - parts = virStringSplit(hostport, "\\:", 0); - if (!parts) - goto error; - src->hosts[src->nhosts-1].name = virStringListJoin((const char **)parts, ":"); - if (!src->hosts[src->nhosts-1].name) - goto error; - - src->hosts[src->nhosts-1].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - src->hosts[src->nhosts-1].socket = NULL; - - return 0; - - error: - VIR_FREE(src->hosts[src->nhosts-1].name); - return -1; -} - - -int -virStorageSourceParseRBDColonString(const char *rbdstr, - virStorageSourcePtr src) -{ - char *p, *e, *next; - g_autofree char *options = NULL; - g_autoptr(virStorageAuthDef) authdef = NULL; - - /* optionally skip the "rbd:" prefix if provided */ - if (STRPREFIX(rbdstr, "rbd:")) - rbdstr += strlen("rbd:"); - - src->path = g_strdup(rbdstr); - - p = strchr(src->path, ':'); - if (p) { - options = g_strdup(p + 1); - *p = '\0'; - } - - /* snapshot name */ - if ((p = strchr(src->path, '@'))) { - src->snapshot = g_strdup(p + 1); - *p = '\0'; - } - - /* pool vs. image name */ - if ((p = strchr(src->path, '/'))) { - src->volume = g_steal_pointer(&src->path); - src->path = g_strdup(p + 1); - *p = '\0'; - } - - /* options */ - if (!options) - return 0; /* all done */ - - p = options; - while (*p) { - /* find : delimiter or end of string */ - for (e = p; *e && *e != ':'; ++e) { - if (*e == '\\') { - e++; - if (*e == '\0') - break; - } - } - if (*e == '\0') { - next = e; /* last kv pair */ - } else { - next = e + 1; - *e = '\0'; - } - - if (STRPREFIX(p, "id=")) { - /* formulate authdef for src->auth */ - if (src->auth) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("duplicate 'id' found in '%s'"), src->path); - return -1; - } - - authdef = g_new0(virStorageAuthDef, 1); - - authdef->username = g_strdup(p + strlen("id=")); - - authdef->secrettype = g_strdup(virSecretUsageTypeToString(VIR_SECRET_USAGE_TYPE_CEPH)); - src->auth = g_steal_pointer(&authdef); - - /* Cannot formulate a secretType (eg, usage or uuid) given - * what is provided. - */ - } - if (STRPREFIX(p, "mon_host=")) { - char *h, *sep; - - h = p + strlen("mon_host="); - while (h < e) { - for (sep = h; sep < e; ++sep) { - if (*sep == '\\' && (sep[1] == ',' || - sep[1] == ';' || - sep[1] == ' ')) { - *sep = '\0'; - sep += 2; - break; - } - } - - if (virStorageSourceRBDAddHost(src, h) < 0) - return -1; - - h = sep; - } - } - - if (STRPREFIX(p, "conf=")) - src->configFile = g_strdup(p + strlen("conf=")); - - p = next; - } - return 0; -} - - -static int -virStorageSourceParseNBDColonString(const char *nbdstr, - virStorageSourcePtr src) -{ - g_autofree char *nbd = g_strdup(nbdstr); - char *export_name; - char *host_spec; - char *unixpath; - char *port; - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - /* We extract the parameters in a similar way qemu does it */ - - /* format: [] denotes optional sections, uppercase are variable strings - * nbd:unix:/PATH/TO/SOCKET[:exportname=EXPORTNAME] - * nbd:HOSTNAME:PORT[:exportname=EXPORTNAME] - */ - - /* first look for ':exportname=' and cut it off */ - if ((export_name = strstr(nbd, ":exportname="))) { - src->path = g_strdup(export_name + strlen(":exportname=")); - export_name[0] = '\0'; - } - - /* Verify the prefix and contents. Note that we require a - * "host_spec" part to be present. */ - if (!(host_spec = STRSKIP(nbd, "nbd:")) || host_spec[0] == '\0') - goto malformed; - - if ((unixpath = STRSKIP(host_spec, "unix:"))) { - src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; - - if (unixpath[0] == '\0') - goto malformed; - - src->hosts->socket = g_strdup(unixpath); - } else { - src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - - if (host_spec[0] == ':') { - /* no host given */ - goto malformed; - } else if (host_spec[0] == '[') { - host_spec++; - /* IPv6 addr */ - if (!(port = strstr(host_spec, "]:"))) - goto malformed; - - port[0] = '\0'; - port += 2; - - if (host_spec[0] == '\0') - goto malformed; - } else { - if (!(port = strchr(host_spec, ':'))) - goto malformed; - - port[0] = '\0'; - port++; - } - - if (virStringParsePort(port, &src->hosts->port) < 0) - return -1; - - src->hosts->name = g_strdup(host_spec); - } - - return 0; - - malformed: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("malformed nbd string '%s'"), nbdstr); - return -1; -} - - -static int -virStorageSourceParseBackingColon(virStorageSourcePtr src, - const char *path) -{ - const char *p; - g_autofree char *protocol = NULL; - - if (!(p = strchr(path, ':'))) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid backing protocol string '%s'"), - path); - return -1; - } - - protocol = g_strndup(path, p - path); - - if ((src->protocol = virStorageNetProtocolTypeFromString(protocol)) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("invalid backing protocol '%s'"), - protocol); - return -1; - } - - switch ((virStorageNetProtocol) src->protocol) { - case VIR_STORAGE_NET_PROTOCOL_NBD: - if (virStorageSourceParseNBDColonString(path, src) < 0) - return -1; - break; - - case VIR_STORAGE_NET_PROTOCOL_RBD: - if (virStorageSourceParseRBDColonString(path, src) < 0) - return -1; - break; - - case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: - case VIR_STORAGE_NET_PROTOCOL_LAST: - case VIR_STORAGE_NET_PROTOCOL_NONE: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("backing store parser is not implemented for protocol %s"), - protocol); - return -1; - - case VIR_STORAGE_NET_PROTOCOL_HTTP: - case VIR_STORAGE_NET_PROTOCOL_HTTPS: - case VIR_STORAGE_NET_PROTOCOL_FTP: - case VIR_STORAGE_NET_PROTOCOL_FTPS: - case VIR_STORAGE_NET_PROTOCOL_TFTP: - case VIR_STORAGE_NET_PROTOCOL_ISCSI: - case VIR_STORAGE_NET_PROTOCOL_GLUSTER: - case VIR_STORAGE_NET_PROTOCOL_SSH: - case VIR_STORAGE_NET_PROTOCOL_VXHS: - case VIR_STORAGE_NET_PROTOCOL_NFS: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("malformed backing store path for protocol %s"), - protocol); - return -1; - } - - return 0; -} - - -static int -virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr, - bool allowformat); - - -static int -virStorageSourceParseBackingJSONPath(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int type) -{ - const char *path; - - if (!(path = virJSONValueObjectGetString(json, "filename"))) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'filename' field in JSON backing volume " - "definition")); - return -1; - } - - src->path = g_strdup(path); - - src->type = type; - return 0; -} - - -static int -virStorageSourceParseBackingJSONUriStr(virStorageSourcePtr src, - const char *uri, - int protocol) -{ - int rc; - - if ((rc = virStorageSourceParseBackingURI(src, uri)) < 0) - return -1; - - if (src->protocol != protocol) { - virReportError(VIR_ERR_INVALID_ARG, - _("expected protocol '%s' but got '%s' in URI JSON volume " - "definition"), - virStorageNetProtocolTypeToString(protocol), - virStorageNetProtocolTypeToString(src->protocol)); - return -1; - } - - return rc; -} - - -static int -virStorageSourceParseBackingJSONUriCookies(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr) -{ - const char *cookiestr; - g_auto(GStrv) cookies = NULL; - size_t ncookies = 0; - size_t i; - - if (!virJSONValueObjectHasKey(json, "cookie")) - return 0; - - if (!(cookiestr = virJSONValueObjectGetString(json, "cookie"))) { - virReportError(VIR_ERR_INVALID_ARG, - _("wrong format of 'cookie' field in backing store definition '%s'"), - jsonstr); - return -1; - } - - if (!(cookies = virStringSplitCount(cookiestr, ";", 0, &ncookies))) - return -1; - - src->cookies = g_new0(virStorageNetCookieDefPtr, ncookies); - src->ncookies = ncookies; - - for (i = 0; i < ncookies; i++) { - char *cookiename = cookies[i]; - char *cookievalue; - - virSkipSpaces((const char **) &cookiename); - - if (!(cookievalue = strchr(cookiename, '='))) { - virReportError(VIR_ERR_INVALID_ARG, - _("malformed http cookie '%s' in backing store definition '%s'"), - cookies[i], jsonstr); - return -1; - } - - *cookievalue = '\0'; - cookievalue++; - - src->cookies[i] = g_new0(virStorageNetCookieDef, 1); - src->cookies[i]->name = g_strdup(cookiename); - src->cookies[i]->value = g_strdup(cookievalue); - } - - return 0; -} - - -static int -virStorageSourceParseBackingJSONUri(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr, - int protocol) -{ - const char *uri; - - if (!(uri = virJSONValueObjectGetString(json, "url"))) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'url' in JSON backing volume definition")); - return -1; - } - - if (protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS || - protocol == VIR_STORAGE_NET_PROTOCOL_FTPS) { - if (virJSONValueObjectHasKey(json, "sslverify")) { - const char *tmpstr; - bool tmp; - - /* libguestfs still uses undocumented legacy value of 'off' */ - if ((tmpstr = virJSONValueObjectGetString(json, "sslverify")) && - STREQ(tmpstr, "off")) { - src->sslverify = VIR_TRISTATE_BOOL_NO; - } else { - if (virJSONValueObjectGetBoolean(json, "sslverify", &tmp) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("malformed 'sslverify' field in backing store definition '%s'"), - jsonstr); - return -1; - } - - src->sslverify = virTristateBoolFromBool(tmp); - } - } - } - - if (protocol == VIR_STORAGE_NET_PROTOCOL_HTTPS || - protocol == VIR_STORAGE_NET_PROTOCOL_HTTP) { - if (virStorageSourceParseBackingJSONUriCookies(src, json, jsonstr) < 0) - return -1; - } - - if (virJSONValueObjectHasKey(json, "readahead") && - virJSONValueObjectGetNumberUlong(json, "readahead", &src->readahead) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("malformed 'readahead' field in backing store definition '%s'"), - jsonstr); - return -1; - } - - if (virJSONValueObjectHasKey(json, "timeout") && - virJSONValueObjectGetNumberUlong(json, "timeout", &src->timeout) < 0) { - virReportError(VIR_ERR_INVALID_ARG, - _("malformed 'timeout' field in backing store definition '%s'"), - jsonstr); - return -1; - } - - return virStorageSourceParseBackingJSONUriStr(src, uri, protocol); -} - - -static int -virStorageSourceParseBackingJSONInetSocketAddress(virStorageNetHostDefPtr host, - virJSONValuePtr json) -{ - const char *hostname; - const char *port; - - if (!json) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing remote server specification in JSON " - "backing volume definition")); - return -1; - } - - hostname = virJSONValueObjectGetString(json, "host"); - port = virJSONValueObjectGetString(json, "port"); - - if (!hostname) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing hostname for tcp backing server in " - "JSON backing volume definition")); - return -1; - } - - host->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - host->name = g_strdup(hostname); - - if (virStringParsePort(port, &host->port) < 0) - return -1; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONSocketAddress(virStorageNetHostDefPtr host, - virJSONValuePtr json) -{ - const char *type; - const char *socket; - - if (!json) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing remote server specification in JSON " - "backing volume definition")); - return -1; - } - - if (!(type = virJSONValueObjectGetString(json, "type"))) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing socket address type in " - "JSON backing volume definition")); - return -1; - } - - if (STREQ(type, "tcp") || STREQ(type, "inet")) { - return virStorageSourceParseBackingJSONInetSocketAddress(host, json); - - } else if (STREQ(type, "unix")) { - host->transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; - - socket = virJSONValueObjectGetString(json, "path"); - - /* check for old spelling for gluster protocol */ - if (!socket) - socket = virJSONValueObjectGetString(json, "socket"); - - if (!socket) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing socket path for udp backing server in " - "JSON backing volume definition")); - return -1; - } - - host->socket = g_strdup(socket); - } else { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("backing store protocol '%s' is not yet supported"), - type); - return -1; - } - - return 0; -} - - -static int -virStorageSourceParseBackingJSONGluster(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *uri = virJSONValueObjectGetString(json, "filename"); - const char *volume = virJSONValueObjectGetString(json, "volume"); - const char *path = virJSONValueObjectGetString(json, "path"); - virJSONValuePtr server = virJSONValueObjectGetArray(json, "server"); - size_t nservers; - size_t i; - - /* legacy URI based syntax passed via 'filename' option */ - if (uri) - return virStorageSourceParseBackingJSONUriStr(src, uri, - VIR_STORAGE_NET_PROTOCOL_GLUSTER); - - if (!volume || !path || !server) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'volume', 'path' or 'server' attribute in " - "JSON backing definition for gluster volume")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_GLUSTER; - - src->volume = g_strdup(volume); - src->path = g_strdup(path); - - nservers = virJSONValueArraySize(server); - if (nservers == 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("at least 1 server is necessary in " - "JSON backing definition for gluster volume")); - - return -1; - } - - src->hosts = g_new0(virStorageNetHostDef, nservers); - src->nhosts = nservers; - - for (i = 0; i < nservers; i++) { - if (virStorageSourceParseBackingJSONSocketAddress(src->hosts + i, - virJSONValueArrayGet(server, i)) < 0) - return -1; - } - - return 0; -} - - -static int -virStorageSourceParseBackingJSONiSCSI(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *transport = virJSONValueObjectGetString(json, "transport"); - const char *portal = virJSONValueObjectGetString(json, "portal"); - const char *target = virJSONValueObjectGetString(json, "target"); - const char *lun = virJSONValueObjectGetStringOrNumber(json, "lun"); - const char *uri; - char *port; - - /* legacy URI based syntax passed via 'filename' option */ - if ((uri = virJSONValueObjectGetString(json, "filename"))) - return virStorageSourceParseBackingJSONUriStr(src, uri, - VIR_STORAGE_NET_PROTOCOL_ISCSI); - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_ISCSI; - - if (!lun) - lun = "0"; - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (STRNEQ_NULLABLE(transport, "tcp")) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("only TCP transport is supported for iSCSI volumes")); - return -1; - } - - src->hosts->transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - - if (!portal) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'portal' address in iSCSI backing definition")); - return -1; - } - - if (!target) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'target' in iSCSI backing definition")); - return -1; - } - - src->hosts->name = g_strdup(portal); - - if ((port = strrchr(src->hosts->name, ':')) && - !strchr(port, ']')) { - if (virStringParsePort(port + 1, &src->hosts->port) < 0) - return -1; - - *port = '\0'; - } - - src->path = g_strdup_printf("%s/%s", target, lun); - - /* Libvirt doesn't handle inline authentication. Make the caller aware. */ - if (virJSONValueObjectGetString(json, "user") || - virJSONValueObjectGetString(json, "password")) - return 1; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONNbd(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *path = virJSONValueObjectGetString(json, "path"); - const char *host = virJSONValueObjectGetString(json, "host"); - const char *port = virJSONValueObjectGetString(json, "port"); - const char *export = virJSONValueObjectGetString(json, "export"); - virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); - - if (!path && !host && !server) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing host specification of NBD server in JSON " - "backing volume definition")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_NBD; - - src->path = g_strdup(export); - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (server) { - if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0) - return -1; - } else { - if (path) { - src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_UNIX; - src->hosts[0].socket = g_strdup(path); - } else { - src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - src->hosts[0].name = g_strdup(host); - - if (virStringParsePort(port, &src->hosts[0].port) < 0) - return -1; - } - } - - return 0; -} - - -static int -virStorageSourceParseBackingJSONSheepdog(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *filename; - const char *vdi = virJSONValueObjectGetString(json, "vdi"); - virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); - - /* legacy URI based syntax passed via 'filename' option */ - if ((filename = virJSONValueObjectGetString(json, "filename"))) { - if (strstr(filename, "://")) - return virStorageSourceParseBackingJSONUriStr(src, filename, - VIR_STORAGE_NET_PROTOCOL_SHEEPDOG); - - /* libvirt doesn't implement a parser for the legacy non-URI syntax */ - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing sheepdog URI in JSON backing volume definition")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_SHEEPDOG; - - if (!vdi) { - virReportError(VIR_ERR_INVALID_ARG, "%s", _("missing sheepdog vdi name")); - return -1; - } - - src->path = g_strdup(vdi); - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (virStorageSourceParseBackingJSONSocketAddress(src->hosts, server) < 0) - return -1; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONSSH(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *path = virJSONValueObjectGetString(json, "path"); - const char *host = virJSONValueObjectGetString(json, "host"); - const char *port = virJSONValueObjectGetString(json, "port"); - const char *user = virJSONValueObjectGetString(json, "user"); - const char *host_key_check = virJSONValueObjectGetString(json, "host_key_check"); - virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); - - if (!(host || server) || !path) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing host/server or path of SSH JSON backing " - "volume definition")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_SSH; - - src->path = g_strdup(path); - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (server) { - if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, - server) < 0) - return -1; - } else { - src->hosts[0].transport = VIR_STORAGE_NET_HOST_TRANS_TCP; - src->hosts[0].name = g_strdup(host); - - if (virStringParsePort(port, &src->hosts[0].port) < 0) - return -1; - } - - /* these two are parsed just to be passed back as we don't model them yet */ - src->ssh_user = g_strdup(user); - if (STREQ_NULLABLE(host_key_check, "no")) - src->ssh_host_key_check_disabled = true; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONRBD(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *filename; - const char *pool = virJSONValueObjectGetString(json, "pool"); - const char *image = virJSONValueObjectGetString(json, "image"); - const char *conf = virJSONValueObjectGetString(json, "conf"); - const char *snapshot = virJSONValueObjectGetString(json, "snapshot"); - virJSONValuePtr servers = virJSONValueObjectGetArray(json, "server"); - size_t nservers; - size_t i; - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_RBD; - - /* legacy syntax passed via 'filename' option */ - if ((filename = virJSONValueObjectGetString(json, "filename"))) - return virStorageSourceParseRBDColonString(filename, src); - - if (!pool || !image) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing pool or image name in ceph backing volume " - "JSON specification")); - return -1; - } - - src->volume = g_strdup(pool); - src->path = g_strdup(image); - src->snapshot = g_strdup(snapshot); - src->configFile = g_strdup(conf); - - if (servers) { - nservers = virJSONValueArraySize(servers); - - src->hosts = g_new0(virStorageNetHostDef, nservers); - src->nhosts = nservers; - - for (i = 0; i < nservers; i++) { - if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts + i, - virJSONValueArrayGet(servers, i)) < 0) - return -1; - } - } - - return 0; -} - -static int -virStorageSourceParseBackingJSONRaw(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr, - int opaque G_GNUC_UNUSED) -{ - bool has_offset = virJSONValueObjectHasKey(json, "offset"); - bool has_size = virJSONValueObjectHasKey(json, "size"); - virJSONValuePtr file; - - if (has_offset || has_size) { - src->sliceStorage = g_new0(virStorageSourceSlice, 1); - - if (has_offset && - virJSONValueObjectGetNumberUlong(json, "offset", &src->sliceStorage->offset) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("malformed 'offset' property of 'raw' driver")); - return -1; - } - - if (has_size && - virJSONValueObjectGetNumberUlong(json, "size", &src->sliceStorage->size) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("malformed 'size' property of 'raw' driver")); - return -1; - } - } - - /* 'raw' is a format driver so it can have protocol driver children */ - if (!(file = virJSONValueObjectGetObject(json, "file"))) { - virReportError(VIR_ERR_INVALID_ARG, - _("JSON backing volume definition '%s' lacks 'file' object"), - jsonstr); - return -1; - } - - return virStorageSourceParseBackingJSONInternal(src, file, jsonstr, false); -} - - -static int -virStorageSourceParseBackingJSONVxHS(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - const char *vdisk_id = virJSONValueObjectGetString(json, "vdisk-id"); - virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); - - if (!vdisk_id || !server) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'vdisk-id' or 'server' attribute in " - "JSON backing definition for VxHS volume")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_VXHS; - - src->path = g_strdup(vdisk_id); - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, - server) < 0) - return -1; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONNFS(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - virJSONValuePtr server = virJSONValueObjectGetObject(json, "server"); - int uidStore = -1; - int gidStore = -1; - int gotUID = virJSONValueObjectGetNumberInt(json, "user", &uidStore); - int gotGID = virJSONValueObjectGetNumberInt(json, "group", &gidStore); - - if (!server) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'server' attribute in JSON backing definition for NFS volume")); - return -1; - } - - if (gotUID < 0 || gotGID < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'user' or 'group' attribute in JSON backing definition for NFS volume")); - return -1; - } - - src->path = g_strdup(virJSONValueObjectGetString(json, "path")); - if (!src->path) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing 'path' attribute in JSON backing definition for NFS volume")); - return -1; - } - - src->nfs_user = g_strdup_printf("+%d", uidStore); - src->nfs_group = g_strdup_printf("+%d", gidStore); - - src->type = VIR_STORAGE_TYPE_NETWORK; - src->protocol = VIR_STORAGE_NET_PROTOCOL_NFS; - - src->hosts = g_new0(virStorageNetHostDef, 1); - src->nhosts = 1; - - if (virStorageSourceParseBackingJSONInetSocketAddress(src->hosts, - server) < 0) - return -1; - - return 0; -} - - -static int -virStorageSourceParseBackingJSONNVMe(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr G_GNUC_UNUSED, - int opaque G_GNUC_UNUSED) -{ - g_autoptr(virStorageSourceNVMeDef) nvme = g_new0(virStorageSourceNVMeDef, 1); - const char *device = virJSONValueObjectGetString(json, "device"); - - if (!device || virPCIDeviceAddressParse((char *) device, &nvme->pciAddr) < 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing or malformed 'device' field of 'nvme' storage")); - return -1; - } - - if (virJSONValueObjectGetNumberUlong(json, "namespace", &nvme->namespc) < 0 || - nvme->namespc == 0) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("missing or malformed 'namespace' field of 'nvme' storage")); - return -1; - } - - src->type = VIR_STORAGE_TYPE_NVME; - src->nvme = g_steal_pointer(&nvme); - - return 0; -} - - -struct virStorageSourceJSONDriverParser { - const char *drvname; - bool formatdriver; - /** - * The callback gets a pre-allocated storage source @src and the JSON - * object to parse. The callback shall return -1 on error and report error - * 0 on success and 1 in cases when the configuration itself is valid, but - * can't be converted to libvirt's configuration (e.g. inline authentication - * credentials are present). - */ - int (*func)(virStorageSourcePtr src, virJSONValuePtr json, const char *jsonstr, int opaque); - int opaque; -}; - -static const struct virStorageSourceJSONDriverParser jsonParsers[] = { - {"file", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_FILE}, - {"host_device", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK}, - {"host_cdrom", false, virStorageSourceParseBackingJSONPath, VIR_STORAGE_TYPE_BLOCK}, - {"http", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTP}, - {"https", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_HTTPS}, - {"ftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTP}, - {"ftps", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_FTPS}, - {"tftp", false, virStorageSourceParseBackingJSONUri, VIR_STORAGE_NET_PROTOCOL_TFTP}, - {"gluster", false, virStorageSourceParseBackingJSONGluster, 0}, - {"iscsi", false, virStorageSourceParseBackingJSONiSCSI, 0}, - {"nbd", false, virStorageSourceParseBackingJSONNbd, 0}, - {"sheepdog", false, virStorageSourceParseBackingJSONSheepdog, 0}, - {"ssh", false, virStorageSourceParseBackingJSONSSH, 0}, - {"rbd", false, virStorageSourceParseBackingJSONRBD, 0}, - {"raw", true, virStorageSourceParseBackingJSONRaw, 0}, - {"nfs", false, virStorageSourceParseBackingJSONNFS, 0}, - {"vxhs", false, virStorageSourceParseBackingJSONVxHS, 0}, - {"nvme", false, virStorageSourceParseBackingJSONNVMe, 0}, -}; - - - -static int -virStorageSourceParseBackingJSONInternal(virStorageSourcePtr src, - virJSONValuePtr json, - const char *jsonstr, - bool allowformat) -{ - const char *drvname; - size_t i; - - if (!(drvname = virJSONValueObjectGetString(json, "driver"))) { - virReportError(VIR_ERR_INVALID_ARG, - _("JSON backing volume definition '%s' lacks driver name"), - jsonstr); - return -1; - } - - for (i = 0; i < G_N_ELEMENTS(jsonParsers); i++) { - if (STRNEQ(drvname, jsonParsers[i].drvname)) - continue; - - if (jsonParsers[i].formatdriver && !allowformat) { - virReportError(VIR_ERR_INVALID_ARG, - _("JSON backing volume definition '%s' must not have nested format drivers"), - jsonstr); - return -1; - } - - return jsonParsers[i].func(src, json, jsonstr, jsonParsers[i].opaque); - } - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("missing parser implementation for JSON backing volume " - "driver '%s'"), drvname); - return -1; -} - - -static int -virStorageSourceParseBackingJSON(virStorageSourcePtr src, - const char *json) -{ - g_autoptr(virJSONValue) root = NULL; - g_autoptr(virJSONValue) deflattened = NULL; - virJSONValuePtr file = NULL; - - if (!(root = virJSONValueFromString(json))) - return -1; - - if (!(deflattened = virJSONValueObjectDeflatten(root))) - return -1; - - /* There are 2 possible syntaxes: - * 1) json:{"file":{"driver":...}} - * 2) json:{"driver":...} - * Remove the 'file' wrapper object in case 1. - */ - if (!virJSONValueObjectHasKey(deflattened, "driver")) - file = virJSONValueObjectGetObject(deflattened, "file"); - - if (!file) - file = deflattened; - - return virStorageSourceParseBackingJSONInternal(src, file, json, true); -} - - -/** - * virStorageSourceNewFromBackingAbsolute - * @path: string representing absolute location of a storage source - * @src: filled with virStorageSource object representing @path - * - * Returns 0 on success, 1 if we could parse all location data but @path - * specified other data unrepresentable by libvirt (e.g. inline authentication). - * In both cases @src is filled. On error -1 is returned @src is NULL and an - * error is reported. - */ -int -virStorageSourceNewFromBackingAbsolute(const char *path, - virStorageSourcePtr *src) -{ - const char *json; - const char *dirpath; - int rc = 0; - g_autoptr(virStorageSource) def = virStorageSourceNew(); - - *src = NULL; - - if (virStorageIsFile(path)) { - def->type = VIR_STORAGE_TYPE_FILE; - - def->path = g_strdup(path); - } else { - if ((dirpath = STRSKIP(path, "fat:"))) { - def->type = VIR_STORAGE_TYPE_DIR; - def->format = VIR_STORAGE_FILE_FAT; - def->path = g_strdup(dirpath); - *src = g_steal_pointer(&def); - return 0; - } - - def->type = VIR_STORAGE_TYPE_NETWORK; - - VIR_DEBUG("parsing backing store string: '%s'", path); - - /* handle URI formatted backing stores */ - if ((json = STRSKIP(path, "json:"))) - rc = virStorageSourceParseBackingJSON(def, json); - else if (strstr(path, "://")) - rc = virStorageSourceParseBackingURI(def, path); - else - rc = virStorageSourceParseBackingColon(def, path); - - if (rc < 0) - return -1; - - virStorageSourceNetworkAssignDefaultPorts(def); - - /* Some of the legacy parsers parse authentication data since they are - * also used in other places. For backing store detection the - * authentication data would be invalid anyways, so we clear it */ - if (def->auth) { - virStorageAuthDefFree(def->auth); - def->auth = NULL; - } - } - - *src = g_steal_pointer(&def); - return rc; -} - - -/** - * virStorageSourceNewFromChild: - * @parent: storage source parent - * @child: returned child/backing store definition - * @parentRaw: raw child string (backingStoreRaw) - * - * Creates a storage source which describes the backing image of @parent and - * fills it into @backing depending on the passed parentRaw (backingStoreRaw) - * and other data. Note that for local storage this function accesses the file - * to update the actual type of the child store. - * - * Returns 0 on success, 1 if we could parse all location data but the child - * store specification contained other data unrepresentable by libvirt (e.g. - * inline authentication). - * In both cases @src is filled. On error -1 is returned @src is NULL and an - * error is reported. - */ -static int -virStorageSourceNewFromChild(virStorageSourcePtr parent, - const char *parentRaw, - virStorageSourcePtr *child) -{ - struct stat st; - g_autoptr(virStorageSource) def = NULL; - int rc = 0; - - *child = NULL; - - if (virStorageIsRelative(parentRaw)) { - if (!(def = virStorageSourceNewFromBackingRelative(parent, parentRaw))) - return -1; - } else { - if ((rc = virStorageSourceNewFromBackingAbsolute(parentRaw, &def)) < 0) - return -1; - } - - /* possibly update local type */ - if (def->type == VIR_STORAGE_TYPE_FILE) { - if (stat(def->path, &st) == 0) { - if (S_ISDIR(st.st_mode)) { - def->type = VIR_STORAGE_TYPE_DIR; - def->format = VIR_STORAGE_FILE_DIR; - } else if (S_ISBLK(st.st_mode)) { - def->type = VIR_STORAGE_TYPE_BLOCK; - } - } - } - - /* copy parent's labelling and other top level stuff */ - if (virStorageSourceInitChainElement(def, parent, true) < 0) - return -1; - - def->detected = true; - - *child = g_steal_pointer(&def); - return rc; -} - - -int -virStorageSourceNewFromBacking(virStorageSourcePtr parent, - virStorageSourcePtr *backing) -{ - int rc; - - if ((rc = virStorageSourceNewFromChild(parent, - parent->backingStoreRaw, - backing)) < 0) - return rc; - - (*backing)->format = parent->backingStoreRawFormat; - (*backing)->readonly = true; - return rc; -} - - -/** - * @src: disk source definition structure - * @fd: file descriptor - * @sb: stat buffer - * - * Updates src->physical depending on the actual type of storage being used. - * To be called for domain storage source reporting as the volume code does - * not set/use the 'type' field for the voldef->source.target - * - * Returns 0 on success, -1 on error. No libvirt errors are reported. - */ -int -virStorageSourceUpdatePhysicalSize(virStorageSourcePtr src, - int fd, - struct stat const *sb) -{ - off_t end; - virStorageType actual_type = virStorageSourceGetActualType(src); - - switch (actual_type) { - case VIR_STORAGE_TYPE_FILE: - case VIR_STORAGE_TYPE_NETWORK: - src->physical = sb->st_size; - break; - - case VIR_STORAGE_TYPE_BLOCK: - if ((end = lseek(fd, 0, SEEK_END)) == (off_t) -1) - return -1; - - src->physical = end; - break; - - case VIR_STORAGE_TYPE_DIR: - src->physical = 0; - break; - - /* We shouldn't get VOLUME, but the switch requires all cases */ - case VIR_STORAGE_TYPE_VOLUME: - case VIR_STORAGE_TYPE_NVME: - case VIR_STORAGE_TYPE_NONE: - case VIR_STORAGE_TYPE_LAST: - return -1; - } - - return 0; -} - - -/** - * @src: disk source definition structure - * @fd: file descriptor - * @sb: stat buffer - * - * Update the capacity, allocation, physical values for the storage @src - * Shared between the domain storage source for an inactive domain and the - * voldef source target as the result is not affected by the 'type' field. - * - * Returns 0 on success, -1 on error. - */ -int -virStorageSourceUpdateBackingSizes(virStorageSourcePtr src, - int fd, - struct stat const *sb) -{ - /* Get info for normal formats */ - if (S_ISREG(sb->st_mode) || fd == -1) { -#ifndef WIN32 - src->allocation = (unsigned long long)sb->st_blocks * - (unsigned long long)DEV_BSIZE; -#else - src->allocation = sb->st_size; -#endif - /* Regular files may be sparse, so logical size (capacity) is not same - * as actual allocation above - */ - src->capacity = sb->st_size; - - /* Allocation tracks when the file is sparse, physical is the - * last offset of the file. */ - src->physical = sb->st_size; - } else if (S_ISDIR(sb->st_mode)) { - src->allocation = 0; - src->capacity = 0; - src->physical = 0; - } else if (fd >= 0) { - off_t end; - - /* XXX this is POSIX compliant, but doesn't work for CHAR files, - * only BLOCK. There is a Linux specific ioctl() for getting - * size of both CHAR / BLOCK devices we should check for in - * configure - * - * NB. Because we configure with AC_SYS_LARGEFILE, off_t - * should be 64 bits on all platforms. For block devices, we - * have to seek (safe even if someone else is writing) to - * determine physical size, and assume that allocation is the - * same as physical (but can refine that assumption later if - * qemu is still running). - */ - if ((end = lseek(fd, 0, SEEK_END)) == (off_t)-1) { - virReportSystemError(errno, - _("failed to seek to end of %s"), src->path); - return -1; - } - src->physical = end; - src->allocation = end; - src->capacity = end; - } - - return 0; -} - - -/** - * @src: disk source definition structure - * @buf: buffer to the storage file header - * @len: length of the storage file header - * - * Update the storage @src capacity. - * - * Returns 0 on success, -1 on error. - */ -int -virStorageSourceUpdateCapacity(virStorageSourcePtr src, - char *buf, - ssize_t len) -{ - int format = src->format; - g_autoptr(virStorageSource) meta = NULL; - - /* Raw files: capacity is physical size. For all other files: if - * the metadata has a capacity, use that, otherwise fall back to - * physical size. */ - if (format == VIR_STORAGE_FILE_NONE) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("no disk format for %s was specified"), - src->path); - return -1; - } - - if (format == VIR_STORAGE_FILE_RAW && !src->encryption) { - src->capacity = src->physical; - } else if ((meta = virStorageFileGetMetadataFromBuf(src->path, buf, - len, format))) { - src->capacity = meta->capacity ? meta->capacity : src->physical; - if (src->encryption && meta->encryption) - src->encryption->payload_offset = meta->encryption->payload_offset; - } else { - return -1; - } - - if (src->encryption && src->encryption->payload_offset != -1) - src->capacity -= src->encryption->payload_offset * 512; - - return 0; -} - - static char * virStorageFileCanonicalizeFormatPath(char **components, size_t ncomponents, @@ -3414,76 +1644,6 @@ virStorageFileCanonicalizePath(const char *path, } -/** - * virStorageFileRemoveLastPathComponent: - * - * @path: Path string to remove the last component from - * - * Removes the last path component of a path. This function is designed to be - * called on file paths only (no trailing slashes in @path). Caller is - * responsible to free the returned string. - */ -static char * -virStorageFileRemoveLastPathComponent(const char *path) -{ - char *ret; - - ret = g_strdup(NULLSTR_EMPTY(path)); - - virFileRemoveLastComponent(ret); - - return ret; -} - - -/* - * virStorageFileGetRelativeBackingPath: - * - * Resolve relative path to be written to the overlay of @top image when - * collapsing the backing chain between @top and @base. - * - * Returns 0 on success; 1 if backing chain isn't relative and -1 on error. - */ -int -virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, - virStorageSourcePtr base, - char **relpath) -{ - virStorageSourcePtr next; - g_autofree char *tmp = NULL; - g_autofree char *path = NULL; - - *relpath = NULL; - - for (next = top; virStorageSourceIsBacking(next); next = next->backingStore) { - if (!next->relPath) - return 1; - - if (!(tmp = virStorageFileRemoveLastPathComponent(path))) - return -1; - - VIR_FREE(path); - - path = g_strdup_printf("%s%s", tmp, next->relPath); - - VIR_FREE(tmp); - - if (next == base) - break; - } - - if (next != base) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("failed to resolve relative backing name: " - "base image is not in backing chain")); - return -1; - } - - *relpath = g_steal_pointer(&path); - return 0; -} - - /** * virStorageSourceIsRelative: * @src: storage source to check @@ -3636,736 +1796,3 @@ virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator) { VIR_FREE(initiator->iqn); } - -static bool -virStorageFileIsInitialized(const virStorageSource *src) -{ - return src && src->drv; -} - - -/** - * virStorageFileGetBackendForSupportCheck: - * @src: storage source to check support for - * @backend: pointer to the storage backend for @src if it's supported - * - * Returns 0 if @src is not supported by any storage backend currently linked - * 1 if it is supported and -1 on error with an error reported. - */ -static int -virStorageFileGetBackendForSupportCheck(const virStorageSource *src, - virStorageFileBackendPtr *backend) -{ - int actualType; - - - if (!src) { - *backend = NULL; - return 0; - } - - if (src->drv) { - virStorageDriverDataPtr drv = src->drv; - *backend = drv->backend; - return 1; - } - - actualType = virStorageSourceGetActualType(src); - - if (virStorageFileBackendForType(actualType, src->protocol, false, backend) < 0) - return -1; - - if (!*backend) - return 0; - - return 1; -} - - -int -virStorageFileSupportsBackingChainTraversal(const virStorageSource *src) -{ - virStorageFileBackendPtr backend; - int rv; - - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) - return rv; - - return backend->storageFileGetUniqueIdentifier && - backend->storageFileRead && - backend->storageFileAccess ? 1 : 0; -} - - -/** - * virStorageFileSupportsSecurityDriver: - * - * @src: a storage file structure - * - * Check if a storage file supports operations needed by the security - * driver to perform labelling - */ -int -virStorageFileSupportsSecurityDriver(const virStorageSource *src) -{ - virStorageFileBackendPtr backend; - int rv; - - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) - return rv; - - return backend->storageFileChown ? 1 : 0; -} - - -/** - * virStorageFileSupportsAccess: - * - * @src: a storage file structure - * - * Check if a storage file supports checking if the storage source is accessible - * for the given vm. - */ -int -virStorageFileSupportsAccess(const virStorageSource *src) -{ - virStorageFileBackendPtr backend; - int rv; - - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) - return rv; - - return backend->storageFileAccess ? 1 : 0; -} - - -/** - * virStorageFileSupportsCreate: - * @src: a storage file structure - * - * Check if the storage driver supports creating storage described by @src - * via virStorageFileCreate. - */ -int -virStorageFileSupportsCreate(const virStorageSource *src) -{ - virStorageFileBackendPtr backend; - int rv; - - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) - return rv; - - return backend->storageFileCreate ? 1 : 0; -} - - -void -virStorageFileDeinit(virStorageSourcePtr src) -{ - virStorageDriverDataPtr drv = NULL; - - if (!virStorageFileIsInitialized(src)) - return; - - drv = src->drv; - - if (drv->backend && - drv->backend->backendDeinit) - 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); - virStorageDriverDataPtr drv = g_new0(virStorageDriverData, 1); - - src->drv = drv; - - if (uid == (uid_t) -1) - drv->uid = geteuid(); - else - drv->uid = uid; - - if (gid == (gid_t) -1) - drv->gid = getegid(); - else - drv->gid = gid; - - if (virStorageFileBackendForType(actualType, - src->protocol, - true, - &drv->backend) < 0) - goto error; - - if (drv->backend->backendInit && - 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) -{ - virStorageDriverDataPtr drv = NULL; - int ret; - - if (!virStorageFileIsInitialized(src)) { - errno = ENOSYS; - return -2; - } - - drv = src->drv; - - if (!drv->backend->storageFileCreate) { - errno = ENOSYS; - return -2; - } - - ret = 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) -{ - virStorageDriverDataPtr drv = NULL; - int ret; - - if (!virStorageFileIsInitialized(src)) { - errno = ENOSYS; - return -2; - } - - drv = src->drv; - - if (!drv->backend->storageFileUnlink) { - errno = ENOSYS; - return -2; - } - - ret = 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) -{ - virStorageDriverDataPtr drv = NULL; - int ret; - - if (!virStorageFileIsInitialized(src)) { - errno = ENOSYS; - return -2; - } - - drv = src->drv; - - if (!drv->backend->storageFileStat) { - errno = ENOSYS; - return -2; - } - - ret = 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) -{ - virStorageDriverDataPtr drv = NULL; - ssize_t ret; - - if (!virStorageFileIsInitialized(src)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("storage file backend not initialized")); - return -1; - } - - drv = src->drv; - - if (!drv->backend->storageFileRead) - return -2; - - ret = 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) -{ - virStorageDriverDataPtr drv = NULL; - - if (!virStorageFileIsInitialized(src)) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("storage file backend not initialized")); - return NULL; - } - - drv = src->drv; - - if (!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 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) -{ - virStorageDriverDataPtr drv = NULL; - - if (!virStorageFileIsInitialized(src)) { - errno = ENOSYS; - return -2; - } - - drv = src->drv; - - if (!drv->backend->storageFileAccess) { - errno = ENOSYS; - return -2; - } - - return 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) -{ - virStorageDriverDataPtr drv = NULL; - - if (!virStorageFileIsInitialized(src)) { - errno = ENOSYS; - return -2; - } - - drv = src->drv; - - if (!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 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) { - virStorageDriverDataPtr drv = src->drv; - unsigned int access_user = drv->uid; - unsigned int access_group = 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); - } - } -} - - -static int -virStorageFileGetMetadataRecurseReadHeader(virStorageSourcePtr src, - virStorageSourcePtr parent, - uid_t uid, - gid_t gid, - char **buf, - size_t *headerLen, - GHashTable *cycle) -{ - int ret = -1; - const char *uniqueName; - ssize_t len; - - 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 (virHashHasEntry(cycle, uniqueName)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("backing store for %s (%s) is self-referential"), - NULLSTR(src->path), uniqueName); - goto cleanup; - } - - if (virHashAddEntry(cycle, uniqueName, NULL) < 0) - goto cleanup; - - if ((len = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, buf)) < 0) - goto cleanup; - - *headerLen = len; - ret = 0; - - cleanup: - virStorageFileDeinit(src); - return ret; -} - - -/* Recursive workhorse for virStorageFileGetMetadata. */ -static int -virStorageFileGetMetadataRecurse(virStorageSourcePtr src, - virStorageSourcePtr parent, - uid_t uid, gid_t gid, - bool report_broken, - GHashTable *cycle, - unsigned int depth) -{ - virStorageFileFormat orig_format = src->format; - size_t headerLen; - int rv; - g_autofree char *buf = NULL; - g_autoptr(virStorageSource) backingStore = NULL; - - VIR_DEBUG("path=%s format=%d uid=%u gid=%u", - NULLSTR(src->path), src->format, - (unsigned int)uid, (unsigned int)gid); - - if (src->format == VIR_STORAGE_FILE_AUTO_SAFE) - src->format = VIR_STORAGE_FILE_AUTO; - - /* exit if we can't load information about the current image */ - rv = virStorageFileSupportsBackingChainTraversal(src); - if (rv <= 0) { - if (orig_format == VIR_STORAGE_FILE_AUTO) - return -2; - - return rv; - } - - if (virStorageFileGetMetadataRecurseReadHeader(src, parent, uid, gid, - &buf, &headerLen, cycle) < 0) - return -1; - - if (virStorageFileProbeGetMetadata(src, buf, headerLen) < 0) - return -1; - - /* If we probed the format we MUST ensure that nothing else than the current - * image is considered for security labelling and/or recursion. */ - if (orig_format == VIR_STORAGE_FILE_AUTO) { - if (src->backingStoreRaw) { - src->format = VIR_STORAGE_FILE_RAW; - VIR_FREE(src->backingStoreRaw); - return -2; - } - } - - if (src->backingStoreRaw) { - if ((rv = virStorageSourceNewFromBacking(src, &backingStore)) < 0) - return -1; - - /* the backing file would not be usable for VM usage */ - if (rv == 1) - return 0; - - if ((rv = virStorageFileGetMetadataRecurse(backingStore, parent, - uid, gid, - report_broken, - cycle, depth + 1)) < 0) { - if (!report_broken) - return 0; - - if (rv == -2) { - virReportError(VIR_ERR_OPERATION_INVALID, - _("format of backing image '%s' of image '%s' was not specified in the image metadata " - "(See https://libvirt.org/kbase/backing_chains.html for troubleshooting)"), - src->backingStoreRaw, NULLSTR(src->path)); - } - - return -1; - } - - backingStore->id = depth; - src->backingStore = g_steal_pointer(&backingStore); - } else { - /* add terminator */ - src->backingStore = virStorageSourceNew(); - } - - return 0; -} - - -/** - * 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. Note that the inability for - * libvirt to traverse a given source is not considered an error. - * - * Caller MUST free result after use via virObjectUnref. - */ -int -virStorageFileGetMetadata(virStorageSourcePtr src, - uid_t uid, gid_t gid, - bool report_broken) -{ - GHashTable *cycle = NULL; - virStorageType actualType = virStorageSourceGetActualType(src); - int ret = -1; - - VIR_DEBUG("path=%s format=%d uid=%u gid=%u report_broken=%d", - src->path, src->format, (unsigned int)uid, (unsigned int)gid, - report_broken); - - if (!(cycle = virHashNew(NULL))) - return -1; - - if (src->format <= VIR_STORAGE_FILE_NONE) { - if (actualType == VIR_STORAGE_TYPE_DIR) - src->format = VIR_STORAGE_FILE_DIR; - else - src->format = VIR_STORAGE_FILE_RAW; - } - - ret = virStorageFileGetMetadataRecurse(src, src, uid, gid, - 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. - */ -int -virStorageFileGetBackingStoreStr(virStorageSourcePtr src, - char **backing) -{ - ssize_t headerLen; - int rv; - g_autofree char *buf = NULL; - g_autoptr(virStorageSource) tmp = NULL; - - *backing = NULL; - - /* exit if we can't load information about the current image */ - if (!virStorageFileSupportsBackingChainTraversal(src)) - return 0; - - rv = virStorageFileAccess(src, F_OK); - if (rv == -2) - return 0; - if (rv < 0) { - virStorageFileReportBrokenChain(errno, src, src); - return -1; - } - - if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, - &buf)) < 0) { - if (headerLen == -2) - return 0; - return -1; - } - - if (!(tmp = virStorageSourceCopy(src, false))) - return -1; - - if (virStorageFileProbeGetMetadata(tmp, buf, headerLen) < 0) - return -1; - - *backing = g_steal_pointer(&tmp->backingStoreRaw); - return 0; -} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 27ac6a493f..d6f194a7dd 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -388,18 +388,6 @@ struct _virStorageSource { G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); -#ifndef DEV_BSIZE -# define DEV_BSIZE 512 -#endif - -virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format); -virStorageSourcePtr virStorageFileGetMetadataFromBuf(const char *path, - char *buf, - size_t len, - int format) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virStorageFileParseChainIndex(const char *diskTarget, const char *name, unsigned int *chainIndex) @@ -410,13 +398,6 @@ int virStorageFileParseBackingStoreStr(const char *str, unsigned int *chainIndex) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); -virStorageSourcePtr virStorageFileChainLookup(virStorageSourcePtr chain, - virStorageSourcePtr startFrom, - const char *name, - unsigned int idx, - virStorageSourcePtr *parent) - ATTRIBUTE_NONNULL(1); - bool virStorageIsFile(const char *path); bool virStorageIsRelative(const char *backing); @@ -469,15 +450,6 @@ bool virStorageSourceIsEmpty(virStorageSourcePtr src); bool virStorageSourceIsBlockLocal(const virStorageSource *src); virStorageSourcePtr virStorageSourceNew(void); void virStorageSourceBackingStoreClear(virStorageSourcePtr def); -int virStorageSourceUpdatePhysicalSize(virStorageSourcePtr src, - int fd, struct stat const *sb); -int virStorageSourceUpdateBackingSizes(virStorageSourcePtr src, - int fd, struct stat const *sb); -int virStorageSourceUpdateCapacity(virStorageSourcePtr src, - char *buf, ssize_t len); - -int virStorageSourceNewFromBacking(virStorageSourcePtr parent, - virStorageSourcePtr *backing); int virStorageSourceNetCookiesValidate(virStorageSourcePtr src); @@ -488,10 +460,6 @@ bool virStorageSourceIsSameLocation(virStorageSourcePtr a, virStorageSourcePtr b) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virStorageSourceParseRBDColonString(const char *rbdstr, - virStorageSourcePtr src) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - typedef int (*virStorageFileSimplifyPathReadlinkCallback)(const char *path, char **link, @@ -500,14 +468,6 @@ char *virStorageFileCanonicalizePath(const char *path, virStorageFileSimplifyPathReadlinkCallback cb, void *cbdata); -int virStorageFileGetRelativeBackingPath(virStorageSourcePtr from, - virStorageSourcePtr to, - char **relpath) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); - -int virStorageSourceNewFromBackingAbsolute(const char *path, - virStorageSourcePtr *src); - bool virStorageSourceIsRelative(virStorageSourcePtr src); void @@ -542,39 +502,4 @@ virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest, void virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator); -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); - -int virStorageFileSupportsSecurityDriver(const virStorageSource *src); -int virStorageFileSupportsAccess(const virStorageSource *src); -int virStorageFileSupportsCreate(const virStorageSource *src); -int virStorageFileSupportsBackingChainTraversal(const virStorageSource *src); - -int virStorageFileGetMetadata(virStorageSourcePtr src, - uid_t uid, gid_t gid, - bool report_broken) - ATTRIBUTE_NONNULL(1); - -int virStorageFileGetBackingStoreStr(virStorageSourcePtr src, - char **backing) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - -void virStorageFileReportBrokenChain(int errcode, - virStorageSourcePtr src, - virStorageSourcePtr parent); - G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageAuthDef, virStorageAuthDefFree); diff --git a/tests/meson.build b/tests/meson.build index 23255dd62a..0de0783839 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -442,7 +442,7 @@ endif if conf.has('WITH_QEMU') tests += [ { 'name': 'qemuagenttest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, - { 'name': 'qemublocktest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, + { 'name': 'qemublocktest', 'include': [ storage_file_inc_dir ], 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemucapabilitiestest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemucaps2xmltest', 'link_with': [ test_qemu_driver_lib ], 'link_whole': [ test_utils_qemu_lib ] }, { 'name': 'qemucommandutiltest', 'link_with': [ test_qemu_driver_lib, test_utils_qemu_monitor_lib ], 'link_whole': [ test_utils_qemu_lib ] }, @@ -509,7 +509,7 @@ endif if conf.has('WITH_STORAGE_FS') tests += [ - { 'name': 'virstoragetest', 'link_with': [ storage_driver_impl_lib ] }, + { 'name': 'virstoragetest', 'include': [ storage_file_inc_dir ],'link_with': [ storage_driver_impl_lib ] }, ] endif diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index f86e9fd552..ddaf73359d 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -17,6 +17,7 @@ #include <config.h> +#include "storage_source.h" #include "testutils.h" #include "testutilsqemu.h" #include "testutilsqemuschema.h" diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c index 86c7cd910c..5c2f211557 100644 --- a/tests/virstoragetest.c +++ b/tests/virstoragetest.c @@ -20,6 +20,7 @@ #include <unistd.h> +#include "storage_source.h" #include "testutils.h" #include "vircommand.h" #include "virerror.h" -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:21 +0100, Pavel Hrdina wrote:
Up until now we had a runtime code and XML related code in the same source file inside util directory.
This patch takes the runtime part and extracts it into the new storage_file directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
Reviewed-by: Peter Krempa <pkrempa@redhat.com> As a follow-up I'd prefer if we also extract the backing store string parsers into a separate module. We have the legacy ones for RBD and NBD and then the JSON one.

It's used only by storage file code so it doesn't make sense to have it in util directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 8 ++++---- src/storage_file/meson.build | 1 + .../storage_file_backend.c} | 4 ++-- .../storage_file_backend.h} | 2 +- src/storage_file/storage_file_fs.c | 2 +- src/storage_file/storage_file_gluster.c | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 9 files changed, 12 insertions(+), 12 deletions(-) rename src/{util/virstoragefilebackend.c => storage_file/storage_file_backend.c} (97%) rename src/{util/virstoragefilebackend.h => storage_file/storage_file_backend.h} (97%) diff --git a/po/POTFILES.in b/po/POTFILES.in index 1e47af987d..4da22ede8f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -223,6 +223,7 @@ @SRCDIR@src/storage/storage_backend_zfs.c @SRCDIR@src/storage/storage_driver.c @SRCDIR@src/storage/storage_util.c +@SRCDIR@src/storage_file/storage_file_backend.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c @SRCDIR@src/storage_file/storage_source.c @@ -306,7 +307,6 @@ @SRCDIR@src/util/virsocketaddr.c @SRCDIR@src/util/virstorageencryption.c @SRCDIR@src/util/virstoragefile.c -@SRCDIR@src/util/virstoragefilebackend.c @SRCDIR@src/util/virstoragefileprobe.c @SRCDIR@src/util/virstring.c @SRCDIR@src/util/virsysinfo.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 67a863467d..e7af8f0599 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1618,6 +1618,10 @@ virSecurityManagerVerify; virSecurityXATTRNamespaceDefined; +# storage_file/storage_file_backend.h +virStorageFileBackendRegister; + + # storage_file/storage_source.h virStorageFileAccess; virStorageFileChainLookup; @@ -3210,10 +3214,6 @@ virStorageTypeFromString; virStorageTypeToString; -# util/virstoragefilebackend.h -virStorageFileBackendRegister; - - # util/virstoragefileprobe.h virStorageFileProbeFormat; virStorageFileProbeGetMetadata; diff --git a/src/storage_file/meson.build b/src/storage_file/meson.build index bae018feac..bcd6f01906 100644 --- a/src/storage_file/meson.build +++ b/src/storage_file/meson.build @@ -1,5 +1,6 @@ storage_file_sources = [ 'storage_source.c', + 'storage_file_backend.c', ] stoarge_file_fs_sources = [ diff --git a/src/util/virstoragefilebackend.c b/src/storage_file/storage_file_backend.c similarity index 97% rename from src/util/virstoragefilebackend.c rename to src/storage_file/storage_file_backend.c index 55c62b0212..6e4b2f408b 100644 --- a/src/util/virstoragefilebackend.c +++ b/src/storage_file/storage_file_backend.c @@ -1,5 +1,5 @@ /* - * virstoragefilebackend.c: internal storage source backend contract + * storage_file_backend.c: internal storage source backend contract * * Copyright (C) 2007-2018 Red Hat, Inc. * Copyright (C) 2007-2008 Daniel P. Berrange @@ -27,7 +27,7 @@ #include "virerror.h" #include "viralloc.h" #include "internal.h" -#include "virstoragefilebackend.h" +#include "storage_file_backend.h" #include "virlog.h" #include "virmodule.h" #include "virfile.h" diff --git a/src/util/virstoragefilebackend.h b/src/storage_file/storage_file_backend.h similarity index 97% rename from src/util/virstoragefilebackend.h rename to src/storage_file/storage_file_backend.h index 43b36e95bc..ad0f66212c 100644 --- a/src/util/virstoragefilebackend.h +++ b/src/storage_file/storage_file_backend.h @@ -1,5 +1,5 @@ /* - * virstoragefilebackend.h: internal storage source backend contract + * storage_file_backend.h: internal storage source backend contract * * Copyright (C) 2007-2018 Red Hat, Inc. * diff --git a/src/storage_file/storage_file_fs.c b/src/storage_file/storage_file_fs.c index 5a44ef8c2d..1cc9233512 100644 --- a/src/storage_file/storage_file_fs.c +++ b/src/storage_file/storage_file_fs.c @@ -25,9 +25,9 @@ #include <fcntl.h> #include "virerror.h" +#include "storage_file_backend.h" #include "storage_file_fs.h" #include "storage_util.h" -#include "virstoragefilebackend.h" #include "vircommand.h" #include "viralloc.h" #include "virfile.h" diff --git a/src/storage_file/storage_file_gluster.c b/src/storage_file/storage_file_gluster.c index 2560e10d37..0828088c2c 100644 --- a/src/storage_file/storage_file_gluster.c +++ b/src/storage_file/storage_file_gluster.c @@ -23,12 +23,12 @@ #include <glusterfs/api/glfs.h> +#include "storage_file_backend.h" #include "storage_file_gluster.h" #include "viralloc.h" #include "virerror.h" #include "virlog.h" #include "virstoragefile.h" -#include "virstoragefilebackend.h" #include "virstring.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage_file/storage_source.c b/src/storage_file/storage_source.c index b5e0bc5040..744d3e94fd 100644 --- a/src/storage_file/storage_source.c +++ b/src/storage_file/storage_source.c @@ -25,6 +25,7 @@ #include <unistd.h> #include "internal.h" +#include "storage_file_backend.h" #include "storage_source.h" #include "viralloc.h" #include "virerror.h" @@ -34,7 +35,6 @@ #include "virlog.h" #include "virobject.h" #include "virstoragefile.h" -#include "virstoragefilebackend.h" #include "virstoragefileprobe.h" #include "virstring.h" #include "viruri.h" diff --git a/src/util/meson.build b/src/util/meson.build index 9fb270fadd..64c0f9df6d 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -90,7 +90,6 @@ util_sources = [ 'virsocketaddr.c', 'virstorageencryption.c', 'virstoragefile.c', - 'virstoragefilebackend.c', 'virstoragefileprobe.c', 'virstring.c', 'virsysinfo.c', -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:22 +0100, Pavel Hrdina wrote:
It's used only by storage file code so it doesn't make sense to have it in util directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 8 ++++---- src/storage_file/meson.build | 1 + .../storage_file_backend.c} | 4 ++-- .../storage_file_backend.h} | 2 +- src/storage_file/storage_file_fs.c | 2 +- src/storage_file/storage_file_gluster.c | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 9 files changed, 12 insertions(+), 12 deletions(-) rename src/{util/virstoragefilebackend.c => storage_file/storage_file_backend.c} (97%) rename src/{util/virstoragefilebackend.h => storage_file/storage_file_backend.h} (97%)
Reviewed-by: Peter Krempa <pkrempa@redhat.com> although I'm probably more inclined to keep the original name without underscores and with vir prefix.

On Fri, Jan 22, 2021 at 09:54:06AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:22 +0100, Pavel Hrdina wrote:
It's used only by storage file code so it doesn't make sense to have it in util directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 8 ++++---- src/storage_file/meson.build | 1 + .../storage_file_backend.c} | 4 ++-- .../storage_file_backend.h} | 2 +- src/storage_file/storage_file_fs.c | 2 +- src/storage_file/storage_file_gluster.c | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 9 files changed, 12 insertions(+), 12 deletions(-) rename src/{util/virstoragefilebackend.c => storage_file/storage_file_backend.c} (97%) rename src/{util/virstoragefilebackend.h => storage_file/storage_file_backend.h} (97%)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
although I'm probably more inclined to keep the original name without underscores and with vir prefix.
I personally don't have any preference. The only motivation was not to mix two different naming styles withing one directory. We should eventually unify the file naming style across the whole project as we use underscores, dash and nothing all over the place. Pavel

On Fri, Jan 22, 2021 at 10:13:02 +0100, Pavel Hrdina wrote:
On Fri, Jan 22, 2021 at 09:54:06AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:22 +0100, Pavel Hrdina wrote:
It's used only by storage file code so it doesn't make sense to have it in util directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 8 ++++---- src/storage_file/meson.build | 1 + .../storage_file_backend.c} | 4 ++-- .../storage_file_backend.h} | 2 +- src/storage_file/storage_file_fs.c | 2 +- src/storage_file/storage_file_gluster.c | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 9 files changed, 12 insertions(+), 12 deletions(-) rename src/{util/virstoragefilebackend.c => storage_file/storage_file_backend.c} (97%) rename src/{util/virstoragefilebackend.h => storage_file/storage_file_backend.h} (97%)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
although I'm probably more inclined to keep the original name without underscores and with vir prefix.
I personally don't have any preference. The only motivation was not to mix two different naming styles withing one directory.
We should eventually unify the file naming style across the whole project as we use underscores, dash and nothing all over the place.
Yes, it can be done separately.

Same as virStorageFileBackend, it doesn't belong into util directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 10 +++++----- src/qemu/qemu_driver.c | 2 +- src/storage/storage_backend_gluster.c | 2 +- src/storage/storage_util.c | 2 +- src/storage_file/meson.build | 1 + .../storage_file_probe.c} | 6 +++--- .../storage_file_probe.h} | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 10 files changed, 15 insertions(+), 15 deletions(-) rename src/{util/virstoragefileprobe.c => storage_file/storage_file_probe.c} (99%) rename src/{util/virstoragefileprobe.h => storage_file/storage_file_probe.h} (95%) diff --git a/po/POTFILES.in b/po/POTFILES.in index 4da22ede8f..eeff3f9f2f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -226,6 +226,7 @@ @SRCDIR@src/storage_file/storage_file_backend.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c +@SRCDIR@src/storage_file/storage_file_probe.c @SRCDIR@src/storage_file/storage_source.c @SRCDIR@src/test/test_driver.c @SRCDIR@src/util/iohelper.c @@ -307,7 +308,6 @@ @SRCDIR@src/util/virsocketaddr.c @SRCDIR@src/util/virstorageencryption.c @SRCDIR@src/util/virstoragefile.c -@SRCDIR@src/util/virstoragefileprobe.c @SRCDIR@src/util/virstring.c @SRCDIR@src/util/virsysinfo.c @SRCDIR@src/util/virsystemd.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e7af8f0599..b49eee3750 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1622,6 +1622,11 @@ virSecurityXATTRNamespaceDefined; virStorageFileBackendRegister; +# storage_file/storage_file_probe.h +virStorageFileProbeFormat; +virStorageFileProbeGetMetadata; + + # storage_file/storage_source.h virStorageFileAccess; virStorageFileChainLookup; @@ -3214,11 +3219,6 @@ virStorageTypeFromString; virStorageTypeToString; -# util/virstoragefileprobe.h -virStorageFileProbeFormat; -virStorageFileProbeGetMetadata; - - # util/virstring.h virSkipSpaces; virSkipSpacesAndBackslash; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index a5c2488f2c..5363af3f56 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -83,7 +83,7 @@ #include "domain_nwfilter.h" #include "virhook.h" #include "virstoragefile.h" -#include "virstoragefileprobe.h" +#include "storage_file_probe.h" #include "storage_source.h" #include "virfile.h" #include "virfdstream.h" diff --git a/src/storage/storage_backend_gluster.c b/src/storage/storage_backend_gluster.c index 782f8eb611..554c76ddb4 100644 --- a/src/storage/storage_backend_gluster.c +++ b/src/storage/storage_backend_gluster.c @@ -28,9 +28,9 @@ #include "viralloc.h" #include "virerror.h" #include "virlog.h" -#include "virstoragefileprobe.h" #include "virstring.h" #include "viruri.h" +#include "storage_file_probe.h" #include "storage_util.h" #include "storage_source.h" diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index d51fa2b4c0..04f9a442f2 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -62,7 +62,7 @@ #include "vircrypto.h" #include "viruuid.h" #include "virstoragefile.h" -#include "virstoragefileprobe.h" +#include "storage_file_probe.h" #include "storage_util.h" #include "storage_source.h" #include "virlog.h" diff --git a/src/storage_file/meson.build b/src/storage_file/meson.build index bcd6f01906..eb9453e7b0 100644 --- a/src/storage_file/meson.build +++ b/src/storage_file/meson.build @@ -1,6 +1,7 @@ storage_file_sources = [ 'storage_source.c', 'storage_file_backend.c', + 'storage_file_probe.c', ] stoarge_file_fs_sources = [ diff --git a/src/util/virstoragefileprobe.c b/src/storage_file/storage_file_probe.c similarity index 99% rename from src/util/virstoragefileprobe.c rename to src/storage_file/storage_file_probe.c index bca098cd35..e5e1b272ac 100644 --- a/src/util/virstoragefileprobe.c +++ b/src/storage_file/storage_file_probe.c @@ -1,5 +1,5 @@ /* - * virstoragefileprobe.c: file utility functions for FS storage backend + * storage_file_probe.c: file utility functions for FS storage backend * * Copyright (C) 2007-2017 Red Hat, Inc. * Copyright (C) 2007-2008 Daniel P. Berrange @@ -26,17 +26,17 @@ #include <fcntl.h> #include "internal.h" +#include "storage_file_probe.h" #include "viralloc.h" #include "virbitmap.h" #include "virendian.h" #include "virfile.h" #include "virlog.h" #include "virstoragefile.h" -#include "virstoragefileprobe.h" #define VIR_FROM_THIS VIR_FROM_STORAGE -VIR_LOG_INIT("util.storagefileprobe"); +VIR_LOG_INIT("storage_file.storagefileprobe"); enum lv_endian { LV_LITTLE_ENDIAN = 1, /* 1234 */ diff --git a/src/util/virstoragefileprobe.h b/src/storage_file/storage_file_probe.h similarity index 95% rename from src/util/virstoragefileprobe.h rename to src/storage_file/storage_file_probe.h index 2b94a4ae51..c443c11606 100644 --- a/src/util/virstoragefileprobe.h +++ b/src/storage_file/storage_file_probe.h @@ -1,5 +1,5 @@ /* - * virstoragefileprobe.h: file utility functions for FS storage backend + * storage_file_probe.h: file utility functions for FS storage backend * * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. * Copyright (C) 2007-2008 Daniel P. Berrange diff --git a/src/storage_file/storage_source.c b/src/storage_file/storage_source.c index 744d3e94fd..d1e0aeb2c1 100644 --- a/src/storage_file/storage_source.c +++ b/src/storage_file/storage_source.c @@ -26,6 +26,7 @@ #include "internal.h" #include "storage_file_backend.h" +#include "storage_file_probe.h" #include "storage_source.h" #include "viralloc.h" #include "virerror.h" @@ -35,7 +36,6 @@ #include "virlog.h" #include "virobject.h" #include "virstoragefile.h" -#include "virstoragefileprobe.h" #include "virstring.h" #include "viruri.h" #include "virutil.h" diff --git a/src/util/meson.build b/src/util/meson.build index 64c0f9df6d..b510f0ebe9 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -90,7 +90,6 @@ util_sources = [ 'virsocketaddr.c', 'virstorageencryption.c', 'virstoragefile.c', - 'virstoragefileprobe.c', 'virstring.c', 'virsysinfo.c', 'virsystemd.c', -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:23 +0100, Pavel Hrdina wrote:
Same as virStorageFileBackend, it doesn't belong into util directory.
Arguably, after you remove the file access, it kinda becomes just an utility function. On the other hand, it's use is strictly limited to the storage source code, so it makes sense to stop linking it with the general util module.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 10 +++++----- src/qemu/qemu_driver.c | 2 +- src/storage/storage_backend_gluster.c | 2 +- src/storage/storage_util.c | 2 +- src/storage_file/meson.build | 1 + .../storage_file_probe.c} | 6 +++--- .../storage_file_probe.h} | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 10 files changed, 15 insertions(+), 15 deletions(-) rename src/{util/virstoragefileprobe.c => storage_file/storage_file_probe.c} (99%) rename src/{util/virstoragefileprobe.h => storage_file/storage_file_probe.h} (95%)
diff --git a/po/POTFILES.in b/po/POTFILES.in index 4da22ede8f..eeff3f9f2f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -226,6 +226,7 @@ @SRCDIR@src/storage_file/storage_file_backend.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c +@SRCDIR@src/storage_file/storage_file_probe.c
Hmm, I think we should add a prefix for the _fs and _gluster backend drivers so that it doesn't get confused with the probing code. Also same comment as previous patch regarding naming. Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On Fri, Jan 22, 2021 at 09:57:03AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:23 +0100, Pavel Hrdina wrote:
Same as virStorageFileBackend, it doesn't belong into util directory.
Arguably, after you remove the file access, it kinda becomes just an utility function.
On the other hand, it's use is strictly limited to the storage source code, so it makes sense to stop linking it with the general util module.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/libvirt_private.syms | 10 +++++----- src/qemu/qemu_driver.c | 2 +- src/storage/storage_backend_gluster.c | 2 +- src/storage/storage_util.c | 2 +- src/storage_file/meson.build | 1 + .../storage_file_probe.c} | 6 +++--- .../storage_file_probe.h} | 2 +- src/storage_file/storage_source.c | 2 +- src/util/meson.build | 1 - 10 files changed, 15 insertions(+), 15 deletions(-) rename src/{util/virstoragefileprobe.c => storage_file/storage_file_probe.c} (99%) rename src/{util/virstoragefileprobe.h => storage_file/storage_file_probe.h} (95%)
diff --git a/po/POTFILES.in b/po/POTFILES.in index 4da22ede8f..eeff3f9f2f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -226,6 +226,7 @@ @SRCDIR@src/storage_file/storage_file_backend.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c +@SRCDIR@src/storage_file/storage_file_probe.c
Hmm, I think we should add a prefix for the _fs and _gluster backend drivers so that it doesn't get confused with the probing code.
Good point. How about storage_file_backend_fs ?
Also same comment as previous patch regarding naming.
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

On Fri, Jan 22, 2021 at 10:15:52 +0100, Pavel Hrdina wrote:
On Fri, Jan 22, 2021 at 09:57:03AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:23 +0100, Pavel Hrdina wrote:
[...]
@SRCDIR@src/storage_file/storage_file_backend.c @SRCDIR@src/storage_file/storage_file_fs.c @SRCDIR@src/storage_file/storage_file_gluster.c +@SRCDIR@src/storage_file/storage_file_probe.c
Hmm, I think we should add a prefix for the _fs and _gluster backend drivers so that it doesn't get confused with the probing code.
Good point. How about storage_file_backend_fs ?
Sounds good to me.

The code handles XML bits and internal definition and should be in conf directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 1 + src/conf/backup_conf.c | 2 +- src/conf/checkpoint_conf.c | 2 +- src/conf/domain_conf.c | 2 +- src/conf/domain_conf.h | 4 +- src/conf/meson.build | 1 + src/conf/snapshot_conf.c | 2 +- src/conf/storage_conf.c | 2 +- src/conf/storage_conf.h | 2 +- src/conf/storage_source_conf.c | 1350 +++++++++++++++++++++++ src/conf/storage_source_conf.h | 537 +++++++++ src/esx/esx_storage_backend_iscsi.c | 2 +- src/esx/esx_storage_backend_vmfs.c | 2 +- src/libvirt_private.syms | 101 +- src/qemu/qemu_backup.c | 2 +- src/qemu/qemu_blockjob.c | 2 +- src/qemu/qemu_command.c | 2 +- src/qemu/qemu_driver.c | 1 + src/qemu/qemu_hotplug.c | 2 +- src/qemu/qemu_migration.c | 2 +- src/storage/storage_backend.c | 2 +- src/storage/storage_util.c | 1 + src/storage_file/meson.build | 3 + src/storage_file/storage_file_backend.h | 2 +- src/storage_file/storage_file_probe.c | 2 +- src/storage_file/storage_file_probe.h | 2 +- src/storage_file/storage_source.h | 2 +- src/util/virstoragefile.c | 1308 +--------------------- src/util/virstoragefile.h | 456 +------- 29 files changed, 1968 insertions(+), 1831 deletions(-) create mode 100644 src/conf/storage_source_conf.c create mode 100644 src/conf/storage_source_conf.h diff --git a/po/POTFILES.in b/po/POTFILES.in index eeff3f9f2f..00100d7d73 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,6 +43,7 @@ @SRCDIR@src/conf/snapshot_conf.c @SRCDIR@src/conf/storage_adapter_conf.c @SRCDIR@src/conf/storage_conf.c +@SRCDIR@src/conf/storage_source_conf.c @SRCDIR@src/conf/virchrdev.c @SRCDIR@src/conf/virdomainmomentobjlist.c @SRCDIR@src/conf/virdomainobjlist.c diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 90ffcc51d1..ba58b2e322 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -26,7 +26,7 @@ #include "virlog.h" #include "viralloc.h" #include "backup_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virfile.h" #include "virerror.h" #include "virxml.h" diff --git a/src/conf/checkpoint_conf.c b/src/conf/checkpoint_conf.c index 7edc7daa12..16fb138a3e 100644 --- a/src/conf/checkpoint_conf.c +++ b/src/conf/checkpoint_conf.c @@ -30,7 +30,7 @@ #include "virlog.h" #include "viralloc.h" #include "checkpoint_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "viruuid.h" #include "virfile.h" #include "virerror.h" diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index fcf332fe44..dab4f10326 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -43,7 +43,7 @@ #include "nwfilter_conf.h" #include "virnetworkportdef.h" #include "storage_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virfile.h" #include "virbitmap.h" #include "secret_conf.h" diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d514f6360f..f5d346ddf0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -48,7 +48,7 @@ #include "virobject.h" #include "device_conf.h" #include "virbitmap.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virseclabel.h" #include "virprocess.h" #include "virgic.h" @@ -359,7 +359,7 @@ struct _virDomainHostdevDef { /* Types of disk frontend (guest view). For backends (host view), see - * virStorageType in util/virstoragefile.h */ + * virStorageType in conf/storage_source_conf.h */ typedef enum { VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM, diff --git a/src/conf/meson.build b/src/conf/meson.build index 8ddcc9968d..9d4831b815 100644 --- a/src/conf/meson.build +++ b/src/conf/meson.build @@ -54,6 +54,7 @@ storage_conf_sources = [ 'storage_adapter_conf.c', 'storage_capabilities.c', 'storage_conf.c', + 'storage_source_conf.c', 'virstorageobj.c', ] diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 673282be7a..0b78699589 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -38,7 +38,7 @@ #include "nwfilter_conf.h" #include "secret_conf.h" #include "snapshot_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "viruuid.h" #include "virfile.h" #include "virerror.h" diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 0c50529ace..9aed602fd6 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -31,7 +31,7 @@ #include "node_device_conf.h" #include "storage_adapter_conf.h" #include "storage_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virxml.h" #include "viruuid.h" diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index ffd406e093..aeda2891d4 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -23,7 +23,7 @@ #include "internal.h" #include "virstorageencryption.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virbitmap.h" #include "virthread.h" #include "device_conf.h" diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c new file mode 100644 index 0000000000..dab5e855f5 --- /dev/null +++ b/src/conf/storage_source_conf.c @@ -0,0 +1,1350 @@ +/* + * storage_source_conf.c: file utility functions for FS storage backend + * + * Copyright (C) 2007-2017 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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 "storage_source_conf.h" + +#include "viralloc.h" +#include "virbuffer.h" +#include "virerror.h" +#include "virlog.h" +#include "virstring.h" + +#define VIR_FROM_THIS VIR_FROM_STORAGE + +VIR_LOG_INIT("conf.storage_source_conf"); + + +static virClassPtr virStorageSourceClass; + + +VIR_ENUM_IMPL(virStorage, + VIR_STORAGE_TYPE_LAST, + "none", + "file", + "block", + "dir", + "network", + "volume", + "nvme", +); + + +VIR_ENUM_IMPL(virStorageFileFormat, + VIR_STORAGE_FILE_LAST, + "none", + "raw", "dir", "bochs", + "cloop", "dmg", "iso", + "vpc", "vdi", + /* Not direct file formats, but used for various drivers */ + "fat", "vhd", "ploop", + /* Formats with backing file below here */ + "cow", "qcow", "qcow2", "qed", "vmdk", +); + + +VIR_ENUM_IMPL(virStorageFileFeature, + VIR_STORAGE_FILE_FEATURE_LAST, + "lazy_refcounts", +); + + +VIR_ENUM_IMPL(virStorageNetProtocol, + VIR_STORAGE_NET_PROTOCOL_LAST, + "none", + "nbd", + "rbd", + "sheepdog", + "gluster", + "iscsi", + "http", + "https", + "ftp", + "ftps", + "tftp", + "ssh", + "vxhs", + "nfs", +); + + +VIR_ENUM_IMPL(virStorageNetHostTransport, + VIR_STORAGE_NET_HOST_TRANS_LAST, + "tcp", + "unix", + "rdma", +); + + +VIR_ENUM_IMPL(virStorageSourcePoolMode, + VIR_STORAGE_SOURCE_POOL_MODE_LAST, + "default", + "host", + "direct", +); + + +VIR_ENUM_IMPL(virStorageAuth, + VIR_STORAGE_AUTH_TYPE_LAST, + "none", "chap", "ceph", +); + + +/** + * virStorageSourceIsBacking: + * @src: storage source + * + * Returns true if @src is a eligible backing store structure. Useful + * for iterators. + */ +bool +virStorageSourceIsBacking(const virStorageSource *src) +{ + return src && src->type != VIR_STORAGE_TYPE_NONE; +} + +/** + * virStorageSourceHasBacking: + * @src: storage source + * + * Returns true if @src has backing store/chain. + */ +bool +virStorageSourceHasBacking(const virStorageSource *src) +{ + return virStorageSourceIsBacking(src) && src->backingStore && + src->backingStore->type != VIR_STORAGE_TYPE_NONE; +} + + +void +virStorageNetHostDefClear(virStorageNetHostDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->name); + VIR_FREE(def->socket); +} + + +void +virStorageNetHostDefFree(size_t nhosts, + virStorageNetHostDefPtr hosts) +{ + size_t i; + + if (!hosts) + return; + + for (i = 0; i < nhosts; i++) + virStorageNetHostDefClear(&hosts[i]); + + VIR_FREE(hosts); +} + + +static void +virStoragePermsFree(virStoragePermsPtr def) +{ + if (!def) + return; + + VIR_FREE(def->label); + VIR_FREE(def); +} + + +virStorageNetHostDefPtr +virStorageNetHostDefCopy(size_t nhosts, + virStorageNetHostDefPtr hosts) +{ + virStorageNetHostDefPtr ret = NULL; + size_t i; + + ret = g_new0(virStorageNetHostDef, nhosts); + + for (i = 0; i < nhosts; i++) { + virStorageNetHostDefPtr src = &hosts[i]; + virStorageNetHostDefPtr dst = &ret[i]; + + dst->transport = src->transport; + dst->port = src->port; + + dst->name = g_strdup(src->name); + dst->socket = g_strdup(src->socket); + } + + return ret; +} + + +void +virStorageAuthDefFree(virStorageAuthDefPtr authdef) +{ + if (!authdef) + return; + + VIR_FREE(authdef->username); + VIR_FREE(authdef->secrettype); + virSecretLookupDefClear(&authdef->seclookupdef); + VIR_FREE(authdef); +} + + +virStorageAuthDefPtr +virStorageAuthDefCopy(const virStorageAuthDef *src) +{ + g_autoptr(virStorageAuthDef) authdef = NULL; + + authdef = g_new0(virStorageAuthDef, 1); + + authdef->username = g_strdup(src->username); + /* Not present for storage pool, but used for disk source */ + authdef->secrettype = g_strdup(src->secrettype); + authdef->authType = src->authType; + + virSecretLookupDefCopy(&authdef->seclookupdef, &src->seclookupdef); + + return g_steal_pointer(&authdef); +} + + +virStorageAuthDefPtr +virStorageAuthDefParse(xmlNodePtr node, + xmlXPathContextPtr ctxt) +{ + VIR_XPATH_NODE_AUTORESTORE(ctxt) + virStorageAuthDefPtr ret = NULL; + xmlNodePtr secretnode = NULL; + g_autoptr(virStorageAuthDef) authdef = NULL; + g_autofree char *authtype = NULL; + + ctxt->node = node; + + authdef = g_new0(virStorageAuthDef, 1); + + if (!(authdef->username = virXPathString("string(./@username)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing username for auth")); + goto cleanup; + } + + authdef->authType = VIR_STORAGE_AUTH_TYPE_NONE; + authtype = virXPathString("string(./@type)", ctxt); + if (authtype) { + /* Used by the storage pool instead of the secret type field + * to define whether chap or ceph being used + */ + if ((authdef->authType = virStorageAuthTypeFromString(authtype)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown auth type '%s'"), authtype); + goto cleanup; + } + } + + if (!(secretnode = virXPathNode("./secret ", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("Missing <secret> element in auth")); + goto cleanup; + } + + /* Used by the domain disk xml parsing in order to ensure the + * <secret type='%s' value matches the expected secret type for + * the style of disk (iscsi is chap, nbd is ceph). For some reason + * the virSecretUsageType{From|To}String() cannot be linked here + * and because only the domain parsing code cares - just keep + * it as a string. + */ + authdef->secrettype = virXMLPropString(secretnode, "type"); + + if (virSecretLookupParseSecret(secretnode, &authdef->seclookupdef) < 0) + goto cleanup; + + ret = g_steal_pointer(&authdef); + + cleanup: + + return ret; +} + + +void +virStorageAuthDefFormat(virBufferPtr buf, + virStorageAuthDefPtr authdef) +{ + if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) { + virBufferEscapeString(buf, "<auth username='%s'>\n", authdef->username); + } else { + virBufferAsprintf(buf, "<auth type='%s' ", + virStorageAuthTypeToString(authdef->authType)); + virBufferEscapeString(buf, "username='%s'>\n", authdef->username); + } + + virBufferAdjustIndent(buf, 2); + virSecretLookupFormatSecret(buf, authdef->secrettype, + &authdef->seclookupdef); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</auth>\n"); +} + + +void +virStoragePRDefFree(virStoragePRDefPtr prd) +{ + if (!prd) + return; + + VIR_FREE(prd->path); + VIR_FREE(prd->mgralias); + VIR_FREE(prd); +} + + +virStoragePRDefPtr +virStoragePRDefParseXML(xmlXPathContextPtr ctxt) +{ + virStoragePRDefPtr prd; + virStoragePRDefPtr ret = NULL; + g_autofree char *managed = NULL; + g_autofree char *type = NULL; + g_autofree char *path = NULL; + g_autofree char *mode = NULL; + + prd = g_new0(virStoragePRDef, 1); + + if (!(managed = virXPathString("string(./@managed)", ctxt))) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing @managed attribute for <reservations/>")); + goto cleanup; + } + + if ((prd->managed = virTristateBoolTypeFromString(managed)) <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid value for 'managed': %s"), managed); + goto cleanup; + } + + type = virXPathString("string(./source[1]/@type)", ctxt); + path = virXPathString("string(./source[1]/@path)", ctxt); + mode = virXPathString("string(./source[1]/@mode)", ctxt); + + if (prd->managed == VIR_TRISTATE_BOOL_NO || type || path || mode) { + if (!type) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing connection type for <reservations/>")); + goto cleanup; + } + + if (!path) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing path for <reservations/>")); + goto cleanup; + } + + if (!mode) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("missing connection mode for <reservations/>")); + goto cleanup; + } + } + + if (type && STRNEQ(type, "unix")) { + virReportError(VIR_ERR_XML_ERROR, + _("unsupported connection type for <reservations/>: %s"), + type); + goto cleanup; + } + + if (mode && STRNEQ(mode, "client")) { + virReportError(VIR_ERR_XML_ERROR, + _("unsupported connection mode for <reservations/>: %s"), + mode); + goto cleanup; + } + + prd->path = g_steal_pointer(&path); + ret = g_steal_pointer(&prd); + + cleanup: + virStoragePRDefFree(prd); + return ret; +} + + +void +virStoragePRDefFormat(virBufferPtr buf, + virStoragePRDefPtr prd, + bool migratable) +{ + virBufferAsprintf(buf, "<reservations managed='%s'", + virTristateBoolTypeToString(prd->managed)); + if (prd->path && + (prd->managed == VIR_TRISTATE_BOOL_NO || !migratable)) { + virBufferAddLit(buf, ">\n"); + virBufferAdjustIndent(buf, 2); + virBufferAddLit(buf, "<source type='unix'"); + virBufferEscapeString(buf, " path='%s'", prd->path); + virBufferAddLit(buf, " mode='client'/>\n"); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</reservations>\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } +} + + +bool +virStoragePRDefIsEqual(virStoragePRDefPtr a, + virStoragePRDefPtr b) +{ + if (!a && !b) + return true; + + if (!a || !b) + return false; + + if (a->managed != b->managed || + STRNEQ_NULLABLE(a->path, b->path)) + return false; + + return true; +} + + +bool +virStoragePRDefIsManaged(virStoragePRDefPtr prd) +{ + return prd && prd->managed == VIR_TRISTATE_BOOL_YES; +} + + +bool +virStorageSourceChainHasManagedPR(virStorageSourcePtr src) +{ + virStorageSourcePtr n; + + for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { + if (virStoragePRDefIsManaged(n->pr)) + return true; + } + + return false; +} + + +static virStoragePRDefPtr +virStoragePRDefCopy(virStoragePRDefPtr src) +{ + virStoragePRDefPtr copy = NULL; + virStoragePRDefPtr ret = NULL; + + copy = g_new0(virStoragePRDef, 1); + + copy->managed = src->managed; + + copy->path = g_strdup(src->path); + copy->mgralias = g_strdup(src->mgralias); + + ret = g_steal_pointer(©); + + virStoragePRDefFree(copy); + return ret; +} + + +static virStorageSourceNVMeDefPtr +virStorageSourceNVMeDefCopy(const virStorageSourceNVMeDef *src) +{ + virStorageSourceNVMeDefPtr ret = NULL; + + ret = g_new0(virStorageSourceNVMeDef, 1); + + ret->namespc = src->namespc; + ret->managed = src->managed; + virPCIDeviceAddressCopy(&ret->pciAddr, &src->pciAddr); + return ret; +} + + +static bool +virStorageSourceNVMeDefIsEqual(const virStorageSourceNVMeDef *a, + const virStorageSourceNVMeDef *b) +{ + if (!a && !b) + return true; + + if (!a || !b) + return false; + + if (a->namespc != b->namespc || + a->managed != b->managed || + !virPCIDeviceAddressEqual(&a->pciAddr, &b->pciAddr)) + return false; + + return true; +} + + +void +virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def); +} + + +bool +virStorageSourceChainHasNVMe(const virStorageSource *src) +{ + const virStorageSource *n; + + for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { + if (n->type == VIR_STORAGE_TYPE_NVME) + return true; + } + + return false; +} + + +virSecurityDeviceLabelDefPtr +virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, + const char *model) +{ + size_t i; + + for (i = 0; i < src->nseclabels; i++) { + if (STREQ_NULLABLE(src->seclabels[i]->model, model)) + return src->seclabels[i]; + } + + return NULL; +} + + +static void +virStorageSourceSeclabelsClear(virStorageSourcePtr def) +{ + size_t i; + + if (def->seclabels) { + for (i = 0; i < def->nseclabels; i++) + virSecurityDeviceLabelDefFree(def->seclabels[i]); + VIR_FREE(def->seclabels); + } +} + + +static int +virStorageSourceSeclabelsCopy(virStorageSourcePtr to, + const virStorageSource *from) +{ + size_t i; + + if (from->nseclabels == 0) + return 0; + + to->seclabels = g_new0(virSecurityDeviceLabelDefPtr, from->nseclabels); + to->nseclabels = from->nseclabels; + + for (i = 0; i < to->nseclabels; i++) { + if (!(to->seclabels[i] = virSecurityDeviceLabelDefCopy(from->seclabels[i]))) + goto error; + } + + return 0; + + error: + virStorageSourceSeclabelsClear(to); + return -1; +} + + +void +virStorageNetCookieDefFree(virStorageNetCookieDefPtr def) +{ + if (!def) + return; + + g_free(def->name); + g_free(def->value); + + g_free(def); +} + + +static void +virStorageSourceNetCookiesClear(virStorageSourcePtr src) +{ + size_t i; + + if (!src || !src->cookies) + return; + + for (i = 0; i < src->ncookies; i++) + virStorageNetCookieDefFree(src->cookies[i]); + + g_clear_pointer(&src->cookies, g_free); + src->ncookies = 0; +} + + +static void +virStorageSourceNetCookiesCopy(virStorageSourcePtr to, + const virStorageSource *from) +{ + size_t i; + + if (from->ncookies == 0) + return; + + to->cookies = g_new0(virStorageNetCookieDefPtr, from->ncookies); + to->ncookies = from->ncookies; + + for (i = 0; i < from->ncookies; i++) { + to->cookies[i]->name = g_strdup(from->cookies[i]->name); + to->cookies[i]->value = g_strdup(from->cookies[i]->value); + } +} + + +/* see https://tools.ietf.org/html/rfc6265#section-4.1.1 */ +static const char virStorageSourceCookieValueInvalidChars[] = + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + " \",;\\"; + +/* in addition cookie name can't contain these */ +static const char virStorageSourceCookieNameInvalidChars[] = + "()<>@:/[]?={}"; + +static int +virStorageSourceNetCookieValidate(virStorageNetCookieDefPtr def) +{ + g_autofree char *val = g_strdup(def->value); + const char *checkval = val; + size_t len = strlen(val); + + /* name must have at least 1 character */ + if (*(def->name) == '\0') { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("cookie name must not be empty")); + return -1; + } + + /* check invalid characters in name */ + if (virStringHasChars(def->name, virStorageSourceCookieValueInvalidChars) || + virStringHasChars(def->name, virStorageSourceCookieNameInvalidChars)) { + virReportError(VIR_ERR_XML_ERROR, + _("cookie name '%s' contains invalid characters"), + def->name); + return -1; + } + + /* check for optional quotes around the cookie value string */ + if (val[0] == '"') { + if (val[len - 1] != '"') { + virReportError(VIR_ERR_XML_ERROR, + _("value of cookie '%s' contains invalid characters"), + def->name); + return -1; + } + + val[len - 1] = '\0'; + checkval++; + } + + /* check invalid characters in value */ + if (virStringHasChars(checkval, virStorageSourceCookieValueInvalidChars)) { + virReportError(VIR_ERR_XML_ERROR, + _("value of cookie '%s' contains invalid characters"), + def->name); + return -1; + } + + return 0; +} + + +int +virStorageSourceNetCookiesValidate(virStorageSourcePtr src) +{ + size_t i; + size_t j; + + for (i = 0; i < src->ncookies; i++) { + if (virStorageSourceNetCookieValidate(src->cookies[i]) < 0) + return -1; + + for (j = i + 1; j < src->ncookies; j++) { + if (STREQ(src->cookies[i]->name, src->cookies[j]->name)) { + virReportError(VIR_ERR_XML_ERROR, _("duplicate cookie '%s'"), + src->cookies[i]->name); + return -1; + } + } + } + + return 0; +} + + +static virStorageTimestampsPtr +virStorageTimestampsCopy(const virStorageTimestamps *src) +{ + virStorageTimestampsPtr ret; + + ret = g_new0(virStorageTimestamps, 1); + + memcpy(ret, src, sizeof(*src)); + + return ret; +} + + +static virStoragePermsPtr +virStoragePermsCopy(const virStoragePerms *src) +{ + virStoragePermsPtr ret; + + ret = g_new0(virStoragePerms, 1); + + ret->mode = src->mode; + ret->uid = src->uid; + ret->gid = src->gid; + + ret->label = g_strdup(src->label); + + return ret; +} + + +static virStorageSourcePoolDefPtr +virStorageSourcePoolDefCopy(const virStorageSourcePoolDef *src) +{ + virStorageSourcePoolDefPtr ret; + + ret = g_new0(virStorageSourcePoolDef, 1); + + ret->voltype = src->voltype; + ret->pooltype = src->pooltype; + ret->actualtype = src->actualtype; + ret->mode = src->mode; + + ret->pool = g_strdup(src->pool); + ret->volume = g_strdup(src->volume); + + return ret; +} + + +static virStorageSourceSlicePtr +virStorageSourceSliceCopy(const virStorageSourceSlice *src) +{ + virStorageSourceSlicePtr ret = g_new0(virStorageSourceSlice, 1); + + ret->offset = src->offset; + ret->size = src->size; + ret->nodename = g_strdup(src->nodename); + + return ret; +} + + +static void +virStorageSourceSliceFree(virStorageSourceSlicePtr slice) +{ + if (!slice) + return; + + g_free(slice->nodename); + g_free(slice); +} + + +/** + * virStorageSourcePtr: + * + * Deep-copies a virStorageSource structure. If @backing chain is true + * then also copies the backing chain recursively, otherwise just + * the top element is copied. This function doesn't copy the + * storage driver access structure and thus the struct needs to be initialized + * separately. + */ +virStorageSourcePtr +virStorageSourceCopy(const virStorageSource *src, + bool backingChain) +{ + g_autoptr(virStorageSource) def = virStorageSourceNew(); + + def->id = src->id; + def->type = src->type; + def->protocol = src->protocol; + def->format = src->format; + def->capacity = src->capacity; + def->allocation = src->allocation; + def->has_allocation = src->has_allocation; + def->physical = src->physical; + def->readonly = src->readonly; + def->shared = src->shared; + def->haveTLS = src->haveTLS; + def->tlsFromConfig = src->tlsFromConfig; + def->detected = src->detected; + def->debugLevel = src->debugLevel; + def->debug = src->debug; + def->iomode = src->iomode; + def->cachemode = src->cachemode; + def->discard = src->discard; + def->detect_zeroes = src->detect_zeroes; + def->sslverify = src->sslverify; + def->readahead = src->readahead; + def->timeout = src->timeout; + def->metadataCacheMaxSize = src->metadataCacheMaxSize; + + /* storage driver metadata are not copied */ + def->drv = NULL; + + def->path = g_strdup(src->path); + def->volume = g_strdup(src->volume); + def->relPath = g_strdup(src->relPath); + def->backingStoreRaw = g_strdup(src->backingStoreRaw); + def->backingStoreRawFormat = src->backingStoreRawFormat; + def->snapshot = g_strdup(src->snapshot); + def->configFile = g_strdup(src->configFile); + def->nodeformat = g_strdup(src->nodeformat); + def->nodestorage = g_strdup(src->nodestorage); + def->compat = g_strdup(src->compat); + def->tlsAlias = g_strdup(src->tlsAlias); + def->tlsCertdir = g_strdup(src->tlsCertdir); + def->query = g_strdup(src->query); + + if (src->sliceStorage) + def->sliceStorage = virStorageSourceSliceCopy(src->sliceStorage); + + if (src->nhosts) { + if (!(def->hosts = virStorageNetHostDefCopy(src->nhosts, src->hosts))) + return NULL; + + def->nhosts = src->nhosts; + } + + virStorageSourceNetCookiesCopy(def, src); + + if (src->srcpool && + !(def->srcpool = virStorageSourcePoolDefCopy(src->srcpool))) + return NULL; + + if (src->features) + def->features = virBitmapNewCopy(src->features); + + if (src->encryption && + !(def->encryption = virStorageEncryptionCopy(src->encryption))) + return NULL; + + if (src->perms && + !(def->perms = virStoragePermsCopy(src->perms))) + return NULL; + + if (src->timestamps && + !(def->timestamps = virStorageTimestampsCopy(src->timestamps))) + return NULL; + + if (virStorageSourceSeclabelsCopy(def, src) < 0) + return NULL; + + if (src->auth && + !(def->auth = virStorageAuthDefCopy(src->auth))) + return NULL; + + if (src->pr && + !(def->pr = virStoragePRDefCopy(src->pr))) + return NULL; + + if (src->nvme) + def->nvme = virStorageSourceNVMeDefCopy(src->nvme); + + if (virStorageSourceInitiatorCopy(&def->initiator, &src->initiator) < 0) + return NULL; + + if (backingChain && src->backingStore) { + if (!(def->backingStore = virStorageSourceCopy(src->backingStore, + true))) + return NULL; + } + + /* ssh config passthrough for libguestfs */ + def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled; + def->ssh_user = g_strdup(src->ssh_user); + + def->nfs_user = g_strdup(src->nfs_user); + def->nfs_group = g_strdup(src->nfs_group); + def->nfs_uid = src->nfs_uid; + def->nfs_gid = src->nfs_gid; + + return g_steal_pointer(&def); +} + + +/** + * virStorageSourceIsSameLocation: + * + * Returns true if the sources @a and @b point to the same storage location. + * This does not compare any other configuration option + */ +bool +virStorageSourceIsSameLocation(virStorageSourcePtr a, + virStorageSourcePtr b) +{ + size_t i; + + /* there are multiple possibilities to define an empty source */ + if (virStorageSourceIsEmpty(a) && + virStorageSourceIsEmpty(b)) + return true; + + if (virStorageSourceGetActualType(a) != virStorageSourceGetActualType(b)) + return false; + + if (STRNEQ_NULLABLE(a->path, b->path) || + STRNEQ_NULLABLE(a->volume, b->volume) || + STRNEQ_NULLABLE(a->snapshot, b->snapshot)) + return false; + + if (a->type == VIR_STORAGE_TYPE_NETWORK) { + if (a->protocol != b->protocol || + a->nhosts != b->nhosts) + return false; + + for (i = 0; i < a->nhosts; i++) { + if (a->hosts[i].transport != b->hosts[i].transport || + a->hosts[i].port != b->hosts[i].port || + STRNEQ_NULLABLE(a->hosts[i].name, b->hosts[i].name) || + STRNEQ_NULLABLE(a->hosts[i].socket, b->hosts[i].socket)) + return false; + } + } + + if (a->type == VIR_STORAGE_TYPE_NVME && + !virStorageSourceNVMeDefIsEqual(a->nvme, b->nvme)) + return false; + + return true; +} + + +/** + * virStorageSourceInitChainElement: + * @newelem: New backing chain element disk source + * @old: Existing top level disk source + * @transferLabels: Transfer security labels. + * + * Transfers relevant information from the existing disk source to the new + * backing chain element if they weren't supplied so that labelling info + * and possibly other stuff is correct. + * + * If @transferLabels is true, security labels from the existing disk are copied + * to the new disk. Otherwise the default domain imagelabel label will be used. + * + * Returns 0 on success, -1 on error. + */ +int +virStorageSourceInitChainElement(virStorageSourcePtr newelem, + virStorageSourcePtr old, + bool transferLabels) +{ + if (transferLabels && + !newelem->seclabels && + virStorageSourceSeclabelsCopy(newelem, old) < 0) + return -1; + + newelem->shared = old->shared; + newelem->readonly = old->readonly; + + return 0; +} + + +void +virStorageSourcePoolDefFree(virStorageSourcePoolDefPtr def) +{ + if (!def) + return; + + VIR_FREE(def->pool); + VIR_FREE(def->volume); + + VIR_FREE(def); +} + + +/** + * virStorageSourceGetActualType: + * @def: storage source definition + * + * Returns type of @def. In case when the type is VIR_STORAGE_TYPE_VOLUME + * and virDomainDiskTranslateSourcePool was called on @def the actual type + * of the storage volume is returned rather than VIR_STORAGE_TYPE_VOLUME. + */ +int +virStorageSourceGetActualType(const virStorageSource *def) +{ + if (def->type == VIR_STORAGE_TYPE_VOLUME && + def->srcpool && + def->srcpool->actualtype != VIR_STORAGE_TYPE_NONE) + return def->srcpool->actualtype; + + return def->type; +} + + +bool +virStorageSourceIsLocalStorage(const virStorageSource *src) +{ + virStorageType type = virStorageSourceGetActualType(src); + + switch (type) { + case VIR_STORAGE_TYPE_FILE: + case VIR_STORAGE_TYPE_BLOCK: + case VIR_STORAGE_TYPE_DIR: + return true; + + case VIR_STORAGE_TYPE_NETWORK: + case VIR_STORAGE_TYPE_VOLUME: + /* While NVMe disks are local, they are not accessible via src->path. + * Therefore, we have to return false here. */ + case VIR_STORAGE_TYPE_NVME: + case VIR_STORAGE_TYPE_LAST: + case VIR_STORAGE_TYPE_NONE: + return false; + } + + return false; +} + + +/** + * virStorageSourceIsEmpty: + * + * @src: disk source to check + * + * Returns true if the guest disk has no associated host storage source + * (such as an empty cdrom drive). + */ +bool +virStorageSourceIsEmpty(virStorageSourcePtr src) +{ + if (virStorageSourceIsLocalStorage(src) && !src->path) + return true; + + if (src->type == VIR_STORAGE_TYPE_NONE) + return true; + + if (src->type == VIR_STORAGE_TYPE_NETWORK && + src->protocol == VIR_STORAGE_NET_PROTOCOL_NONE) + return true; + + return false; +} + + +/** + * virStorageSourceIsBlockLocal: + * @src: disk source definition + * + * Returns true if @src describes a locally accessible block storage source. + * This includes block devices and host-mapped iSCSI volumes. + */ +bool +virStorageSourceIsBlockLocal(const virStorageSource *src) +{ + return virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_BLOCK; +} + + +/** + * virStorageSourceBackingStoreClear: + * + * @src: disk source to clear + * + * Clears information about backing store of the current storage file. + */ +void +virStorageSourceBackingStoreClear(virStorageSourcePtr def) +{ + if (!def) + return; + + VIR_FREE(def->relPath); + VIR_FREE(def->backingStoreRaw); + + /* recursively free backing chain */ + virObjectUnref(def->backingStore); + def->backingStore = NULL; +} + + +void +virStorageSourceClear(virStorageSourcePtr def) +{ + if (!def) + return; + + VIR_FREE(def->path); + VIR_FREE(def->volume); + VIR_FREE(def->snapshot); + VIR_FREE(def->configFile); + VIR_FREE(def->query); + virStorageSourceNetCookiesClear(def); + virStorageSourcePoolDefFree(def->srcpool); + virBitmapFree(def->features); + VIR_FREE(def->compat); + virStorageEncryptionFree(def->encryption); + virStoragePRDefFree(def->pr); + virStorageSourceNVMeDefFree(def->nvme); + virStorageSourceSeclabelsClear(def); + virStoragePermsFree(def->perms); + VIR_FREE(def->timestamps); + + virStorageSourceSliceFree(def->sliceStorage); + + virStorageNetHostDefFree(def->nhosts, def->hosts); + virStorageAuthDefFree(def->auth); + virObjectUnref(def->privateData); + + VIR_FREE(def->nodestorage); + VIR_FREE(def->nodeformat); + + virStorageSourceBackingStoreClear(def); + + VIR_FREE(def->tlsAlias); + VIR_FREE(def->tlsCertdir); + + VIR_FREE(def->ssh_user); + + VIR_FREE(def->nfs_user); + VIR_FREE(def->nfs_group); + + virStorageSourceInitiatorClear(&def->initiator); + + /* clear everything except the class header as the object APIs + * will break otherwise */ + memset((char *) def + sizeof(def->parent), 0, + sizeof(*def) - sizeof(def->parent)); +} + + +static void +virStorageSourceDispose(void *obj) +{ + virStorageSourcePtr src = obj; + + virStorageSourceClear(src); +} + + +static int +virStorageSourceOnceInit(void) +{ + if (!VIR_CLASS_NEW(virStorageSource, virClassForObject())) + return -1; + + return 0; +} + + +VIR_ONCE_GLOBAL_INIT(virStorageSource); + + +virStorageSourcePtr +virStorageSourceNew(void) +{ + virStorageSourcePtr ret; + + if (virStorageSourceInitialize() < 0) + abort(); + + if (!(ret = virObjectNew(virStorageSourceClass))) + abort(); + + return ret; +} + + +/** + * virStorageSourceIsRelative: + * @src: storage source to check + * + * Returns true if given storage source definition is a relative path. + */ +bool +virStorageSourceIsRelative(virStorageSourcePtr src) +{ + virStorageType actual_type = virStorageSourceGetActualType(src); + + if (!src->path) + return false; + + switch (actual_type) { + case VIR_STORAGE_TYPE_FILE: + case VIR_STORAGE_TYPE_BLOCK: + case VIR_STORAGE_TYPE_DIR: + return src->path[0] != '/'; + + case VIR_STORAGE_TYPE_NETWORK: + case VIR_STORAGE_TYPE_VOLUME: + case VIR_STORAGE_TYPE_NVME: + case VIR_STORAGE_TYPE_NONE: + case VIR_STORAGE_TYPE_LAST: + return false; + } + + return false; +} + + +static unsigned int +virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol) +{ + switch (protocol) { + case VIR_STORAGE_NET_PROTOCOL_HTTP: + return 80; + + case VIR_STORAGE_NET_PROTOCOL_HTTPS: + return 443; + + case VIR_STORAGE_NET_PROTOCOL_FTP: + return 21; + + case VIR_STORAGE_NET_PROTOCOL_FTPS: + return 990; + + case VIR_STORAGE_NET_PROTOCOL_TFTP: + return 69; + + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + return 7000; + + case VIR_STORAGE_NET_PROTOCOL_NBD: + return 10809; + + case VIR_STORAGE_NET_PROTOCOL_SSH: + return 22; + + case VIR_STORAGE_NET_PROTOCOL_ISCSI: + return 3260; + + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + return 24007; + + case VIR_STORAGE_NET_PROTOCOL_RBD: + /* we don't provide a default for RBD */ + return 0; + + case VIR_STORAGE_NET_PROTOCOL_VXHS: + return 9999; + + case VIR_STORAGE_NET_PROTOCOL_NFS: + /* Port is not supported by NFS, so no default is provided */ + return 0; + + case VIR_STORAGE_NET_PROTOCOL_LAST: + case VIR_STORAGE_NET_PROTOCOL_NONE: + return 0; + } + + return 0; +} + + +void +virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src) +{ + size_t i; + + for (i = 0; i < src->nhosts; i++) { + if (src->hosts[i].transport == VIR_STORAGE_NET_HOST_TRANS_TCP && + src->hosts[i].port == 0) + src->hosts[i].port = virStorageSourceNetworkDefaultPort(src->protocol); + } +} + + +int +virStorageSourcePrivateDataParseRelPath(xmlXPathContextPtr ctxt, + virStorageSourcePtr src) +{ + src->relPath = virXPathString("string(./relPath)", ctxt); + return 0; +} + + +int +virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src, + virBufferPtr buf) +{ + if (src->relPath) + virBufferEscapeString(buf, "<relPath>%s</relPath>\n", src->relPath); + + return 0; +} + + +void +virStorageSourceInitiatorParseXML(xmlXPathContextPtr ctxt, + virStorageSourceInitiatorDefPtr initiator) +{ + initiator->iqn = virXPathString("string(./initiator/iqn/@name)", ctxt); +} + + +void +virStorageSourceInitiatorFormatXML(virStorageSourceInitiatorDefPtr initiator, + virBufferPtr buf) +{ + if (!initiator->iqn) + return; + + virBufferAddLit(buf, "<initiator>\n"); + virBufferAdjustIndent(buf, 2); + virBufferEscapeString(buf, "<iqn name='%s'/>\n", initiator->iqn); + virBufferAdjustIndent(buf, -2); + virBufferAddLit(buf, "</initiator>\n"); +} + + +int +virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest, + const virStorageSourceInitiatorDef *src) +{ + dest->iqn = g_strdup(src->iqn); + return 0; +} + + +void +virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator) +{ + VIR_FREE(initiator->iqn); +} diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h new file mode 100644 index 0000000000..6f39ab4bd0 --- /dev/null +++ b/src/conf/storage_source_conf.h @@ -0,0 +1,537 @@ +/* + * storage_source_conf.h: file utility functions for FS storage backend + * + * Copyright (C) 2007-2009, 2012-2016 Red Hat, Inc. + * Copyright (C) 2007-2008 Daniel P. Berrange + * + * 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/>. + */ + +#pragma once + +#include "virbitmap.h" +#include "virenum.h" +#include "virobject.h" +#include "virpci.h" +#include "virseclabel.h" +#include "virsecret.h" +#include "virstorageencryption.h" + +/* Types of disk backends (host resource). Comparable to the public + * virStorageVolType, except we have an undetermined state, don't have + * a netdir type, and add a volume type for reference through a + * storage pool. */ +typedef enum { + VIR_STORAGE_TYPE_NONE, + VIR_STORAGE_TYPE_FILE, + VIR_STORAGE_TYPE_BLOCK, + VIR_STORAGE_TYPE_DIR, + VIR_STORAGE_TYPE_NETWORK, + VIR_STORAGE_TYPE_VOLUME, + VIR_STORAGE_TYPE_NVME, + + VIR_STORAGE_TYPE_LAST +} virStorageType; + +VIR_ENUM_DECL(virStorage); + + +typedef enum { + VIR_STORAGE_FILE_AUTO_SAFE = -2, + VIR_STORAGE_FILE_AUTO = -1, + VIR_STORAGE_FILE_NONE = 0, + VIR_STORAGE_FILE_RAW, + VIR_STORAGE_FILE_DIR, + VIR_STORAGE_FILE_BOCHS, + VIR_STORAGE_FILE_CLOOP, + VIR_STORAGE_FILE_DMG, + VIR_STORAGE_FILE_ISO, + VIR_STORAGE_FILE_VPC, + VIR_STORAGE_FILE_VDI, + + /* Not direct file formats, but used for various drivers */ + VIR_STORAGE_FILE_FAT, + VIR_STORAGE_FILE_VHD, + VIR_STORAGE_FILE_PLOOP, + + /* Not a format, but a marker: all formats below this point have + * libvirt support for following a backing chain */ + VIR_STORAGE_FILE_BACKING, + + VIR_STORAGE_FILE_COW = VIR_STORAGE_FILE_BACKING, + VIR_STORAGE_FILE_QCOW, + VIR_STORAGE_FILE_QCOW2, + VIR_STORAGE_FILE_QED, + VIR_STORAGE_FILE_VMDK, + + VIR_STORAGE_FILE_LAST, +} virStorageFileFormat; + +VIR_ENUM_DECL(virStorageFileFormat); + + +typedef enum { + VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS = 0, + + VIR_STORAGE_FILE_FEATURE_LAST +} virStorageFileFeature; + +VIR_ENUM_DECL(virStorageFileFeature); + + +typedef struct _virStoragePerms virStoragePerms; +typedef virStoragePerms *virStoragePermsPtr; +struct _virStoragePerms { + mode_t mode; + uid_t uid; + gid_t gid; + char *label; +}; + + +typedef struct _virStorageTimestamps virStorageTimestamps; +typedef virStorageTimestamps *virStorageTimestampsPtr; +struct _virStorageTimestamps { + struct timespec atime; + struct timespec btime; /* birth time unknown if btime.tv_nsec == -1 */ + struct timespec ctime; + struct timespec mtime; +}; + + +/* Information related to network storage */ +typedef enum { + VIR_STORAGE_NET_PROTOCOL_NONE, + VIR_STORAGE_NET_PROTOCOL_NBD, + VIR_STORAGE_NET_PROTOCOL_RBD, + VIR_STORAGE_NET_PROTOCOL_SHEEPDOG, + VIR_STORAGE_NET_PROTOCOL_GLUSTER, + VIR_STORAGE_NET_PROTOCOL_ISCSI, + VIR_STORAGE_NET_PROTOCOL_HTTP, + VIR_STORAGE_NET_PROTOCOL_HTTPS, + VIR_STORAGE_NET_PROTOCOL_FTP, + VIR_STORAGE_NET_PROTOCOL_FTPS, + VIR_STORAGE_NET_PROTOCOL_TFTP, + VIR_STORAGE_NET_PROTOCOL_SSH, + VIR_STORAGE_NET_PROTOCOL_VXHS, + VIR_STORAGE_NET_PROTOCOL_NFS, + + VIR_STORAGE_NET_PROTOCOL_LAST +} virStorageNetProtocol; + +VIR_ENUM_DECL(virStorageNetProtocol); + + +typedef enum { + VIR_STORAGE_NET_HOST_TRANS_TCP, + VIR_STORAGE_NET_HOST_TRANS_UNIX, + VIR_STORAGE_NET_HOST_TRANS_RDMA, + + VIR_STORAGE_NET_HOST_TRANS_LAST +} virStorageNetHostTransport; + +VIR_ENUM_DECL(virStorageNetHostTransport); + + +typedef struct _virStorageNetHostDef virStorageNetHostDef; +typedef virStorageNetHostDef *virStorageNetHostDefPtr; +struct _virStorageNetHostDef { + char *name; + unsigned int port; + int transport; /* virStorageNetHostTransport */ + char *socket; /* path to unix socket */ +}; + + +typedef struct _virStorageNetCookieDef virStorageNetCookieDef; +typedef virStorageNetCookieDef *virStorageNetCookieDefPtr; +struct _virStorageNetCookieDef { + char *name; + char *value; +}; + + +void +virStorageNetCookieDefFree(virStorageNetCookieDefPtr def); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageNetCookieDef, virStorageNetCookieDefFree); + + +/* Information for a storage volume from a virStoragePool */ + +/* + * Used for volume "type" disk to indicate how to represent + * the disk source if the specified "pool" is of iscsi type. + */ +typedef enum { + VIR_STORAGE_SOURCE_POOL_MODE_DEFAULT = 0, + + /* Use the path as it shows up on host, e.g. + * /dev/disk/by-path/ip-$ip-iscsi-$iqn:iscsi.iscsi-pool0-lun-1 + */ + VIR_STORAGE_SOURCE_POOL_MODE_HOST, + + /* Use the URI from the storage pool source element host attribute. E.g. + * file=iscsi://demo.org:6000/iqn.1992-01.com.example/1. + */ + VIR_STORAGE_SOURCE_POOL_MODE_DIRECT, + + VIR_STORAGE_SOURCE_POOL_MODE_LAST +} virStorageSourcePoolMode; + +VIR_ENUM_DECL(virStorageSourcePoolMode); + + +typedef struct _virStorageSourcePoolDef virStorageSourcePoolDef; +typedef virStorageSourcePoolDef *virStorageSourcePoolDefPtr; +struct _virStorageSourcePoolDef { + char *pool; /* pool name */ + char *volume; /* volume name */ + int voltype; /* virStorageVolType, internal only */ + int pooltype; /* virStoragePoolType from storage_conf.h, internal only */ + int actualtype; /* virStorageType, internal only */ + int mode; /* virStorageSourcePoolMode, currently makes sense only for iscsi pool */ +}; + + +typedef enum { + VIR_STORAGE_AUTH_TYPE_NONE, + VIR_STORAGE_AUTH_TYPE_CHAP, + VIR_STORAGE_AUTH_TYPE_CEPHX, + + VIR_STORAGE_AUTH_TYPE_LAST, +} virStorageAuthType; + +VIR_ENUM_DECL(virStorageAuth); + + +typedef struct _virStorageAuthDef virStorageAuthDef; +typedef virStorageAuthDef *virStorageAuthDefPtr; +struct _virStorageAuthDef { + char *username; + char *secrettype; /* <secret type='%s' for disk source */ + int authType; /* virStorageAuthType */ + virSecretLookupTypeDef seclookupdef; +}; + + +typedef struct _virStoragePRDef virStoragePRDef; +typedef virStoragePRDef *virStoragePRDefPtr; +struct _virStoragePRDef { + int managed; /* enum virTristateBool */ + char *path; + + /* manager object alias */ + char *mgralias; +}; + + +typedef struct _virStorageSourceInitiatorDef virStorageSourceInitiatorDef; +typedef virStorageSourceInitiatorDef *virStorageSourceInitiatorDefPtr; +struct _virStorageSourceInitiatorDef { + char *iqn; /* Initiator IQN */ +}; + + +typedef struct _virStorageSourceNVMeDef virStorageSourceNVMeDef; +typedef virStorageSourceNVMeDef *virStorageSourceNVMeDefPtr; +struct _virStorageSourceNVMeDef { + unsigned long long namespc; + int managed; /* enum virTristateBool */ + virPCIDeviceAddress pciAddr; + + /* Don't forget to update virStorageSourceNVMeDefCopy */ +}; + + +typedef struct _virStorageSourceSlice virStorageSourceSlice; +typedef virStorageSourceSlice *virStorageSourceSlicePtr; +struct _virStorageSourceSlice { + unsigned long long offset; + unsigned long long size; + char *nodename; +}; + + +typedef struct _virStorageSource virStorageSource; +typedef virStorageSource *virStorageSourcePtr; + +/* Stores information related to a host resource. In the case of backing + * chains, multiple source disks join to form a single guest view. + * + * IMPORTANT: When adding fields to this struct it's also necessary to add + * appropriate code to the virStorageSourceCopy deep copy function */ +struct _virStorageSource { + virObject parent; + + unsigned int id; /* backing chain identifier, 0 is unset */ + int type; /* virStorageType */ + char *path; + int protocol; /* virStorageNetProtocol */ + char *volume; /* volume name for remote storage */ + char *snapshot; /* for storage systems supporting internal snapshots */ + char *configFile; /* some storage systems use config file as part of + the source definition */ + char *query; /* query string for HTTP based protocols */ + size_t nhosts; + virStorageNetHostDefPtr hosts; + size_t ncookies; + virStorageNetCookieDefPtr *cookies; + virStorageSourcePoolDefPtr srcpool; + virStorageAuthDefPtr auth; + virStorageEncryptionPtr encryption; + virStoragePRDefPtr pr; + virTristateBool sslverify; + /* both values below have 0 as default value */ + unsigned long long readahead; /* size of the readahead buffer in bytes */ + unsigned long long timeout; /* connection timeout in seconds */ + + virStorageSourceNVMeDefPtr nvme; /* type == VIR_STORAGE_TYPE_NVME */ + + virStorageSourceInitiatorDef initiator; + + virObjectPtr privateData; + + int format; /* virStorageFileFormat in domain backing chains, but + * pool-specific enum for storage volumes */ + virBitmapPtr features; + char *compat; + bool nocow; + bool sparse; + + virStorageSourceSlicePtr sliceStorage; + + virStoragePermsPtr perms; + virStorageTimestampsPtr timestamps; + unsigned long long capacity; /* in bytes, 0 if unknown */ + unsigned long long allocation; /* in bytes, 0 if unknown */ + unsigned long long physical; /* in bytes, 0 if unknown */ + unsigned long long clusterSize; /* in bytes, 0 if unknown */ + bool has_allocation; /* Set to true when provided in XML */ + + unsigned long long metadataCacheMaxSize; /* size of the metadata cache in bytes */ + + size_t nseclabels; + virSecurityDeviceLabelDefPtr *seclabels; + + /* Don't ever write to the image */ + bool readonly; + + /* image is shared across hosts */ + bool shared; + + /* backing chain of the storage source */ + virStorageSourcePtr backingStore; + + /* metadata for storage driver access to remote and local volumes */ + void *drv; + + /* metadata about storage image which need separate fields */ + /* Relative name by which this image was opened from its parent, or NULL + * if this image was opened by absolute name */ + char *relPath; + /* Name of the child backing store recorded in metadata of the + * current file. */ + char *backingStoreRaw; + virStorageFileFormat backingStoreRawFormat; + + /* metadata that allows identifying given storage source */ + char *nodeformat; /* name of the format handler object */ + char *nodestorage; /* name of the storage object */ + + /* An optional setting to enable usage of TLS for the storage source */ + int haveTLS; /* enum virTristateBool */ + + /* Indication whether the haveTLS value was altered due to qemu.conf + * setting when haveTLS is missing from the domain config file */ + bool tlsFromConfig; + + /* If TLS is used, then mgmt of the TLS credentials occurs via an + * object that is generated using a specific alias for a specific + * certificate directory with listen and verify bools. */ + char *tlsAlias; + char *tlsCertdir; + + bool detected; /* true if this entry was not provided by the user */ + + unsigned int debugLevel; + bool debug; + + /* Libvirt currently stores the following properties in virDomainDiskDef. + * These instances are currently just copies from the parent definition and + * are not mapped back to the XML */ + int iomode; /* enum virDomainDiskIo */ + int cachemode; /* enum virDomainDiskCache */ + int discard; /* enum virDomainDiskDiscard */ + int detect_zeroes; /* enum virDomainDiskDetectZeroes */ + + bool floppyimg; /* set to true if the storage source is going to be used + as a source for floppy drive */ + + bool hostcdrom; /* backing device is a cdrom */ + + /* passthrough variables for the ssh driver which we don't handle properly */ + /* these must not be used apart from formatting the output JSON in the qemu driver */ + char *ssh_user; + bool ssh_host_key_check_disabled; + + /* nfs_user and nfs_group store the strings passed in by the user for NFS params. + * nfs_uid and nfs_gid represent the converted/looked up ID numbers which are used + * during run time, and are not based on the configuration */ + char *nfs_user; + char *nfs_group; + uid_t nfs_uid; + gid_t nfs_gid; +}; + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); + +void +virStorageAuthDefFree(virStorageAuthDefPtr def); + +virStorageAuthDefPtr +virStorageAuthDefCopy(const virStorageAuthDef *src); + +virStorageAuthDefPtr +virStorageAuthDefParse(xmlNodePtr node, + xmlXPathContextPtr ctxt); + +void +virStorageAuthDefFormat(virBufferPtr buf, + virStorageAuthDefPtr authdef); + +void +virStoragePRDefFree(virStoragePRDefPtr prd); + +virStoragePRDefPtr +virStoragePRDefParseXML(xmlXPathContextPtr ctxt); + +void +virStoragePRDefFormat(virBufferPtr buf, + virStoragePRDefPtr prd, + bool migratable); + +bool +virStoragePRDefIsEqual(virStoragePRDefPtr a, + virStoragePRDefPtr b); + +bool +virStoragePRDefIsManaged(virStoragePRDefPtr prd); + +bool +virStorageSourceChainHasManagedPR(virStorageSourcePtr src); + +void +virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSourceNVMeDef, virStorageSourceNVMeDefFree); + +bool +virStorageSourceChainHasNVMe(const virStorageSource *src); + +virSecurityDeviceLabelDefPtr +virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, + const char *model); + +void +virStorageNetHostDefClear(virStorageNetHostDefPtr def); + +void +virStorageNetHostDefFree(size_t nhosts, + virStorageNetHostDefPtr hosts); + +virStorageNetHostDefPtr +virStorageNetHostDefCopy(size_t nhosts, + virStorageNetHostDefPtr hosts); + +int +virStorageSourceInitChainElement(virStorageSourcePtr newelem, + virStorageSourcePtr old, + bool force); + +void +virStorageSourcePoolDefFree(virStorageSourcePoolDefPtr def); + +void +virStorageSourceClear(virStorageSourcePtr def); + +int +virStorageSourceGetActualType(const virStorageSource *def); + +bool +virStorageSourceIsLocalStorage(const virStorageSource *src); + +bool +virStorageSourceIsEmpty(virStorageSourcePtr src); + +bool +virStorageSourceIsBlockLocal(const virStorageSource *src); + +virStorageSourcePtr +virStorageSourceNew(void); + +void +virStorageSourceBackingStoreClear(virStorageSourcePtr def); + +int +virStorageSourceNetCookiesValidate(virStorageSourcePtr src); + +virStorageSourcePtr +virStorageSourceCopy(const virStorageSource *src, + bool backingChain) + ATTRIBUTE_NONNULL(1); + +bool +virStorageSourceIsSameLocation(virStorageSourcePtr a, + virStorageSourcePtr b) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +bool +virStorageSourceIsRelative(virStorageSourcePtr src); + +void +virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src) + ATTRIBUTE_NONNULL(1); + +bool +virStorageSourceIsBacking(const virStorageSource *src); + +bool +virStorageSourceHasBacking(const virStorageSource *src); + +int +virStorageSourcePrivateDataParseRelPath(xmlXPathContextPtr ctxt, + virStorageSourcePtr src); + +int +virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src, + virBufferPtr buf); + +void +virStorageSourceInitiatorParseXML(xmlXPathContextPtr ctxt, + virStorageSourceInitiatorDefPtr initiator); + +void +virStorageSourceInitiatorFormatXML(virStorageSourceInitiatorDefPtr initiator, + virBufferPtr buf); + +int +virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest, + const virStorageSourceInitiatorDef *src); + +void +virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageAuthDef, virStorageAuthDefFree); diff --git a/src/esx/esx_storage_backend_iscsi.c b/src/esx/esx_storage_backend_iscsi.c index edbc65f5c0..4d16ba2520 100644 --- a/src/esx/esx_storage_backend_iscsi.c +++ b/src/esx/esx_storage_backend_iscsi.c @@ -28,7 +28,7 @@ #include "viralloc.h" #include "viruuid.h" #include "storage_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "esx_storage_backend_iscsi.h" #include "esx_private.h" #include "esx_vi.h" diff --git a/src/esx/esx_storage_backend_vmfs.c b/src/esx/esx_storage_backend_vmfs.c index c7a7863a61..27d8016194 100644 --- a/src/esx/esx_storage_backend_vmfs.c +++ b/src/esx/esx_storage_backend_vmfs.c @@ -32,7 +32,7 @@ #include "virlog.h" #include "viruuid.h" #include "storage_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "esx_storage_backend_vmfs.h" #include "esx_private.h" #include "esx_vi.h" diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b49eee3750..b13d0db209 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1053,6 +1053,58 @@ virStoragePoolEventRefreshNew; virStoragePoolEventStateRegisterID; +# conf/storage_source_conf.h +virStorageAuthDefCopy; +virStorageAuthDefFormat; +virStorageAuthDefFree; +virStorageAuthDefParse; +virStorageFileFeatureTypeFromString; +virStorageFileFeatureTypeToString; +virStorageFileFormatTypeFromString; +virStorageFileFormatTypeToString; +virStorageNetHostDefClear; +virStorageNetHostDefCopy; +virStorageNetHostDefFree; +virStorageNetHostTransportTypeFromString; +virStorageNetHostTransportTypeToString; +virStorageNetProtocolTypeToString; +virStoragePRDefFormat; +virStoragePRDefFree; +virStoragePRDefIsEqual; +virStoragePRDefIsManaged; +virStoragePRDefParseXML; +virStorageSourceBackingStoreClear; +virStorageSourceChainHasManagedPR; +virStorageSourceChainHasNVMe; +virStorageSourceClear; +virStorageSourceCopy; +virStorageSourceGetActualType; +virStorageSourceGetSecurityLabelDef; +virStorageSourceHasBacking; +virStorageSourceInitChainElement; +virStorageSourceInitiatorClear; +virStorageSourceInitiatorCopy; +virStorageSourceInitiatorFormatXML; +virStorageSourceInitiatorParseXML; +virStorageSourceIsBacking; +virStorageSourceIsBlockLocal; +virStorageSourceIsEmpty; +virStorageSourceIsLocalStorage; +virStorageSourceIsRelative; +virStorageSourceIsSameLocation; +virStorageSourceNetCookiesValidate; +virStorageSourceNetworkAssignDefaultPorts; +virStorageSourceNew; +virStorageSourceNVMeDefFree; +virStorageSourcePoolDefFree; +virStorageSourcePoolModeTypeFromString; +virStorageSourcePoolModeTypeToString; +virStorageSourcePrivateDataFormatRelPath; +virStorageSourcePrivateDataParseRelPath; +virStorageTypeFromString; +virStorageTypeToString; + + # conf/virchrdev.h virChrdevAlloc; virChrdevFree; @@ -3161,62 +3213,13 @@ virStorageEncryptionParseNode; # util/virstoragefile.h -virStorageAuthDefCopy; -virStorageAuthDefFormat; -virStorageAuthDefFree; -virStorageAuthDefParse; virStorageFileCanonicalizePath; -virStorageFileFeatureTypeFromString; -virStorageFileFeatureTypeToString; -virStorageFileFormatTypeFromString; -virStorageFileFormatTypeToString; virStorageFileGetNPIVKey; virStorageFileGetSCSIKey; virStorageFileParseBackingStoreStr; virStorageFileParseChainIndex; virStorageIsFile; virStorageIsRelative; -virStorageNetHostDefClear; -virStorageNetHostDefCopy; -virStorageNetHostDefFree; -virStorageNetHostTransportTypeFromString; -virStorageNetHostTransportTypeToString; -virStorageNetProtocolTypeToString; -virStoragePRDefFormat; -virStoragePRDefFree; -virStoragePRDefIsEqual; -virStoragePRDefIsManaged; -virStoragePRDefParseXML; -virStorageSourceBackingStoreClear; -virStorageSourceChainHasManagedPR; -virStorageSourceChainHasNVMe; -virStorageSourceClear; -virStorageSourceCopy; -virStorageSourceGetActualType; -virStorageSourceGetSecurityLabelDef; -virStorageSourceHasBacking; -virStorageSourceInitChainElement; -virStorageSourceInitiatorClear; -virStorageSourceInitiatorCopy; -virStorageSourceInitiatorFormatXML; -virStorageSourceInitiatorParseXML; -virStorageSourceIsBacking; -virStorageSourceIsBlockLocal; -virStorageSourceIsEmpty; -virStorageSourceIsLocalStorage; -virStorageSourceIsRelative; -virStorageSourceIsSameLocation; -virStorageSourceNetCookiesValidate; -virStorageSourceNetworkAssignDefaultPorts; -virStorageSourceNew; -virStorageSourceNVMeDefFree; -virStorageSourcePoolDefFree; -virStorageSourcePoolModeTypeFromString; -virStorageSourcePoolModeTypeToString; -virStorageSourcePrivateDataFormatRelPath; -virStorageSourcePrivateDataParseRelPath; -virStorageTypeFromString; -virStorageTypeToString; # util/virstring.h diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index 72ca781d8b..4a07f6a5f4 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -30,12 +30,12 @@ #include "qemu_command.h" #include "storage_source.h" +#include "storage_source_conf.h" #include "virerror.h" #include "virlog.h" #include "virbuffer.h" #include "viralloc.h" #include "virxml.h" -#include "virstoragefile.h" #include "virstring.h" #include "backup_conf.h" #include "virdomaincheckpointobjlist.h" diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 0d00dbc947..582fe45c66 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -32,8 +32,8 @@ #include "conf/domain_conf.h" #include "conf/domain_event.h" +#include "storage_source_conf.h" #include "virlog.h" -#include "virstoragefile.h" #include "virthread.h" #include "virtime.h" #include "locking/domain_lock.h" diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2506248866..1ec302d4ac 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -53,7 +53,7 @@ #include "virnetdevtap.h" #include "virnetdevopenvswitch.h" #include "device_conf.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "virtpm.h" #include "virscsi.h" #include "virnuma.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 5363af3f56..8048c86632 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -83,6 +83,7 @@ #include "domain_nwfilter.h" #include "virhook.h" #include "virstoragefile.h" +#include "storage_source_conf.h" #include "storage_file_probe.h" #include "storage_source.h" #include "virfile.h" diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index f1fa5986e1..99950a1360 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -52,8 +52,8 @@ #include "virnetdevopenvswitch.h" #include "virnetdevmidonet.h" #include "device_conf.h" -#include "virstoragefile.h" #include "storage_source.h" +#include "storage_source_conf.h" #include "virstring.h" #include "virtime.h" #include "virqemu.h" diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index 5353c7ee01..0adfdb9351 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -52,7 +52,7 @@ #include "virtime.h" #include "locking/domain_lock.h" #include "rpc/virnetsocket.h" -#include "virstoragefile.h" +#include "storage_source_conf.h" #include "viruri.h" #include "virhook.h" #include "virstring.h" diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c index 2bce445575..83a4b8602a 100644 --- a/src/storage/storage_backend.c +++ b/src/storage/storage_backend.c @@ -27,8 +27,8 @@ #include "virerror.h" #include "viralloc.h" #include "internal.h" -#include "virstoragefile.h" #include "storage_backend.h" +#include "storage_source_conf.h" #include "virlog.h" #include "virmodule.h" #include "virfile.h" diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 04f9a442f2..10c04e1257 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -65,6 +65,7 @@ #include "storage_file_probe.h" #include "storage_util.h" #include "storage_source.h" +#include "storage_source_conf.h" #include "virlog.h" #include "virfile.h" #include "virjson.h" diff --git a/src/storage_file/meson.build b/src/storage_file/meson.build index eb9453e7b0..c97c7f8009 100644 --- a/src/storage_file/meson.build +++ b/src/storage_file/meson.build @@ -22,6 +22,9 @@ virt_storage_file_lib = static_library( dependencies: [ src_dep, ], + include_directories: [ + conf_inc_dir, + ], ) libvirt_libs += virt_storage_file_lib diff --git a/src/storage_file/storage_file_backend.h b/src/storage_file/storage_file_backend.h index ad0f66212c..ecf5883a55 100644 --- a/src/storage_file/storage_file_backend.h +++ b/src/storage_file/storage_file_backend.h @@ -22,7 +22,7 @@ #include <sys/stat.h> -#include "virstoragefile.h" +#include "storage_source_conf.h" /* ------- virStorageFile backends ------------ */ typedef struct _virStorageFileBackend virStorageFileBackend; diff --git a/src/storage_file/storage_file_probe.c b/src/storage_file/storage_file_probe.c index e5e1b272ac..29baa0596f 100644 --- a/src/storage_file/storage_file_probe.c +++ b/src/storage_file/storage_file_probe.c @@ -27,12 +27,12 @@ #include "internal.h" #include "storage_file_probe.h" +#include "storage_source_conf.h" #include "viralloc.h" #include "virbitmap.h" #include "virendian.h" #include "virfile.h" #include "virlog.h" -#include "virstoragefile.h" #define VIR_FROM_THIS VIR_FROM_STORAGE diff --git a/src/storage_file/storage_file_probe.h b/src/storage_file/storage_file_probe.h index c443c11606..0d0ac38185 100644 --- a/src/storage_file/storage_file_probe.h +++ b/src/storage_file/storage_file_probe.h @@ -23,7 +23,7 @@ #include <sys/stat.h> -#include "virstoragefile.h" +#include "storage_source_conf.h" /* Minimum header size required to probe all known formats with * virStorageFileProbeFormat, or obtain metadata from a known format. diff --git a/src/storage_file/storage_source.h b/src/storage_file/storage_source.h index 23f56417a8..5d6ad4606d 100644 --- a/src/storage_file/storage_source.h +++ b/src/storage_file/storage_source.h @@ -21,7 +21,7 @@ #pragma once -#include "virstoragefile.h" +#include "storage_source_conf.h" #ifndef DEV_BSIZE # define DEV_BSIZE 512 diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index c70d5713de..85ccd9f52c 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -23,89 +23,19 @@ #include "virstoragefile.h" #include "viralloc.h" -#include "virxml.h" #include "viruuid.h" #include "virerror.h" #include "virlog.h" -#include "virfile.h" #include "vircommand.h" #include "virhash.h" #include "virstring.h" #include "virbuffer.h" -#include "virstorageencryption.h" #include "virsecret.h" #define VIR_FROM_THIS VIR_FROM_STORAGE VIR_LOG_INIT("util.storagefile"); -static virClassPtr virStorageSourceClass; - -VIR_ENUM_IMPL(virStorage, - VIR_STORAGE_TYPE_LAST, - "none", - "file", - "block", - "dir", - "network", - "volume", - "nvme", -); - -VIR_ENUM_IMPL(virStorageFileFormat, - VIR_STORAGE_FILE_LAST, - "none", - "raw", "dir", "bochs", - "cloop", "dmg", "iso", - "vpc", "vdi", - /* Not direct file formats, but used for various drivers */ - "fat", "vhd", "ploop", - /* Formats with backing file below here */ - "cow", "qcow", "qcow2", "qed", "vmdk", -); - -VIR_ENUM_IMPL(virStorageFileFeature, - VIR_STORAGE_FILE_FEATURE_LAST, - "lazy_refcounts", -); - -VIR_ENUM_IMPL(virStorageNetProtocol, - VIR_STORAGE_NET_PROTOCOL_LAST, - "none", - "nbd", - "rbd", - "sheepdog", - "gluster", - "iscsi", - "http", - "https", - "ftp", - "ftps", - "tftp", - "ssh", - "vxhs", - "nfs", -); - -VIR_ENUM_IMPL(virStorageNetHostTransport, - VIR_STORAGE_NET_HOST_TRANS_LAST, - "tcp", - "unix", - "rdma", -); - -VIR_ENUM_IMPL(virStorageSourcePoolMode, - VIR_STORAGE_SOURCE_POOL_MODE_LAST, - "default", - "host", - "direct", -); - -VIR_ENUM_IMPL(virStorageAuth, - VIR_STORAGE_AUTH_TYPE_LAST, - "none", "chap", "ceph", -); - bool virStorageIsFile(const char *backing) @@ -278,6 +208,7 @@ int virStorageFileGetNPIVKey(const char *path G_GNUC_UNUSED, } #endif + /** * virStorageFileParseBackingStoreStr: * @str: backing store specifier string to parse @@ -351,1089 +282,6 @@ virStorageFileParseChainIndex(const char *diskTarget, } -/** - * virStorageSourceIsBacking: - * @src: storage source - * - * Returns true if @src is a eligible backing store structure. Useful - * for iterators. - */ -bool -virStorageSourceIsBacking(const virStorageSource *src) -{ - return src && src->type != VIR_STORAGE_TYPE_NONE; -} - -/** - * virStorageSourceHasBacking: - * @src: storage source - * - * Returns true if @src has backing store/chain. - */ -bool -virStorageSourceHasBacking(const virStorageSource *src) -{ - return virStorageSourceIsBacking(src) && src->backingStore && - src->backingStore->type != VIR_STORAGE_TYPE_NONE; -} - - -void -virStorageNetHostDefClear(virStorageNetHostDefPtr def) -{ - if (!def) - return; - - VIR_FREE(def->name); - VIR_FREE(def->socket); -} - - -void -virStorageNetHostDefFree(size_t nhosts, - virStorageNetHostDefPtr hosts) -{ - size_t i; - - if (!hosts) - return; - - for (i = 0; i < nhosts; i++) - virStorageNetHostDefClear(&hosts[i]); - - VIR_FREE(hosts); -} - - -static void -virStoragePermsFree(virStoragePermsPtr def) -{ - if (!def) - return; - - VIR_FREE(def->label); - VIR_FREE(def); -} - - -virStorageNetHostDefPtr -virStorageNetHostDefCopy(size_t nhosts, - virStorageNetHostDefPtr hosts) -{ - virStorageNetHostDefPtr ret = NULL; - size_t i; - - ret = g_new0(virStorageNetHostDef, nhosts); - - for (i = 0; i < nhosts; i++) { - virStorageNetHostDefPtr src = &hosts[i]; - virStorageNetHostDefPtr dst = &ret[i]; - - dst->transport = src->transport; - dst->port = src->port; - - dst->name = g_strdup(src->name); - dst->socket = g_strdup(src->socket); - } - - return ret; -} - - -void -virStorageAuthDefFree(virStorageAuthDefPtr authdef) -{ - if (!authdef) - return; - - VIR_FREE(authdef->username); - VIR_FREE(authdef->secrettype); - virSecretLookupDefClear(&authdef->seclookupdef); - VIR_FREE(authdef); -} - - -virStorageAuthDefPtr -virStorageAuthDefCopy(const virStorageAuthDef *src) -{ - g_autoptr(virStorageAuthDef) authdef = NULL; - - authdef = g_new0(virStorageAuthDef, 1); - - authdef->username = g_strdup(src->username); - /* Not present for storage pool, but used for disk source */ - authdef->secrettype = g_strdup(src->secrettype); - authdef->authType = src->authType; - - virSecretLookupDefCopy(&authdef->seclookupdef, &src->seclookupdef); - - return g_steal_pointer(&authdef); -} - - -virStorageAuthDefPtr -virStorageAuthDefParse(xmlNodePtr node, - xmlXPathContextPtr ctxt) -{ - VIR_XPATH_NODE_AUTORESTORE(ctxt) - virStorageAuthDefPtr ret = NULL; - xmlNodePtr secretnode = NULL; - g_autoptr(virStorageAuthDef) authdef = NULL; - g_autofree char *authtype = NULL; - - ctxt->node = node; - - authdef = g_new0(virStorageAuthDef, 1); - - if (!(authdef->username = virXPathString("string(./@username)", ctxt))) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing username for auth")); - goto cleanup; - } - - authdef->authType = VIR_STORAGE_AUTH_TYPE_NONE; - authtype = virXPathString("string(./@type)", ctxt); - if (authtype) { - /* Used by the storage pool instead of the secret type field - * to define whether chap or ceph being used - */ - if ((authdef->authType = virStorageAuthTypeFromString(authtype)) < 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("unknown auth type '%s'"), authtype); - goto cleanup; - } - } - - if (!(secretnode = virXPathNode("./secret ", ctxt))) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("Missing <secret> element in auth")); - goto cleanup; - } - - /* Used by the domain disk xml parsing in order to ensure the - * <secret type='%s' value matches the expected secret type for - * the style of disk (iscsi is chap, nbd is ceph). For some reason - * the virSecretUsageType{From|To}String() cannot be linked here - * and because only the domain parsing code cares - just keep - * it as a string. - */ - authdef->secrettype = virXMLPropString(secretnode, "type"); - - if (virSecretLookupParseSecret(secretnode, &authdef->seclookupdef) < 0) - goto cleanup; - - ret = g_steal_pointer(&authdef); - - cleanup: - - return ret; -} - - -void -virStorageAuthDefFormat(virBufferPtr buf, - virStorageAuthDefPtr authdef) -{ - if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) { - virBufferEscapeString(buf, "<auth username='%s'>\n", authdef->username); - } else { - virBufferAsprintf(buf, "<auth type='%s' ", - virStorageAuthTypeToString(authdef->authType)); - virBufferEscapeString(buf, "username='%s'>\n", authdef->username); - } - - virBufferAdjustIndent(buf, 2); - virSecretLookupFormatSecret(buf, authdef->secrettype, - &authdef->seclookupdef); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "</auth>\n"); -} - - -void -virStoragePRDefFree(virStoragePRDefPtr prd) -{ - if (!prd) - return; - - VIR_FREE(prd->path); - VIR_FREE(prd->mgralias); - VIR_FREE(prd); -} - - -virStoragePRDefPtr -virStoragePRDefParseXML(xmlXPathContextPtr ctxt) -{ - virStoragePRDefPtr prd; - virStoragePRDefPtr ret = NULL; - g_autofree char *managed = NULL; - g_autofree char *type = NULL; - g_autofree char *path = NULL; - g_autofree char *mode = NULL; - - prd = g_new0(virStoragePRDef, 1); - - if (!(managed = virXPathString("string(./@managed)", ctxt))) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing @managed attribute for <reservations/>")); - goto cleanup; - } - - if ((prd->managed = virTristateBoolTypeFromString(managed)) <= 0) { - virReportError(VIR_ERR_XML_ERROR, - _("invalid value for 'managed': %s"), managed); - goto cleanup; - } - - type = virXPathString("string(./source[1]/@type)", ctxt); - path = virXPathString("string(./source[1]/@path)", ctxt); - mode = virXPathString("string(./source[1]/@mode)", ctxt); - - if (prd->managed == VIR_TRISTATE_BOOL_NO || type || path || mode) { - if (!type) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing connection type for <reservations/>")); - goto cleanup; - } - - if (!path) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing path for <reservations/>")); - goto cleanup; - } - - if (!mode) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("missing connection mode for <reservations/>")); - goto cleanup; - } - } - - if (type && STRNEQ(type, "unix")) { - virReportError(VIR_ERR_XML_ERROR, - _("unsupported connection type for <reservations/>: %s"), - type); - goto cleanup; - } - - if (mode && STRNEQ(mode, "client")) { - virReportError(VIR_ERR_XML_ERROR, - _("unsupported connection mode for <reservations/>: %s"), - mode); - goto cleanup; - } - - prd->path = g_steal_pointer(&path); - ret = g_steal_pointer(&prd); - - cleanup: - virStoragePRDefFree(prd); - return ret; -} - - -void -virStoragePRDefFormat(virBufferPtr buf, - virStoragePRDefPtr prd, - bool migratable) -{ - virBufferAsprintf(buf, "<reservations managed='%s'", - virTristateBoolTypeToString(prd->managed)); - if (prd->path && - (prd->managed == VIR_TRISTATE_BOOL_NO || !migratable)) { - virBufferAddLit(buf, ">\n"); - virBufferAdjustIndent(buf, 2); - virBufferAddLit(buf, "<source type='unix'"); - virBufferEscapeString(buf, " path='%s'", prd->path); - virBufferAddLit(buf, " mode='client'/>\n"); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "</reservations>\n"); - } else { - virBufferAddLit(buf, "/>\n"); - } -} - - -bool -virStoragePRDefIsEqual(virStoragePRDefPtr a, - virStoragePRDefPtr b) -{ - if (!a && !b) - return true; - - if (!a || !b) - return false; - - if (a->managed != b->managed || - STRNEQ_NULLABLE(a->path, b->path)) - return false; - - return true; -} - - -bool -virStoragePRDefIsManaged(virStoragePRDefPtr prd) -{ - return prd && prd->managed == VIR_TRISTATE_BOOL_YES; -} - - -bool -virStorageSourceChainHasManagedPR(virStorageSourcePtr src) -{ - virStorageSourcePtr n; - - for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { - if (virStoragePRDefIsManaged(n->pr)) - return true; - } - - return false; -} - - -static virStoragePRDefPtr -virStoragePRDefCopy(virStoragePRDefPtr src) -{ - virStoragePRDefPtr copy = NULL; - virStoragePRDefPtr ret = NULL; - - copy = g_new0(virStoragePRDef, 1); - - copy->managed = src->managed; - - copy->path = g_strdup(src->path); - copy->mgralias = g_strdup(src->mgralias); - - ret = g_steal_pointer(©); - - virStoragePRDefFree(copy); - return ret; -} - - -static virStorageSourceNVMeDefPtr -virStorageSourceNVMeDefCopy(const virStorageSourceNVMeDef *src) -{ - virStorageSourceNVMeDefPtr ret = NULL; - - ret = g_new0(virStorageSourceNVMeDef, 1); - - ret->namespc = src->namespc; - ret->managed = src->managed; - virPCIDeviceAddressCopy(&ret->pciAddr, &src->pciAddr); - return ret; -} - - -static bool -virStorageSourceNVMeDefIsEqual(const virStorageSourceNVMeDef *a, - const virStorageSourceNVMeDef *b) -{ - if (!a && !b) - return true; - - if (!a || !b) - return false; - - if (a->namespc != b->namespc || - a->managed != b->managed || - !virPCIDeviceAddressEqual(&a->pciAddr, &b->pciAddr)) - return false; - - return true; -} - - -void -virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def) -{ - if (!def) - return; - - VIR_FREE(def); -} - - -bool -virStorageSourceChainHasNVMe(const virStorageSource *src) -{ - const virStorageSource *n; - - for (n = src; virStorageSourceIsBacking(n); n = n->backingStore) { - if (n->type == VIR_STORAGE_TYPE_NVME) - return true; - } - - return false; -} - - -virSecurityDeviceLabelDefPtr -virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, - const char *model) -{ - size_t i; - - for (i = 0; i < src->nseclabels; i++) { - if (STREQ_NULLABLE(src->seclabels[i]->model, model)) - return src->seclabels[i]; - } - - return NULL; -} - - -static void -virStorageSourceSeclabelsClear(virStorageSourcePtr def) -{ - size_t i; - - if (def->seclabels) { - for (i = 0; i < def->nseclabels; i++) - virSecurityDeviceLabelDefFree(def->seclabels[i]); - VIR_FREE(def->seclabels); - } -} - - -static int -virStorageSourceSeclabelsCopy(virStorageSourcePtr to, - const virStorageSource *from) -{ - size_t i; - - if (from->nseclabels == 0) - return 0; - - to->seclabels = g_new0(virSecurityDeviceLabelDefPtr, from->nseclabels); - to->nseclabels = from->nseclabels; - - for (i = 0; i < to->nseclabels; i++) { - if (!(to->seclabels[i] = virSecurityDeviceLabelDefCopy(from->seclabels[i]))) - goto error; - } - - return 0; - - error: - virStorageSourceSeclabelsClear(to); - return -1; -} - - -void -virStorageNetCookieDefFree(virStorageNetCookieDefPtr def) -{ - if (!def) - return; - - g_free(def->name); - g_free(def->value); - - g_free(def); -} - - -static void -virStorageSourceNetCookiesClear(virStorageSourcePtr src) -{ - size_t i; - - if (!src || !src->cookies) - return; - - for (i = 0; i < src->ncookies; i++) - virStorageNetCookieDefFree(src->cookies[i]); - - g_clear_pointer(&src->cookies, g_free); - src->ncookies = 0; -} - - -static void -virStorageSourceNetCookiesCopy(virStorageSourcePtr to, - const virStorageSource *from) -{ - size_t i; - - if (from->ncookies == 0) - return; - - to->cookies = g_new0(virStorageNetCookieDefPtr, from->ncookies); - to->ncookies = from->ncookies; - - for (i = 0; i < from->ncookies; i++) { - to->cookies[i]->name = g_strdup(from->cookies[i]->name); - to->cookies[i]->value = g_strdup(from->cookies[i]->value); - } -} - - -/* see https://tools.ietf.org/html/rfc6265#section-4.1.1 */ -static const char virStorageSourceCookieValueInvalidChars[] = - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" - " \",;\\"; - -/* in addition cookie name can't contain these */ -static const char virStorageSourceCookieNameInvalidChars[] = - "()<>@:/[]?={}"; - -static int -virStorageSourceNetCookieValidate(virStorageNetCookieDefPtr def) -{ - g_autofree char *val = g_strdup(def->value); - const char *checkval = val; - size_t len = strlen(val); - - /* name must have at least 1 character */ - if (*(def->name) == '\0') { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("cookie name must not be empty")); - return -1; - } - - /* check invalid characters in name */ - if (virStringHasChars(def->name, virStorageSourceCookieValueInvalidChars) || - virStringHasChars(def->name, virStorageSourceCookieNameInvalidChars)) { - virReportError(VIR_ERR_XML_ERROR, - _("cookie name '%s' contains invalid characters"), - def->name); - return -1; - } - - /* check for optional quotes around the cookie value string */ - if (val[0] == '"') { - if (val[len - 1] != '"') { - virReportError(VIR_ERR_XML_ERROR, - _("value of cookie '%s' contains invalid characters"), - def->name); - return -1; - } - - val[len - 1] = '\0'; - checkval++; - } - - /* check invalid characters in value */ - if (virStringHasChars(checkval, virStorageSourceCookieValueInvalidChars)) { - virReportError(VIR_ERR_XML_ERROR, - _("value of cookie '%s' contains invalid characters"), - def->name); - return -1; - } - - return 0; -} - - -int -virStorageSourceNetCookiesValidate(virStorageSourcePtr src) -{ - size_t i; - size_t j; - - for (i = 0; i < src->ncookies; i++) { - if (virStorageSourceNetCookieValidate(src->cookies[i]) < 0) - return -1; - - for (j = i + 1; j < src->ncookies; j++) { - if (STREQ(src->cookies[i]->name, src->cookies[j]->name)) { - virReportError(VIR_ERR_XML_ERROR, _("duplicate cookie '%s'"), - src->cookies[i]->name); - return -1; - } - } - } - - return 0; -} - - -static virStorageTimestampsPtr -virStorageTimestampsCopy(const virStorageTimestamps *src) -{ - virStorageTimestampsPtr ret; - - ret = g_new0(virStorageTimestamps, 1); - - memcpy(ret, src, sizeof(*src)); - - return ret; -} - - -static virStoragePermsPtr -virStoragePermsCopy(const virStoragePerms *src) -{ - virStoragePermsPtr ret; - - ret = g_new0(virStoragePerms, 1); - - ret->mode = src->mode; - ret->uid = src->uid; - ret->gid = src->gid; - - ret->label = g_strdup(src->label); - - return ret; -} - - -static virStorageSourcePoolDefPtr -virStorageSourcePoolDefCopy(const virStorageSourcePoolDef *src) -{ - virStorageSourcePoolDefPtr ret; - - ret = g_new0(virStorageSourcePoolDef, 1); - - ret->voltype = src->voltype; - ret->pooltype = src->pooltype; - ret->actualtype = src->actualtype; - ret->mode = src->mode; - - ret->pool = g_strdup(src->pool); - ret->volume = g_strdup(src->volume); - - return ret; -} - - -static virStorageSourceSlicePtr -virStorageSourceSliceCopy(const virStorageSourceSlice *src) -{ - virStorageSourceSlicePtr ret = g_new0(virStorageSourceSlice, 1); - - ret->offset = src->offset; - ret->size = src->size; - ret->nodename = g_strdup(src->nodename); - - return ret; -} - - -static void -virStorageSourceSliceFree(virStorageSourceSlicePtr slice) -{ - if (!slice) - return; - - g_free(slice->nodename); - g_free(slice); -} - - -/** - * virStorageSourcePtr: - * - * Deep-copies a virStorageSource structure. If @backing chain is true - * then also copies the backing chain recursively, otherwise just - * the top element is copied. This function doesn't copy the - * storage driver access structure and thus the struct needs to be initialized - * separately. - */ -virStorageSourcePtr -virStorageSourceCopy(const virStorageSource *src, - bool backingChain) -{ - g_autoptr(virStorageSource) def = virStorageSourceNew(); - - def->id = src->id; - def->type = src->type; - def->protocol = src->protocol; - def->format = src->format; - def->capacity = src->capacity; - def->allocation = src->allocation; - def->has_allocation = src->has_allocation; - def->physical = src->physical; - def->readonly = src->readonly; - def->shared = src->shared; - def->haveTLS = src->haveTLS; - def->tlsFromConfig = src->tlsFromConfig; - def->detected = src->detected; - def->debugLevel = src->debugLevel; - def->debug = src->debug; - def->iomode = src->iomode; - def->cachemode = src->cachemode; - def->discard = src->discard; - def->detect_zeroes = src->detect_zeroes; - def->sslverify = src->sslverify; - def->readahead = src->readahead; - def->timeout = src->timeout; - def->metadataCacheMaxSize = src->metadataCacheMaxSize; - - /* storage driver metadata are not copied */ - def->drv = NULL; - - def->path = g_strdup(src->path); - def->volume = g_strdup(src->volume); - def->relPath = g_strdup(src->relPath); - def->backingStoreRaw = g_strdup(src->backingStoreRaw); - def->backingStoreRawFormat = src->backingStoreRawFormat; - def->snapshot = g_strdup(src->snapshot); - def->configFile = g_strdup(src->configFile); - def->nodeformat = g_strdup(src->nodeformat); - def->nodestorage = g_strdup(src->nodestorage); - def->compat = g_strdup(src->compat); - def->tlsAlias = g_strdup(src->tlsAlias); - def->tlsCertdir = g_strdup(src->tlsCertdir); - def->query = g_strdup(src->query); - - if (src->sliceStorage) - def->sliceStorage = virStorageSourceSliceCopy(src->sliceStorage); - - if (src->nhosts) { - if (!(def->hosts = virStorageNetHostDefCopy(src->nhosts, src->hosts))) - return NULL; - - def->nhosts = src->nhosts; - } - - virStorageSourceNetCookiesCopy(def, src); - - if (src->srcpool && - !(def->srcpool = virStorageSourcePoolDefCopy(src->srcpool))) - return NULL; - - if (src->features) - def->features = virBitmapNewCopy(src->features); - - if (src->encryption && - !(def->encryption = virStorageEncryptionCopy(src->encryption))) - return NULL; - - if (src->perms && - !(def->perms = virStoragePermsCopy(src->perms))) - return NULL; - - if (src->timestamps && - !(def->timestamps = virStorageTimestampsCopy(src->timestamps))) - return NULL; - - if (virStorageSourceSeclabelsCopy(def, src) < 0) - return NULL; - - if (src->auth && - !(def->auth = virStorageAuthDefCopy(src->auth))) - return NULL; - - if (src->pr && - !(def->pr = virStoragePRDefCopy(src->pr))) - return NULL; - - if (src->nvme) - def->nvme = virStorageSourceNVMeDefCopy(src->nvme); - - if (virStorageSourceInitiatorCopy(&def->initiator, &src->initiator) < 0) - return NULL; - - if (backingChain && src->backingStore) { - if (!(def->backingStore = virStorageSourceCopy(src->backingStore, - true))) - return NULL; - } - - /* ssh config passthrough for libguestfs */ - def->ssh_host_key_check_disabled = src->ssh_host_key_check_disabled; - def->ssh_user = g_strdup(src->ssh_user); - - def->nfs_user = g_strdup(src->nfs_user); - def->nfs_group = g_strdup(src->nfs_group); - def->nfs_uid = src->nfs_uid; - def->nfs_gid = src->nfs_gid; - - return g_steal_pointer(&def); -} - - -/** - * virStorageSourceIsSameLocation: - * - * Returns true if the sources @a and @b point to the same storage location. - * This does not compare any other configuration option - */ -bool -virStorageSourceIsSameLocation(virStorageSourcePtr a, - virStorageSourcePtr b) -{ - size_t i; - - /* there are multiple possibilities to define an empty source */ - if (virStorageSourceIsEmpty(a) && - virStorageSourceIsEmpty(b)) - return true; - - if (virStorageSourceGetActualType(a) != virStorageSourceGetActualType(b)) - return false; - - if (STRNEQ_NULLABLE(a->path, b->path) || - STRNEQ_NULLABLE(a->volume, b->volume) || - STRNEQ_NULLABLE(a->snapshot, b->snapshot)) - return false; - - if (a->type == VIR_STORAGE_TYPE_NETWORK) { - if (a->protocol != b->protocol || - a->nhosts != b->nhosts) - return false; - - for (i = 0; i < a->nhosts; i++) { - if (a->hosts[i].transport != b->hosts[i].transport || - a->hosts[i].port != b->hosts[i].port || - STRNEQ_NULLABLE(a->hosts[i].name, b->hosts[i].name) || - STRNEQ_NULLABLE(a->hosts[i].socket, b->hosts[i].socket)) - return false; - } - } - - if (a->type == VIR_STORAGE_TYPE_NVME && - !virStorageSourceNVMeDefIsEqual(a->nvme, b->nvme)) - return false; - - return true; -} - - -/** - * virStorageSourceInitChainElement: - * @newelem: New backing chain element disk source - * @old: Existing top level disk source - * @transferLabels: Transfer security labels. - * - * Transfers relevant information from the existing disk source to the new - * backing chain element if they weren't supplied so that labelling info - * and possibly other stuff is correct. - * - * If @transferLabels is true, security labels from the existing disk are copied - * to the new disk. Otherwise the default domain imagelabel label will be used. - * - * Returns 0 on success, -1 on error. - */ -int -virStorageSourceInitChainElement(virStorageSourcePtr newelem, - virStorageSourcePtr old, - bool transferLabels) -{ - if (transferLabels && - !newelem->seclabels && - virStorageSourceSeclabelsCopy(newelem, old) < 0) - return -1; - - newelem->shared = old->shared; - newelem->readonly = old->readonly; - - return 0; -} - - -void -virStorageSourcePoolDefFree(virStorageSourcePoolDefPtr def) -{ - if (!def) - return; - - VIR_FREE(def->pool); - VIR_FREE(def->volume); - - VIR_FREE(def); -} - - -/** - * virStorageSourceGetActualType: - * @def: storage source definition - * - * Returns type of @def. In case when the type is VIR_STORAGE_TYPE_VOLUME - * and virDomainDiskTranslateSourcePool was called on @def the actual type - * of the storage volume is returned rather than VIR_STORAGE_TYPE_VOLUME. - */ -int -virStorageSourceGetActualType(const virStorageSource *def) -{ - if (def->type == VIR_STORAGE_TYPE_VOLUME && - def->srcpool && - def->srcpool->actualtype != VIR_STORAGE_TYPE_NONE) - return def->srcpool->actualtype; - - return def->type; -} - - -bool -virStorageSourceIsLocalStorage(const virStorageSource *src) -{ - virStorageType type = virStorageSourceGetActualType(src); - - switch (type) { - case VIR_STORAGE_TYPE_FILE: - case VIR_STORAGE_TYPE_BLOCK: - case VIR_STORAGE_TYPE_DIR: - return true; - - case VIR_STORAGE_TYPE_NETWORK: - case VIR_STORAGE_TYPE_VOLUME: - /* While NVMe disks are local, they are not accessible via src->path. - * Therefore, we have to return false here. */ - case VIR_STORAGE_TYPE_NVME: - case VIR_STORAGE_TYPE_LAST: - case VIR_STORAGE_TYPE_NONE: - return false; - } - - return false; -} - - -/** - * virStorageSourceIsEmpty: - * - * @src: disk source to check - * - * Returns true if the guest disk has no associated host storage source - * (such as an empty cdrom drive). - */ -bool -virStorageSourceIsEmpty(virStorageSourcePtr src) -{ - if (virStorageSourceIsLocalStorage(src) && !src->path) - return true; - - if (src->type == VIR_STORAGE_TYPE_NONE) - return true; - - if (src->type == VIR_STORAGE_TYPE_NETWORK && - src->protocol == VIR_STORAGE_NET_PROTOCOL_NONE) - return true; - - return false; -} - - -/** - * virStorageSourceIsBlockLocal: - * @src: disk source definition - * - * Returns true if @src describes a locally accessible block storage source. - * This includes block devices and host-mapped iSCSI volumes. - */ -bool -virStorageSourceIsBlockLocal(const virStorageSource *src) -{ - return virStorageSourceGetActualType(src) == VIR_STORAGE_TYPE_BLOCK; -} - - -/** - * virStorageSourceBackingStoreClear: - * - * @src: disk source to clear - * - * Clears information about backing store of the current storage file. - */ -void -virStorageSourceBackingStoreClear(virStorageSourcePtr def) -{ - if (!def) - return; - - VIR_FREE(def->relPath); - VIR_FREE(def->backingStoreRaw); - - /* recursively free backing chain */ - virObjectUnref(def->backingStore); - def->backingStore = NULL; -} - - -void -virStorageSourceClear(virStorageSourcePtr def) -{ - if (!def) - return; - - VIR_FREE(def->path); - VIR_FREE(def->volume); - VIR_FREE(def->snapshot); - VIR_FREE(def->configFile); - VIR_FREE(def->query); - virStorageSourceNetCookiesClear(def); - virStorageSourcePoolDefFree(def->srcpool); - virBitmapFree(def->features); - VIR_FREE(def->compat); - virStorageEncryptionFree(def->encryption); - virStoragePRDefFree(def->pr); - virStorageSourceNVMeDefFree(def->nvme); - virStorageSourceSeclabelsClear(def); - virStoragePermsFree(def->perms); - VIR_FREE(def->timestamps); - - virStorageSourceSliceFree(def->sliceStorage); - - virStorageNetHostDefFree(def->nhosts, def->hosts); - virStorageAuthDefFree(def->auth); - virObjectUnref(def->privateData); - - VIR_FREE(def->nodestorage); - VIR_FREE(def->nodeformat); - - virStorageSourceBackingStoreClear(def); - - VIR_FREE(def->tlsAlias); - VIR_FREE(def->tlsCertdir); - - VIR_FREE(def->ssh_user); - - VIR_FREE(def->nfs_user); - VIR_FREE(def->nfs_group); - - virStorageSourceInitiatorClear(&def->initiator); - - /* clear everything except the class header as the object APIs - * will break otherwise */ - memset((char *) def + sizeof(def->parent), 0, - sizeof(*def) - sizeof(def->parent)); -} - - -static void -virStorageSourceDispose(void *obj) -{ - virStorageSourcePtr src = obj; - - virStorageSourceClear(src); -} - - -static int -virStorageSourceOnceInit(void) -{ - if (!VIR_CLASS_NEW(virStorageSource, virClassForObject())) - return -1; - - return 0; -} - - -VIR_ONCE_GLOBAL_INIT(virStorageSource); - - -virStorageSourcePtr -virStorageSourceNew(void) -{ - virStorageSourcePtr ret; - - if (virStorageSourceInitialize() < 0) - abort(); - - if (!(ret = virObjectNew(virStorageSourceClass))) - abort(); - - return ret; -} - - static char * virStorageFileCanonicalizeFormatPath(char **components, size_t ncomponents, @@ -1642,157 +490,3 @@ virStorageFileCanonicalizePath(const char *path, return ret; } - - -/** - * virStorageSourceIsRelative: - * @src: storage source to check - * - * Returns true if given storage source definition is a relative path. - */ -bool -virStorageSourceIsRelative(virStorageSourcePtr src) -{ - virStorageType actual_type = virStorageSourceGetActualType(src); - - if (!src->path) - return false; - - switch (actual_type) { - case VIR_STORAGE_TYPE_FILE: - case VIR_STORAGE_TYPE_BLOCK: - case VIR_STORAGE_TYPE_DIR: - return src->path[0] != '/'; - - case VIR_STORAGE_TYPE_NETWORK: - case VIR_STORAGE_TYPE_VOLUME: - case VIR_STORAGE_TYPE_NVME: - case VIR_STORAGE_TYPE_NONE: - case VIR_STORAGE_TYPE_LAST: - return false; - } - - return false; -} - - -static unsigned int -virStorageSourceNetworkDefaultPort(virStorageNetProtocol protocol) -{ - switch (protocol) { - case VIR_STORAGE_NET_PROTOCOL_HTTP: - return 80; - - case VIR_STORAGE_NET_PROTOCOL_HTTPS: - return 443; - - case VIR_STORAGE_NET_PROTOCOL_FTP: - return 21; - - case VIR_STORAGE_NET_PROTOCOL_FTPS: - return 990; - - case VIR_STORAGE_NET_PROTOCOL_TFTP: - return 69; - - case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: - return 7000; - - case VIR_STORAGE_NET_PROTOCOL_NBD: - return 10809; - - case VIR_STORAGE_NET_PROTOCOL_SSH: - return 22; - - case VIR_STORAGE_NET_PROTOCOL_ISCSI: - return 3260; - - case VIR_STORAGE_NET_PROTOCOL_GLUSTER: - return 24007; - - case VIR_STORAGE_NET_PROTOCOL_RBD: - /* we don't provide a default for RBD */ - return 0; - - case VIR_STORAGE_NET_PROTOCOL_VXHS: - return 9999; - - case VIR_STORAGE_NET_PROTOCOL_NFS: - /* Port is not supported by NFS, so no default is provided */ - return 0; - - case VIR_STORAGE_NET_PROTOCOL_LAST: - case VIR_STORAGE_NET_PROTOCOL_NONE: - return 0; - } - - return 0; -} - - -void -virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src) -{ - size_t i; - - for (i = 0; i < src->nhosts; i++) { - if (src->hosts[i].transport == VIR_STORAGE_NET_HOST_TRANS_TCP && - src->hosts[i].port == 0) - src->hosts[i].port = virStorageSourceNetworkDefaultPort(src->protocol); - } -} - - -int -virStorageSourcePrivateDataParseRelPath(xmlXPathContextPtr ctxt, - virStorageSourcePtr src) -{ - src->relPath = virXPathString("string(./relPath)", ctxt); - return 0; -} - - -int -virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src, - virBufferPtr buf) -{ - if (src->relPath) - virBufferEscapeString(buf, "<relPath>%s</relPath>\n", src->relPath); - - return 0; -} - -void -virStorageSourceInitiatorParseXML(xmlXPathContextPtr ctxt, - virStorageSourceInitiatorDefPtr initiator) -{ - initiator->iqn = virXPathString("string(./initiator/iqn/@name)", ctxt); -} - -void -virStorageSourceInitiatorFormatXML(virStorageSourceInitiatorDefPtr initiator, - virBufferPtr buf) -{ - if (!initiator->iqn) - return; - - virBufferAddLit(buf, "<initiator>\n"); - virBufferAdjustIndent(buf, 2); - virBufferEscapeString(buf, "<iqn name='%s'/>\n", initiator->iqn); - virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "</initiator>\n"); -} - -int -virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest, - const virStorageSourceInitiatorDef *src) -{ - dest->iqn = g_strdup(src->iqn); - return 0; -} - -void -virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator) -{ - VIR_FREE(initiator->iqn); -} diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index d6f194a7dd..2c1a250f20 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -21,372 +21,7 @@ #pragma once -#include <sys/stat.h> - -#include "virbitmap.h" -#include "virobject.h" -#include "virseclabel.h" -#include "virstorageencryption.h" -#include "virsecret.h" -#include "virenum.h" -#include "virpci.h" - -/* Types of disk backends (host resource). Comparable to the public - * virStorageVolType, except we have an undetermined state, don't have - * a netdir type, and add a volume type for reference through a - * storage pool. */ -typedef enum { - VIR_STORAGE_TYPE_NONE, - VIR_STORAGE_TYPE_FILE, - VIR_STORAGE_TYPE_BLOCK, - VIR_STORAGE_TYPE_DIR, - VIR_STORAGE_TYPE_NETWORK, - VIR_STORAGE_TYPE_VOLUME, - VIR_STORAGE_TYPE_NVME, - - VIR_STORAGE_TYPE_LAST -} virStorageType; - -VIR_ENUM_DECL(virStorage); - - -typedef enum { - VIR_STORAGE_FILE_AUTO_SAFE = -2, - VIR_STORAGE_FILE_AUTO = -1, - VIR_STORAGE_FILE_NONE = 0, - VIR_STORAGE_FILE_RAW, - VIR_STORAGE_FILE_DIR, - VIR_STORAGE_FILE_BOCHS, - VIR_STORAGE_FILE_CLOOP, - VIR_STORAGE_FILE_DMG, - VIR_STORAGE_FILE_ISO, - VIR_STORAGE_FILE_VPC, - VIR_STORAGE_FILE_VDI, - - /* Not direct file formats, but used for various drivers */ - VIR_STORAGE_FILE_FAT, - VIR_STORAGE_FILE_VHD, - VIR_STORAGE_FILE_PLOOP, - - /* Not a format, but a marker: all formats below this point have - * libvirt support for following a backing chain */ - VIR_STORAGE_FILE_BACKING, - - VIR_STORAGE_FILE_COW = VIR_STORAGE_FILE_BACKING, - VIR_STORAGE_FILE_QCOW, - VIR_STORAGE_FILE_QCOW2, - VIR_STORAGE_FILE_QED, - VIR_STORAGE_FILE_VMDK, - - VIR_STORAGE_FILE_LAST, -} virStorageFileFormat; - -VIR_ENUM_DECL(virStorageFileFormat); - -typedef enum { - VIR_STORAGE_FILE_FEATURE_LAZY_REFCOUNTS = 0, - - VIR_STORAGE_FILE_FEATURE_LAST -} virStorageFileFeature; - -VIR_ENUM_DECL(virStorageFileFeature); - -typedef struct _virStoragePerms virStoragePerms; -typedef virStoragePerms *virStoragePermsPtr; -struct _virStoragePerms { - mode_t mode; - uid_t uid; - gid_t gid; - char *label; -}; - - -typedef struct _virStorageTimestamps virStorageTimestamps; -typedef virStorageTimestamps *virStorageTimestampsPtr; -struct _virStorageTimestamps { - struct timespec atime; - struct timespec btime; /* birth time unknown if btime.tv_nsec == -1 */ - struct timespec ctime; - struct timespec mtime; -}; - - -/* Information related to network storage */ -typedef enum { - VIR_STORAGE_NET_PROTOCOL_NONE, - VIR_STORAGE_NET_PROTOCOL_NBD, - VIR_STORAGE_NET_PROTOCOL_RBD, - VIR_STORAGE_NET_PROTOCOL_SHEEPDOG, - VIR_STORAGE_NET_PROTOCOL_GLUSTER, - VIR_STORAGE_NET_PROTOCOL_ISCSI, - VIR_STORAGE_NET_PROTOCOL_HTTP, - VIR_STORAGE_NET_PROTOCOL_HTTPS, - VIR_STORAGE_NET_PROTOCOL_FTP, - VIR_STORAGE_NET_PROTOCOL_FTPS, - VIR_STORAGE_NET_PROTOCOL_TFTP, - VIR_STORAGE_NET_PROTOCOL_SSH, - VIR_STORAGE_NET_PROTOCOL_VXHS, - VIR_STORAGE_NET_PROTOCOL_NFS, - - VIR_STORAGE_NET_PROTOCOL_LAST -} virStorageNetProtocol; - -VIR_ENUM_DECL(virStorageNetProtocol); - - -typedef enum { - VIR_STORAGE_NET_HOST_TRANS_TCP, - VIR_STORAGE_NET_HOST_TRANS_UNIX, - VIR_STORAGE_NET_HOST_TRANS_RDMA, - - VIR_STORAGE_NET_HOST_TRANS_LAST -} virStorageNetHostTransport; - -VIR_ENUM_DECL(virStorageNetHostTransport); - -typedef struct _virStorageNetHostDef virStorageNetHostDef; -typedef virStorageNetHostDef *virStorageNetHostDefPtr; -struct _virStorageNetHostDef { - char *name; - unsigned int port; - int transport; /* virStorageNetHostTransport */ - char *socket; /* path to unix socket */ -}; - -typedef struct _virStorageNetCookieDef virStorageNetCookieDef; -typedef virStorageNetCookieDef *virStorageNetCookieDefPtr; -struct _virStorageNetCookieDef { - char *name; - char *value; -}; - -void virStorageNetCookieDefFree(virStorageNetCookieDefPtr def); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageNetCookieDef, virStorageNetCookieDefFree); - -/* Information for a storage volume from a virStoragePool */ - -/* - * Used for volume "type" disk to indicate how to represent - * the disk source if the specified "pool" is of iscsi type. - */ -typedef enum { - VIR_STORAGE_SOURCE_POOL_MODE_DEFAULT = 0, - - /* Use the path as it shows up on host, e.g. - * /dev/disk/by-path/ip-$ip-iscsi-$iqn:iscsi.iscsi-pool0-lun-1 - */ - VIR_STORAGE_SOURCE_POOL_MODE_HOST, - - /* Use the URI from the storage pool source element host attribute. E.g. - * file=iscsi://demo.org:6000/iqn.1992-01.com.example/1. - */ - VIR_STORAGE_SOURCE_POOL_MODE_DIRECT, - - VIR_STORAGE_SOURCE_POOL_MODE_LAST -} virStorageSourcePoolMode; - -VIR_ENUM_DECL(virStorageSourcePoolMode); - -typedef struct _virStorageSourcePoolDef virStorageSourcePoolDef; -struct _virStorageSourcePoolDef { - char *pool; /* pool name */ - char *volume; /* volume name */ - int voltype; /* virStorageVolType, internal only */ - int pooltype; /* virStoragePoolType from storage_conf.h, internal only */ - int actualtype; /* virStorageType, internal only */ - int mode; /* virStorageSourcePoolMode, currently makes sense only for iscsi pool */ -}; -typedef virStorageSourcePoolDef *virStorageSourcePoolDefPtr; - - -typedef enum { - VIR_STORAGE_AUTH_TYPE_NONE, - VIR_STORAGE_AUTH_TYPE_CHAP, - VIR_STORAGE_AUTH_TYPE_CEPHX, - - VIR_STORAGE_AUTH_TYPE_LAST, -} virStorageAuthType; -VIR_ENUM_DECL(virStorageAuth); - -typedef struct _virStorageAuthDef virStorageAuthDef; -typedef virStorageAuthDef *virStorageAuthDefPtr; -struct _virStorageAuthDef { - char *username; - char *secrettype; /* <secret type='%s' for disk source */ - int authType; /* virStorageAuthType */ - virSecretLookupTypeDef seclookupdef; -}; - -typedef struct _virStoragePRDef virStoragePRDef; -typedef virStoragePRDef *virStoragePRDefPtr; -struct _virStoragePRDef { - int managed; /* enum virTristateBool */ - char *path; - - /* manager object alias */ - char *mgralias; -}; - -typedef struct _virStorageSourceInitiatorDef virStorageSourceInitiatorDef; -typedef virStorageSourceInitiatorDef *virStorageSourceInitiatorDefPtr; -struct _virStorageSourceInitiatorDef { - char *iqn; /* Initiator IQN */ -}; - -typedef struct _virStorageSourceNVMeDef virStorageSourceNVMeDef; -typedef virStorageSourceNVMeDef *virStorageSourceNVMeDefPtr; -struct _virStorageSourceNVMeDef { - unsigned long long namespc; - int managed; /* enum virTristateBool */ - virPCIDeviceAddress pciAddr; - - /* Don't forget to update virStorageSourceNVMeDefCopy */ -}; - - -typedef struct _virStorageSourceSlice virStorageSourceSlice; -typedef virStorageSourceSlice *virStorageSourceSlicePtr; -struct _virStorageSourceSlice { - unsigned long long offset; - unsigned long long size; - char *nodename; -}; - - -typedef struct _virStorageSource virStorageSource; -typedef virStorageSource *virStorageSourcePtr; - -/* Stores information related to a host resource. In the case of backing - * chains, multiple source disks join to form a single guest view. - * - * IMPORTANT: When adding fields to this struct it's also necessary to add - * appropriate code to the virStorageSourceCopy deep copy function */ -struct _virStorageSource { - virObject parent; - - unsigned int id; /* backing chain identifier, 0 is unset */ - int type; /* virStorageType */ - char *path; - int protocol; /* virStorageNetProtocol */ - char *volume; /* volume name for remote storage */ - char *snapshot; /* for storage systems supporting internal snapshots */ - char *configFile; /* some storage systems use config file as part of - the source definition */ - char *query; /* query string for HTTP based protocols */ - size_t nhosts; - virStorageNetHostDefPtr hosts; - size_t ncookies; - virStorageNetCookieDefPtr *cookies; - virStorageSourcePoolDefPtr srcpool; - virStorageAuthDefPtr auth; - virStorageEncryptionPtr encryption; - virStoragePRDefPtr pr; - virTristateBool sslverify; - /* both values below have 0 as default value */ - unsigned long long readahead; /* size of the readahead buffer in bytes */ - unsigned long long timeout; /* connection timeout in seconds */ - - virStorageSourceNVMeDefPtr nvme; /* type == VIR_STORAGE_TYPE_NVME */ - - virStorageSourceInitiatorDef initiator; - - virObjectPtr privateData; - - int format; /* virStorageFileFormat in domain backing chains, but - * pool-specific enum for storage volumes */ - virBitmapPtr features; - char *compat; - bool nocow; - bool sparse; - - virStorageSourceSlicePtr sliceStorage; - - virStoragePermsPtr perms; - virStorageTimestampsPtr timestamps; - unsigned long long capacity; /* in bytes, 0 if unknown */ - unsigned long long allocation; /* in bytes, 0 if unknown */ - unsigned long long physical; /* in bytes, 0 if unknown */ - unsigned long long clusterSize; /* in bytes, 0 if unknown */ - bool has_allocation; /* Set to true when provided in XML */ - - unsigned long long metadataCacheMaxSize; /* size of the metadata cache in bytes */ - - size_t nseclabels; - virSecurityDeviceLabelDefPtr *seclabels; - - /* Don't ever write to the image */ - bool readonly; - - /* image is shared across hosts */ - bool shared; - - /* backing chain of the storage source */ - virStorageSourcePtr backingStore; - - /* metadata for storage driver access to remote and local volumes */ - void *drv; - - /* metadata about storage image which need separate fields */ - /* Relative name by which this image was opened from its parent, or NULL - * if this image was opened by absolute name */ - char *relPath; - /* Name of the child backing store recorded in metadata of the - * current file. */ - char *backingStoreRaw; - virStorageFileFormat backingStoreRawFormat; - - /* metadata that allows identifying given storage source */ - char *nodeformat; /* name of the format handler object */ - char *nodestorage; /* name of the storage object */ - - /* An optional setting to enable usage of TLS for the storage source */ - int haveTLS; /* enum virTristateBool */ - - /* Indication whether the haveTLS value was altered due to qemu.conf - * setting when haveTLS is missing from the domain config file */ - bool tlsFromConfig; - - /* If TLS is used, then mgmt of the TLS credentials occurs via an - * object that is generated using a specific alias for a specific - * certificate directory with listen and verify bools. */ - char *tlsAlias; - char *tlsCertdir; - - bool detected; /* true if this entry was not provided by the user */ - - unsigned int debugLevel; - bool debug; - - /* Libvirt currently stores the following properties in virDomainDiskDef. - * These instances are currently just copies from the parent definition and - * are not mapped back to the XML */ - int iomode; /* enum virDomainDiskIo */ - int cachemode; /* enum virDomainDiskCache */ - int discard; /* enum virDomainDiskDiscard */ - int detect_zeroes; /* enum virDomainDiskDetectZeroes */ - - bool floppyimg; /* set to true if the storage source is going to be used - as a source for floppy drive */ - - bool hostcdrom; /* backing device is a cdrom */ - - /* passthrough variables for the ssh driver which we don't handle properly */ - /* these must not be used apart from formatting the output JSON in the qemu driver */ - char *ssh_user; - bool ssh_host_key_check_disabled; - - /* nfs_user and nfs_group store the strings passed in by the user for NFS params. - * nfs_uid and nfs_gid represent the converted/looked up ID numbers which are used - * during run time, and are not based on the configuration */ - char *nfs_user; - char *nfs_group; - uid_t nfs_uid; - gid_t nfs_gid; -}; - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSource, virObjectUnref); - +#include "internal.h" int virStorageFileParseChainIndex(const char *diskTarget, const char *name, @@ -407,59 +42,6 @@ int virStorageFileGetSCSIKey(const char *path, int virStorageFileGetNPIVKey(const char *path, char **key); -void virStorageAuthDefFree(virStorageAuthDefPtr def); -virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src); -virStorageAuthDefPtr virStorageAuthDefParse(xmlNodePtr node, - xmlXPathContextPtr ctxt); -void virStorageAuthDefFormat(virBufferPtr buf, virStorageAuthDefPtr authdef); - -void virStoragePRDefFree(virStoragePRDefPtr prd); -virStoragePRDefPtr virStoragePRDefParseXML(xmlXPathContextPtr ctxt); -void virStoragePRDefFormat(virBufferPtr buf, - virStoragePRDefPtr prd, - bool migratable); -bool virStoragePRDefIsEqual(virStoragePRDefPtr a, - virStoragePRDefPtr b); -bool virStoragePRDefIsManaged(virStoragePRDefPtr prd); - -bool -virStorageSourceChainHasManagedPR(virStorageSourcePtr src); - -void virStorageSourceNVMeDefFree(virStorageSourceNVMeDefPtr def); -G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageSourceNVMeDef, virStorageSourceNVMeDefFree); - -bool virStorageSourceChainHasNVMe(const virStorageSource *src); - -virSecurityDeviceLabelDefPtr -virStorageSourceGetSecurityLabelDef(virStorageSourcePtr src, - const char *model); - -void virStorageNetHostDefClear(virStorageNetHostDefPtr def); -void virStorageNetHostDefFree(size_t nhosts, virStorageNetHostDefPtr hosts); -virStorageNetHostDefPtr virStorageNetHostDefCopy(size_t nhosts, - virStorageNetHostDefPtr hosts); - -int virStorageSourceInitChainElement(virStorageSourcePtr newelem, - virStorageSourcePtr old, - bool force); -void virStorageSourcePoolDefFree(virStorageSourcePoolDefPtr def); -void virStorageSourceClear(virStorageSourcePtr def); -int virStorageSourceGetActualType(const virStorageSource *def); -bool virStorageSourceIsLocalStorage(const virStorageSource *src); -bool virStorageSourceIsEmpty(virStorageSourcePtr src); -bool virStorageSourceIsBlockLocal(const virStorageSource *src); -virStorageSourcePtr virStorageSourceNew(void); -void virStorageSourceBackingStoreClear(virStorageSourcePtr def); - -int virStorageSourceNetCookiesValidate(virStorageSourcePtr src); - -virStorageSourcePtr virStorageSourceCopy(const virStorageSource *src, - bool backingChain) - ATTRIBUTE_NONNULL(1); -bool virStorageSourceIsSameLocation(virStorageSourcePtr a, - virStorageSourcePtr b) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - typedef int (*virStorageFileSimplifyPathReadlinkCallback)(const char *path, char **link, @@ -467,39 +49,3 @@ typedef int char *virStorageFileCanonicalizePath(const char *path, virStorageFileSimplifyPathReadlinkCallback cb, void *cbdata); - -bool virStorageSourceIsRelative(virStorageSourcePtr src); - -void -virStorageSourceNetworkAssignDefaultPorts(virStorageSourcePtr src) - ATTRIBUTE_NONNULL(1); - -bool -virStorageSourceIsBacking(const virStorageSource *src); -bool -virStorageSourceHasBacking(const virStorageSource *src); - - -int -virStorageSourcePrivateDataParseRelPath(xmlXPathContextPtr ctxt, - virStorageSourcePtr src); -int -virStorageSourcePrivateDataFormatRelPath(virStorageSourcePtr src, - virBufferPtr buf); - -void -virStorageSourceInitiatorParseXML(xmlXPathContextPtr ctxt, - virStorageSourceInitiatorDefPtr initiator); - -void -virStorageSourceInitiatorFormatXML(virStorageSourceInitiatorDefPtr initiator, - virBufferPtr buf); - -int -virStorageSourceInitiatorCopy(virStorageSourceInitiatorDefPtr dest, - const virStorageSourceInitiatorDef *src); - -void -virStorageSourceInitiatorClear(virStorageSourceInitiatorDefPtr initiator); - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(virStorageAuthDef, virStorageAuthDefFree); -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:24 +0100, Pavel Hrdina wrote:
The code handles XML bits and internal definition and should be in conf directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

The code handles XML bits and internal definition and should be in conf directory. Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- po/POTFILES.in | 2 +- src/conf/domain_conf.h | 2 +- src/conf/meson.build | 1 + src/conf/storage_conf.h | 2 +- .../storage_encryption_conf.c} | 4 ++-- .../storage_encryption_conf.h} | 2 +- src/conf/storage_source_conf.h | 2 +- src/libvirt_private.syms | 12 ++++++------ src/util/meson.build | 1 - 9 files changed, 14 insertions(+), 14 deletions(-) rename src/{util/virstorageencryption.c => conf/storage_encryption_conf.c} (99%) rename src/{util/virstorageencryption.h => conf/storage_encryption_conf.h} (98%) diff --git a/po/POTFILES.in b/po/POTFILES.in index 00100d7d73..05bbe21462 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -43,6 +43,7 @@ @SRCDIR@src/conf/snapshot_conf.c @SRCDIR@src/conf/storage_adapter_conf.c @SRCDIR@src/conf/storage_conf.c +@SRCDIR@src/conf/storage_encryption_conf.c @SRCDIR@src/conf/storage_source_conf.c @SRCDIR@src/conf/virchrdev.c @SRCDIR@src/conf/virdomainmomentobjlist.c @@ -307,7 +308,6 @@ @SRCDIR@src/util/virscsivhost.c @SRCDIR@src/util/virsecret.c @SRCDIR@src/util/virsocketaddr.c -@SRCDIR@src/util/virstorageencryption.c @SRCDIR@src/util/virstoragefile.c @SRCDIR@src/util/virstring.c @SRCDIR@src/util/virsysinfo.c diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index f5d346ddf0..95ad052891 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -29,7 +29,7 @@ #include "internal.h" #include "virconftypes.h" #include "capabilities.h" -#include "virstorageencryption.h" +#include "storage_encryption_conf.h" #include "cpu_conf.h" #include "virthread.h" #include "virhash.h" diff --git a/src/conf/meson.build b/src/conf/meson.build index 9d4831b815..bd35d87e0a 100644 --- a/src/conf/meson.build +++ b/src/conf/meson.build @@ -54,6 +54,7 @@ storage_conf_sources = [ 'storage_adapter_conf.c', 'storage_capabilities.c', 'storage_conf.c', + 'storage_encryption_conf.c', 'storage_source_conf.c', 'virstorageobj.c', ] diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index aeda2891d4..647eb847bf 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -22,7 +22,7 @@ #pragma once #include "internal.h" -#include "virstorageencryption.h" +#include "storage_encryption_conf.h" #include "storage_source_conf.h" #include "virbitmap.h" #include "virthread.h" diff --git a/src/util/virstorageencryption.c b/src/conf/storage_encryption_conf.c similarity index 99% rename from src/util/virstorageencryption.c rename to src/conf/storage_encryption_conf.c index c893f0babe..34ad5dffeb 100644 --- a/src/util/virstorageencryption.c +++ b/src/conf/storage_encryption_conf.c @@ -1,5 +1,5 @@ /* - * virstorageencryption.c: volume encryption information + * storage_encryption_conf.c: volume encryption information * * Copyright (C) 2009-2014 Red Hat, Inc. * @@ -27,7 +27,7 @@ #include "virbuffer.h" #include "viralloc.h" -#include "virstorageencryption.h" +#include "storage_encryption_conf.h" #include "virxml.h" #include "virerror.h" #include "viruuid.h" diff --git a/src/util/virstorageencryption.h b/src/conf/storage_encryption_conf.h similarity index 98% rename from src/util/virstorageencryption.h rename to src/conf/storage_encryption_conf.h index 352dd373d6..0799421763 100644 --- a/src/util/virstorageencryption.h +++ b/src/conf/storage_encryption_conf.h @@ -1,5 +1,5 @@ /* - * virstorageencryption.h: volume encryption information + * storage_encryption_conf.h: volume encryption information * * Copyright (C) 2009-2011, 2014 Red Hat, Inc. * diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h index 6f39ab4bd0..e66ccdedef 100644 --- a/src/conf/storage_source_conf.h +++ b/src/conf/storage_source_conf.h @@ -21,13 +21,13 @@ #pragma once +#include "storage_encryption_conf.h" #include "virbitmap.h" #include "virenum.h" #include "virobject.h" #include "virpci.h" #include "virseclabel.h" #include "virsecret.h" -#include "virstorageencryption.h" /* Types of disk backends (host resource). Comparable to the public * virStorageVolType, except we have an undetermined state, don't have diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b13d0db209..e8fe8e6c12 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1047,6 +1047,12 @@ virStorageVolTypeFromString; virStorageVolTypeToString; +# conf/storage_encryption_conf.h +virStorageEncryptionFormat; +virStorageEncryptionFree; +virStorageEncryptionParseNode; + + # conf/storage_event.h virStoragePoolEventLifecycleNew; virStoragePoolEventRefreshNew; @@ -3206,12 +3212,6 @@ virSocketAddrSetIPv6AddrNetOrder; virSocketAddrSetPort; -# util/virstorageencryption.h -virStorageEncryptionFormat; -virStorageEncryptionFree; -virStorageEncryptionParseNode; - - # util/virstoragefile.h virStorageFileCanonicalizePath; virStorageFileGetNPIVKey; diff --git a/src/util/meson.build b/src/util/meson.build index b510f0ebe9..c077c5cc99 100644 --- a/src/util/meson.build +++ b/src/util/meson.build @@ -88,7 +88,6 @@ util_sources = [ 'virsecret.c', 'virsocket.c', 'virsocketaddr.c', - 'virstorageencryption.c', 'virstoragefile.c', 'virstring.c', 'virsysinfo.c', -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:25 +0100, Pavel Hrdina wrote:
The code handles XML bits and internal definition and should be in conf directory.
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
Reviewed-by: Peter Krempa <pkrempa@redhat.com>

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/libvirt_private.syms | 4 ++-- src/qemu/qemu_block.c | 2 +- src/qemu/qemu_snapshot.c | 2 +- src/storage_file/storage_source.c | 6 +++--- src/util/virstoragefile.c | 6 +++--- src/util/virstoragefile.h | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index e8fe8e6c12..088474d54b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -3216,10 +3216,10 @@ virSocketAddrSetPort; virStorageFileCanonicalizePath; virStorageFileGetNPIVKey; virStorageFileGetSCSIKey; +virStorageFileIsFile; +virStorageFileIsRelative; virStorageFileParseBackingStoreStr; virStorageFileParseChainIndex; -virStorageIsFile; -virStorageIsRelative; # util/virstring.h diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index ca23466b22..fafa35071c 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -3439,7 +3439,7 @@ qemuBlockUpdateRelativeBacking(virDomainObjPtr vm, if (rc < 0) return rc; - if (backingStoreStr && virStorageIsRelative(backingStoreStr)) + if (backingStoreStr && virStorageFileIsRelative(backingStoreStr)) n->backingStore->relPath = g_steal_pointer(&backingStoreStr); } diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 994c7dc60b..699090ae40 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -1094,7 +1094,7 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, if (virStorageFileGetBackingStoreStr(dd->src, &backingStoreStr) < 0) return -1; if (backingStoreStr != NULL) { - if (virStorageIsRelative(backingStoreStr)) + if (virStorageFileIsRelative(backingStoreStr)) dd->relPath = g_steal_pointer(&backingStoreStr); } } diff --git a/src/storage_file/storage_source.c b/src/storage_file/storage_source.c index d1e0aeb2c1..ffc7fe8ea5 100644 --- a/src/storage_file/storage_source.c +++ b/src/storage_file/storage_source.c @@ -185,7 +185,7 @@ virStorageFileChainLookup(virStorageSourcePtr chain, { virStorageSourcePtr prev; const char *start = chain->path; - bool nameIsFile = virStorageIsFile(name); + bool nameIsFile = virStorageFileIsFile(name); if (!parent) parent = &prev; @@ -1532,7 +1532,7 @@ virStorageSourceNewFromBackingAbsolute(const char *path, *src = NULL; - if (virStorageIsFile(path)) { + if (virStorageFileIsFile(path)) { def->type = VIR_STORAGE_TYPE_FILE; def->path = g_strdup(path); @@ -1604,7 +1604,7 @@ virStorageSourceNewFromChild(virStorageSourcePtr parent, *child = NULL; - if (virStorageIsRelative(parentRaw)) { + if (virStorageFileIsRelative(parentRaw)) { if (!(def = virStorageSourceNewFromBackingRelative(parent, parentRaw))) return -1; } else { diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 85ccd9f52c..c9c735831d 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -38,7 +38,7 @@ VIR_LOG_INIT("util.storagefile"); bool -virStorageIsFile(const char *backing) +virStorageFileIsFile(const char *backing) { char *colon; char *slash; @@ -59,12 +59,12 @@ virStorageIsFile(const char *backing) bool -virStorageIsRelative(const char *backing) +virStorageFileIsRelative(const char *backing) { if (backing[0] == '/') return false; - if (!virStorageIsFile(backing)) + if (!virStorageFileIsFile(backing)) return false; return true; diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 2c1a250f20..e56796ec95 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -33,8 +33,8 @@ int virStorageFileParseBackingStoreStr(const char *str, unsigned int *chainIndex) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); -bool virStorageIsFile(const char *path); -bool virStorageIsRelative(const char *backing); +bool virStorageFileIsFile(const char *path); +bool virStorageFileIsRelative(const char *backing); int virStorageFileGetSCSIKey(const char *path, char **key, -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:26 +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
I really hate that these functions are exported. If this patch is necessary for the following, then commit it, otherwise drop it. I'll follow up with patches for moving the two functions appropriately and unexporting them. Reviewed-by: Peter Krempa <pkrempa@redhat.com> Otherwise just drop it.

On Fri, Jan 22, 2021 at 10:10:33AM +0100, Peter Krempa wrote:
On Thu, Jan 21, 2021 at 20:34:26 +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> ---
I really hate that these functions are exported.
If this patch is necessary for the following, then commit it, otherwise drop it. I'll follow up with patches for moving the two functions appropriately and unexporting them.
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Otherwise just drop it.
I'll drop it then.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/libvirt_private.syms | 42 ++--- src/qemu/qemu_backup.c | 8 +- src/qemu/qemu_block.c | 6 +- src/qemu/qemu_domain.c | 16 +- src/qemu/qemu_driver.c | 66 +++---- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 4 +- src/qemu/qemu_snapshot.c | 20 +-- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend_gluster.c | 4 +- src/storage/storage_util.c | 6 +- src/storage_file/storage_source.c | 250 +++++++++++++------------- src/storage_file/storage_source.h | 90 +++++----- tests/virstoragetest.c | 18 +- 14 files changed, 268 insertions(+), 268 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 088474d54b..41fa8ae5ba 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1686,30 +1686,30 @@ virStorageFileProbeGetMetadata; # storage_file/storage_source.h -virStorageFileAccess; -virStorageFileChainLookup; -virStorageFileChown; -virStorageFileCreate; -virStorageFileDeinit; -virStorageFileGetBackingStoreStr; -virStorageFileGetMetadata; -virStorageFileGetMetadataFromBuf; -virStorageFileGetMetadataFromFD; -virStorageFileGetRelativeBackingPath; -virStorageFileGetUniqueIdentifier; -virStorageFileInit; -virStorageFileInitAs; -virStorageFileRead; -virStorageFileReportBrokenChain; -virStorageFileStat; -virStorageFileSupportsAccess; -virStorageFileSupportsBackingChainTraversal; -virStorageFileSupportsCreate; -virStorageFileSupportsSecurityDriver; -virStorageFileUnlink; +virStorageSourceAccess; +virStorageSourceChainLookup; +virStorageSourceChown; +virStorageSourceCreate; +virStorageSourceDeinit; +virStorageSourceGetBackingStoreStr; +virStorageSourceGetMetadata; +virStorageSourceGetMetadataFromBuf; +virStorageSourceGetMetadataFromFD; +virStorageSourceGetRelativeBackingPath; +virStorageSourceGetUniqueIdentifier; +virStorageSourceInit; +virStorageSourceInitAs; virStorageSourceNewFromBacking; virStorageSourceNewFromBackingAbsolute; virStorageSourceParseRBDColonString; +virStorageSourceRead; +virStorageSourceReportBrokenChain; +virStorageSourceStat; +virStorageSourceSupportsAccess; +virStorageSourceSupportsBackingChainTraversal; +virStorageSourceSupportsCreate; +virStorageSourceSupportsSecurityDriver; +virStorageSourceUnlink; virStorageSourceUpdateBackingSizes; virStorageSourceUpdateCapacity; virStorageSourceUpdatePhysicalSize; diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index 4a07f6a5f4..423de9c719 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -135,7 +135,7 @@ qemuBackupDiskDataCleanupOne(virDomainObjPtr vm, } if (dd->created) { - if (virStorageFileUnlink(dd->store) < 0) + if (virStorageSourceUnlink(dd->store) < 0) VIR_WARN("Unable to remove just-created %s", NULLSTR(dd->store->path)); } @@ -144,7 +144,7 @@ qemuBackupDiskDataCleanupOne(virDomainObjPtr vm, } if (dd->initialized) - virStorageFileDeinit(dd->store); + virStorageSourceDeinit(dd->store); if (dd->blockjob) qemuBlockJobStartupFinalize(vm, dd->blockjob); @@ -429,7 +429,7 @@ qemuBackupDiskPrepareOneStorage(virDomainObjPtr vm, if (!reuse_external && dd->store->type == VIR_STORAGE_TYPE_FILE && - virStorageFileSupportsCreate(dd->store)) { + virStorageSourceSupportsCreate(dd->store)) { if (virFileExists(dd->store->path)) { virReportError(VIR_ERR_INVALID_ARG, @@ -443,7 +443,7 @@ qemuBackupDiskPrepareOneStorage(virDomainObjPtr vm, dd->initialized = true; - if (virStorageFileCreate(dd->store) < 0) { + if (virStorageSourceCreate(dd->store) < 0) { virReportSystemError(errno, _("failed to create image file '%s'"), NULLSTR(dd->store->path)); diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index fafa35071c..15019657e4 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -3426,15 +3426,15 @@ qemuBlockUpdateRelativeBacking(virDomainObjPtr vm, if (n->backingStore->relPath) break; - if (!virStorageFileSupportsBackingChainTraversal(n)) + if (!virStorageSourceSupportsBackingChainTraversal(n)) continue; if (qemuDomainStorageFileInit(driver, vm, n, topsrc) < 0) return -1; - rc = virStorageFileGetBackingStoreStr(n, &backingStoreStr); + rc = virStorageSourceGetBackingStoreStr(n, &backingStoreStr); - virStorageFileDeinit(n); + virStorageSourceDeinit(n); if (rc < 0) return rc; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 165321858e..0c078a9388 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -7160,7 +7160,7 @@ qemuDomainStorageFileInit(virQEMUDriverPtr driver, qemuDomainGetImageIds(cfg, vm, src, parent, &uid, &gid); - if (virStorageFileInitAs(src, uid, gid) < 0) + if (virStorageSourceInitAs(src, uid, gid) < 0) return -1; return 0; @@ -7298,7 +7298,7 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, if (!virFileExists(disksrc->path)) { if (report_broken) - virStorageFileReportBrokenChain(errno, disksrc, disksrc); + virStorageSourceReportBrokenChain(errno, disksrc, disksrc); return -1; } @@ -7322,7 +7322,7 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, /* skip to the end of the chain if there is any */ while (virStorageSourceHasBacking(src)) { if (report_broken) { - int rv = virStorageFileSupportsAccess(src); + int rv = virStorageSourceSupportsAccess(src); if (rv < 0) return -1; @@ -7331,13 +7331,13 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, if (qemuDomainStorageFileInit(driver, vm, src, disksrc) < 0) return -1; - if (virStorageFileAccess(src, F_OK) < 0) { - virStorageFileReportBrokenChain(errno, src, disksrc); - virStorageFileDeinit(src); + if (virStorageSourceAccess(src, F_OK) < 0) { + virStorageSourceReportBrokenChain(errno, src, disksrc); + virStorageSourceDeinit(src); return -1; } - virStorageFileDeinit(src); + virStorageSourceDeinit(src); } } src = src->backingStore; @@ -7354,7 +7354,7 @@ qemuDomainDetermineDiskChain(virQEMUDriverPtr driver, qemuDomainGetImageIds(cfg, vm, src, disksrc, &uid, &gid); - if (virStorageFileGetMetadata(src, uid, gid, report_broken) < 0) + if (virStorageSourceGetMetadata(src, uid, gid, report_broken) < 0) return -1; for (n = src->backingStore; virStorageSourceIsBacking(n); n = n->backingStore) { diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 8048c86632..ed966cf7e3 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -253,20 +253,20 @@ qemuSecurityChownCallback(const virStorageSource *src, return 0; } - if ((rv = virStorageFileSupportsSecurityDriver(src)) <= 0) + if ((rv = virStorageSourceSupportsSecurityDriver(src)) <= 0) return rv; if (!(cpy = virStorageSourceCopy(src, false))) return -1; /* src file init reports errors, return -2 on failure */ - if (virStorageFileInit(cpy) < 0) + if (virStorageSourceInit(cpy) < 0) return -2; - ret = virStorageFileChown(cpy, uid, gid); + ret = virStorageSourceChown(cpy, uid, gid); save_errno = errno; - virStorageFileDeinit(cpy); + virStorageSourceDeinit(cpy); errno = save_errno; return ret; @@ -10620,7 +10620,7 @@ qemuDomainBlockPeek(virDomainPtr dom, if (qemuDomainStorageFileInit(driver, vm, disk->src, NULL) < 0) goto cleanup; - if ((nread = virStorageFileRead(disk->src, offset, size, &tmpbuf)) < 0) { + if ((nread = virStorageSourceRead(disk->src, offset, size, &tmpbuf)) < 0) { if (nread == -2) { virReportError(VIR_ERR_INTERNAL_ERROR, _("storage file reading is not supported for " @@ -10644,7 +10644,7 @@ qemuDomainBlockPeek(virDomainPtr dom, cleanup: if (disk) - virStorageFileDeinit(disk->src); + virStorageSourceDeinit(disk->src); virDomainObjEndAPI(&vm); return ret; } @@ -10776,14 +10776,14 @@ qemuDomainStorageOpenStat(virQEMUDriverPtr driver, return -1; } } else { - if (skipInaccessible && virStorageFileSupportsBackingChainTraversal(src) <= 0) + if (skipInaccessible && virStorageSourceSupportsBackingChainTraversal(src) <= 0) return 0; - if (virStorageFileInitAs(src, cfg->user, cfg->group) < 0) + if (virStorageSourceInitAs(src, cfg->user, cfg->group) < 0) return -1; - if (virStorageFileStat(src, ret_sb) < 0) { - virStorageFileDeinit(src); + if (virStorageSourceStat(src, ret_sb) < 0) { + virStorageSourceDeinit(src); virReportSystemError(errno, _("failed to stat remote file '%s'"), NULLSTR(src->path)); return -1; @@ -10808,7 +10808,7 @@ qemuDomainStorageCloseStat(virStorageSourcePtr src, if (virStorageSourceIsLocalStorage(src)) VIR_FORCE_CLOSE(*fd); else - virStorageFileDeinit(src); + virStorageSourceDeinit(src); } @@ -10908,7 +10908,7 @@ qemuStorageLimitsRefresh(virQEMUDriverPtr driver, goto cleanup; } } else { - if ((len = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, &buf)) < 0) + if ((len = virStorageSourceRead(src, 0, VIR_STORAGE_MAX_HEADER, &buf)) < 0) goto cleanup; } @@ -14449,8 +14449,8 @@ qemuDomainBlockPullCommon(virDomainObjPtr vm, if (base && (virStorageFileParseChainIndex(disk->dst, base, &baseIndex) < 0 || - !(baseSource = virStorageFileChainLookup(disk->src, disk->src, - base, baseIndex, NULL)))) + !(baseSource = virStorageSourceChainLookup(disk->src, disk->src, + base, baseIndex, NULL)))) goto endjob; if (baseSource) { @@ -14466,9 +14466,9 @@ qemuDomainBlockPullCommon(virDomainObjPtr vm, qemuBlockUpdateRelativeBacking(vm, disk->src, disk->src) < 0) goto endjob; - if (virStorageFileGetRelativeBackingPath(disk->src->backingStore, - baseSource, - &backingPath) < 0) + if (virStorageSourceGetRelativeBackingPath(disk->src->backingStore, + baseSource, + &backingPath) < 0) goto endjob; if (!backingPath) { @@ -14839,7 +14839,7 @@ qemuDomainBlockCopyValidateMirror(virStorageSourcePtr mirror, if (!virStorageSourceIsLocalStorage(mirror)) return 0; - if (virStorageFileAccess(mirror, F_OK) < 0) { + if (virStorageSourceAccess(mirror, F_OK) < 0) { if (errno != ENOENT) { virReportSystemError(errno, "%s", _("unable to verify existence of " @@ -14854,7 +14854,7 @@ qemuDomainBlockCopyValidateMirror(virStorageSourcePtr mirror, return -1; } } else { - if (virStorageFileStat(mirror, &st) < 0) { + if (virStorageSourceStat(mirror, &st) < 0) { virReportSystemError(errno, _("unable to stat block copy target '%s'"), mirror->path); @@ -15058,9 +15058,9 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm, goto endjob; } - supports_access = virStorageFileSupportsAccess(mirror) == 1; - supports_create = virStorageFileSupportsCreate(mirror) == 1; - supports_detect = virStorageFileSupportsBackingChainTraversal(mirror) == 1; + supports_access = virStorageSourceSupportsAccess(mirror) == 1; + supports_create = virStorageSourceSupportsCreate(mirror) == 1; + supports_detect = virStorageSourceSupportsBackingChainTraversal(mirror) == 1; if (supports_access || supports_create || supports_detect) { if (qemuDomainStorageFileInit(driver, vm, mirror, NULL) < 0) @@ -15104,7 +15104,7 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm, * required so that libvirt can properly label the image for access by qemu */ if (!existing) { if (supports_create) { - if (virStorageFileCreate(mirror) < 0) { + if (virStorageSourceCreate(mirror) < 0) { virReportSystemError(errno, "%s", _("failed to create copy target")); goto endjob; } @@ -15247,7 +15247,7 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm, /* Update vm in place to match changes. */ need_unlink = false; - virStorageFileDeinit(mirror); + virStorageSourceDeinit(mirror); disk->mirror = g_steal_pointer(&mirror); disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY; qemuBlockJobStarted(job, vm); @@ -15266,9 +15266,9 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm, if (need_revoke) qemuDomainStorageSourceChainAccessRevoke(driver, vm, mirror); } - if (need_unlink && virStorageFileUnlink(mirror) < 0) + if (need_unlink && virStorageSourceUnlink(mirror) < 0) VIR_WARN("%s", _("unable to remove just-created copy target")); - virStorageFileDeinit(mirror); + virStorageSourceDeinit(mirror); qemuDomainObjEndJob(driver, vm); qemuBlockJobStartupFinalize(vm, job); @@ -15541,9 +15541,9 @@ qemuDomainBlockCommit(virDomainPtr dom, if (!top || STREQ(top, disk->dst)) topSource = disk->src; else if (virStorageFileParseChainIndex(disk->dst, top, &topIndex) < 0 || - !(topSource = virStorageFileChainLookup(disk->src, NULL, - top, topIndex, - &top_parent))) + !(topSource = virStorageSourceChainLookup(disk->src, NULL, + top, topIndex, + &top_parent))) goto endjob; if (topSource == disk->src) { @@ -15576,8 +15576,8 @@ qemuDomainBlockCommit(virDomainPtr dom, if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) baseSource = topSource->backingStore; else if (virStorageFileParseChainIndex(disk->dst, base, &baseIndex) < 0 || - !(baseSource = virStorageFileChainLookup(disk->src, topSource, - base, baseIndex, NULL))) + !(baseSource = virStorageSourceChainLookup(disk->src, topSource, + base, baseIndex, NULL))) goto endjob; if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) && @@ -15611,8 +15611,8 @@ qemuDomainBlockCommit(virDomainPtr dom, qemuBlockUpdateRelativeBacking(vm, top_parent, disk->src) < 0) goto endjob; - if (virStorageFileGetRelativeBackingPath(topSource, baseSource, - &backingPath) < 0) + if (virStorageSourceGetRelativeBackingPath(topSource, baseSource, + &backingPath) < 0) goto endjob; if (!backingPath) { diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 99950a1360..882e5d2384 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -4375,8 +4375,8 @@ qemuDomainRemoveDiskDevice(virQEMUDriverPtr driver, VIR_DEBUG("Removing transient overlay '%s' of disk '%s'", disk->src->path, disk->dst); if (qemuDomainStorageFileInit(driver, vm, disk->src, NULL) >= 0) { - virStorageFileUnlink(disk->src); - virStorageFileDeinit(disk->src); + virStorageSourceUnlink(disk->src); + virStorageSourceDeinit(disk->src); } } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 14e1f5d962..f87a3c0f60 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -7887,8 +7887,8 @@ void qemuProcessStop(virQEMUDriverPtr driver, VIR_DEBUG("Removing transient overlay '%s' of disk '%s'", disk->src->path, disk->dst); if (qemuDomainStorageFileInit(driver, vm, disk->src, NULL) >= 0) { - virStorageFileUnlink(disk->src); - virStorageFileDeinit(disk->src); + virStorageSourceUnlink(disk->src); + virStorageSourceDeinit(disk->src); } } } diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c index 699090ae40..1c8b1a70f8 100644 --- a/src/qemu/qemu_snapshot.c +++ b/src/qemu/qemu_snapshot.c @@ -567,13 +567,13 @@ qemuSnapshotPrepareDiskExternal(virDomainObjPtr vm, } if (virStorageSourceIsLocalStorage(snapdisk->src)) { - if (virStorageFileInit(snapdisk->src) < 0) + if (virStorageSourceInit(snapdisk->src) < 0) return -1; - rc = virStorageFileStat(snapdisk->src, &st); + rc = virStorageSourceStat(snapdisk->src, &st); err = errno; - virStorageFileDeinit(snapdisk->src); + virStorageSourceDeinit(snapdisk->src); if (rc < 0) { if (err != ENOENT) { @@ -867,13 +867,13 @@ qemuSnapshotDiskCleanup(qemuSnapshotDiskDataPtr data, } if (data[i].created && - virStorageFileUnlink(data[i].src) < 0) { + virStorageSourceUnlink(data[i].src) < 0) { VIR_WARN("Unable to remove just-created %s", NULLSTR(data[i].src->path)); } if (data[i].initialized) - virStorageFileDeinit(data[i].src); + virStorageSourceDeinit(data[i].src); if (data[i].prepared) qemuDomainStorageSourceAccessRevoke(driver, vm, data[i].src); @@ -1072,13 +1072,13 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, return -1; } - supportsCreate = virStorageFileSupportsCreate(dd->src); + supportsCreate = virStorageSourceSupportsCreate(dd->src); /* relative backing store paths need to be updated so that relative * block commit still works. With blockdev we must update it when doing * commit anyways so it's skipped here */ if (!blockdev && - virStorageFileSupportsBackingChainTraversal(dd->src)) + virStorageSourceSupportsBackingChainTraversal(dd->src)) updateRelativeBacking = true; if (supportsCreate || updateRelativeBacking) { @@ -1091,7 +1091,7 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, if (updateRelativeBacking) { g_autofree char *backingStoreStr = NULL; - if (virStorageFileGetBackingStoreStr(dd->src, &backingStoreStr) < 0) + if (virStorageSourceGetBackingStoreStr(dd->src, &backingStoreStr) < 0) return -1; if (backingStoreStr != NULL) { if (virStorageFileIsRelative(backingStoreStr)) @@ -1101,7 +1101,7 @@ qemuSnapshotDiskPrepareOne(virDomainObjPtr vm, } else { /* pre-create the image file so that we can label it before handing it to qemu */ if (supportsCreate && dd->src->type != VIR_STORAGE_TYPE_BLOCK) { - if (virStorageFileCreate(dd->src) < 0) { + if (virStorageSourceCreate(dd->src) < 0) { virReportSystemError(errno, _("failed to create image file '%s'"), NULLSTR(dd->src->path)); return -1; @@ -1251,7 +1251,7 @@ qemuSnapshotDiskUpdateSource(virDomainObjPtr vm, /* storage driver access won'd be needed */ if (dd->initialized) - virStorageFileDeinit(dd->src); + virStorageSourceDeinit(dd->src); if (qemuSecurityMoveImageMetadata(driver, vm, dd->disk->src, dd->src) < 0) VIR_WARN("Unable to move disk metadata on vm %s", vm->def->name); diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 6525baf193..f71fe6f23b 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -939,7 +939,7 @@ get_files(vahControl * ctl) * so that the open could be re-tried as that user:group. */ if (!virStorageSourceHasBacking(disk->src)) - virStorageFileGetMetadata(disk->src, -1, -1, false); + virStorageSourceGetMetadata(disk->src, -1, -1, false); /* XXX should handle open errors more careful than just ignoring them. */ diff --git a/src/storage/storage_backend_gluster.c b/src/storage/storage_backend_gluster.c index 554c76ddb4..8de0cb8a6b 100644 --- a/src/storage/storage_backend_gluster.c +++ b/src/storage/storage_backend_gluster.c @@ -272,8 +272,8 @@ virStorageBackendGlusterRefreshVol(virStorageBackendGlusterStatePtr state, &header)) < 0) goto cleanup; - if (!(meta = virStorageFileGetMetadataFromBuf(name, header, len, - VIR_STORAGE_FILE_AUTO))) + if (!(meta = virStorageSourceGetMetadataFromBuf(name, header, len, + VIR_STORAGE_FILE_AUTO))) goto cleanup; if (meta->backingStoreRaw) { diff --git a/src/storage/storage_util.c b/src/storage/storage_util.c index 10c04e1257..3d8de16341 100644 --- a/src/storage/storage_util.c +++ b/src/storage/storage_util.c @@ -3427,9 +3427,9 @@ storageBackendProbeTarget(virStorageSourcePtr target, } } - if (!(meta = virStorageFileGetMetadataFromFD(target->path, - fd, - VIR_STORAGE_FILE_AUTO))) + if (!(meta = virStorageSourceGetMetadataFromFD(target->path, + fd, + VIR_STORAGE_FILE_AUTO))) return -1; if (meta->backingStoreRaw) { diff --git a/src/storage_file/storage_source.c b/src/storage_file/storage_source.c index ffc7fe8ea5..71bff1e55e 100644 --- a/src/storage_file/storage_source.c +++ b/src/storage_file/storage_source.c @@ -46,8 +46,8 @@ VIR_LOG_INIT("storage_source"); static virStorageSourcePtr -virStorageFileMetadataNew(const char *path, - int format) +virStorageSourceMetadataNew(const char *path, + int format) { g_autoptr(virStorageSource) def = virStorageSourceNew(); @@ -61,7 +61,7 @@ virStorageFileMetadataNew(const char *path, /** - * virStorageFileGetMetadataFromBuf: + * virStorageSourceGetMetadataFromBuf: * @path: name of file, for error messages * @buf: header bytes from @path * @len: length of @buf @@ -83,14 +83,14 @@ virStorageFileMetadataNew(const char *path, * Caller MUST free the result after use via virObjectUnref. */ virStorageSourcePtr -virStorageFileGetMetadataFromBuf(const char *path, - char *buf, - size_t len, - int format) +virStorageSourceGetMetadataFromBuf(const char *path, + char *buf, + size_t len, + int format) { virStorageSourcePtr ret = NULL; - if (!(ret = virStorageFileMetadataNew(path, format))) + if (!(ret = virStorageSourceMetadataNew(path, format))) return NULL; if (virStorageFileProbeGetMetadata(ret, buf, len) < 0) { @@ -103,7 +103,7 @@ virStorageFileGetMetadataFromBuf(const char *path, /** - * virStorageFileGetMetadataFromFD: + * virStorageSourceGetMetadataFromFD: * * Extract metadata about the storage volume with the specified * image format. If image format is VIR_STORAGE_FILE_AUTO, it @@ -116,9 +116,9 @@ virStorageFileGetMetadataFromBuf(const char *path, * Caller MUST free the result after use via virObjectUnref. */ virStorageSourcePtr -virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format) +virStorageSourceGetMetadataFromFD(const char *path, + int fd, + int format) { ssize_t len = VIR_STORAGE_MAX_HEADER; @@ -132,7 +132,7 @@ virStorageFileGetMetadataFromFD(const char *path, return NULL; } - if (!(meta = virStorageFileMetadataNew(path, format))) + if (!(meta = virStorageSourceMetadataNew(path, format))) return NULL; if (S_ISDIR(sb.st_mode)) { @@ -177,11 +177,11 @@ virStorageFileGetMetadataFromFD(const char *path, * found. */ virStorageSourcePtr -virStorageFileChainLookup(virStorageSourcePtr chain, - virStorageSourcePtr startFrom, - const char *name, - unsigned int idx, - virStorageSourcePtr *parent) +virStorageSourceChainLookup(virStorageSourcePtr chain, + virStorageSourcePtr startFrom, + const char *name, + unsigned int idx, + virStorageSourcePtr *parent) { virStorageSourcePtr prev; const char *start = chain->path; @@ -1794,8 +1794,8 @@ virStorageSourceUpdateCapacity(virStorageSourcePtr src, if (format == VIR_STORAGE_FILE_RAW && !src->encryption) { src->capacity = src->physical; - } else if ((meta = virStorageFileGetMetadataFromBuf(src->path, buf, - len, format))) { + } else if ((meta = virStorageSourceGetMetadataFromBuf(src->path, buf, + len, format))) { src->capacity = meta->capacity ? meta->capacity : src->physical; if (src->encryption && meta->encryption) src->encryption->payload_offset = meta->encryption->payload_offset; @@ -1811,7 +1811,7 @@ virStorageSourceUpdateCapacity(virStorageSourcePtr src, /** - * virStorageFileRemoveLastPathComponent: + * virStorageSourceRemoveLastPathComponent: * * @path: Path string to remove the last component from * @@ -1820,7 +1820,7 @@ virStorageSourceUpdateCapacity(virStorageSourcePtr src, * responsible to free the returned string. */ static char * -virStorageFileRemoveLastPathComponent(const char *path) +virStorageSourceRemoveLastPathComponent(const char *path) { char *ret; @@ -1833,7 +1833,7 @@ virStorageFileRemoveLastPathComponent(const char *path) /* - * virStorageFileGetRelativeBackingPath: + * virStorageSourceGetRelativeBackingPath: * * Resolve relative path to be written to the overlay of @top image when * collapsing the backing chain between @top and @base. @@ -1841,9 +1841,9 @@ virStorageFileRemoveLastPathComponent(const char *path) * Returns 0 on success; 1 if backing chain isn't relative and -1 on error. */ int -virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, - virStorageSourcePtr base, - char **relpath) +virStorageSourceGetRelativeBackingPath(virStorageSourcePtr top, + virStorageSourcePtr base, + char **relpath) { virStorageSourcePtr next; g_autofree char *tmp = NULL; @@ -1855,7 +1855,7 @@ virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, if (!next->relPath) return 1; - if (!(tmp = virStorageFileRemoveLastPathComponent(path))) + if (!(tmp = virStorageSourceRemoveLastPathComponent(path))) return -1; VIR_FREE(path); @@ -1881,14 +1881,14 @@ virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, static bool -virStorageFileIsInitialized(const virStorageSource *src) +virStorageSourceIsInitialized(const virStorageSource *src) { return src && src->drv; } /** - * virStorageFileGetBackendForSupportCheck: + * virStorageSourceGetBackendForSupportCheck: * @src: storage source to check support for * @backend: pointer to the storage backend for @src if it's supported * @@ -1896,8 +1896,8 @@ virStorageFileIsInitialized(const virStorageSource *src) * 1 if it is supported and -1 on error with an error reported. */ static int -virStorageFileGetBackendForSupportCheck(const virStorageSource *src, - virStorageFileBackendPtr *backend) +virStorageSourceGetBackendForSupportCheck(const virStorageSource *src, + virStorageFileBackendPtr *backend) { int actualType; @@ -1926,12 +1926,12 @@ virStorageFileGetBackendForSupportCheck(const virStorageSource *src, int -virStorageFileSupportsBackingChainTraversal(const virStorageSource *src) +virStorageSourceSupportsBackingChainTraversal(const virStorageSource *src) { virStorageFileBackendPtr backend; int rv; - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + if ((rv = virStorageSourceGetBackendForSupportCheck(src, &backend)) < 1) return rv; return backend->storageFileGetUniqueIdentifier && @@ -1941,7 +1941,7 @@ virStorageFileSupportsBackingChainTraversal(const virStorageSource *src) /** - * virStorageFileSupportsSecurityDriver: + * virStorageSourceSupportsSecurityDriver: * * @src: a storage file structure * @@ -1949,12 +1949,12 @@ virStorageFileSupportsBackingChainTraversal(const virStorageSource *src) * driver to perform labelling */ int -virStorageFileSupportsSecurityDriver(const virStorageSource *src) +virStorageSourceSupportsSecurityDriver(const virStorageSource *src) { virStorageFileBackendPtr backend; int rv; - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + if ((rv = virStorageSourceGetBackendForSupportCheck(src, &backend)) < 1) return rv; return backend->storageFileChown ? 1 : 0; @@ -1962,7 +1962,7 @@ virStorageFileSupportsSecurityDriver(const virStorageSource *src) /** - * virStorageFileSupportsAccess: + * virStorageSourceSupportsAccess: * * @src: a storage file structure * @@ -1970,12 +1970,12 @@ virStorageFileSupportsSecurityDriver(const virStorageSource *src) * for the given vm. */ int -virStorageFileSupportsAccess(const virStorageSource *src) +virStorageSourceSupportsAccess(const virStorageSource *src) { virStorageFileBackendPtr backend; int rv; - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + if ((rv = virStorageSourceGetBackendForSupportCheck(src, &backend)) < 1) return rv; return backend->storageFileAccess ? 1 : 0; @@ -1983,19 +1983,19 @@ virStorageFileSupportsAccess(const virStorageSource *src) /** - * virStorageFileSupportsCreate: + * virStorageSourceSupportsCreate: * @src: a storage file structure * * Check if the storage driver supports creating storage described by @src - * via virStorageFileCreate. + * via virStorageSourceCreate. */ int -virStorageFileSupportsCreate(const virStorageSource *src) +virStorageSourceSupportsCreate(const virStorageSource *src) { virStorageFileBackendPtr backend; int rv; - if ((rv = virStorageFileGetBackendForSupportCheck(src, &backend)) < 1) + if ((rv = virStorageSourceGetBackendForSupportCheck(src, &backend)) < 1) return rv; return backend->storageFileCreate ? 1 : 0; @@ -2003,11 +2003,11 @@ virStorageFileSupportsCreate(const virStorageSource *src) void -virStorageFileDeinit(virStorageSourcePtr src) +virStorageSourceDeinit(virStorageSourcePtr src) { virStorageDriverDataPtr drv = NULL; - if (!virStorageFileIsInitialized(src)) + if (!virStorageSourceIsInitialized(src)) return; drv = src->drv; @@ -2021,7 +2021,7 @@ virStorageFileDeinit(virStorageSourcePtr src) /** - * virStorageFileInitAs: + * virStorageSourceInitAs: * * @src: storage source definition * @uid: uid used to access the file, or -1 for current uid @@ -2034,8 +2034,8 @@ virStorageFileDeinit(virStorageSourcePtr src) * initialization failed. Libvirt error is reported. */ int -virStorageFileInitAs(virStorageSourcePtr src, - uid_t uid, gid_t gid) +virStorageSourceInitAs(virStorageSourcePtr src, + uid_t uid, gid_t gid) { int actualType = virStorageSourceGetActualType(src); virStorageDriverDataPtr drv = g_new0(virStorageDriverData, 1); @@ -2071,20 +2071,20 @@ virStorageFileInitAs(virStorageSourcePtr src, /** - * virStorageFileInit: + * virStorageSourceInit: * - * See virStorageFileInitAs. The file is initialized to be accessed by the + * See virStorageSourceInitAs. The file is initialized to be accessed by the * current user. */ int -virStorageFileInit(virStorageSourcePtr src) +virStorageSourceInit(virStorageSourcePtr src) { - return virStorageFileInitAs(src, -1, -1); + return virStorageSourceInitAs(src, -1, -1); } /** - * virStorageFileCreate: Creates an empty storage file via storage driver + * virStorageSourceCreate: Creates an empty storage file via storage driver * * @src: file structure pointing to the file * @@ -2092,12 +2092,12 @@ virStorageFileInit(virStorageSourcePtr src) * -1 on other failure. Errno is set in case of failure. */ int -virStorageFileCreate(virStorageSourcePtr src) +virStorageSourceCreate(virStorageSourcePtr src) { virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { errno = ENOSYS; return -2; } @@ -2119,7 +2119,7 @@ virStorageFileCreate(virStorageSourcePtr src) /** - * virStorageFileUnlink: Unlink storage file via storage driver + * virStorageSourceUnlink: Unlink storage file via storage driver * * @src: file structure pointing to the file * @@ -2129,12 +2129,12 @@ virStorageFileCreate(virStorageSourcePtr src) * -1 on other failure. Errno is set in case of failure. */ int -virStorageFileUnlink(virStorageSourcePtr src) +virStorageSourceUnlink(virStorageSourcePtr src) { virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { errno = ENOSYS; return -2; } @@ -2156,7 +2156,7 @@ virStorageFileUnlink(virStorageSourcePtr src) /** - * virStorageFileStat: returns stat struct of a file via storage driver + * virStorageSourceStat: returns stat struct of a file via storage driver * * @src: file structure pointing to the file * @stat: stat structure to return data @@ -2165,13 +2165,13 @@ virStorageFileUnlink(virStorageSourcePtr src) * -1 on other failure. Errno is set in case of failure. */ int -virStorageFileStat(virStorageSourcePtr src, - struct stat *st) +virStorageSourceStat(virStorageSourcePtr src, + struct stat *st) { virStorageDriverDataPtr drv = NULL; int ret; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { errno = ENOSYS; return -2; } @@ -2193,7 +2193,7 @@ virStorageFileStat(virStorageSourcePtr src, /** - * virStorageFileRead: read bytes from a file into a buffer + * virStorageSourceRead: 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 @@ -2205,15 +2205,15 @@ virStorageFileStat(virStorageSourcePtr src, * Libvirt error is reported on failure. */ ssize_t -virStorageFileRead(virStorageSourcePtr src, - size_t offset, - size_t len, - char **buf) +virStorageSourceRead(virStorageSourcePtr src, + size_t offset, + size_t len, + char **buf) { virStorageDriverDataPtr drv = NULL; ssize_t ret; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("storage file backend not initialized")); return -1; @@ -2234,7 +2234,7 @@ virStorageFileRead(virStorageSourcePtr src, /* - * virStorageFileGetUniqueIdentifier: Get a unique string describing the volume + * virStorageSourceGetUniqueIdentifier: Get a unique string describing the volume * * @src: file structure pointing to the file * @@ -2242,11 +2242,11 @@ virStorageFileRead(virStorageSourcePtr src, * 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) +virStorageSourceGetUniqueIdentifier(virStorageSourcePtr src) { virStorageDriverDataPtr drv = NULL; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("storage file backend not initialized")); return NULL; @@ -2268,7 +2268,7 @@ virStorageFileGetUniqueIdentifier(virStorageSourcePtr src) /** - * virStorageFileAccess: Check accessibility of a storage file + * virStorageSourceAccess: Check accessibility of a storage file * * @src: storage file to check access permissions * @mode: accessibility check options (see man 2 access) @@ -2278,12 +2278,12 @@ virStorageFileGetUniqueIdentifier(virStorageSourcePtr src) * by libvirt storage backend. */ int -virStorageFileAccess(virStorageSourcePtr src, - int mode) +virStorageSourceAccess(virStorageSourcePtr src, + int mode) { virStorageDriverDataPtr drv = NULL; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { errno = ENOSYS; return -2; } @@ -2300,7 +2300,7 @@ virStorageFileAccess(virStorageSourcePtr src, /** - * virStorageFileChown: Change owner of a storage file + * virStorageSourceChown: Change owner of a storage file * * @src: storage file to change owner of * @uid: new owner id @@ -2311,13 +2311,13 @@ virStorageFileAccess(virStorageSourcePtr src, * by libvirt storage backend. */ int -virStorageFileChown(const virStorageSource *src, - uid_t uid, - gid_t gid) +virStorageSourceChown(const virStorageSource *src, + uid_t uid, + gid_t gid) { virStorageDriverDataPtr drv = NULL; - if (!virStorageFileIsInitialized(src)) { + if (!virStorageSourceIsInitialized(src)) { errno = ENOSYS; return -2; } @@ -2337,7 +2337,7 @@ virStorageFileChown(const virStorageSource *src, /** - * virStorageFileReportBrokenChain: + * virStorageSourceReportBrokenChain: * * @errcode: errno when accessing @src * @src: inaccessible file in the backing chain of @parent @@ -2347,9 +2347,9 @@ virStorageFileChown(const virStorageSource *src, * for @parent. */ void -virStorageFileReportBrokenChain(int errcode, - virStorageSourcePtr src, - virStorageSourcePtr parent) +virStorageSourceReportBrokenChain(int errcode, + virStorageSourcePtr src, + virStorageSourcePtr parent) { if (src->drv) { virStorageDriverDataPtr drv = src->drv; @@ -2383,27 +2383,27 @@ virStorageFileReportBrokenChain(int errcode, static int -virStorageFileGetMetadataRecurseReadHeader(virStorageSourcePtr src, - virStorageSourcePtr parent, - uid_t uid, - gid_t gid, - char **buf, - size_t *headerLen, - GHashTable *cycle) +virStorageSourceGetMetadataRecurseReadHeader(virStorageSourcePtr src, + virStorageSourcePtr parent, + uid_t uid, + gid_t gid, + char **buf, + size_t *headerLen, + GHashTable *cycle) { int ret = -1; const char *uniqueName; ssize_t len; - if (virStorageFileInitAs(src, uid, gid) < 0) + if (virStorageSourceInitAs(src, uid, gid) < 0) return -1; - if (virStorageFileAccess(src, F_OK) < 0) { - virStorageFileReportBrokenChain(errno, src, parent); + if (virStorageSourceAccess(src, F_OK) < 0) { + virStorageSourceReportBrokenChain(errno, src, parent); goto cleanup; } - if (!(uniqueName = virStorageFileGetUniqueIdentifier(src))) + if (!(uniqueName = virStorageSourceGetUniqueIdentifier(src))) goto cleanup; if (virHashHasEntry(cycle, uniqueName)) { @@ -2416,26 +2416,26 @@ virStorageFileGetMetadataRecurseReadHeader(virStorageSourcePtr src, if (virHashAddEntry(cycle, uniqueName, NULL) < 0) goto cleanup; - if ((len = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, buf)) < 0) + if ((len = virStorageSourceRead(src, 0, VIR_STORAGE_MAX_HEADER, buf)) < 0) goto cleanup; *headerLen = len; ret = 0; cleanup: - virStorageFileDeinit(src); + virStorageSourceDeinit(src); return ret; } -/* Recursive workhorse for virStorageFileGetMetadata. */ +/* Recursive workhorse for virStorageSourceGetMetadata. */ static int -virStorageFileGetMetadataRecurse(virStorageSourcePtr src, - virStorageSourcePtr parent, - uid_t uid, gid_t gid, - bool report_broken, - GHashTable *cycle, - unsigned int depth) +virStorageSourceGetMetadataRecurse(virStorageSourcePtr src, + virStorageSourcePtr parent, + uid_t uid, gid_t gid, + bool report_broken, + GHashTable *cycle, + unsigned int depth) { virStorageFileFormat orig_format = src->format; size_t headerLen; @@ -2451,7 +2451,7 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, src->format = VIR_STORAGE_FILE_AUTO; /* exit if we can't load information about the current image */ - rv = virStorageFileSupportsBackingChainTraversal(src); + rv = virStorageSourceSupportsBackingChainTraversal(src); if (rv <= 0) { if (orig_format == VIR_STORAGE_FILE_AUTO) return -2; @@ -2459,8 +2459,8 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, return rv; } - if (virStorageFileGetMetadataRecurseReadHeader(src, parent, uid, gid, - &buf, &headerLen, cycle) < 0) + if (virStorageSourceGetMetadataRecurseReadHeader(src, parent, uid, gid, + &buf, &headerLen, cycle) < 0) return -1; if (virStorageFileProbeGetMetadata(src, buf, headerLen) < 0) @@ -2484,10 +2484,10 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, if (rv == 1) return 0; - if ((rv = virStorageFileGetMetadataRecurse(backingStore, parent, - uid, gid, - report_broken, - cycle, depth + 1)) < 0) { + if ((rv = virStorageSourceGetMetadataRecurse(backingStore, parent, + uid, gid, + report_broken, + cycle, depth + 1)) < 0) { if (!report_broken) return 0; @@ -2513,7 +2513,7 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, /** - * virStorageFileGetMetadata: + * virStorageSourceGetMetadata: * * Extract metadata about the storage volume with the specified * image format. If image format is VIR_STORAGE_FILE_AUTO, it @@ -2534,9 +2534,9 @@ virStorageFileGetMetadataRecurse(virStorageSourcePtr src, * Caller MUST free result after use via virObjectUnref. */ int -virStorageFileGetMetadata(virStorageSourcePtr src, - uid_t uid, gid_t gid, - bool report_broken) +virStorageSourceGetMetadata(virStorageSourcePtr src, + uid_t uid, gid_t gid, + bool report_broken) { GHashTable *cycle = NULL; virStorageType actualType = virStorageSourceGetActualType(src); @@ -2556,8 +2556,8 @@ virStorageFileGetMetadata(virStorageSourcePtr src, src->format = VIR_STORAGE_FILE_RAW; } - ret = virStorageFileGetMetadataRecurse(src, src, uid, gid, - report_broken, cycle, 1); + ret = virStorageSourceGetMetadataRecurse(src, src, uid, gid, + report_broken, cycle, 1); virHashFree(cycle); return ret; @@ -2565,7 +2565,7 @@ virStorageFileGetMetadata(virStorageSourcePtr src, /** - * virStorageFileGetBackingStoreStr: + * virStorageSourceGetBackingStoreStr: * @src: storage object * * Extracts the backing store string as stored in the storage volume described @@ -2574,8 +2574,8 @@ virStorageFileGetMetadata(virStorageSourcePtr src, * returned. */ int -virStorageFileGetBackingStoreStr(virStorageSourcePtr src, - char **backing) +virStorageSourceGetBackingStoreStr(virStorageSourcePtr src, + char **backing) { ssize_t headerLen; int rv; @@ -2585,19 +2585,19 @@ virStorageFileGetBackingStoreStr(virStorageSourcePtr src, *backing = NULL; /* exit if we can't load information about the current image */ - if (!virStorageFileSupportsBackingChainTraversal(src)) + if (!virStorageSourceSupportsBackingChainTraversal(src)) return 0; - rv = virStorageFileAccess(src, F_OK); + rv = virStorageSourceAccess(src, F_OK); if (rv == -2) return 0; if (rv < 0) { - virStorageFileReportBrokenChain(errno, src, src); + virStorageSourceReportBrokenChain(errno, src, src); return -1; } - if ((headerLen = virStorageFileRead(src, 0, VIR_STORAGE_MAX_HEADER, - &buf)) < 0) { + if ((headerLen = virStorageSourceRead(src, 0, VIR_STORAGE_MAX_HEADER, + &buf)) < 0) { if (headerLen == -2) return 0; return -1; diff --git a/src/storage_file/storage_source.h b/src/storage_file/storage_source.h index 5d6ad4606d..480333d37a 100644 --- a/src/storage_file/storage_source.h +++ b/src/storage_file/storage_source.h @@ -28,23 +28,23 @@ #endif virStorageSourcePtr -virStorageFileGetMetadataFromFD(const char *path, - int fd, - int format); +virStorageSourceGetMetadataFromFD(const char *path, + int fd, + int format); virStorageSourcePtr -virStorageFileGetMetadataFromBuf(const char *path, - char *buf, - size_t len, - int format) +virStorageSourceGetMetadataFromBuf(const char *path, + char *buf, + size_t len, + int format) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); virStorageSourcePtr -virStorageFileChainLookup(virStorageSourcePtr chain, - virStorageSourcePtr startFrom, - const char *name, - unsigned int idx, - virStorageSourcePtr *parent) +virStorageSourceChainLookup(virStorageSourcePtr chain, + virStorageSourcePtr startFrom, + const char *name, + unsigned int idx, + virStorageSourcePtr *parent) ATTRIBUTE_NONNULL(1); int @@ -72,9 +72,9 @@ virStorageSourceParseRBDColonString(const char *rbdstr, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int -virStorageFileGetRelativeBackingPath(virStorageSourcePtr top, - virStorageSourcePtr base, - char **relpath) +virStorageSourceGetRelativeBackingPath(virStorageSourcePtr top, + virStorageSourcePtr base, + char **relpath) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); int @@ -82,67 +82,67 @@ virStorageSourceNewFromBackingAbsolute(const char *path, virStorageSourcePtr *src); int -virStorageFileInit(virStorageSourcePtr src); +virStorageSourceInit(virStorageSourcePtr src); int -virStorageFileInitAs(virStorageSourcePtr src, - uid_t uid, gid_t gid); +virStorageSourceInitAs(virStorageSourcePtr src, + uid_t uid, gid_t gid); void -virStorageFileDeinit(virStorageSourcePtr src); +virStorageSourceDeinit(virStorageSourcePtr src); int -virStorageFileCreate(virStorageSourcePtr src); +virStorageSourceCreate(virStorageSourcePtr src); int -virStorageFileUnlink(virStorageSourcePtr src); +virStorageSourceUnlink(virStorageSourcePtr src); int -virStorageFileStat(virStorageSourcePtr src, - struct stat *st); +virStorageSourceStat(virStorageSourcePtr src, + struct stat *st); ssize_t -virStorageFileRead(virStorageSourcePtr src, - size_t offset, - size_t len, - char **buf); +virStorageSourceRead(virStorageSourcePtr src, + size_t offset, + size_t len, + char **buf); const char * -virStorageFileGetUniqueIdentifier(virStorageSourcePtr src); +virStorageSourceGetUniqueIdentifier(virStorageSourcePtr src); int -virStorageFileAccess(virStorageSourcePtr src, - int mode); +virStorageSourceAccess(virStorageSourcePtr src, + int mode); int -virStorageFileChown(const virStorageSource *src, - uid_t uid, - gid_t gid); +virStorageSourceChown(const virStorageSource *src, + uid_t uid, + gid_t gid); int -virStorageFileSupportsSecurityDriver(const virStorageSource *src); +virStorageSourceSupportsSecurityDriver(const virStorageSource *src); int -virStorageFileSupportsAccess(const virStorageSource *src); +virStorageSourceSupportsAccess(const virStorageSource *src); int -virStorageFileSupportsCreate(const virStorageSource *src); +virStorageSourceSupportsCreate(const virStorageSource *src); int -virStorageFileSupportsBackingChainTraversal(const virStorageSource *src); +virStorageSourceSupportsBackingChainTraversal(const virStorageSource *src); int -virStorageFileGetMetadata(virStorageSourcePtr src, - uid_t uid, gid_t gid, - bool report_broken) +virStorageSourceGetMetadata(virStorageSourcePtr src, + uid_t uid, gid_t gid, + bool report_broken) ATTRIBUTE_NONNULL(1); int -virStorageFileGetBackingStoreStr(virStorageSourcePtr src, - char **backing) +virStorageSourceGetBackingStoreStr(virStorageSourcePtr src, + char **backing) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); void -virStorageFileReportBrokenChain(int errcode, - virStorageSourcePtr src, - virStorageSourcePtr parent); +virStorageSourceReportBrokenChain(int errcode, + virStorageSourcePtr src, + virStorageSourcePtr parent); diff --git a/tests/virstoragetest.c b/tests/virstoragetest.c index 5c2f211557..0e168ce730 100644 --- a/tests/virstoragetest.c +++ b/tests/virstoragetest.c @@ -101,7 +101,7 @@ testStorageFileGetMetadata(const char *path, def->path = g_strdup(path); - if (virStorageFileGetMetadata(def, uid, gid, true) < 0) + if (virStorageSourceGetMetadata(def, uid, gid, true) < 0) return NULL; return g_steal_pointer(&def); @@ -366,9 +366,9 @@ testStorageLookup(const void *args) } /* Test twice to ensure optional parameter doesn't cause NULL deref. */ - result = virStorageFileChainLookup(data->chain, data->from, - idx ? NULL : data->name, - idx, NULL); + result = virStorageSourceChainLookup(data->chain, data->from, + idx ? NULL : data->name, + idx, NULL); if (!data->expResult) { if (virGetLastErrorCode() == VIR_ERR_OK) { @@ -395,8 +395,8 @@ testStorageLookup(const void *args) ret = -1; } - result = virStorageFileChainLookup(data->chain, data->from, - data->name, idx, &actualParent); + result = virStorageSourceChainLookup(data->chain, data->from, + data->name, idx, &actualParent); if (!data->expResult) virResetLastError(); @@ -552,9 +552,9 @@ testPathRelative(const void *args) const struct testPathRelativeBacking *data = args; g_autofree char *actual = NULL; - if (virStorageFileGetRelativeBackingPath(data->top, - data->base, - &actual) < 0) { + if (virStorageSourceGetRelativeBackingPath(data->top, + data->base, + &actual) < 0) { fprintf(stderr, "relative backing path resolution failed\n"); return -1; } -- 2.29.2

On Thu, Jan 21, 2021 at 20:34:27 +0100, Pavel Hrdina wrote:
Signed-off-by: Pavel Hrdina <phrdina@redhat.com> --- src/libvirt_private.syms | 42 ++--- src/qemu/qemu_backup.c | 8 +- src/qemu/qemu_block.c | 6 +- src/qemu/qemu_domain.c | 16 +- src/qemu/qemu_driver.c | 66 +++---- src/qemu/qemu_hotplug.c | 4 +- src/qemu/qemu_process.c | 4 +- src/qemu/qemu_snapshot.c | 20 +-- src/security/virt-aa-helper.c | 2 +- src/storage/storage_backend_gluster.c | 4 +- src/storage/storage_util.c | 6 +- src/storage_file/storage_source.c | 250 +++++++++++++------------- src/storage_file/storage_source.h | 90 +++++----- tests/virstoragetest.c | 18 +- 14 files changed, 268 insertions(+), 268 deletions(-)
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
participants (2)
-
Pavel Hrdina
-
Peter Krempa