Diff for /qemu/qemu-img.c between versions 1.1.1.4 and 1.1.1.5

version 1.1.1.4, 2018/04/24 16:47:25 version 1.1.1.5, 2018/04/24 16:50:44
Line 22 Line 22
  * THE SOFTWARE.   * THE SOFTWARE.
  */   */
 #include "qemu-common.h"  #include "qemu-common.h"
   #include "osdep.h"
 #include "block_int.h"  #include "block_int.h"
 #include <assert.h>  #include <assert.h>
   
Line 30 Line 31
 #include <windows.h>  #include <windows.h>
 #endif  #endif
   
 void *get_mmap_addr(unsigned long size)  /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
 {  #define BRDV_O_FLAGS BDRV_O_CACHE_WB
     return NULL;  
 }  
   
 void qemu_free(void *ptr)  
 {  
     free(ptr);  
 }  
   
 void *qemu_malloc(size_t size)  static void QEMU_NORETURN error(const char *fmt, ...)
 {  
     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;  
 }  
   
 static void __attribute__((noreturn)) error(const char *fmt, ...)  
 {  {
     va_list ap;      va_list ap;
     va_start(ap, fmt);      va_start(ap, fmt);
Line 81  static void format_print(void *opaque, c Line 50  static void format_print(void *opaque, c
     printf(" %s", name);      printf(" %s", name);
 }  }
   
   /* Please keep in synch with qemu-img.texi */
 static void help(void)  static void help(void)
 {  {
     printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"      printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
Line 90  static void help(void) Line 60  static void help(void)
            "Command syntax:\n"             "Command syntax:\n"
            "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"             "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
            "  commit [-f fmt] filename\n"             "  commit [-f fmt] filename\n"
            "  convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n"             "  convert [-c] [-e] [-6] [-f fmt] [-O output_fmt] [-B output_base_image] filename [filename2 [...]] output_filename\n"
            "  info [-f fmt] filename\n"             "  info [-f fmt] filename\n"
              "  snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename\n"
            "\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"             "  '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"             "    write image; the copy on write image only stores the modified data\n"
              "  'output_base_image' forces the output image to be created as a copy on write\n"
              "    image of the specified base image; 'output_base_image' should have the same\n"
              "    content as the input's base image, however the path, image format, etc may\n"
              "    differ\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 kilobytes. Optional suffixes\n"
            "    and 'G' (gigabyte) are supported\n"             "    'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are"
              "    supported any @code{k} or @code{K} 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"
            "  '-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"             "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
            "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"             "  '-6' indicates that the target image must use compatibility level 6 (vmdk 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);
Line 217  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 348  static int img_commit(int argc, char **a Line 332  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 385  static int is_not_zero(const uint8_t *se Line 369  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 408  static int is_allocated_sectors(const ui Line 399  static int is_allocated_sectors(const ui
 static int img_convert(int argc, char **argv)  static int img_convert(int argc, char **argv)
 {  {
     int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;      int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
     const char *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, bs_offset;      int64_t total_sectors, nb_sectors, sector_num, bs_offset;
Line 419  static int img_convert(int argc, char ** Line 410  static int img_convert(int argc, char **
   
     fmt = NULL;      fmt = NULL;
     out_fmt = "raw";      out_fmt = "raw";
       out_baseimg = NULL;
     flags = 0;      flags = 0;
     for(;;) {      for(;;) {
         c = getopt(argc, argv, "f:O:hce6");          c = getopt(argc, argv, "f:O:B:hce6");
         if (c == -1)          if (c == -1)
             break;              break;
         switch(c) {          switch(c) {
Line 434  static int img_convert(int argc, char ** Line 426  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':
             flags |= BLOCK_FLAG_COMPRESS;              flags |= BLOCK_FLAG_COMPRESS;
             break;              break;
Line 450  static int img_convert(int argc, char ** Line 445  static int img_convert(int argc, char **
     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)
           error("-B makes no sense when concatenating multiple input images");
                   
     bs = calloc(bs_n, sizeof(BlockDriverState *));      bs = calloc(bs_n, sizeof(BlockDriverState *));
     if (!bs)      if (!bs)
Line 476  static int img_convert(int argc, char ** Line 474  static int img_convert(int argc, char **
     if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)      if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
         error("Compression and encryption not supported at the same time");          error("Compression and encryption not supported at the same time");
   
     ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags);      ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
     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'", fmt);
Line 555  static int img_convert(int argc, char ** Line 553  static int img_convert(int argc, char **
         /* signal EOF to align */          /* signal EOF to align */
         bdrv_write_compressed(out_bs, 0, NULL, 0);          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 578  static int img_convert(int argc, char ** Line 576  static int img_convert(int argc, char **
             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 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;
               }
   
             if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)               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
Line 585  static int img_convert(int argc, char ** Line 597  static int img_convert(int argc, char **
                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,
                      copy all sectors even the ones containing only NUL bytes,
                      because they may differ from the sectors in the base image. */
                   if (out_baseimg || is_allocated_sectors(buf1, n, &n1)) {
                     if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)                      if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
                         error("error while writing");                          error("error while writing");
                 }                  }
Line 691  static int img_info(int argc, char **arg Line 706  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 699  static int img_info(int argc, char **arg Line 714  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);
Line 715  static int img_info(int argc, char **arg Line 730  static int img_info(int argc, char **arg
     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.highest_alloc)
               printf("highest_alloc: %" PRId64 "\n", bdi.highest_alloc);
           if (bdi.num_free_bytes)
               printf("num_free_bytes: %" PRId64 "\n", bdi.num_free_bytes);
     }      }
     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') {
Line 729  static int img_info(int argc, char **arg Line 748  static int img_info(int argc, char **arg
     return 0;      return 0;
 }  }
   
   #define SNAPSHOT_LIST   1
   #define SNAPSHOT_CREATE 2
   #define SNAPSHOT_APPLY  3
   #define SNAPSHOT_DELETE 4
   
   static void 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;
           case 'l':
               if (action) {
                   help();
                   return;
               }
               action = SNAPSHOT_LIST;
               break;
           case 'a':
               if (action) {
                   help();
                   return;
               }
               action = SNAPSHOT_APPLY;
               snapshot_name = optarg;
               break;
           case 'c':
               if (action) {
                   help();
                   return;
               }
               action = SNAPSHOT_CREATE;
               snapshot_name = optarg;
               break;
           case 'd':
               if (action) {
                   help();
                   return;
               }
               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);
   }
   
 int main(int argc, char **argv)  int main(int argc, char **argv)
 {  {
     const char *cmd;      const char *cmd;
Line 737  int main(int argc, char **argv) Line 865  int main(int argc, char **argv)
     if (argc < 2)      if (argc < 2)
         help();          help();
     cmd = argv[1];      cmd = argv[1];
     optind++;      argc--; argv++;
     if (!strcmp(cmd, "create")) {      if (!strcmp(cmd, "create")) {
         img_create(argc, argv);          img_create(argc, argv);
     } else if (!strcmp(cmd, "commit")) {      } else if (!strcmp(cmd, "commit")) {
Line 746  int main(int argc, char **argv) Line 874  int main(int argc, char **argv)
         img_convert(argc, argv);          img_convert(argc, argv);
     } else if (!strcmp(cmd, "info")) {      } else if (!strcmp(cmd, "info")) {
         img_info(argc, argv);          img_info(argc, argv);
       } else if (!strcmp(cmd, "snapshot")) {
           img_snapshot(argc, argv);
     } else {      } else {
         help();          help();
     }      }

Removed from v.1.1.1.4  
changed lines
  Added in v.1.1.1.5


unix.superglobalmegacorp.com