Diff for /qemu/qemu-img.c between versions 1.1.1.11 and 1.1.1.15

version 1.1.1.11, 2018/04/24 18:24:09 version 1.1.1.15, 2018/04/24 19:34:36
Line 23 Line 23
  */   */
 #include "qemu-common.h"  #include "qemu-common.h"
 #include "qemu-option.h"  #include "qemu-option.h"
   #include "qemu-error.h"
 #include "osdep.h"  #include "osdep.h"
   #include "sysemu.h"
 #include "block_int.h"  #include "block_int.h"
 #include <stdio.h>  #include <stdio.h>
   
Line 38  typedef struct img_cmd_t { Line 40  typedef struct img_cmd_t {
   
 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */  /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
 #define BDRV_O_FLAGS BDRV_O_CACHE_WB  #define BDRV_O_FLAGS BDRV_O_CACHE_WB
   #define BDRV_DEFAULT_CACHE "writeback"
 static void error(const char *fmt, ...)  
 {  
     va_list ap;  
     va_start(ap, fmt);  
     fprintf(stderr, "qemu-img: ");  
     vfprintf(stderr, fmt, ap);  
     fprintf(stderr, "\n");  
     va_end(ap);  
 }  
   
 static void format_print(void *opaque, const char *name)  static void format_print(void *opaque, const char *name)
 {  {
Line 72  static void help(void) Line 65  static void help(void)
            "Command parameters:\n"             "Command parameters:\n"
            "  'filename' is a disk image filename\n"             "  'filename' is a disk image filename\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"
              "  'cache' is the cache mode used to write the output disk image, the valid\n"
              "    options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
              "    'directsync' and 'unsafe' (default for convert)\n"
            "  'size' is the disk image size in bytes. Optional suffixes\n"             "  'size' is the disk image size in bytes. Optional suffixes\n"
            "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"             "    'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
            "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"             "    and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
Line 85  static void help(void) Line 81  static void help(void)
            "       match exactly. The image doesn't need a working backing file before\n"             "       match exactly. The image doesn't need a working backing file before\n"
            "       rebasing in this case (useful for renaming the backing file)\n"             "       rebasing in this case (useful for renaming the backing file)\n"
            "  '-h' with or without a command shows this help and lists the supported formats\n"             "  '-h' with or without a command shows this help and lists the supported formats\n"
              "  '-p' show progress of command (only certain commands)\n"
              "  '-S' indicates the consecutive number of bytes that must contain only zeros\n"
              "       for qemu-img to create a sparse image during conversion\n"
            "\n"             "\n"
            "Parameters to snapshot subcommand:\n"             "Parameters to snapshot subcommand:\n"
            "  'snapshot' is the name of the snapshot to create, apply or delete\n"             "  'snapshot' is the name of the snapshot to create, apply or delete\n"
Line 187  static int read_password(char *buf, int  Line 186  static int read_password(char *buf, int 
 }  }
 #endif  #endif
   
   static int print_block_option_help(const char *filename, const char *fmt)
   {
       BlockDriver *drv, *proto_drv;
       QEMUOptionParameter *create_options = NULL;
   
       /* Find driver and parse its options */
       drv = bdrv_find_format(fmt);
       if (!drv) {
           error_report("Unknown file format '%s'", fmt);
           return 1;
       }
   
       proto_drv = bdrv_find_protocol(filename);
       if (!proto_drv) {
           error_report("Unknown protocol '%s'", filename);
           return 1;
       }
   
       create_options = append_option_parameters(create_options,
                                                 drv->create_options);
       create_options = append_option_parameters(create_options,
                                                 proto_drv->create_options);
       print_option_help(create_options);
       free_option_parameters(create_options);
       return 0;
   }
   
 static BlockDriverState *bdrv_new_open(const char *filename,  static BlockDriverState *bdrv_new_open(const char *filename,
                                        const char *fmt,                                         const char *fmt,
                                        int flags)                                         int flags)
Line 194  static BlockDriverState *bdrv_new_open(c Line 220  static BlockDriverState *bdrv_new_open(c
     BlockDriverState *bs;      BlockDriverState *bs;
     BlockDriver *drv;      BlockDriver *drv;
     char password[256];      char password[256];
       int ret;
   
       bs = bdrv_new("image");
   
     bs = bdrv_new("");  
     if (!bs) {  
         error("Not enough memory");  
         goto fail;  
     }  
     if (fmt) {      if (fmt) {
         drv = bdrv_find_format(fmt);          drv = bdrv_find_format(fmt);
         if (!drv) {          if (!drv) {
             error("Unknown file format '%s'", fmt);              error_report("Unknown file format '%s'", fmt);
             goto fail;              goto fail;
         }          }
     } else {      } else {
         drv = NULL;          drv = NULL;
     }      }
     if (bdrv_open(bs, filename, flags, drv) < 0) {  
         error("Could not open '%s'", filename);      ret = bdrv_open(bs, filename, flags, drv);
       if (ret < 0) {
           error_report("Could not open '%s': %s", filename, strerror(-ret));
         goto fail;          goto fail;
     }      }
   
     if (bdrv_is_encrypted(bs)) {      if (bdrv_is_encrypted(bs)) {
         printf("Disk image '%s' is encrypted.\n", filename);          printf("Disk image '%s' is encrypted.\n", filename);
         if (read_password(password, sizeof(password)) < 0) {          if (read_password(password, sizeof(password)) < 0) {
             error("No password given");              error_report("No password given");
             goto fail;              goto fail;
         }          }
         if (bdrv_set_key(bs, password) < 0) {          if (bdrv_set_key(bs, password) < 0) {
             error("invalid password");              error_report("invalid password");
             goto fail;              goto fail;
         }          }
     }      }
Line 233  fail: Line 260  fail:
 }  }
   
 static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,  static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
     int flags, const char *base_filename, const char *base_fmt)                                   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);  
             return -1;  
         }  
     }  
     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);  
             return -1;  
         }  
     }  
   
     if (base_filename) {      if (base_filename) {
         if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {          if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
             error("Backing file not supported for file format '%s'", fmt);              error_report("Backing file not supported for file format '%s'",
                            fmt);
             return -1;              return -1;
         }          }
     }      }
     if (base_fmt) {      if (base_fmt) {
         if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {          if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
             error("Backing file format not supported for file format '%s'", fmt);              error_report("Backing file format not supported for file "
                            "format '%s'", fmt);
             return -1;              return -1;
         }          }
     }      }
Line 265  static int add_old_style_options(const c Line 282  static int add_old_style_options(const c
   
 static int img_create(int argc, char **argv)  static int img_create(int argc, char **argv)
 {  {
     int c, ret = 0, flags;      int c, ret = 0;
       uint64_t img_size = -1;
     const char *fmt = "raw";      const char *fmt = "raw";
     const char *base_fmt = NULL;      const char *base_fmt = NULL;
     const char *filename;      const char *filename;
     const char *base_filename = NULL;      const char *base_filename = NULL;
     BlockDriver *drv, *proto_drv;  
     QEMUOptionParameter *param = NULL, *create_options = NULL;  
     char *options = NULL;      char *options = NULL;
   
     flags = 0;  
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "F:b:f:he6o:");          c = getopt(argc, argv, "F:b:f:he6o:");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
Line 293  static int img_create(int argc, char **a Line 310  static int img_create(int argc, char **a
             fmt = optarg;              fmt = optarg;
             break;              break;
         case 'e':          case 'e':
             flags |= BLOCK_FLAG_ENCRYPT;              error_report("option -e is deprecated, please use \'-o "
             break;                    "encryption\' instead!");
               return 1;
         case '6':          case '6':
             flags |= BLOCK_FLAG_COMPAT6;              error_report("option -6 is deprecated, please use \'-o "
             break;                    "compat6\' instead!");
               return 1;
         case 'o':          case 'o':
             options = optarg;              options = optarg;
             break;              break;
Line 305  static int img_create(int argc, char **a Line 324  static int img_create(int argc, char **a
     }      }
   
     /* Get the filename */      /* Get the filename */
     if (optind >= argc)      if (optind >= argc) {
         help();          help();
     filename = argv[optind++];  
   
     /* Find driver and parse its options */  
     drv = bdrv_find_format(fmt);  
     if (!drv) {  
         error("Unknown file format '%s'", fmt);  
         return 1;  
     }  
   
     proto_drv = bdrv_find_protocol(filename);  
     if (!proto_drv) {  
         error("Unknown protocol '%s'", filename);  
         return 1;  
     }  
   
     create_options = append_option_parameters(create_options,  
                                               drv->create_options);  
     create_options = append_option_parameters(create_options,  
                                               proto_drv->create_options);  
   
     if (options && !strcmp(options, "?")) {  
         print_option_help(create_options);  
         goto out;  
     }      }
       filename = argv[optind++];
   
     /* Create parameter list with default values */      /* Get image size, if specified */
     param = parse_option_parameters("", create_options, param);      if (optind < argc) {
     set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);          int64_t sval;
           char *end;
     /* Parse -o options */          sval = strtosz_suffix(argv[optind++], &end, STRTOSZ_DEFSUFFIX_B);
     if (options) {          if (sval < 0 || *end) {
         param = parse_option_parameters(options, create_options, param);              error_report("Invalid image size specified! You may use k, M, G or "
         if (param == NULL) {                    "T suffixes for ");
             error("Invalid options for file format '%s'.", fmt);              error_report("kilobytes, megabytes, gigabytes and terabytes.");
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
           img_size = (uint64_t)sval;
     }      }
   
     /* Add size to parameters */      if (options && !strcmp(options, "?")) {
     if (optind < argc) {          ret = print_block_option_help(filename, fmt);
         set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);  
     }  
   
     /* Add old-style options to parameters */  
     ret = add_old_style_options(fmt, param, flags, base_filename, base_fmt);  
     if (ret < 0) {  
         goto out;          goto out;
     }      }
   
     // The size for the image must always be specified, with one exception:      ret = bdrv_img_create(filename, fmt, base_filename, base_fmt,
     // If we are using a backing file, we can obtain the size from there                            options, img_size, BDRV_O_FLAGS);
     if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {  
   
         QEMUOptionParameter *backing_file =  
             get_option_parameter(param, BLOCK_OPT_BACKING_FILE);  
         QEMUOptionParameter *backing_fmt =  
             get_option_parameter(param, BLOCK_OPT_BACKING_FMT);  
   
         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);  
                      ret = -1;  
                      goto out;  
                 }  
             }  
   
             bs = bdrv_new_open(backing_file->value.s, fmt, BDRV_O_FLAGS);  
             if (!bs) {  
                 ret = -1;  
                 goto out;  
             }  
             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 {  
             error("Image creation needs a size parameter");  
             ret = -1;  
             goto out;  
         }  
     }  
   
     printf("Formatting '%s', fmt=%s ", filename, fmt);  
     print_option_parameters(param);  
     puts("");  
   
     ret = bdrv_create(drv, filename, param);  
     free_option_parameters(create_options);  
     free_option_parameters(param);  
   
     if (ret < 0) {  
         if (ret == -ENOTSUP) {  
             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 {  
             error("%s: error while creating %s: %s", filename, fmt, strerror(-ret));  
         }  
     }  
 out:  out:
     if (ret) {      if (ret) {
         return 1;          return 1;
Line 443  static int img_check(int argc, char **ar Line 376  static int img_check(int argc, char **ar
     fmt = NULL;      fmt = NULL;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:h");          c = getopt(argc, argv, "f:h");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
Line 454  static int img_check(int argc, char **ar Line 389  static int img_check(int argc, char **ar
             break;              break;
         }          }
     }      }
     if (optind >= argc)      if (optind >= argc) {
         help();          help();
       }
     filename = argv[optind++];      filename = argv[optind++];
   
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);      bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS);
Line 465  static int img_check(int argc, char **ar Line 401  static int img_check(int argc, char **ar
     ret = bdrv_check(bs, &result);      ret = bdrv_check(bs, &result);
   
     if (ret == -ENOTSUP) {      if (ret == -ENOTSUP) {
         error("This image format does not support checks");          error_report("This image format does not support checks");
         bdrv_delete(bs);          bdrv_delete(bs);
         return 1;          return 1;
     }      }
Line 492  static int img_check(int argc, char **ar Line 428  static int img_check(int argc, char **ar
         }          }
     }      }
   
       if (result.bfi.total_clusters != 0 && result.bfi.allocated_clusters != 0) {
           printf("%" PRId64 "/%" PRId64 "= %0.2f%% allocated, %0.2f%% fragmented\n",
           result.bfi.allocated_clusters, result.bfi.total_clusters,
           result.bfi.allocated_clusters * 100.0 / result.bfi.total_clusters,
           result.bfi.fragmented_clusters * 100.0 / result.bfi.allocated_clusters);
       }
   
     bdrv_delete(bs);      bdrv_delete(bs);
   
     if (ret < 0 || result.check_errors) {      if (ret < 0 || result.check_errors) {
Line 512  static int img_check(int argc, char **ar Line 455  static int img_check(int argc, char **ar
   
 static int img_commit(int argc, char **argv)  static int img_commit(int argc, char **argv)
 {  {
     int c, ret;      int c, ret, flags;
     const char *filename, *fmt;      const char *filename, *fmt, *cache;
     BlockDriverState *bs;      BlockDriverState *bs;
   
     fmt = NULL;      fmt = NULL;
       cache = BDRV_DEFAULT_CACHE;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:h");          c = getopt(argc, argv, "f:ht:");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
         case 'f':          case 'f':
             fmt = optarg;              fmt = optarg;
             break;              break;
           case 't':
               cache = optarg;
               break;
         }          }
     }      }
     if (optind >= argc)      if (optind >= argc) {
         help();          help();
       }
     filename = argv[optind++];      filename = argv[optind++];
   
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);      flags = BDRV_O_RDWR;
       ret = bdrv_parse_cache_flags(cache, &flags);
       if (ret < 0) {
           error_report("Invalid cache option: %s", cache);
           return -1;
       }
   
       bs = bdrv_new_open(filename, fmt, flags);
     if (!bs) {      if (!bs) {
         return 1;          return 1;
     }      }
Line 544  static int img_commit(int argc, char **a Line 501  static int img_commit(int argc, char **a
         printf("Image committed.\n");          printf("Image committed.\n");
         break;          break;
     case -ENOENT:      case -ENOENT:
         error("No disk inserted");          error_report("No disk inserted");
         break;          break;
     case -EACCES:      case -EACCES:
         error("Image is read-only");          error_report("Image is read-only");
         break;          break;
     case -ENOTSUP:      case -ENOTSUP:
         error("Image is already committed");          error_report("Image is already committed");
         break;          break;
     default:      default:
         error("Error while committing image");          error_report("Error while committing image");
         break;          break;
     }      }
   
Line 564  static int img_commit(int argc, char **a Line 521  static int img_commit(int argc, char **a
     return 0;      return 0;
 }  }
   
 static int is_not_zero(const uint8_t *sector, int len)  
 {  
     int i;  
     len >>= 2;  
     for(i = 0;i < len; i++) {  
         if (((uint32_t *)sector)[i] != 0)  
             return 1;  
     }  
     return 0;  
 }  
   
 /*  /*
  * Returns true iff the first sector pointed to by 'buf' contains at least   * Returns true iff the first sector pointed to by 'buf' contains at least
  * a non-NUL byte.   * a non-NUL byte.
Line 584  static int is_not_zero(const uint8_t *se Line 530  static int is_not_zero(const uint8_t *se
  */   */
 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;      bool is_zero;
       int i;
   
     if (n <= 0) {      if (n <= 0) {
         *pnum = 0;          *pnum = 0;
         return 0;          return 0;
     }      }
     v = is_not_zero(buf, 512);      is_zero = buffer_is_zero(buf, 512);
     for(i = 1; i < n; i++) {      for(i = 1; i < n; i++) {
         buf += 512;          buf += 512;
         if (v != is_not_zero(buf, 512))          if (is_zero != buffer_is_zero(buf, 512)) {
             break;              break;
           }
     }      }
     *pnum = i;      *pnum = i;
     return v;      return !is_zero;
   }
   
   /*
    * Like is_allocated_sectors, but if the buffer starts with a used sector,
    * up to 'min' consecutive sectors containing zeros are ignored. This avoids
    * breaking up write requests for only small sparse areas.
    */
   static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum,
       int min)
   {
       int ret;
       int num_checked, num_used;
   
       if (n < min) {
           min = n;
       }
   
       ret = is_allocated_sectors(buf, n, pnum);
       if (!ret) {
           return ret;
       }
   
       num_used = *pnum;
       buf += BDRV_SECTOR_SIZE * *pnum;
       n -= *pnum;
       num_checked = num_used;
   
       while (n > 0) {
           ret = is_allocated_sectors(buf, n, pnum);
   
           buf += BDRV_SECTOR_SIZE * *pnum;
           n -= *pnum;
           num_checked += *pnum;
           if (ret) {
               num_used = num_checked;
           } else if (*pnum >= min) {
               break;
           }
       }
   
       *pnum = num_used;
       return 1;
 }  }
   
 /*  /*
Line 635  static int compare_sectors(const uint8_t Line 625  static int compare_sectors(const uint8_t
   
 static int img_convert(int argc, char **argv)  static int img_convert(int argc, char **argv)
 {  {
     int c, ret = 0, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;      int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
     const char *fmt, *out_fmt, *out_baseimg, *out_filename;      int progress = 0, flags;
       const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
     BlockDriver *drv, *proto_drv;      BlockDriver *drv, *proto_drv;
     BlockDriverState **bs = NULL, *out_bs = NULL;      BlockDriverState **bs = NULL, *out_bs = NULL;
     int64_t total_sectors, nb_sectors, sector_num, bs_offset;      int64_t total_sectors, nb_sectors, sector_num, bs_offset;
Line 645  static int img_convert(int argc, char ** Line 636  static int img_convert(int argc, char **
     const uint8_t *buf1;      const uint8_t *buf1;
     BlockDriverInfo bdi;      BlockDriverInfo bdi;
     QEMUOptionParameter *param = NULL, *create_options = NULL;      QEMUOptionParameter *param = NULL, *create_options = NULL;
       QEMUOptionParameter *out_baseimg_param;
     char *options = NULL;      char *options = NULL;
       const char *snapshot_name = NULL;
       float local_progress;
       int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
   
     fmt = NULL;      fmt = NULL;
     out_fmt = "raw";      out_fmt = "raw";
       cache = "unsafe";
     out_baseimg = NULL;      out_baseimg = NULL;
     flags = 0;      compress = 0;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:O:B:hce6o:");          c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
Line 669  static int img_convert(int argc, char ** Line 667  static int img_convert(int argc, char **
             out_baseimg = optarg;              out_baseimg = optarg;
             break;              break;
         case 'c':          case 'c':
             flags |= BLOCK_FLAG_COMPRESS;              compress = 1;
             break;              break;
         case 'e':          case 'e':
             flags |= BLOCK_FLAG_ENCRYPT;              error_report("option -e is deprecated, please use \'-o "
             break;                    "encryption\' instead!");
               return 1;
         case '6':          case '6':
             flags |= BLOCK_FLAG_COMPAT6;              error_report("option -6 is deprecated, please use \'-o "
             break;                    "compat6\' instead!");
               return 1;
         case 'o':          case 'o':
             options = optarg;              options = optarg;
             break;              break;
           case 's':
               snapshot_name = optarg;
               break;
           case 'S':
           {
               int64_t sval;
               char *end;
               sval = strtosz_suffix(optarg, &end, STRTOSZ_DEFSUFFIX_B);
               if (sval < 0 || *end) {
                   error_report("Invalid minimum zero buffer size for sparse output specified");
                   return 1;
               }
   
               min_sparse = sval / BDRV_SECTOR_SIZE;
               break;
           }
           case 'p':
               progress = 1;
               break;
           case 't':
               cache = optarg;
               break;
         }          }
     }      }
   
     bs_n = argc - optind - 1;      bs_n = argc - optind - 1;
     if (bs_n < 1) help();      if (bs_n < 1) {
           help();
       }
   
     out_filename = argv[argc - 1];      out_filename = argv[argc - 1];
   
     if (bs_n > 1 && out_baseimg) {      /* Initialize before goto out */
         error("-B makes no sense when concatenating multiple input images");      qemu_progress_init(progress, 2.0);
         return 1;  
       if (options && !strcmp(options, "?")) {
           ret = print_block_option_help(out_filename, out_fmt);
           goto out;
     }      }
           
     bs = calloc(bs_n, sizeof(BlockDriverState *));      if (bs_n > 1 && out_baseimg) {
     if (!bs) {          error_report("-B makes no sense when concatenating multiple input "
         error("Out of memory");                       "images");
         return 1;          ret = -1;
           goto out;
     }      }
   
       qemu_progress_print(0, 100);
   
       bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
   
     total_sectors = 0;      total_sectors = 0;
     for (bs_i = 0; bs_i < bs_n; bs_i++) {      for (bs_i = 0; bs_i < bs_n; bs_i++) {
         bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);          bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS);
         if (!bs[bs_i]) {          if (!bs[bs_i]) {
             error("Could not open '%s'", argv[optind + bs_i]);              error_report("Could not open '%s'", argv[optind + bs_i]);
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
Line 711  static int img_convert(int argc, char ** Line 743  static int img_convert(int argc, char **
         total_sectors += bs_sectors;          total_sectors += bs_sectors;
     }      }
   
       if (snapshot_name != NULL) {
           if (bs_n > 1) {
               error_report("No support for concatenating multiple snapshot");
               ret = -1;
               goto out;
           }
           if (bdrv_snapshot_load_tmp(bs[0], snapshot_name) < 0) {
               error_report("Failed to load snapshot");
               ret = -1;
               goto out;
           }
       }
   
     /* Find driver and parse its options */      /* 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'", out_fmt);          error_report("Unknown file format '%s'", out_fmt);
         ret = -1;          ret = -1;
         goto out;          goto out;
     }      }
   
     proto_drv = bdrv_find_protocol(out_filename);      proto_drv = bdrv_find_protocol(out_filename);
     if (!proto_drv) {      if (!proto_drv) {
         error("Unknown protocol '%s'", out_filename);          error_report("Unknown protocol '%s'", out_filename);
         ret = -1;          ret = -1;
         goto out;          goto out;
     }      }
Line 730  static int img_convert(int argc, char ** Line 775  static int img_convert(int argc, char **
                                               drv->create_options);                                                drv->create_options);
     create_options = append_option_parameters(create_options,      create_options = append_option_parameters(create_options,
                                               proto_drv->create_options);                                                proto_drv->create_options);
     if (options && !strcmp(options, "?")) {  
         print_option_help(create_options);  
         goto out;  
     }  
   
     if (options) {      if (options) {
         param = parse_option_parameters(options, create_options, param);          param = parse_option_parameters(options, create_options, param);
         if (param == NULL) {          if (param == NULL) {
             error("Invalid options for file format '%s'.", out_fmt);              error_report("Invalid options for file format '%s'.", out_fmt);
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
Line 747  static int img_convert(int argc, char ** Line 788  static int img_convert(int argc, char **
     }      }
   
     set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);      set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
     ret = add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);      ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
     if (ret < 0) {      if (ret < 0) {
         goto out;          goto out;
     }      }
   
       /* Get backing file name if -o backing_file was used */
       out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
       if (out_baseimg_param) {
           out_baseimg = out_baseimg_param->value.s;
       }
   
     /* Check if compression is supported */      /* Check if compression is supported */
     if (flags & BLOCK_FLAG_COMPRESS) {      if (compress) {
         QEMUOptionParameter *encryption =          QEMUOptionParameter *encryption =
             get_option_parameter(param, BLOCK_OPT_ENCRYPT);              get_option_parameter(param, BLOCK_OPT_ENCRYPT);
           QEMUOptionParameter *preallocation =
               get_option_parameter(param, BLOCK_OPT_PREALLOC);
   
         if (!drv->bdrv_write_compressed) {          if (!drv->bdrv_write_compressed) {
             error("Compression not supported for this file format");              error_report("Compression not supported for this file format");
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
   
         if (encryption && encryption->value.n) {          if (encryption && encryption->value.n) {
             error("Compression and encryption not supported at the same time");              error_report("Compression and encryption not supported at "
                            "the same time");
               ret = -1;
               goto out;
           }
   
           if (preallocation && preallocation->value.s
               && strcmp(preallocation->value.s, "off"))
           {
               error_report("Compression and preallocation not supported at "
                            "the same time");
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
Line 774  static int img_convert(int argc, char ** Line 833  static int img_convert(int argc, char **
     ret = bdrv_create(drv, out_filename, param);      ret = bdrv_create(drv, out_filename, param);
     if (ret < 0) {      if (ret < 0) {
         if (ret == -ENOTSUP) {          if (ret == -ENOTSUP) {
             error("Formatting not supported for file format '%s'", out_fmt);              error_report("Formatting not supported for file format '%s'",
                            out_fmt);
         } else if (ret == -EFBIG) {          } else if (ret == -EFBIG) {
             error("The image size is too large for file format '%s'", out_fmt);              error_report("The image size is too large for file format '%s'",
                            out_fmt);
         } else {          } else {
             error("%s: error while converting %s: %s", out_filename, out_fmt, strerror(-ret));              error_report("%s: error while converting %s: %s",
                            out_filename, out_fmt, strerror(-ret));
         }          }
         goto out;          goto out;
     }      }
   
     out_bs = bdrv_new_open(out_filename, out_fmt,      flags = BDRV_O_RDWR;
         BDRV_O_FLAGS | BDRV_O_RDWR | BDRV_O_NO_FLUSH);      ret = bdrv_parse_cache_flags(cache, &flags);
       if (ret < 0) {
           error_report("Invalid cache option: %s", cache);
           return -1;
       }
   
       out_bs = bdrv_new_open(out_filename, out_fmt, flags);
     if (!out_bs) {      if (!out_bs) {
         ret = -1;          ret = -1;
         goto out;          goto out;
Line 793  static int img_convert(int argc, char ** Line 861  static int img_convert(int argc, char **
     bs_i = 0;      bs_i = 0;
     bs_offset = 0;      bs_offset = 0;
     bdrv_get_geometry(bs[0], &bs_sectors);      bdrv_get_geometry(bs[0], &bs_sectors);
     buf = qemu_malloc(IO_BUF_SIZE);      buf = qemu_blockalign(out_bs, IO_BUF_SIZE);
   
     if (flags & BLOCK_FLAG_COMPRESS) {      if (compress) {
         ret = bdrv_get_info(out_bs, &bdi);          ret = bdrv_get_info(out_bs, &bdi);
         if (ret < 0) {          if (ret < 0) {
             error("could not get block driver info");              error_report("could not get block driver info");
             goto out;              goto out;
         }          }
         cluster_size = bdi.cluster_size;          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_report("invalid cluster size");
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
         cluster_sectors = cluster_size >> 9;          cluster_sectors = cluster_size >> 9;
         sector_num = 0;          sector_num = 0;
   
           nb_sectors = total_sectors;
           local_progress = (float)100 /
               (nb_sectors / MIN(nb_sectors, cluster_sectors));
   
         for(;;) {          for(;;) {
             int64_t bs_num;              int64_t bs_num;
             int remainder;              int remainder;
Line 844  static int img_convert(int argc, char ** Line 917  static int img_convert(int argc, char **
   
                 ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);                  ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
                 if (ret < 0) {                  if (ret < 0) {
                     error("error while reading");                      error_report("error while reading sector %" PRId64 ": %s",
                                    bs_num, strerror(-ret));
                     goto out;                      goto out;
                 }                  }
   
Line 855  static int img_convert(int argc, char ** Line 929  static int img_convert(int argc, char **
             }              }
             assert (remainder == 0);              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 (!buffer_is_zero(buf, cluster_size)) {
                 ret = bdrv_write_compressed(out_bs, sector_num, buf,                  ret = bdrv_write_compressed(out_bs, sector_num, buf,
                                             cluster_sectors);                                              cluster_sectors);
                 if (ret != 0) {                  if (ret != 0) {
                     error("error while compressing sector %" PRId64,                      error_report("error while compressing sector %" PRId64
                           sector_num);                                   ": %s", sector_num, strerror(-ret));
                     goto out;                      goto out;
                 }                  }
             }              }
             sector_num += n;              sector_num += n;
               qemu_progress_print(local_progress, 100);
         }          }
         /* signal EOF to align */          /* signal EOF to align */
         bdrv_write_compressed(out_bs, 0, NULL, 0);          bdrv_write_compressed(out_bs, 0, NULL, 0);
Line 874  static int img_convert(int argc, char ** Line 950  static int img_convert(int argc, char **
         int has_zero_init = bdrv_has_zero_init(out_bs);          int has_zero_init = bdrv_has_zero_init(out_bs);
   
         sector_num = 0; // total number of sectors converted so far          sector_num = 0; // total number of sectors converted so far
           nb_sectors = total_sectors - sector_num;
           local_progress = (float)100 /
               (nb_sectors / MIN(nb_sectors, IO_BUF_SIZE / 512));
   
         for(;;) {          for(;;) {
             nb_sectors = total_sectors - sector_num;              nb_sectors = total_sectors - sector_num;
             if (nb_sectors <= 0)              if (nb_sectors <= 0) {
                 break;                  break;
             if (nb_sectors >= (IO_BUF_SIZE / 512))              }
               if (nb_sectors >= (IO_BUF_SIZE / 512)) {
                 n = (IO_BUF_SIZE / 512);                  n = (IO_BUF_SIZE / 512);
             else              } else {
                 n = nb_sectors;                  n = nb_sectors;
               }
   
             while (sector_num - bs_offset >= bs_sectors) {              while (sector_num - bs_offset >= bs_sectors) {
                 bs_i ++;                  bs_i ++;
Line 893  static int img_convert(int argc, char ** Line 975  static int img_convert(int argc, char **
                    sector_num, bs_i, bs_offset, bs_sectors); */                     sector_num, bs_i, bs_offset, bs_sectors); */
             }              }
   
             if (n > bs_offset + bs_sectors - sector_num)              if (n > bs_offset + bs_sectors - sector_num) {
                 n = bs_offset + bs_sectors - sector_num;                  n = bs_offset + bs_sectors - sector_num;
               }
   
             if (has_zero_init) {              if (has_zero_init) {
                 /* If the output image is being created as a copy on write image,                  /* If the output image is being created as a copy on write image,
Line 917  static int img_convert(int argc, char ** Line 1000  static int img_convert(int argc, char **
   
             ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);              ret = bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n);
             if (ret < 0) {              if (ret < 0) {
                 error("error while reading");                  error_report("error while reading sector %" PRId64 ": %s",
                                sector_num - bs_offset, strerror(-ret));
                 goto out;                  goto out;
             }              }
             /* NOTE: at the same time we convert, we do not write zero              /* NOTE: at the same time we convert, we do not write zero
Line 933  static int img_convert(int argc, char ** Line 1017  static int img_convert(int argc, char **
                    sectors that are entirely 0, since whatever data was                     sectors that are entirely 0, since whatever data was
                    already there is garbage, not 0s. */                     already there is garbage, not 0s. */
                 if (!has_zero_init || out_baseimg ||                  if (!has_zero_init || out_baseimg ||
                     is_allocated_sectors(buf1, n, &n1)) {                      is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
                     ret = bdrv_write(out_bs, sector_num, buf1, n1);                      ret = bdrv_write(out_bs, sector_num, buf1, n1);
                     if (ret < 0) {                      if (ret < 0) {
                         error("error while writing");                          error_report("error while writing sector %" PRId64
                                        ": %s", sector_num, strerror(-ret));
                         goto out;                          goto out;
                     }                      }
                 }                  }
Line 944  static int img_convert(int argc, char ** Line 1029  static int img_convert(int argc, char **
                 n -= n1;                  n -= n1;
                 buf1 += n1 * 512;                  buf1 += n1 * 512;
             }              }
               qemu_progress_print(local_progress, 100);
         }          }
     }      }
 out:  out:
       qemu_progress_end();
     free_option_parameters(create_options);      free_option_parameters(create_options);
     free_option_parameters(param);      free_option_parameters(param);
     qemu_free(buf);      qemu_vfree(buf);
     if (out_bs) {      if (out_bs) {
         bdrv_delete(out_bs);          bdrv_delete(out_bs);
     }      }
     for (bs_i = 0; bs_i < bs_n; bs_i++) {      if (bs) {
         if (bs[bs_i]) {          for (bs_i = 0; bs_i < bs_n; bs_i++) {
             bdrv_delete(bs[bs_i]);              if (bs[bs_i]) {
                   bdrv_delete(bs[bs_i]);
               }
         }          }
           g_free(bs);
     }      }
     free(bs);  
     if (ret) {      if (ret) {
         return 1;          return 1;
     }      }
     return 0;      return 0;
 }  }
   
 #ifdef _WIN32  
 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;  
   
     /* 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 st.st_size;  
 }  
 #else  
 static int64_t get_allocated_file_size(const char *filename)  
 {  
     struct stat st;  
     if (stat(filename, &st) < 0)  
         return -1;  
     return (int64_t)st.st_blocks * 512;  
 }  
 #endif  
   
 static void dump_snapshots(BlockDriverState *bs)  static void dump_snapshots(BlockDriverState *bs)
 {  {
Line 1010  static void dump_snapshots(BlockDriverSt Line 1070  static void dump_snapshots(BlockDriverSt
         sn = &sn_tab[i];          sn = &sn_tab[i];
         printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));          printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
     }      }
     qemu_free(sn_tab);      g_free(sn_tab);
 }  }
   
 static int img_info(int argc, char **argv)  static int img_info(int argc, char **argv)
Line 1028  static int img_info(int argc, char **arg Line 1088  static int img_info(int argc, char **arg
     fmt = NULL;      fmt = NULL;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:h");          c = getopt(argc, argv, "f:h");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
Line 1039  static int img_info(int argc, char **arg Line 1101  static int img_info(int argc, char **arg
             break;              break;
         }          }
     }      }
     if (optind >= argc)      if (optind >= argc) {
         help();          help();
       }
     filename = argv[optind++];      filename = argv[optind++];
   
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);      bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING);
Line 1050  static int img_info(int argc, char **arg Line 1113  static int img_info(int argc, char **arg
     bdrv_get_format(bs, fmt_name, sizeof(fmt_name));      bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
     bdrv_get_geometry(bs, &total_sectors);      bdrv_get_geometry(bs, &total_sectors);
     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 = bdrv_get_allocated_file_size(bs);
     if (allocated_size < 0)      if (allocated_size < 0) {
         snprintf(dsize_buf, sizeof(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 (%" PRId64 " bytes)\n"             "virtual size: %s (%" PRId64 " bytes)\n"
Line 1063  static int img_info(int argc, char **arg Line 1127  static int img_info(int argc, char **arg
            filename, fmt_name, size_buf,             filename, fmt_name, size_buf,
            (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 (bdrv_get_info(bs, &bdi) >= 0) {
         if (bdi.cluster_size != 0)          if (bdi.cluster_size != 0) {
             printf("cluster_size: %d\n", bdi.cluster_size);              printf("cluster_size: %d\n", bdi.cluster_size);
           }
           if (bdi.is_dirty) {
               printf("cleanly shut down: no\n");
           }
     }      }
     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));      bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
     if (backing_filename[0] != '\0') {      if (backing_filename[0] != '\0') {
         path_combine(backing_filename2, sizeof(backing_filename2),          bdrv_get_full_backing_filename(bs, backing_filename2,
                      filename, backing_filename);                                         sizeof(backing_filename2));
         printf("backing file: %s (actual path: %s)\n",          printf("backing file: %s", backing_filename);
                backing_filename,          if (strcmp(backing_filename, backing_filename2) != 0) {
                backing_filename2);              printf(" (actual path: %s)", backing_filename2);
           }
           putchar('\n');
     }      }
     dump_snapshots(bs);      dump_snapshots(bs);
     bdrv_delete(bs);      bdrv_delete(bs);
Line 1096  static int img_snapshot(int argc, char * Line 1167  static int img_snapshot(int argc, char *
     int action = 0;      int action = 0;
     qemu_timeval tv;      qemu_timeval tv;
   
     bdrv_oflags = BDRV_O_RDWR;      bdrv_oflags = BDRV_O_FLAGS | BDRV_O_RDWR;
     /* Parse commandline parameters */      /* Parse commandline parameters */
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "la:c:d:h");          c = getopt(argc, argv, "la:c:d:h");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             return 0;              return 0;
Line 1141  static int img_snapshot(int argc, char * Line 1214  static int img_snapshot(int argc, char *
         }          }
     }      }
   
     if (optind >= argc)      if (optind >= argc) {
         help();          help();
       }
     filename = argv[optind++];      filename = argv[optind++];
   
     /* Open the image */      /* Open the image */
Line 1166  static int img_snapshot(int argc, char * Line 1240  static int img_snapshot(int argc, char *
         sn.date_nsec = tv.tv_usec * 1000;          sn.date_nsec = tv.tv_usec * 1000;
   
         ret = bdrv_snapshot_create(bs, &sn);          ret = bdrv_snapshot_create(bs, &sn);
         if (ret)          if (ret) {
             error("Could not create snapshot '%s': %d (%s)",              error_report("Could not create snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));                  snapshot_name, ret, strerror(-ret));
           }
         break;          break;
   
     case SNAPSHOT_APPLY:      case SNAPSHOT_APPLY:
         ret = bdrv_snapshot_goto(bs, snapshot_name);          ret = bdrv_snapshot_goto(bs, snapshot_name);
         if (ret)          if (ret) {
             error("Could not apply snapshot '%s': %d (%s)",              error_report("Could not apply snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));                  snapshot_name, ret, strerror(-ret));
           }
         break;          break;
   
     case SNAPSHOT_DELETE:      case SNAPSHOT_DELETE:
         ret = bdrv_snapshot_delete(bs, snapshot_name);          ret = bdrv_snapshot_delete(bs, snapshot_name);
         if (ret)          if (ret) {
             error("Could not delete snapshot '%s': %d (%s)",              error_report("Could not delete snapshot '%s': %d (%s)",
                 snapshot_name, ret, strerror(-ret));                  snapshot_name, ret, strerror(-ret));
           }
         break;          break;
     }      }
   
Line 1199  static int img_rebase(int argc, char **a Line 1276  static int img_rebase(int argc, char **a
     BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;      BlockDriverState *bs, *bs_old_backing = NULL, *bs_new_backing = NULL;
     BlockDriver *old_backing_drv, *new_backing_drv;      BlockDriver *old_backing_drv, *new_backing_drv;
     char *filename;      char *filename;
     const char *fmt, *out_basefmt, *out_baseimg;      const char *fmt, *cache, *out_basefmt, *out_baseimg;
     int c, flags, ret;      int c, flags, ret;
     int unsafe = 0;      int unsafe = 0;
       int progress = 0;
   
     /* Parse commandline parameters */      /* Parse commandline parameters */
     fmt = NULL;      fmt = NULL;
       cache = BDRV_DEFAULT_CACHE;
     out_baseimg = NULL;      out_baseimg = NULL;
     out_basefmt = NULL;      out_basefmt = NULL;
   
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "uhf:F:b:");          c = getopt(argc, argv, "uhf:F:b:pt:");
         if (c == -1)          if (c == -1) {
             break;              break;
           }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             return 0;              return 0;
Line 1228  static int img_rebase(int argc, char **a Line 1308  static int img_rebase(int argc, char **a
         case 'u':          case 'u':
             unsafe = 1;              unsafe = 1;
             break;              break;
           case 'p':
               progress = 1;
               break;
           case 't':
               cache = optarg;
               break;
         }          }
     }      }
   
     if ((optind >= argc) || !out_baseimg)      if ((optind >= argc) || (!unsafe && !out_baseimg)) {
         help();          help();
       }
     filename = argv[optind++];      filename = argv[optind++];
   
       qemu_progress_init(progress, 2.0);
       qemu_progress_print(0, 100);
   
       flags = BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);
       ret = bdrv_parse_cache_flags(cache, &flags);
       if (ret < 0) {
           error_report("Invalid cache option: %s", cache);
           return -1;
       }
   
     /*      /*
      * Open the images.       * Open the images.
      *       *
      * Ignore the old backing file for unsafe rebase in case we want to correct       * Ignore the old backing file for unsafe rebase in case we want to correct
      * the reference to a renamed or moved backing file.       * the reference to a renamed or moved backing file.
      */       */
     flags = BDRV_O_FLAGS | BDRV_O_RDWR | (unsafe ? BDRV_O_NO_BACKING : 0);  
     bs = bdrv_new_open(filename, fmt, flags);      bs = bdrv_new_open(filename, fmt, flags);
     if (!bs) {      if (!bs) {
         return 1;          return 1;
Line 1254  static int img_rebase(int argc, char **a Line 1350  static int img_rebase(int argc, char **a
     if (!unsafe && bs->backing_format[0] != '\0') {      if (!unsafe && bs->backing_format[0] != '\0') {
         old_backing_drv = bdrv_find_format(bs->backing_format);          old_backing_drv = bdrv_find_format(bs->backing_format);
         if (old_backing_drv == NULL) {          if (old_backing_drv == NULL) {
             error("Invalid format name: '%s'", bs->backing_format);              error_report("Invalid format name: '%s'", bs->backing_format);
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
Line 1263  static int img_rebase(int argc, char **a Line 1359  static int img_rebase(int argc, char **a
     if (out_basefmt != NULL) {      if (out_basefmt != NULL) {
         new_backing_drv = bdrv_find_format(out_basefmt);          new_backing_drv = bdrv_find_format(out_basefmt);
         if (new_backing_drv == NULL) {          if (new_backing_drv == NULL) {
             error("Invalid format name: '%s'", out_basefmt);              error_report("Invalid format name: '%s'", out_basefmt);
             ret = -1;              ret = -1;
             goto out;              goto out;
         }          }
Line 1282  static int img_rebase(int argc, char **a Line 1378  static int img_rebase(int argc, char **a
         ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,          ret = bdrv_open(bs_old_backing, backing_name, BDRV_O_FLAGS,
                         old_backing_drv);                          old_backing_drv);
         if (ret) {          if (ret) {
             error("Could not open old backing file '%s'", backing_name);              error_report("Could not open old backing file '%s'", backing_name);
             goto out;              goto out;
         }          }
   
Line 1290  static int img_rebase(int argc, char **a Line 1386  static int img_rebase(int argc, char **a
         ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,          ret = bdrv_open(bs_new_backing, out_baseimg, BDRV_O_FLAGS,
                         new_backing_drv);                          new_backing_drv);
         if (ret) {          if (ret) {
             error("Could not open new backing file '%s'", out_baseimg);              error_report("Could not open new backing file '%s'", out_baseimg);
             goto out;              goto out;
         }          }
     }      }
Line 1306  static int img_rebase(int argc, char **a Line 1402  static int img_rebase(int argc, char **a
      */       */
     if (!unsafe) {      if (!unsafe) {
         uint64_t num_sectors;          uint64_t num_sectors;
           uint64_t old_backing_num_sectors;
           uint64_t new_backing_num_sectors;
         uint64_t sector;          uint64_t sector;
         int n;          int n;
         uint8_t * buf_old;          uint8_t * buf_old;
         uint8_t * buf_new;          uint8_t * buf_new;
           float local_progress;
   
         buf_old = qemu_malloc(IO_BUF_SIZE);          buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
         buf_new = qemu_malloc(IO_BUF_SIZE);          buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
   
         bdrv_get_geometry(bs, &num_sectors);          bdrv_get_geometry(bs, &num_sectors);
           bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
           bdrv_get_geometry(bs_new_backing, &new_backing_num_sectors);
   
           local_progress = (float)100 /
               (num_sectors / MIN(num_sectors, IO_BUF_SIZE / 512));
         for (sector = 0; sector < num_sectors; sector += n) {          for (sector = 0; sector < num_sectors; sector += n) {
   
             /* How many sectors can we handle with the next read? */              /* How many sectors can we handle with the next read? */
Line 1331  static int img_rebase(int argc, char **a Line 1434  static int img_rebase(int argc, char **a
                 continue;                  continue;
             }              }
   
             /* Read old and new backing file */              /*
             ret = bdrv_read(bs_old_backing, sector, buf_old, n);               * Read old and new backing file and take into consideration that
             if (ret < 0) {               * backing files may be smaller than the COW image.
                 error("error while reading from old backing file");               */
                 goto out;              if (sector >= old_backing_num_sectors) {
                   memset(buf_old, 0, n * BDRV_SECTOR_SIZE);
               } else {
                   if (sector + n > old_backing_num_sectors) {
                       n = old_backing_num_sectors - sector;
                   }
   
                   ret = bdrv_read(bs_old_backing, sector, buf_old, n);
                   if (ret < 0) {
                       error_report("error while reading from old backing file");
                       goto out;
                   }
             }              }
             ret = bdrv_read(bs_new_backing, sector, buf_new, n);  
             if (ret < 0) {              if (sector >= new_backing_num_sectors) {
                 error("error while reading from new backing file");                  memset(buf_new, 0, n * BDRV_SECTOR_SIZE);
                 goto out;              } else {
                   if (sector + n > new_backing_num_sectors) {
                       n = new_backing_num_sectors - sector;
                   }
   
                   ret = bdrv_read(bs_new_backing, sector, buf_new, n);
                   if (ret < 0) {
                       error_report("error while reading from new backing file");
                       goto out;
                   }
             }              }
   
             /* If they differ, we need to write to the COW file */              /* If they differ, we need to write to the COW file */
Line 1355  static int img_rebase(int argc, char **a Line 1478  static int img_rebase(int argc, char **a
                     ret = bdrv_write(bs, sector + written,                      ret = bdrv_write(bs, sector + written,
                         buf_old + written * 512, pnum);                          buf_old + written * 512, pnum);
                     if (ret < 0) {                      if (ret < 0) {
                         error("Error while writing to COW image: %s",                          error_report("Error while writing to COW image: %s",
                             strerror(-ret));                              strerror(-ret));
                         goto out;                          goto out;
                     }                      }
Line 1363  static int img_rebase(int argc, char **a Line 1486  static int img_rebase(int argc, char **a
   
                 written += pnum;                  written += pnum;
             }              }
               qemu_progress_print(local_progress, 100);
         }          }
   
         qemu_free(buf_old);          qemu_vfree(buf_old);
         qemu_free(buf_new);          qemu_vfree(buf_new);
     }      }
   
     /*      /*
Line 1376  static int img_rebase(int argc, char **a Line 1500  static int img_rebase(int argc, char **a
      */       */
     ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);      ret = bdrv_change_backing_file(bs, out_baseimg, out_basefmt);
     if (ret == -ENOSPC) {      if (ret == -ENOSPC) {
         error("Could not change the backing file to '%s': No space left in "          error_report("Could not change the backing file to '%s': No "
             "the file header", out_baseimg);                       "space left in the file header", out_baseimg);
     } else if (ret < 0) {      } else if (ret < 0) {
         error("Could not change the backing file to '%s': %s",          error_report("Could not change the backing file to '%s': %s",
             out_baseimg, strerror(-ret));              out_baseimg, strerror(-ret));
     }      }
   
       qemu_progress_print(100, 0);
     /*      /*
      * TODO At this point it is possible to check if any clusters that are       * TODO At this point it is possible to check if any clusters that are
      * allocated in the COW file are the same in the backing file. If so, they       * allocated in the COW file are the same in the backing file. If so, they
Line 1390  static int img_rebase(int argc, char **a Line 1515  static int img_rebase(int argc, char **a
      * backing file, in case of a crash this would lead to corruption.       * backing file, in case of a crash this would lead to corruption.
      */       */
 out:  out:
       qemu_progress_end();
     /* Cleanup */      /* Cleanup */
     if (!unsafe) {      if (!unsafe) {
         bdrv_delete(bs_old_backing);          if (bs_old_backing != NULL) {
         bdrv_delete(bs_new_backing);              bdrv_delete(bs_old_backing);
           }
           if (bs_new_backing != NULL) {
               bdrv_delete(bs_new_backing);
           }
     }      }
   
     bdrv_delete(bs);      bdrv_delete(bs);
Line 1408  static int img_resize(int argc, char **a Line 1538  static int img_resize(int argc, char **a
     int c, ret, relative;      int c, ret, relative;
     const char *filename, *fmt, *size;      const char *filename, *fmt, *size;
     int64_t n, total_size;      int64_t n, total_size;
     BlockDriverState *bs;      BlockDriverState *bs = NULL;
     QEMUOptionParameter *param;      QEMUOptionParameter *param;
     QEMUOptionParameter resize_options[] = {      QEMUOptionParameter resize_options[] = {
         {          {
Line 1419  static int img_resize(int argc, char **a Line 1549  static int img_resize(int argc, char **a
         { NULL }          { NULL }
     };      };
   
       /* Remove size from argv manually so that negative numbers are not treated
        * as options by getopt. */
       if (argc < 3) {
           help();
           return 1;
       }
   
       size = argv[--argc];
   
       /* Parse getopt arguments */
     fmt = NULL;      fmt = NULL;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:h");          c = getopt(argc, argv, "f:h");
Line 1426  static int img_resize(int argc, char **a Line 1566  static int img_resize(int argc, char **a
             break;              break;
         }          }
         switch(c) {          switch(c) {
           case '?':
         case 'h':          case 'h':
             help();              help();
             break;              break;
Line 1434  static int img_resize(int argc, char **a Line 1575  static int img_resize(int argc, char **a
             break;              break;
         }          }
     }      }
     if (optind + 1 >= argc) {      if (optind >= argc) {
         help();          help();
     }      }
     filename = argv[optind++];      filename = argv[optind++];
     size = argv[optind++];  
   
     /* Choose grow, shrink, or absolute resize mode */      /* Choose grow, shrink, or absolute resize mode */
     switch (size[0]) {      switch (size[0]) {
Line 1459  static int img_resize(int argc, char **a Line 1599  static int img_resize(int argc, char **a
     param = parse_option_parameters("", resize_options, NULL);      param = parse_option_parameters("", resize_options, NULL);
     if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {      if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) {
         /* Error message already printed when size parsing fails */          /* Error message already printed when size parsing fails */
         exit(1);          ret = -1;
           goto out;
     }      }
     n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;      n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n;
     free_option_parameters(param);      free_option_parameters(param);
   
     bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);      bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR);
     if (!bs) {      if (!bs) {
         return 1;          ret = -1;
           goto out;
     }      }
   
     if (relative) {      if (relative) {
Line 1475  static int img_resize(int argc, char **a Line 1617  static int img_resize(int argc, char **a
         total_size = n;          total_size = n;
     }      }
     if (total_size <= 0) {      if (total_size <= 0) {
         error("New image size must be positive");          error_report("New image size must be positive");
         ret = -1;          ret = -1;
         goto out;          goto out;
     }      }
Line 1486  static int img_resize(int argc, char **a Line 1628  static int img_resize(int argc, char **a
         printf("Image resized.\n");          printf("Image resized.\n");
         break;          break;
     case -ENOTSUP:      case -ENOTSUP:
         error("This image format does not support resize");          error_report("This image does not support resize");
         break;          break;
     case -EACCES:      case -EACCES:
         error("Image is read-only");          error_report("Image is read-only");
         break;          break;
     default:      default:
         error("Error resizing image (%d)", -ret);          error_report("Error resizing image (%d)", -ret);
         break;          break;
     }      }
 out:  out:
     bdrv_delete(bs);      if (bs) {
           bdrv_delete(bs);
       }
     if (ret) {      if (ret) {
         return 1;          return 1;
     }      }
Line 1517  int main(int argc, char **argv) Line 1661  int main(int argc, char **argv)
     const img_cmd_t *cmd;      const img_cmd_t *cmd;
     const char *cmdname;      const char *cmdname;
   
       error_set_progname(argv[0]);
   
     bdrv_init();      bdrv_init();
     if (argc < 2)      if (argc < 2)
         help();          help();
     cmdname = argv[1];      cmdname = argv[1];
     argc--; argv++;      argc--; argv++;
   
       qemu_init_main_loop();
   
     /* find the command */      /* find the command */
     for(cmd = img_cmds; cmd->name != NULL; cmd++) {      for(cmd = img_cmds; cmd->name != NULL; cmd++) {
         if (!strcmp(cmdname, cmd->name)) {          if (!strcmp(cmdname, cmd->name)) {

Removed from v.1.1.1.11  
changed lines
  Added in v.1.1.1.15


unix.superglobalmegacorp.com