Commit 926c2d23dfa599ea8c8213342b21cfe56b1d22ca
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,6 +23,7 @@ | ||
| 23 | */ | 23 | */ |
| 24 | #include "vl.h" | 24 | #include "vl.h" |
| 25 | #include "block_int.h" | 25 | #include "block_int.h" |
| 26 | +#include <assert.h> | ||
| 26 | 27 | ||
| 27 | #ifdef _WIN32 | 28 | #ifdef _WIN32 |
| 28 | #include <windows.h> | 29 | #include <windows.h> |
| @@ -101,7 +102,7 @@ void help(void) | @@ -101,7 +102,7 @@ void help(void) | ||
| 101 | "Command syntax:\n" | 102 | "Command syntax:\n" |
| 102 | " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" | 103 | " create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n" |
| 103 | " commit [-f fmt] filename\n" | 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 | " info [-f fmt] filename\n" | 106 | " info [-f fmt] filename\n" |
| 106 | "\n" | 107 | "\n" |
| 107 | "Command parameters:\n" | 108 | "Command parameters:\n" |
| @@ -418,11 +419,11 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) | @@ -418,11 +419,11 @@ static int is_allocated_sectors(const uint8_t *buf, int n, int *pnum) | ||
| 418 | 419 | ||
| 419 | static int img_convert(int argc, char **argv) | 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 | BlockDriver *drv; | 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 | uint8_t buf[IO_BUF_SIZE]; | 427 | uint8_t buf[IO_BUF_SIZE]; |
| 427 | const uint8_t *buf1; | 428 | const uint8_t *buf1; |
| 428 | BlockDriverInfo bdi; | 429 | BlockDriverInfo bdi; |
| @@ -455,14 +456,24 @@ static int img_convert(int argc, char **argv) | @@ -455,14 +456,24 @@ static int img_convert(int argc, char **argv) | ||
| 455 | break; | 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 | drv = bdrv_find_format(out_fmt); | 478 | drv = bdrv_find_format(out_fmt); |
| 468 | if (!drv) | 479 | if (!drv) |
| @@ -475,7 +486,7 @@ static int img_convert(int argc, char **argv) | @@ -475,7 +486,7 @@ static int img_convert(int argc, char **argv) | ||
| 475 | error("Alternative compatibility level not supported for this file format"); | 486 | error("Alternative compatibility level not supported for this file format"); |
| 476 | if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) | 487 | if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS) |
| 477 | error("Compression and encryption not supported at the same time"); | 488 | error("Compression and encryption not supported at the same time"); |
| 478 | - bdrv_get_geometry(bs, &total_sectors); | 489 | + |
| 479 | ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags); | 490 | ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags); |
| 480 | if (ret < 0) { | 491 | if (ret < 0) { |
| 481 | if (ret == -ENOTSUP) { | 492 | if (ret == -ENOTSUP) { |
| @@ -487,7 +498,11 @@ static int img_convert(int argc, char **argv) | @@ -487,7 +498,11 @@ static int img_convert(int argc, char **argv) | ||
| 487 | 498 | ||
| 488 | out_bs = bdrv_new_open(out_filename, out_fmt); | 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 | if (bdrv_get_info(out_bs, &bdi) < 0) | 506 | if (bdrv_get_info(out_bs, &bdi) < 0) |
| 492 | error("could not get block driver info"); | 507 | error("could not get block driver info"); |
| 493 | cluster_size = bdi.cluster_size; | 508 | cluster_size = bdi.cluster_size; |
| @@ -496,6 +511,10 @@ static int img_convert(int argc, char **argv) | @@ -496,6 +511,10 @@ static int img_convert(int argc, char **argv) | ||
| 496 | cluster_sectors = cluster_size >> 9; | 511 | cluster_sectors = cluster_size >> 9; |
| 497 | sector_num = 0; | 512 | sector_num = 0; |
| 498 | for(;;) { | 513 | for(;;) { |
| 514 | + int64_t bs_num; | ||
| 515 | + int remainder; | ||
| 516 | + uint8_t *buf2; | ||
| 517 | + | ||
| 499 | nb_sectors = total_sectors - sector_num; | 518 | nb_sectors = total_sectors - sector_num; |
| 500 | if (nb_sectors <= 0) | 519 | if (nb_sectors <= 0) |
| 501 | break; | 520 | break; |
| @@ -503,8 +522,37 @@ static int img_convert(int argc, char **argv) | @@ -503,8 +522,37 @@ static int img_convert(int argc, char **argv) | ||
| 503 | n = cluster_sectors; | 522 | n = cluster_sectors; |
| 504 | else | 523 | else |
| 505 | n = nb_sectors; | 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 | if (n < cluster_sectors) | 556 | if (n < cluster_sectors) |
| 509 | memset(buf + n * 512, 0, cluster_size - n * 512); | 557 | memset(buf + n * 512, 0, cluster_size - n * 512); |
| 510 | if (is_not_zero(buf, cluster_size)) { | 558 | if (is_not_zero(buf, cluster_size)) { |
| @@ -527,7 +575,21 @@ static int img_convert(int argc, char **argv) | @@ -527,7 +575,21 @@ static int img_convert(int argc, char **argv) | ||
| 527 | n = (IO_BUF_SIZE / 512); | 575 | n = (IO_BUF_SIZE / 512); |
| 528 | else | 576 | else |
| 529 | n = nb_sectors; | 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 | error("error while reading"); | 593 | error("error while reading"); |
| 532 | /* NOTE: at the same time we convert, we do not write zero | 594 | /* NOTE: at the same time we convert, we do not write zero |
| 533 | sectors to have a chance to compress the image. Ideally, we | 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,7 +607,9 @@ static int img_convert(int argc, char **argv) | ||
| 545 | } | 607 | } |
| 546 | } | 608 | } |
| 547 | bdrv_delete(out_bs); | 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 | return 0; | 613 | return 0; |
| 550 | } | 614 | } |
| 551 | 615 |