File:  [Qemu by Fabrice Bellard] / qemu / qemu-img.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:44 2018 UTC (22 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0100, HEAD
qemu 0.10.0

    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 "osdep.h"
   26: #include "block_int.h"
   27: #include <assert.h>
   28: 
   29: #ifdef _WIN32
   30: #define WIN32_LEAN_AND_MEAN
   31: #include <windows.h>
   32: #endif
   33: 
   34: /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
   35: #define BRDV_O_FLAGS BDRV_O_CACHE_WB
   36: 
   37: static void QEMU_NORETURN error(const char *fmt, ...)
   38: {
   39:     va_list ap;
   40:     va_start(ap, fmt);
   41:     fprintf(stderr, "qemu-img: ");
   42:     vfprintf(stderr, fmt, ap);
   43:     fprintf(stderr, "\n");
   44:     exit(1);
   45:     va_end(ap);
   46: }
   47: 
   48: static void format_print(void *opaque, const char *name)
   49: {
   50:     printf(" %s", name);
   51: }
   52: 
   53: /* Please keep in synch with qemu-img.texi */
   54: static void help(void)
   55: {
   56:     printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
   57:            "usage: qemu-img command [command options]\n"
   58:            "QEMU disk image utility\n"
   59:            "\n"
   60:            "Command syntax:\n"
   61:            "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
   62:            "  commit [-f fmt] filename\n"
   63:            "  convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
   64:            "  info [-f fmt] filename\n"
   65:            "  snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n"
   66:            "\n"
   67:            "Command parameters:\n"
   68:            "  'filename' is a disk image filename\n"
   69:            "  'base_image' is the read-only disk image which is used as base for a copy on\n"
   70:            "    write image; the copy on write image only stores the modified data\n"
   71:            "  'output_base_image' forces the output image to be created as a copy on write\n"
   72:            "    image of the specified base image; 'output_base_image' should have the same\n"
   73:            "    content as the input's base image, however the path, image format, etc may\n"
   74:            "    differ\n"
   75:            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
   76:            "  'size' is the disk image size in kilobytes. Optional suffixes\n"
   77:            "    'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are"
   78:            "    supported any @code{k} or @code{K} is ignored\n"
   79:            "  'output_filename' is the destination disk image filename\n"
   80:            "  'output_fmt' is the destination format\n"
   81:            "  '-c' indicates that target image must be compressed (qcow format only)\n"
   82:            "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
   83:            "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
   84:            "  '-h' with or without a command shows this help and lists the supported formats\n"
   85:            "\n"
   86:            "Parameters to snapshot subcommand:\n"
   87:            "  'snapshot' is the name of the snapshot to create, apply or delete\n"
   88:            "  '-a' applies a snapshot (revert disk to saved state)\n"
   89:            "  '-c' creates a snapshot\n"
   90:            "  '-d' deletes a snapshot\n"
   91:            "  '-l' lists all snapshots in the given image\n"
   92:            );
   93:     printf("\nSupported formats:");
   94:     bdrv_iterate_format(format_print, NULL);
   95:     printf("\n");
   96:     exit(1);
   97: }
   98: 
   99: #if defined(WIN32)
  100: /* XXX: put correct support for win32 */
  101: static int read_password(char *buf, int buf_size)
  102: {
  103:     int c, i;
  104:     printf("Password: ");
  105:     fflush(stdout);
  106:     i = 0;
  107:     for(;;) {
  108:         c = getchar();
  109:         if (c == '\n')
  110:             break;
  111:         if (i < (buf_size - 1))
  112:             buf[i++] = c;
  113:     }
  114:     buf[i] = '\0';
  115:     return 0;
  116: }
  117: 
  118: #else
  119: 
  120: #include <termios.h>
  121: 
  122: static struct termios oldtty;
  123: 
  124: static void term_exit(void)
  125: {
  126:     tcsetattr (0, TCSANOW, &oldtty);
  127: }
  128: 
  129: static void term_init(void)
  130: {
  131:     struct termios tty;
  132: 
  133:     tcgetattr (0, &tty);
  134:     oldtty = tty;
  135: 
  136:     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
  137:                           |INLCR|IGNCR|ICRNL|IXON);
  138:     tty.c_oflag |= OPOST;
  139:     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
  140:     tty.c_cflag &= ~(CSIZE|PARENB);
  141:     tty.c_cflag |= CS8;
  142:     tty.c_cc[VMIN] = 1;
  143:     tty.c_cc[VTIME] = 0;
  144: 
  145:     tcsetattr (0, TCSANOW, &tty);
  146: 
  147:     atexit(term_exit);
  148: }
  149: 
  150: static int read_password(char *buf, int buf_size)
  151: {
  152:     uint8_t ch;
  153:     int i, ret;
  154: 
  155:     printf("password: ");
  156:     fflush(stdout);
  157:     term_init();
  158:     i = 0;
  159:     for(;;) {
  160:         ret = read(0, &ch, 1);
  161:         if (ret == -1) {
  162:             if (errno == EAGAIN || errno == EINTR) {
  163:                 continue;
  164:             } else {
  165:                 ret = -1;
  166:                 break;
  167:             }
  168:         } else if (ret == 0) {
  169:             ret = -1;
  170:             break;
  171:         } else {
  172:             if (ch == '\r') {
  173:                 ret = 0;
  174:                 break;
  175:             }
  176:             if (i < (buf_size - 1))
  177:                 buf[i++] = ch;
  178:         }
  179:     }
  180:     term_exit();
  181:     buf[i] = '\0';
  182:     printf("\n");
  183:     return ret;
  184: }
  185: #endif
  186: 
  187: static BlockDriverState *bdrv_new_open(const char *filename,
  188:                                        const char *fmt)
  189: {
  190:     BlockDriverState *bs;
  191:     BlockDriver *drv;
  192:     char password[256];
  193: 
  194:     bs = bdrv_new("");
  195:     if (!bs)
  196:         error("Not enough memory");
  197:     if (fmt) {
  198:         drv = bdrv_find_format(fmt);
  199:         if (!drv)
  200:             error("Unknown file format '%s'", fmt);
  201:     } else {
  202:         drv = NULL;
  203:     }
  204:     if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
  205:         error("Could not open '%s'", filename);
  206:     }
  207:     if (bdrv_is_encrypted(bs)) {
  208:         printf("Disk image '%s' is encrypted.\n", filename);
  209:         if (read_password(password, sizeof(password)) < 0)
  210:             error("No password given");
  211:         if (bdrv_set_key(bs, password) < 0)
  212:             error("invalid password");
  213:     }
  214:     return bs;
  215: }
  216: 
  217: static int img_create(int argc, char **argv)
  218: {
  219:     int c, ret, flags;
  220:     const char *fmt = "raw";
  221:     const char *filename;
  222:     const char *base_filename = NULL;
  223:     uint64_t size;
  224:     const char *p;
  225:     BlockDriver *drv;
  226: 
  227:     flags = 0;
  228:     for(;;) {
  229:         c = getopt(argc, argv, "b:f:he6");
  230:         if (c == -1)
  231:             break;
  232:         switch(c) {
  233:         case 'h':
  234:             help();
  235:             break;
  236:         case 'b':
  237:             base_filename = optarg;
  238:             break;
  239:         case 'f':
  240:             fmt = optarg;
  241:             break;
  242:         case 'e':
  243:             flags |= BLOCK_FLAG_ENCRYPT;
  244:             break;
  245:         case '6':
  246:             flags |= BLOCK_FLAG_COMPAT6;
  247:             break;
  248:         }
  249:     }
  250:     if (optind >= argc)
  251:         help();
  252:     filename = argv[optind++];
  253:     size = 0;
  254:     if (base_filename) {
  255:         BlockDriverState *bs;
  256:         bs = bdrv_new_open(base_filename, NULL);
  257:         bdrv_get_geometry(bs, &size);
  258:         size *= 512;
  259:         bdrv_delete(bs);
  260:     } else {
  261:         if (optind >= argc)
  262:             help();
  263:         p = argv[optind];
  264:         size = strtoul(p, (char **)&p, 0);
  265:         if (*p == 'M') {
  266:             size *= 1024 * 1024;
  267:         } else if (*p == 'G') {
  268:             size *= 1024 * 1024 * 1024;
  269:         } else if (*p == 'k' || *p == 'K' || *p == '\0') {
  270:             size *= 1024;
  271:         } else {
  272:             help();
  273:         }
  274:     }
  275:     drv = bdrv_find_format(fmt);
  276:     if (!drv)
  277:         error("Unknown file format '%s'", fmt);
  278:     printf("Formatting '%s', fmt=%s",
  279:            filename, fmt);
  280:     if (flags & BLOCK_FLAG_ENCRYPT)
  281:         printf(", encrypted");
  282:     if (flags & BLOCK_FLAG_COMPAT6)
  283:         printf(", compatibility level=6");
  284:     if (base_filename) {
  285:         printf(", backing_file=%s",
  286:                base_filename);
  287:     }
  288:     printf(", size=%" PRIu64 " kB\n", size / 1024);
  289:     ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
  290:     if (ret < 0) {
  291:         if (ret == -ENOTSUP) {
  292:             error("Formatting or formatting option not supported for file format '%s'", fmt);
  293:         } else {
  294:             error("Error while formatting");
  295:         }
  296:     }
  297:     return 0;
  298: }
  299: 
  300: static int img_commit(int argc, char **argv)
  301: {
  302:     int c, ret;
  303:     const char *filename, *fmt;
  304:     BlockDriver *drv;
  305:     BlockDriverState *bs;
  306: 
  307:     fmt = NULL;
  308:     for(;;) {
  309:         c = getopt(argc, argv, "f:h");
  310:         if (c == -1)
  311:             break;
  312:         switch(c) {
  313:         case 'h':
  314:             help();
  315:             break;
  316:         case 'f':
  317:             fmt = optarg;
  318:             break;
  319:         }
  320:     }
  321:     if (optind >= argc)
  322:         help();
  323:     filename = argv[optind++];
  324: 
  325:     bs = bdrv_new("");
  326:     if (!bs)
  327:         error("Not enough memory");
  328:     if (fmt) {
  329:         drv = bdrv_find_format(fmt);
  330:         if (!drv)
  331:             error("Unknown file format '%s'", fmt);
  332:     } else {
  333:         drv = NULL;
  334:     }
  335:     if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
  336:         error("Could not open '%s'", filename);
  337:     }
  338:     ret = bdrv_commit(bs);
  339:     switch(ret) {
  340:     case 0:
  341:         printf("Image committed.\n");
  342:         break;
  343:     case -ENOENT:
  344:         error("No disk inserted");
  345:         break;
  346:     case -EACCES:
  347:         error("Image is read-only");
  348:         break;
  349:     case -ENOTSUP:
  350:         error("Image is already committed");
  351:         break;
  352:     default:
  353:         error("Error while committing image");
  354:         break;
  355:     }
  356: 
  357:     bdrv_delete(bs);
  358:     return 0;
  359: }
  360: 
  361: static int is_not_zero(const uint8_t *sector, int len)
  362: {
  363:     int i;
  364:     len >>= 2;
  365:     for(i = 0;i < len; i++) {
  366:         if (((uint32_t *)sector)[i] != 0)
  367:             return 1;
  368:     }
  369:     return 0;
  370: }
  371: 
  372: /*
  373:  * Returns true iff the first sector pointed to by 'buf' contains at least
  374:  * a non-NUL byte.
  375:  *
  376:  * 'pnum' is set to the number of sectors (including and immediately following
  377:  * the first one) that are known to be in the same allocated/unallocated state.
  378:  */
  379: static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
  380: {
  381:     int v, i;
  382: 
  383:     if (n <= 0) {
  384:         *pnum = 0;
  385:         return 0;
  386:     }
  387:     v = is_not_zero(buf, 512);
  388:     for(i = 1; i < n; i++) {
  389:         buf += 512;
  390:         if (v != is_not_zero(buf, 512))
  391:             break;
  392:     }
  393:     *pnum = i;
  394:     return v;
  395: }
  396: 
  397: #define IO_BUF_SIZE 65536
  398: 
  399: static int img_convert(int argc, char **argv)
  400: {
  401:     int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
  402:     const char *fmt, *out_fmt, *out_baseimg, *out_filename;
  403:     BlockDriver *drv;
  404:     BlockDriverState **bs, *out_bs;
  405:     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
  406:     uint64_t bs_sectors;
  407:     uint8_t buf[IO_BUF_SIZE];
  408:     const uint8_t *buf1;
  409:     BlockDriverInfo bdi;
  410: 
  411:     fmt = NULL;
  412:     out_fmt = "raw";
  413:     out_baseimg = NULL;
  414:     flags = 0;
  415:     for(;;) {
  416:         c = getopt(argc, argv, "f:O:B:hce6");
  417:         if (c == -1)
  418:             break;
  419:         switch(c) {
  420:         case 'h':
  421:             help();
  422:             break;
  423:         case 'f':
  424:             fmt = optarg;
  425:             break;
  426:         case 'O':
  427:             out_fmt = optarg;
  428:             break;
  429:         case 'B':
  430:             out_baseimg = optarg;
  431:             break;
  432:         case 'c':
  433:             flags |= BLOCK_FLAG_COMPRESS;
  434:             break;
  435:         case 'e':
  436:             flags |= BLOCK_FLAG_ENCRYPT;
  437:             break;
  438:         case '6':
  439:             flags |= BLOCK_FLAG_COMPAT6;
  440:             break;
  441:         }
  442:     }
  443: 
  444:     bs_n = argc - optind - 1;
  445:     if (bs_n < 1) help();
  446: 
  447:     out_filename = argv[argc - 1];
  448: 
  449:     if (bs_n > 1 && out_baseimg)
  450:         error("-B makes no sense when concatenating multiple input images");
  451:         
  452:     bs = calloc(bs_n, sizeof(BlockDriverState *));
  453:     if (!bs)
  454:         error("Out of memory");
  455: 
  456:     total_sectors = 0;
  457:     for (bs_i = 0; bs_i < bs_n; bs_i++) {
  458:         bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
  459:         if (!bs[bs_i])
  460:             error("Could not open '%s'", argv[optind + bs_i]);
  461:         bdrv_get_geometry(bs[bs_i], &bs_sectors);
  462:         total_sectors += bs_sectors;
  463:     }
  464: 
  465:     drv = bdrv_find_format(out_fmt);
  466:     if (!drv)
  467:         error("Unknown file format '%s'", out_fmt);
  468:     if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
  469:         error("Compression not supported for this file format");
  470:     if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
  471:         error("Encryption not supported for this file format");
  472:     if (flags & BLOCK_FLAG_COMPAT6 && drv != &bdrv_vmdk)
  473:         error("Alternative compatibility level not supported for this file format");
  474:     if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
  475:         error("Compression and encryption not supported at the same time");
  476: 
  477:     ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
  478:     if (ret < 0) {
  479:         if (ret == -ENOTSUP) {
  480:             error("Formatting not supported for file format '%s'", fmt);
  481:         } else {
  482:             error("Error while formatting '%s'", out_filename);
  483:         }
  484:     }
  485: 
  486:     out_bs = bdrv_new_open(out_filename, out_fmt);
  487: 
  488:     bs_i = 0;
  489:     bs_offset = 0;
  490:     bdrv_get_geometry(bs[0], &bs_sectors);
  491: 
  492:     if (flags & BLOCK_FLAG_COMPRESS) {
  493:         if (bdrv_get_info(out_bs, &bdi) < 0)
  494:             error("could not get block driver info");
  495:         cluster_size = bdi.cluster_size;
  496:         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
  497:             error("invalid cluster size");
  498:         cluster_sectors = cluster_size >> 9;
  499:         sector_num = 0;
  500:         for(;;) {
  501:             int64_t bs_num;
  502:             int remainder;
  503:             uint8_t *buf2;
  504: 
  505:             nb_sectors = total_sectors - sector_num;
  506:             if (nb_sectors <= 0)
  507:                 break;
  508:             if (nb_sectors >= cluster_sectors)
  509:                 n = cluster_sectors;
  510:             else
  511:                 n = nb_sectors;
  512: 
  513:             bs_num = sector_num - bs_offset;
  514:             assert (bs_num >= 0);
  515:             remainder = n;
  516:             buf2 = buf;
  517:             while (remainder > 0) {
  518:                 int nlow;
  519:                 while (bs_num == bs_sectors) {
  520:                     bs_i++;
  521:                     assert (bs_i < bs_n);
  522:                     bs_offset += bs_sectors;
  523:                     bdrv_get_geometry(bs[bs_i], &bs_sectors);
  524:                     bs_num = 0;
  525:                     /* printf("changing part: sector_num=%lld, "
  526:                        "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
  527:                        sector_num, bs_i, bs_offset, bs_sectors); */
  528:                 }
  529:                 assert (bs_num < bs_sectors);
  530: 
  531:                 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
  532: 
  533:                 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
  534:                     error("error while reading");
  535: 
  536:                 buf2 += nlow * 512;
  537:                 bs_num += nlow;
  538: 
  539:                 remainder -= nlow;
  540:             }
  541:             assert (remainder == 0);
  542: 
  543:             if (n < cluster_sectors)
  544:                 memset(buf + n * 512, 0, cluster_size - n * 512);
  545:             if (is_not_zero(buf, cluster_size)) {
  546:                 if (bdrv_write_compressed(out_bs, sector_num, buf,
  547:                                           cluster_sectors) != 0)
  548:                     error("error while compressing sector %" PRId64,
  549:                           sector_num);
  550:             }
  551:             sector_num += n;
  552:         }
  553:         /* signal EOF to align */
  554:         bdrv_write_compressed(out_bs, 0, NULL, 0);
  555:     } else {
  556:         sector_num = 0; // total number of sectors converted so far
  557:         for(;;) {
  558:             nb_sectors = total_sectors - sector_num;
  559:             if (nb_sectors <= 0)
  560:                 break;
  561:             if (nb_sectors >= (IO_BUF_SIZE / 512))
  562:                 n = (IO_BUF_SIZE / 512);
  563:             else
  564:                 n = nb_sectors;
  565: 
  566:             while (sector_num - bs_offset >= bs_sectors) {
  567:                 bs_i ++;
  568:                 assert (bs_i < bs_n);
  569:                 bs_offset += bs_sectors;
  570:                 bdrv_get_geometry(bs[bs_i], &bs_sectors);
  571:                 /* printf("changing part: sector_num=%lld, bs_i=%d, "
  572:                   "bs_offset=%lld, bs_sectors=%lld\n",
  573:                    sector_num, bs_i, bs_offset, bs_sectors); */
  574:             }
  575: 
  576:             if (n > bs_offset + bs_sectors - sector_num)
  577:                 n = bs_offset + bs_sectors - sector_num;
  578: 
  579:             /* If the output image is being created as a copy on write image,
  580:                assume that sectors which are unallocated in the input image
  581:                are present in both the output's and input's base images (no
  582:                need to copy them). */
  583:             if (out_baseimg) {
  584:                if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset, n, &n1)) {
  585:                   sector_num += n1;
  586:                   continue;
  587:                }
  588:                /* The next 'n1' sectors are allocated in the input image. Copy
  589:                   only those as they may be followed by unallocated sectors. */
  590:                n = n1;
  591:             }
  592: 
  593:             if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
  594:                 error("error while reading");
  595:             /* NOTE: at the same time we convert, we do not write zero
  596:                sectors to have a chance to compress the image. Ideally, we
  597:                should add a specific call to have the info to go faster */
  598:             buf1 = buf;
  599:             while (n > 0) {
  600:                 /* If the output image is being created as a copy on write image,
  601:                    copy all sectors even the ones containing only NUL bytes,
  602:                    because they may differ from the sectors in the base image. */
  603:                 if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
  604:                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
  605:                         error("error while writing");
  606:                 }
  607:                 sector_num += n1;
  608:                 n -= n1;
  609:                 buf1 += n1 * 512;
  610:             }
  611:         }
  612:     }
  613:     bdrv_delete(out_bs);
  614:     for (bs_i = 0; bs_i < bs_n; bs_i++)
  615:         bdrv_delete(bs[bs_i]);
  616:     free(bs);
  617:     return 0;
  618: }
  619: 
  620: #ifdef _WIN32
  621: static int64_t get_allocated_file_size(const char *filename)
  622: {
  623:     typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
  624:     get_compressed_t get_compressed;
  625:     struct _stati64 st;
  626: 
  627:     /* WinNT support GetCompressedFileSize to determine allocate size */
  628:     get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
  629:     if (get_compressed) {
  630:     	DWORD high, low;
  631:     	low = get_compressed(filename, &high);
  632:     	if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
  633: 	    return (((int64_t) high) << 32) + low;
  634:     }
  635: 
  636:     if (_stati64(filename, &st) < 0)
  637:         return -1;
  638:     return st.st_size;
  639: }
  640: #else
  641: static int64_t get_allocated_file_size(const char *filename)
  642: {
  643:     struct stat st;
  644:     if (stat(filename, &st) < 0)
  645:         return -1;
  646:     return (int64_t)st.st_blocks * 512;
  647: }
  648: #endif
  649: 
  650: static void dump_snapshots(BlockDriverState *bs)
  651: {
  652:     QEMUSnapshotInfo *sn_tab, *sn;
  653:     int nb_sns, i;
  654:     char buf[256];
  655: 
  656:     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
  657:     if (nb_sns <= 0)
  658:         return;
  659:     printf("Snapshot list:\n");
  660:     printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
  661:     for(i = 0; i < nb_sns; i++) {
  662:         sn = &sn_tab[i];
  663:         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
  664:     }
  665:     qemu_free(sn_tab);
  666: }
  667: 
  668: static int img_info(int argc, char **argv)
  669: {
  670:     int c;
  671:     const char *filename, *fmt;
  672:     BlockDriver *drv;
  673:     BlockDriverState *bs;
  674:     char fmt_name[128], size_buf[128], dsize_buf[128];
  675:     uint64_t total_sectors;
  676:     int64_t allocated_size;
  677:     char backing_filename[1024];
  678:     char backing_filename2[1024];
  679:     BlockDriverInfo bdi;
  680: 
  681:     fmt = NULL;
  682:     for(;;) {
  683:         c = getopt(argc, argv, "f:h");
  684:         if (c == -1)
  685:             break;
  686:         switch(c) {
  687:         case 'h':
  688:             help();
  689:             break;
  690:         case 'f':
  691:             fmt = optarg;
  692:             break;
  693:         }
  694:     }
  695:     if (optind >= argc)
  696:         help();
  697:     filename = argv[optind++];
  698: 
  699:     bs = bdrv_new("");
  700:     if (!bs)
  701:         error("Not enough memory");
  702:     if (fmt) {
  703:         drv = bdrv_find_format(fmt);
  704:         if (!drv)
  705:             error("Unknown file format '%s'", fmt);
  706:     } else {
  707:         drv = NULL;
  708:     }
  709:     if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
  710:         error("Could not open '%s'", filename);
  711:     }
  712:     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
  713:     bdrv_get_geometry(bs, &total_sectors);
  714:     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
  715:     allocated_size = get_allocated_file_size(filename);
  716:     if (allocated_size < 0)
  717:         snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
  718:     else
  719:         get_human_readable_size(dsize_buf, sizeof(dsize_buf),
  720:                                 allocated_size);
  721:     printf("image: %s\n"
  722:            "file format: %s\n"
  723:            "virtual size: %s (%" PRId64 " bytes)\n"
  724:            "disk size: %s\n",
  725:            filename, fmt_name, size_buf,
  726:            (total_sectors * 512),
  727:            dsize_buf);
  728:     if (bdrv_is_encrypted(bs))
  729:         printf("encrypted: yes\n");
  730:     if (bdrv_get_info(bs, &bdi) >= 0) {
  731:         if (bdi.cluster_size != 0)
  732:             printf("cluster_size: %d\n", bdi.cluster_size);
  733:         if (bdi.highest_alloc)
  734:             printf("highest_alloc: %" PRId64 "\n", bdi.highest_alloc);
  735:         if (bdi.num_free_bytes)
  736:             printf("num_free_bytes: %" PRId64 "\n", bdi.num_free_bytes);
  737:     }
  738:     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
  739:     if (backing_filename[0] != '\0') {
  740:         path_combine(backing_filename2, sizeof(backing_filename2),
  741:                      filename, backing_filename);
  742:         printf("backing file: %s (actual path: %s)\n",
  743:                backing_filename,
  744:                backing_filename2);
  745:     }
  746:     dump_snapshots(bs);
  747:     bdrv_delete(bs);
  748:     return 0;
  749: }
  750: 
  751: #define SNAPSHOT_LIST   1
  752: #define SNAPSHOT_CREATE 2
  753: #define SNAPSHOT_APPLY  3
  754: #define SNAPSHOT_DELETE 4
  755: 
  756: static void img_snapshot(int argc, char **argv)
  757: {
  758:     BlockDriverState *bs;
  759:     QEMUSnapshotInfo sn;
  760:     char *filename, *snapshot_name = NULL;
  761:     int c, ret;
  762:     int action = 0;
  763:     qemu_timeval tv;
  764: 
  765:     /* Parse commandline parameters */
  766:     for(;;) {
  767:         c = getopt(argc, argv, "la:c:d:h");
  768:         if (c == -1)
  769:             break;
  770:         switch(c) {
  771:         case 'h':
  772:             help();
  773:             return;
  774:         case 'l':
  775:             if (action) {
  776:                 help();
  777:                 return;
  778:             }
  779:             action = SNAPSHOT_LIST;
  780:             break;
  781:         case 'a':
  782:             if (action) {
  783:                 help();
  784:                 return;
  785:             }
  786:             action = SNAPSHOT_APPLY;
  787:             snapshot_name = optarg;
  788:             break;
  789:         case 'c':
  790:             if (action) {
  791:                 help();
  792:                 return;
  793:             }
  794:             action = SNAPSHOT_CREATE;
  795:             snapshot_name = optarg;
  796:             break;
  797:         case 'd':
  798:             if (action) {
  799:                 help();
  800:                 return;
  801:             }
  802:             action = SNAPSHOT_DELETE;
  803:             snapshot_name = optarg;
  804:             break;
  805:         }
  806:     }
  807: 
  808:     if (optind >= argc)
  809:         help();
  810:     filename = argv[optind++];
  811: 
  812:     /* Open the image */
  813:     bs = bdrv_new("");
  814:     if (!bs)
  815:         error("Not enough memory");
  816: 
  817:     if (bdrv_open2(bs, filename, 0, NULL) < 0) {
  818:         error("Could not open '%s'", filename);
  819:     }
  820: 
  821:     /* Perform the requested action */
  822:     switch(action) {
  823:     case SNAPSHOT_LIST:
  824:         dump_snapshots(bs);
  825:         break;
  826: 
  827:     case SNAPSHOT_CREATE:
  828:         memset(&sn, 0, sizeof(sn));
  829:         pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
  830: 
  831:         qemu_gettimeofday(&tv);
  832:         sn.date_sec = tv.tv_sec;
  833:         sn.date_nsec = tv.tv_usec * 1000;
  834: 
  835:         ret = bdrv_snapshot_create(bs, &sn);
  836:         if (ret)
  837:             error("Could not create snapshot '%s': %d (%s)",
  838:                 snapshot_name, ret, strerror(-ret));
  839:         break;
  840: 
  841:     case SNAPSHOT_APPLY:
  842:         ret = bdrv_snapshot_goto(bs, snapshot_name);
  843:         if (ret)
  844:             error("Could not apply snapshot '%s': %d (%s)",
  845:                 snapshot_name, ret, strerror(-ret));
  846:         break;
  847: 
  848:     case SNAPSHOT_DELETE:
  849:         ret = bdrv_snapshot_delete(bs, snapshot_name);
  850:         if (ret)
  851:             error("Could not delete snapshot '%s': %d (%s)",
  852:                 snapshot_name, ret, strerror(-ret));
  853:         break;
  854:     }
  855: 
  856:     /* Cleanup */
  857:     bdrv_delete(bs);
  858: }
  859: 
  860: int main(int argc, char **argv)
  861: {
  862:     const char *cmd;
  863: 
  864:     bdrv_init();
  865:     if (argc < 2)
  866:         help();
  867:     cmd = argv[1];
  868:     argc--; argv++;
  869:     if (!strcmp(cmd, "create")) {
  870:         img_create(argc, argv);
  871:     } else if (!strcmp(cmd, "commit")) {
  872:         img_commit(argc, argv);
  873:     } else if (!strcmp(cmd, "convert")) {
  874:         img_convert(argc, argv);
  875:     } else if (!strcmp(cmd, "info")) {
  876:         img_info(argc, argv);
  877:     } else if (!strcmp(cmd, "snapshot")) {
  878:         img_snapshot(argc, argv);
  879:     } else {
  880:         help();
  881:     }
  882:     return 0;
  883: }

unix.superglobalmegacorp.com