/* 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 */
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}