clamav/libclamav/cache.c

186 lines
4 KiB
C
Raw Normal View History

2009-08-11 12:23:14 +02:00
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
2009-08-11 12:23:14 +02:00
#include "md5.h"
#include "mpool.h"
#include "clamav.h"
#include "cache.h"
2010-01-05 14:56:33 +01:00
#include "fmap.h"
2009-08-11 12:23:14 +02:00
#define CACHE_PERTURB 10
/* 1/10th */
static mpool_t *mempool = NULL;
static struct CACHE {
struct CACHE_ENTRY {
unsigned char hash[15];
uint32_t dbver;
uint32_t hits;
} *items;
pthread_mutex_t mutex;
uint32_t lastdb;
} *cache = NULL;
static unsigned int cache_entries = 0;
2010-01-05 14:56:33 +01:00
int cl_cache_init(unsigned int entries) {
2009-08-11 12:23:14 +02:00
unsigned int i;
if(!(mempool = mpool_create())) {
cli_errmsg("mpool init fail\n");
return 1;
}
if(!(cache = mpool_malloc(mempool, sizeof(struct CACHE) * 256))) {
cli_errmsg("mpool malloc fail\n");
mpool_destroy(mempool);
return 1;
}
for(i=0; i<256; i++) {
struct CACHE_ENTRY *e = mpool_calloc(mempool, sizeof(struct CACHE_ENTRY), entries);
if(!e) {
cli_errmsg("mpool calloc fail\n");
mpool_destroy(mempool);
return 1;
}
cache[i].items = e;
cache[i].lastdb = 0;
if(pthread_mutex_init(&cache[i].mutex, NULL)) {
cli_errmsg("mutex init fail\n");
mpool_destroy(mempool);
return 1;
}
}
cache_entries = entries;
return 0;
}
void cache_swap(struct CACHE_ENTRY *e, unsigned int a) {
struct CACHE_ENTRY t;
unsigned int b = a-1;
if(!a || e[a].hits <= e[b].hits)
return;
do {
if(e[a].hits > e[b].hits)
continue;
break;
} while(b--);
b++;
memcpy(&t, &e[a], sizeof(t));
memcpy(&e[a], &e[b], sizeof(t));
memcpy(&e[b], &t, sizeof(t));
}
2010-01-05 14:56:33 +01:00
static void updb(uint32_t db, unsigned int skip) {
2009-08-11 12:23:14 +02:00
unsigned int i;
for(i=0; i<256; i++) {
if(i==skip) continue;
if(pthread_mutex_lock(&cache[i].mutex)) {
cli_errmsg("mutex lock fail\n");
continue;
}
cache[i].lastdb = db;
pthread_mutex_unlock(&cache[i].mutex);
}
}
2010-01-05 14:56:33 +01:00
static int cache_lookup_hash(unsigned char *md5, cli_ctx *ctx) {
2009-08-11 12:23:14 +02:00
unsigned int i;
int ret = CL_VIRUS;
struct CACHE_ENTRY *e;
struct CACHE *c;
if(!cache) return ret;
c = &cache[*md5];
e = c->items;
if(pthread_mutex_lock(&c->mutex)) {
cli_errmsg("mutex lock fail\n");
return ret;
}
if(c->lastdb <= ctx->engine->dbversion[0]) {
if(c->lastdb < ctx->engine->dbversion[0]) {
c->lastdb = ctx->engine->dbversion[0];
updb(c->lastdb, *md5);
} else {
for(i=0; i<cache_entries; i++) {
if(!e[i].hits) break;
if(e[i].dbver == c->lastdb && !memcmp(e[i].hash, md5 + 1, 15)) {
e[i].hits++;
cache_swap(e, i);
ret = CL_CLEAN;
cli_warnmsg("cached\n");
break;
}
}
}
}
pthread_mutex_unlock(&c->mutex);
return ret;
}
void cache_add(unsigned char *md5, cli_ctx *ctx) {
unsigned int i, replace;
struct CACHE_ENTRY *e;
struct CACHE *c;
if(!cache) return;
c = &cache[*md5];
e = c->items;
if(pthread_mutex_lock(&c->mutex)) {
cli_errmsg("mutex lock fail\n");
return;
}
if(c->lastdb == ctx->engine->dbversion[0]) {
replace = cache_entries;
for(i=0; i<cache_entries; i++) {
if(!e[i].hits) break;
if(replace == cache_entries && e[i].dbver < c->lastdb) {
replace = i;
} else if(e[i].hits && !memcmp(e[i].hash, md5 + 1, 15)) {
e[i].hits++;
cache_swap(e, i);
pthread_mutex_unlock(&c->mutex);
return;
}
}
if(replace == cache_entries)
replace = cache_entries - 1 - (rand() % (cache_entries / CACHE_PERTURB));
e[replace].hits = 1;
e[replace].dbver = c->lastdb;
memcpy(e[replace].hash, md5 + 1, 15);
cache_swap(e, replace);
}
pthread_mutex_unlock(&c->mutex);
return;
}
2010-01-05 14:56:33 +01:00
int cache_check(unsigned char *hash, cli_ctx *ctx) {
fmap_t *map = *ctx->fmap;
2010-01-05 15:27:36 +01:00
size_t todo = map->len, at = 0;
2009-08-11 12:23:14 +02:00
cli_md5_ctx md5;
if(!cache) return CL_VIRUS;
cli_md5_init(&md5);
2010-01-05 14:56:33 +01:00
while(todo) {
void *buf;
size_t readme = todo < FILEBUFF ? todo : FILEBUFF;
2010-01-05 15:27:36 +01:00
if(!(buf = fmap_need_off_once(map, at, readme)))
2009-08-11 12:23:14 +02:00
return CL_VIRUS;
2010-01-05 14:56:33 +01:00
todo -= readme;
at += readme;
2009-08-11 12:23:14 +02:00
cli_md5_update(&md5, buf, readme);
}
cli_md5_final(hash, &md5);
2010-01-05 14:56:33 +01:00
return cache_lookup_hash(hash, ctx);
2009-08-11 12:23:14 +02:00
}