Browse code

bb #1570: turn mish blocks into list and process stripes

David Raynor authored on 2013/09/14 07:37:25
Showing 2 changed files
... ...
@@ -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:
... ...
@@ -115,6 +115,7 @@ struct dmg_block_data {
115 115
 struct dmg_mish_with_stripes {
116 116
     struct dmg_mish_block *mish;
117 117
     struct dmg_block_data *stripes;
118
+    struct dmg_mish_with_stripes *next;
118 119
 };
119 120
 
120 121
 #ifdef HAVE_PRAGMA_PACK