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(); |
} |
} |