mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2026-05-06 22:55:49 -04:00
rewrite file/folder handling code as a complete and proper solution for bb#730
git-svn: trunk@3542
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
Fri Jan 25 16:35:34 CET 2008 (tk)
|
||||
---------------------------------
|
||||
* libclamav/cab.[ch]: rewrite file/folder handling code as a complete
|
||||
and proper solution for bb#730
|
||||
|
||||
Fri Jan 25 12:43:30 CET 2008 (tk)
|
||||
---------------------------------
|
||||
* libclamav/cab.c: improve performance of cabinet extractor (bb#730)
|
||||
|
||||
172
libclamav/cab.c
172
libclamav/cab.c
@@ -1,4 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Sourcefire, Inc.
|
||||
* Author: Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* This code is based on the work of Stuart Caie and the official
|
||||
@@ -157,6 +160,20 @@ void cab_free(struct cab_archive *cab)
|
||||
struct cab_file *file;
|
||||
|
||||
|
||||
if(cab->state) {
|
||||
switch(cab->state->cmethod & 0x000f) {
|
||||
case 0x0001:
|
||||
mszip_free(cab->state->stream);
|
||||
break;
|
||||
case 0x0002:
|
||||
qtm_free(cab->state->stream);
|
||||
break;
|
||||
case 0x0003:
|
||||
lzx_free(cab->state->stream);
|
||||
}
|
||||
free(cab->state);
|
||||
}
|
||||
|
||||
while(cab->folders) {
|
||||
folder = cab->folders;
|
||||
cab->folders = cab->folders->next;
|
||||
@@ -505,36 +522,36 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes)
|
||||
|
||||
todo = bytes;
|
||||
while(todo > 0) {
|
||||
left = file->state->end - file->state->pt;
|
||||
left = file->cab->state->end - file->cab->state->pt;
|
||||
|
||||
if(left) {
|
||||
if(left > todo)
|
||||
left = todo;
|
||||
|
||||
memcpy(buffer, file->state->pt, left);
|
||||
file->state->pt += left;
|
||||
memcpy(buffer, file->cab->state->pt, left);
|
||||
file->cab->state->pt += left;
|
||||
buffer += left;
|
||||
todo -= left;
|
||||
|
||||
} else {
|
||||
if(file->state->blknum++ >= file->folder->nblocks) {
|
||||
if(file->cab->state->blknum++ >= file->folder->nblocks) {
|
||||
file->error = CL_EFORMAT;
|
||||
break;
|
||||
}
|
||||
|
||||
file->error = cab_read_block(file->fd, file->state, file->cab->resdata);
|
||||
file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata);
|
||||
if(file->error)
|
||||
return -1;
|
||||
|
||||
if((file->folder->cmethod & 0x000f) == 0x0002) /* Quantum hack */
|
||||
*file->state->end++ = 0xff;
|
||||
*file->cab->state->end++ = 0xff;
|
||||
|
||||
if(file->state->blknum >= file->folder->nblocks) {
|
||||
if(file->cab->state->blknum >= file->folder->nblocks) {
|
||||
if((file->folder->cmethod & 0x000f) == 0x0003) { /* LZX hack */
|
||||
lzx_set_output_length(file->state->stream, (off_t) ((file->state->blknum - 1) * CAB_BLOCKMAX + file->state->outlen));
|
||||
lzx_set_output_length(file->cab->state->stream, (off_t) ((file->cab->state->blknum - 1) * CAB_BLOCKMAX + file->cab->state->outlen));
|
||||
}
|
||||
} else {
|
||||
if(file->state->outlen != CAB_BLOCKMAX) {
|
||||
if(file->cab->state->outlen != CAB_BLOCKMAX) {
|
||||
cli_dbgmsg("cab_read: WARNING: partial data block\n");
|
||||
}
|
||||
}
|
||||
@@ -584,9 +601,52 @@ static int cab_unstore(struct cab_file *file, int bytes, uint8_t wflag)
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
#define CAB_CHGFOLDER \
|
||||
if(!file->cab->actfol || (file->folder != file->cab->actfol)) { \
|
||||
if(file->cab->state) { \
|
||||
switch(file->cab->state->cmethod & 0x000f) { \
|
||||
case 0x0001: \
|
||||
mszip_free(file->cab->state->stream); \
|
||||
break; \
|
||||
case 0x0002: \
|
||||
qtm_free(file->cab->state->stream); \
|
||||
break; \
|
||||
case 0x0003: \
|
||||
lzx_free(file->cab->state->stream); \
|
||||
} \
|
||||
free(file->cab->state); \
|
||||
} \
|
||||
file->cab->actfol = file->folder; \
|
||||
if(lseek(file->fd, file->folder->offset, SEEK_SET) == -1) { \
|
||||
cli_dbgmsg("cab_extract: Can't lseek to %u\n", (unsigned int) file->folder->offset); \
|
||||
return CL_EFORMAT; /* truncated file? */ \
|
||||
} \
|
||||
file->cab->state = (struct cab_state *) cli_calloc(1, sizeof(struct cab_state)); \
|
||||
if(!file->cab->state) { \
|
||||
cli_errmsg("cab_extract: Can't allocate memory for internal state\n"); \
|
||||
return CL_EMEM; \
|
||||
} \
|
||||
file->cab->state->cmethod = file->folder->cmethod; \
|
||||
switch(file->folder->cmethod & 0x000f) { \
|
||||
case 0x0001: \
|
||||
file->cab->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read); \
|
||||
break; \
|
||||
case 0x0002: \
|
||||
file->cab->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read); \
|
||||
break; \
|
||||
case 0x0003: \
|
||||
file->cab->state->stream = (struct lzx_stream *) lzx_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read); \
|
||||
} \
|
||||
if(!file->cab->state->stream) { \
|
||||
free(file->cab->state); \
|
||||
close(file->ofd); \
|
||||
return CL_EMSCAB; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
int cab_extract(struct cab_file *file, const char *name)
|
||||
{
|
||||
struct cab_folder *folder;
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -595,26 +655,15 @@ int cab_extract(struct cab_file *file, const char *name)
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
if(!(folder = file->folder)) {
|
||||
if(!file->folder) {
|
||||
cli_errmsg("cab_extract: file->folder == NULL\n");
|
||||
return CL_ENULLARG;
|
||||
}
|
||||
|
||||
if(lseek(file->fd, file->folder->offset, SEEK_SET) == -1) {
|
||||
cli_errmsg("cab_extract: Can't lseek to %u\n", (unsigned int) file->folder->offset);
|
||||
return CL_EIO;
|
||||
}
|
||||
|
||||
file->state = (struct cab_state *) cli_calloc(1, sizeof(struct cab_state));
|
||||
if(!file->state) {
|
||||
cli_errmsg("cab_extract: Can't allocate memory for internal state\n");
|
||||
return CL_EIO;
|
||||
}
|
||||
|
||||
file->ofd = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
|
||||
if(file->ofd == -1) {
|
||||
cli_errmsg("cab_extract: Can't open file %s in write mode\n", name);
|
||||
free(file->state);
|
||||
free(file->cab->state);
|
||||
return CL_EIO;
|
||||
}
|
||||
|
||||
@@ -628,84 +677,20 @@ int cab_extract(struct cab_file *file, const char *name)
|
||||
|
||||
case 0x0001: /* MSZIP */
|
||||
cli_dbgmsg("CAB: Compression method: MSZIP\n");
|
||||
file->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
ret = mszip_decompress(file->state->stream, file->length);
|
||||
mszip_free(file->state->stream);
|
||||
if(ret < 0 && file->offset > 0) {
|
||||
memset(file->state, 0, sizeof(struct cab_state));
|
||||
file->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
((struct mszip_stream *) file->state->stream)->wflag = 0;
|
||||
if(mszip_decompress(file->state->stream, file->offset) == CL_SUCCESS) {
|
||||
((struct mszip_stream *) file->state->stream)->wflag = 1;
|
||||
ret = mszip_decompress(file->state->stream, file->length);
|
||||
}
|
||||
mszip_free(file->state->stream);
|
||||
}
|
||||
CAB_CHGFOLDER;
|
||||
ret = mszip_decompress(file->cab->state->stream, file->length);
|
||||
break;
|
||||
|
||||
case 0x0002: /* QUANTUM */
|
||||
cli_dbgmsg("CAB: Compression method: QUANTUM\n");
|
||||
file->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
ret = qtm_decompress(file->state->stream, file->length);
|
||||
qtm_free(file->state->stream);
|
||||
if(ret < 0 && file->offset > 0) {
|
||||
memset(file->state, 0, sizeof(struct cab_state));
|
||||
file->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
((struct qtm_stream *) file->state->stream)->wflag = 0;
|
||||
if(qtm_decompress(file->state->stream, file->offset) == CL_SUCCESS) {
|
||||
((struct qtm_stream *) file->state->stream)->wflag = 1;
|
||||
ret = qtm_decompress(file->state->stream, file->length);
|
||||
}
|
||||
qtm_free(file->state->stream);
|
||||
}
|
||||
CAB_CHGFOLDER;
|
||||
ret = qtm_decompress(file->cab->state->stream, file->length);
|
||||
break;
|
||||
|
||||
case 0x0003: /* LZX */
|
||||
cli_dbgmsg("CAB: Compression method: LZX\n");
|
||||
file->state->stream = (struct lzx_stream *) lzx_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
if(file->offset > 0) {
|
||||
((struct lzx_stream *) file->state->stream)->wflag = 0;
|
||||
ret = lzx_decompress(file->state->stream, file->offset);
|
||||
((struct lzx_stream *) file->state->stream)->wflag = 1;
|
||||
if(ret < 0) {
|
||||
lzx_free(file->state->stream);
|
||||
memset(file->state, 0, sizeof(struct cab_state));
|
||||
file->state->stream = (struct lzx_stream *) lzx_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read);
|
||||
if(!file->state->stream) {
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
return CL_EMSCAB;
|
||||
}
|
||||
lseek(file->fd, file->folder->offset, SEEK_SET);
|
||||
}
|
||||
}
|
||||
ret = lzx_decompress(file->state->stream, file->length);
|
||||
lzx_free(file->state->stream);
|
||||
CAB_CHGFOLDER;
|
||||
ret = lzx_decompress(file->cab->state->stream, file->length);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -713,7 +698,6 @@ int cab_extract(struct cab_file *file, const char *name)
|
||||
ret = CL_EFORMAT;
|
||||
}
|
||||
|
||||
free(file->state);
|
||||
close(file->ofd);
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2008 Sourcefire, Inc.
|
||||
* Author: Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,8 +29,9 @@
|
||||
#define CAB_INPUTMAX (CAB_BLOCKMAX + 6144)
|
||||
|
||||
struct cab_archive {
|
||||
struct cab_folder *folders;
|
||||
struct cab_folder *folders, *actfol;
|
||||
struct cab_file *files;
|
||||
struct cab_state *state;
|
||||
uint32_t length;
|
||||
uint16_t nfolders;
|
||||
uint16_t nfiles;
|
||||
@@ -43,6 +47,7 @@ struct cab_state {
|
||||
uint16_t blklen;
|
||||
uint16_t outlen;
|
||||
uint16_t blknum;
|
||||
uint16_t cmethod;
|
||||
};
|
||||
|
||||
struct cab_file {
|
||||
@@ -55,7 +60,6 @@ struct cab_file {
|
||||
struct cab_folder *folder;
|
||||
struct cab_file *next;
|
||||
struct cab_archive *cab;
|
||||
struct cab_state *state;
|
||||
uint16_t attribs;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user