You need to sign in or sign up before continuing.
virstoragetest.c 23.1 KB
Newer Older
1
/*
2
 * Copyright (C) 2013-2014 Red Hat, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * 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/>.
 *
 * Author: Eric Blake <eblake@redhat.com>
 */

#include <config.h>

#include <stdlib.h>

#include "testutils.h"
#include "vircommand.h"
#include "virerror.h"
28
#include "virfile.h"
29 30
#include "virlog.h"
#include "virstoragefile.h"
31
#include "virstring.h"
32 33 34

#define VIR_FROM_THIS VIR_FROM_NONE

35 36
VIR_LOG_INIT("tests.storagetest");

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#define datadir abs_builddir "/virstoragedata"

/* This test creates the following files, all in datadir:

 * raw: 1024-byte raw file
 * qcow2: qcow2 file with 'raw' as backing
 * wrap: qcow2 file with 'qcow2' as backing
 * qed: qed file with 'raw' as backing
 * sub/link1: symlink to qcow2
 * sub/link2: symlink to wrap
 *
 * Relative names to these files are known at compile time, but absolute
 * and canonical names depend on where the test is run; for convenience,
 * we pre-populate the computation of these names for use during the test.
*/

static char *qemuimg;
static char *absraw;
static char *canonraw;
static char *absqcow2;
static char *canonqcow2;
static char *abswrap;
static char *absqed;
E
Eric Blake 已提交
60
static char *absdir;
61 62 63 64 65 66 67 68 69 70 71 72
static char *abslink2;

static void
testCleanupImages(void)
{
    VIR_FREE(qemuimg);
    VIR_FREE(absraw);
    VIR_FREE(canonraw);
    VIR_FREE(absqcow2);
    VIR_FREE(canonqcow2);
    VIR_FREE(abswrap);
    VIR_FREE(absqed);
E
Eric Blake 已提交
73
    VIR_FREE(absdir);
74 75 76 77 78 79 80 81
    VIR_FREE(abslink2);

    if (chdir(abs_builddir) < 0) {
        fprintf(stderr, "unable to return to correct directory, refusing to "
                "clean up %s\n", datadir);
        return;
    }

82
    virFileDeleteTree(datadir);
83 84 85 86 87 88 89
}

static int
testPrepImages(void)
{
    int ret = EXIT_FAILURE;
    virCommandPtr cmd = NULL;
90 91
    char *buf = NULL;
    bool compat = false;
92 93 94 95

    qemuimg = virFindFileInPath("kvm-img");
    if (!qemuimg)
        qemuimg = virFindFileInPath("qemu-img");
96 97
    if (!qemuimg)
        goto skip;
98

99 100 101 102 103 104 105 106 107 108 109 110
    /* See if qemu-img supports '-o compat=xxx'.  If so, we force the
     * use of both v2 and v3 files; if not, it is v2 only but the test
     * still works. */
    cmd = virCommandNewArgList(qemuimg, "create", "-f", "qcow2",
                               "-o?", "/dev/null", NULL);
    virCommandSetOutputBuffer(cmd, &buf);
    if (virCommandRun(cmd, NULL) < 0)
        goto skip;
    if (strstr(buf, "compat "))
        compat = true;
    VIR_FREE(buf);

111 112 113 114
    if (virAsprintf(&absraw, "%s/raw", datadir) < 0 ||
        virAsprintf(&absqcow2, "%s/qcow2", datadir) < 0 ||
        virAsprintf(&abswrap, "%s/wrap", datadir) < 0 ||
        virAsprintf(&absqed, "%s/qed", datadir) < 0 ||
E
Eric Blake 已提交
115
        virAsprintf(&absdir, "%s/dir", datadir) < 0 ||
116
        virAsprintf(&abslink2, "%s/sub/link2", datadir) < 0)
117 118 119 120 121 122
        goto cleanup;

    if (virFileMakePath(datadir "/sub") < 0) {
        fprintf(stderr, "unable to create directory %s\n", datadir "/sub");
        goto cleanup;
    }
E
Eric Blake 已提交
123 124 125 126
    if (virFileMakePath(datadir "/dir") < 0) {
        fprintf(stderr, "unable to create directory %s\n", datadir "/dir");
        goto cleanup;
    }
127 128 129 130 131 132

    if (chdir(datadir) < 0) {
        fprintf(stderr, "unable to test relative backing chains\n");
        goto cleanup;
    }

133 134
    if (virAsprintf(&buf, "%1024d", 0) < 0 ||
        virFileWriteStr("raw", buf, 0600) < 0) {
135
        fprintf(stderr, "unable to create raw file\n");
136
        goto cleanup;
137
    }
138 139 140 141 142 143 144 145
    if (!(canonraw = canonicalize_file_name(absraw))) {
        virReportOOMError();
        goto cleanup;
    }

    /* Create a qcow2 wrapping relative raw; later on, we modify its
     * metadata to test other configurations */
    virCommandFree(cmd);
146 147 148 149
    cmd = virCommandNewArgList(qemuimg, "create", "-f", "qcow2", NULL);
    virCommandAddArgFormat(cmd, "-obacking_file=raw,backing_fmt=raw%s",
                           compat ? ",compat=0.10" : "");
    virCommandAddArg(cmd, "qcow2");
150
    if (virCommandRun(cmd, NULL) < 0)
151
        goto skip;
152 153
    /* Make sure our later uses of 'qemu-img rebase' will work */
    virCommandFree(cmd);
154
    cmd = virCommandNewArgList(qemuimg, "rebase", "-u", "-f", "qcow2",
155
                               "-F", "raw", "-b", "raw", "qcow2", NULL);
156 157
    if (virCommandRun(cmd, NULL) < 0)
        goto skip;
158 159 160 161 162 163 164 165
    if (!(canonqcow2 = canonicalize_file_name(absqcow2))) {
        virReportOOMError();
        goto cleanup;
    }

    /* Create a second qcow2 wrapping the first, to be sure that we
     * can correctly avoid insecure probing.  */
    virCommandFree(cmd);
166
    cmd = virCommandNewArgList(qemuimg, "create", "-f", "qcow2", NULL);
167 168
    virCommandAddArgFormat(cmd, "-obacking_file=%s,backing_fmt=qcow2%s",
                           absqcow2, compat ? ",compat=1.1" : "");
169 170
    virCommandAddArg(cmd, "wrap");
    if (virCommandRun(cmd, NULL) < 0)
171
        goto skip;
172 173 174

    /* Create a qed file. */
    virCommandFree(cmd);
175
    cmd = virCommandNewArgList(qemuimg, "create", "-f", "qed", NULL);
176 177 178 179
    virCommandAddArgFormat(cmd, "-obacking_file=%s,backing_fmt=raw",
                           absraw);
    virCommandAddArg(cmd, "qed");
    if (virCommandRun(cmd, NULL) < 0)
180
        goto skip;
181

182
#ifdef HAVE_SYMLINK
183 184 185 186 187 188
    /* Create some symlinks in a sub-directory. */
    if (symlink("../qcow2", datadir "/sub/link1") < 0 ||
        symlink("../wrap", datadir "/sub/link2") < 0) {
        fprintf(stderr, "unable to create symlink");
        goto cleanup;
    }
189
#endif
190 191

    ret = 0;
192
 cleanup:
193
    VIR_FREE(buf);
194 195 196 197
    virCommandFree(cmd);
    if (ret)
        testCleanupImages();
    return ret;
198

199
 skip:
200 201 202
    fputs("qemu-img is too old; skipping this test\n", stderr);
    ret = EXIT_AM_SKIP;
    goto cleanup;
203 204
}

205 206 207 208 209
/* Many fields of virStorageFileMetadata have the same content whether
 * we access the file relatively or absolutely; but file names differ
 * depending on how the chain was opened.  For ease of testing, we
 * test both relative and absolute starts, and use a flag to say which
 * of the two variations to compare against.  */
210 211 212 213 214
typedef struct _testFileData testFileData;
struct _testFileData
{
    const char *expBackingStore;
    const char *expBackingStoreRaw;
215 216
    const char *expDirectoryRel;
    const char *expDirectoryAbs;
217 218 219 220 221 222 223 224 225 226 227
    enum virStorageFileFormat expFormat;
    bool expIsFile;
    unsigned long long expCapacity;
    bool expEncrypted;
};

enum {
    EXP_PASS = 0,
    EXP_FAIL = 1,
    EXP_WARN = 2,
    ALLOW_PROBE = 4,
228
    ABS_START = 8,
229 230 231 232 233 234
};

struct testChainData
{
    const char *start;
    enum virStorageFileFormat format;
235
    const testFileData *files[4];
236 237 238 239 240 241 242 243 244 245 246
    int nfiles;
    unsigned int flags;
};

static int
testStorageChain(const void *args)
{
    const struct testChainData *data = args;
    int ret = -1;
    virStorageFileMetadataPtr meta;
    virStorageFileMetadataPtr elt;
247
    size_t i = 0;
E
Eric Blake 已提交
248
    char *broken = NULL;
249
    bool isAbs = !!(data->flags & ABS_START);
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

    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();
E
Eric Blake 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281
        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;
        }
282 283 284 285 286 287
    }

    elt = meta;
    while (elt) {
        char *expect = NULL;
        char *actual = NULL;
288
        const char *expDirectory;
289 290 291 292 293 294

        if (i == data->nfiles) {
            fprintf(stderr, "probed chain was too long\n");
            goto cleanup;
        }

295
        expDirectory = isAbs ? data->files[i]->expDirectoryAbs
296
            : data->files[i]->expDirectoryRel;
297 298
        if (virAsprintf(&expect,
                        "store:%s\nraw:%s\ndirectory:%s\nother:%d %d %lld %d",
299 300
                        NULLSTR(data->files[i]->expBackingStore),
                        NULLSTR(data->files[i]->expBackingStoreRaw),
301
                        NULLSTR(expDirectory),
302 303 304 305
                        data->files[i]->expFormat,
                        data->files[i]->expIsFile,
                        data->files[i]->expCapacity,
                        data->files[i]->expEncrypted) < 0 ||
306 307 308 309 310 311
            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,
312
                        elt->capacity, !!elt->encryption) < 0) {
313 314 315 316 317
            VIR_FREE(expect);
            VIR_FREE(actual);
            goto cleanup;
        }
        if (STRNEQ(expect, actual)) {
318
            fprintf(stderr, "chain member %zu", i);
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
            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;
335
 cleanup:
E
Eric Blake 已提交
336
    VIR_FREE(broken);
337 338 339 340 341 342 343 344 345
    virStorageFileFreeMetadata(meta);
    return ret;
}

static int
mymain(void)
{
    int ret;
    virCommandPtr cmd = NULL;
346
    struct testChainData data;
347 348 349 350 351 352

    /* 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;

353
#define TEST_ONE_CHAIN(id, start, format, flags, ...)                \
354
    do {                                                             \
355 356 357 358
        size_t i;                                                    \
        memset(&data, 0, sizeof(data));                              \
        data = (struct testChainData){                               \
            start, format, { __VA_ARGS__ }, 0, flags,                \
359
        };                                                           \
360 361 362
        for (i = 0; i < ARRAY_CARDINALITY(data.files); i++)          \
            if (data.files[i])                                       \
                data.nfiles++;                                       \
363
        if (virtTestRun("Storage backing chain " id,                 \
364 365 366 367
                        testStorageChain, &data) < 0)                \
            ret = -1;                                                \
    } while (0)

368 369 370
#define VIR_FLATTEN_2(...) __VA_ARGS__
#define VIR_FLATTEN_1(_1) VIR_FLATTEN_2 _1

371 372 373
#define TEST_CHAIN(id, relstart, absstart, format, chain1, flags1,   \
                   chain2, flags2, chain3, flags3, chain4, flags4)   \
    do {                                                             \
374 375 376 377
        TEST_ONE_CHAIN(#id "a", relstart, format, flags1,            \
                       VIR_FLATTEN_1(chain1));                       \
        TEST_ONE_CHAIN(#id "b", relstart, format, flags2,            \
                       VIR_FLATTEN_1(chain2));                       \
378
        TEST_ONE_CHAIN(#id "c", absstart, format, flags3 | ABS_START,\
379
                       VIR_FLATTEN_1(chain3));                       \
380
        TEST_ONE_CHAIN(#id "d", absstart, format, flags4 | ABS_START,\
381
                       VIR_FLATTEN_1(chain4));                       \
382 383 384 385 386
    } while (0)

    /* The actual tests, in several groups. */

    /* Missing file */
387
    TEST_ONE_CHAIN("0", "bogus", VIR_STORAGE_FILE_RAW, EXP_FAIL);
388 389

    /* Raw image, whether with right format or no specified format */
390 391 392
    testFileData raw = {
        .expFormat = VIR_STORAGE_FILE_NONE,
    };
393
    TEST_CHAIN(1, "raw", absraw, VIR_STORAGE_FILE_RAW,
394 395 396 397
               (&raw), EXP_PASS,
               (&raw), ALLOW_PROBE | EXP_PASS,
               (&raw), EXP_PASS,
               (&raw), ALLOW_PROBE | EXP_PASS);
398
    TEST_CHAIN(2, "raw", absraw, VIR_STORAGE_FILE_AUTO,
399 400 401 402
               (&raw), EXP_PASS,
               (&raw), ALLOW_PROBE | EXP_PASS,
               (&raw), EXP_PASS,
               (&raw), ALLOW_PROBE | EXP_PASS);
403 404

    /* Qcow2 file with relative raw backing, format provided */
405
    testFileData qcow2 = {
406 407
        .expBackingStore = canonraw,
        .expBackingStoreRaw = "raw",
408 409
        .expDirectoryRel = ".",
        .expDirectoryAbs = datadir,
410 411 412 413
        .expFormat = VIR_STORAGE_FILE_RAW,
        .expIsFile = true,
        .expCapacity = 1024,
    };
414
    TEST_CHAIN(3, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2,
415 416 417 418
               (&qcow2, &raw), EXP_PASS,
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS,
               (&qcow2, &raw), EXP_PASS,
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS);
419
    TEST_CHAIN(4, "qcow2", absqcow2, VIR_STORAGE_FILE_AUTO,
420
               (&raw), EXP_PASS,
421
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS,
422
               (&raw), EXP_PASS,
423
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS);
424 425 426 427 428 429 430

    /* 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;
431 432
    qcow2.expBackingStoreRaw = absraw;
    qcow2.expDirectoryRel = datadir;
433 434 435

    /* Qcow2 file with raw as absolute backing, backing format provided */
    TEST_CHAIN(5, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2,
436 437 438 439
               (&qcow2, &raw), EXP_PASS,
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS,
               (&qcow2, &raw), EXP_PASS,
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS);
440
    TEST_CHAIN(6, "qcow2", absqcow2, VIR_STORAGE_FILE_AUTO,
441
               (&raw), EXP_PASS,
442
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS,
443
               (&raw), EXP_PASS,
444
               (&qcow2, &raw), ALLOW_PROBE | EXP_PASS);
445 446

    /* Wrapped file access */
447 448 449
    testFileData wrap = {
        .expBackingStore = canonqcow2,
        .expBackingStoreRaw = absqcow2,
450 451
        .expDirectoryRel = datadir,
        .expDirectoryAbs = datadir,
452 453 454 455
        .expFormat = VIR_STORAGE_FILE_QCOW2,
        .expIsFile = true,
        .expCapacity = 1024,
    };
456
    TEST_CHAIN(7, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2,
457 458 459 460
               (&wrap, &qcow2, &raw), EXP_PASS,
               (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS,
               (&wrap, &qcow2, &raw), EXP_PASS,
               (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS);
461 462 463 464 465 466 467 468 469 470 471 472 473

    /* 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;
474
    wrap.expFormat = VIR_STORAGE_FILE_AUTO;
475
    qcow2.expFormat = VIR_STORAGE_FILE_AUTO;
476 477

    /* Qcow2 file with raw as absolute backing, backing format omitted */
478 479 480
    testFileData wrap_as_raw = {
        .expBackingStore = canonqcow2,
        .expBackingStoreRaw = absqcow2,
481 482
        .expDirectoryRel = datadir,
        .expDirectoryAbs = datadir,
483 484 485 486
        .expFormat = VIR_STORAGE_FILE_RAW,
        .expIsFile = true,
        .expCapacity = 1024,
    };
487
    TEST_CHAIN(8, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2,
488
               (&wrap_as_raw, &raw), EXP_PASS,
489
               (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS,
490
               (&wrap_as_raw, &raw), EXP_PASS,
491
               (&wrap, &qcow2, &raw), ALLOW_PROBE | EXP_PASS);
492 493 494 495 496 497 498 499

    /* 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;
500 501 502 503
    qcow2.expBackingStore = NULL;
    qcow2.expBackingStoreRaw = datadir "/bogus";
    qcow2.expFormat = VIR_STORAGE_FILE_NONE;
    qcow2.expIsFile = false;
504 505 506

    /* Qcow2 file with missing backing file but specified type */
    TEST_CHAIN(9, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2,
507 508 509 510
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN,
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN);
511 512 513 514 515 516 517 518 519 520

    /* 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,
521 522 523 524
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN,
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN);
525 526 527 528 529 530 531 532

    /* 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;
533 534 535 536 537
    qcow2.expBackingStore = "nbd:example.org:6000";
    qcow2.expBackingStoreRaw = NULL;
    qcow2.expDirectoryRel = NULL;
    qcow2.expDirectoryAbs = NULL;
    qcow2.expFormat = VIR_STORAGE_FILE_RAW;
538 539 540

    /* Qcow2 file with backing protocol instead of file */
    TEST_CHAIN(11, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2,
541 542 543 544
               (&qcow2), EXP_PASS,
               (&qcow2), ALLOW_PROBE | EXP_PASS,
               (&qcow2), EXP_PASS,
               (&qcow2), ALLOW_PROBE | EXP_PASS);
545 546

    /* qed file */
547 548 549
    testFileData qed = {
        .expBackingStore = canonraw,
        .expBackingStoreRaw = absraw,
550 551
        .expDirectoryRel = datadir,
        .expDirectoryAbs = datadir,
552 553 554 555
        .expFormat = VIR_STORAGE_FILE_RAW,
        .expIsFile = true,
        .expCapacity = 1024,
    };
556
    TEST_CHAIN(12, "qed", absqed, VIR_STORAGE_FILE_AUTO,
557 558 559 560
               (&raw), EXP_PASS,
               (&qed, &raw), ALLOW_PROBE | EXP_PASS,
               (&raw), EXP_PASS,
               (&qed, &raw), ALLOW_PROBE | EXP_PASS);
561

E
Eric Blake 已提交
562
    /* directory */
563 564 565
    testFileData dir = {
        .expIsFile = false,
    };
E
Eric Blake 已提交
566 567 568 569 570 571 572 573 574 575 576
    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);

577
#ifdef HAVE_SYMLINK
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
    /* 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 */
594
    testFileData link1 = {
595 596
        .expBackingStore = canonraw,
        .expBackingStoreRaw = "../raw",
597 598
        .expDirectoryRel = "sub/../sub/..",
        .expDirectoryAbs = datadir "/sub/../sub/..",
599 600 601 602
        .expFormat = VIR_STORAGE_FILE_RAW,
        .expIsFile = true,
        .expCapacity = 1024,
    };
603
    testFileData link2 = {
604 605
        .expBackingStore = canonqcow2,
        .expBackingStoreRaw = "../sub/link1",
606 607
        .expDirectoryRel = "sub/../sub",
        .expDirectoryAbs = datadir "/sub/../sub",
608 609 610 611
        .expFormat = VIR_STORAGE_FILE_QCOW2,
        .expIsFile = true,
        .expCapacity = 1024,
    };
E
Eric Blake 已提交
612
    TEST_CHAIN(15, "sub/link2", abslink2, VIR_STORAGE_FILE_QCOW2,
613 614 615 616
               (&link2, &link1, &raw), EXP_PASS,
               (&link2, &link1, &raw), ALLOW_PROBE | EXP_PASS,
               (&link2, &link1, &raw), EXP_PASS,
               (&link2, &link1, &raw), ALLOW_PROBE | EXP_PASS);
617
#endif
E
Eric Blake 已提交
618 619 620 621 622 623 624

    /* 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;
625 626 627 628 629 630
    qcow2.expBackingStore = NULL;
    qcow2.expBackingStoreRaw = "qcow2";
    qcow2.expDirectoryRel = ".";
    qcow2.expDirectoryAbs = datadir;
    qcow2.expFormat= VIR_STORAGE_FILE_NONE;
    qcow2.expIsFile = true;
E
Eric Blake 已提交
631 632 633

    /* Behavior of an infinite loop chain */
    TEST_CHAIN(16, "qcow2", absqcow2, VIR_STORAGE_FILE_QCOW2,
634 635 636 637
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN,
               (&qcow2), EXP_WARN,
               (&qcow2), ALLOW_PROBE | EXP_WARN);
E
Eric Blake 已提交
638 639 640 641 642 643 644 645 646 647 648 649 650

    /* 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;
651 652
    qcow2.expBackingStoreRaw = "wrap";
    qcow2.expDirectoryRel = datadir;
653
    wrap.expFormat = VIR_STORAGE_FILE_QCOW2;
E
Eric Blake 已提交
654 655 656

    /* Behavior of an infinite loop chain */
    TEST_CHAIN(17, "wrap", abswrap, VIR_STORAGE_FILE_QCOW2,
657 658 659 660
               (&wrap, &qcow2), EXP_WARN,
               (&wrap, &qcow2), ALLOW_PROBE | EXP_WARN,
               (&wrap, &qcow2), EXP_WARN,
               (&wrap, &qcow2), ALLOW_PROBE | EXP_WARN);
E
Eric Blake 已提交
661

662 663 664 665 666 667 668 669
    /* Final cleanup */
    testCleanupImages();
    virCommandFree(cmd);

    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}

VIRT_TEST_MAIN(mymain)