pci: add helper functions to check ranges overlap.
[qemu/aliguori-queue.git] / qemu-img.c
blob00fcade83fe48c8780760524575370c9caad7699
1 /*
2 * QEMU disk image utility
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu-common.h"
25 #include "qemu-option.h"
26 #include "osdep.h"
27 #include "block_int.h"
28 #include <stdio.h>
30 #ifdef _WIN32
31 #include <windows.h>
32 #endif
34 typedef struct img_cmd_t {
35 const char *name;
36 int (*handler)(int argc, char **argv);
37 } img_cmd_t;
39 /* Default to cache=writeback as data integrity is not important for qemu-tcg. */
40 #define BRDV_O_FLAGS BDRV_O_CACHE_WB
42 static void QEMU_NORETURN error(const char *fmt, ...)
44 va_list ap;
45 va_start(ap, fmt);
46 fprintf(stderr, "qemu-img: ");
47 vfprintf(stderr, fmt, ap);
48 fprintf(stderr, "\n");
49 exit(1);
50 va_end(ap);
53 static void format_print(void *opaque, const char *name)
55 printf(" %s", name);
58 /* Please keep in synch with qemu-img.texi */
59 static void help(void)
61 printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2008 Fabrice Bellard\n"
62 "usage: qemu-img command [command options]\n"
63 "QEMU disk image utility\n"
64 "\n"
65 "Command syntax:\n"
66 #define DEF(option, callback, arg_string) \
67 " " arg_string "\n"
68 #include "qemu-img-cmds.h"
69 #undef DEF
70 #undef GEN_DOCS
71 "\n"
72 "Command parameters:\n"
73 " 'filename' is a disk image filename\n"
74 " 'base_image' is the read-only disk image which is used as base for a copy on\n"
75 " write image; the copy on write image only stores the modified data\n"
76 " 'output_base_image' forces the output image to be created as a copy on write\n"
77 " image of the specified base image; 'output_base_image' should have the same\n"
78 " content as the input's base image, however the path, image format, etc may\n"
79 " differ\n"
80 " 'fmt' is the disk image format. It is guessed automatically in most cases\n"
81 " 'size' is the disk image size in kilobytes. Optional suffixes\n"
82 " 'M' (megabyte, 1024 * 1024) and 'G' (gigabyte, 1024 * 1024 * 1024) are\n"
83 " supported any 'k' or 'K' is ignored\n"
84 " 'output_filename' is the destination disk image filename\n"
85 " 'output_fmt' is the destination format\n"
86 " 'options' is a comma separated list of format specific options in a\n"
87 " name=value format. Use -o ? for an overview of the options supported by the\n"
88 " used format\n"
89 " '-c' indicates that target image must be compressed (qcow format only)\n"
90 " '-h' with or without a command shows this help and lists the supported formats\n"
91 "\n"
92 "Parameters to snapshot subcommand:\n"
93 " 'snapshot' is the name of the snapshot to create, apply or delete\n"
94 " '-a' applies a snapshot (revert disk to saved state)\n"
95 " '-c' creates a snapshot\n"
96 " '-d' deletes a snapshot\n"
97 " '-l' lists all snapshots in the given image\n"
99 printf("\nSupported formats:");
100 bdrv_iterate_format(format_print, NULL);
101 printf("\n");
102 exit(1);
105 #if defined(WIN32)
106 /* XXX: put correct support for win32 */
107 static int read_password(char *buf, int buf_size)
109 int c, i;
110 printf("Password: ");
111 fflush(stdout);
112 i = 0;
113 for(;;) {
114 c = getchar();
115 if (c == '\n')
116 break;
117 if (i < (buf_size - 1))
118 buf[i++] = c;
120 buf[i] = '\0';
121 return 0;
124 #else
126 #include <termios.h>
128 static struct termios oldtty;
130 static void term_exit(void)
132 tcsetattr (0, TCSANOW, &oldtty);
135 static void term_init(void)
137 struct termios tty;
139 tcgetattr (0, &tty);
140 oldtty = tty;
142 tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
143 |INLCR|IGNCR|ICRNL|IXON);
144 tty.c_oflag |= OPOST;
145 tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
146 tty.c_cflag &= ~(CSIZE|PARENB);
147 tty.c_cflag |= CS8;
148 tty.c_cc[VMIN] = 1;
149 tty.c_cc[VTIME] = 0;
151 tcsetattr (0, TCSANOW, &tty);
153 atexit(term_exit);
156 static int read_password(char *buf, int buf_size)
158 uint8_t ch;
159 int i, ret;
161 printf("password: ");
162 fflush(stdout);
163 term_init();
164 i = 0;
165 for(;;) {
166 ret = read(0, &ch, 1);
167 if (ret == -1) {
168 if (errno == EAGAIN || errno == EINTR) {
169 continue;
170 } else {
171 ret = -1;
172 break;
174 } else if (ret == 0) {
175 ret = -1;
176 break;
177 } else {
178 if (ch == '\r') {
179 ret = 0;
180 break;
182 if (i < (buf_size - 1))
183 buf[i++] = ch;
186 term_exit();
187 buf[i] = '\0';
188 printf("\n");
189 return ret;
191 #endif
193 static BlockDriverState *bdrv_new_open(const char *filename,
194 const char *fmt)
196 BlockDriverState *bs;
197 BlockDriver *drv;
198 char password[256];
200 bs = bdrv_new("");
201 if (!bs)
202 error("Not enough memory");
203 if (fmt) {
204 drv = bdrv_find_format(fmt);
205 if (!drv)
206 error("Unknown file format '%s'", fmt);
207 } else {
208 drv = NULL;
210 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
211 error("Could not open '%s'", filename);
213 if (bdrv_is_encrypted(bs)) {
214 printf("Disk image '%s' is encrypted.\n", filename);
215 if (read_password(password, sizeof(password)) < 0)
216 error("No password given");
217 if (bdrv_set_key(bs, password) < 0)
218 error("invalid password");
220 return bs;
223 static void add_old_style_options(const char *fmt, QEMUOptionParameter *list,
224 int flags, const char *base_filename, const char *base_fmt)
226 if (flags & BLOCK_FLAG_ENCRYPT) {
227 if (set_option_parameter(list, BLOCK_OPT_ENCRYPT, "on")) {
228 error("Encryption not supported for file format '%s'", fmt);
231 if (flags & BLOCK_FLAG_COMPAT6) {
232 if (set_option_parameter(list, BLOCK_OPT_COMPAT6, "on")) {
233 error("VMDK version 6 not supported for file format '%s'", fmt);
237 if (base_filename) {
238 if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
239 error("Backing file not supported for file format '%s'", fmt);
242 if (base_fmt) {
243 if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
244 error("Backing file format not supported for file format '%s'", fmt);
249 static int img_create(int argc, char **argv)
251 int c, ret, flags;
252 const char *fmt = "raw";
253 const char *base_fmt = NULL;
254 const char *filename;
255 const char *base_filename = NULL;
256 BlockDriver *drv;
257 QEMUOptionParameter *param = NULL;
258 char *options = NULL;
260 flags = 0;
261 for(;;) {
262 c = getopt(argc, argv, "F:b:f:he6o:");
263 if (c == -1)
264 break;
265 switch(c) {
266 case 'h':
267 help();
268 break;
269 case 'F':
270 base_fmt = optarg;
271 break;
272 case 'b':
273 base_filename = optarg;
274 break;
275 case 'f':
276 fmt = optarg;
277 break;
278 case 'e':
279 flags |= BLOCK_FLAG_ENCRYPT;
280 break;
281 case '6':
282 flags |= BLOCK_FLAG_COMPAT6;
283 break;
284 case 'o':
285 options = optarg;
286 break;
290 /* Find driver and parse its options */
291 drv = bdrv_find_format(fmt);
292 if (!drv)
293 error("Unknown file format '%s'", fmt);
295 if (options && !strcmp(options, "?")) {
296 print_option_help(drv->create_options);
297 return 0;
300 /* Create parameter list with default values */
301 param = parse_option_parameters("", drv->create_options, param);
302 set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
304 /* Parse -o options */
305 if (options) {
306 param = parse_option_parameters(options, drv->create_options, param);
307 if (param == NULL) {
308 error("Invalid options for file format '%s'.", fmt);
312 /* Get the filename */
313 if (optind >= argc)
314 help();
315 filename = argv[optind++];
317 /* Add size to parameters */
318 if (optind < argc) {
319 set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
322 /* Add old-style options to parameters */
323 add_old_style_options(fmt, param, flags, base_filename, base_fmt);
325 // The size for the image must always be specified, with one exception:
326 // If we are using a backing file, we can obtain the size from there
327 if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == -1) {
329 QEMUOptionParameter *backing_file =
330 get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
331 QEMUOptionParameter *backing_fmt =
332 get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
334 if (backing_file && backing_file->value.s) {
335 BlockDriverState *bs;
336 uint64_t size;
337 const char *fmt = NULL;
338 char buf[32];
340 if (backing_fmt && backing_fmt->value.s) {
341 if (bdrv_find_format(backing_fmt->value.s)) {
342 fmt = backing_fmt->value.s;
343 } else {
344 error("Unknown backing file format '%s'",
345 backing_fmt->value.s);
349 bs = bdrv_new_open(backing_file->value.s, fmt);
350 bdrv_get_geometry(bs, &size);
351 size *= 512;
352 bdrv_delete(bs);
354 snprintf(buf, sizeof(buf), "%" PRId64, size);
355 set_option_parameter(param, BLOCK_OPT_SIZE, buf);
356 } else {
357 error("Image creation needs a size parameter");
361 printf("Formatting '%s', fmt=%s ", filename, fmt);
362 print_option_parameters(param);
363 puts("");
365 ret = bdrv_create(drv, filename, param);
366 free_option_parameters(param);
368 if (ret < 0) {
369 if (ret == -ENOTSUP) {
370 error("Formatting or formatting option not supported for file format '%s'", fmt);
371 } else if (ret == -EFBIG) {
372 error("The image size is too large for file format '%s'", fmt);
373 } else {
374 error("Error while formatting");
377 return 0;
380 static int img_check(int argc, char **argv)
382 int c, ret;
383 const char *filename, *fmt;
384 BlockDriver *drv;
385 BlockDriverState *bs;
387 fmt = NULL;
388 for(;;) {
389 c = getopt(argc, argv, "f:h");
390 if (c == -1)
391 break;
392 switch(c) {
393 case 'h':
394 help();
395 break;
396 case 'f':
397 fmt = optarg;
398 break;
401 if (optind >= argc)
402 help();
403 filename = argv[optind++];
405 bs = bdrv_new("");
406 if (!bs)
407 error("Not enough memory");
408 if (fmt) {
409 drv = bdrv_find_format(fmt);
410 if (!drv)
411 error("Unknown file format '%s'", fmt);
412 } else {
413 drv = NULL;
415 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
416 error("Could not open '%s'", filename);
418 ret = bdrv_check(bs);
419 switch(ret) {
420 case 0:
421 printf("No errors were found on the image.\n");
422 break;
423 case -ENOTSUP:
424 error("This image format does not support checks");
425 break;
426 default:
427 if (ret < 0) {
428 error("An error occurred during the check");
429 } else {
430 printf("%d errors were found on the image.\n", ret);
432 break;
435 bdrv_delete(bs);
436 return 0;
439 static int img_commit(int argc, char **argv)
441 int c, ret;
442 const char *filename, *fmt;
443 BlockDriver *drv;
444 BlockDriverState *bs;
446 fmt = NULL;
447 for(;;) {
448 c = getopt(argc, argv, "f:h");
449 if (c == -1)
450 break;
451 switch(c) {
452 case 'h':
453 help();
454 break;
455 case 'f':
456 fmt = optarg;
457 break;
460 if (optind >= argc)
461 help();
462 filename = argv[optind++];
464 bs = bdrv_new("");
465 if (!bs)
466 error("Not enough memory");
467 if (fmt) {
468 drv = bdrv_find_format(fmt);
469 if (!drv)
470 error("Unknown file format '%s'", fmt);
471 } else {
472 drv = NULL;
474 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
475 error("Could not open '%s'", filename);
477 ret = bdrv_commit(bs);
478 switch(ret) {
479 case 0:
480 printf("Image committed.\n");
481 break;
482 case -ENOENT:
483 error("No disk inserted");
484 break;
485 case -EACCES:
486 error("Image is read-only");
487 break;
488 case -ENOTSUP:
489 error("Image is already committed");
490 break;
491 default:
492 error("Error while committing image");
493 break;
496 bdrv_delete(bs);
497 return 0;
500 static int is_not_zero(const uint8_t *sector, int len)
502 int i;
503 len >>= 2;
504 for(i = 0;i < len; i++) {
505 if (((uint32_t *)sector)[i] != 0)
506 return 1;
508 return 0;
512 * Returns true iff the first sector pointed to by 'buf' contains at least
513 * a non-NUL byte.
515 * 'pnum' is set to the number of sectors (including and immediately following
516 * the first one) that are known to be in the same allocated/unallocated state.
518 static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
520 int v, i;
522 if (n <= 0) {
523 *pnum = 0;
524 return 0;
526 v = is_not_zero(buf, 512);
527 for(i = 1; i < n; i++) {
528 buf += 512;
529 if (v != is_not_zero(buf, 512))
530 break;
532 *pnum = i;
533 return v;
536 #define IO_BUF_SIZE (2 * 1024 * 1024)
538 static int img_convert(int argc, char **argv)
540 int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
541 const char *fmt, *out_fmt, *out_baseimg, *out_filename;
542 BlockDriver *drv;
543 BlockDriverState **bs, *out_bs;
544 int64_t total_sectors, nb_sectors, sector_num, bs_offset;
545 uint64_t bs_sectors;
546 uint8_t buf[IO_BUF_SIZE];
547 const uint8_t *buf1;
548 BlockDriverInfo bdi;
549 QEMUOptionParameter *param = NULL;
550 char *options = NULL;
552 fmt = NULL;
553 out_fmt = "raw";
554 out_baseimg = NULL;
555 flags = 0;
556 for(;;) {
557 c = getopt(argc, argv, "f:O:B:hce6o:");
558 if (c == -1)
559 break;
560 switch(c) {
561 case 'h':
562 help();
563 break;
564 case 'f':
565 fmt = optarg;
566 break;
567 case 'O':
568 out_fmt = optarg;
569 break;
570 case 'B':
571 out_baseimg = optarg;
572 break;
573 case 'c':
574 flags |= BLOCK_FLAG_COMPRESS;
575 break;
576 case 'e':
577 flags |= BLOCK_FLAG_ENCRYPT;
578 break;
579 case '6':
580 flags |= BLOCK_FLAG_COMPAT6;
581 break;
582 case 'o':
583 options = optarg;
584 break;
588 bs_n = argc - optind - 1;
589 if (bs_n < 1) help();
591 out_filename = argv[argc - 1];
593 if (bs_n > 1 && out_baseimg)
594 error("-B makes no sense when concatenating multiple input images");
596 bs = calloc(bs_n, sizeof(BlockDriverState *));
597 if (!bs)
598 error("Out of memory");
600 total_sectors = 0;
601 for (bs_i = 0; bs_i < bs_n; bs_i++) {
602 bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
603 if (!bs[bs_i])
604 error("Could not open '%s'", argv[optind + bs_i]);
605 bdrv_get_geometry(bs[bs_i], &bs_sectors);
606 total_sectors += bs_sectors;
609 /* Find driver and parse its options */
610 drv = bdrv_find_format(out_fmt);
611 if (!drv)
612 error("Unknown file format '%s'", out_fmt);
614 if (options && !strcmp(options, "?")) {
615 print_option_help(drv->create_options);
616 return 0;
619 if (options) {
620 param = parse_option_parameters(options, drv->create_options, param);
621 if (param == NULL) {
622 error("Invalid options for file format '%s'.", out_fmt);
624 } else {
625 param = parse_option_parameters("", drv->create_options, param);
628 set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
629 add_old_style_options(out_fmt, param, flags, out_baseimg, NULL);
631 /* Check if compression is supported */
632 if (flags & BLOCK_FLAG_COMPRESS) {
633 QEMUOptionParameter *encryption =
634 get_option_parameter(param, BLOCK_OPT_ENCRYPT);
636 if (!drv->bdrv_write_compressed) {
637 error("Compression not supported for this file format");
640 if (encryption && encryption->value.n) {
641 error("Compression and encryption not supported at the same time");
645 /* Create the new image */
646 ret = bdrv_create(drv, out_filename, param);
647 free_option_parameters(param);
649 if (ret < 0) {
650 if (ret == -ENOTSUP) {
651 error("Formatting not supported for file format '%s'", out_fmt);
652 } else if (ret == -EFBIG) {
653 error("The image size is too large for file format '%s'", out_fmt);
654 } else {
655 error("Error while formatting '%s'", out_filename);
659 out_bs = bdrv_new_open(out_filename, out_fmt);
661 bs_i = 0;
662 bs_offset = 0;
663 bdrv_get_geometry(bs[0], &bs_sectors);
665 if (flags & BLOCK_FLAG_COMPRESS) {
666 if (bdrv_get_info(out_bs, &bdi) < 0)
667 error("could not get block driver info");
668 cluster_size = bdi.cluster_size;
669 if (cluster_size <= 0 || cluster_size > IO_BUF_SIZE)
670 error("invalid cluster size");
671 cluster_sectors = cluster_size >> 9;
672 sector_num = 0;
673 for(;;) {
674 int64_t bs_num;
675 int remainder;
676 uint8_t *buf2;
678 nb_sectors = total_sectors - sector_num;
679 if (nb_sectors <= 0)
680 break;
681 if (nb_sectors >= cluster_sectors)
682 n = cluster_sectors;
683 else
684 n = nb_sectors;
686 bs_num = sector_num - bs_offset;
687 assert (bs_num >= 0);
688 remainder = n;
689 buf2 = buf;
690 while (remainder > 0) {
691 int nlow;
692 while (bs_num == bs_sectors) {
693 bs_i++;
694 assert (bs_i < bs_n);
695 bs_offset += bs_sectors;
696 bdrv_get_geometry(bs[bs_i], &bs_sectors);
697 bs_num = 0;
698 /* printf("changing part: sector_num=%lld, "
699 "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
700 sector_num, bs_i, bs_offset, bs_sectors); */
702 assert (bs_num < bs_sectors);
704 nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
706 if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
707 error("error while reading");
709 buf2 += nlow * 512;
710 bs_num += nlow;
712 remainder -= nlow;
714 assert (remainder == 0);
716 if (n < cluster_sectors)
717 memset(buf + n * 512, 0, cluster_size - n * 512);
718 if (is_not_zero(buf, cluster_size)) {
719 if (bdrv_write_compressed(out_bs, sector_num, buf,
720 cluster_sectors) != 0)
721 error("error while compressing sector %" PRId64,
722 sector_num);
724 sector_num += n;
726 /* signal EOF to align */
727 bdrv_write_compressed(out_bs, 0, NULL, 0);
728 } else {
729 sector_num = 0; // total number of sectors converted so far
730 for(;;) {
731 nb_sectors = total_sectors - sector_num;
732 if (nb_sectors <= 0)
733 break;
734 if (nb_sectors >= (IO_BUF_SIZE / 512))
735 n = (IO_BUF_SIZE / 512);
736 else
737 n = nb_sectors;
739 while (sector_num - bs_offset >= bs_sectors) {
740 bs_i ++;
741 assert (bs_i < bs_n);
742 bs_offset += bs_sectors;
743 bdrv_get_geometry(bs[bs_i], &bs_sectors);
744 /* printf("changing part: sector_num=%lld, bs_i=%d, "
745 "bs_offset=%lld, bs_sectors=%lld\n",
746 sector_num, bs_i, bs_offset, bs_sectors); */
749 if (n > bs_offset + bs_sectors - sector_num)
750 n = bs_offset + bs_sectors - sector_num;
752 if (strcmp(drv->format_name, "host_device")) {
753 /* If the output image is being created as a copy on write image,
754 assume that sectors which are unallocated in the input image
755 are present in both the output's and input's base images (no
756 need to copy them). */
757 if (out_baseimg) {
758 if (!bdrv_is_allocated(bs[bs_i], sector_num - bs_offset,
759 n, &n1)) {
760 sector_num += n1;
761 continue;
763 /* The next 'n1' sectors are allocated in the input image. Copy
764 only those as they may be followed by unallocated sectors. */
765 n = n1;
767 } else {
768 n1 = n;
771 if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
772 error("error while reading");
773 /* NOTE: at the same time we convert, we do not write zero
774 sectors to have a chance to compress the image. Ideally, we
775 should add a specific call to have the info to go faster */
776 buf1 = buf;
777 while (n > 0) {
778 /* If the output image is being created as a copy on write image,
779 copy all sectors even the ones containing only NUL bytes,
780 because they may differ from the sectors in the base image.
782 If the output is to a host device, we also write out
783 sectors that are entirely 0, since whatever data was
784 already there is garbage, not 0s. */
785 if (strcmp(drv->format_name, "host_device") == 0 || out_baseimg ||
786 is_allocated_sectors(buf1, n, &n1)) {
787 if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
788 error("error while writing");
790 sector_num += n1;
791 n -= n1;
792 buf1 += n1 * 512;
796 bdrv_delete(out_bs);
797 for (bs_i = 0; bs_i < bs_n; bs_i++)
798 bdrv_delete(bs[bs_i]);
799 free(bs);
800 return 0;
803 #ifdef _WIN32
804 static int64_t get_allocated_file_size(const char *filename)
806 typedef DWORD (WINAPI * get_compressed_t)(const char *filename, DWORD *high);
807 get_compressed_t get_compressed;
808 struct _stati64 st;
810 /* WinNT support GetCompressedFileSize to determine allocate size */
811 get_compressed = (get_compressed_t) GetProcAddress(GetModuleHandle("kernel32"), "GetCompressedFileSizeA");
812 if (get_compressed) {
813 DWORD high, low;
814 low = get_compressed(filename, &high);
815 if (low != 0xFFFFFFFFlu || GetLastError() == NO_ERROR)
816 return (((int64_t) high) << 32) + low;
819 if (_stati64(filename, &st) < 0)
820 return -1;
821 return st.st_size;
823 #else
824 static int64_t get_allocated_file_size(const char *filename)
826 struct stat st;
827 if (stat(filename, &st) < 0)
828 return -1;
829 return (int64_t)st.st_blocks * 512;
831 #endif
833 static void dump_snapshots(BlockDriverState *bs)
835 QEMUSnapshotInfo *sn_tab, *sn;
836 int nb_sns, i;
837 char buf[256];
839 nb_sns = bdrv_snapshot_list(bs, &sn_tab);
840 if (nb_sns <= 0)
841 return;
842 printf("Snapshot list:\n");
843 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));
844 for(i = 0; i < nb_sns; i++) {
845 sn = &sn_tab[i];
846 printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));
848 qemu_free(sn_tab);
851 static int img_info(int argc, char **argv)
853 int c;
854 const char *filename, *fmt;
855 BlockDriver *drv;
856 BlockDriverState *bs;
857 char fmt_name[128], size_buf[128], dsize_buf[128];
858 uint64_t total_sectors;
859 int64_t allocated_size;
860 char backing_filename[1024];
861 char backing_filename2[1024];
862 BlockDriverInfo bdi;
864 fmt = NULL;
865 for(;;) {
866 c = getopt(argc, argv, "f:h");
867 if (c == -1)
868 break;
869 switch(c) {
870 case 'h':
871 help();
872 break;
873 case 'f':
874 fmt = optarg;
875 break;
878 if (optind >= argc)
879 help();
880 filename = argv[optind++];
882 bs = bdrv_new("");
883 if (!bs)
884 error("Not enough memory");
885 if (fmt) {
886 drv = bdrv_find_format(fmt);
887 if (!drv)
888 error("Unknown file format '%s'", fmt);
889 } else {
890 drv = NULL;
892 if (bdrv_open2(bs, filename, BRDV_O_FLAGS, drv) < 0) {
893 error("Could not open '%s'", filename);
895 bdrv_get_format(bs, fmt_name, sizeof(fmt_name));
896 bdrv_get_geometry(bs, &total_sectors);
897 get_human_readable_size(size_buf, sizeof(size_buf), total_sectors * 512);
898 allocated_size = get_allocated_file_size(filename);
899 if (allocated_size < 0)
900 snprintf(dsize_buf, sizeof(dsize_buf), "unavailable");
901 else
902 get_human_readable_size(dsize_buf, sizeof(dsize_buf),
903 allocated_size);
904 printf("image: %s\n"
905 "file format: %s\n"
906 "virtual size: %s (%" PRId64 " bytes)\n"
907 "disk size: %s\n",
908 filename, fmt_name, size_buf,
909 (total_sectors * 512),
910 dsize_buf);
911 if (bdrv_is_encrypted(bs))
912 printf("encrypted: yes\n");
913 if (bdrv_get_info(bs, &bdi) >= 0) {
914 if (bdi.cluster_size != 0)
915 printf("cluster_size: %d\n", bdi.cluster_size);
917 bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
918 if (backing_filename[0] != '\0') {
919 path_combine(backing_filename2, sizeof(backing_filename2),
920 filename, backing_filename);
921 printf("backing file: %s (actual path: %s)\n",
922 backing_filename,
923 backing_filename2);
925 dump_snapshots(bs);
926 bdrv_delete(bs);
927 return 0;
930 #define SNAPSHOT_LIST 1
931 #define SNAPSHOT_CREATE 2
932 #define SNAPSHOT_APPLY 3
933 #define SNAPSHOT_DELETE 4
935 static int img_snapshot(int argc, char **argv)
937 BlockDriverState *bs;
938 QEMUSnapshotInfo sn;
939 char *filename, *snapshot_name = NULL;
940 int c, ret;
941 int action = 0;
942 qemu_timeval tv;
944 /* Parse commandline parameters */
945 for(;;) {
946 c = getopt(argc, argv, "la:c:d:h");
947 if (c == -1)
948 break;
949 switch(c) {
950 case 'h':
951 help();
952 return 0;
953 case 'l':
954 if (action) {
955 help();
956 return 0;
958 action = SNAPSHOT_LIST;
959 break;
960 case 'a':
961 if (action) {
962 help();
963 return 0;
965 action = SNAPSHOT_APPLY;
966 snapshot_name = optarg;
967 break;
968 case 'c':
969 if (action) {
970 help();
971 return 0;
973 action = SNAPSHOT_CREATE;
974 snapshot_name = optarg;
975 break;
976 case 'd':
977 if (action) {
978 help();
979 return 0;
981 action = SNAPSHOT_DELETE;
982 snapshot_name = optarg;
983 break;
987 if (optind >= argc)
988 help();
989 filename = argv[optind++];
991 /* Open the image */
992 bs = bdrv_new("");
993 if (!bs)
994 error("Not enough memory");
996 if (bdrv_open2(bs, filename, 0, NULL) < 0) {
997 error("Could not open '%s'", filename);
1000 /* Perform the requested action */
1001 switch(action) {
1002 case SNAPSHOT_LIST:
1003 dump_snapshots(bs);
1004 break;
1006 case SNAPSHOT_CREATE:
1007 memset(&sn, 0, sizeof(sn));
1008 pstrcpy(sn.name, sizeof(sn.name), snapshot_name);
1010 qemu_gettimeofday(&tv);
1011 sn.date_sec = tv.tv_sec;
1012 sn.date_nsec = tv.tv_usec * 1000;
1014 ret = bdrv_snapshot_create(bs, &sn);
1015 if (ret)
1016 error("Could not create snapshot '%s': %d (%s)",
1017 snapshot_name, ret, strerror(-ret));
1018 break;
1020 case SNAPSHOT_APPLY:
1021 ret = bdrv_snapshot_goto(bs, snapshot_name);
1022 if (ret)
1023 error("Could not apply snapshot '%s': %d (%s)",
1024 snapshot_name, ret, strerror(-ret));
1025 break;
1027 case SNAPSHOT_DELETE:
1028 ret = bdrv_snapshot_delete(bs, snapshot_name);
1029 if (ret)
1030 error("Could not delete snapshot '%s': %d (%s)",
1031 snapshot_name, ret, strerror(-ret));
1032 break;
1035 /* Cleanup */
1036 bdrv_delete(bs);
1038 return 0;
1041 static const img_cmd_t img_cmds[] = {
1042 #define DEF(option, callback, arg_string) \
1043 { option, callback },
1044 #include "qemu-img-cmds.h"
1045 #undef DEF
1046 #undef GEN_DOCS
1047 { NULL, NULL, },
1050 int main(int argc, char **argv)
1052 const img_cmd_t *cmd;
1053 const char *cmdname;
1055 bdrv_init();
1056 if (argc < 2)
1057 help();
1058 cmdname = argv[1];
1059 argc--; argv++;
1061 /* find the command */
1062 for(cmd = img_cmds; cmd->name != NULL; cmd++) {
1063 if (!strcmp(cmdname, cmd->name)) {
1064 return cmd->handler(argc, argv);
1068 /* not found */
1069 help();
1070 return 0;