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 | 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 | ... | ... |