git-svn: trunk@3542
Tomasz Kojm authored on 2008/01/26 00:58:25... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Fri Jan 25 16:35:34 CET 2008 (tk) |
|
2 |
+--------------------------------- |
|
3 |
+ * libclamav/cab.[ch]: rewrite file/folder handling code as a complete |
|
4 |
+ and proper solution for bb#730 |
|
5 |
+ |
|
1 | 6 |
Fri Jan 25 12:43:30 CET 2008 (tk) |
2 | 7 |
--------------------------------- |
3 | 8 |
* libclamav/cab.c: improve performance of cabinet extractor (bb#730) |
... | ... |
@@ -1,4 +1,7 @@ |
1 | 1 |
/* |
2 |
+ * Copyright (C) 2007-2008 Sourcefire, Inc. |
|
3 |
+ * Author: Tomasz Kojm <tkojm@clamav.net> |
|
4 |
+ * |
|
2 | 5 |
* Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net> |
3 | 6 |
* |
4 | 7 |
* This code is based on the work of Stuart Caie and the official |
... | ... |
@@ -157,6 +160,20 @@ void cab_free(struct cab_archive *cab) |
157 | 157 |
struct cab_file *file; |
158 | 158 |
|
159 | 159 |
|
160 |
+ if(cab->state) { |
|
161 |
+ switch(cab->state->cmethod & 0x000f) { |
|
162 |
+ case 0x0001: |
|
163 |
+ mszip_free(cab->state->stream); |
|
164 |
+ break; |
|
165 |
+ case 0x0002: |
|
166 |
+ qtm_free(cab->state->stream); |
|
167 |
+ break; |
|
168 |
+ case 0x0003: |
|
169 |
+ lzx_free(cab->state->stream); |
|
170 |
+ } |
|
171 |
+ free(cab->state); |
|
172 |
+ } |
|
173 |
+ |
|
160 | 174 |
while(cab->folders) { |
161 | 175 |
folder = cab->folders; |
162 | 176 |
cab->folders = cab->folders->next; |
... | ... |
@@ -505,36 +522,36 @@ static int cab_read(struct cab_file *file, unsigned char *buffer, int bytes) |
505 | 505 |
|
506 | 506 |
todo = bytes; |
507 | 507 |
while(todo > 0) { |
508 |
- left = file->state->end - file->state->pt; |
|
508 |
+ left = file->cab->state->end - file->cab->state->pt; |
|
509 | 509 |
|
510 | 510 |
if(left) { |
511 | 511 |
if(left > todo) |
512 | 512 |
left = todo; |
513 | 513 |
|
514 |
- memcpy(buffer, file->state->pt, left); |
|
515 |
- file->state->pt += left; |
|
514 |
+ memcpy(buffer, file->cab->state->pt, left); |
|
515 |
+ file->cab->state->pt += left; |
|
516 | 516 |
buffer += left; |
517 | 517 |
todo -= left; |
518 | 518 |
|
519 | 519 |
} else { |
520 |
- if(file->state->blknum++ >= file->folder->nblocks) { |
|
520 |
+ if(file->cab->state->blknum++ >= file->folder->nblocks) { |
|
521 | 521 |
file->error = CL_EFORMAT; |
522 | 522 |
break; |
523 | 523 |
} |
524 | 524 |
|
525 |
- file->error = cab_read_block(file->fd, file->state, file->cab->resdata); |
|
525 |
+ file->error = cab_read_block(file->fd, file->cab->state, file->cab->resdata); |
|
526 | 526 |
if(file->error) |
527 | 527 |
return -1; |
528 | 528 |
|
529 | 529 |
if((file->folder->cmethod & 0x000f) == 0x0002) /* Quantum hack */ |
530 |
- *file->state->end++ = 0xff; |
|
530 |
+ *file->cab->state->end++ = 0xff; |
|
531 | 531 |
|
532 |
- if(file->state->blknum >= file->folder->nblocks) { |
|
532 |
+ if(file->cab->state->blknum >= file->folder->nblocks) { |
|
533 | 533 |
if((file->folder->cmethod & 0x000f) == 0x0003) { /* LZX hack */ |
534 |
- lzx_set_output_length(file->state->stream, (off_t) ((file->state->blknum - 1) * CAB_BLOCKMAX + file->state->outlen)); |
|
534 |
+ lzx_set_output_length(file->cab->state->stream, (off_t) ((file->cab->state->blknum - 1) * CAB_BLOCKMAX + file->cab->state->outlen)); |
|
535 | 535 |
} |
536 | 536 |
} else { |
537 |
- if(file->state->outlen != CAB_BLOCKMAX) { |
|
537 |
+ if(file->cab->state->outlen != CAB_BLOCKMAX) { |
|
538 | 538 |
cli_dbgmsg("cab_read: WARNING: partial data block\n"); |
539 | 539 |
} |
540 | 540 |
} |
... | ... |
@@ -584,9 +601,52 @@ static int cab_unstore(struct cab_file *file, int bytes, uint8_t wflag) |
584 | 584 |
return CL_SUCCESS; |
585 | 585 |
} |
586 | 586 |
|
587 |
+#define CAB_CHGFOLDER \ |
|
588 |
+ if(!file->cab->actfol || (file->folder != file->cab->actfol)) { \ |
|
589 |
+ if(file->cab->state) { \ |
|
590 |
+ switch(file->cab->state->cmethod & 0x000f) { \ |
|
591 |
+ case 0x0001: \ |
|
592 |
+ mszip_free(file->cab->state->stream); \ |
|
593 |
+ break; \ |
|
594 |
+ case 0x0002: \ |
|
595 |
+ qtm_free(file->cab->state->stream); \ |
|
596 |
+ break; \ |
|
597 |
+ case 0x0003: \ |
|
598 |
+ lzx_free(file->cab->state->stream); \ |
|
599 |
+ } \ |
|
600 |
+ free(file->cab->state); \ |
|
601 |
+ } \ |
|
602 |
+ file->cab->actfol = file->folder; \ |
|
603 |
+ if(lseek(file->fd, file->folder->offset, SEEK_SET) == -1) { \ |
|
604 |
+ cli_dbgmsg("cab_extract: Can't lseek to %u\n", (unsigned int) file->folder->offset); \ |
|
605 |
+ return CL_EFORMAT; /* truncated file? */ \ |
|
606 |
+ } \ |
|
607 |
+ file->cab->state = (struct cab_state *) cli_calloc(1, sizeof(struct cab_state)); \ |
|
608 |
+ if(!file->cab->state) { \ |
|
609 |
+ cli_errmsg("cab_extract: Can't allocate memory for internal state\n"); \ |
|
610 |
+ return CL_EMEM; \ |
|
611 |
+ } \ |
|
612 |
+ file->cab->state->cmethod = file->folder->cmethod; \ |
|
613 |
+ switch(file->folder->cmethod & 0x000f) { \ |
|
614 |
+ case 0x0001: \ |
|
615 |
+ file->cab->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read); \ |
|
616 |
+ break; \ |
|
617 |
+ case 0x0002: \ |
|
618 |
+ file->cab->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read); \ |
|
619 |
+ break; \ |
|
620 |
+ case 0x0003: \ |
|
621 |
+ 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); \ |
|
622 |
+ } \ |
|
623 |
+ if(!file->cab->state->stream) { \ |
|
624 |
+ free(file->cab->state); \ |
|
625 |
+ close(file->ofd); \ |
|
626 |
+ return CL_EMSCAB; \ |
|
627 |
+ } \ |
|
628 |
+ } |
|
629 |
+ |
|
630 |
+ |
|
587 | 631 |
int cab_extract(struct cab_file *file, const char *name) |
588 | 632 |
{ |
589 |
- struct cab_folder *folder; |
|
590 | 633 |
int ret; |
591 | 634 |
|
592 | 635 |
|
... | ... |
@@ -595,26 +655,15 @@ int cab_extract(struct cab_file *file, const char *name) |
595 | 595 |
return CL_ENULLARG; |
596 | 596 |
} |
597 | 597 |
|
598 |
- if(!(folder = file->folder)) { |
|
598 |
+ if(!file->folder) { |
|
599 | 599 |
cli_errmsg("cab_extract: file->folder == NULL\n"); |
600 | 600 |
return CL_ENULLARG; |
601 | 601 |
} |
602 | 602 |
|
603 |
- if(lseek(file->fd, file->folder->offset, SEEK_SET) == -1) { |
|
604 |
- cli_errmsg("cab_extract: Can't lseek to %u\n", (unsigned int) file->folder->offset); |
|
605 |
- return CL_EIO; |
|
606 |
- } |
|
607 |
- |
|
608 |
- file->state = (struct cab_state *) cli_calloc(1, sizeof(struct cab_state)); |
|
609 |
- if(!file->state) { |
|
610 |
- cli_errmsg("cab_extract: Can't allocate memory for internal state\n"); |
|
611 |
- return CL_EIO; |
|
612 |
- } |
|
613 |
- |
|
614 | 603 |
file->ofd = open(name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU); |
615 | 604 |
if(file->ofd == -1) { |
616 | 605 |
cli_errmsg("cab_extract: Can't open file %s in write mode\n", name); |
617 |
- free(file->state); |
|
606 |
+ free(file->cab->state); |
|
618 | 607 |
return CL_EIO; |
619 | 608 |
} |
620 | 609 |
|
... | ... |
@@ -628,84 +677,20 @@ int cab_extract(struct cab_file *file, const char *name) |
628 | 628 |
|
629 | 629 |
case 0x0001: /* MSZIP */ |
630 | 630 |
cli_dbgmsg("CAB: Compression method: MSZIP\n"); |
631 |
- file->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read); |
|
632 |
- if(!file->state->stream) { |
|
633 |
- free(file->state); |
|
634 |
- close(file->ofd); |
|
635 |
- return CL_EMSCAB; |
|
636 |
- } |
|
637 |
- ret = mszip_decompress(file->state->stream, file->length); |
|
638 |
- mszip_free(file->state->stream); |
|
639 |
- if(ret < 0 && file->offset > 0) { |
|
640 |
- memset(file->state, 0, sizeof(struct cab_state)); |
|
641 |
- file->state->stream = (struct mszip_stream *) mszip_init(file->fd, file->ofd, 4096, 1, file, &cab_read); |
|
642 |
- if(!file->state->stream) { |
|
643 |
- free(file->state); |
|
644 |
- close(file->ofd); |
|
645 |
- return CL_EMSCAB; |
|
646 |
- } |
|
647 |
- ((struct mszip_stream *) file->state->stream)->wflag = 0; |
|
648 |
- if(mszip_decompress(file->state->stream, file->offset) == CL_SUCCESS) { |
|
649 |
- ((struct mszip_stream *) file->state->stream)->wflag = 1; |
|
650 |
- ret = mszip_decompress(file->state->stream, file->length); |
|
651 |
- } |
|
652 |
- mszip_free(file->state->stream); |
|
653 |
- } |
|
631 |
+ CAB_CHGFOLDER; |
|
632 |
+ ret = mszip_decompress(file->cab->state->stream, file->length); |
|
654 | 633 |
break; |
655 | 634 |
|
656 | 635 |
case 0x0002: /* QUANTUM */ |
657 | 636 |
cli_dbgmsg("CAB: Compression method: QUANTUM\n"); |
658 |
- file->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read); |
|
659 |
- if(!file->state->stream) { |
|
660 |
- free(file->state); |
|
661 |
- close(file->ofd); |
|
662 |
- return CL_EMSCAB; |
|
663 |
- } |
|
664 |
- ret = qtm_decompress(file->state->stream, file->length); |
|
665 |
- qtm_free(file->state->stream); |
|
666 |
- if(ret < 0 && file->offset > 0) { |
|
667 |
- memset(file->state, 0, sizeof(struct cab_state)); |
|
668 |
- file->state->stream = (struct qtm_stream *) qtm_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 4096, file, &cab_read); |
|
669 |
- if(!file->state->stream) { |
|
670 |
- free(file->state); |
|
671 |
- close(file->ofd); |
|
672 |
- return CL_EMSCAB; |
|
673 |
- } |
|
674 |
- ((struct qtm_stream *) file->state->stream)->wflag = 0; |
|
675 |
- if(qtm_decompress(file->state->stream, file->offset) == CL_SUCCESS) { |
|
676 |
- ((struct qtm_stream *) file->state->stream)->wflag = 1; |
|
677 |
- ret = qtm_decompress(file->state->stream, file->length); |
|
678 |
- } |
|
679 |
- qtm_free(file->state->stream); |
|
680 |
- } |
|
637 |
+ CAB_CHGFOLDER; |
|
638 |
+ ret = qtm_decompress(file->cab->state->stream, file->length); |
|
681 | 639 |
break; |
682 | 640 |
|
683 | 641 |
case 0x0003: /* LZX */ |
684 | 642 |
cli_dbgmsg("CAB: Compression method: LZX\n"); |
685 |
- file->state->stream = (struct lzx_stream *) lzx_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read); |
|
686 |
- if(!file->state->stream) { |
|
687 |
- free(file->state); |
|
688 |
- close(file->ofd); |
|
689 |
- return CL_EMSCAB; |
|
690 |
- } |
|
691 |
- if(file->offset > 0) { |
|
692 |
- ((struct lzx_stream *) file->state->stream)->wflag = 0; |
|
693 |
- ret = lzx_decompress(file->state->stream, file->offset); |
|
694 |
- ((struct lzx_stream *) file->state->stream)->wflag = 1; |
|
695 |
- if(ret < 0) { |
|
696 |
- lzx_free(file->state->stream); |
|
697 |
- memset(file->state, 0, sizeof(struct cab_state)); |
|
698 |
- file->state->stream = (struct lzx_stream *) lzx_init(file->fd, file->ofd, (int) (file->folder->cmethod >> 8) & 0x1f, 0, 4096, 0, file, &cab_read); |
|
699 |
- if(!file->state->stream) { |
|
700 |
- free(file->state); |
|
701 |
- close(file->ofd); |
|
702 |
- return CL_EMSCAB; |
|
703 |
- } |
|
704 |
- lseek(file->fd, file->folder->offset, SEEK_SET); |
|
705 |
- } |
|
706 |
- } |
|
707 |
- ret = lzx_decompress(file->state->stream, file->length); |
|
708 |
- lzx_free(file->state->stream); |
|
643 |
+ CAB_CHGFOLDER; |
|
644 |
+ ret = lzx_decompress(file->cab->state->stream, file->length); |
|
709 | 645 |
break; |
710 | 646 |
|
711 | 647 |
default: |
... | ... |
@@ -713,7 +698,6 @@ int cab_extract(struct cab_file *file, const char *name) |
713 | 713 |
ret = CL_EFORMAT; |
714 | 714 |
} |
715 | 715 |
|
716 |
- free(file->state); |
|
717 | 716 |
close(file->ofd); |
718 | 717 |
|
719 | 718 |
return ret; |
... | ... |
@@ -1,4 +1,7 @@ |
1 | 1 |
/* |
2 |
+ * Copyright (C) 2007-2008 Sourcefire, Inc. |
|
3 |
+ * Author: Tomasz Kojm <tkojm@clamav.net> |
|
4 |
+ * |
|
2 | 5 |
* Copyright (C) 2006 Tomasz Kojm <tkojm@clamav.net> |
3 | 6 |
* |
4 | 7 |
* This program is free software; you can redistribute it and/or modify |
... | ... |
@@ -26,8 +29,9 @@ |
26 | 26 |
#define CAB_INPUTMAX (CAB_BLOCKMAX + 6144) |
27 | 27 |
|
28 | 28 |
struct cab_archive { |
29 |
- struct cab_folder *folders; |
|
29 |
+ struct cab_folder *folders, *actfol; |
|
30 | 30 |
struct cab_file *files; |
31 |
+ struct cab_state *state; |
|
31 | 32 |
uint32_t length; |
32 | 33 |
uint16_t nfolders; |
33 | 34 |
uint16_t nfiles; |
... | ... |
@@ -43,6 +47,7 @@ struct cab_state { |
43 | 43 |
uint16_t blklen; |
44 | 44 |
uint16_t outlen; |
45 | 45 |
uint16_t blknum; |
46 |
+ uint16_t cmethod; |
|
46 | 47 |
}; |
47 | 48 |
|
48 | 49 |
struct cab_file { |
... | ... |
@@ -55,7 +60,6 @@ struct cab_file { |
55 | 55 |
struct cab_folder *folder; |
56 | 56 |
struct cab_file *next; |
57 | 57 |
struct cab_archive *cab; |
58 |
- struct cab_state *state; |
|
59 | 58 |
uint16_t attribs; |
60 | 59 |
}; |
61 | 60 |
|