Diff for /qemu/qemu-img.c between versions 1.1 and 1.1.1.10

version 1.1, 2018/04/24 16:37:52 version 1.1.1.10, 2018/04/24 18:16:38
Line 1 Line 1
 /*  /*
  * create a COW disk image   * QEMU disk image utility
  *    *
  * Copyright (c) 2003 Fabrice Bellard   * Copyright (c) 2003-2008 Fabrice Bellard
  *    *
  * Permission is hereby granted, free of charge, to any person obtaining a copy   * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal   * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights   * in the Software without restriction, including without limitation the rights
Line 21 Line 21
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.   * THE SOFTWARE.
  */   */
 #include "vl.h"  #include "qemu-common.h"
   #include "qemu-option.h"
 void *get_mmap_addr(unsigned long size)  #include "osdep.h"
 {  #include "block_int.h"
     return NULL;  #include <stdio.h>
 }  
   
 void qemu_free(void *ptr)  
 {  
     free(ptr);  
 }  
   
 void *qemu_malloc(size_t size)  
 {  
     return malloc(size);  
 }  
   
 void *qemu_mallocz(size_t size)  
 {  
     void *ptr;  
     ptr = qemu_malloc(size);  
     if (!ptr)  
         return NULL;  
     memset(ptr, 0, size);  
     return ptr;  
 }  
   
 char *qemu_strdup(const char *str)  
 {  
     char *ptr;  
     ptr = qemu_malloc(strlen(str) + 1);  
     if (!ptr)  
         return NULL;  
     strcpy(ptr, str);  
     return ptr;  
 }  
   
 void pstrcpy(char *buf, int buf_size, const char *str)  #ifdef _WIN32
 {  #include <windows.h>
     int c;  #endif
     char *q = buf;  
   
     if (buf_size <= 0)  
         return;  
   
     for(;;) {  
         c = *str++;  
         if (c == 0 || q >= buf + buf_size - 1)  
             break;  
         *q++ = c;  
     }  
     *q = '\0';  
 }  
   
 /* strcat and truncate. */  
 char *pstrcat(char *buf, int buf_size, const char *s)  
 {  
     int len;  
     len = strlen(buf);  
     if (len < buf_size)   
         pstrcpy(buf + len, buf_size - len, s);  
     return buf;  
 }  
   
 int strstart(const char *str, const char *val, const char **ptr)  typedef struct img_cmd_t {
 {      const char *name;
     const char *p, *q;      int (*handler)(int argc, char **argv);
     p = str;  } img_cmd_t;
     q = val;  
     while (*q != '\0') {  
         if (*p != *q)  
             return 0;  
         p++;  
         q++;  
     }  
     if (ptr)  
         *ptr = p;  
     return 1;  
 }  
   
 void term_printf(const char *fmt, ...)  /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
 {  #define BRDV_O_FLAGS BDRV_O_CACHE_WB
     va_list ap;  
     va_start(ap, fmt);  
     vprintf(fmt, ap);  
     va_end(ap);  
 }  
   
 void __attribute__((noreturn)) error(const char *fmt, ...)   static void QEMU_NORETURN error(const char *fmt, ...)
 {  {
     va_list ap;      va_list ap;
     va_start(ap, fmt);      va_start(ap, fmt);
Line 125  static void format_print(void *opaque, c Line 55  static void format_print(void *opaque, c
     printf(" %s", name);      printf(" %s", name);
 }  }
   
 void help(void)  /* Please keep in synch with qemu-img.texi */
   static void help(void)
 {  {
     printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2005 Fabrice Bellard\n"      printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
            "usage: qemu-img command [command options]\n"             "usage: qemu-img command [command options]\n"
            "QEMU disk image utility\n"             "QEMU disk image utility\n"
            "\n"             "\n"
            "Command syntax:\n"             "Command syntax:\n"
            "  create [-e] [-b base_image] [-f fmt] filename [size]\n"  #define DEF(option, callback, arg_string)        \
            "  commit [-f fmt] filename\n"             "  " arg_string "\n"
            "  convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n"  #include "qemu-img-cmds.h"
            "  info [-f fmt] filename\n"  #undef DEF
   #undef GEN_DOCS
            "\n"             "\n"
            "Command parameters:\n"             "Command parameters:\n"
            "  'filename' is a disk image filename\n"             "  'filename' is a disk image filename\n"
            "  'base_image' is the read-only disk image which is used as base for a copy on\n"  
            "    write image; the copy on write image only stores the modified data\n"  
            "  'fmt' is the disk image format. It is guessed automatically in most cases\n"             "  'fmt' is the disk image format. It is guessed automatically in most cases\n"
            "  'size' is the disk image size in kilobytes. Optional suffixes 'M' (megabyte)\n"             "  'size' is the disk image size in bytes. Optional suffixes\n"
            "    and 'G' (gigabyte) are supported\n"             "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
              "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
            "  'output_filename' is the destination disk image filename\n"             "  'output_filename' is the destination disk image filename\n"
            "  'output_fmt' is the destination format\n"             "  'output_fmt' is the destination format\n"
              "  'options' is a comma separated list of format specific options in a\n"
              "    name=value format. Use -o ? for an overview of the options supported by the\n"
              "    used format\n"
            "  '-c' indicates that target image must be compressed (qcow format only)\n"             "  '-c' indicates that target image must be compressed (qcow format only)\n"
            "  '-e' indicates that the target image must be encrypted (qcow format only)\n"             "  '-h' with or without a command shows this help and lists the supported formats\n"
              "\n"
              "Parameters to snapshot subcommand:\n"
              "  'snapshot' is the name of the snapshot to create, apply or delete\n"
              "  '-a' applies a snapshot (revert disk to saved state)\n"
              "  '-c' creates a snapshot\n"
              "  '-d' deletes a snapshot\n"
              "  '-l' lists all snapshots in the given image\n"
            );             );
     printf("\nSupported format:");      printf("\nSupported formats:");
     bdrv_iterate_format(format_print, NULL);      bdrv_iterate_format(format_print, NULL);
     printf("\n");      printf("\n");
     exit(1);      exit(1);
 }  }
   
   
 #define NB_SUFFIXES 4  
   
 static void get_human_readable_size(char *buf, int buf_size, int64_t size)  
 {  
     char suffixes[NB_SUFFIXES] = "KMGT";  
     int64_t base;  
     int i;  
   
     if (size <= 999) {  
         snprintf(buf, buf_size, "%lld", (long long) size);  
     } else {  
         base = 1024;  
         for(i = 0; i < NB_SUFFIXES; i++) {  
             if (size < (10 * base)) {  
                 snprintf(buf, buf_size, "%0.1f%c",   
                          (double)size / base,  
                          suffixes[i]);  
                 break;  
             } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {  
                 snprintf(buf, buf_size, "%lld%c",   
                          (long long) ((size + (base >> 1)) / base),  
                          suffixes[i]);  
                 break;  
             }  
             base = base * 1024;  
         }  
     }  
 }  
   
 #if defined(WIN32)  #if defined(WIN32)
 /* XXX: put correct support for win32 */  /* XXX: put correct support for win32 */
 static int read_password(char *buf, int buf_size)  static int read_password(char *buf, int buf_size)
Line 230  static void term_init(void) Line 141  static void term_init(void)
     tty.c_cflag |= CS8;      tty.c_cflag |= CS8;
     tty.c_cc[VMIN] = 1;      tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;      tty.c_cc[VTIME] = 0;
       
     tcsetattr (0, TCSANOW, &tty);      tcsetattr (0, TCSANOW, &tty);
   
     atexit(term_exit);      atexit(term_exit);
 }  }
   
 int read_password(char *buf, int buf_size)  static int read_password(char *buf, int buf_size)
 {  {
     uint8_t ch;      uint8_t ch;
     int i, ret;      int i, ret;
Line 290  static BlockDriverState *bdrv_new_open(c Line 201  static BlockDriverState *bdrv_new_open(c
     } else {      } else {
         drv = NULL;          drv = NULL;
     }      }
     if (bdrv_open2(bs, filename, 0, drv) < 0) {      if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
         error("Could not open '%s'", filename);          error("Could not open '%s'", filename);
     }      }
     if (bdrv_is_encrypted(bs)) {      if (bdrv_is_encrypted(bs)) {
Line 303  static BlockDriverState *bdrv_new_open(c Line 214  static BlockDriverState *bdrv_new_open(c
     return bs;      return bs;
 }  }
   
   static void add_old_style_options(const char *fmt, QEMUOptionParameter *list,
       int flags, const char *base_filename, const char *base_fmt)
   {
       if (flags & BLOCK_FLAG_ENCRYPT) {
           if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) {
               error("Encryption not supported for file format '%s'", fmt);
           }
       }
       if (flags & BLOCK_FLAG_COMPAT6) {
           if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) {
               error("VMDK version 6 not supported for file format '%s'", fmt);
           }
       }
   
       if (base_filename) {
           if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
               error("Backing file not supported for file format '%s'", fmt);
           }
       }
       if (base_fmt) {
           if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
               error("Backing file format not supported for file format '%s'", fmt);
           }
       }
   }
   
 static int img_create(int argc, char **argv)  static int img_create(int argc, char **argv)
 {  {
     int c, ret, encrypted;      int c, ret, flags;
     const char *fmt = "raw";      const char *fmt = "raw";
       const char *base_fmt = NULL;
     const char *filename;      const char *filename;
     const char *base_filename = NULL;      const char *base_filename = NULL;
     int64_t size;  
     const char *p;  
     BlockDriver *drv;      BlockDriver *drv;
           QEMUOptionParameter *param = NULL;
     encrypted = 0;      char *options = NULL;
   
       flags = 0;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "b:f:he");          c = getopt(argc, argv, "F:b:f:he6o:");
         if (c == -1)          if (c == -1)
             break;              break;
         switch(c) {          switch(c) {
         case 'h':          case 'h':
             help();              help();
             break;              break;
           case 'F':
               base_fmt = optarg;
               break;
         case 'b':          case 'b':
             base_filename = optarg;              base_filename = optarg;
             break;              break;
Line 329  static int img_create(int argc, char **a Line 270  static int img_create(int argc, char **a
             fmt = optarg;              fmt = optarg;
             break;              break;
         case 'e':          case 'e':
             encrypted = 1;              flags |= BLOCK_FLAG_ENCRYPT;
               break;
           case '6':
               flags |= BLOCK_FLAG_COMPAT6;
               break;
           case 'o':
               options = optarg;
             break;              break;
         }          }
     }      }
     if (optind >= argc)   
       /* Find driver and parse its options */
       drv = bdrv_find_format(fmt);
       if (!drv)
           error("Unknown file format '%s'", fmt);
   
       if (options && !strcmp(options, "?")) {
           print_option_help(drv->create_options);
           return 0;
       }
   
       /* Create parameter list with default values */
       param = parse_option_parameters("", drv->create_options, param);
       set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
   
       /* Parse -o options */
       if (options) {
           param = parse_option_parameters(options, drv->create_options, param);
           if (param == NULL) {
               error("Invalid options for file format '%s'.", fmt);
           }
       }
   
       /* Get the filename */
       if (optind >= argc)
         help();          help();
     filename = argv[optind++];      filename = argv[optind++];
     size = 0;  
     if (base_filename) {      /* Add size to parameters */
         BlockDriverState *bs;      if (optind < argc) {
         bs = bdrv_new_open(base_filename, NULL);          set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
         bdrv_get_geometry(bs, &size);      }
         size *= 512;  
         bdrv_delete(bs);      /* Add old-style options to parameters */
     } else {      add_old_style_options(fmt, param, flags, base_filename, base_fmt);
         if (optind >= argc)  
             help();      // The size for the image must always be specified, with one exception:
         p = argv[optind];      // If we are using a backing file, we can obtain the size from there
         size = strtoul(p, (char **)&p, 0);      if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
         if (*p == 'M') {  
             size *= 1024 * 1024;          QEMUOptionParameter *backing_file =
         } else if (*p == 'G') {              get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
             size *= 1024 * 1024 * 1024;          QEMUOptionParameter *backing_fmt =
         } else if (*p == 'k' || *p == 'K' || *p == '\0') {              get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
             size *= 1024;  
           if (backing_file && backing_file->value.s) {
               BlockDriverState *bs;
               uint64_t size;
               const char *fmt = NULL;
               char buf[32];
   
               if (backing_fmt && backing_fmt->value.s) {
                    if (bdrv_find_format(backing_fmt->value.s)) {
                        fmt = backing_fmt->value.s;
                   } else {
                        error("Unknown backing file format '%s'",
                           backing_fmt->value.s);
                   }
               }
   
               bs = bdrv_new_open(backing_file->value.s, fmt);
               bdrv_get_geometry(bs, &size);
               size *= 512;
               bdrv_delete(bs);
   
               snprintf(buf, sizeof(buf), "%" PRId64, size);
               set_option_parameter(param, BLOCK_OPT_SIZE, buf);
         } else {          } else {
             help();              error("Image creation needs a size parameter");
         }          }
     }      }
     drv = bdrv_find_format(fmt);  
     if (!drv)      printf("Formatting '%s', fmt=%s ", filename, fmt);
         error("Unknown file format '%s'", fmt);      print_option_parameters(param);
     printf("Formating '%s', fmt=%s",      puts("");
            filename, fmt);  
     if (encrypted)      ret = bdrv_create(drv, filename, param);
         printf(", encrypted");      free_option_parameters(param);
     if (base_filename) {  
         printf(", backing_file=%s",  
                base_filename);  
     }  
     printf(", size=%lld kB\n", (long long) (size / 1024));  
     ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted);  
     if (ret < 0) {      if (ret < 0) {
         if (ret == -ENOTSUP) {          if (ret == -ENOTSUP) {
             error("Formatting or formatting option not supported for file format '%s'", fmt);              error("Formatting or formatting option not supported for file format '%s'", fmt);
           } else if (ret == -EFBIG) {
               error("The image size is too large for file format '%s'", fmt);
         } else {          } else {
             error("Error while formatting");              error("Error while formatting");
         }          }
Line 381  static int img_create(int argc, char **a Line 371  static int img_create(int argc, char **a
     return 0;      return 0;
 }  }
   
   static int img_check(int argc, char **argv)
   {
       int c, ret;
       const char *filename, *fmt;
       BlockDriver *drv;
       BlockDriverState *bs;
   
       fmt = NULL;
       for(;;) {
           c = getopt(argc, argv, "f:h");
           if (c == -1)
               break;
           switch(c) {
           case 'h':
               help();
               break;
           case 'f':
               fmt = optarg;
               break;
           }
       }
       if (optind >= argc)
           help();
       filename = argv[optind++];
   
       bs = bdrv_new("");
       if (!bs)
           error("Not enough memory");
       if (fmt) {
           drv = bdrv_find_format(fmt);
           if (!drv)
               error("Unknown file format '%s'", fmt);
       } else {
           drv = NULL;
       }
       if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
           error("Could not open '%s'", filename);
       }
       ret = bdrv_check(bs);
       switch(ret) {
       case 0:
           printf("No errors were found on the image.\n");
           break;
       case -ENOTSUP:
           error("This image format does not support checks");
           break;
       default:
           if (ret < 0) {
               error("An error occurred during the check");
           } else {
               printf("%d errors were found on the image.\n", ret);
           }
           break;
       }
   
       bdrv_delete(bs);
       return 0;
   }
   
 static int img_commit(int argc, char **argv)  static int img_commit(int argc, char **argv)
 {  {
     int c, ret;      int c, ret;
Line 402  static int img_commit(int argc, char **a Line 451  static int img_commit(int argc, char **a
             break;              break;
         }          }
     }      }
     if (optind >= argc)       if (optind >= argc)
         help();          help();
     filename = argv[optind++];      filename = argv[optind++];
   
Line 416  static int img_commit(int argc, char **a Line 465  static int img_commit(int argc, char **a
     } else {      } else {
         drv = NULL;          drv = NULL;
     }      }
     if (bdrv_open2(bs, filename, 0, drv) < 0) {      if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
         error("Could not open '%s'", filename);          error("Could not open '%s'", filename);
     }      }
     ret = bdrv_commit(bs);      ret = bdrv_commit(bs);
Line 453  static int is_not_zero(const uint8_t *se Line 502  static int is_not_zero(const uint8_t *se
     return 0;      return 0;
 }  }
   
   /*
    * Returns true iff the first sector pointed to by 'buf' contains at least
    * a non-NUL byte.
    *
    * 'pnum' is set to the number of sectors (including and immediately following
    * the first one) that are known to be in the same allocated/unallocated state.
    */
 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)  static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
 {  {
     int v, i;      int v, i;
Line 471  static int is_allocated_sectors(const ui Line 527  static int is_allocated_sectors(const ui
     return v;      return v;
 }  }
   
 #define IO_BUF_SIZE 65536  #define IO_BUF_SIZE (2 * 1024 * 1024)
   
 static int img_convert(int argc, char **argv)  static int img_convert(int argc, char **argv)
 {  {
     int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt;      int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
     const char *filename, *fmt, *out_fmt, *out_filename;      const char *fmt, *out_fmt, *out_baseimg, *out_filename;
     BlockDriver *drv;      BlockDriver *drv;
     BlockDriverState *bs, *out_bs;      BlockDriverState **bs, *out_bs;
     int64_t total_sectors, nb_sectors, sector_num;      int64_t total_sectors, nb_sectors, sector_num, bs_offset;
     uint8_t buf[IO_BUF_SIZE];      uint64_t bs_sectors;
       uint8_t * buf;
     const uint8_t *buf1;      const uint8_t *buf1;
       BlockDriverInfo bdi;
       QEMUOptionParameter *param = NULL;
       char *options = NULL;
   
     fmt = NULL;      fmt = NULL;
     out_fmt = "raw";      out_fmt = "raw";
     compress = 0;      out_baseimg = NULL;
     encrypt = 0;      flags = 0;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:O:hce");          c = getopt(argc, argv, "f:O:B:hce6o:");
         if (c == -1)          if (c == -1)
             break;              break;
         switch(c) {          switch(c) {
Line 501  static int img_convert(int argc, char ** Line 561  static int img_convert(int argc, char **
         case 'O':          case 'O':
             out_fmt = optarg;              out_fmt = optarg;
             break;              break;
           case 'B':
               out_baseimg = optarg;
               break;
         case 'c':          case 'c':
             compress = 1;              flags |= BLOCK_FLAG_COMPRESS;
             break;              break;
         case 'e':          case 'e':
             encrypt = 1;              flags |= BLOCK_FLAG_ENCRYPT;
               break;
           case '6':
               flags |= BLOCK_FLAG_COMPAT6;
               break;
           case 'o':
               options = optarg;
             break;              break;
         }          }
     }      }
     if (optind >= argc)   
         help();  
     filename = argv[optind++];  
     if (optind >= argc)   
         help();  
     out_filename = argv[optind++];  
       
     bs = bdrv_new_open(filename, fmt);  
   
       bs_n = argc - optind - 1;
       if (bs_n < 1) help();
   
       out_filename = argv[argc - 1];
   
       if (bs_n > 1 && out_baseimg)
           error("-B makes no sense when concatenating multiple input images");
           
       bs = calloc(bs_n, sizeof(BlockDriverState *));
       if (!bs)
           error("Out of memory");
   
       total_sectors = 0;
       for (bs_i = 0; bs_i < bs_n; bs_i++) {
           bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
           if (!bs[bs_i])
               error("Could not open '%s'", argv[optind + bs_i]);
           bdrv_get_geometry(bs[bs_i], &bs_sectors);
           total_sectors += bs_sectors;
       }
   
       /* Find driver and parse its options */
     drv = bdrv_find_format(out_fmt);      drv = bdrv_find_format(out_fmt);
     if (!drv)      if (!drv)
         error("Unknown file format '%s'", fmt);          error("Unknown file format '%s'", out_fmt);
     if (compress && drv != &bdrv_qcow)  
         error("Compression not supported for this file format");      if (options && !strcmp(options, "?")) {
     if (encrypt && drv != &bdrv_qcow)          print_option_help(drv->create_options);
         error("Encryption not supported for this file format");          free(bs);
     if (compress && encrypt)          return 0;
         error("Compression and encryption not supported at the same time");      }
     bdrv_get_geometry(bs, &total_sectors);  
     ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt);      if (options) {
           param = parse_option_parameters(options, drv->create_options, param);
           if (param == NULL) {
               error("Invalid options for file format '%s'.", out_fmt);
           }
       } else {
           param = parse_option_parameters("", drv->create_options, param);
       }
   
       set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
       add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);
   
       /* Check if compression is supported */
       if (flags & BLOCK_FLAG_COMPRESS) {
           QEMUOptionParameter *encryption =
               get_option_parameter(param, BLOCK_OPT_ENCRYPT);
   
           if (!drv->bdrv_write_compressed) {
               error("Compression not supported for this file format");
           }
   
           if (encryption && encryption->value.n) {
               error("Compression and encryption not supported at the same time");
           }
       }
   
       /* Create the new image */
       ret = bdrv_create(drv, out_filename, param);
       free_option_parameters(param);
   
     if (ret < 0) {      if (ret < 0) {
         if (ret == -ENOTSUP) {          if (ret == -ENOTSUP) {
             error("Formatting not supported for file format '%s'", fmt);              error("Formatting not supported for file format '%s'", out_fmt);
           } else if (ret == -EFBIG) {
               error("The image size is too large for file format '%s'", out_fmt);
         } else {          } else {
             error("Error while formatting '%s'", out_filename);              error("Error while formatting '%s'", out_filename);
         }          }
     }      }
       
     out_bs = bdrv_new_open(out_filename, out_fmt);      out_bs = bdrv_new_open(out_filename, out_fmt);
   
     if (compress) {      bs_i = 0;
         cluster_size = qcow_get_cluster_size(out_bs);      bs_offset = 0;
       bdrv_get_geometry(bs[0], &bs_sectors);
       buf = qemu_malloc(IO_BUF_SIZE);
   
       if (flags & BLOCK_FLAG_COMPRESS) {
           if (bdrv_get_info(out_bs, &bdi) < 0)
               error("could not get block driver info");
           cluster_size = bdi.cluster_size;
         if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)          if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
             error("invalid cluster size");              error("invalid cluster size");
         cluster_sectors = cluster_size >> 9;          cluster_sectors = cluster_size >> 9;
         sector_num = 0;          sector_num = 0;
         for(;;) {          for(;;) {
               int64_t bs_num;
               int remainder;
               uint8_t *buf2;
   
             nb_sectors = total_sectors - sector_num;              nb_sectors = total_sectors - sector_num;
             if (nb_sectors <= 0)              if (nb_sectors <= 0)
                 break;                  break;
Line 553  static int img_convert(int argc, char ** Line 678  static int img_convert(int argc, char **
                 n = cluster_sectors;                  n = cluster_sectors;
             else              else
                 n = nb_sectors;                  n = nb_sectors;
             if (bdrv_read(bs, sector_num, buf, n) < 0)   
                 error("error while reading");              bs_num = sector_num - bs_offset;
               assert (bs_num >= 0);
               remainder = n;
               buf2 = buf;
               while (remainder > 0) {
                   int nlow;
                   while (bs_num == bs_sectors) {
                       bs_i++;
                       assert (bs_i < bs_n);
                       bs_offset += bs_sectors;
                       bdrv_get_geometry(bs[bs_i], &bs_sectors);
                       bs_num = 0;
                       /* printf("changing part: sector_num=%lld, "
                          "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
                          sector_num, bs_i, bs_offset, bs_sectors); */
                   }
                   assert (bs_num < bs_sectors);
   
                   nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
   
                   if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0) 
                       error("error while reading");
   
                   buf2 += nlow * 512;
                   bs_num += nlow;
   
                   remainder -= nlow;
               }
               assert (remainder == 0);
   
             if (n < cluster_sectors)              if (n < cluster_sectors)
                 memset(buf + n * 512, 0, cluster_size - n * 512);                  memset(buf + n * 512, 0, cluster_size - n * 512);
             if (is_not_zero(buf, cluster_size)) {              if (is_not_zero(buf, cluster_size)) {
                 if (qcow_compress_cluster(out_bs, sector_num, buf) != 0)                  if (bdrv_write_compressed(out_bs, sector_num, buf,
                     error("error while compressing sector %lld", sector_num);                                            cluster_sectors) != 0)
                       error("error while compressing sector %" PRId64,
                             sector_num);
             }              }
             sector_num += n;              sector_num += n;
         }          }
           /* signal EOF to align */
           bdrv_write_compressed(out_bs, 0, NULL, 0);
     } else {      } else {
         sector_num = 0;          sector_num = 0; // total number of sectors converted so far
         for(;;) {          for(;;) {
             nb_sectors = total_sectors - sector_num;              nb_sectors = total_sectors - sector_num;
             if (nb_sectors <= 0)              if (nb_sectors <= 0)
Line 573  static int img_convert(int argc, char ** Line 731  static int img_convert(int argc, char **
                 n = (IO_BUF_SIZE / 512);                  n = (IO_BUF_SIZE / 512);
             else              else
                 n = nb_sectors;                  n = nb_sectors;
             if (bdrv_read(bs, sector_num, buf, n) < 0)   
               while (sector_num - bs_offset >= bs_sectors) {
                   bs_i ++;
                   assert (bs_i < bs_n);
                   bs_offset += bs_sectors;
                   bdrv_get_geometry(bs[bs_i], &bs_sectors);
                   /* printf("changing part: sector_num=%lld, bs_i=%d, "
                     "bs_offset=%lld, bs_sectors=%lld\n",
                      sector_num, bs_i, bs_offset, bs_sectors); */
               }
   
               if (n > bs_offset + bs_sectors - sector_num)
                   n = bs_offset + bs_sectors - sector_num;
   
               if (!drv->no_zero_init) {
                   /* If the output image is being created as a copy on write image,
                      assume that sectors which are unallocated in the input image
                      are present in both the output's and input's base images (no
                      need to copy them). */
                   if (out_baseimg) {
                       if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
                                              n, &n1)) {
                           sector_num += n1;
                           continue;
                       }
                       /* The next 'n1' sectors are allocated in the input image. Copy
                          only those as they may be followed by unallocated sectors. */
                       n = n1;
                   }
               } else {
                   n1 = n;
               }
   
               if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0) 
                 error("error while reading");                  error("error while reading");
             /* NOTE: at the same time we convert, we do not write zero              /* NOTE: at the same time we convert, we do not write zero
                sectors to have a chance to compress the image. Ideally, we                 sectors to have a chance to compress the image. Ideally, we
                should add a specific call to have the info to go faster */                 should add a specific call to have the info to go faster */
             buf1 = buf;              buf1 = buf;
             while (n > 0) {              while (n > 0) {
                 if (is_allocated_sectors(buf1, n, &n1)) {                  /* If the output image is being created as a copy on write image,
                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)                      copy all sectors even the ones containing only NUL bytes,
                      because they may differ from the sectors in the base image.
   
                      If the output is to a host device, we also write out
                      sectors that are entirely 0, since whatever data was
                      already there is garbage, not 0s. */
                   if (drv->no_zero_init || out_baseimg ||
                       is_allocated_sectors(buf1, n, &n1)) {
                       if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
                         error("error while writing");                          error("error while writing");
                 }                  }
                 sector_num += n1;                  sector_num += n1;
Line 590  static int img_convert(int argc, char ** Line 789  static int img_convert(int argc, char **
             }              }
         }          }
     }      }
       qemu_free(buf);
     bdrv_delete(out_bs);      bdrv_delete(out_bs);
     bdrv_delete(bs);      for (bs_i = 0; bs_i < bs_n; bs_i++)
           bdrv_delete(bs[bs_i]);
       free(bs);
     return 0;      return 0;
 }  }
   
 #ifdef _WIN32  #ifdef _WIN32
 static int64_t get_allocated_file_size(const char *filename)  static int64_t get_allocated_file_size(const char *filename)
 {  {
       typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
       get_compressed_t get_compressed;
     struct _stati64 st;      struct _stati64 st;
     if (_stati64(filename, &st) < 0)   
       /* WinNT support GetCompressedFileSize to determine allocate size */
       get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
       if (get_compressed) {
           DWORD high, low;
           low = get_compressed(filename, &high);
           if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
               return (((int64_t) high) << 32) + low;
       }
   
       if (_stati64(filename, &st) < 0)
         return -1;          return -1;
     return st.st_size;      return st.st_size;
 }  }
Line 607  static int64_t get_allocated_file_size(c Line 821  static int64_t get_allocated_file_size(c
 static int64_t get_allocated_file_size(const char *filename)  static int64_t get_allocated_file_size(const char *filename)
 {  {
     struct stat st;      struct stat st;
     if (stat(filename, &st) < 0)       if (stat(filename, &st) < 0)
         return -1;          return -1;
     return (int64_t)st.st_blocks * 512;      return (int64_t)st.st_blocks * 512;
 }  }
 #endif  #endif
   
   static void dump_snapshots(BlockDriverState *bs)
   {
       QEMUSnapshotInfo *sn_tab, *sn;
       int nb_sns, i;
       char buf[256];
   
       nb_sns = bdrv_snapshot_list(bs, &sn_tab);
       if (nb_sns <= 0)
           return;
       printf("Snapshot list:\n");
       printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
       for(i = 0; i < nb_sns; i++) {
           sn = &sn_tab[i];
           printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
       }
       qemu_free(sn_tab);
   }
   
 static int img_info(int argc, char **argv)  static int img_info(int argc, char **argv)
 {  {
     int c;      int c;
Line 620  static int img_info(int argc, char **arg Line 852  static int img_info(int argc, char **arg
     BlockDriver *drv;      BlockDriver *drv;
     BlockDriverState *bs;      BlockDriverState *bs;
     char fmt_name[128], size_buf[128], dsize_buf[128];      char fmt_name[128], size_buf[128], dsize_buf[128];
     int64_t total_sectors, allocated_size;      uint64_t total_sectors;
       int64_t allocated_size;
       char backing_filename[1024];
       char backing_filename2[1024];
       BlockDriverInfo bdi;
   
     fmt = NULL;      fmt = NULL;
     for(;;) {      for(;;) {
Line 636  static int img_info(int argc, char **arg Line 872  static int img_info(int argc, char **arg
             break;              break;
         }          }
     }      }
     if (optind >= argc)       if (optind >= argc)
         help();          help();
     filename = argv[optind++];      filename = argv[optind++];
   
Line 650  static int img_info(int argc, char **arg Line 886  static int img_info(int argc, char **arg
     } else {      } else {
         drv = NULL;          drv = NULL;
     }      }
     if (bdrv_open2(bs, filename, 0, drv) < 0) {      if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
         error("Could not open '%s'", filename);          error("Could not open '%s'", filename);
     }      }
     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));      bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
Line 658  static int img_info(int argc, char **arg Line 894  static int img_info(int argc, char **arg
     get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);      get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
     allocated_size = get_allocated_file_size(filename);      allocated_size = get_allocated_file_size(filename);
     if (allocated_size < 0)      if (allocated_size < 0)
         sprintf(dsize_buf, "unavailable");          snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
     else      else
         get_human_readable_size(dsize_buf, sizeof(dsize_buf),           get_human_readable_size(dsize_buf, sizeof(dsize_buf),
                                 allocated_size);                                  allocated_size);
     printf("image: %s\n"      printf("image: %s\n"
            "file format: %s\n"             "file format: %s\n"
            "virtual size: %s (%lld bytes)\n"             "virtual size: %s (%" PRId64 " bytes)\n"
            "disk size: %s\n",             "disk size: %s\n",
            filename, fmt_name, size_buf,              filename, fmt_name, size_buf,
            (long long) (total_sectors * 512),             (total_sectors * 512),
            dsize_buf);             dsize_buf);
     if (bdrv_is_encrypted(bs))      if (bdrv_is_encrypted(bs))
         printf("encrypted: yes\n");          printf("encrypted: yes\n");
       if (bdrv_get_info(bs, &bdi) >= 0) {
           if (bdi.cluster_size != 0)
               printf("cluster_size: %d\n", bdi.cluster_size);
       }
       bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
       if (backing_filename[0] != '\0') {
           path_combine(backing_filename2, sizeof(backing_filename2),
                        filename, backing_filename);
           printf("backing file: %s (actual path: %s)\n",
                  backing_filename,
                  backing_filename2);
       }
       dump_snapshots(bs);
     bdrv_delete(bs);      bdrv_delete(bs);
     return 0;      return 0;
 }  }
   
   #define SNAPSHOT_LIST   1
   #define SNAPSHOT_CREATE 2
   #define SNAPSHOT_APPLY  3
   #define SNAPSHOT_DELETE 4
   
   static int img_snapshot(int argc, char **argv)
   {
       BlockDriverState *bs;
       QEMUSnapshotInfo sn;
       char *filename, *snapshot_name = NULL;
       int c, ret;
       int action = 0;
       qemu_timeval tv;
   
       /* Parse commandline parameters */
       for(;;) {
           c = getopt(argc, argv, "la:c:d:h");
           if (c == -1)
               break;
           switch(c) {
           case 'h':
               help();
               return 0;
           case 'l':
               if (action) {
                   help();
                   return 0;
               }
               action = SNAPSHOT_LIST;
               break;
           case 'a':
               if (action) {
                   help();
                   return 0;
               }
               action = SNAPSHOT_APPLY;
               snapshot_name = optarg;
               break;
           case 'c':
               if (action) {
                   help();
                   return 0;
               }
               action = SNAPSHOT_CREATE;
               snapshot_name = optarg;
               break;
           case 'd':
               if (action) {
                   help();
                   return 0;
               }
               action = SNAPSHOT_DELETE;
               snapshot_name = optarg;
               break;
           }
       }
   
       if (optind >= argc)
           help();
       filename = argv[optind++];
   
       /* Open the image */
       bs = bdrv_new("");
       if (!bs)
           error("Not enough memory");
   
       if (bdrv_open2(bs, filename, 0, NULL) < 0) {
           error("Could not open '%s'", filename);
       }
   
       /* Perform the requested action */
       switch(action) {
       case SNAPSHOT_LIST:
           dump_snapshots(bs);
           break;
   
       case SNAPSHOT_CREATE:
           memset(&sn, 0, sizeof(sn));
           pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
   
           qemu_gettimeofday(&tv);
           sn.date_sec = tv.tv_sec;
           sn.date_nsec = tv.tv_usec * 1000;
   
           ret = bdrv_snapshot_create(bs, &sn);
           if (ret)
               error("Could not create snapshot '%s': %d (%s)",
                   snapshot_name, ret, strerror(-ret));
           break;
   
       case SNAPSHOT_APPLY:
           ret = bdrv_snapshot_goto(bs, snapshot_name);
           if (ret)
               error("Could not apply snapshot '%s': %d (%s)",
                   snapshot_name, ret, strerror(-ret));
           break;
   
       case SNAPSHOT_DELETE:
           ret = bdrv_snapshot_delete(bs, snapshot_name);
           if (ret)
               error("Could not delete snapshot '%s': %d (%s)",
                   snapshot_name, ret, strerror(-ret));
           break;
       }
   
       /* Cleanup */
       bdrv_delete(bs);
   
       return 0;
   }
   
   static const img_cmd_t img_cmds[] = {
   #define DEF(option, callback, arg_string)        \
       { option, callback },
   #include "qemu-img-cmds.h"
   #undef DEF
   #undef GEN_DOCS
       { NULL, NULL, },
   };
   
 int main(int argc, char **argv)  int main(int argc, char **argv)
 {  {
     const char *cmd;      const img_cmd_t *cmd;
       const char *cmdname;
   
     bdrv_init();      bdrv_init();
     if (argc < 2)      if (argc < 2)
         help();          help();
     cmd = argv[1];      cmdname = argv[1];
     optind++;      argc--; argv++;
     if (!strcmp(cmd, "create")) {  
         img_create(argc, argv);      /* find the command */
     } else if (!strcmp(cmd, "commit")) {      for(cmd = img_cmds; cmd->name != NULL; cmd++) {
         img_commit(argc, argv);          if (!strcmp(cmdname, cmd->name)) {
     } else if (!strcmp(cmd, "convert")) {              return cmd->handler(argc, argv);
         img_convert(argc, argv);          }
     } else if (!strcmp(cmd, "info")) {  
         img_info(argc, argv);  
     } else {  
         help();  
     }      }
   
       /* not found */
       help();
     return 0;      return 0;
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.10


unix.superglobalmegacorp.com