static virStorageSourcePtr testStorageFileGetMetadata(const char *path, int format, uid_t uid, gid_t gid, bool allow_probe) { virStorageSourcePtr ret = NULL; if (VIR_ALLOC(ret) < 0) return NULL; ret->type = VIR_STORAGE_TYPE_FILE; ret->format = format; if (VIR_STRDUP(ret->relPath, path) < 0) goto error; if (!(ret->relDir = mdir_name(path))) { virReportOOMError(); goto error; } if (!(ret->path = canonicalize_file_name(path))) { virReportError(VIR_ERR_INTERNAL_ERROR, "failed to resolve '%s'", path); goto error; } if (virStorageFileGetMetadata(ret, uid, gid, allow_probe) < 0) goto error; return ret; error: virStorageSourceFree(ret); return NULL; }
static virStorageSourcePtr testStorageFileGetMetadata(const char *path, int format, uid_t uid, gid_t gid, bool allow_probe) { struct stat st; virStorageSourcePtr ret = NULL; if (VIR_ALLOC(ret) < 0) return NULL; ret->type = VIR_STORAGE_TYPE_FILE; ret->format = format; if (stat(path, &st) == 0) { if (S_ISDIR(st.st_mode)) { ret->type = VIR_STORAGE_TYPE_DIR; ret->format = VIR_STORAGE_FILE_DIR; } else if (S_ISBLK(st.st_mode)) { ret->type = VIR_STORAGE_TYPE_BLOCK; } } if (VIR_STRDUP(ret->path, path) < 0) goto error; if (virStorageFileGetMetadata(ret, uid, gid, allow_probe, false) < 0) goto error; return ret; error: virStorageSourceFree(ret); return NULL; }
static int testStorageChain(const void *args) { const struct testChainData *data = args; int ret = -1; virStorageFileMetadataPtr meta; virStorageFileMetadataPtr elt; int i = 0; meta = virStorageFileGetMetadata(data->start, data->format, -1, -1, (data->flags & ALLOW_PROBE) != 0); if (!meta) { if (data->flags & EXP_FAIL) { virResetLastError(); ret = 0; } goto cleanup; } else if (data->flags & EXP_FAIL) { fprintf(stderr, "call should have failed\n"); goto cleanup; } if (data->flags & EXP_WARN) { if (!virGetLastError()) { fprintf(stderr, "call should have warned\n"); goto cleanup; } virResetLastError(); } else if (virGetLastError()) { fprintf(stderr, "call should not have warned\n"); goto cleanup; } elt = meta; while (elt) { char *expect = NULL; char *actual = NULL; if (i == data->nfiles) { fprintf(stderr, "probed chain was too long\n"); goto cleanup; } if (virAsprintf(&expect, "store:%s\nraw:%s\ndirectory:%s\nother:%d %d %lld %d", NULLSTR(data->files[i].expBackingStore), NULLSTR(data->files[i].expBackingStoreRaw), NULLSTR(data->files[i].expDirectory), data->files[i].expFormat, data->files[i].expIsFile, data->files[i].expCapacity, data->files[i].expEncrypted) < 0 || virAsprintf(&actual, "store:%s\nraw:%s\ndirectory:%s\nother:%d %d %lld %d", NULLSTR(elt->backingStore), NULLSTR(elt->backingStoreRaw), NULLSTR(elt->directory), elt->backingStoreFormat, elt->backingStoreIsFile, elt->capacity, elt->encrypted) < 0) { virReportOOMError(); VIR_FREE(expect); VIR_FREE(actual); goto cleanup; } if (STRNEQ(expect, actual)) { virtTestDifference(stderr, expect, actual); VIR_FREE(expect); VIR_FREE(actual); goto cleanup; } VIR_FREE(expect); VIR_FREE(actual); elt = elt->backingMeta; i++; } if (i != data->nfiles) { fprintf(stderr, "probed chain was too short\n"); goto cleanup; } ret = 0; cleanup: virStorageFileFreeMetadata(meta); return ret; }
static int mymain(void) { int ret; virCommandPtr cmd = NULL; struct testChainData data; virStorageFileMetadataPtr chain = NULL; /* Prep some files with qemu-img; if that is not found on PATH, or * if it lacks support for qcow2 and qed, skip this test. */ if ((ret = testPrepImages()) != 0) return ret; #define TEST_ONE_CHAIN(id, start, format, flags, ...) \ do { \ size_t i; \ memset(&data, 0, sizeof(data)); \ data = (struct testChainData){ \ start, format, { __VA_ARGS__ }, 0, flags, \ }; \ for (i = 0; i < ARRAY_CARDINALITY(data.files); i++) \ if (data.files[i]) \ data.nfiles++; \ if (virtTestRun("Storage backing chain " id, \ testStorageChain, &data) < 0) \ ret = -1; \ } while (0) #define VIR_FLATTEN_2(...) __VA_ARGS__ #define VIR_FLATTEN_1(_1) VIR_FLATTEN_2 _1 #define TEST_CHAIN(id, relstart, absstart, format, chain1, flags1, \ chain2, flags2, chain3, flags3, chain4, flags4) \ do { \ TEST_ONE_CHAIN(#id "a", relstart, format, flags1, \ VIR_FLATTEN_1(chain1)); \ TEST_ONE_CHAIN(#id "b", relstart, format, flags2, \ VIR_FLATTEN_1(chain2)); \ TEST_ONE_CHAIN(#id "c", absstart, format, flags3 | ABS_START,\ VIR_FLATTEN_1(chain3)); \ TEST_ONE_CHAIN(#id "d", absstart, format, flags4 | ABS_START,\ VIR_FLATTEN_1(chain4)); \ } while (0) /* The actual tests, in several groups. */ /* Missing file */ TEST_ONE_CHAIN("0", "bogus", VIR_STORAGE_FILE_RAW, EXP_FAIL); /* Raw image, whether with right format or no specified format */ testFileData raw = { .pathRel = "raw", .pathAbs = canonraw, .canonPath = canonraw, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_RAW, }; TEST_CHAIN(1, "raw", absraw, VIR_STORAGE_FILE_RAW, (&raw), EXP_PASS, (&raw), ALLOW_PROBE | EXP_PASS, (&raw), EXP_PASS, (&raw), ALLOW_PROBE | EXP_PASS); TEST_CHAIN(2, "raw", absraw, VIR_STORAGE_FILE_AUTO, (&raw), EXP_PASS, (&raw), ALLOW_PROBE | EXP_PASS, (&raw), EXP_PASS, (&raw), ALLOW_PROBE | EXP_PASS); /* Qcow2 file with relative raw backing, format provided */ raw.pathAbs = "raw"; testFileData qcow2 = { .expBackingStore = canonraw, .expBackingStoreRaw = "raw", .expCapacity = 1024, .pathRel = "qcow2", .pathAbs = canonqcow2, .canonPath = canonqcow2, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, }; testFileData qcow2_as_raw = { .pathRel = "qcow2", .pathAbs = canonqcow2, .canonPath = canonqcow2, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_RAW, }; TEST_CHAIN(3, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2, &raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&qcow2, &raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS); TEST_CHAIN(4, "qcow2", absqcow2, VIR_STORAGE_FILE_AUTO, (&qcow2_as_raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&qcow2_as_raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS); /* Rewrite qcow2 file to use absolute backing name */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "raw", "-b", absraw, "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2.expBackingStoreRaw = absraw; raw.pathRel = absraw; raw.pathAbs = absraw; raw.relDirRel = datadir; /* Qcow2 file with raw as absolute backing, backing format provided */ TEST_CHAIN(5, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2, &raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&qcow2, &raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS); TEST_CHAIN(6, "qcow2", absqcow2, VIR_STORAGE_FILE_AUTO, (&qcow2_as_raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&qcow2_as_raw), EXP_PASS, (&qcow2, &raw), ALLOW_PROBE | EXP_PASS); /* Wrapped file access */ testFileData wrap = { .expBackingStore = canonqcow2, .expBackingStoreRaw = absqcow2, .expCapacity = 1024, .pathRel = "wrap", .pathAbs = abswrap, .canonPath = canonwrap, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, }; qcow2.pathRel = absqcow2; qcow2.relDirRel = datadir; TEST_CHAIN(7, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2, (&wrap, &qcow2, &raw), EXP_PASS, (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&wrap, &qcow2, &raw), EXP_PASS, (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS); /* Rewrite qcow2 and wrap file to omit backing file type */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-b", absraw, "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-b", absqcow2, "wrap", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2_as_raw.pathRel = absqcow2; qcow2_as_raw.relDirRel = datadir; /* Qcow2 file with raw as absolute backing, backing format omitted */ testFileData wrap_as_raw = { .expBackingStore = canonqcow2, .expBackingStoreRaw = absqcow2, .expCapacity = 1024, .pathRel = "wrap", .pathAbs = abswrap, .canonPath = canonwrap, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, }; TEST_CHAIN(8, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2, (&wrap_as_raw, &qcow2_as_raw), EXP_PASS, (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS, (&wrap_as_raw, &qcow2_as_raw), EXP_PASS, (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS); /* Rewrite qcow2 to a missing backing file, with backing type */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", datadir "/bogus", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2.expBackingStore = NULL; qcow2.expBackingStoreRaw = datadir "/bogus"; qcow2.pathRel = "qcow2"; qcow2.relDirRel = "."; /* Qcow2 file with missing backing file but specified type */ TEST_CHAIN(9, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN); /* Rewrite qcow2 to a missing backing file, without backing type */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-b", datadir "/bogus", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; /* Qcow2 file with missing backing file and no specified type */ TEST_CHAIN(10, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN); /* Rewrite qcow2 to use an nbd: protocol as backend */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "raw", "-b", "nbd:example.org:6000", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2.expBackingStore = "nbd:example.org:6000"; qcow2.expBackingStoreRaw = "nbd:example.org:6000"; /* Qcow2 file with backing protocol instead of file */ testFileData nbd = { .pathRel = "nbd:example.org:6000", .pathAbs = "nbd:example.org:6000", .canonPath = "nbd:example.org:6000", .type = VIR_STORAGE_TYPE_NETWORK, .format = VIR_STORAGE_FILE_RAW, }; TEST_CHAIN(11, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2, &nbd), EXP_PASS, (&qcow2, &nbd), ALLOW_PROBE | EXP_PASS, (&qcow2, &nbd), EXP_PASS, (&qcow2, &nbd), ALLOW_PROBE | EXP_PASS); /* qed file */ testFileData qed = { .expBackingStore = canonraw, .expBackingStoreRaw = absraw, .expCapacity = 1024, .pathRel = "qed", .pathAbs = absqed, .canonPath = canonqed, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QED, }; testFileData qed_as_raw = { .pathRel = "qed", .pathAbs = absqed, .canonPath = canonqed, .relDirRel = ".", .relDirAbs = datadir, .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_RAW, }; TEST_CHAIN(12, "qed", absqed, VIR_STORAGE_FILE_AUTO, (&qed_as_raw), EXP_PASS, (&qed, &raw), ALLOW_PROBE | EXP_PASS, (&qed_as_raw), EXP_PASS, (&qed, &raw), ALLOW_PROBE | EXP_PASS); /* directory */ testFileData dir = { .pathRel = "dir", .pathAbs = absdir, .type = VIR_STORAGE_TYPE_DIR, .format = VIR_STORAGE_FILE_DIR, }; TEST_CHAIN(13, "dir", absdir, VIR_STORAGE_FILE_AUTO, (&dir), EXP_PASS, (&dir), ALLOW_PROBE | EXP_PASS, (&dir), EXP_PASS, (&dir), ALLOW_PROBE | EXP_PASS); TEST_CHAIN(14, "dir", absdir, VIR_STORAGE_FILE_DIR, (&dir), EXP_PASS, (&dir), ALLOW_PROBE | EXP_PASS, (&dir), EXP_PASS, (&dir), ALLOW_PROBE | EXP_PASS); #ifdef HAVE_SYMLINK /* Rewrite qcow2 and wrap file to use backing names relative to a * symlink from a different directory */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "raw", "-b", "../raw", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", "../sub/link1", "wrap", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; /* Behavior of symlinks to qcow2 with relative backing files */ testFileData link1 = { .expBackingStore = canonraw, .expBackingStoreRaw = "../raw", .expCapacity = 1024, .pathRel = "../sub/link1", .pathAbs = "../sub/link1", .canonPath = canonqcow2, .relDirRel = "sub/../sub", .relDirAbs = datadir "/sub/../sub", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, }; testFileData link2 = { .expBackingStore = canonqcow2, .expBackingStoreRaw = "../sub/link1", .expCapacity = 1024, .pathRel = "sub/link2", .pathAbs = abslink2, .canonPath = canonwrap, .relDirRel = "sub", .relDirAbs = datadir "/sub", .type = VIR_STORAGE_TYPE_FILE, .format = VIR_STORAGE_FILE_QCOW2, }; raw.pathRel = "../raw"; raw.pathAbs = "../raw"; raw.relDirRel = "sub/../sub/.."; raw.relDirAbs = datadir "/sub/../sub/.."; TEST_CHAIN(15, "sub/link2", abslink2, VIR_STORAGE_FILE_QCOW2, (&link2, &link1, &raw), EXP_PASS, (&link2, &link1, &raw), ALLOW_PROBE | EXP_PASS, (&link2, &link1, &raw), EXP_PASS, (&link2, &link1, &raw), ALLOW_PROBE | EXP_PASS); #endif /* Rewrite qcow2 to be a self-referential loop */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", "qcow2", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2.expBackingStore = NULL; qcow2.expBackingStoreRaw = "qcow2"; /* Behavior of an infinite loop chain */ TEST_CHAIN(16, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN, (&qcow2), EXP_WARN, (&qcow2), ALLOW_PROBE | EXP_WARN); /* Rewrite wrap and qcow2 to be mutually-referential loop */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", "wrap", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", absqcow2, "wrap", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; qcow2.expBackingStoreRaw = "wrap"; qcow2.pathRel = absqcow2; qcow2.relDirRel = datadir; /* Behavior of an infinite loop chain */ TEST_CHAIN(17, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2, (&wrap, &qcow2), EXP_WARN, (&wrap, &qcow2), ALLOW_PROBE | EXP_WARN, (&wrap, &qcow2), EXP_WARN, (&wrap, &qcow2), ALLOW_PROBE | EXP_WARN); /* Rewrite wrap and qcow2 back to 3-deep chain, absolute backing */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", absraw, "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; /* Test behavior of chain lookups, absolute backing from relative start */ chain = virStorageFileGetMetadata("wrap", VIR_STORAGE_FILE_QCOW2, -1, -1, false); if (!chain) { ret = -1; goto cleanup; } #define TEST_LOOKUP(id, name, result, meta, parent) \ do { \ struct testLookupData data2 = { chain, name, \ result, meta, parent, }; \ if (virtTestRun("Chain lookup " #id, \ testStorageLookup, &data2) < 0) \ ret = -1; \ } while (0) TEST_LOOKUP(0, "bogus", NULL, NULL, NULL); TEST_LOOKUP(1, "wrap", chain->canonPath, chain, NULL); TEST_LOOKUP(2, abswrap, chain->canonPath, chain, NULL); TEST_LOOKUP(3, "qcow2", chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(4, absqcow2, chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(5, "raw", chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(6, absraw, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(7, NULL, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); /* Rewrite wrap and qcow2 back to 3-deep chain, relative backing */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "raw", "-b", "raw", "qcow2", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", "qcow2", "wrap", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; /* Test behavior of chain lookups, relative backing from absolute start */ virStorageFileFreeMetadata(chain); chain = virStorageFileGetMetadata(abswrap, VIR_STORAGE_FILE_QCOW2, -1, -1, false); if (!chain) { ret = -1; goto cleanup; } TEST_LOOKUP(8, "bogus", NULL, NULL, NULL); TEST_LOOKUP(9, "wrap", chain->canonPath, chain, NULL); TEST_LOOKUP(10, abswrap, chain->canonPath, chain, NULL); TEST_LOOKUP(11, "qcow2", chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(12, absqcow2, chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(13, "raw", chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(14, absraw, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(15, NULL, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); /* Use link to wrap with cross-directory relative backing */ virCommandFree(cmd); cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2", "-F", "qcow2", "-b", "../qcow2", "wrap", NULL); if (virCommandRun(cmd, NULL) < 0) ret = -1; /* Test behavior of chain lookups, relative backing */ virStorageFileFreeMetadata(chain); chain = virStorageFileGetMetadata("sub/link2", VIR_STORAGE_FILE_QCOW2, -1, -1, false); if (!chain) { ret = -1; goto cleanup; } TEST_LOOKUP(16, "bogus", NULL, NULL, NULL); TEST_LOOKUP(17, "sub/link2", chain->canonPath, chain, NULL); TEST_LOOKUP(18, "wrap", chain->canonPath, chain, NULL); TEST_LOOKUP(19, abswrap, chain->canonPath, chain, NULL); TEST_LOOKUP(20, "../qcow2", chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(21, "qcow2", NULL, NULL, NULL); TEST_LOOKUP(22, absqcow2, chain->backingStore, chain->backingMeta, chain->canonPath); TEST_LOOKUP(23, "raw", chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(24, absraw, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); TEST_LOOKUP(25, NULL, chain->backingMeta->backingStore, chain->backingMeta->backingMeta, chain->backingStore); cleanup: /* Final cleanup */ virStorageFileFreeMetadata(chain); testCleanupImages(); virCommandFree(cmd); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } VIRT_TEST_MAIN(mymain)
static int testStorageChain(const void *args) { const struct testChainData *data = args; int ret = -1; virStorageFileMetadataPtr meta; virStorageFileMetadataPtr elt; size_t i = 0; char *broken = NULL; bool isAbs = !!(data->flags & ABS_START); meta = virStorageFileGetMetadata(data->start, data->format, -1, -1, (data->flags & ALLOW_PROBE) != 0); if (!meta) { if (data->flags & EXP_FAIL) { virResetLastError(); ret = 0; } goto cleanup; } else if (data->flags & EXP_FAIL) { fprintf(stderr, "call should have failed\n"); goto cleanup; } if (data->flags & EXP_WARN) { if (!virGetLastError()) { fprintf(stderr, "call should have warned\n"); goto cleanup; } virResetLastError(); if (virStorageFileChainGetBroken(meta, &broken) || !broken) { fprintf(stderr, "call should identify broken part of chain\n"); goto cleanup; } } else { if (virGetLastError()) { fprintf(stderr, "call should not have warned\n"); goto cleanup; } if (virStorageFileChainGetBroken(meta, &broken) || broken) { fprintf(stderr, "chain should not be identified as broken\n"); goto cleanup; } } elt = meta; while (elt) { char *expect = NULL; char *actual = NULL; const char *expPath; const char *expRelDir; if (i == data->nfiles) { fprintf(stderr, "probed chain was too long\n"); goto cleanup; } expPath = isAbs ? data->files[i]->pathAbs : data->files[i]->pathRel; expRelDir = isAbs ? data->files[i]->relDirAbs : data->files[i]->relDirRel; if (virAsprintf(&expect, "store:%s\nraw:%s\nother:%lld %d\n" "path:%s\ncanon:%s\nrelDir:%s\ntype:%d %d\n", NULLSTR(data->files[i]->expBackingStore), NULLSTR(data->files[i]->expBackingStoreRaw), data->files[i]->expCapacity, data->files[i]->expEncrypted, NULLSTR(expPath), NULLSTR(data->files[i]->canonPath), NULLSTR(expRelDir), data->files[i]->type, data->files[i]->format) < 0 || virAsprintf(&actual, "store:%s\nraw:%s\nother:%lld %d\n" "path:%s\ncanon:%s\nrelDir:%s\ntype:%d %d\n", NULLSTR(elt->backingStore), NULLSTR(elt->backingStoreRaw), elt->capacity, !!elt->encryption, NULLSTR(elt->path), NULLSTR(elt->canonPath), NULLSTR(elt->relDir), elt->type, elt->format) < 0) { VIR_FREE(expect); VIR_FREE(actual); goto cleanup; } if (STRNEQ(expect, actual)) { fprintf(stderr, "chain member %zu", i); virtTestDifference(stderr, expect, actual); VIR_FREE(expect); VIR_FREE(actual); goto cleanup; } VIR_FREE(expect); VIR_FREE(actual); elt = elt->backingMeta; i++; } if (i != data->nfiles) { fprintf(stderr, "probed chain was too short\n"); goto cleanup; } ret = 0; cleanup: VIR_FREE(broken); virStorageFileFreeMetadata(meta); return ret; }