Statistics
| Branch: | Revision:

root / qemu-img.c @ 8c5e95d8

History | View | Annotate | Download (21.6 kB)

1
/*
2
 * QEMU disk image utility
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "qemu-common.h"
25
#include "block_int.h"
26
#include <assert.h>
27

    
28
#ifdef _WIN32
29
#define WIN32_LEAN_AND_MEAN
30
#include <windows.h>
31
#endif
32

    
33
static void __attribute__((noreturn)) error(const char *fmt, ...)
34
{
35
    va_list ap;
36
    va_start(ap, fmt);
37
    fprintf(stderr, "qemu-img: ");
38
    vfprintf(stderr, fmt, ap);
39
    fprintf(stderr, "\n");
40
    exit(1);
41
    va_end(ap);
42
}
43

    
44
static void format_print(void *opaque, const char *name)
45
{
46
    printf(" %s", name);
47
}
48

    
49
static void help(void)
50
{
51
    printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
52
           "usage: qemu-img command [command options]\n"
53
           "QEMU disk image utility\n"
54
           "\n"
55
           "Command syntax:\n"
56
           "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
57
           "  commit [-f fmt] filename\n"
58
           "  convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
59
           "  info [-f fmt] filename\n"
60
           "\n"
61
           "Command parameters:\n"
62
           "  'filename' is a disk image filename\n"
63
           "  'base_image' is the read-only disk image which is used as base for a copy on\n"
64
           "    write image; the copy on write image only stores the modified data\n"
65
           "  'output_base_image' forces the output image to be created as a copy on write\n"
66
           "    image of the specified base image; 'output_base_image' should have the same\n"
67
           "    content as the input's base image, however the path, image format, etc may\n"
68
           "    differ\n"
69
           "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
70
           "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
71
           "    and 'G' (gigabyte) are supported\n"
72
           "  'output_filename' is the destination disk image filename\n"
73
           "  'output_fmt' is the destination format\n"
74
           "  '-c' indicates that target image must be compressed (qcow format only)\n"
75
           "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
76
           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
77
           );
78
    printf("\nSupported format:");
79
    bdrv_iterate_format(format_print, NULL);
80
    printf("\n");
81
    exit(1);
82
}
83

    
84
#if defined(WIN32)
85
/* XXX: put correct support for win32 */
86
static int read_password(char *buf, int buf_size)
87
{
88
    int c, i;
89
    printf("Password: ");
90
    fflush(stdout);
91
    i = 0;
92
    for(;;) {
93
        c = getchar();
94
        if (c == '\n')
95
            break;
96
        if (i < (buf_size - 1))
97
            buf[i++] = c;
98
    }
99
    buf[i] = '\0';
100
    return 0;
101
}
102

    
103
#else
104

    
105
#include <termios.h>
106

    
107
static struct termios oldtty;
108

    
109
static void term_exit(void)
110
{
111
    tcsetattr (0, TCSANOW, &oldtty);
112
}
113

    
114
static void term_init(void)
115
{
116
    struct termios tty;
117

    
118
    tcgetattr (0, &tty);
119
    oldtty = tty;
120

    
121
    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
122
                          |INLCR|IGNCR|ICRNL|IXON);
123
    tty.c_oflag |= OPOST;
124
    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
125
    tty.c_cflag &= ~(CSIZE|PARENB);
126
    tty.c_cflag |= CS8;
127
    tty.c_cc[VMIN] = 1;
128
    tty.c_cc[VTIME] = 0;
129

    
130
    tcsetattr (0, TCSANOW, &tty);
131

    
132
    atexit(term_exit);
133
}
134

    
135
static int read_password(char *buf, int buf_size)
136
{
137
    uint8_t ch;
138
    int i, ret;
139

    
140
    printf("password: ");
141
    fflush(stdout);
142
    term_init();
143
    i = 0;
144
    for(;;) {
145
        ret = read(0, &ch, 1);
146
        if (ret == -1) {
147
            if (errno == EAGAIN || errno == EINTR) {
148
                continue;
149
            } else {
150
                ret = -1;
151
                break;
152
            }
153
        } else if (ret == 0) {
154
            ret = -1;
155
            break;
156
        } else {
157
            if (ch == '\r') {
158
                ret = 0;
159
                break;
160
            }
161
            if (i < (buf_size - 1))
162
                buf[i++] = ch;
163
        }
164
    }
165
    term_exit();
166
    buf[i] = '\0';
167
    printf("\n");
168
    return ret;
169
}
170
#endif
171

    
172
static BlockDriverState *bdrv_new_open(const char *filename,
173
                                       const char *fmt)
174
{
175
    BlockDriverState *bs;
176
    BlockDriver *drv;
177
    char password[256];
178

    
179
    bs = bdrv_new("");
180
    if (!bs)
181
        error("Not enough memory");
182
    if (fmt) {
183
        drv = bdrv_find_format(fmt);
184
        if (!drv)
185
            error("Unknown file format '%s'", fmt);
186
    } else {
187
        drv = NULL;
188
    }
189
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
190
        error("Could not open '%s'", filename);
191
    }
192
    if (bdrv_is_encrypted(bs)) {
193
        printf("Disk image '%s' is encrypted.\n", filename);
194
        if (read_password(password, sizeof(password)) < 0)
195
            error("No password given");
196
        if (bdrv_set_key(bs, password) < 0)
197
            error("invalid password");
198
    }
199
    return bs;
200
}
201

    
202
static int img_create(int argc, char **argv)
203
{
204
    int c, ret, flags;
205
    const char *fmt = "raw";
206
    const char *filename;
207
    const char *base_filename = NULL;
208
    uint64_t size;
209
    const char *p;
210
    BlockDriver *drv;
211

    
212
    flags = 0;
213
    for(;;) {
214
        c = getopt(argc, argv, "b:f:he6");
215
        if (c == -1)
216
            break;
217
        switch(c) {
218
        case 'h':
219
            help();
220
            break;
221
        case 'b':
222
            base_filename = optarg;
223
            break;
224
        case 'f':
225
            fmt = optarg;
226
            break;
227
        case 'e':
228
            flags |= BLOCK_FLAG_ENCRYPT;
229
            break;
230
        case '6':
231
            flags |= BLOCK_FLAG_COMPAT6;
232
            break;
233
        }
234
    }
235
    if (optind >= argc)
236
        help();
237
    filename = argv[optind++];
238
    size = 0;
239
    if (base_filename) {
240
        BlockDriverState *bs;
241
        bs = bdrv_new_open(base_filename, NULL);
242
        bdrv_get_geometry(bs, &size);
243
        size *= 512;
244
        bdrv_delete(bs);
245
    } else {
246
        if (optind >= argc)
247
            help();
248
        p = argv[optind];
249
        size = strtoul(p, (char **)&p, 0);
250
        if (*p == 'M') {
251
            size *= 1024 * 1024;
252
        } else if (*p == 'G') {
253
            size *= 1024 * 1024 * 1024;
254
        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
255
            size *= 1024;
256
        } else {
257
            help();
258
        }
259
    }
260
    drv = bdrv_find_format(fmt);
261
    if (!drv)
262
        error("Unknown file format '%s'", fmt);
263
    printf("Formatting '%s', fmt=%s",
264
           filename, fmt);
265
    if (flags & BLOCK_FLAG_ENCRYPT)
266
        printf(", encrypted");
267
    if (flags & BLOCK_FLAG_COMPAT6)
268
        printf(", compatibility level=6");
269
    if (base_filename) {
270
        printf(", backing_file=%s",
271
               base_filename);
272
    }
273
    printf(", size=%" PRIu64 " kB\n", size / 1024);
274
    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
275
    if (ret < 0) {
276
        if (ret == -ENOTSUP) {
277
            error("Formatting or formatting option not supported for file format '%s'", fmt);
278
        } else {
279
            error("Error while formatting");
280
        }
281
    }
282
    return 0;
283
}
284

    
285
static int img_commit(int argc, char **argv)
286
{
287
    int c, ret;
288
    const char *filename, *fmt;
289
    BlockDriver *drv;
290
    BlockDriverState *bs;
291

    
292
    fmt = NULL;
293
    for(;;) {
294
        c = getopt(argc, argv, "f:h");
295
        if (c == -1)
296
            break;
297
        switch(c) {
298
        case 'h':
299
            help();
300
            break;
301
        case 'f':
302
            fmt = optarg;
303
            break;
304
        }
305
    }
306
    if (optind >= argc)
307
        help();
308
    filename = argv[optind++];
309

    
310
    bs = bdrv_new("");
311
    if (!bs)
312
        error("Not enough memory");
313
    if (fmt) {
314
        drv = bdrv_find_format(fmt);
315
        if (!drv)
316
            error("Unknown file format '%s'", fmt);
317
    } else {
318
        drv = NULL;
319
    }
320
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
321
        error("Could not open '%s'", filename);
322
    }
323
    ret = bdrv_commit(bs);
324
    switch(ret) {
325
    case 0:
326
        printf("Image committed.\n");
327
        break;
328
    case -ENOENT:
329
        error("No disk inserted");
330
        break;
331
    case -EACCES:
332
        error("Image is read-only");
333
        break;
334
    case -ENOTSUP:
335
        error("Image is already committed");
336
        break;
337
    default:
338
        error("Error while committing image");
339
        break;
340
    }
341

    
342
    bdrv_delete(bs);
343
    return 0;
344
}
345

    
346
static int is_not_zero(const uint8_t *sector, int len)
347
{
348
    int i;
349
    len >>= 2;
350
    for(i = 0;i < len; i++) {
351
        if (((uint32_t *)sector)[i] != 0)
352
            return 1;
353
    }
354
    return 0;
355
}
356

    
357
/*
358
 * Returns true iff the first sector pointed to by 'buf' contains at least
359
 * a non-NUL byte.
360
 *
361
 * 'pnum' is set to the number of sectors (including and immediately following
362
 * the first one) that are known to be in the same allocated/unallocated state.
363
 */
364
static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
365
{
366
    int v, i;
367

    
368
    if (n <= 0) {
369
        *pnum = 0;
370
        return 0;
371
    }
372
    v = is_not_zero(buf, 512);
373
    for(i = 1; i < n; i++) {
374
        buf += 512;
375
        if (v != is_not_zero(buf, 512))
376
            break;
377
    }
378
    *pnum = i;
379
    return v;
380
}
381

    
382
#define IO_BUF_SIZE 65536
383

    
384
static int img_convert(int argc, char **argv)
385
{
386
    int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
387
    const char *fmt, *out_fmt, *out_baseimg, *out_filename;
388
    BlockDriver *drv;
389
    BlockDriverState **bs, *out_bs;
390
    int64_t total_sectors, nb_sectors, sector_num, bs_offset;
391
    uint64_t bs_sectors;
392
    uint8_t buf[IO_BUF_SIZE];
393
    const uint8_t *buf1;
394
    BlockDriverInfo bdi;
395

    
396
    fmt = NULL;
397
    out_fmt = "raw";
398
    out_baseimg = NULL;
399
    flags = 0;
400
    for(;;) {
401
        c = getopt(argc, argv, "f:O:B:hce6");
402
        if (c == -1)
403
            break;
404
        switch(c) {
405
        case 'h':
406
            help();
407
            break;
408
        case 'f':
409
            fmt = optarg;
410
            break;
411
        case 'O':
412
            out_fmt = optarg;
413
            break;
414
        case 'B':
415
            out_baseimg = optarg;
416
            break;
417
        case 'c':
418
            flags |= BLOCK_FLAG_COMPRESS;
419
            break;
420
        case 'e':
421
            flags |= BLOCK_FLAG_ENCRYPT;
422
            break;
423
        case '6':
424
            flags |= BLOCK_FLAG_COMPAT6;
425
            break;
426
        }
427
    }
428

    
429
    bs_n = argc - optind - 1;
430
    if (bs_n < 1) help();
431

    
432
    out_filename = argv[argc - 1];
433

    
434
    if (bs_n > 1 && out_baseimg)
435
        error("-B makes no sense when concatenating multiple input images");
436
        
437
    bs = calloc(bs_n, sizeof(BlockDriverState *));
438
    if (!bs)
439
        error("Out of memory");
440

    
441
    total_sectors = 0;
442
    for (bs_i = 0; bs_i < bs_n; bs_i++) {
443
        bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
444
        if (!bs[bs_i])
445
            error("Could not open '%s'", argv[optind + bs_i]);
446
        bdrv_get_geometry(bs[bs_i], &bs_sectors);
447
        total_sectors += bs_sectors;
448
    }
449

    
450
    drv = bdrv_find_format(out_fmt);
451
    if (!drv)
452
        error("Unknown file format '%s'", out_fmt);
453
    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
454
        error("Compression not supported for this file format");
455
    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
456
        error("Encryption not supported for this file format");
457
    if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
458
        error("Alternative compatibility level not supported for this file format");
459
    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
460
        error("Compression and encryption not supported at the same time");
461

    
462
    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
463
    if (ret < 0) {
464
        if (ret == -ENOTSUP) {
465
            error("Formatting not supported for file format '%s'", fmt);
466
        } else {
467
            error("Error while formatting '%s'", out_filename);
468
        }
469
    }
470

    
471
    out_bs = bdrv_new_open(out_filename, out_fmt);
472

    
473
    bs_i = 0;
474
    bs_offset = 0;
475
    bdrv_get_geometry(bs[0], &bs_sectors);
476

    
477
    if (flags & BLOCK_FLAG_COMPRESS) {
478
        if (bdrv_get_info(out_bs, &bdi) < 0)
479
            error("could not get block driver info");
480
        cluster_size = bdi.cluster_size;
481
        if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
482
            error("invalid cluster size");
483
        cluster_sectors = cluster_size >> 9;
484
        sector_num = 0;
485
        for(;;) {
486
            int64_t bs_num;
487
            int remainder;
488
            uint8_t *buf2;
489

    
490
            nb_sectors = total_sectors - sector_num;
491
            if (nb_sectors <= 0)
492
                break;
493
            if (nb_sectors >= cluster_sectors)
494
                n = cluster_sectors;
495
            else
496
                n = nb_sectors;
497

    
498
            bs_num = sector_num - bs_offset;
499
            assert (bs_num >= 0);
500
            remainder = n;
501
            buf2 = buf;
502
            while (remainder > 0) {
503
                int nlow;
504
                while (bs_num == bs_sectors) {
505
                    bs_i++;
506
                    assert (bs_i < bs_n);
507
                    bs_offset += bs_sectors;
508
                    bdrv_get_geometry(bs[bs_i], &bs_sectors);
509
                    bs_num = 0;
510
                    /* printf("changing part: sector_num=%lld, "
511
                       "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
512
                       sector_num, bs_i, bs_offset, bs_sectors); */
513
                }
514
                assert (bs_num < bs_sectors);
515

    
516
                nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
517

    
518
                if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
519
                    error("error while reading");
520

    
521
                buf2 += nlow * 512;
522
                bs_num += nlow;
523

    
524
                remainder -= nlow;
525
            }
526
            assert (remainder == 0);
527

    
528
            if (n < cluster_sectors)
529
                memset(buf + n * 512, 0, cluster_size - n * 512);
530
            if (is_not_zero(buf, cluster_size)) {
531
                if (bdrv_write_compressed(out_bs, sector_num, buf,
532
                                          cluster_sectors) != 0)
533
                    error("error while compressing sector %" PRId64,
534
                          sector_num);
535
            }
536
            sector_num += n;
537
        }
538
        /* signal EOF to align */
539
        bdrv_write_compressed(out_bs, 0, NULL, 0);
540
    } else {
541
        sector_num = 0; // total number of sectors converted so far
542
        for(;;) {
543
            nb_sectors = total_sectors - sector_num;
544
            if (nb_sectors <= 0)
545
                break;
546
            if (nb_sectors >= (IO_BUF_SIZE / 512))
547
                n = (IO_BUF_SIZE / 512);
548
            else
549
                n = nb_sectors;
550

    
551
            while (sector_num - bs_offset >= bs_sectors) {
552
                bs_i ++;
553
                assert (bs_i < bs_n);
554
                bs_offset += bs_sectors;
555
                bdrv_get_geometry(bs[bs_i], &bs_sectors);
556
                /* printf("changing part: sector_num=%lld, bs_i=%d, "
557
                  "bs_offset=%lld, bs_sectors=%lld\n",
558
                   sector_num, bs_i, bs_offset, bs_sectors); */
559
            }
560

    
561
            if (n > bs_offset + bs_sectors - sector_num)
562
                n = bs_offset + bs_sectors - sector_num;
563

    
564
            /* If the output image is being created as a copy on write image,
565
               assume that sectors which are unallocated in the input image
566
               are present in both the output's and input's base images (no
567
               need to copy them). */
568
            if (out_baseimg) {
569
               if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
570
                  sector_num += n1;
571
                  continue;
572
               }
573
               /* The next 'n1' sectors are allocated in the input image. Copy
574
                  only those as they may be followed by unallocated sectors. */
575
               n = n1;
576
            }
577

    
578
            if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
579
                error("error while reading");
580
            /* NOTE: at the same time we convert, we do not write zero
581
               sectors to have a chance to compress the image. Ideally, we
582
               should add a specific call to have the info to go faster */
583
            buf1 = buf;
584
            while (n > 0) {
585
                /* If the output image is being created as a copy on write image,
586
                   copy all sectors even the ones containing only NUL bytes,
587
                   because they may differ from the sectors in the base image. */
588
                if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
589
                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
590
                        error("error while writing");
591
                }
592
                sector_num += n1;
593
                n -= n1;
594
                buf1 += n1 * 512;
595
            }
596
        }
597
    }
598
    bdrv_delete(out_bs);
599
    for (bs_i = 0; bs_i < bs_n; bs_i++)
600
        bdrv_delete(bs[bs_i]);
601
    free(bs);
602
    return 0;
603
}
604

    
605
#ifdef _WIN32
606
static int64_t get_allocated_file_size(const char *filename)
607
{
608
    typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
609
    get_compressed_t get_compressed;
610
    struct _stati64 st;
611

    
612
    /* WinNT support GetCompressedFileSize to determine allocate size */
613
    get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
614
    if (get_compressed) {
615
            DWORD high, low;
616
            low = get_compressed(filename, &high);
617
            if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
618
            return (((int64_t) high) << 32) + low;
619
    }
620

    
621
    if (_stati64(filename, &st) < 0)
622
        return -1;
623
    return st.st_size;
624
}
625
#else
626
static int64_t get_allocated_file_size(const char *filename)
627
{
628
    struct stat st;
629
    if (stat(filename, &st) < 0)
630
        return -1;
631
    return (int64_t)st.st_blocks * 512;
632
}
633
#endif
634

    
635
static void dump_snapshots(BlockDriverState *bs)
636
{
637
    QEMUSnapshotInfo *sn_tab, *sn;
638
    int nb_sns, i;
639
    char buf[256];
640

    
641
    nb_sns = bdrv_snapshot_list(bs, &sn_tab);
642
    if (nb_sns <= 0)
643
        return;
644
    printf("Snapshot list:\n");
645
    printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
646
    for(i = 0; i < nb_sns; i++) {
647
        sn = &sn_tab[i];
648
        printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
649
    }
650
    qemu_free(sn_tab);
651
}
652

    
653
static int img_info(int argc, char **argv)
654
{
655
    int c;
656
    const char *filename, *fmt;
657
    BlockDriver *drv;
658
    BlockDriverState *bs;
659
    char fmt_name[128], size_buf[128], dsize_buf[128];
660
    uint64_t total_sectors;
661
    int64_t allocated_size;
662
    char backing_filename[1024];
663
    char backing_filename2[1024];
664
    BlockDriverInfo bdi;
665

    
666
    fmt = NULL;
667
    for(;;) {
668
        c = getopt(argc, argv, "f:h");
669
        if (c == -1)
670
            break;
671
        switch(c) {
672
        case 'h':
673
            help();
674
            break;
675
        case 'f':
676
            fmt = optarg;
677
            break;
678
        }
679
    }
680
    if (optind >= argc)
681
        help();
682
    filename = argv[optind++];
683

    
684
    bs = bdrv_new("");
685
    if (!bs)
686
        error("Not enough memory");
687
    if (fmt) {
688
        drv = bdrv_find_format(fmt);
689
        if (!drv)
690
            error("Unknown file format '%s'", fmt);
691
    } else {
692
        drv = NULL;
693
    }
694
    if (bdrv_open2(bs, filename, 0, drv) < 0) {
695
        error("Could not open '%s'", filename);
696
    }
697
    bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
698
    bdrv_get_geometry(bs, &total_sectors);
699
    get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
700
    allocated_size = get_allocated_file_size(filename);
701
    if (allocated_size < 0)
702
        sprintf(dsize_buf, "unavailable");
703
    else
704
        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
705
                                allocated_size);
706
    printf("image: %s\n"
707
           "file format: %s\n"
708
           "virtual size: %s (%" PRId64 " bytes)\n"
709
           "disk size: %s\n",
710
           filename, fmt_name, size_buf,
711
           (total_sectors * 512),
712
           dsize_buf);
713
    if (bdrv_is_encrypted(bs))
714
        printf("encrypted: yes\n");
715
    if (bdrv_get_info(bs, &bdi) >= 0) {
716
        if (bdi.cluster_size != 0)
717
            printf("cluster_size: %d\n", bdi.cluster_size);
718
    }
719
    bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
720
    if (backing_filename[0] != '\0') {
721
        path_combine(backing_filename2, sizeof(backing_filename2),
722
                     filename, backing_filename);
723
        printf("backing file: %s (actual path: %s)\n",
724
               backing_filename,
725
               backing_filename2);
726
    }
727
    dump_snapshots(bs);
728
    bdrv_delete(bs);
729
    return 0;
730
}
731

    
732
int main(int argc, char **argv)
733
{
734
    const char *cmd;
735

    
736
    bdrv_init();
737
    if (argc < 2)
738
        help();
739
    cmd = argv[1];
740
    optind++;
741
    if (!strcmp(cmd, "create")) {
742
        img_create(argc, argv);
743
    } else if (!strcmp(cmd, "commit")) {
744
        img_commit(argc, argv);
745
    } else if (!strcmp(cmd, "convert")) {
746
        img_convert(argc, argv);
747
    } else if (!strcmp(cmd, "info")) {
748
        img_info(argc, argv);
749
    } else {
750
        help();
751
    }
752
    return 0;
753
}