/* Included from initramfs et al code */ STATIC int INIT gunzip(unsigned char *buf, int len, int(*fill)(void*, unsigned int), int(*flush)(void*, unsigned int), unsigned char *out_buf, int *pos, void(*error_fn)(char *x)) { u8 *zbuf; struct z_stream_s *strm; int rc; size_t out_len; set_error_fn(error_fn); rc = -1; if (flush) { out_len = 0x8100; /* 32 K */ out_buf = malloc(out_len); } else { out_len = 0x7fffffff; /* no limit */ } if (!out_buf) { error("Out of memory while allocating output buffer"); goto gunzip_nomem1; } if (buf) zbuf = buf; else { zbuf = malloc(INBUF_LEN); len = 0; } if (!zbuf) { error("Out of memory while allocating input buffer"); goto gunzip_nomem2; } strm = malloc(sizeof(*strm)); if (strm == NULL) { error("Out of memory while allocating z_stream"); goto gunzip_nomem3; } strm->workspace = malloc(flush ? zlib_inflate_workspacesize() : sizeof(struct inflate_state)); if (strm->workspace == NULL) { error("Out of memory while allocating workspace"); goto gunzip_nomem4; } if (len == 0) len = fill(zbuf, INBUF_LEN); /* verify the gzip header */ if (len < 10 || zbuf[0] != 0x1f || zbuf[1] != 0x8b || zbuf[2] != 0x08) { if (pos) *pos = 0; error("Not a gzip file"); goto gunzip_5; } /* skip over gzip header (1f,8b,08... 10 bytes total + * possible asciz filename) */ strm->next_in = zbuf + 10; /* skip over asciz filename */ if (zbuf[3] & 0x8) { while (strm->next_in[0]) strm->next_in++; strm->next_in++; } strm->avail_in = len - 10; strm->next_out = out_buf; strm->avail_out = out_len; rc = zlib_inflateInit2(strm, -MAX_WBITS); if (!flush) { WS(strm)->inflate_state.wsize = 0; WS(strm)->inflate_state.window = NULL; } while (rc == Z_OK) { if (strm->avail_in == 0) { /* TODO: handle case where both pos and fill are set */ len = fill(zbuf, INBUF_LEN); if (len < 0) { rc = -1; error("read error"); break; } strm->next_in = zbuf; strm->avail_in = len; } rc = zlib_inflate(strm, 0); /* Write any data generated */ if (flush && strm->next_out > out_buf) { int l = strm->next_out - out_buf; if (l != flush(out_buf, l)) { rc = -1; error("write error"); break; } strm->next_out = out_buf; strm->avail_out = out_len; } /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ if (rc == Z_STREAM_END) { rc = 0; break; } else if (rc != Z_OK) { error("uncompression error"); rc = -1; } } zlib_inflateEnd(strm); if (pos) /* add + 8 to skip over trailer */ *pos = strm->next_in - zbuf+8; gunzip_5: free(strm->workspace); gunzip_nomem4: free(strm); gunzip_nomem3: if (!buf) free(zbuf); gunzip_nomem2: if (flush) free(out_buf); gunzip_nomem1: return rc; /* returns Z_OK (0) if successful */ }
STATIC inline int INIT unlzo(u8 *input, int in_len, int (*fill) (void *, unsigned int), int (*flush) (void *, unsigned int), u8 *output, int *posp, void (*error_fn) (char *x)) { u8 skip = 0, r = 0; u32 src_len, dst_len; size_t tmp; u8 *in_buf, *in_buf_save, *out_buf; int ret = -1; set_error_fn(error_fn); if (output) { out_buf = output; } else if (!flush) { error("NULL output pointer and no flush function provided"); goto exit; } else { out_buf = malloc(LZO_BLOCK_SIZE); if (!out_buf) { error("Could not allocate output buffer"); goto exit; } } if (input && fill) { error("Both input pointer and fill function provided, don't know what to do"); goto exit_1; } else if (input) { in_buf = input; } else if (!fill || !posp) { error("NULL input pointer and missing position pointer or fill function"); goto exit_1; } else { in_buf = malloc(lzo1x_worst_compress(LZO_BLOCK_SIZE)); if (!in_buf) { error("Could not allocate input buffer"); goto exit_1; } } in_buf_save = in_buf; if (posp) *posp = 0; if (fill) fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE)); if (!parse_header(input, &skip)) { error("invalid header"); goto exit_2; } in_buf += skip; if (posp) *posp = skip; for (;;) { /* read uncompressed block size */ dst_len = get_unaligned_be32(in_buf); in_buf += 4; /* exit if last block */ if (dst_len == 0) { if (posp) *posp += 4; break; } if (dst_len > LZO_BLOCK_SIZE) { error("dest len longer than block size"); goto exit_2; } /* read compressed block size, and skip block checksum info */ src_len = get_unaligned_be32(in_buf); in_buf += 8; if (src_len <= 0 || src_len > dst_len) { error("file corrupted"); goto exit_2; } /* decompress */ tmp = dst_len; /* When the input data is not compressed at all, * lzo1x_decompress_safe will fail, so call memcpy() * instead */ if (unlikely(dst_len == src_len)) memcpy(out_buf, in_buf, src_len); else { r = lzo1x_decompress_safe((u8 *) in_buf, src_len, out_buf, &tmp); if (r != LZO_E_OK || dst_len != tmp) { error("Compressed data violation"); goto exit_2; } } if (flush) flush(out_buf, dst_len); if (output) out_buf += dst_len; if (posp) *posp += src_len + 12; if (fill) { in_buf = in_buf_save; fill(in_buf, lzo1x_worst_compress(LZO_BLOCK_SIZE)); } else in_buf += src_len; } ret = 0; exit_2: if (!input) free(in_buf); exit_1: if (!output) free(out_buf); exit: return ret; }
static void expect_errors(const error_t *lines) { fail_unless(orig_error_fn == NULL); orig_error_fn = set_error_fn(test_error_fn); error_lines = lines; }