Commit 926c2d23dfa599ea8c8213342b21cfe56b1d22ca

Authored by balrog
1 parent fe8f78e4

Support multipart images as input to qemu-img (Salvador Fandino).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3496 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 82 additions and 18 deletions
qemu-img.c
... ... @@ -23,6 +23,7 @@
23 23 */
24 24 #include "vl.h"
25 25 #include "block_int.h"
  26 +#include <assert.h>
26 27  
27 28 #ifdef _WIN32
28 29 #include <windows.h>
... ... @@ -101,7 +102,7 @@ void help(void)
101 102 "Command syntax:\n"
102 103 " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
103 104 " commit [-f fmt] filename\n"
104   - " convert [-c] [-e] [-6] [-f fmt] filename [-O output_fmt] output_filename\n"
  105 + " convert [-c] [-e] [-6] [-f fmt] filename [filename2 [...]] [-O output_fmt] output_filename\n"
105 106 " info [-f fmt] filename\n"
106 107 "\n"
107 108 "Command parameters:\n"
... ... @@ -418,11 +419,11 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum)
418 419  
419 420 static int img_convert(int argc, char **argv)
420 421 {
421   - int c, ret, n, n1, flags, cluster_size, cluster_sectors;
422   - const char *filename, *fmt, *out_fmt, *out_filename;
  422 + int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
  423 + const char *fmt, *out_fmt, *out_filename;
423 424 BlockDriver *drv;
424   - BlockDriverState *bs, *out_bs;
425   - int64_t total_sectors, nb_sectors, sector_num;
  425 + BlockDriverState **bs, *out_bs;
  426 + int64_t total_sectors, nb_sectors, sector_num, bs_offset, bs_sectors;
426 427 uint8_t buf[IO_BUF_SIZE];
427 428 const uint8_t *buf1;
428 429 BlockDriverInfo bdi;
... ... @@ -455,14 +456,24 @@ static int img_convert(int argc, char **argv)
455 456 break;
456 457 }
457 458 }
458   - if (optind >= argc)
459   - help();
460   - filename = argv[optind++];
461   - if (optind >= argc)
462   - help();
463   - out_filename = argv[optind++];
464 459  
465   - bs = bdrv_new_open(filename, fmt);
  460 + bs_n = argc - optind - 1;
  461 + if (bs_n < 1) help();
  462 +
  463 + out_filename = argv[argc - 1];
  464 +
  465 + bs = calloc(bs_n, sizeof(BlockDriverState *));
  466 + if (!bs)
  467 + error("Out of memory");
  468 +
  469 + total_sectors = 0;
  470 + for (bs_i = 0; bs_i < bs_n; bs_i++) {
  471 + bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt);
  472 + if (!bs[bs_i])
  473 + error("Could not open '%s'", argv[optind + bs_i]);
  474 + bdrv_get_geometry(bs[bs_i], &bs_sectors);
  475 + total_sectors += bs_sectors;
  476 + }
466 477  
467 478 drv = bdrv_find_format(out_fmt);
468 479 if (!drv)
... ... @@ -475,7 +486,7 @@ static int img_convert(int argc, char **argv)
475 486 error("Alternative compatibility level not supported for this file format");
476 487 if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
477 488 error("Compression and encryption not supported at the same time");
478   - bdrv_get_geometry(bs, &total_sectors);
  489 +
479 490 ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags);
480 491 if (ret < 0) {
481 492 if (ret == -ENOTSUP) {
... ... @@ -487,7 +498,11 @@ static int img_convert(int argc, char **argv)
487 498  
488 499 out_bs = bdrv_new_open(out_filename, out_fmt);
489 500  
490   - if (flags && BLOCK_FLAG_COMPRESS) {
  501 + bs_i = 0;
  502 + bs_offset = 0;
  503 + bdrv_get_geometry(bs[0], &bs_sectors);
  504 +
  505 + if (flags & BLOCK_FLAG_COMPRESS) {
491 506 if (bdrv_get_info(out_bs, &bdi) < 0)
492 507 error("could not get block driver info");
493 508 cluster_size = bdi.cluster_size;
... ... @@ -496,6 +511,10 @@ static int img_convert(int argc, char **argv)
496 511 cluster_sectors = cluster_size >> 9;
497 512 sector_num = 0;
498 513 for(;;) {
  514 + int64_t bs_num;
  515 + int remainder;
  516 + uint8_t *buf2;
  517 +
499 518 nb_sectors = total_sectors - sector_num;
500 519 if (nb_sectors <= 0)
501 520 break;
... ... @@ -503,8 +522,37 @@ static int img_convert(int argc, char **argv)
503 522 n = cluster_sectors;
504 523 else
505 524 n = nb_sectors;
506   - if (bdrv_read(bs, sector_num, buf, n) < 0)
507   - error("error while reading");
  525 +
  526 + bs_num = sector_num - bs_offset;
  527 + assert (bs_num >= 0);
  528 + remainder = n;
  529 + buf2 = buf;
  530 + while (remainder > 0) {
  531 + int nlow;
  532 + while (bs_num == bs_sectors) {
  533 + bs_i++;
  534 + assert (bs_i < bs_n);
  535 + bs_offset += bs_sectors;
  536 + bdrv_get_geometry(bs[bs_i], &bs_sectors);
  537 + bs_num = 0;
  538 + /* printf("changing part: sector_num=%lld, "
  539 + "bs_i=%d, bs_offset=%lld, bs_sectors=%lld\n",
  540 + sector_num, bs_i, bs_offset, bs_sectors); */
  541 + }
  542 + assert (bs_num < bs_sectors);
  543 +
  544 + nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
  545 +
  546 + if (bdrv_read(bs[bs_i], bs_num, buf2, nlow) < 0)
  547 + error("error while reading");
  548 +
  549 + buf2 += nlow * 512;
  550 + bs_num += nlow;
  551 +
  552 + remainder -= nlow;
  553 + }
  554 + assert (remainder == 0);
  555 +
508 556 if (n < cluster_sectors)
509 557 memset(buf + n * 512, 0, cluster_size - n * 512);
510 558 if (is_not_zero(buf, cluster_size)) {
... ... @@ -527,7 +575,21 @@ static int img_convert(int argc, char **argv)
527 575 n = (IO_BUF_SIZE / 512);
528 576 else
529 577 n = nb_sectors;
530   - if (bdrv_read(bs, sector_num, buf, n) < 0)
  578 +
  579 + while (sector_num - bs_offset >= bs_sectors) {
  580 + bs_i ++;
  581 + assert (bs_i < bs_n);
  582 + bs_offset += bs_sectors;
  583 + bdrv_get_geometry(bs[bs_i], &bs_sectors);
  584 + /* printf("changing part: sector_num=%lld, bs_i=%d, "
  585 + "bs_offset=%lld, bs_sectors=%lld\n",
  586 + sector_num, bs_i, bs_offset, bs_sectors); */
  587 + }
  588 +
  589 + if (n > bs_offset + bs_sectors - sector_num)
  590 + n = bs_offset + bs_sectors - sector_num;
  591 +
  592 + if (bdrv_read(bs[bs_i], sector_num - bs_offset, buf, n) < 0)
531 593 error("error while reading");
532 594 /* NOTE: at the same time we convert, we do not write zero
533 595 sectors to have a chance to compress the image. Ideally, we
... ... @@ -545,7 +607,9 @@ static int img_convert(int argc, char **argv)
545 607 }
546 608 }
547 609 bdrv_delete(out_bs);
548   - bdrv_delete(bs);
  610 + for (bs_i = 0; bs_i < bs_n; bs_i++)
  611 + bdrv_delete(bs[bs_i]);
  612 + free(bs);
549 613 return 0;
550 614 }
551 615  
... ...