Browse code

re-structure CHM unpacker. Uses no dynamic memory when mmap() available.

git-svn: trunk@3437

Trog authored on 2007/12/19 20:00:41
Showing 4 changed files
... ...
@@ -1,3 +1,8 @@
1
+Wed Dec 19 10:17:02 GMT 2007 (trog)
2
+-----------------------------------
3
+  * libclamav/chmunpack.[ch], scanners.c: re-structure CHM unpacker. Uses no
4
+  			dynamic memory when mmap() available.
5
+
1 6
 Tue Dec 18 19:55:13 CET 2007 (acab)
2 7
 -----------------------------------
3 8
   * libclamav/unzip.c: Fix mmap leaks in unzip 
... ...
@@ -65,63 +65,7 @@
65 65
 #define	O_BINARY	0
66 66
 #endif
67 67
 
68
-#define CHM_ITSF_MIN_LEN (0x60)
69
-typedef struct itsf_header_tag
70
-{
71
-	unsigned char signature[4];
72
-	int32_t version __attribute__ ((packed));
73
-	int32_t header_len __attribute__ ((packed));
74
-	uint32_t unknown __attribute__ ((packed));
75
-	uint32_t last_modified __attribute__ ((packed));
76
-	uint32_t lang_id __attribute__ ((packed));
77
-	unsigned char dir_clsid[16];
78
-	unsigned char stream_clsid[16];
79
-	uint64_t sec0_offset __attribute__ ((packed));
80
-	uint64_t sec0_len __attribute__ ((packed));
81
-	uint64_t dir_offset __attribute__ ((packed));
82
-	uint64_t dir_len __attribute__ ((packed));
83
-	uint64_t data_offset __attribute__ ((packed));
84
-} itsf_header_t;
85
-
86
-#define CHM_ITSP_LEN (0x54)
87
-typedef struct itsp_header_tag
88
-{
89
-	unsigned char signature[4];
90
-	int32_t version __attribute__ ((packed));
91
-	int32_t header_len __attribute__ ((packed));
92
-	int32_t unknown1 __attribute__ ((packed));
93
-	uint32_t block_len __attribute__ ((packed));
94
-	int32_t blockidx_intvl __attribute__ ((packed));
95
-	int32_t index_depth __attribute__ ((packed));
96
-	int32_t index_root __attribute__ ((packed));
97
-	int32_t index_head __attribute__ ((packed));
98
-	int32_t index_tail __attribute__ ((packed));
99
-	int32_t unknown2 __attribute__ ((packed));
100
-	uint32_t num_blocks __attribute__ ((packed));
101
-	uint32_t lang_id __attribute__ ((packed));
102
-	unsigned char system_clsid[16];
103
-	unsigned char unknown4[16];
104
-} itsp_header_t;
105
-
106 68
 #define CHM_CHUNK_HDR_LEN (0x14)
107
-typedef struct chunk_header_tag
108
-{
109
-	char signature[4];
110
-	uint32_t free_space __attribute__ ((packed));
111
-	uint32_t unknown __attribute__ ((packed));
112
-	int32_t block_prev __attribute__ ((packed));
113
-	int32_t block_next __attribute__ ((packed));
114
-	char *chunk_data;
115
-	uint16_t num_entries;
116
-} chunk_header_t;
117
-
118
-typedef struct file_list_tag
119
-{
120
-	uint64_t section;
121
-	uint64_t offset;
122
-	uint64_t length;
123
-	struct file_list_tag *next;
124
-} file_list_t;
125 69
 
126 70
 #define CHM_CONTROL_LEN (0x18)
127 71
 typedef struct lzx_control_tag {
... ...
@@ -215,18 +159,7 @@ static uint64_t chm_copy_file_data(int ifd, int ofd, uint64_t len)
215 215
 	return len;
216 216
 }
217 217
 
218
-static void free_file_list(file_list_t *file_l)
219
-{
220
-	file_list_t *next;
221
-	
222
-	while (file_l) {
223
-		next = file_l->next;
224
-		free(file_l);
225
-		file_l = next;
226
-	}
227
-}
228
-
229
-static void itsf_print_header(itsf_header_t *itsf_hdr)
218
+static void itsf_print_header(chm_itsf_header_t *itsf_hdr)
230 219
 {
231 220
 	if (!itsf_hdr) {
232 221
 		return;
... ...
@@ -247,7 +180,7 @@ static void itsf_print_header(itsf_header_t *itsf_hdr)
247 247
 	}
248 248
 }
249 249
 
250
-static int itsf_read_header(int fd, itsf_header_t *itsf_hdr, char *m_area, off_t m_length)
250
+static int itsf_read_header(int fd, chm_itsf_header_t *itsf_hdr, char *m_area, off_t m_length)
251 251
 {
252 252
 #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
253 253
 	if (!chm_read_data(fd, (char *) itsf_hdr, 0, CHM_ITSF_MIN_LEN,
... ...
@@ -315,7 +248,7 @@ static int itsf_read_header(int fd, itsf_header_t *itsf_hdr, char *m_area, off_t
315 315
 	return TRUE;
316 316
 }
317 317
 
318
-static void itsp_print_header(itsp_header_t *itsp_hdr)
318
+static void itsp_print_header(chm_itsp_header_t *itsp_hdr)
319 319
 {
320 320
 	if (!itsp_hdr) {
321 321
 		return;
... ...
@@ -335,7 +268,7 @@ static void itsp_print_header(itsp_header_t *itsp_hdr)
335 335
 	cli_dbgmsg("Lang ID:\t%u\n\n", itsp_hdr->lang_id);
336 336
 }
337 337
 
338
-static int itsp_read_header(int fd, itsp_header_t *itsp_hdr, off_t offset,
338
+static int itsp_read_header(int fd, chm_itsp_header_t *itsp_hdr, off_t offset,
339 339
 				char *m_area, off_t m_length)
340 340
 {
341 341
 #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
... ...
@@ -438,167 +371,128 @@ static uint64_t read_enc_int(char **start, char *end)
438 438
 	return retval;
439 439
 }
440 440
 
441
-/* Read chunk entries */
442
-/* Note: the file lists end up in reverse order to the order in the chunk */
443
-static int read_chunk_entries(char *chunk, uint32_t chunk_len,
444
-					uint16_t num_entries,
445
-					file_list_t *file_l, file_list_t *sys_file_l)
441
+/* Read control entries */
442
+static int read_control_entries(chm_metadata_t *metadata)
446 443
 {
447
-	char *current, *end;
448
-	uint64_t name_len;
449
-	file_list_t *file_e;
444
+	char *name;
445
+	uint64_t name_len, section, offset, length;
450 446
 
451
-	end = chunk + chunk_len;
452
-	current = chunk + CHM_CHUNK_HDR_LEN;
453
-	
454
-	while (num_entries--) {
455
-		if (current > end) {
447
+	while (metadata->chunk_entries--) {
448
+		if (metadata->chunk_current > metadata->chunk_end) {
456 449
 			cli_dbgmsg("read chunk entries failed\n");
457 450
 			return FALSE;
458 451
 		}
459 452
 
460
-		name_len = read_enc_int(&current, end);
461
-		if (((current + name_len) > end) || ((current + name_len) < chunk)) {
453
+		name_len = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
454
+		if (((metadata->chunk_current + name_len) > metadata->chunk_end) || ((metadata->chunk_current + name_len) < metadata->chunk_data)) {
462 455
 			cli_dbgmsg("Bad CHM name_len detected\n");
463 456
 			return FALSE;
464 457
 		}
465
-		if ((name_len >= 2) && (current[0] == ':') &&
466
-				(current[1] == ':')) {
467
-			if ((name_len == CHM_SYS_CONTROL_LEN) && (strcmp(current, CHM_SYS_CONTROL_NAME) == 0)) {
468
-				current += name_len;
469
-				sys_file_l[0].section = read_enc_int(&current, end);
470
-				sys_file_l[0].offset = read_enc_int(&current, end);
471
-				sys_file_l[0].length = read_enc_int(&current, end);
472
-			} else if ((name_len == CHM_SYS_CONTENT_LEN) && (strcmp(current, CHM_SYS_CONTENT_NAME) == 0)) {
473
-				current += name_len;
474
-				sys_file_l[1].section = read_enc_int(&current, end);
475
-				sys_file_l[1].offset = read_enc_int(&current, end);
476
-				sys_file_l[1].length = read_enc_int(&current, end);
477
-			} else if ((name_len == CHM_SYS_RESETTABLE_LEN) && (strcmp(current, CHM_SYS_RESETTABLE_NAME) == 0)) {
478
-				current += name_len;
479
-				sys_file_l[2].section = read_enc_int(&current, end);
480
-				sys_file_l[2].offset = read_enc_int(&current, end);
481
-				sys_file_l[2].length = read_enc_int(&current, end);
482
-			}
483
-		} else {
484
-			current += name_len;
485
-			file_e = (file_list_t *) cli_malloc(sizeof(file_list_t));
486
-			if (!file_e) {
487
-				return FALSE;
458
+		name = metadata->chunk_current;
459
+		metadata->chunk_current += name_len;
460
+		section = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
461
+		offset = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
462
+		length = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
463
+		
464
+		/* CHM_SYS_CONTENT_LEN is the shortest name we are searching for */
465
+		if ((name_len >= CHM_SYS_CONTENT_LEN) && (name[0] == ':') &&
466
+				(name[1] == ':')) {
467
+			if ((name_len == CHM_SYS_CONTROL_LEN) && (strcmp(name, CHM_SYS_CONTROL_NAME) == 0)) {
468
+				cli_dbgmsg("found CHM_SYS_CONTROL_NAME\n");
469
+				metadata->sys_control.offset = offset;
470
+				metadata->sys_control.length = length;
471
+			} else if ((name_len == CHM_SYS_CONTENT_LEN) && (strcmp(name, CHM_SYS_CONTENT_NAME) == 0)) {
472
+				cli_dbgmsg("found CHM_SYS_CONTENT_NAME\n");
473
+				metadata->sys_content.offset = offset;
474
+				metadata->sys_content.length = length;
475
+			} else if ((name_len == CHM_SYS_RESETTABLE_LEN) && (strcmp(name, CHM_SYS_RESETTABLE_NAME) == 0)) {
476
+				cli_dbgmsg("found CHM_SYS_RESETTABLE_NAME\n");
477
+				metadata->sys_reset.offset = offset;
478
+				metadata->sys_reset.length = length;
488 479
 			}
489
-			file_e->section = read_enc_int(&current, end);
490
-			file_e->offset = read_enc_int(&current, end);
491
-			file_e->length = read_enc_int(&current, end);
492
-			file_e->next = file_l->next;
493
-			file_l->next = file_e;
494
-			cli_dbgmsg("Section: %llu Offset: %llu Length: %llu\n",
495
-					file_e->section, file_e->offset,
496
-					file_e->length);
497 480
 		}
498 481
 	}
499 482
 	return TRUE;
500 483
 }
501 484
 
502
-static void print_chunk(chunk_header_t *chunk)
485
+static int prepare_file(int fd, chm_metadata_t *metadata)
503 486
 {
487
+	uint64_t name_len, section;
504 488
 
505
-	cli_dbgmsg("---- Chunk ----\n");
506
-	cli_dbgmsg("Signature:\t%c%c%c%c\n", chunk->signature[0],
507
-		chunk->signature[1],chunk->signature[2],chunk->signature[3]);
508
-	cli_dbgmsg("Free Space:\t%u\n", chunk->free_space);
509
-	if (memcmp(chunk->signature, "PMGL", 4) == 0) {
510
-		cli_dbgmsg("Prev Block:\t%d\n", chunk->block_prev);
511
-		cli_dbgmsg("Next Block:\t%d\n", chunk->block_next);
512
-		cli_dbgmsg("Num entries:\t%d\n\n", chunk->num_entries);
489
+	while (metadata->chunk_entries--) {
490
+		if (metadata->chunk_current >= metadata->chunk_end) {
491
+			return CL_EFORMAT;
492
+		}
493
+	
494
+		name_len = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
495
+		if (((metadata->chunk_current + name_len) >= metadata->chunk_end) ||
496
+				((metadata->chunk_current + name_len) < metadata->chunk_data)) {
497
+			cli_dbgmsg("Bad CHM name_len detected\n");
498
+			return CL_EFORMAT;
499
+		}
500
+		metadata->chunk_current += name_len;
501
+		section = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
502
+		metadata->file_offset = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
503
+                metadata->file_length = read_enc_int(&metadata->chunk_current, metadata->chunk_end);
504
+		if (section == 1) {
505
+			return CL_SUCCESS;
506
+		}
513 507
 	}
514
-	return;
508
+	
509
+	return CL_BREAK;
515 510
 }
516 511
 
517
-static int read_chunk(int fd, off_t offset, uint32_t chunk_len,
518
-					char *m_area, off_t m_length,
519
-					file_list_t *file_l, file_list_t *sys_file_l)
512
+static int read_chunk(chm_metadata_t *metadata, int fd)
520 513
 {
521
-	chunk_header_t *chunk_hdr;
522
-	int retval = FALSE;
523
-	
524
-	if (chunk_len < 8 || chunk_len > 33554432) {
525
-		return FALSE;
526
-	}
527
-	
528
-	chunk_hdr = (chunk_header_t *) cli_malloc(sizeof(chunk_header_t));
529
-	if (!chunk_hdr) {
530
-		return FALSE;
531
-	}
532
-	
533
-	chunk_hdr->chunk_data = (char *) cli_malloc(chunk_len);
534
-	if (!chunk_hdr->chunk_data) {
535
-		free(chunk_hdr);
514
+	cli_dbgmsg("in read_chunk\n");
515
+
516
+	if (metadata->itsp_hdr.block_len < 8 || metadata->itsp_hdr.block_len > 33554432) {
536 517
 		return FALSE;
537 518
 	}
538
-	
539
-#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
540
-	/* 8 bytes reads the signature and the free_space */
541
-	if (!chm_read_data(fd, chunk_hdr->signature, offset, 8,
542
-				m_area,	m_length)) {
543
-		goto abort;
544
-	}
545
-	if (!chm_read_data(fd, chunk_hdr->chunk_data, offset, chunk_len,
546
-				m_area,	m_length)) {
547
-		goto abort;
548
-	}
549
-#else	
550
-	if (lseek(fd, offset, SEEK_SET) != offset) {
551
-		goto abort;
552
-	}
553
-	if (cli_readn(fd, chunk_hdr->chunk_data, chunk_len) != chunk_len) {
554
-		goto abort;
555
-	}
556
-	if (lseek(fd, offset, SEEK_SET) != offset) {
557
-		goto abort;
558
-	}
559
-	if (cli_readn(fd, &chunk_hdr->signature, 4) != 4) {
560
-		goto abort;
561
-	}
562
-	if (cli_readn(fd, &chunk_hdr->free_space, 4) != 4) {
563
-		goto abort;
564
-	}
565
-#endif
566
-	chunk_hdr->free_space = chm_endian_convert_32(chunk_hdr->free_space);
567
-	
568
-	if (memcmp(chunk_hdr->signature, "PMGL", 4) == 0) {
569
-#if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
570
-		if (!chm_read_data(fd, (char *) &chunk_hdr->unknown, offset+8, 12,
571
-					m_area,	m_length)) {
572
-			goto abort;
519
+
520
+	if (metadata->m_area != NULL) {
521
+		if (metadata->chunk_offset > metadata->m_length) {
522
+			return CL_EFORMAT;
573 523
 		}
574
-#else
575
-		if (cli_readn(fd, &chunk_hdr->unknown, 4) != 4) {
576
-			goto abort;
524
+		if ((metadata->chunk_offset + metadata->itsp_hdr.block_len) > metadata->m_length) {
525
+			return CL_EFORMAT;
577 526
 		}
578
-		if (cli_readn(fd, &chunk_hdr->block_next, 4) != 4) {
579
-			goto abort;
527
+		metadata->chunk_data = metadata->m_area + metadata->chunk_offset;
528
+
529
+	} else {
530
+		if (!metadata->chunk_data) {
531
+			metadata->chunk_data = (char *) cli_malloc(metadata->itsp_hdr.block_len);
532
+			if (!metadata->chunk_data) {
533
+				return CL_EMEM;
534
+			}
580 535
 		}
581
-		if (cli_readn(fd, &chunk_hdr->block_prev, 4) != 4) {
582
-			goto abort;
536
+        	if (lseek(fd, metadata->chunk_offset, SEEK_SET) != metadata->chunk_offset) {
537
+                	goto abort;
538
+        	}
539
+        	if (cli_readn(fd, metadata->chunk_data, metadata->itsp_hdr.block_len) != metadata->itsp_hdr.block_len) {
540
+               		goto abort;
541
+        	}
542
+	}
543
+	metadata->chunk_current = metadata->chunk_data + CHM_CHUNK_HDR_LEN;
544
+	metadata->chunk_end = metadata->chunk_data + metadata->itsp_hdr.block_len;
545
+
546
+	if (memcmp(metadata->chunk_data, "PMGL", 4) == 0) {
547
+		metadata->chunk_entries = (uint16_t)((((uint8_t const *)(metadata->chunk_data))[metadata->itsp_hdr.block_len-2] << 0)
548
+					| (((uint8_t const *)(metadata->chunk_data))[metadata->itsp_hdr.block_len-1] << 8));
549
+	} else if (memcmp(metadata->chunk_data, "PMGI", 4) != 0) {
550
+		if (metadata->m_area != NULL) {
551
+			free(metadata->chunk_data);
583 552
 		}
584
-#endif
585
-		chunk_hdr->block_next = chm_endian_convert_32(chunk_hdr->block_next);
586
-		chunk_hdr->block_prev = chm_endian_convert_32(chunk_hdr->block_prev);
587
-		
588
-		chunk_hdr->num_entries = (uint16_t)((((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-2] << 0)
589
-					| (((uint8_t const *)(chunk_hdr->chunk_data))[chunk_len-1] << 8));
590
-		read_chunk_entries(chunk_hdr->chunk_data, chunk_len,
591
-                        chunk_hdr->num_entries, file_l, sys_file_l);
592
-	} else if (memcmp(chunk_hdr->signature, "PMGI", 4) != 0) {
593
-		goto abort;
553
+		return CL_BREAK;
594 554
 	}
595 555
 
596
-	print_chunk(chunk_hdr);
597
-	retval=TRUE;
556
+	return CL_SUCCESS;
598 557
 abort:
599
-	free(chunk_hdr->chunk_data);
600
-	free(chunk_hdr);
601
-	return retval;
558
+	if (metadata->m_area != NULL) {
559
+		free(metadata->chunk_data);
560
+		metadata->chunk_data = NULL;
561
+	}
562
+	return CL_EFORMAT;
602 563
 }
603 564
 
604 565
 static void print_sys_control(lzx_control_t *lzx_control)
... ...
@@ -617,50 +511,44 @@ static void print_sys_control(lzx_control_t *lzx_control)
617 617
 	cli_dbgmsg("Cache Size:\t%d\n\n", lzx_control->cache_size);
618 618
 }
619 619
 
620
-static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e,
621
-					char *m_area, off_t m_length)
620
+static int read_sys_control(int fd, chm_metadata_t *metadata, lzx_control_t *lzx_control)
622 621
 {
623 622
 	off_t offset;
624
-	lzx_control_t *lzx_control;
625 623
 	
626
-	if (file_e->length != 28) {
627
-		return NULL;
624
+	if (metadata->sys_control.length != 28) {
625
+		return FALSE;
628 626
 	}
629
-	offset = itsf_hdr->data_offset + file_e->offset;
627
+	offset = metadata->itsf_hdr.data_offset + metadata->sys_control.offset;
630 628
 	if (offset < 0) {
631
-		return NULL;
629
+		return FALSE;
632 630
 	}
633 631
 
634
-	lzx_control = (lzx_control_t *) cli_malloc(sizeof(lzx_control_t));
635
-	if (!lzx_control) {
636
-		return NULL;
637
-	}
638 632
 #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
639 633
 	if (!chm_read_data(fd, (char *) lzx_control, offset, CHM_CONTROL_LEN,
640
-				m_area,	m_length)) {
641
-		goto abort;
634
+				metadata->m_area, metadata->m_length)) {
635
+		return FALSE;
642 636
 	}
643 637
 #else
644 638
 	if (lseek(fd, offset, SEEK_SET) != offset) {
645
-		goto abort;
639
+		return FALSE;
646 640
 	}
647 641
 	if (cli_readn(fd, &lzx_control->length, 4) != 4) {
648
-		goto abort;
642
+		return FALSE;
649 643
 	}
650 644
 	if (cli_readn(fd, &lzx_control->signature, 4) != 4) {
651
-		goto abort;
645
+		return FALSE;
652 646
 	}
653 647
 	if (cli_readn(fd, &lzx_control->version, 4) != 4) {
654
-		goto abort;
648
+		return FALSE;
655 649
 	}
656 650
 	if (cli_readn(fd, &lzx_control->reset_interval, 4) != 4) {
657
-		goto abort;
651
+		return FALSE;
658 652
 	}
659 653
 	if (cli_readn(fd, &lzx_control->window_size, 4) != 4) {
660
-		goto abort;
654
+		return FALSE;
661 655
 	}
662 656
 	if (cli_readn(fd, &lzx_control->cache_size, 4) != 4) {
663
-		goto abort;
657
+		return FALSE;
664 658
 	}
665 659
 #endif
666 660
 	lzx_control->length = chm_endian_convert_32(lzx_control->length);
... ...
@@ -671,7 +559,7 @@ static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_lis
671 671
 	
672 672
 	if (strncmp((const char *) "LZXC", (const char *) lzx_control->signature, 4) != 0) {
673 673
 		cli_dbgmsg("bad sys_control signature");
674
-		goto abort;
674
+		return FALSE;
675 675
 	}
676 676
 	switch(lzx_control->version) {
677 677
 		case 1:
... ...
@@ -682,14 +570,11 @@ static lzx_control_t *read_sys_control(int fd, itsf_header_t *itsf_hdr, file_lis
682 682
 			break;
683 683
 		default:
684 684
 			cli_dbgmsg("Unknown sys_control version:%d\n", lzx_control->version);
685
-			goto abort;
685
+			return FALSE;
686 686
 	}
687 687
 			
688 688
 	print_sys_control(lzx_control);
689
-	return lzx_control;
690
-abort:
691
-	free(lzx_control);
692
-	return NULL;
689
+	return TRUE;
693 690
 }
694 691
 
695 692
 static void print_sys_content(lzx_content_t *lzx_content)
... ...
@@ -703,19 +588,13 @@ static void print_sys_content(lzx_content_t *lzx_content)
703 703
 	cli_dbgmsg("Length:\t%llu\n\n", lzx_content->length);
704 704
 }
705 705
 
706
-static lzx_content_t *read_sys_content(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e)
706
+static int read_sys_content(int fd, chm_metadata_t *metadata, lzx_content_t *lzx_content)
707 707
 {
708
-	lzx_content_t *lzx_content;
709
-	
710
-	lzx_content = (lzx_content_t *) cli_malloc(sizeof(lzx_content_t));
711
-	if (!lzx_content) {
712
-		return NULL;
713
-	}
714
-	lzx_content->offset = itsf_hdr->data_offset + file_e->offset;
715
-	lzx_content->length = file_e->length;
708
+	lzx_content->offset = metadata->itsf_hdr.data_offset + metadata->sys_content.offset;
709
+	lzx_content->length = metadata->sys_content.length;
716 710
 	
717 711
 	print_sys_content(lzx_content);
718
-	return lzx_content;
712
+	return TRUE;
719 713
 }
720 714
 
721 715
 static void print_sys_reset_table(lzx_reset_table_t *lzx_reset_table)
... ...
@@ -733,25 +612,18 @@ static void print_sys_reset_table(lzx_reset_table_t *lzx_reset_table)
733 733
 	cli_dbgmsg("Frame Len:\t%llu\n\n", lzx_reset_table->frame_len);
734 734
 }
735 735
 
736
-static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr, file_list_t *file_e,
737
-						char *m_area, off_t m_length)
736
+static int read_sys_reset_table(int fd, chm_metadata_t *metadata, lzx_reset_table_t *lzx_reset_table)
738 737
 {
739 738
 	off_t offset;
740
-	lzx_reset_table_t *lzx_reset_table;
741 739
 
742
-	if (file_e->length < 40) {
743
-		return NULL;
740
+	if (metadata->sys_reset.length < 40) {
741
+		return FALSE;
744 742
 	}
745 743
 	/* Skip past unknown entry in offset calc */
746
-	offset = itsf_hdr->data_offset + file_e->offset + 4;
744
+	offset = metadata->itsf_hdr.data_offset + metadata->sys_reset.offset + 4;
747 745
 	
748 746
 	if (offset < 0) {
749
-		return NULL;
750
-	}
751
-
752
-	lzx_reset_table = (lzx_reset_table_t *) cli_malloc(sizeof(lzx_reset_table_t));
753
-	if (!lzx_reset_table) {
754
-		return NULL;
747
+		return FALSE;
755 748
 	}
756 749
 	
757 750
 	/* Save the entry offset for later use */
... ...
@@ -759,30 +631,30 @@ static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr,
759 759
 
760 760
 #if defined(HAVE_ATTRIB_PACKED) || defined(HAVE_PRAGMA_PACK) || defined(HAVE_PRAGMA_PACK_HPPA)
761 761
 	if (!chm_read_data(fd, (char *) lzx_reset_table, offset, CHM_RESET_TABLE_LEN,
762
-				m_area,	m_length)) {
763
-		goto abort;
762
+				metadata->m_area, metadata->m_length)) {
763
+		return FALSE;
764 764
 	}
765 765
 #else	
766 766
 	if (lseek(fd, offset, SEEK_SET) != offset) {
767
-		goto abort;
767
+		return FALSE;
768 768
 	}
769 769
 	if (cli_readn(fd, &lzx_reset_table->num_entries, 4) != 4) {
770
-		goto abort;
770
+		return FALSE;
771 771
 	}
772 772
 	if (cli_readn(fd, &lzx_reset_table->entry_size, 4) != 4) {
773
-		goto abort;
773
+		return FALSE;
774 774
 	}
775 775
 	if (cli_readn(fd, &lzx_reset_table->table_offset, 4) != 4) {
776
-		goto abort;
776
+		return FALSE;
777 777
 	}
778 778
 	if (cli_readn(fd, &lzx_reset_table->uncom_len, 8) != 8) {
779
-		goto abort;
779
+		return FALSE;
780 780
 	}
781 781
 	if (cli_readn(fd, &lzx_reset_table->com_len, 8) != 8) {
782
-		goto abort;
782
+		return FALSE;
783 783
 	}
784 784
 	if (cli_readn(fd, &lzx_reset_table->frame_len, 8) != 8) {
785
-		goto abort;
785
+		return FALSE;
786 786
 	}
787 787
 #endif
788 788
 	lzx_reset_table->num_entries = chm_endian_convert_32(lzx_reset_table->num_entries);
... ...
@@ -794,56 +666,52 @@ static lzx_reset_table_t *read_sys_reset_table(int fd, itsf_header_t *itsf_hdr,
794 794
 
795 795
 	if (lzx_reset_table->frame_len != LZX_FRAME_SIZE) {
796 796
 		cli_dbgmsg("bad sys_reset_table frame_len: 0x%lx\n", (long unsigned int) lzx_reset_table->frame_len);
797
-		goto abort;
797
+		return FALSE;
798 798
 	}
799 799
 	if ((lzx_reset_table->entry_size != 4) && (lzx_reset_table->entry_size != 8)) {
800 800
 		cli_dbgmsg("bad sys_reset_table entry_size: 0x%x\n",lzx_reset_table->entry_size);
801
-		goto abort;
801
+		return FALSE;
802 802
 	}
803 803
 	print_sys_reset_table(lzx_reset_table);
804
-	return lzx_reset_table;
805
-abort:
806
-	free(lzx_reset_table);
807
-	return NULL;
804
+	return TRUE;
808 805
 }
809 806
 
810 807
 /* *****************************************************************/
811 808
 /* This section interfaces to the mspack files. As such, this is a */
812 809
 /* little bit dirty compared to my usual code */
813 810
 
814
-static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *itsf_hdr,
815
-				file_list_t *file_l, file_list_t *sys_file_l,
816
-				char *m_area, off_t m_length)
811
+static int chm_decompress_stream(int fd, chm_metadata_t *metadata, const char *dirname)
817 812
 {
818
-	file_list_t *entry;
819
-	lzx_content_t *lzx_content=NULL;
820
-	lzx_reset_table_t *lzx_reset_table=NULL;
821
-	lzx_control_t *lzx_control=NULL;
822
-	int window_bits, count, length, tmpfd, ofd, retval=FALSE;
823
-	uint64_t com_offset;
813
+	lzx_content_t lzx_content;
814
+	lzx_reset_table_t lzx_reset_table;
815
+	lzx_control_t lzx_control;
816
+	int window_bits, length, tmpfd, retval=-1;
824 817
 	struct lzx_stream * stream;
825 818
 	char filename[1024];
826 819
 	
827 820
 	snprintf(filename, 1024, "%s/clamav-unchm.bin", dirname);
828
-	tmpfd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
821
+	tmpfd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
829 822
 	if (tmpfd<0) {
830 823
 		cli_dbgmsg("open failed for %s\n", filename);
831
-		return FALSE;
824
+		return -1;
832 825
 	}
833 826
 
834
-	if (!sys_file_l[0].length || !sys_file_l[1].length ||!sys_file_l[2].length) {
827
+	if (!metadata->sys_control.length || !metadata->sys_content.length ||!metadata->sys_reset.length) {
828
+		cli_dbgmsg("Control file missing\n");
835 829
 		goto abort;
836 830
 	}
837 831
 
838
-	lzx_control = read_sys_control(fd, itsf_hdr, &sys_file_l[0], m_area, m_length);
839
-	lzx_content = read_sys_content(fd, itsf_hdr, &sys_file_l[1]);
840
-	lzx_reset_table = read_sys_reset_table(fd, itsf_hdr, &sys_file_l[2], m_area, m_length);
841
-
842
-	if (!lzx_content || !lzx_reset_table || !lzx_control) {
832
+	if (!read_sys_control(fd, metadata, &lzx_control)) {
833
+		goto abort;
834
+	}
835
+	if (!read_sys_content(fd, metadata, &lzx_content)) {
836
+		goto abort;
837
+	}
838
+	if (!read_sys_reset_table(fd, metadata, &lzx_reset_table)) {
843 839
 		goto abort;
844 840
 	}
845 841
 	
846
-	switch (lzx_control->window_size) {
842
+	switch (lzx_control.window_size) {
847 843
 		case 0x008000:
848 844
 			window_bits = 15;
849 845
 			break;
... ...
@@ -866,26 +734,27 @@ static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *its
866 866
 			window_bits = 21;
867 867
 			break;
868 868
 		default:
869
-			cli_dbgmsg("bad control window size: 0x%x\n", lzx_control->window_size);
869
+			cli_dbgmsg("bad control window size: 0x%x\n", lzx_control.window_size);
870 870
 			goto abort;
871 871
 	}
872 872
 	
873
-	if (lzx_control->reset_interval % LZX_FRAME_SIZE) {
874
-		cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control->window_size);
873
+	if (lzx_control.reset_interval % LZX_FRAME_SIZE) {
874
+		cli_dbgmsg("bad reset_interval: 0x%x\n", lzx_control.window_size);
875 875
 		goto abort;
876 876
 	}
877 877
 	
878
-	length = lzx_reset_table->uncom_len;
879
-	length += lzx_control->reset_interval;
880
-	length &= -lzx_control->reset_interval;
878
+	length = lzx_reset_table.uncom_len;
879
+	length += lzx_control.reset_interval;
880
+	length &= -lzx_control.reset_interval;
881 881
 	
882
-	com_offset = lzx_content->offset;
883
-	cli_dbgmsg("Compressed offset: %llu\n", com_offset);
882
+	cli_dbgmsg("Compressed offset: %llu\n", lzx_content.offset);
883
+	if (lseek(fd, lzx_content.offset, SEEK_SET) != lzx_content.offset) {
884
+		goto abort;
885
+	}
884 886
 	
885 887
 	stream = lzx_init(fd, tmpfd, window_bits,
886
-			lzx_control->reset_interval / LZX_FRAME_SIZE,
888
+			lzx_control.reset_interval / LZX_FRAME_SIZE,
887 889
 			4096, length, NULL, NULL);
888
-	lseek(fd, com_offset, SEEK_SET);
889 890
 	if (!stream) {
890 891
 		cli_dbgmsg("lzx_init failed\n");
891 892
 		goto abort;
... ...
@@ -894,149 +763,175 @@ static int chm_decompress_stream(int fd, const char *dirname, itsf_header_t *its
894 894
 	lzx_decompress(stream, length);
895 895
 	lzx_free(stream);
896 896
 	
897
-	entry = file_l->next;
898
-	close(tmpfd);
899
-	
900
-	/* Reopen the file for reading */
901
-	tmpfd = open(filename, O_RDONLY|O_BINARY);
902
-	if (tmpfd < 0) {
903
-		cli_dbgmsg("re-open output failed\n");
904
-		goto abort;
905
-	}
906
-	
907 897
 	/* Delete the file */
908 898
 	unlink(filename);
909
-	
910
-	count=0;
911
-	while(entry) {
912
-		if (entry->section != 1) {
913
-			entry = entry->next;
914
-			continue;
915
-		}
916
-		if (lseek(tmpfd, entry->offset, SEEK_SET) != (off_t)entry->offset) {
917
-			cli_dbgmsg("seek in output failed\n");
918
-			entry = entry->next;
919
-			continue;
920
-		}
921
-		
922
-		snprintf(filename, 1024, "%s/%d-%llu.chm", dirname, count, entry->offset);
923
-		ofd = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
924
-		if (ofd < 0) {
925
-			entry = entry->next;
926
-			continue;
927
-		}
928
-		if (chm_copy_file_data(tmpfd, ofd, entry->length) != entry->length) {
929
-			cli_dbgmsg("failed to copy %lu bytes\n", (long unsigned int) entry->length);
930
-		}
931
-		
932
-		close(ofd);		
933
-		entry = entry->next;
934
-		count++;
935
-	}
936
-	close(tmpfd);
937
-	tmpfd=-1;
938
-	retval = TRUE;
899
+	retval = tmpfd;
939 900
 	
940 901
 abort:
941
-	if (tmpfd>=0) {
902
+	if ((retval == -1) && (tmpfd >= 0)) {
942 903
 		close(tmpfd);
943 904
 	}
944
-	if (lzx_content) {
945
-		free(lzx_content);
905
+	return retval;
906
+}
907
+
908
+/* ************ End dirty section ********************/
909
+
910
+static int chm_init_metadata(chm_metadata_t *metadata)
911
+{
912
+	if (!metadata) {
913
+		return CL_ENULLARG;
946 914
 	}
947
-	if (lzx_reset_table) {
948
-		free(lzx_reset_table);
915
+	
916
+	metadata->sys_control.length = metadata->sys_content.length = metadata->sys_reset.length = 0;
917
+	metadata->m_area = NULL;
918
+	metadata->m_area = 0;
919
+	metadata->ufd = -1;
920
+	metadata->num_chunks = metadata->chunk_entries = 0;
921
+	metadata->chunk_data = NULL;
922
+	return CL_SUCCESS;
923
+}
924
+
925
+void cli_chm_close(chm_metadata_t *metadata)
926
+{
927
+	if (metadata->ufd >= 0) {
928
+		close(metadata->ufd);
949 929
 	}
950
-	if (lzx_control) {
951
-		free(lzx_control);
930
+	if (!metadata->m_area && metadata->chunk_data) {
931
+		free(metadata->chunk_data);
952 932
 	}
953
-	return retval;
933
+#ifdef HAVE_MMAP
934
+	if (metadata->m_area) {
935
+		munmap(metadata->m_area, metadata-> m_length);
936
+	}
937
+#endif
954 938
 }
955 939
 
956
-/* ************ End dirty section ********************/
940
+int cli_chm_extract_file(int fd, char *dirname, chm_metadata_t *metadata)
941
+{
942
+	char filename[1024];
943
+
944
+	cli_dbgmsg("in cli_chm_extract_file\n");
945
+	
946
+	if (lseek(metadata->ufd, metadata->file_offset, SEEK_SET) != (off_t) metadata->file_offset) {
947
+		cli_dbgmsg("seek in uncompressed stream failed\n");
948
+		return CL_EFORMAT;
949
+	}
950
+	snprintf(filename, 1024, "%s/%llu.chm", dirname, metadata->file_offset);
951
+	metadata->ofd = open(filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, S_IRWXU);
952
+	if (metadata->ofd < 0) {
953
+		return CL_EIO;
954
+	}
955
+	if (chm_copy_file_data(metadata->ufd, metadata->ofd, metadata->file_length) != metadata->file_length) {
956
+		cli_dbgmsg("failed to copy %lu bytes\n", (long unsigned int) metadata->file_length);
957
+		close(metadata->ofd);
958
+		return CL_EIO;
959
+	}
960
+		
961
+	return CL_SUCCESS;
962
+}	
957 963
 
958
-int chm_unpack(int fd, const char *dirname)
964
+int cli_chm_prepare_file(int fd, char *dirname, chm_metadata_t *metadata)
965
+{
966
+	int retval;
967
+	
968
+	cli_dbgmsg("in cli_chm_prepare_file\n");
969
+
970
+	if (metadata->chunk_entries == 0) {
971
+		if (metadata->num_chunks == 0) {
972
+			return CL_BREAK;
973
+		}
974
+		if ((retval = read_chunk(metadata, fd)) != CL_SUCCESS) {
975
+			return retval;
976
+		}
977
+	}
978
+
979
+	return prepare_file(fd, metadata);
980
+}
981
+
982
+int cli_chm_open(int fd, const char *dirname, chm_metadata_t *metadata)
959 983
 {
960
-	int retval=FALSE;
961
-	char *m_area=NULL;
962
-	off_t m_length=0, offset;
963
-	file_list_t *file_l, sys_file_l[3];
964 984
 	struct stat statbuf;
965
-	itsf_header_t itsf_hdr;
966
-	itsp_header_t itsp_hdr;
967
-	uint32_t num_chunks;
985
+	int retval;
968 986
 
969
-	/* These two lists contain the list of files and system files in
970
-	the archive. The first entry in the list is an empty entry */
987
+	cli_dbgmsg("in cli_chm_open\n");
971 988
 	
972
-        file_l = (file_list_t *) cli_malloc(sizeof(file_list_t));
973
-	if (!file_l) {
974
-		return FALSE;
989
+	if ((retval = chm_init_metadata(metadata)) != CL_SUCCESS) {
990
+		return retval;
975 991
 	}
976
-	file_l->next = NULL;
977
-	sys_file_l[0].length = sys_file_l[1].length = sys_file_l[2].length = 0;
978
-	
992
+
979 993
 #ifdef HAVE_MMAP
980 994
 	if (fstat(fd, &statbuf) == 0) {
981 995
 		if (statbuf.st_size < CHM_ITSF_MIN_LEN) {
982 996
 			goto abort;
983 997
 		}
984
-		m_length = statbuf.st_size;
985
-		m_area = (char *) mmap(NULL, m_length, PROT_READ, MAP_PRIVATE, fd, 0);
986
-		if (m_area == MAP_FAILED) {
987
-			m_area = NULL;
998
+		metadata->m_length = statbuf.st_size;
999
+		metadata->m_area = (char *) mmap(NULL, metadata->m_length, PROT_READ, MAP_PRIVATE, fd, 0);
1000
+		if (metadata->m_area == MAP_FAILED) {
1001
+			metadata->m_area = NULL;
988 1002
 		}
989 1003
 	}
990 1004
 #endif
991 1005
 
992
-	if (!itsf_read_header(fd, &itsf_hdr, m_area, m_length)) {
1006
+	if (!itsf_read_header(fd, &metadata->itsf_hdr, metadata->m_area, metadata->m_length)) {
993 1007
 		goto abort;
994 1008
 	}
995
-	itsf_print_header(&itsf_hdr);
1009
+	itsf_print_header(&metadata->itsf_hdr);
996 1010
 
997
-	if (!itsp_read_header(fd, &itsp_hdr, itsf_hdr.dir_offset, m_area, m_length)) {
1011
+	if (!itsp_read_header(fd, &metadata->itsp_hdr, metadata->itsf_hdr.dir_offset, metadata->m_area, metadata->m_length)) {
998 1012
 		goto abort;
999 1013
 	}
1000
-	itsp_print_header(&itsp_hdr);
1001
-	
1002
-	offset = itsf_hdr.dir_offset+CHM_ITSP_LEN;
1014
+	itsp_print_header(&metadata->itsp_hdr);
1015
+
1016
+	metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN;
1003 1017
 	
1004 1018
 	/* TODO: need to check this first calculation,
1005 1019
 		currently have no files of this type */
1006
-	if (itsp_hdr.index_head > 0) {
1007
-		offset += itsp_hdr.index_head * itsp_hdr.block_len;
1020
+	if (metadata->itsp_hdr.index_head > 0) {
1021
+		metadata->chunk_offset += metadata->itsp_hdr.index_head * metadata->itsp_hdr.block_len;
1008 1022
 	}
1009 1023
 
1010
-	num_chunks = itsp_hdr.index_tail - itsp_hdr.index_head + 1;
1024
+	metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1;
1011 1025
 	
1012 1026
 	/* Versions before 3 didn't have a data_offset */
1013 1027
 	/* TODO: need to check this calculation,
1014 1028
 		 currently have no files of this type */
1015
-	if (itsf_hdr.version < 3) {
1016
-		itsf_hdr.data_offset = itsf_hdr.dir_offset + CHM_ITSP_LEN + (itsp_hdr.block_len*itsp_hdr.num_blocks);
1029
+	if (metadata->itsf_hdr.version < 3) {
1030
+		metadata->itsf_hdr.data_offset = metadata->itsf_hdr.dir_offset + CHM_ITSP_LEN +
1031
+				(metadata->itsp_hdr.block_len*metadata->itsp_hdr.num_blocks);
1017 1032
 	}
1018
-
1019
-	while (num_chunks) {
1020
-		if (!read_chunk(fd, offset, itsp_hdr.block_len, m_area,
1021
-					m_length, file_l, sys_file_l)) {
1033
+	
1034
+	while (metadata->num_chunks) {
1035
+		if (read_chunk(metadata, fd) != CL_SUCCESS) {
1036
+			cli_dbgmsg("read_chunk failed");
1022 1037
 			goto abort;
1023 1038
 		}
1039
+		read_control_entries(metadata);
1040
+		metadata->num_chunks--;
1041
+		metadata->chunk_offset += metadata->itsp_hdr.block_len;
1042
+	}
1024 1043
 
1025
-		num_chunks--;
1026
-		offset += itsp_hdr.block_len;
1044
+	if (!metadata->sys_content.length || !metadata->sys_control.length || !metadata->sys_reset.length) {
1045
+		cli_dbgmsg("sys file missing");
1046
+		goto abort;
1027 1047
 	}
1048
+	
1049
+	metadata->ufd = chm_decompress_stream(fd, metadata, dirname);
1050
+	if (metadata->ufd == -1) {
1051
+		goto abort;
1052
+	}
1053
+	
1054
+	metadata->chunk_entries = 0;
1055
+	metadata->chunk_data = NULL;
1056
+	metadata->chunk_offset = metadata->itsf_hdr.dir_offset+CHM_ITSP_LEN;
1057
+	metadata->num_chunks = metadata->itsp_hdr.index_tail - metadata->itsp_hdr.index_head + 1;
1028 1058
 
1029
-	chm_decompress_stream(fd, dirname, &itsf_hdr, file_l, sys_file_l, m_area, m_length);
1059
+	return CL_SUCCESS;
1030 1060
 
1031
-	/* Signal success */
1032
-	retval = TRUE;
1033 1061
 abort:
1034
-	free_file_list(file_l);
1035
-
1036 1062
 #ifdef HAVE_MMAP
1037
-	if (m_area) {
1038
-		munmap(m_area, m_length);
1063
+	if (metadata->m_area) {
1064
+		munmap(metadata->m_area, metadata->m_length);
1039 1065
 	}
1040 1066
 #endif
1041
-	return retval;
1067
+	return CL_EFORMAT;
1042 1068
 }
... ...
@@ -21,7 +21,71 @@
21 21
  
22 22
 #ifndef __CHM_UNPACK_H
23 23
 #define __CHM_UNPACK_H
24
- 
24
+
25
+#define CHM_ITSF_MIN_LEN (0x60)
26
+typedef struct chm_itsf_header_tag
27
+{
28
+	unsigned char signature[4];
29
+	int32_t version __attribute__ ((packed));
30
+	int32_t header_len __attribute__ ((packed));
31
+	uint32_t unknown __attribute__ ((packed));
32
+	uint32_t last_modified __attribute__ ((packed));
33
+	uint32_t lang_id __attribute__ ((packed));
34
+	unsigned char dir_clsid[16];
35
+	unsigned char stream_clsid[16];
36
+	uint64_t sec0_offset __attribute__ ((packed));
37
+	uint64_t sec0_len __attribute__ ((packed));
38
+	uint64_t dir_offset __attribute__ ((packed));
39
+	uint64_t dir_len __attribute__ ((packed));
40
+	uint64_t data_offset __attribute__ ((packed));
41
+} chm_itsf_header_t;
42
+
43
+#define CHM_ITSP_LEN (0x54)
44
+typedef struct chm_itsp_header_tag
45
+{
46
+	unsigned char signature[4];
47
+	int32_t version __attribute__ ((packed));
48
+	int32_t header_len __attribute__ ((packed));
49
+	int32_t unknown1 __attribute__ ((packed));
50
+	uint32_t block_len __attribute__ ((packed));
51
+	int32_t blockidx_intvl __attribute__ ((packed));
52
+	int32_t index_depth __attribute__ ((packed));
53
+	int32_t index_root __attribute__ ((packed));
54
+	int32_t index_head __attribute__ ((packed));
55
+	int32_t index_tail __attribute__ ((packed));
56
+	int32_t unknown2 __attribute__ ((packed));
57
+	uint32_t num_blocks __attribute__ ((packed));
58
+	uint32_t lang_id __attribute__ ((packed));
59
+	unsigned char system_clsid[16];
60
+	unsigned char unknown4[16];
61
+} chm_itsp_header_t;
62
+
63
+typedef struct chm_sys_entry_tag
64
+{
65
+	uint64_t offset;
66
+	uint64_t length;
67
+} chm_sys_entry_t;
68
+
69
+typedef struct chm_metadata_tag {
70
+	chm_sys_entry_t sys_control;
71
+	chm_sys_entry_t sys_content;
72
+	chm_sys_entry_t sys_reset;
73
+	off_t m_length;
74
+	char *m_area;
75
+	chm_itsf_header_t itsf_hdr;
76
+	chm_itsp_header_t itsp_hdr;
77
+	int ufd;
78
+	int ofd;
79
+	uint32_t num_chunks;
80
+	off_t chunk_offset;
81
+	char *chunk_data;
82
+	char *chunk_current;
83
+	char *chunk_end;
84
+	uint16_t chunk_entries;
85
+	uint64_t file_length;
86
+	uint64_t file_offset;
87
+} chm_metadata_t;
88
+
25 89
 int chm_unpack(int fd, const char *dirname);
26 90
 
27 91
 #endif
... ...
@@ -376,7 +376,7 @@ static int cli_scanarj(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c
376 376
      /* generate the temporary directory */
377 377
     dir = cli_gentemp(NULL);
378 378
     if(mkdir(dir, 0700)) {
379
-	cli_dbgmsg("RAR: Can't create temporary directory %s\n", dir);
379
+	cli_dbgmsg("ARJ: Can't create temporary directory %s\n", dir);
380 380
 	free(dir);
381 381
 	return CL_ETMPDIR;
382 382
     }
... ...
@@ -1204,26 +1204,60 @@ static int cli_scanbinhex(int desc, cli_ctx *ctx)
1204 1204
 
1205 1205
 static int cli_scanmschm(int desc, cli_ctx *ctx)
1206 1206
 {
1207
-	char *tempname;
1208
-	int ret = CL_CLEAN;
1209
-
1207
+	int ret = CL_CLEAN, rc;
1208
+	chm_metadata_t metadata;
1209
+	char *dir;
1210
+	unsigned int file_count = 1;
1210 1211
 
1211
-    cli_dbgmsg("in cli_scanmschm()\n");	
1212
+    cli_dbgmsg("in cli_scanmschm()\n");
1212 1213
 
1213
-    tempname = cli_gentemp(NULL);
1214
-    if(mkdir(tempname, 0700)) {
1215
-	cli_dbgmsg("CHM: Can't create temporary directory %s\n", tempname);
1216
-	free(tempname);
1214
+     /* generate the temporary directory */
1215
+    dir = cli_gentemp(NULL);
1216
+    if(mkdir(dir, 0700)) {
1217
+	cli_dbgmsg("CHM: Can't create temporary directory %s\n", dir);
1218
+	free(dir);
1217 1219
 	return CL_ETMPDIR;
1218 1220
     }
1219 1221
 
1220
-    if(chm_unpack(desc, tempname))
1221
-	ret = cli_scandir(tempname, ctx);
1222
+    ret = cli_chm_open(desc, dir, &metadata);
1223
+    if (ret != CL_SUCCESS) {
1224
+	if(!cli_leavetemps_flag)
1225
+	    cli_rmdirs(dir);
1226
+	free(dir);
1227
+	cli_dbgmsg("CHM: Error: %s\n", cl_strerror(ret));
1228
+	return ret;
1229
+    }
1222 1230
 
1231
+   do {
1232
+	ret = cli_chm_prepare_file(desc, dir, &metadata);
1233
+	if (ret != CL_SUCCESS) {
1234
+	   break;
1235
+	}
1236
+	ret = cli_chm_extract_file(desc, dir, &metadata);
1237
+	if (ret == CL_SUCCESS) {
1238
+	    lseek(metadata.ofd, 0, SEEK_SET);
1239
+	    rc = cli_magic_scandesc(metadata.ofd, ctx);
1240
+	    close(metadata.ofd);
1241
+	    if (rc == CL_VIRUS) {
1242
+		cli_dbgmsg("CHM: infected with %s\n",*ctx->virname);
1243
+		ret = CL_VIRUS;
1244
+		break;
1245
+	    }
1246
+	}
1247
+
1248
+    } while(ret == CL_SUCCESS);
1249
+    
1223 1250
     if(!cli_leavetemps_flag)
1224
-	cli_rmdirs(tempname);
1251
+	cli_rmdirs(dir);
1252
+
1253
+    free(dir);
1254
+
1255
+    cli_chm_close(&metadata);
1256
+   
1257
+    cli_dbgmsg("CHM: Exit code: %d\n", ret);
1258
+    if (ret == CL_BREAK)
1259
+	ret = CL_CLEAN;
1225 1260
 
1226
-    free(tempname);
1227 1261
     return ret;
1228 1262
 }
1229 1263