Browse code

bb #1570: Support ADC compression in DMG

David Raynor authored on 2013/10/03 23:48:52
Showing 5 changed files
... ...
@@ -371,6 +371,8 @@ libclamav_la_SOURCES = \
371 371
 	builtin_bytecodes.h\
372 372
 	events.c\
373 373
 	events.h \
374
+	adc.c \
375
+	adc.h \
374 376
 	dmg.c \
375 377
 	dmg.h \
376 378
 	xar.c \
... ...
@@ -185,7 +185,7 @@ am_libclamav_la_OBJECTS = libclamav_la-matcher-ac.lo \
185 185
 	libclamav_la-ishield.lo libclamav_la-bytecode_api.lo \
186 186
 	libclamav_la-bytecode_api_decl.lo libclamav_la-cache.lo \
187 187
 	libclamav_la-bytecode_detect.lo libclamav_la-events.lo \
188
-	libclamav_la-dmg.lo libclamav_la-xar.lo \
188
+	libclamav_la-adc.lo libclamav_la-dmg.lo libclamav_la-xar.lo \
189 189
 	libclamav_la-sf_base64decode.lo libclamav_la-hfsplus.lo \
190 190
 	libclamav_la-swf.lo libclamav_la-jpeg.lo libclamav_la-png.lo \
191 191
 	libclamav_la-iso9660.lo libclamav_la-arc4.lo \
... ...
@@ -711,11 +711,11 @@ libclamav_la_SOURCES = clamav.h matcher-ac.c matcher-ac.h matcher-bm.c \
711 711
 	bcfeatures.h bytecode_api.c bytecode_api_decl.c bytecode_api.h \
712 712
 	bytecode_api_impl.h bytecode_hooks.h cache.c cache.h \
713 713
 	bytecode_detect.c bytecode_detect.h builtin_bytecodes.h \
714
-	events.c events.h dmg.c dmg.h xar.c xar.h sf_base64decode.c \
715
-	sf_base64decode.h hfsplus.c hfsplus.h swf.c swf.h jpeg.c \
716
-	jpeg.h png.c png.h iso9660.c iso9660.h arc4.c arc4.h \
717
-	rijndael.c rijndael.h crtmgr.c crtmgr.h asn1.c asn1.h bignum.h \
718
-	bignum_fast.h tomsfastmath/addsub/fp_add.c \
714
+	events.c events.h adc.c adc.h dmg.c dmg.h xar.c xar.h \
715
+	sf_base64decode.c sf_base64decode.h hfsplus.c hfsplus.h swf.c \
716
+	swf.h jpeg.c jpeg.h png.c png.h iso9660.c iso9660.h arc4.c \
717
+	arc4.h rijndael.c rijndael.h crtmgr.c crtmgr.h asn1.c asn1.h \
718
+	bignum.h bignum_fast.h tomsfastmath/addsub/fp_add.c \
719 719
 	tomsfastmath/addsub/fp_add_d.c tomsfastmath/addsub/fp_addmod.c \
720 720
 	tomsfastmath/addsub/fp_cmp.c tomsfastmath/addsub/fp_cmp_d.c \
721 721
 	tomsfastmath/addsub/fp_cmp_mag.c tomsfastmath/addsub/fp_sub.c \
... ...
@@ -916,6 +916,7 @@ distclean-compile:
916 916
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-LzmaDec.Plo@am__quote@
917 917
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-Ppmd7.Plo@am__quote@
918 918
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-Ppmd7Dec.Plo@am__quote@
919
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-adc.Plo@am__quote@
919 920
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-arc4.Plo@am__quote@
920 921
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-asn1.Plo@am__quote@
921 922
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamav_la-aspack.Plo@am__quote@
... ...
@@ -1848,6 +1849,13 @@ libclamav_la-events.lo: events.c
1848 1848
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
1849 1849
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-events.lo `test -f 'events.c' || echo '$(srcdir)/'`events.c
1850 1850
 
1851
+libclamav_la-adc.lo: adc.c
1852
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-adc.lo -MD -MP -MF $(DEPDIR)/libclamav_la-adc.Tpo -c -o libclamav_la-adc.lo `test -f 'adc.c' || echo '$(srcdir)/'`adc.c
1853
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-adc.Tpo $(DEPDIR)/libclamav_la-adc.Plo
1854
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='adc.c' object='libclamav_la-adc.lo' libtool=yes @AMDEPBACKSLASH@
1855
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
1856
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -c -o libclamav_la-adc.lo `test -f 'adc.c' || echo '$(srcdir)/'`adc.c
1857
+
1851 1858
 libclamav_la-dmg.lo: dmg.c
1852 1859
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamav_la_CFLAGS) $(CFLAGS) -MT libclamav_la-dmg.lo -MD -MP -MF $(DEPDIR)/libclamav_la-dmg.Tpo -c -o libclamav_la-dmg.lo `test -f 'dmg.c' || echo '$(srcdir)/'`dmg.c
1853 1860
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libclamav_la-dmg.Tpo $(DEPDIR)/libclamav_la-dmg.Plo
1854 1861
new file mode 100644
... ...
@@ -0,0 +1,291 @@
0
+/*
1
+ *  Copyright (C) 2013 Sourcefire, Inc.
2
+ *
3
+ *  Authors: David Raynor <draynor@sourcefire.com>
4
+ *
5
+ *  This program is free software; you can redistribute it and/or modify
6
+ *  it under the terms of the GNU General Public License version 2 as
7
+ *  published by the Free Software Foundation.
8
+ *
9
+ *  This program is distributed in the hope that it will be useful,
10
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
+ *  GNU General Public License for more details.
13
+ *
14
+ *  You should have received a copy of the GNU General Public License
15
+ *  along with this program; if not, write to the Free Software
16
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17
+ *  MA 02110-1301, USA.
18
+ */
19
+
20
+#if HAVE_CONFIG_H
21
+#include "clamav-config.h"
22
+#endif
23
+
24
+#include <stdio.h>
25
+#include <errno.h>
26
+#if HAVE_STRING_H
27
+#include <string.h>
28
+#endif
29
+
30
+#include "cltypes.h"
31
+#include "others.h"
32
+#include "adc.h"
33
+
34
+/* #define DEBUG_ADC */
35
+
36
+#ifdef DEBUG_ADC
37
+#  define adc_dbgmsg(...) cli_dbgmsg( __VA_ARGS__ )
38
+#else
39
+#  define adc_dbgmsg(...) ;
40
+#endif
41
+
42
+/* Initialize values and collect buffer
43
+ * NOTE: buffer size must be larger than largest lookback offset */
44
+int adc_decompressInit(adc_stream *strm)
45
+{
46
+    if (strm == NULL) {
47
+        return ADC_IO_ERROR;
48
+    }
49
+    if (strm->state != ADC_STATE_UNINIT) {
50
+        return ADC_DATA_ERROR;
51
+    }
52
+
53
+    /* Have to buffer maximum backward lookup */
54
+    strm->buffer = calloc(ADC_BUFF_SIZE, 1);
55
+    if (strm->buffer == NULL) {
56
+        return ADC_MEM_ERROR;
57
+    }
58
+    strm->buffered = 0;
59
+    strm->state = ADC_STATE_GETTYPE;
60
+    strm->length = 0;
61
+    strm->offset = 0;
62
+    strm->curr = strm->buffer;
63
+
64
+    return ADC_OK;
65
+}
66
+
67
+/* Decompress routine
68
+ * NOTE: Reaching end of input buffer does not mean end of output.
69
+ * It may fill the output buffer but have more to output.
70
+ * It will only return ADC_STREAM_END if output buffer is not full.
71
+ * It will return ADC_DATA_ERROR if it ends in the middle of a phrase
72
+ * (i.e. in the middle of a lookback code or data run)
73
+ */
74
+int adc_decompress(adc_stream *strm)
75
+{
76
+    uint8_t bData;
77
+    uint8_t didNothing = 1;
78
+
79
+    /* first, the error returns based on strm */
80
+    if ((strm == NULL) || (strm->next_in == NULL) || (strm->next_out == NULL)) {
81
+        return ADC_IO_ERROR;
82
+    }
83
+    if (strm->state == ADC_STATE_UNINIT) {
84
+        return ADC_DATA_ERROR;
85
+    }
86
+
87
+    cli_dbgmsg("adc_decompress: avail_in %lu avail_out %lu state %u\n", strm->avail_in, strm->avail_out, strm->state);
88
+
89
+    while (strm->avail_out) {
90
+        /* Exit if needs more in bytes and none available */
91
+        int needsInput;
92
+        switch (strm->state) {
93
+           case ADC_STATE_SHORTLOOK:
94
+           case ADC_STATE_LONGLOOK:
95
+               needsInput = 0;
96
+               break;
97
+           default:
98
+               needsInput = 1;
99
+               break;
100
+        }
101
+        if (needsInput && (strm->avail_in == 0)) {
102
+            break;
103
+        }
104
+        else {
105
+            didNothing = 0;
106
+        }
107
+
108
+        /* Find or execute statecode */
109
+        switch (strm->state) {
110
+            case ADC_STATE_GETTYPE: {
111
+                /* Grab action code */
112
+                bData = *(uint8_t *)(strm->next_in);
113
+                strm->next_in++;
114
+                strm->avail_in--;
115
+                if (bData & 0x80) {
116
+                    strm->state = ADC_STATE_RAWDATA;
117
+                    strm->offset = 0;
118
+                    strm->length = (bData & 0x7F) + 1;
119
+                }
120
+                else if (bData & 0x40) {
121
+                    strm->state = ADC_STATE_LONGOP2;
122
+                    strm->offset = 0;
123
+                    strm->length = (bData & 0x3F) + 4;
124
+                }
125
+                else {
126
+                    strm->state = ADC_STATE_SHORTOP;
127
+                    strm->offset = (bData & 0x3) * 0x100;
128
+                    strm->length = ((bData & 0x3C) >> 2) + 3;
129
+                }
130
+                adc_dbgmsg("adc_decompress: GETTYPE bData %x state %u offset %u length %u\n",
131
+                           bData, strm->state, strm->offset, strm->length);
132
+                break;
133
+           }
134
+           case ADC_STATE_LONGOP2: {
135
+                /* Grab first offset byte */
136
+                bData = *(uint8_t *)(strm->next_in);
137
+                strm->next_in++;
138
+                strm->avail_in--;
139
+                strm->offset = bData * 0x100;
140
+                strm->state = ADC_STATE_LONGOP1;
141
+                adc_dbgmsg("adc_decompress: LONGOP2 bData %x state %u offset %u length %u\n",
142
+                           bData, strm->state, strm->offset, strm->length);
143
+                break;
144
+           }
145
+           case ADC_STATE_LONGOP1: {
146
+                /* Grab second offset byte */
147
+                bData = *(uint8_t *)(strm->next_in);
148
+                strm->next_in++;
149
+                strm->avail_in--;
150
+                strm->offset += bData + 1;
151
+                strm->state = ADC_STATE_LONGLOOK;
152
+                adc_dbgmsg("adc_decompress: LONGOP1 bData %x state %u offset %u length %u\n",
153
+                           bData, strm->state, strm->offset, strm->length);
154
+                break;
155
+           }
156
+           case ADC_STATE_SHORTOP: {
157
+                /* Grab offset byte */
158
+                bData = *(uint8_t *)(strm->next_in);
159
+                strm->next_in++;
160
+                strm->avail_in--;
161
+                strm->offset += bData + 1;
162
+                strm->state = ADC_STATE_SHORTLOOK;
163
+                adc_dbgmsg("adc_decompress: SHORTOP bData %x state %u offset %u length %u\n",
164
+                           bData, strm->state, strm->offset, strm->length);
165
+                break;
166
+           }
167
+
168
+           case ADC_STATE_RAWDATA: {
169
+                /* Grab data */
170
+                adc_dbgmsg("adc_decompress: RAWDATA offset %u length %u\n", strm->offset, strm->length);
171
+                while ((strm->avail_in > 0) && (strm->avail_out > 0) && (strm->length > 0)) {
172
+                    bData = *(uint8_t *)(strm->next_in);
173
+                    strm->next_in++;
174
+                    strm->avail_in--;
175
+                    /* store to output */
176
+                    *(uint8_t *)(strm->next_out) = bData;
177
+                    strm->next_out++;
178
+                    strm->avail_out--;
179
+                    /* store to buffer */
180
+                    if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
181
+                        strm->curr = strm->buffer;
182
+                    }
183
+                    *(uint8_t *)strm->curr = bData;
184
+                    strm->curr++;
185
+                    if (strm->buffered < ADC_BUFF_SIZE) {
186
+                        strm->buffered++;
187
+                    }
188
+                    strm->length--;
189
+                }
190
+                if (strm->length == 0) {
191
+                    /* adc_dbgmsg("adc_decompress: RAWDATADONE buffered %u avail_in %u avail_out %u \n",
192
+                        strm->buffered, strm->avail_in, strm->avail_out); */
193
+                    strm->state = ADC_STATE_GETTYPE;
194
+                }
195
+                break;
196
+           }
197
+
198
+           case ADC_STATE_SHORTLOOK:
199
+           case ADC_STATE_LONGLOOK: {
200
+                /* Copy data */
201
+                adc_dbgmsg("adc_decompress: LOOKBACK offset %u length %u avail_in %u avail_out %u\n",
202
+                    strm->offset, strm->length, strm->avail_in, strm->avail_out);
203
+                while ((strm->avail_out > 0) && (strm->length > 0)) {
204
+                    /* state validation first */
205
+                    if (strm->offset > 0x10000) {
206
+                        cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
207
+                        return ADC_DATA_ERROR;
208
+                    }
209
+                    else if ((strm->state == ADC_STATE_SHORTLOOK) && (strm->offset > 0x400)) {
210
+                        cli_dbgmsg("adc_decompress: bad LOOKBACK offset %u\n", strm->offset);
211
+                        return ADC_DATA_ERROR;
212
+                    }
213
+                    if (strm->offset > strm->buffered) {
214
+                        cli_dbgmsg("adc_decompress: too large LOOKBACK offset %u\n", strm->offset);
215
+                        return ADC_DATA_ERROR;
216
+                    }
217
+                    /* retrieve byte */
218
+                    if (strm->curr >= (strm->buffer + ADC_BUFF_SIZE)) {
219
+                        strm->curr = strm->buffer;
220
+                    }
221
+                    if (strm->curr > (strm->buffer + strm->offset)) {
222
+                        bData = *(uint8_t *)(strm->curr - strm->offset);
223
+                    }
224
+                    else {
225
+                        bData = *(uint8_t *)(strm->curr + ADC_BUFF_SIZE - strm->offset);
226
+                    }
227
+                    /* store to output */
228
+                    *(uint8_t *)(strm->next_out) = bData;
229
+                    strm->next_out++;
230
+                    strm->avail_out--;
231
+                    /* store to buffer */
232
+                    *(uint8_t *)strm->curr = bData;
233
+                    strm->curr++;
234
+                    if (strm->buffered < ADC_BUFF_SIZE) {
235
+                        strm->buffered++;
236
+                    }
237
+                    strm->length--;
238
+                }
239
+                if (strm->length == 0) {
240
+                    strm->state = ADC_STATE_GETTYPE;
241
+                    /* adc_dbgmsg("adc_decompress: LOOKBACKDONE buffered %u avail_in %u avail_out %u \n",
242
+                        strm->buffered, strm->avail_in, strm->avail_out); */
243
+                }
244
+                break;
245
+            }
246
+
247
+            default: {
248
+                /* bad state */
249
+                cli_errmsg("adc_decompress: invalid state %u\n", strm->state);
250
+                return ADC_DATA_ERROR;
251
+            }
252
+        } /* end switch */
253
+    } /* end while */
254
+
255
+    /* There really isn't a terminator, just end of data */
256
+    if (didNothing && strm->avail_out) {
257
+        if (strm->state == ADC_STATE_GETTYPE) {
258
+            /* Nothing left to do */
259
+            return ADC_STREAM_END;
260
+        }
261
+        else {
262
+            /* Ended mid phrase */
263
+            cli_dbgmsg("adc_decompress: stream ended mid-phrase, state %u\n", strm->state);
264
+            return ADC_DATA_ERROR;
265
+        }
266
+    }
267
+    return ADC_OK;
268
+}
269
+
270
+/* Cleanup routine, frees buffer */
271
+int adc_decompressEnd(adc_stream *strm)
272
+{
273
+    if (strm == NULL) {
274
+        return ADC_IO_ERROR;
275
+    }
276
+    if (strm->state == ADC_STATE_UNINIT) {
277
+        return ADC_DATA_ERROR;
278
+    }
279
+
280
+    if (strm->buffer != NULL) {
281
+        free(strm->buffer);
282
+    }
283
+    strm->buffered = 0;
284
+    strm->state = ADC_STATE_UNINIT;
285
+    strm->length = 0;
286
+    strm->offset = 0;
287
+
288
+    return ADC_OK;
289
+}
290
+
0 291
new file mode 100644
... ...
@@ -0,0 +1,55 @@
0
+
1
+
2
+#ifndef CLAM_ADC_H
3
+#define CLAM_ADC_H
4
+
5
+struct adc_stream {
6
+    void *next_in;
7
+    size_t avail_in;
8
+    size_t total_in;
9
+
10
+    void *next_out;
11
+    size_t avail_out;
12
+    size_t total_out;
13
+
14
+    /* internals */
15
+    uint8_t *buffer;
16
+    uint8_t *curr;
17
+
18
+    uint32_t buffered;
19
+    uint16_t state;
20
+    uint16_t length;
21
+    uint32_t offset;
22
+};
23
+typedef struct adc_stream adc_stream;
24
+
25
+#define ADC_BUFF_SIZE 65536
26
+
27
+#define    ADC_MEM_ERROR -1
28
+#define    ADC_DATA_ERROR -2
29
+#define    ADC_IO_ERROR -3
30
+#define    ADC_OK 0
31
+#define    ADC_STREAM_END 1
32
+
33
+enum adc_state {
34
+    ADC_STATE_UNINIT = 0,
35
+    ADC_STATE_GETTYPE = 1,
36
+    ADC_STATE_RAWDATA = 2,
37
+    ADC_STATE_SHORTOP = 3,
38
+    ADC_STATE_LONGOP2 = 4,
39
+    ADC_STATE_LONGOP1 = 5,
40
+    ADC_STATE_SHORTLOOK = 6,
41
+    ADC_STATE_LONGLOOK = 7
42
+};
43
+
44
+/* Compression phrases
45
+ * store phrase - 1 byte header + data, first byte 0x80-0xFF, max length 0x80 (7 bits + 1), no offset
46
+ * short phrase - 2 byte header + data, first byte 0x00-0x3F, max length 0x12 (4 bits + 3), max offset 0x3FF (10 bits)
47
+ * long phrase  - 3 byte header + data, first byte 0x40-0x7F, max length 0x43 (6 bits + 4), max offset 0xFFFF (16 bits)
48
+ */
49
+
50
+int adc_decompressInit(adc_stream *strm);
51
+int adc_decompress(adc_stream *strm);
52
+int adc_decompressEnd(adc_stream *strm);
53
+
54
+#endif
... ...
@@ -54,9 +54,10 @@
54 54
 #include "dmg.h"
55 55
 #include "scanners.h"
56 56
 #include "sf_base64decode.h"
57
+#include "adc.h"
57 58
 
58
-// #define DEBUG_DMG_PARSE
59
-// #define DEBUG_DMG_BZIP
59
+/* #define DEBUG_DMG_PARSE */
60
+/* #define DEBUG_DMG_BZIP */
60 61
 
61 62
 #ifdef DEBUG_DMG_PARSE
62 63
 #  define dmg_parsemsg(...) cli_dbgmsg( __VA_ARGS__)
... ...
@@ -710,10 +711,84 @@ static int dmg_stripe_store(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mis
710 710
 /* Stripe handling: ADC block (type 0x80000004) */
711 711
 static int dmg_stripe_adc(cli_ctx *ctx, int fd, uint32_t index, struct dmg_mish_with_stripes *mish_set)
712 712
 {
713
-    /* Temporary stub */
714
-    cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 "\n", index);
715
-    /* Return as format error to prevent scan for now */
716
-    return CL_EFORMAT;
713
+    int ret = CL_CLEAN, adcret;
714
+    adc_stream strm;
715
+    size_t off = mish_set->stripes[index].dataOffset;
716
+    size_t len = mish_set->stripes[index].dataLength;
717
+    uint64_t size_so_far = 0;
718
+    uint64_t expected_len = mish_set->stripes[index].sectorCount * DMG_SECTOR_SIZE;
719
+    uint8_t obuf[BUFSIZ];
720
+
721
+    cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " initial len " STDu64 " expected len " STDu64 "\n",
722
+            index, len, expected_len);
723
+    if (len == 0)
724
+        return CL_CLEAN;
725
+
726
+    memset(&strm, 0, sizeof(strm));
727
+    strm.next_in = (void*)fmap_need_off_once(*ctx->fmap, off, len);
728
+    if (!strm.next_in) {
729
+        cli_warnmsg("dmg_stripe_adc: fmap need failed on stripe " STDu32 "\n", index);
730
+        return CL_EMAP;
731
+    }
732
+    strm.avail_in = len;
733
+    strm.next_out = obuf;
734
+    strm.avail_out = sizeof(obuf);
735
+
736
+    adcret = adc_decompressInit(&strm);
737
+    if(adcret != ADC_OK) {
738
+        cli_warnmsg("dmg_stripe_adc: adc_decompressInit failed\n");
739
+        return CL_EMEM;
740
+    }
741
+
742
+    while(adcret == ADC_OK) {
743
+        int written;
744
+        if (size_so_far > expected_len) {
745
+            cli_warnmsg("dmg_stripe_adc: expected size exceeded!\n");
746
+            adc_decompressEnd(&strm);
747
+            return CL_EFORMAT;
748
+        }
749
+        adcret = adc_decompress(&strm);
750
+        switch(adcret) {
751
+            case ADC_OK:
752
+                if(strm.avail_out == 0) {
753
+                    if ((written=cli_writen(fd, obuf, sizeof(obuf)))!=sizeof(obuf)) {
754
+                        cli_errmsg("dmg_stripe_adc: failed write to output file\n");
755
+                        adc_decompressEnd(&strm);
756
+                        return CL_EWRITE;
757
+                    }
758
+                    size_so_far += written;
759
+                    strm.next_out = obuf;
760
+                    strm.avail_out = sizeof(obuf);
761
+                }
762
+                continue;
763
+            case ADC_STREAM_END:
764
+            default:
765
+                written = sizeof(obuf) - strm.avail_out;
766
+                if (written) {
767
+                    if ((cli_writen(fd, obuf, written))!=written) {
768
+                        cli_errmsg("dmg_stripe_adc: failed write to output file\n");
769
+                        adc_decompressEnd(&strm);
770
+                        return CL_EWRITE;
771
+                    }
772
+                    size_so_far += written;
773
+                    strm.next_out = obuf;
774
+                    strm.avail_out = sizeof(obuf);
775
+                }
776
+                if (adcret == Z_STREAM_END)
777
+                    break;
778
+                cli_dbgmsg("dmg_stripe_adc: after writing " STDu64 " bytes, "
779
+                           "got error %d decompressing stripe " STDu32 "\n",
780
+                           size_so_far, adcret, index);
781
+                adc_decompressEnd(&strm);
782
+                return CL_EFORMAT;
783
+        }
784
+        break;
785
+    }
786
+
787
+    adc_decompressEnd(&strm);
788
+    cli_dbgmsg("dmg_stripe_adc: stripe " STDu32 " actual len " STDu64 " expected len " STDu64 "\n",
789
+            index, size_so_far, expected_len);
790
+    return CL_CLEAN;
717 791
 }
718 792
 
719 793
 /* Stripe handling: deflate block (type 0x80000005) */