| ... | ... |
@@ -92,9 +92,12 @@ int cli_scandmg(cli_ctx *ctx) |
| 92 | 92 |
char *dirname, *tmpfile; |
| 93 | 93 |
const char *outdata; |
| 94 | 94 |
unsigned int file = 0; |
| 95 |
- |
|
| 96 |
- unsigned int trailer = 0; |
|
| 97 |
- uint32_t filesize, namesize, hdr_namesize; |
|
| 95 |
+ struct dmg_mish_with_stripes *mish_list = NULL, *mish_list_tail = NULL; |
|
| 96 |
+ enum dmgReadState state = DMG_FIND_BASE_PLIST; |
|
| 97 |
+ int stateDepth[DMG_MAX_STATE]; |
|
| 98 |
+#if HAVE_LIBXML2 |
|
| 99 |
+ xmlTextReaderPtr reader; |
|
| 100 |
+#endif |
|
| 98 | 101 |
|
| 99 | 102 |
if (!ctx || !ctx->fmap) {
|
| 100 | 103 |
cli_errmsg("cli_scandmg: Invalid context\n");
|
| ... | ... |
@@ -191,7 +194,7 @@ int cli_scandmg(cli_ctx *ctx) |
| 191 | 191 |
/* XML_PARSE_NOENT | XML_PARSE_NONET | XML_PARSE_COMPACT */ |
| 192 | 192 |
#define DMG_XML_PARSE_OPTS (1 << 1 | 1 << 11 | 1 << 16) |
| 193 | 193 |
|
| 194 |
- xmlTextReaderPtr reader = xmlReaderForMemory(outdata, (int)hdr.xmlLength, "toc.xml", NULL, DMG_XML_PARSE_OPTS); |
|
| 194 |
+ reader = xmlReaderForMemory(outdata, (int)hdr.xmlLength, "toc.xml", NULL, DMG_XML_PARSE_OPTS); |
|
| 195 | 195 |
if (!reader) {
|
| 196 | 196 |
cli_dbgmsg("cli_scandmg: Failed parsing XML!\n");
|
| 197 | 197 |
if (!ctx->engine->keeptmp) |
| ... | ... |
@@ -200,8 +203,6 @@ int cli_scandmg(cli_ctx *ctx) |
| 200 | 200 |
return CL_EFORMAT; |
| 201 | 201 |
} |
| 202 | 202 |
|
| 203 |
- enum dmgReadState state = DMG_FIND_BASE_PLIST; |
|
| 204 |
- int stateDepth[DMG_MAX_STATE]; |
|
| 205 | 203 |
stateDepth[DMG_FIND_BASE_PLIST] = -1; |
| 206 | 204 |
|
| 207 | 205 |
// May need to check for (xmlTextReaderIsEmptyElement(reader) == 0) |
| ... | ... |
@@ -233,7 +234,7 @@ int cli_scandmg(cli_ctx *ctx) |
| 233 | 233 |
if ((state == DMG_FIND_DATA_MISH) |
| 234 | 234 |
&& (depth == stateDepth[state-1])) {
|
| 235 | 235 |
xmlChar * textValue; |
| 236 |
- struct dmg_mish_with_stripes mish_set; |
|
| 236 |
+ struct dmg_mish_with_stripes *mish_set; |
|
| 237 | 237 |
/* Reset state early, for continue cases */ |
| 238 | 238 |
stateDepth[DMG_FIND_KEY_DATA] = -1; |
| 239 | 239 |
state--; |
| ... | ... |
@@ -264,7 +265,14 @@ int cli_scandmg(cli_ctx *ctx) |
| 264 | 264 |
continue; |
| 265 | 265 |
} |
| 266 | 266 |
/* Have encoded mish block */ |
| 267 |
- ret = dmg_decode_mish(ctx, &file, textValue, &mish_set); |
|
| 267 |
+ mish_set = cli_malloc(sizeof(struct dmg_mish_with_stripes)); |
|
| 268 |
+ if (mish_set == NULL) {
|
|
| 269 |
+ ret = CL_EMEM; |
|
| 270 |
+ xmlFree(textValue); |
|
| 271 |
+ xmlFree(nodeName); |
|
| 272 |
+ break; |
|
| 273 |
+ } |
|
| 274 |
+ ret = dmg_decode_mish(ctx, &file, textValue, mish_set); |
|
| 268 | 275 |
xmlFree(textValue); |
| 269 | 276 |
if (ret == CL_EFORMAT) {
|
| 270 | 277 |
/* Didn't decode, or not a mish block */ |
| ... | ... |
@@ -276,9 +284,16 @@ int cli_scandmg(cli_ctx *ctx) |
| 276 | 276 |
xmlFree(nodeName); |
| 277 | 277 |
continue; |
| 278 | 278 |
} |
| 279 |
- /* Handle & scan mish block */ |
|
| 280 |
- ret = dmg_handle_mish(ctx, file, dirname, hdr.xmlOffset, &mish_set); |
|
| 281 |
- free(mish_set.mish); |
|
| 279 |
+ /* Add mish block to list */ |
|
| 280 |
+ if (mish_list_tail != NULL) {
|
|
| 281 |
+ mish_list_tail->next = mish_set; |
|
| 282 |
+ mish_list_tail = mish_set; |
|
| 283 |
+ } |
|
| 284 |
+ else {
|
|
| 285 |
+ mish_list = mish_set; |
|
| 286 |
+ mish_list_tail = mish_set; |
|
| 287 |
+ } |
|
| 288 |
+ mish_list_tail->next = NULL; |
|
| 282 | 289 |
} |
| 283 | 290 |
if ((state == DMG_FIND_KEY_DATA) |
| 284 | 291 |
&& (depth > stateDepth[state-1]) |
| ... | ... |
@@ -424,13 +439,34 @@ int cli_scandmg(cli_ctx *ctx) |
| 424 | 424 |
} |
| 425 | 425 |
} |
| 426 | 426 |
|
| 427 |
+ xmlFreeTextReader(reader); |
|
| 428 |
+ xmlCleanupParser(); |
|
| 429 |
+ |
|
| 427 | 430 |
#else |
| 428 | 431 |
|
| 429 | 432 |
cli_dbgmsg("cli_scandmg: libxml2 support is compiled out. It is required for full DMG support.\n");
|
| 430 | 433 |
|
| 431 | 434 |
#endif |
| 432 | 435 |
|
| 436 |
+ /* Loop over mish array */ |
|
| 437 |
+ file = 0; |
|
| 438 |
+ while ((ret == CL_CLEAN) && (mish_list != NULL)) {
|
|
| 439 |
+ /* Handle & scan mish block */ |
|
| 440 |
+ ret = dmg_handle_mish(ctx, file++, dirname, hdr.xmlOffset, mish_list); |
|
| 441 |
+ free(mish_list->mish); |
|
| 442 |
+ mish_list_tail = mish_list; |
|
| 443 |
+ mish_list = mish_list->next; |
|
| 444 |
+ free(mish_list_tail); |
|
| 445 |
+ } |
|
| 446 |
+ |
|
| 433 | 447 |
/* Cleanup */ |
| 448 |
+ /* If error occurred, need to free mish items and mish blocks */ |
|
| 449 |
+ while (mish_list != NULL) {
|
|
| 450 |
+ free(mish_list->mish); |
|
| 451 |
+ mish_list_tail = mish_list; |
|
| 452 |
+ mish_list = mish_list->next; |
|
| 453 |
+ free(mish_list_tail); |
|
| 454 |
+ } |
|
| 434 | 455 |
if (!ctx->engine->keeptmp) |
| 435 | 456 |
cli_rmdirs(dirname); |
| 436 | 457 |
free(dirname); |
| ... | ... |
@@ -591,6 +627,175 @@ static int dmg_track_sectors(uint64_t *total, uint8_t *data_to_write, |
| 591 | 591 |
return ret; |
| 592 | 592 |
} |
| 593 | 593 |
|
| 594 |
+/* Stripe handling: zero block (type 0x0 or 0x2) */ |
|
| 595 |
+static int dmg_stripe_zeroes(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set) |
|
| 596 |
+{
|
|
| 597 |
+ int ret = CL_CLEAN; |
|
| 598 |
+ size_t len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE; |
|
| 599 |
+ ssize_t written; |
|
| 600 |
+ uint8_t obuf[BUFSIZ]; |
|
| 601 |
+ |
|
| 602 |
+ cli_dbgmsg("dmg_stripe_zeroes: stripe %lu\n", (unsigned long)index);
|
|
| 603 |
+ if (len == 0) |
|
| 604 |
+ return CL_CLEAN; |
|
| 605 |
+ |
|
| 606 |
+ memset(obuf, 0, sizeof(obuf)); |
|
| 607 |
+ while (len > sizeof(obuf)) {
|
|
| 608 |
+ written = cli_writen(fd, obuf, sizeof(obuf)); |
|
| 609 |
+ if (written != sizeof(obuf)) {
|
|
| 610 |
+ ret = CL_EWRITE; |
|
| 611 |
+ break; |
|
| 612 |
+ } |
|
| 613 |
+ len -= sizeof(obuf); |
|
| 614 |
+ } |
|
| 615 |
+ |
|
| 616 |
+ if ((ret == CL_CLEAN) && (len > 0)) {
|
|
| 617 |
+ written = cli_writen(fd, obuf, len); |
|
| 618 |
+ if (written != len) {
|
|
| 619 |
+ ret = CL_EWRITE; |
|
| 620 |
+ } |
|
| 621 |
+ } |
|
| 622 |
+ |
|
| 623 |
+ if (ret != CL_CLEAN) {
|
|
| 624 |
+ cli_errmsg("dmg_stripe_zeroes: error writing bytes to file (out of disk space?)\n");
|
|
| 625 |
+ return CL_EWRITE; |
|
| 626 |
+ } |
|
| 627 |
+ return CL_CLEAN; |
|
| 628 |
+} |
|
| 629 |
+ |
|
| 630 |
+/* Stripe handling: stored block (type 0x1) */ |
|
| 631 |
+static int dmg_stripe_store(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set) |
|
| 632 |
+{
|
|
| 633 |
+ const void *obuf; |
|
| 634 |
+ int ret; |
|
| 635 |
+ size_t off = mish_set->stripes[index].dataOffset; |
|
| 636 |
+ size_t len = mish_set->stripes[index].dataLength; |
|
| 637 |
+ ssize_t written; |
|
| 638 |
+ |
|
| 639 |
+ cli_dbgmsg("dmg_stripe_store: stripe %lu\n", (unsigned long)index);
|
|
| 640 |
+ if (len == 0) |
|
| 641 |
+ return CL_CLEAN; |
|
| 642 |
+ |
|
| 643 |
+ obuf = (void *)fmap_need_off_once(*ctx->fmap, off, len); |
|
| 644 |
+ if (!obuf) {
|
|
| 645 |
+ cli_warnmsg("dmg_stripe_store: fmap need failed on stripe %lu\n", index);
|
|
| 646 |
+ return CL_EMAP; |
|
| 647 |
+ } |
|
| 648 |
+ written = cli_writen(fd, obuf, len); |
|
| 649 |
+ if (written < 0) {
|
|
| 650 |
+ cli_errmsg("dmg_stripe_store: error writing bytes to file (out of disk space?)\n");
|
|
| 651 |
+ return CL_EWRITE; |
|
| 652 |
+ } |
|
| 653 |
+ else if (written != len) {
|
|
| 654 |
+ cli_errmsg("dmg_stripe_store: error writing bytes to file (out of disk space?)\n");
|
|
| 655 |
+ return CL_EWRITE; |
|
| 656 |
+ } |
|
| 657 |
+ return CL_CLEAN; |
|
| 658 |
+} |
|
| 659 |
+ |
|
| 660 |
+/* Stripe handling: ADC block (type 0x80000004) */ |
|
| 661 |
+static int dmg_stripe_adc(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set) |
|
| 662 |
+{
|
|
| 663 |
+ /* Temporary stub */ |
|
| 664 |
+ cli_dbgmsg("dmg_stripe_adc: stripe %lu\n", (unsigned long)index);
|
|
| 665 |
+ |
|
| 666 |
+ return CL_CLEAN; |
|
| 667 |
+} |
|
| 668 |
+ |
|
| 669 |
+/* Stripe handling: deflate block (type 0x80000005) */ |
|
| 670 |
+static int dmg_stripe_inflate(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set) |
|
| 671 |
+{
|
|
| 672 |
+ int ret = CL_CLEAN, zstat; |
|
| 673 |
+ z_stream strm; |
|
| 674 |
+ size_t off = mish_set->stripes[index].dataOffset; |
|
| 675 |
+ size_t len = mish_set->stripes[index].dataLength; |
|
| 676 |
+ off_t nbytes = 0; |
|
| 677 |
+ char obuf[BUFSIZ]; |
|
| 678 |
+ |
|
| 679 |
+ cli_dbgmsg("dmg_stripe_inflate: stripe %lu\n", (unsigned long)index);
|
|
| 680 |
+ if (len == 0) |
|
| 681 |
+ return CL_CLEAN; |
|
| 682 |
+ |
|
| 683 |
+ memset(&strm, 0, sizeof(strm)); |
|
| 684 |
+ strm.next_in = (void*)fmap_need_off_once(*ctx->fmap, off, len); |
|
| 685 |
+ if (!strm.next_in) {
|
|
| 686 |
+ cli_warnmsg("dmg_stripe_inflate: fmap need failed on stripe %lu\n", index);
|
|
| 687 |
+ return CL_EMAP; |
|
| 688 |
+ } |
|
| 689 |
+ strm.avail_in = len; |
|
| 690 |
+ strm.next_out = obuf; |
|
| 691 |
+ strm.avail_out = sizeof(obuf); |
|
| 692 |
+ |
|
| 693 |
+ zstat = inflateInit(&strm); |
|
| 694 |
+ if(zstat != Z_OK) {
|
|
| 695 |
+ cli_warnmsg("dmg_stripe_inflate: inflateInit failed\n");
|
|
| 696 |
+ return CL_EMEM; |
|
| 697 |
+ } |
|
| 698 |
+ |
|
| 699 |
+ while(strm.avail_in) {
|
|
| 700 |
+ int written; |
|
| 701 |
+ zstat = inflate(&strm, Z_NO_FLUSH); /* zlib */ |
|
| 702 |
+ switch(zstat) {
|
|
| 703 |
+ case Z_OK: |
|
| 704 |
+ if(strm.avail_out == 0) {
|
|
| 705 |
+ if ((written=cli_writen(fd, obuf, sizeof(obuf)))!=sizeof(obuf)) {
|
|
| 706 |
+ cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
|
|
| 707 |
+ inflateEnd(&strm); |
|
| 708 |
+ return CL_EWRITE; |
|
| 709 |
+ } |
|
| 710 |
+ nbytes += written; |
|
| 711 |
+ strm.next_out = (Bytef *)obuf; |
|
| 712 |
+ strm.avail_out = sizeof(obuf); |
|
| 713 |
+ } |
|
| 714 |
+ continue; |
|
| 715 |
+ case Z_STREAM_END: |
|
| 716 |
+ default: |
|
| 717 |
+ written = sizeof(obuf) - strm.avail_out; |
|
| 718 |
+ if (written) {
|
|
| 719 |
+ if ((cli_writen(fd, obuf, written))!=written) {
|
|
| 720 |
+ cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
|
|
| 721 |
+ inflateEnd(&strm); |
|
| 722 |
+ return CL_EWRITE; |
|
| 723 |
+ } |
|
| 724 |
+ nbytes += written; |
|
| 725 |
+ strm.next_out = (Bytef *)obuf; |
|
| 726 |
+ strm.avail_out = sizeof(obuf); |
|
| 727 |
+ if (zstat == Z_STREAM_END) |
|
| 728 |
+ break; |
|
| 729 |
+ } |
|
| 730 |
+ if(strm.msg) |
|
| 731 |
+ cli_dbgmsg("dmg_stripe_inflate: after writing %lu bytes, got error \"%s\" inflating stripe %lu\n",
|
|
| 732 |
+ (unsigned long)nbytes, strm.msg, index); |
|
| 733 |
+ else |
|
| 734 |
+ cli_dbgmsg("dmg_stripe_inflate: after writing %lu bytes, got error %d inflating stripe %lu\n",
|
|
| 735 |
+ (unsigned long)nbytes, zstat, index); |
|
| 736 |
+ inflateEnd(&strm); |
|
| 737 |
+ return CL_EFORMAT; |
|
| 738 |
+ } |
|
| 739 |
+ break; |
|
| 740 |
+ } |
|
| 741 |
+ |
|
| 742 |
+ if(strm.avail_out != sizeof(obuf)) {
|
|
| 743 |
+ if(cli_writen(fd, obuf, sizeof(obuf) - strm.avail_out) < 0) {
|
|
| 744 |
+ cli_errmsg("dmg_stripe_inflate: failed write to output file\n");
|
|
| 745 |
+ inflateEnd(&strm); |
|
| 746 |
+ return CL_EWRITE; |
|
| 747 |
+ } |
|
| 748 |
+ } |
|
| 749 |
+ |
|
| 750 |
+ inflateEnd(&strm); |
|
| 751 |
+ return CL_CLEAN; |
|
| 752 |
+} |
|
| 753 |
+ |
|
| 754 |
+/* Stripe handling: bzip block (type 0x80000006) */ |
|
| 755 |
+static int dmg_stripe_bzip(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set) |
|
| 756 |
+{
|
|
| 757 |
+ /* Temporary stub */ |
|
| 758 |
+ cli_dbgmsg("dmg_stripe_bzip: stripe %lu\n", (unsigned long)index);
|
|
| 759 |
+ |
|
| 760 |
+ return CL_CLEAN; |
|
| 761 |
+} |
|
| 762 |
+ |
|
| 594 | 763 |
/* Given mish data, reconstruct the partition details */ |
| 595 | 764 |
static int dmg_handle_mish(cli_ctx *ctx, unsigned int mishblocknum, char *dir, |
| 596 | 765 |
uint64_t xmlOffset, struct dmg_mish_with_stripes *mish_set) |
| ... | ... |
@@ -669,19 +874,19 @@ static int dmg_handle_mish(cli_ctx *ctx, unsigned int mishblocknum, char *dir, |
| 669 | 669 |
switch (blocklist[i].type) {
|
| 670 | 670 |
case DMG_STRIPE_EMPTY: |
| 671 | 671 |
case DMG_STRIPE_ZEROES: |
| 672 |
- cli_dbgmsg("dmg_handle_mish: stripe %lu, zero block\n", (unsigned long)i);
|
|
| 672 |
+ ret = dmg_stripe_zeroes(ctx, ofd, i, mish_set); |
|
| 673 | 673 |
break; |
| 674 | 674 |
case DMG_STRIPE_STORED: |
| 675 |
- cli_dbgmsg("dmg_handle_mish: stripe %lu, stored data block\n", (unsigned long)i);
|
|
| 675 |
+ ret = dmg_stripe_store(ctx, ofd, i, mish_set); |
|
| 676 | 676 |
break; |
| 677 | 677 |
case DMG_STRIPE_ADC: |
| 678 |
- cli_dbgmsg("dmg_handle_mish: stripe %lu, ADC data block\n", (unsigned long)i);
|
|
| 678 |
+ ret = dmg_stripe_adc(ctx, ofd, i, mish_set); |
|
| 679 | 679 |
break; |
| 680 | 680 |
case DMG_STRIPE_DEFLATE: |
| 681 |
- cli_dbgmsg("dmg_handle_mish: stripe %lu, zlib block\n", (unsigned long)i);
|
|
| 681 |
+ ret = dmg_stripe_inflate(ctx, ofd, i, mish_set); |
|
| 682 | 682 |
break; |
| 683 | 683 |
case DMG_STRIPE_BZ: |
| 684 |
- cli_dbgmsg("dmg_handle_mish: stripe %lu, bzip block\n", (unsigned long)i);
|
|
| 684 |
+ ret = dmg_stripe_bzip(ctx, ofd, i, mish_set); |
|
| 685 | 685 |
break; |
| 686 | 686 |
case DMG_STRIPE_SKIP: |
| 687 | 687 |
case DMG_STRIPE_END: |