diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 1a0c2f6ce78e5aef44614a8858c5f490a5cbd63d..160573cbd70257cf51f16a79b11d82875f7050b6 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1132,6 +1132,7 @@ virStorageGenerateQcowPassphrase; # storage_file.h +virStorageFileChainLookup; virStorageFileFormatTypeFromString; virStorageFileFormatTypeToString; virStorageFileFreeMetadata; diff --git a/src/util/storage_file.c b/src/util/storage_file.c index 2ff444c03bca92fe6049115983214fc67172b73e..882df6ef11a126a4268cf24fc913efafb425ff2e 100644 --- a/src/util/storage_file.c +++ b/src/util/storage_file.c @@ -1262,3 +1262,67 @@ const char *virStorageFileGetSCSIKey(const char *path) return NULL; } #endif + +/* Given a CHAIN that starts at the named file START, return a string + * pointing to either START or within CHAIN that gives the preferred + * name for the backing file NAME within that chain. Pass NULL for + * NAME to find the base of the chain. If META is not NULL, set *META + * to the point in the chain that describes NAME (or to NULL if the + * backing element is not a file). If PARENT is not NULL, set *PARENT + * to the preferred name of the parent (or to NULL if NAME matches + * START). Since the results point within CHAIN, they must not be + * independently freed. */ +const char * +virStorageFileChainLookup(virStorageFileMetadataPtr chain, const char *start, + const char *name, virStorageFileMetadataPtr *meta, + const char **parent) +{ + virStorageFileMetadataPtr owner; + const char *tmp; + + if (!parent) + parent = &tmp; + + *parent = NULL; + if (name ? STREQ(start, name) || virFileLinkPointsTo(start, name) : + !chain->backingStore) { + if (meta) + *meta = chain; + return start; + } + + owner = chain; + *parent = start; + while (owner) { + if (!owner->backingStore) + goto error; + if (!name) { + if (!owner->backingMeta || + !owner->backingMeta->backingStore) + break; + } else if (STREQ_NULLABLE(name, owner->backingStoreRaw) || + STREQ(name, owner->backingStore)) { + break; + } else if (owner->backingStoreIsFile) { + char *absName = absolutePathFromBaseFile(*parent, name); + if (absName && STREQ(absName, owner->backingStore)) { + VIR_FREE(absName); + break; + } + VIR_FREE(absName); + } + *parent = owner->backingStore; + owner = owner->backingMeta; + } + if (!owner) + goto error; + if (meta) + *meta = owner->backingMeta; + return owner->backingStore; + +error: + *parent = NULL; + if (meta) + *meta = NULL; + return NULL; +} diff --git a/src/util/storage_file.h b/src/util/storage_file.h index 685fcb84610e7310824eefd7a88eff77e766a945..9b00dba28c9774c96b6f9608e536b0c04757f2f2 100644 --- a/src/util/storage_file.h +++ b/src/util/storage_file.h @@ -78,6 +78,13 @@ virStorageFileMetadataPtr virStorageFileGetMetadataFromFD(const char *path, int fd, int format); +const char *virStorageFileChainLookup(virStorageFileMetadataPtr chain, + const char *start, + const char *name, + virStorageFileMetadataPtr *meta, + const char **parent) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + void virStorageFileFreeMetadata(virStorageFileMetadataPtr meta); int virStorageFileResize(const char *path, unsigned long long capacity);