192 lines
5.3 KiB
C
192 lines
5.3 KiB
C
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <zlib.h>
|
|
#include <bzlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/mman.h>
|
|
#include "endian.h"
|
|
#include "md5.h"
|
|
#include "jigdo.h"
|
|
|
|
static int ungzip_data_block(char *in_buf, INT64 in_len, char *out_buf, INT64 out_len, FILE *logfile)
|
|
{
|
|
int error = 0;
|
|
z_stream uc_stream;
|
|
|
|
uc_stream.zalloc = NULL;
|
|
uc_stream.zfree = NULL;
|
|
uc_stream.opaque = NULL;
|
|
uc_stream.next_in = (unsigned char *)in_buf;
|
|
uc_stream.avail_in = in_len;
|
|
|
|
error = inflateInit(&uc_stream);
|
|
if (Z_OK != error)
|
|
{
|
|
fprintf(logfile, "ungzip_data_block: failed to init, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
uc_stream.next_out = (unsigned char *)out_buf;
|
|
uc_stream.avail_out = out_len;
|
|
|
|
error = inflate(&uc_stream, Z_FINISH);
|
|
if (Z_OK != error && Z_STREAM_END != error)
|
|
{
|
|
fprintf(logfile, "ungzip_data_block: failed to decompress, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
error = inflateEnd(&uc_stream);
|
|
if (Z_OK != error)
|
|
{
|
|
fprintf(logfile, "ungzip_data_block: failed to end, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int unbzip2_data_block(char *in_buf, INT64 in_len, char *out_buf, INT64 out_len, FILE *logfile)
|
|
{
|
|
int error = 0;
|
|
bz_stream uc_stream;
|
|
|
|
uc_stream.bzalloc = NULL;
|
|
uc_stream.bzfree = NULL;
|
|
uc_stream.opaque = NULL;
|
|
uc_stream.next_in = in_buf;
|
|
uc_stream.avail_in = in_len;
|
|
|
|
error = BZ2_bzDecompressInit(&uc_stream, 0, 0);
|
|
if (BZ_OK != error)
|
|
{
|
|
fprintf(logfile, "unbzip2_data_block: failed to init, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
uc_stream.next_out = out_buf;
|
|
uc_stream.avail_out = out_len;
|
|
|
|
error = BZ2_bzDecompress(&uc_stream);
|
|
if (BZ_OK != error && BZ_STREAM_END != error)
|
|
{
|
|
fprintf(logfile, "unbzip2_data_block: failed to decompress, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
error = BZ2_bzDecompressEnd(&uc_stream);
|
|
if (BZ_OK != error)
|
|
{
|
|
fprintf(logfile, "unbzip2_data_block: failed to end, error %d\n", error);
|
|
return EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int read_data_block(FILE *template_file, FILE *logfile, zip_state_t *zip_state)
|
|
{
|
|
char inbuf[1024];
|
|
INT64 i = 0;
|
|
static INT64 template_offset = -1;
|
|
INT64 compressed_len = 0;
|
|
INT64 uncompressed_len = 0;
|
|
char *comp_buf = NULL;
|
|
int read_num = 0;
|
|
int error = 0;
|
|
int compress_type = COMP_GZIP; /* Sensible default */
|
|
|
|
/* If we've just started on this template file, find the first
|
|
* compressed data block */
|
|
if (-1 == template_offset)
|
|
{
|
|
fseek(template_file, 0, SEEK_SET);
|
|
fread(inbuf, sizeof(inbuf), 1, template_file);
|
|
for (i = 0; i < sizeof(inbuf); i++)
|
|
{
|
|
if (!strncmp(&inbuf[i], "DATA", 4) || !strncmp(&inbuf[i], "BZIP", 4))
|
|
{
|
|
template_offset = i;
|
|
break;
|
|
}
|
|
}
|
|
if (-1 == template_offset)
|
|
{
|
|
fprintf(logfile, "Unable to locate DATA block in template (offset %lld)\n",
|
|
template_offset);
|
|
return EINVAL;
|
|
}
|
|
}
|
|
|
|
/* Seek to the beginning of the (first/next) compressed data
|
|
* block, identify the compression type then decompress using the
|
|
* appropriate algorithm */
|
|
fseek(template_file, template_offset, SEEK_SET);
|
|
fread(inbuf, 16, 1, template_file);
|
|
if (!strncmp(inbuf, "DATA", 4))
|
|
compress_type = COMP_GZIP;
|
|
else if (!strncmp(inbuf, "BZIP", 4))
|
|
compress_type = COMP_BZIP2;
|
|
else
|
|
{
|
|
fprintf(logfile, "Unable to locate DATA block in template (offset %lld)\n",
|
|
template_offset);
|
|
return EINVAL;
|
|
}
|
|
|
|
compressed_len = read_le48((unsigned char *)&inbuf[4]);
|
|
uncompressed_len = read_le48((unsigned char *)&inbuf[10]);
|
|
comp_buf = calloc(1, compressed_len);
|
|
if (!comp_buf)
|
|
{
|
|
fprintf(logfile, "Unable to locate DATA block in template (offset %lld)\n",
|
|
template_offset);
|
|
return ENOMEM;
|
|
}
|
|
|
|
zip_state->data_buf = calloc(1, uncompressed_len);
|
|
if (!zip_state->data_buf)
|
|
{
|
|
fprintf(logfile, "Unable to allocate %lld bytes for decompression\n",
|
|
uncompressed_len);
|
|
return ENOMEM;
|
|
}
|
|
|
|
read_num = fread(comp_buf, compressed_len, 1, template_file);
|
|
if (0 == read_num)
|
|
{
|
|
fprintf(logfile, "Unable to read %lld bytes for decompression\n",
|
|
uncompressed_len);
|
|
return EIO;
|
|
}
|
|
|
|
switch (compress_type)
|
|
{
|
|
case COMP_GZIP:
|
|
error = ungzip_data_block(comp_buf, compressed_len,
|
|
zip_state->data_buf, uncompressed_len, logfile);
|
|
break;
|
|
case COMP_BZIP2:
|
|
error = unbzip2_data_block(comp_buf, compressed_len,
|
|
zip_state->data_buf, uncompressed_len, logfile);
|
|
break;
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
fprintf(logfile, "Unable to decompress data block, error %d\n", error);
|
|
return error;
|
|
}
|
|
|
|
template_offset += compressed_len;
|
|
zip_state->buf_size = uncompressed_len;
|
|
zip_state->offset_in_curr_buf = 0;
|
|
free (comp_buf);
|
|
return 0;
|
|
}
|