Right now, we are allocating virStorageFileMetadata near the bottom of the callchain, only after we have identified that we are visiting a file (and not a network resource). I'm hoping to eventually support parsing the backing chain from XML, where the backing chain crawl then validates what was parsed rather than allocating a fresh structure. Likewise, I'm working towards a setup where we have a backing element even for networks. Both of these use cases are easier to code if the allocation is hoisted earlier. * src/util/virstoragefile.c (virStorageFileGetMetadataInternal) (virStorageFileGetMetadataFromFDInternal): Change signature. (virStorageFileGetMetadataFromBuf) (virStorageFileGetMetadataRecurse, virStorageFileGetMetadata): Update callers. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- src/util/virstoragefile.c | 126 +++++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 51 deletions(-) diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 336842c..e516acf 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -771,26 +771,24 @@ qcow2GetFeatures(virBitmapPtr *features, /* Given a header in BUF with length LEN, as parsed from the file with * user-provided name PATH and opened from CANONPATH, and where any - * relative backing file will be opened from DIRECTORY, return - * metadata about that file, assuming it has the given FORMAT. */ -static virStorageFileMetadataPtr ATTRIBUTE_NONNULL(1) -ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) + * relative backing file will be opened from DIRECTORY, and assuming + * it has the given FORMAT, populate the newly-allocated META with + * information about the file and its backing store. */ +static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) +ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(7) virStorageFileGetMetadataInternal(const char *path, const char *canonPath, const char *directory, char *buf, size_t len, - int format) + int format, + virStorageFileMetadataPtr meta) { - virStorageFileMetadata *meta = NULL; - virStorageFileMetadata *ret = NULL; + int ret = -1; VIR_DEBUG("path=%s, canonPath=%s, dir=%s, buf=%p, len=%zu, format=%d", path, canonPath, directory, buf, len, format); - if (VIR_ALLOC(meta) < 0) - return NULL; - if (format == VIR_STORAGE_FILE_AUTO) format = virStorageFileProbeFormatFromBuf(path, buf, len); @@ -886,11 +884,9 @@ virStorageFileGetMetadataInternal(const char *path, goto cleanup; done: - ret = meta; - meta = NULL; + ret = 0; cleanup: - virStorageFileFreeMetadata(meta); return ret; } @@ -981,44 +977,52 @@ virStorageFileGetMetadataFromBuf(const char *path, size_t len, int format) { - virStorageFileMetadataPtr ret; + virStorageFileMetadataPtr ret = NULL; char *canonPath; if (!(canonPath = canonicalize_file_name(path))) { virReportSystemError(errno, _("unable to resolve '%s'"), path); return NULL; } + if (VIR_ALLOC(ret) < 0) + goto cleanup; + + if (virStorageFileGetMetadataInternal(path, canonPath, ".", buf, len, + format, ret) < 0) { + virStorageFileFreeMetadata(ret); + ret = NULL; + } - ret = virStorageFileGetMetadataInternal(path, canonPath, ".", buf, len, - format); + cleanup: VIR_FREE(canonPath); return ret; } /* Internal version that also supports a containing directory name. */ -static virStorageFileMetadataPtr +static int virStorageFileGetMetadataFromFDInternal(const char *path, const char *canonPath, const char *directory, int fd, - int format) + int format, + virStorageFileMetadataPtr meta) { char *buf = NULL; ssize_t len = VIR_STORAGE_MAX_HEADER; struct stat sb; - virStorageFileMetadataPtr ret = NULL; + int ret = -1; if (fstat(fd, &sb) < 0) { virReportSystemError(errno, _("cannot stat file '%s'"), path); - return NULL; + return -1; } /* No header to probe for directories, but also no backing file */ if (S_ISDIR(sb.st_mode)) { - ignore_value(VIR_ALLOC(ret)); + ret = 0; goto cleanup; } @@ -1033,7 +1037,8 @@ virStorageFileGetMetadataFromFDInternal(const char *path, } ret = virStorageFileGetMetadataInternal(path, canonPath, directory, - buf, len, format); + buf, len, format, meta); + cleanup: VIR_FREE(buf); return ret; @@ -1063,71 +1068,81 @@ virStorageFileGetMetadataFromFD(const char *path, int fd, int format) { - virStorageFileMetadataPtr ret; + virStorageFileMetadataPtr ret = NULL; char *canonPath; if (!(canonPath = canonicalize_file_name(path))) { virReportSystemError(errno, _("unable to resolve '%s'"), path); return NULL; } - ret = virStorageFileGetMetadataFromFDInternal(path, canonPath, ".", - fd, format); + if (VIR_ALLOC(ret) < 0) + goto cleanup; + if (virStorageFileGetMetadataFromFDInternal(path, canonPath, ".", + fd, format, ret) < 0) { + virStorageFileFreeMetadata(ret); + ret = NULL; + } + + cleanup: VIR_FREE(canonPath); return ret; } /* Recursive workhorse for virStorageFileGetMetadata. */ -static virStorageFileMetadataPtr +static int virStorageFileGetMetadataRecurse(const char *path, const char *canonPath, const char *directory, int format, uid_t uid, gid_t gid, - bool allow_probe, virHashTablePtr cycle) + bool allow_probe, virHashTablePtr cycle, + virStorageFileMetadataPtr meta) { int fd; + int ret = -1; VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d", path, canonPath, NULLSTR(directory), format, (int)uid, (int)gid, allow_probe); - virStorageFileMetadataPtr ret = NULL; - if (virHashLookup(cycle, canonPath)) { virReportError(VIR_ERR_INTERNAL_ERROR, _("backing store for %s is self-referential"), path); - return NULL; + return -1; } if (virHashAddEntry(cycle, canonPath, (void *)1) < 0) - return NULL; + return -1; if ((fd = virFileOpenAs(canonPath, O_RDONLY, 0, uid, gid, 0)) < 0) { virReportSystemError(-fd, _("Failed to open file '%s'"), path); - return NULL; + return -1; } ret = virStorageFileGetMetadataFromFDInternal(path, canonPath, directory, - fd, format); + fd, format, meta); if (VIR_CLOSE(fd) < 0) VIR_WARN("could not close file %s", path); - if (ret && ret->backingStoreIsFile) { - if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe) - ret->backingStoreFormat = VIR_STORAGE_FILE_RAW; - else if (ret->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE) - ret->backingStoreFormat = VIR_STORAGE_FILE_AUTO; - format = ret->backingStoreFormat; - ret->backingMeta = virStorageFileGetMetadataRecurse(ret->backingStoreRaw, - ret->backingStore, - ret->directory, - format, - uid, gid, - allow_probe, - cycle); - if (!ret->backingMeta) { + if (ret == 0 && meta->backingStoreIsFile) { + virStorageFileMetadataPtr backing; + + if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO && !allow_probe) + meta->backingStoreFormat = VIR_STORAGE_FILE_RAW; + else if (meta->backingStoreFormat == VIR_STORAGE_FILE_AUTO_SAFE) + meta->backingStoreFormat = VIR_STORAGE_FILE_AUTO; + format = meta->backingStoreFormat; + if (VIR_ALLOC(backing) < 0 || + virStorageFileGetMetadataRecurse(meta->backingStoreRaw, + meta->backingStore, + meta->directory, format, + uid, gid, allow_probe, + cycle, backing) < 0) { /* If we failed to get backing data, mark the chain broken */ - ret->backingStoreFormat = VIR_STORAGE_FILE_NONE; - VIR_FREE(ret->backingStore); + meta->backingStoreFormat = VIR_STORAGE_FILE_NONE; + VIR_FREE(meta->backingStore); + virStorageFileFreeMetadata(backing); + } else { + meta->backingMeta = backing; } } return ret; @@ -1164,6 +1179,7 @@ virStorageFileGetMetadata(const char *path, int format, path, format, (int)uid, (int)gid, allow_probe); virHashTablePtr cycle = virHashCreate(5, NULL); + virStorageFileMetadataPtr meta = NULL; virStorageFileMetadataPtr ret = NULL; char *canonPath = NULL; char *directory = NULL; @@ -1179,12 +1195,20 @@ virStorageFileGetMetadata(const char *path, int format, virReportOOMError(); goto cleanup; } + if (VIR_ALLOC(meta) < 0) + goto cleanup; if (format <= VIR_STORAGE_FILE_NONE) format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW; - ret = virStorageFileGetMetadataRecurse(path, canonPath, directory, format, - uid, gid, allow_probe, cycle); + if (virStorageFileGetMetadataRecurse(path, canonPath, directory, format, + uid, gid, allow_probe, cycle, + meta) < 0) + goto cleanup; + ret = meta; + meta = NULL; + cleanup: + virStorageFileFreeMetadata(meta); VIR_FREE(canonPath); VIR_FREE(directory); virHashFree(cycle); -- 1.9.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list