unit_tests/check_clamav.c
fe473bcb
 #if HAVE_CONFIG_H
 #include "clamav-config.h"
 #endif
 
 #include <stdio.h>
 
 #include <stdlib.h>
 #include <limits.h>
3dcc2d78
 #include <fcntl.h>
fe473bcb
 #include <string.h>
 #include <check.h>
d5f7afdd
 #include <sys/types.h>
 #include <dirent.h>
62ee12b2
 #include <sys/mman.h>
b2e7c931
 
849cdc78
 #if HAVE_LIBXML2
 #include <libxml/parser.h>
 #endif
 
fe473bcb
 #include "../libclamav/clamav.h"
 #include "../libclamav/others.h"
 #include "../libclamav/matcher.h"
04f9bedf
 #include "../libclamav/version.h"
c5944b54
 #include "../libclamav/dsig.h"
a393d999
 #include "../libclamav/fpu.h"
f8b3d2e5
 #include "../platform.h"
a39b29cb
 #include "checks.h"
fe473bcb
 
288057e9
 static int fpu_words = FPU_ENDIAN_INITME;
a393d999
 #define NO_FPU_ENDIAN (fpu_words == FPU_ENDIAN_UNKNOWN)
 #define EA06_SCAN strstr(file, "clam.ea06.exe")
 #define FALSE_NEGATIVE (EA06_SCAN && NO_FPU_ENDIAN)
 
fe473bcb
 /* extern void cl_free(struct cl_engine *engine); */
288057e9
 START_TEST(test_cl_free)
fe473bcb
 /*
     struct cl_engine *engine = NULL;
     cl_free(NULL);
 */
 END_TEST
 
 /* extern struct cl_engine *cl_dup(struct cl_engine *engine); */
288057e9
 START_TEST(test_cl_dup)
 /*
fe473bcb
     struct cl_engine *engine;
     fail_unless(NULL == cl_dup(NULL), "cl_dup null pointer");
     */
 END_TEST
 
 /* extern int cl_build(struct cl_engine *engine); */
288057e9
 START_TEST(test_cl_build)
 /*
fe473bcb
     struct cl_engine *engine;
     fail_unless(CL_ENULLARG == cl_build(NULL), "cl_build null pointer");
     engine = calloc(sizeof(struct cl_engine),1);
     fail_unless(engine, "cl_build calloc");
     fail_unless(CL_ENULLARG == cl_build(engine), "cl_build(engine) with null ->root");
     */
 /*    engine->root = cli_calloc(CL_TARGET_TABLE_SIZE, sizeof(struct cli_matcher *)); */
 END_TEST
 
 /* extern void cl_debug(void); */
288057e9
 START_TEST(test_cl_debug)
5cd3f734
 {
2b9e5d29
     int old_status = cli_debug_flag;
fe473bcb
     cli_debug_flag = 0;
     cl_debug();
     fail_unless(1 == cli_debug_flag, "cl_debug failed to set cli_debug_flag");
 
     cli_debug_flag = 1;
     cl_debug();
     fail_unless(1 == cli_debug_flag, "cl_debug failed when flag was already set");
2b9e5d29
     cli_debug_flag = old_status;
5cd3f734
 }
fe473bcb
 END_TEST
 
 /* extern const char *cl_retdbdir(void); */
288057e9
 START_TEST(test_cl_retdbdir)
 fail_unless(!strcmp(DATADIR, cl_retdbdir()), "cl_retdbdir");
fe473bcb
 END_TEST
 
add738d2
 #ifndef REPO_VERSION
 #define REPO_VERSION VERSION
 #endif
 
fe473bcb
 /* extern const char *cl_retver(void); */
288057e9
 START_TEST(test_cl_retver)
5cd3f734
 {
04f9bedf
     const char *ver = cl_retver();
288057e9
     fail_unless(!strcmp(REPO_VERSION "" VERSION_SUFFIX, ver), "cl_retver");
     fail_unless(strcspn(ver, "012345789") < strlen(ver),
                 "cl_retver must have a number");
5cd3f734
 }
fe473bcb
 END_TEST
 
 /* extern void cl_cvdfree(struct cl_cvd *cvd); */
288057e9
 START_TEST(test_cl_cvdfree)
fe473bcb
 /*
     struct cl_cvd *cvd1, *cvd2;
 
     cvd1 = malloc(sizeof(struct cl_cvd));
     fail_unless(cvd1, "cvd malloc");
     cl_cvdfree(cvd1);
 
     cvd2 = malloc(sizeof(struct cl_cvd));
     cvd2->time = malloc(1);
     cvd2->md5 = malloc(1);
     cvd2->dsig= malloc(1);
     cvd2->builder = malloc(1);
     fail_unless(cvd2, "cvd malloc");
     fail_unless(cvd2->time, "cvd malloc");
     fail_unless(cvd2->md5, "cvd malloc");
     fail_unless(cvd2->dsig, "cvd malloc");
     fail_unless(cvd2->builder, "cvd malloc");
     cl_cvdfree(cvd2);
     cl_cvdfree(NULL);
 */
 END_TEST
 
 /* extern int cl_statfree(struct cl_stat *dbstat); */
288057e9
 START_TEST(test_cl_statfree)
fe473bcb
 /*
     struct cl_stat *stat;
     fail_unless(CL_ENULLARG == cl_statfree(NULL), "cl_statfree(NULL)");
544fa973
 
fe473bcb
     stat = malloc(sizeof(struct cl_stat));
     fail_unless(NULL != stat, "malloc");
     fail_unless(CL_SUCCESS == cl_statfree(stat), "cl_statfree(empty_struct)");
544fa973
 
fe473bcb
     stat = malloc(sizeof(struct cl_stat));
     fail_unless(NULL != stat, "malloc");
     stat->stattab = strdup("test");
     fail_unless(NULL != stat->stattab, "strdup");
     fail_unless(CL_SUCCESS == cl_statfree(stat), "cl_statfree(stat with stattab)");
 
     stat = malloc(sizeof(struct cl_stat));
     fail_unless(NULL != stat, "malloc");
     stat->stattab = NULL;
     fail_unless(CL_SUCCESS == cl_statfree(stat), "cl_statfree(stat with stattab) set to NULL");
 */
 END_TEST
 
 /* extern unsigned int cl_retflevel(void); */
288057e9
 START_TEST(test_cl_retflevel)
 END_TEST
fe473bcb
 
 /* extern struct cl_cvd *cl_cvdhead(const char *file); */
288057e9
 START_TEST(test_cl_cvdhead)
fe473bcb
 /*
     fail_unless(NULL == cl_cvdhead(NULL), "cl_cvdhead(null)");
     fail_unless(NULL == cl_cvdhead("input/cl_cvdhead/1.txt"), "cl_cvdhead(515 byte file, all nulls)");
 */
288057e9
 /* the data read from the file is passed to cl_cvdparse, test cases for that are separate */
fe473bcb
 END_TEST
 
 /* extern struct cl_cvd *cl_cvdparse(const char *head); */
288057e9
 START_TEST(test_cl_cvdparse)
fe473bcb
 END_TEST
 
d5f7afdd
 static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size);
 static struct cl_engine *g_engine;
 
d1b44b4d
 #ifdef CHECK_HAVE_LOOPS
048a88e6
 /* int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, struct cl_scan_options* options) */
288057e9
 START_TEST(test_cl_scandesc)
d5f7afdd
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
d5f7afdd
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     cli_dbgmsg("scanning (scandesc) %s\n", file);
01eebc13
     ret = cl_scandesc(fd, file, &virname, &scanned, g_engine, &options);
d5f7afdd
     cli_dbgmsg("scan end (scandesc) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
d5f7afdd
     close(fd);
 }
fe473bcb
 END_TEST
 
288057e9
 START_TEST(test_cl_scandesc_allscan)
6ad45a29
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     cli_dbgmsg("scanning (scandesc) %s\n", file);
01eebc13
     ret = cl_scandesc(fd, file, &virname, &scanned, g_engine, &options);
a393d999
 
6ad45a29
     cli_dbgmsg("scan end (scandesc) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
6ad45a29
     close(fd);
 }
 END_TEST
 
 //* int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
288057e9
 START_TEST(test_cl_scanfile)
d5f7afdd
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
d5f7afdd
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     close(fd);
 
     cli_dbgmsg("scanning (scanfile) %s\n", file);
048a88e6
     ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
d5f7afdd
     cli_dbgmsg("scan end (scanfile) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
d5f7afdd
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scanfile_allscan)
6ad45a29
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     close(fd);
 
     cli_dbgmsg("scanning (scanfile_allscan) %s\n", file);
048a88e6
     ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
6ad45a29
     cli_dbgmsg("scan end (scanfile_allscan) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
6ad45a29
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scanfile_callback)
d5f7afdd
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
d5f7afdd
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     close(fd);
 
     cli_dbgmsg("scanning (scanfile_cb) %s\n", file);
     /* TODO: test callbacks */
048a88e6
     ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
d5f7afdd
     cli_dbgmsg("scan end (scanfile_cb) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
d5f7afdd
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scanfile_callback_allscan)
6ad45a29
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     close(fd);
 
     cli_dbgmsg("scanning (scanfile_cb_allscan) %s\n", file);
     /* TODO: test callbacks */
048a88e6
     ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
6ad45a29
     cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
6ad45a29
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scandesc_callback)
d5f7afdd
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
d5f7afdd
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
 
     cli_dbgmsg("scanning (scandesc_cb) %s\n", file);
     /* TODO: test callbacks */
01eebc13
     ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
d5f7afdd
     cli_dbgmsg("scan end (scandesc_cb) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
d5f7afdd
     close(fd);
 }
fe473bcb
 END_TEST
6ad45a29
 
288057e9
 START_TEST(test_cl_scandesc_callback_allscan)
6ad45a29
 {
     const char *virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
     int ret;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
 
     cli_dbgmsg("scanning (scandesc_cb_allscan) %s\n", file);
     /* TODO: test callbacks */
01eebc13
     ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
6ad45a29
     cli_dbgmsg("scan end (scandesc_cb_allscan) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
6ad45a29
     close(fd);
 }
 END_TEST
 
d1b44b4d
 #endif
fe473bcb
 
 /* int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options) */
288057e9
 START_TEST(test_cl_load)
fe473bcb
 END_TEST
 
 /* int cl_cvdverify(const char *file) */
288057e9
 START_TEST(test_cl_cvdverify)
fe473bcb
 END_TEST
 
 /* int cl_statinidir(const char *dirname, struct cl_stat *dbstat) */
288057e9
 START_TEST(test_cl_statinidir)
fe473bcb
 END_TEST
 
 /* int cl_statchkdir(const struct cl_stat *dbstat) */
288057e9
 START_TEST(test_cl_statchkdir)
fe473bcb
 END_TEST
 
 /* void cl_settempdir(const char *dir, short leavetemps) */
288057e9
 START_TEST(test_cl_settempdir)
fe473bcb
 END_TEST
 
 /* const char *cl_strerror(int clerror) */
288057e9
 START_TEST(test_cl_strerror)
fe473bcb
 END_TEST
 
288057e9
 static char **testfiles     = NULL;
d5f7afdd
 static unsigned testfiles_n = 0;
f0f3fe69
 
ca804a8d
 static const int expected_testfiles = 48;
d5f7afdd
 
f4f331ae
 static unsigned skip_files(void)
97fd85d1
 {
f4f331ae
     unsigned skipped = 0;
 
     /* skip .rar files if unrar is disabled */
97fd85d1
     const char *s = getenv("unrar_disabled");
f4f331ae
     if (s && !strcmp(s, "1")) {
         skipped += 2;
     }
97fd85d1
 
f4f331ae
     /* skip .bz2 files if bzip is disabled */
 #if HAVE_BZLIB_H
 #else
     skipped += 2;
 #endif
97fd85d1
 
f4f331ae
     /* skip [placeholder] files if xml is disabled */
 #if HAVE_LIBXML2
 #else
     skipped += 0;
 #endif
97fd85d1
 
f4f331ae
     return skipped;
97fd85d1
 }
 
d5f7afdd
 static void init_testfiles(void)
 {
     struct dirent *dirent;
     unsigned i = 0;
04ad6854
     int expect = expected_testfiles;
d5f7afdd
 
288057e9
     DIR *d = opendir(OBJDIR "/../test");
d5f7afdd
     fail_unless(!!d, "opendir");
     if (!d)
288057e9
         return;
     testfiles   = NULL;
d5f7afdd
     testfiles_n = 0;
     while ((dirent = readdir(d))) {
288057e9
         if (strncmp(dirent->d_name, "clam", 4))
             continue;
97fd85d1
         i++;
288057e9
         testfiles = cli_realloc(testfiles, i * sizeof(*testfiles));
         fail_unless(!!testfiles, "cli_realloc");
         testfiles[i - 1] = strdup(dirent->d_name);
d5f7afdd
     }
     testfiles_n = i;
b02190b4
     if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
         expect--;
f4f331ae
     expect -= skip_files();
04ad6854
     fail_unless_fmt(testfiles_n == expect, "testfiles: %d != %d", testfiles_n, expect);
d5f7afdd
 
     closedir(d);
 }
 
 static void free_testfiles(void)
 {
     unsigned i;
288057e9
     for (i = 0; i < testfiles_n; i++) {
         free(testfiles[i]);
d5f7afdd
     }
     free(testfiles);
288057e9
     testfiles   = NULL;
d5f7afdd
     testfiles_n = 0;
 }
 
 static int inited = 0;
 
 static void engine_setup(void)
 {
     unsigned int sigs = 0;
288057e9
     const char *hdb   = OBJDIR "/clamav.hdb";
d5f7afdd
 
     init_testfiles();
     if (!inited)
288057e9
         fail_unless(cl_init(CL_INIT_DEFAULT) == 0, "cl_init");
     inited   = 1;
d5f7afdd
     g_engine = cl_engine_new();
     fail_unless(!!g_engine, "engine");
     fail_unless_fmt(cl_load(hdb, g_engine, &sigs, CL_DB_STDOPT) == 0, "cl_load %s", hdb);
     fail_unless(sigs == 1, "sigs");
     fail_unless(cl_engine_compile(g_engine) == 0, "cl_engine_compile");
 }
 
 static void engine_teardown(void)
 {
     free_testfiles();
     cl_engine_free(g_engine);
 }
 
 static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size)
 {
     int fd;
a2a004df
     STATBUF st;
d5f7afdd
 
04ad6854
     fail_unless(i < testfiles_n, "%i < %i %s", i, testfiles_n, file);
288057e9
     snprintf(file, fsize, OBJDIR "/../test/%s", testfiles[i]);
d5f7afdd
 
     fd = open(file, O_RDONLY);
     fail_unless(fd > 0, "open");
a2a004df
     fail_unless(FSTAT(fd, &st) == 0, "fstat");
d5f7afdd
     *size = st.st_size;
     return fd;
 }
b32ad857
 #ifdef CHECK_HAVE_LOOPS
d5f7afdd
 
e8b63834
 static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
62ee12b2
 {
288057e9
     return pread(*((int *)handle), buf, count, offset);
62ee12b2
 }
 
288057e9
 START_TEST(test_cl_scanmap_callback_handle)
62ee12b2
 {
288057e9
     const char *virname       = NULL;
81e57728
     unsigned long int scanned = 0;
62ee12b2
     cl_fmap_t *map;
     int ret;
592e246c
     char file[256];
     unsigned long size;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
62ee12b2
 
592e246c
     int fd = get_test_file(_i, file, sizeof(file), &size);
62ee12b2
     /* intentionally use different way than scanners.c for testing */
592e246c
     map = cl_fmap_open_handle(&fd, 0, size, pread_cb, 1);
62ee12b2
     fail_unless(!!map, "cl_fmap_open_handle");
 
81e57728
     cli_dbgmsg("scanning (handle) %s\n", file);
01eebc13
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
81e57728
     cli_dbgmsg("scan end (handle) %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
62ee12b2
     close(fd);
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scanmap_callback_handle_allscan)
6ad45a29
 {
288057e9
     const char *virname       = NULL;
6ad45a29
     unsigned long int scanned = 0;
     cl_fmap_t *map;
     int ret;
     char file[256];
     unsigned long size;
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
     /* intentionally use different way than scanners.c for testing */
     map = cl_fmap_open_handle(&fd, 0, size, pread_cb, 1);
a393d999
     fail_unless(!!map, "cl_fmap_open_handle %s");
6ad45a29
 
     cli_dbgmsg("scanning (handle) allscan %s\n", file);
01eebc13
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
6ad45a29
     cli_dbgmsg("scan end (handle) allscan %s\n", file);
 
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
a393d999
     }
6ad45a29
     close(fd);
 }
 END_TEST
 
288057e9
 START_TEST(test_cl_scanmap_callback_mem)
62ee12b2
 {
288057e9
     const char *virname       = NULL;
81e57728
     unsigned long int scanned = 0;
62ee12b2
     cl_fmap_t *map;
     int ret;
     void *mem;
592e246c
     unsigned long size;
     char file[256];
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
62ee12b2
 
592e246c
     int fd = get_test_file(_i, file, sizeof(file), &size);
62ee12b2
 
592e246c
     mem = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
62ee12b2
     fail_unless(mem != MAP_FAILED, "mmap");
 
     /* intentionally use different way than scanners.c for testing */
592e246c
     map = cl_fmap_open_memory(mem, size);
62ee12b2
     fail_unless(!!map, "cl_fmap_open_mem");
 
81e57728
     cli_dbgmsg("scanning (mem) %s\n", file);
01eebc13
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
81e57728
     cli_dbgmsg("scan end (mem) %s\n", file);
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
a393d999
     }
62ee12b2
     close(fd);
0d54f271
     cl_fmap_close(map);
62ee12b2
 
592e246c
     munmap(mem, size);
62ee12b2
 }
 END_TEST
6ad45a29
 
288057e9
 START_TEST(test_cl_scanmap_callback_mem_allscan)
6ad45a29
 {
288057e9
     const char *virname       = NULL;
6ad45a29
     unsigned long int scanned = 0;
     cl_fmap_t *map;
     int ret;
     void *mem;
     unsigned long size;
     char file[256];
048a88e6
     struct cl_scan_options options;
 
     memset(&options, 0, sizeof(struct cl_scan_options));
     options.parse |= ~0;
     options.general |= CL_SCAN_GENERAL_ALLMATCHES;
6ad45a29
 
     int fd = get_test_file(_i, file, sizeof(file), &size);
 
     mem = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
     fail_unless(mem != MAP_FAILED, "mmap");
 
     /* intentionally use different way than scanners.c for testing */
     map = cl_fmap_open_memory(mem, size);
a393d999
     fail_unless(!!map, "cl_fmap_open_mem %s");
6ad45a29
 
     cli_dbgmsg("scanning (mem) allscan %s\n", file);
01eebc13
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
6ad45a29
     cli_dbgmsg("scan end (mem) allscan %s\n", file);
a393d999
     if (!FALSE_NEGATIVE) {
288057e9
         fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
         fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
a393d999
     }
6ad45a29
     close(fd);
     cl_fmap_close(map);
     munmap(mem, size);
 }
 END_TEST
b32ad857
 #endif
62ee12b2
 
c47e43ce
 static Suite *test_cl_suite(void)
fe473bcb
 {
288057e9
     Suite *s           = suite_create("cl_api");
     TCase *tc_cl       = tcase_create("cl_dup");
     TCase *tc_cl_scan  = tcase_create("cl_scan");
11bdd8a7
     char *user_timeout = NULL;
288057e9
     int expect         = expected_testfiles;
     suite_add_tcase(s, tc_cl);
fe473bcb
     tcase_add_test(tc_cl, test_cl_free);
     tcase_add_test(tc_cl, test_cl_dup);
     tcase_add_test(tc_cl, test_cl_build);
     tcase_add_test(tc_cl, test_cl_debug);
     tcase_add_test(tc_cl, test_cl_retdbdir);
     tcase_add_test(tc_cl, test_cl_retver);
     tcase_add_test(tc_cl, test_cl_cvdfree);
     tcase_add_test(tc_cl, test_cl_statfree);
     tcase_add_test(tc_cl, test_cl_retflevel);
     tcase_add_test(tc_cl, test_cl_cvdhead);
     tcase_add_test(tc_cl, test_cl_cvdparse);
     tcase_add_test(tc_cl, test_cl_load);
     tcase_add_test(tc_cl, test_cl_cvdverify);
     tcase_add_test(tc_cl, test_cl_statinidir);
     tcase_add_test(tc_cl, test_cl_statchkdir);
     tcase_add_test(tc_cl, test_cl_settempdir);
     tcase_add_test(tc_cl, test_cl_strerror);
 
d5f7afdd
     suite_add_tcase(s, tc_cl_scan);
288057e9
     tcase_add_checked_fixture(tc_cl_scan, engine_setup, engine_teardown);
d1b44b4d
 #ifdef CHECK_HAVE_LOOPS
b02190b4
     if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
         expect--;
f4f331ae
     expect -= skip_files();
04ad6854
     tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_allscan, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanfile, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_allscan, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback_allscan, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback_allscan, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle_allscan, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem, 0, expect);
     tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect);
11bdd8a7
 
     user_timeout = getenv("T");
     if (user_timeout) {
         int timeout = atoi(user_timeout);
         tcase_set_timeout(tc_cl_scan, timeout);
288057e9
         printf("Using test case timeout of %d seconds set by user\n", timeout);
c2b36ddd
     } else {
288057e9
         printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
11bdd8a7
     }
d1b44b4d
 #endif
fe473bcb
     return s;
 }
 
288057e9
 static uint8_t le_data[4]     = {0x67, 0x45, 0x23, 0x01};
 static int32_t le_expected[4] = {0x01234567, 0x67012345, 0x45670123, 0x23456701};
 uint8_t *data                 = NULL;
 uint8_t *data2                = NULL;
c47e43ce
 #define DATA_REP 100
 
 static void data_setup(void)
 {
288057e9
     uint8_t *p;
     size_t i;
 
     data  = malloc(sizeof(le_data) * DATA_REP);
     data2 = malloc(sizeof(le_data) * DATA_REP);
     fail_unless(!!data, "unable to allocate memory for fixture");
     fail_unless(!!data2, "unable to allocate memory for fixture");
     p = data;
     /* make multiple copies of le_data, we need to run readint tests in a loop, so we need
c47e43ce
          * to give it some data to run it on */
288057e9
     for (i = 0; i < DATA_REP; i++) {
         memcpy(p, le_data, sizeof(le_data));
         p += sizeof(le_data);
     }
     memset(data2, 0, DATA_REP * sizeof(le_data));
c47e43ce
 }
 
 static void data_teardown(void)
 {
288057e9
     free(data);
     free(data2);
c47e43ce
 }
 
99f74adc
 #ifdef CHECK_HAVE_LOOPS
c47e43ce
 /* test reading with different alignments, _i is parameter from tcase_add_loop_test */
288057e9
 START_TEST(test_cli_readint16)
2565ef49
 {
     size_t j;
     int16_t value;
     /* read 2 bytes apart, start is not always aligned*/
288057e9
     for (j = _i; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
         value = le_expected[j & 3];
2565ef49
         fail_unless(cli_readint16(&data[j]) == value, "(1) data read must be little endian");
     }
     /* read 2 bytes apart, always aligned*/
288057e9
     for (j = 0; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
         value = le_expected[j & 3];
2565ef49
         fail_unless(cli_readint16(&data[j]) == value, "(2) data read must be little endian");
     }
 }
 END_TEST
 
 /* test reading with different alignments, _i is parameter from tcase_add_loop_test */
288057e9
 START_TEST(test_cli_readint32)
c47e43ce
 {
     size_t j;
288057e9
     int32_t value = le_expected[_i & 3];
c47e43ce
     /* read 4 bytes apart, start is not always aligned*/
288057e9
     for (j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         fail_unless(cli_readint32(&data[j]) == value, "(1) data read must be little endian");
     }
     value = le_expected[0];
     /* read 4 bytes apart, always aligned*/
288057e9
     for (j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         fail_unless(cli_readint32(&data[j]) == value, "(2) data read must be little endian");
     }
 }
 END_TEST
 
 /* test writing with different alignments, _i is parameter from tcase_add_loop_test */
288057e9
 START_TEST(test_cli_writeint32)
c47e43ce
 {
     size_t j;
     /* write 4 bytes apart, start is not always aligned*/
288057e9
     for (j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         cli_writeint32(&data2[j], 0x12345678);
     }
288057e9
     for (j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
     }
     /* write 4 bytes apart, always aligned*/
288057e9
     for (j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         cli_writeint32(&data2[j], 0x12345678);
     }
288057e9
     for (j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
c47e43ce
         fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
     }
 }
 END_TEST
 
7b57a833
 static struct dsig_test {
     const char *md5;
     const char *dsig;
     int result;
288057e9
 } dsig_tests[] = {
     {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
      CL_SUCCESS},
7b57a833
     {"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
288057e9
      CL_SUCCESS},
7b57a833
     {"ae307614434715274c60854c931a26de", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
288057e9
      CL_EVERIFY},
7b57a833
     {"96b7feb3b2a863846438809fe481906f", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
288057e9
      CL_EVERIFY},
7b57a833
     {"ae307614434715274060854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
288057e9
      CL_EVERIFY},
7b57a833
     {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaatinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
288057e9
      CL_EVERIFY},
7b57a833
     {"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MYYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
288057e9
      CL_EVERIFY},
     {"ge307614434715274c60854c931a26dee", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
      CL_EVERIFY},
     {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGee",
      CL_EVERIFY},
     {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+",
      CL_EVERIFY}};
 
 static const size_t dsig_tests_cnt = sizeof(dsig_tests) / sizeof(dsig_tests[0]);
 
 START_TEST(test_cli_dsig)
7b57a833
 {
     fail_unless(cli_versig(dsig_tests[_i].md5, dsig_tests[_i].dsig) == dsig_tests[_i].result,
288057e9
                 "digital signature verification test failed");
7b57a833
 }
 END_TEST
 
4e46d65d
 static uint8_t tv1[3] = {
288057e9
     0x61, 0x62, 0x63};
4e46d65d
 
 static uint8_t tv2[56] = {
288057e9
     0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
     0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
     0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
     0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b,
     0x69, 0x6a, 0x6b, 0x6c, 0x6a, 0x6b, 0x6c, 0x6d,
     0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
     0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71};
4e46d65d
 
 static uint8_t res256[3][SHA256_HASH_SIZE] = {
288057e9
     {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
      0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
      0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
     {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
      0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
      0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
     {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2,
      0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
      0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
 
 START_TEST(test_sha256)
4e46d65d
 {
da6e06dd
     void *sha256;
4e46d65d
     uint8_t hsha256[SHA256_HASH_SIZE];
     uint8_t buf[1000];
     int i;
 
288057e9
     memset(buf, 0x61, sizeof(buf));
4e46d65d
 
b2e7c931
     cl_sha256(tv1, sizeof(tv1), hsha256, NULL);
288057e9
     fail_unless(!memcmp(hsha256, res256[0], sizeof(hsha256)), "sha256 test vector #1 failed");
4e46d65d
 
b2e7c931
     cl_sha256(tv2, sizeof(tv2), hsha256, NULL);
288057e9
     fail_unless(!memcmp(hsha256, res256[1], sizeof(hsha256)), "sha256 test vector #2 failed");
4e46d65d
 
da6e06dd
     sha256 = cl_hash_init("sha256");
f077c617
     fail_unless(sha256 != NULL, "Could not create EVP_MD_CTX for sha256");
 
4e46d65d
     for (i = 0; i < 1000; i++)
288057e9
         cl_update_hash(sha256, buf, sizeof(buf));
da6e06dd
     cl_finish_hash(sha256, hsha256);
288057e9
     fail_unless(!memcmp(hsha256, res256[2], sizeof(hsha256)), "sha256 test vector #3 failed");
4e46d65d
 }
 END_TEST
 
f8b3d2e5
 START_TEST(test_sanitize_path)
 {
     char *sanitized         = NULL;
     const char *unsanitized = NULL;
 
     unsanitized = "";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL != sanitized, "sanitize_path: Empty path test failed");
 
     unsanitized = NULL;
     sanitized   = cli_sanitize_filepath(unsanitized, 0);
     fail_if(NULL != sanitized, "sanitize_path: NULL path #1 test failed");
 
     unsanitized = NULL;
     sanitized   = cli_sanitize_filepath(unsanitized, 50);
     fail_if(NULL != sanitized, "sanitize_path: NULL path #2 test failed");
 
     unsanitized = "badlen";
     sanitized   = cli_sanitize_filepath(unsanitized, 0);
     fail_if(NULL != sanitized, "sanitize_path: Zero/bad path length test failed");
 
     unsanitized = ".." PATHSEP;
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL");
 
     unsanitized = "." PATHSEP;
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (2)");
 
     unsanitized = PATHSEP;
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (3)");
 
     unsanitized = ".." PATHSEP "relative_bad_1";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative_bad_1"), "sanitize_path: bad relative path test #1 failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP ".." PATHSEP "good";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "good"), "sanitize_path: good relative path test failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP ".." PATHSEP ".." PATHSEP "bad_2";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_2"), "sanitize_path: bad relative path test failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP "." PATHSEP ".." PATHSEP ".." PATHSEP "bad_current";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_current"), "sanitize_path: bad relative current path test failed");
     free(sanitized);
 
     unsanitized = "relative/../../bad_win_posix_path";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative/../bad_win_posix_path"), "sanitize_path: bad relative win posix path test failed");
     free(sanitized);
 
     unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP ".." PATHSEP "bad";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "bad"), "sanitize_path: bad absolute path test failed");
     free(sanitized);
 
     unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP "good";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "good"), "sanitize_path: good absolute path test failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP "normal";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP "normal"), "sanitize_path: relative normal path test failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP PATHSEP "doublesep";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP "doublesep"), "sanitize_path: relative double sep path test failed");
     free(sanitized);
 
     unsanitized = "relative" PATHSEP "shortname" PATHSEP "1";
     sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
     fail_if(NULL == sanitized);
     fail_unless(!strcmp(sanitized, "relative" PATHSEP "shortname" PATHSEP "1"), "sanitize_path: relative short name path test failed");
     free(sanitized);
 }
 END_TEST
 
c47e43ce
 static Suite *test_cli_suite(void)
 {
f8b3d2e5
     Suite *s               = suite_create("cli");
     TCase *tc_cli_others   = tcase_create("byteorder_macros");
     TCase *tc_cli_dsig     = tcase_create("digital signatures");
     TCase *tc_cli_assorted = tcase_create("assorted functions");
c47e43ce
 
288057e9
     suite_add_tcase(s, tc_cli_others);
     tcase_add_checked_fixture(tc_cli_others, data_setup, data_teardown);
7b57a833
     tcase_add_loop_test(tc_cli_others, test_cli_readint32, 0, 16);
     tcase_add_loop_test(tc_cli_others, test_cli_readint16, 0, 16);
     tcase_add_loop_test(tc_cli_others, test_cli_writeint32, 0, 16);
 
288057e9
     suite_add_tcase(s, tc_cli_dsig);
7b57a833
     tcase_add_loop_test(tc_cli_dsig, test_cli_dsig, 0, dsig_tests_cnt);
4e46d65d
     tcase_add_test(tc_cli_dsig, test_sha256);
c47e43ce
 
f8b3d2e5
     suite_add_tcase(s, tc_cli_assorted);
     tcase_add_test(tc_cli_assorted, test_sanitize_path);
 
c47e43ce
     return s;
 }
61b295f4
 #endif /* CHECK_HAVE_LOOPS */
c47e43ce
 
5ee56e41
 void errmsg_expected(void)
 {
288057e9
     fputs("cli_errmsg() expected here\n", stderr);
5ee56e41
 }
 
3dcc2d78
 int open_testfile(const char *name)
 {
288057e9
     int fd;
     const char *srcdir = getenv("srcdir");
     char *str;
 
     if (!srcdir) {
         /* when run from automake srcdir is set, but if run manually then not */
         srcdir = SRCDIR;
     }
 
     str = cli_malloc(strlen(name) + strlen(srcdir) + 2);
     fail_unless(!!str, "cli_malloc");
     sprintf(str, "%s/%s", srcdir, name);
 
     fd = open(str, O_RDONLY);
     fail_unless_fmt(fd >= 0, "open() failed: %s", str);
     free(str);
     return fd;
3dcc2d78
 }
 
1279faf6
 void diff_file_mem(int fd, const char *ref, size_t len)
 {
288057e9
     char c1, c2;
     size_t p, reflen = len;
     char *buf = cli_malloc(len);
 
     fail_unless_fmt(!!buf, "unable to malloc buffer: %d", len);
     p = read(fd, buf, len);
     fail_unless_fmt(p == len, "file is smaller: %lu, expected: %lu", p, len);
     p = 0;
     while (len > 0) {
         c1 = ref[p];
         c2 = buf[p];
         if (c1 != c2)
             break;
         p++;
         len--;
     }
     if (len > 0)
         fail_unless_fmt(c1 == c2, "file contents mismatch at byte: %lu, was: %c, expected: %c", p, c2, c1);
     free(buf);
     p = lseek(fd, 0, SEEK_END);
     fail_unless_fmt(p == reflen, "trailing garbage, file size: %ld, expected: %ld", p, reflen);
     close(fd);
1279faf6
 }
 
 void diff_files(int fd, int ref_fd)
 {
288057e9
     char *ref;
     ssize_t nread;
     off_t siz = lseek(ref_fd, 0, SEEK_END);
     fail_unless_fmt(siz != -1, "lseek failed");
 
     ref = cli_malloc(siz);
     fail_unless_fmt(!!ref, "unable to malloc buffer: %d", siz);
 
     fail_unless_fmt(lseek(ref_fd, 0, SEEK_SET) == 0, "lseek failed");
     nread = read(ref_fd, ref, siz);
     fail_unless_fmt(nread == siz, "short read, expected: %ld, was: %ld", siz, nread);
     close(ref_fd);
     diff_file_mem(fd, ref, siz);
     free(ref);
1279faf6
 }
 
7866b37c
 #ifdef USE_MPOOL
47d40feb
 static mpool_t *pool;
563582a1
 #else
 static void *pool;
 #endif
 struct cli_dconf *dconf;
 
 void dconf_setup(void)
 {
288057e9
     pool  = NULL;
     dconf = NULL;
7866b37c
 #ifdef USE_MPOOL
288057e9
     pool = mpool_create();
     fail_unless(!!pool, "unable to create pool");
563582a1
 #endif
288057e9
     dconf = cli_mpool_dconf_init(pool);
     fail_unless(!!dconf, "failed to init dconf");
563582a1
 }
 
 void dconf_teardown(void)
 {
544fa973
     MPOOL_FREE(pool, dconf);
7866b37c
 #ifdef USE_MPOOL
288057e9
     if (pool)
         mpool_destroy(pool);
563582a1
 #endif
 }
 
acba3cf5
 static void check_version_compatible()
 {
     /* check 0.9.8 is not ABI compatible with 0.9.6,
      * if by accident you compile with check 0.9.6 header
      * and link with 0.9.8 then check will hang/crash. */
     if ((check_major_version != CHECK_MAJOR_VERSION) ||
288057e9
         (check_minor_version != CHECK_MINOR_VERSION) ||
         (check_micro_version != CHECK_MICRO_VERSION)) {
         fprintf(stderr, "ERROR: check version mismatch!\n"
                         "\tVersion from header: %u.%u.%u\n"
                         "\tVersion from library: %u.%u.%u\n"
                         "\tMake sure check.h and -lcheck are same version!\n",
                 CHECK_MAJOR_VERSION,
                 CHECK_MINOR_VERSION,
                 CHECK_MICRO_VERSION,
                 check_major_version,
                 check_minor_version,
                 check_micro_version);
         exit(EXIT_FAILURE);
acba3cf5
     }
 }
563582a1
 
15adbc84
 int main(void)
fe473bcb
 {
c47e43ce
     int nf;
acba3cf5
     Suite *s;
     SRunner *sr;
 
f9afc309
     cl_initialize_crypto();
 
288057e9
     fpu_words = get_fpu_endian();
 
acba3cf5
     check_version_compatible();
288057e9
     s  = test_cl_suite();
acba3cf5
     sr = srunner_create(s);
99f74adc
 #ifdef CHECK_HAVE_LOOPS
c47e43ce
     srunner_add_suite(sr, test_cli_suite());
61b295f4
 #else
abbd1d36
     printf("*** Warning ***: your check version is too old,\nseveral important tests will not execute\n");
99f74adc
 #endif
4a6ade44
     srunner_add_suite(sr, test_jsnorm_suite());
eb290151
     srunner_add_suite(sr, test_str_suite());
9ee053fe
     srunner_add_suite(sr, test_regex_suite());
c92b0057
     srunner_add_suite(sr, test_disasm_suite());
5e07cfed
     srunner_add_suite(sr, test_uniq_suite());
ec285505
     srunner_add_suite(sr, test_matchers_suite());
1279faf6
     srunner_add_suite(sr, test_htmlnorm_suite());
d99c0c42
     srunner_add_suite(sr, test_bytecode_suite());
fe473bcb
 
     srunner_set_log(sr, "test.log");
288057e9
     if (freopen("test-stderr.log", "w+", stderr) == NULL) {
         fputs("Unable to redirect stderr!\n", stderr);
a497dce5
     }
5cd3f734
     cl_debug();
5ee56e41
 
fe473bcb
     srunner_run_all(sr, CK_NORMAL);
     nf = srunner_ntests_failed(sr);
c2b36ddd
     if (nf)
288057e9
         printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
fe473bcb
     srunner_free(sr);
62ee12b2
 
849cdc78
 #if HAVE_LIBXML2
     xmlCleanupParser();
 #endif
f9afc309
 
fe473bcb
     return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }