Annotation of qemu/qemu-img.c, revision 1.1.1.3

1.1       root        1: /*
1.1.1.3 ! root        2:  * QEMU disk image utility
1.1       root        3:  * 
1.1.1.3 ! root        4:  * Copyright (c) 2003-2007 Fabrice Bellard
1.1       root        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 "vl.h"
                     25: 
1.1.1.2   root       26: #ifdef _WIN32
                     27: #include <windows.h>
                     28: #endif
                     29: 
1.1       root       30: void *get_mmap_addr(unsigned long size)
                     31: {
                     32:     return NULL;
                     33: }
                     34: 
                     35: void qemu_free(void *ptr)
                     36: {
                     37:     free(ptr);
                     38: }
                     39: 
                     40: void *qemu_malloc(size_t size)
                     41: {
                     42:     return malloc(size);
                     43: }
                     44: 
                     45: void *qemu_mallocz(size_t size)
                     46: {
                     47:     void *ptr;
                     48:     ptr = qemu_malloc(size);
                     49:     if (!ptr)
                     50:         return NULL;
                     51:     memset(ptr, 0, size);
                     52:     return ptr;
                     53: }
                     54: 
                     55: char *qemu_strdup(const char *str)
                     56: {
                     57:     char *ptr;
                     58:     ptr = qemu_malloc(strlen(str) + 1);
                     59:     if (!ptr)
                     60:         return NULL;
                     61:     strcpy(ptr, str);
                     62:     return ptr;
                     63: }
                     64: 
                     65: void term_printf(const char *fmt, ...)
                     66: {
                     67:     va_list ap;
                     68:     va_start(ap, fmt);
                     69:     vprintf(fmt, ap);
                     70:     va_end(ap);
                     71: }
                     72: 
1.1.1.3 ! root       73: void term_print_filename(const char *filename)
        !            74: {
        !            75:     term_printf(filename);
        !            76: }
        !            77: 
1.1       root       78: void __attribute__((noreturn)) error(const char *fmt, ...) 
                     79: {
                     80:     va_list ap;
                     81:     va_start(ap, fmt);
                     82:     fprintf(stderr, "qemu-img: ");
                     83:     vfprintf(stderr, fmt, ap);
                     84:     fprintf(stderr, "\n");
                     85:     exit(1);
                     86:     va_end(ap);
                     87: }
                     88: 
                     89: static void format_print(void *opaque, const char *name)
                     90: {
                     91:     printf(" %s", name);
                     92: }
                     93: 
                     94: void help(void)
                     95: {
1.1.1.3 ! root       96:     printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2007 Fabrice Bellard\n"
1.1       root       97:            "usage: qemu-img command [command options]\n"
                     98:            "QEMU disk image utility\n"
                     99:            "\n"
                    100:            "Command syntax:\n"
                    101:            "  create [-e] [-b base_image] [-f fmt] filename [size]\n"
                    102:            "  commit [-f fmt] filename\n"
                    103:            "  convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n"
                    104:            "  info [-f fmt] filename\n"
                    105:            "\n"
                    106:            "Command parameters:\n"
                    107:            "  'filename' is a disk image filename\n"
                    108:            "  'base_image' is the read-only disk image which is used as base for a copy on\n"
                    109:            "    write image; the copy on write image only stores the modified data\n"
                    110:            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
                    111:            "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"
                    112:            "    and 'G' (gigabyte) are supported\n"
                    113:            "  'output_filename' is the destination disk image filename\n"
                    114:            "  'output_fmt' is the destination format\n"
                    115:            "  '-c' indicates that target image must be compressed (qcow format only)\n"
                    116:            "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
                    117:            );
                    118:     printf("\nSupported format:");
                    119:     bdrv_iterate_format(format_print, NULL);
                    120:     printf("\n");
                    121:     exit(1);
                    122: }
                    123: 
                    124: #if defined(WIN32)
                    125: /* XXX: put correct support for win32 */
                    126: static int read_password(char *buf, int buf_size)
                    127: {
                    128:     int c, i;
                    129:     printf("Password: ");
                    130:     fflush(stdout);
                    131:     i = 0;
                    132:     for(;;) {
                    133:         c = getchar();
                    134:         if (c == '\n')
                    135:             break;
                    136:         if (i < (buf_size - 1))
                    137:             buf[i++] = c;
                    138:     }
                    139:     buf[i] = '\0';
                    140:     return 0;
                    141: }
                    142: 
                    143: #else
                    144: 
                    145: #include <termios.h>
                    146: 
                    147: static struct termios oldtty;
                    148: 
                    149: static void term_exit(void)
                    150: {
                    151:     tcsetattr (0, TCSANOW, &oldtty);
                    152: }
                    153: 
                    154: static void term_init(void)
                    155: {
                    156:     struct termios tty;
                    157: 
                    158:     tcgetattr (0, &tty);
                    159:     oldtty = tty;
                    160: 
                    161:     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
                    162:                           |INLCR|IGNCR|ICRNL|IXON);
                    163:     tty.c_oflag |= OPOST;
                    164:     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
                    165:     tty.c_cflag &= ~(CSIZE|PARENB);
                    166:     tty.c_cflag |= CS8;
                    167:     tty.c_cc[VMIN] = 1;
                    168:     tty.c_cc[VTIME] = 0;
                    169:     
                    170:     tcsetattr (0, TCSANOW, &tty);
                    171: 
                    172:     atexit(term_exit);
                    173: }
                    174: 
                    175: int read_password(char *buf, int buf_size)
                    176: {
                    177:     uint8_t ch;
                    178:     int i, ret;
                    179: 
                    180:     printf("password: ");
                    181:     fflush(stdout);
                    182:     term_init();
                    183:     i = 0;
                    184:     for(;;) {
                    185:         ret = read(0, &ch, 1);
                    186:         if (ret == -1) {
                    187:             if (errno == EAGAIN || errno == EINTR) {
                    188:                 continue;
                    189:             } else {
                    190:                 ret = -1;
                    191:                 break;
                    192:             }
                    193:         } else if (ret == 0) {
                    194:             ret = -1;
                    195:             break;
                    196:         } else {
                    197:             if (ch == '\r') {
                    198:                 ret = 0;
                    199:                 break;
                    200:             }
                    201:             if (i < (buf_size - 1))
                    202:                 buf[i++] = ch;
                    203:         }
                    204:     }
                    205:     term_exit();
                    206:     buf[i] = '\0';
                    207:     printf("\n");
                    208:     return ret;
                    209: }
                    210: #endif
                    211: 
                    212: static BlockDriverState *bdrv_new_open(const char *filename,
                    213:                                        const char *fmt)
                    214: {
                    215:     BlockDriverState *bs;
                    216:     BlockDriver *drv;
                    217:     char password[256];
                    218: 
                    219:     bs = bdrv_new("");
                    220:     if (!bs)
                    221:         error("Not enough memory");
                    222:     if (fmt) {
                    223:         drv = bdrv_find_format(fmt);
                    224:         if (!drv)
                    225:             error("Unknown file format '%s'", fmt);
                    226:     } else {
                    227:         drv = NULL;
                    228:     }
                    229:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
                    230:         error("Could not open '%s'", filename);
                    231:     }
                    232:     if (bdrv_is_encrypted(bs)) {
                    233:         printf("Disk image '%s' is encrypted.\n", filename);
                    234:         if (read_password(password, sizeof(password)) < 0)
                    235:             error("No password given");
                    236:         if (bdrv_set_key(bs, password) < 0)
                    237:             error("invalid password");
                    238:     }
                    239:     return bs;
                    240: }
                    241: 
                    242: static int img_create(int argc, char **argv)
                    243: {
                    244:     int c, ret, encrypted;
                    245:     const char *fmt = "raw";
                    246:     const char *filename;
                    247:     const char *base_filename = NULL;
                    248:     int64_t size;
                    249:     const char *p;
                    250:     BlockDriver *drv;
                    251:     
                    252:     encrypted = 0;
                    253:     for(;;) {
                    254:         c = getopt(argc, argv, "b:f:he");
                    255:         if (c == -1)
                    256:             break;
                    257:         switch(c) {
                    258:         case 'h':
                    259:             help();
                    260:             break;
                    261:         case 'b':
                    262:             base_filename = optarg;
                    263:             break;
                    264:         case 'f':
                    265:             fmt = optarg;
                    266:             break;
                    267:         case 'e':
                    268:             encrypted = 1;
                    269:             break;
                    270:         }
                    271:     }
                    272:     if (optind >= argc) 
                    273:         help();
                    274:     filename = argv[optind++];
                    275:     size = 0;
                    276:     if (base_filename) {
                    277:         BlockDriverState *bs;
                    278:         bs = bdrv_new_open(base_filename, NULL);
                    279:         bdrv_get_geometry(bs, &size);
                    280:         size *= 512;
                    281:         bdrv_delete(bs);
                    282:     } else {
                    283:         if (optind >= argc)
                    284:             help();
                    285:         p = argv[optind];
                    286:         size = strtoul(p, (char **)&p, 0);
                    287:         if (*p == 'M') {
                    288:             size *= 1024 * 1024;
                    289:         } else if (*p == 'G') {
                    290:             size *= 1024 * 1024 * 1024;
                    291:         } else if (*p == 'k' || *p == 'K' || *p == '\0') {
                    292:             size *= 1024;
                    293:         } else {
                    294:             help();
                    295:         }
                    296:     }
                    297:     drv = bdrv_find_format(fmt);
                    298:     if (!drv)
                    299:         error("Unknown file format '%s'", fmt);
                    300:     printf("Formating '%s', fmt=%s",
                    301:            filename, fmt);
                    302:     if (encrypted)
                    303:         printf(", encrypted");
                    304:     if (base_filename) {
                    305:         printf(", backing_file=%s",
                    306:                base_filename);
                    307:     }
1.1.1.2   root      308:     printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024));
1.1       root      309:     ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted);
                    310:     if (ret < 0) {
                    311:         if (ret == -ENOTSUP) {
                    312:             error("Formatting or formatting option not supported for file format '%s'", fmt);
                    313:         } else {
                    314:             error("Error while formatting");
                    315:         }
                    316:     }
                    317:     return 0;
                    318: }
                    319: 
                    320: static int img_commit(int argc, char **argv)
                    321: {
                    322:     int c, ret;
                    323:     const char *filename, *fmt;
                    324:     BlockDriver *drv;
                    325:     BlockDriverState *bs;
                    326: 
                    327:     fmt = NULL;
                    328:     for(;;) {
                    329:         c = getopt(argc, argv, "f:h");
                    330:         if (c == -1)
                    331:             break;
                    332:         switch(c) {
                    333:         case 'h':
                    334:             help();
                    335:             break;
                    336:         case 'f':
                    337:             fmt = optarg;
                    338:             break;
                    339:         }
                    340:     }
                    341:     if (optind >= argc) 
                    342:         help();
                    343:     filename = argv[optind++];
                    344: 
                    345:     bs = bdrv_new("");
                    346:     if (!bs)
                    347:         error("Not enough memory");
                    348:     if (fmt) {
                    349:         drv = bdrv_find_format(fmt);
                    350:         if (!drv)
                    351:             error("Unknown file format '%s'", fmt);
                    352:     } else {
                    353:         drv = NULL;
                    354:     }
                    355:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
                    356:         error("Could not open '%s'", filename);
                    357:     }
                    358:     ret = bdrv_commit(bs);
                    359:     switch(ret) {
                    360:     case 0:
                    361:         printf("Image committed.\n");
                    362:         break;
                    363:     case -ENOENT:
                    364:         error("No disk inserted");
                    365:         break;
                    366:     case -EACCES:
                    367:         error("Image is read-only");
                    368:         break;
                    369:     case -ENOTSUP:
                    370:         error("Image is already committed");
                    371:         break;
                    372:     default:
                    373:         error("Error while committing image");
                    374:         break;
                    375:     }
                    376: 
                    377:     bdrv_delete(bs);
                    378:     return 0;
                    379: }
                    380: 
                    381: static int is_not_zero(const uint8_t *sector, int len)
                    382: {
                    383:     int i;
                    384:     len >>= 2;
                    385:     for(i = 0;i < len; i++) {
                    386:         if (((uint32_t *)sector)[i] != 0)
                    387:             return 1;
                    388:     }
                    389:     return 0;
                    390: }
                    391: 
                    392: static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
                    393: {
                    394:     int v, i;
                    395: 
                    396:     if (n <= 0) {
                    397:         *pnum = 0;
                    398:         return 0;
                    399:     }
                    400:     v = is_not_zero(buf, 512);
                    401:     for(i = 1; i < n; i++) {
                    402:         buf += 512;
                    403:         if (v != is_not_zero(buf, 512))
                    404:             break;
                    405:     }
                    406:     *pnum = i;
                    407:     return v;
                    408: }
                    409: 
                    410: #define IO_BUF_SIZE 65536
                    411: 
                    412: static int img_convert(int argc, char **argv)
                    413: {
                    414:     int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt;
                    415:     const char *filename, *fmt, *out_fmt, *out_filename;
                    416:     BlockDriver *drv;
                    417:     BlockDriverState *bs, *out_bs;
                    418:     int64_t total_sectors, nb_sectors, sector_num;
                    419:     uint8_t buf[IO_BUF_SIZE];
                    420:     const uint8_t *buf1;
1.1.1.3 ! root      421:     BlockDriverInfo bdi;
1.1       root      422: 
                    423:     fmt = NULL;
                    424:     out_fmt = "raw";
                    425:     compress = 0;
                    426:     encrypt = 0;
                    427:     for(;;) {
                    428:         c = getopt(argc, argv, "f:O:hce");
                    429:         if (c == -1)
                    430:             break;
                    431:         switch(c) {
                    432:         case 'h':
                    433:             help();
                    434:             break;
                    435:         case 'f':
                    436:             fmt = optarg;
                    437:             break;
                    438:         case 'O':
                    439:             out_fmt = optarg;
                    440:             break;
                    441:         case 'c':
                    442:             compress = 1;
                    443:             break;
                    444:         case 'e':
                    445:             encrypt = 1;
                    446:             break;
                    447:         }
                    448:     }
                    449:     if (optind >= argc) 
                    450:         help();
                    451:     filename = argv[optind++];
                    452:     if (optind >= argc) 
                    453:         help();
                    454:     out_filename = argv[optind++];
                    455:     
                    456:     bs = bdrv_new_open(filename, fmt);
                    457: 
                    458:     drv = bdrv_find_format(out_fmt);
                    459:     if (!drv)
                    460:         error("Unknown file format '%s'", fmt);
1.1.1.3 ! root      461:     if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2)
1.1       root      462:         error("Compression not supported for this file format");
1.1.1.3 ! root      463:     if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2)
1.1       root      464:         error("Encryption not supported for this file format");
                    465:     if (compress && encrypt)
                    466:         error("Compression and encryption not supported at the same time");
                    467:     bdrv_get_geometry(bs, &total_sectors);
                    468:     ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt);
                    469:     if (ret < 0) {
                    470:         if (ret == -ENOTSUP) {
                    471:             error("Formatting not supported for file format '%s'", fmt);
                    472:         } else {
                    473:             error("Error while formatting '%s'", out_filename);
                    474:         }
                    475:     }
                    476:     
                    477:     out_bs = bdrv_new_open(out_filename, out_fmt);
                    478: 
                    479:     if (compress) {
1.1.1.3 ! root      480:         if (bdrv_get_info(out_bs, &bdi) < 0)
        !           481:             error("could not get block driver info");
        !           482:         cluster_size = bdi.cluster_size;
1.1       root      483:         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
                    484:             error("invalid cluster size");
                    485:         cluster_sectors = cluster_size >> 9;
                    486:         sector_num = 0;
                    487:         for(;;) {
                    488:             nb_sectors = total_sectors - sector_num;
                    489:             if (nb_sectors <= 0)
                    490:                 break;
                    491:             if (nb_sectors >= cluster_sectors)
                    492:                 n = cluster_sectors;
                    493:             else
                    494:                 n = nb_sectors;
                    495:             if (bdrv_read(bs, sector_num, buf, n) < 0) 
                    496:                 error("error while reading");
                    497:             if (n < cluster_sectors)
                    498:                 memset(buf + n * 512, 0, cluster_size - n * 512);
                    499:             if (is_not_zero(buf, cluster_size)) {
1.1.1.3 ! root      500:                 if (bdrv_write_compressed(out_bs, sector_num, buf, 
        !           501:                                           cluster_sectors) != 0)
1.1.1.2   root      502:                     error("error while compressing sector %" PRId64,
                    503:                           sector_num);
1.1       root      504:             }
                    505:             sector_num += n;
                    506:         }
1.1.1.3 ! root      507:         /* signal EOF to align */
        !           508:         bdrv_write_compressed(out_bs, 0, NULL, 0);
1.1       root      509:     } else {
                    510:         sector_num = 0;
                    511:         for(;;) {
                    512:             nb_sectors = total_sectors - sector_num;
                    513:             if (nb_sectors <= 0)
                    514:                 break;
                    515:             if (nb_sectors >= (IO_BUF_SIZE / 512))
                    516:                 n = (IO_BUF_SIZE / 512);
                    517:             else
                    518:                 n = nb_sectors;
                    519:             if (bdrv_read(bs, sector_num, buf, n) < 0) 
                    520:                 error("error while reading");
                    521:             /* NOTE: at the same time we convert, we do not write zero
                    522:                sectors to have a chance to compress the image. Ideally, we
                    523:                should add a specific call to have the info to go faster */
                    524:             buf1 = buf;
                    525:             while (n > 0) {
                    526:                 if (is_allocated_sectors(buf1, n, &n1)) {
                    527:                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) 
                    528:                         error("error while writing");
                    529:                 }
                    530:                 sector_num += n1;
                    531:                 n -= n1;
                    532:                 buf1 += n1 * 512;
                    533:             }
                    534:         }
                    535:     }
                    536:     bdrv_delete(out_bs);
                    537:     bdrv_delete(bs);
                    538:     return 0;
                    539: }
                    540: 
                    541: #ifdef _WIN32
                    542: static int64_t get_allocated_file_size(const char *filename)
                    543: {
1.1.1.2   root      544:     typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
                    545:     get_compressed_t get_compressed;
1.1       root      546:     struct _stati64 st;
1.1.1.2   root      547: 
                    548:     /* WinNT support GetCompressedFileSize to determine allocate size */
                    549:     get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
                    550:     if (get_compressed) {
                    551:        DWORD high, low;
                    552:        low = get_compressed(filename, &high);
                    553:        if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
                    554:            return (((int64_t) high) << 32) + low;
                    555:     }
                    556: 
1.1       root      557:     if (_stati64(filename, &st) < 0) 
                    558:         return -1;
                    559:     return st.st_size;
                    560: }
                    561: #else
                    562: static int64_t get_allocated_file_size(const char *filename)
                    563: {
                    564:     struct stat st;
                    565:     if (stat(filename, &st) < 0) 
                    566:         return -1;
                    567:     return (int64_t)st.st_blocks * 512;
                    568: }
                    569: #endif
                    570: 
1.1.1.3 ! root      571: static void dump_snapshots(BlockDriverState *bs)
        !           572: {
        !           573:     QEMUSnapshotInfo *sn_tab, *sn;
        !           574:     int nb_sns, i;
        !           575:     char buf[256];
        !           576: 
        !           577:     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
        !           578:     if (nb_sns <= 0)
        !           579:         return;
        !           580:     printf("Snapshot list:\n");
        !           581:     printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
        !           582:     for(i = 0; i < nb_sns; i++) {
        !           583:         sn = &sn_tab[i];
        !           584:         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
        !           585:     }
        !           586:     qemu_free(sn_tab);
        !           587: }
        !           588: 
1.1       root      589: static int img_info(int argc, char **argv)
                    590: {
                    591:     int c;
                    592:     const char *filename, *fmt;
                    593:     BlockDriver *drv;
                    594:     BlockDriverState *bs;
                    595:     char fmt_name[128], size_buf[128], dsize_buf[128];
                    596:     int64_t total_sectors, allocated_size;
1.1.1.3 ! root      597:     char backing_filename[1024];
        !           598:     char backing_filename2[1024];
        !           599:     BlockDriverInfo bdi;
1.1       root      600: 
                    601:     fmt = NULL;
                    602:     for(;;) {
                    603:         c = getopt(argc, argv, "f:h");
                    604:         if (c == -1)
                    605:             break;
                    606:         switch(c) {
                    607:         case 'h':
                    608:             help();
                    609:             break;
                    610:         case 'f':
                    611:             fmt = optarg;
                    612:             break;
                    613:         }
                    614:     }
                    615:     if (optind >= argc) 
                    616:         help();
                    617:     filename = argv[optind++];
                    618: 
                    619:     bs = bdrv_new("");
                    620:     if (!bs)
                    621:         error("Not enough memory");
                    622:     if (fmt) {
                    623:         drv = bdrv_find_format(fmt);
                    624:         if (!drv)
                    625:             error("Unknown file format '%s'", fmt);
                    626:     } else {
                    627:         drv = NULL;
                    628:     }
                    629:     if (bdrv_open2(bs, filename, 0, drv) < 0) {
                    630:         error("Could not open '%s'", filename);
                    631:     }
                    632:     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
                    633:     bdrv_get_geometry(bs, &total_sectors);
                    634:     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
                    635:     allocated_size = get_allocated_file_size(filename);
                    636:     if (allocated_size < 0)
                    637:        sprintf(dsize_buf, "unavailable");
                    638:     else
                    639:         get_human_readable_size(dsize_buf, sizeof(dsize_buf), 
                    640:                                 allocated_size);
                    641:     printf("image: %s\n"
                    642:            "file format: %s\n"
1.1.1.2   root      643:            "virtual size: %s (%" PRId64 " bytes)\n"
1.1       root      644:            "disk size: %s\n",
                    645:            filename, fmt_name, size_buf, 
1.1.1.2   root      646:            (total_sectors * 512),
1.1       root      647:            dsize_buf);
                    648:     if (bdrv_is_encrypted(bs))
                    649:         printf("encrypted: yes\n");
1.1.1.3 ! root      650:     if (bdrv_get_info(bs, &bdi) >= 0) {
        !           651:         if (bdi.cluster_size != 0) 
        !           652:             printf("cluster_size: %d\n", bdi.cluster_size);
        !           653:     }
        !           654:     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
        !           655:     if (backing_filename[0] != '\0') {
        !           656:         path_combine(backing_filename2, sizeof(backing_filename2),
        !           657:                      filename, backing_filename);
        !           658:         printf("backing file: %s (actual path: %s)\n", 
        !           659:                backing_filename,
        !           660:                backing_filename2);
        !           661:     }
        !           662:     dump_snapshots(bs);
1.1       root      663:     bdrv_delete(bs);
                    664:     return 0;
                    665: }
                    666: 
                    667: int main(int argc, char **argv)
                    668: {
                    669:     const char *cmd;
                    670: 
                    671:     bdrv_init();
                    672:     if (argc < 2)
                    673:         help();
                    674:     cmd = argv[1];
                    675:     optind++;
                    676:     if (!strcmp(cmd, "create")) {
                    677:         img_create(argc, argv);
                    678:     } else if (!strcmp(cmd, "commit")) {
                    679:         img_commit(argc, argv);
                    680:     } else if (!strcmp(cmd, "convert")) {
                    681:         img_convert(argc, argv);
                    682:     } else if (!strcmp(cmd, "info")) {
                    683:         img_info(argc, argv);
                    684:     } else {
                    685:         help();
                    686:     }
                    687:     return 0;
                    688: }

unix.superglobalmegacorp.com