2010-01-05 19:07:23 +01:00
/*
2019-01-25 10:15:50 -05:00
* Copyright ( C ) 2013 - 2019 Cisco Systems , Inc . and / or its affiliates . All rights reserved .
* Copyright ( C ) 2010 - 2013 Sourcefire , Inc .
2010-01-05 19:07:23 +01:00
*
2010-01-07 23:38:33 +01:00
* Authors : aCaB < acab @ clamav . net > , Török Edvin < edwin @ clamav . net >
2010-01-05 19:07:23 +01:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*/
2010-01-05 18:15:59 +01:00
# if HAVE_CONFIG_H
# include "clamav-config.h"
# endif
2010-01-06 19:32:34 +02:00
# include <string.h>
# include <stdlib.h>
# include <pthread.h>
# include <assert.h>
2010-01-05 18:15:59 +01:00
2009-08-11 12:23:14 +02:00
# 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
2010-05-07 13:00:11 +03:00
# ifdef CL_THREAD_SAFE
static pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER ;
# else
# define pthread_mutex_lock(x) 0
# define pthread_mutex_unlock(x)
# define pthread_mutex_init(a, b) 0
2018-12-03 12:40:13 -05:00
# define pthread_mutex_destroy(a) \
do { \
} while ( 0 )
2010-05-07 13:00:11 +03:00
# endif
2010-01-15 03:00:15 +01:00
2019-05-03 18:16:03 -04:00
/* The number of root trees and the chooser function
2010-01-15 03:00:15 +01:00
Each tree is protected by a mutex against concurrent access */
/* #define TREES 1 */
/* static inline unsigned int getkey(uint8_t *hash) { return 0; } */
# define TREES 256
2018-12-03 12:40:13 -05:00
static inline unsigned int getkey ( uint8_t * hash )
{
return * hash ;
}
2010-01-15 03:00:15 +01:00
/* #define TREES 4096 */
/* static inline unsigned int getkey(uint8_t *hash) { return hash[0] | ((unsigned int)(hash[1] & 0xf)<<8) ; } */
/* #define TREES 65536 */
/* static inline unsigned int getkey(uint8_t *hash) { return hash[0] | (((unsigned int)hash[1])<<8) ; } */
/* The number of nodes in each tree */
2010-01-14 18:54:53 +01:00
# define NODES 256
2010-01-09 02:19:25 +01:00
2010-01-15 03:00:15 +01:00
/* The replacement policy algorithm to use */
/* #define USE_LRUHASHCACHE */
2010-01-11 13:10:36 +01:00
# define USE_SPLAY
2010-01-06 19:32:34 +02:00
2010-01-15 03:00:15 +01:00
/* LRUHASHCACHE --------------------------------------------------------------------- */
2010-01-09 02:19:25 +01:00
# ifdef USE_LRUHASHCACHE
2010-01-08 16:05:02 +01:00
struct cache_key {
2010-01-14 04:38:31 +01:00
int64_t digest [ 2 ] ;
2010-01-08 16:05:02 +01:00
uint32_t size ; /* 0 is used to mark an empty hash slot! */
struct cache_key * lru_next , * lru_prev ;
} ;
struct cache_set {
struct cache_key * data ;
size_t maxelements ; /* considering load factor */
2010-01-14 04:38:31 +01:00
size_t maxdeleted ;
2010-01-08 16:05:02 +01:00
size_t elements ;
2010-01-14 04:38:31 +01:00
size_t deleted ;
2010-01-08 16:05:02 +01:00
struct cache_key * lru_head , * lru_tail ;
} ;
# define CACHE_KEY_DELETED ~0u
# define CACHE_KEY_EMPTY 0
static void cacheset_lru_remove ( struct cache_set * map , size_t howmany )
{
while ( howmany - - ) {
2018-12-03 12:40:13 -05:00
struct cache_key * old ;
assert ( map - > lru_head ) ;
/* Remove a key from the head of the list */
old = map - > lru_head ;
assert ( ! old - > lru_prev ) ;
map - > lru_head = old - > lru_next ;
old - > size = CACHE_KEY_DELETED ;
/* This slot is now deleted, it is not empty,
2010-01-08 16:05:02 +01:00
* because previously we could have inserted a key that has seen this
* slot as occupied , to find that key we need to ensure that all keys
* that were occupied when the key was inserted , are seen as occupied
* when searching too .
* Of course when inserting a new value , we treat deleted slots as
* empty .
* We only replace old values with new values , but there is no guarantee
* that the newly inserted value would hash to same place as the value
* we remove due to LRU ! */
2018-12-03 12:40:13 -05:00
if ( old = = map - > lru_tail )
map - > lru_tail = 0 ;
map - > elements - - ;
map - > deleted + + ;
2010-01-08 16:05:02 +01:00
}
}
2010-01-14 04:38:31 +01:00
static inline int cacheset_lookup_internal ( struct cache_set * map ,
2018-12-03 12:40:13 -05:00
const char * md5 , size_t size ,
uint32_t * insert_pos , int deletedok )
2010-01-08 16:05:02 +01:00
{
2018-12-03 12:40:13 -05:00
const struct cache_key * data = map - > data ;
uint32_t capmask = NODES - 1 ;
2010-01-14 04:38:31 +01:00
const struct cache_key * k ;
uint32_t idx , tries = 0 ;
uint64_t md5_0 , md5_1 ;
uint64_t md5a [ 2 ] ;
memcpy ( & md5a , md5 , 16 ) ;
md5_0 = md5a [ 0 ] ;
md5_1 = md5a [ 1 ] ;
2018-12-03 12:40:13 -05:00
idx = md5_1 & capmask ;
k = & data [ idx ] ;
2010-01-14 04:38:31 +01:00
while ( k - > size ! = CACHE_KEY_EMPTY & & tries < = capmask ) {
2018-12-03 12:40:13 -05:00
if ( k - > digest [ 0 ] = = md5_0 & &
k - > digest [ 1 ] = = md5_1 & &
k - > size = = size ) {
/* found key */
* insert_pos = idx ;
return 1 ;
}
if ( deletedok & & k - > size = = CACHE_KEY_DELETED ) {
/* treat deleted slot as empty */
* insert_pos = idx ;
return 0 ;
}
idx = ( idx + tries + + ) & capmask ;
k = & data [ idx ] ;
2010-01-08 16:05:02 +01:00
}
/* found empty pos */
* insert_pos = idx ;
return 0 ;
}
static inline void lru_remove ( struct cache_set * map , struct cache_key * newkey )
{
if ( newkey - > lru_next )
2018-12-03 12:40:13 -05:00
newkey - > lru_next - > lru_prev = newkey - > lru_prev ;
2010-01-08 16:05:02 +01:00
if ( newkey - > lru_prev )
2018-12-03 12:40:13 -05:00
newkey - > lru_prev - > lru_next = newkey - > lru_next ;
2010-01-08 16:05:02 +01:00
if ( newkey = = map - > lru_head )
2018-12-03 12:40:13 -05:00
map - > lru_head = newkey - > lru_next ;
2010-01-08 16:05:02 +01:00
}
static inline void lru_addtail ( struct cache_set * map , struct cache_key * newkey )
{
if ( ! map - > lru_head )
2018-12-03 12:40:13 -05:00
map - > lru_head = newkey ;
2010-01-08 16:05:02 +01:00
if ( map - > lru_tail )
2018-12-03 12:40:13 -05:00
map - > lru_tail - > lru_next = newkey ;
2010-01-08 16:05:02 +01:00
newkey - > lru_next = NULL ;
newkey - > lru_prev = map - > lru_tail ;
2018-12-03 12:40:13 -05:00
map - > lru_tail = newkey ;
2010-01-08 16:05:02 +01:00
}
2010-01-14 18:54:53 +01:00
static void cacheset_add ( struct cache_set * map , unsigned char * md5 , size_t size , mpool_t * mempool ) ;
static int cacheset_init ( struct cache_set * map , mpool_t * mempool ) ;
2010-01-14 04:38:31 +01:00
2010-01-14 18:54:53 +01:00
static void cacheset_rehash ( struct cache_set * map , mpool_t * mempool )
2010-01-14 04:38:31 +01:00
{
unsigned i ;
int ret ;
struct cache_set tmp_set ;
struct cache_key * key ;
pthread_mutex_lock ( & pool_mutex ) ;
2010-01-14 18:54:53 +01:00
ret = cacheset_init ( & tmp_set , mempool ) ;
2010-01-14 04:38:31 +01:00
pthread_mutex_unlock ( & pool_mutex ) ;
if ( ret )
2018-12-03 12:40:13 -05:00
return ;
2010-01-14 04:38:31 +01:00
key = map - > lru_head ;
2018-12-03 12:40:13 -05:00
for ( i = 0 ; key & & i < tmp_set . maxelements / 2 ; i + + ) {
cacheset_add ( & tmp_set , ( unsigned char * ) & key - > digest , key - > size , mempool ) ;
key = key - > lru_next ;
2010-01-14 04:38:31 +01:00
}
pthread_mutex_lock ( & pool_mutex ) ;
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( mempool , map - > data ) ;
2010-01-14 04:38:31 +01:00
pthread_mutex_unlock ( & pool_mutex ) ;
memcpy ( map , & tmp_set , sizeof ( tmp_set ) ) ;
}
2010-01-14 18:54:53 +01:00
static void cacheset_add ( struct cache_set * map , unsigned char * md5 , size_t size , mpool_t * mempool )
2010-01-08 16:05:02 +01:00
{
int ret ;
uint32_t pos ;
struct cache_key * newkey ;
2010-01-14 04:38:31 +01:00
if ( map - > elements > = map - > maxelements ) {
2018-12-03 12:40:13 -05:00
cacheset_lru_remove ( map , 1 ) ;
if ( map - > deleted > = map - > maxdeleted ) {
cacheset_rehash ( map , mempool ) ;
}
2010-01-14 04:38:31 +01:00
}
2010-01-08 16:05:02 +01:00
assert ( map - > elements < map - > maxelements ) ;
2018-12-03 12:40:13 -05:00
ret = cacheset_lookup_internal ( map , md5 , size , & pos , 1 ) ;
2010-01-08 16:05:02 +01:00
newkey = & map - > data [ pos ] ;
2010-01-14 04:38:31 +01:00
if ( newkey - > size = = CACHE_KEY_DELETED )
2018-12-03 12:40:13 -05:00
map - > deleted - - ;
2010-01-08 16:05:02 +01:00
if ( ret ) {
2018-12-03 12:40:13 -05:00
/* was already added, remove from LRU list */
lru_remove ( map , newkey ) ;
2010-01-08 16:05:02 +01:00
}
/* add new key to tail of LRU list */
2010-01-09 02:19:25 +01:00
memcpy ( & map - > data [ pos ] . digest , md5 , sizeof ( map - > data [ pos ] . digest ) ) ;
map - > data [ pos ] . size = size ;
2010-01-08 16:05:02 +01:00
lru_addtail ( map , newkey ) ;
map - > elements + + ;
assert ( pos < map - > maxelements ) ;
}
2012-11-27 11:24:52 -05:00
static void cacheset_remove ( struct cache_set * map , unsigned char * md5 , size_t size , mpool_t * mempool )
{
int ret ;
uint32_t pos ;
struct cache_key * newkey ;
2018-12-03 12:40:13 -05:00
ret = cacheset_lookup_internal ( map , md5 , size , & pos , 1 ) ;
2012-11-27 11:24:52 -05:00
newkey = & map - > data [ pos ] ;
if ( ! ret | | ( newkey - > size = = CACHE_KEY_DELETED ) ) {
/* already deleted */
return ;
}
/* remove from list */
lru_remove ( map , newkey ) ;
newkey - > size = CACHE_KEY_DELETED ;
map - > deleted + + ;
map - > elements - - ;
if ( map - > deleted > = map - > maxdeleted ) {
cacheset_rehash ( map , mempool ) ;
}
}
2010-01-09 02:19:25 +01:00
static int cacheset_lookup ( struct cache_set * map , unsigned char * md5 , size_t size )
2010-01-08 16:05:02 +01:00
{
struct cache_key * newkey ;
int ret ;
uint32_t pos ;
2010-01-14 04:38:31 +01:00
2010-01-09 02:19:25 +01:00
ret = cacheset_lookup_internal ( map , md5 , size , & pos , 0 ) ;
2010-01-08 16:05:02 +01:00
if ( ! ret )
2018-12-03 12:40:13 -05:00
return 0 ;
2010-01-08 16:05:02 +01:00
newkey = & map - > data [ pos ] ;
/* update LRU position: move to tail */
lru_remove ( map , newkey ) ;
lru_addtail ( map , newkey ) ;
2010-01-14 18:54:53 +01:00
return 1 ;
2010-01-08 16:05:02 +01:00
}
2018-12-03 12:40:13 -05:00
static int cacheset_init ( struct cache_set * map , mpool_t * mempool )
{
2019-05-03 18:16:03 -04:00
map - > data = MPOOL_CALLOC ( mempool , NODES , sizeof ( * map - > data ) ) ;
2010-01-09 02:19:25 +01:00
if ( ! map - > data )
2018-12-03 12:40:13 -05:00
return CL_EMEM ;
2010-01-14 18:54:53 +01:00
map - > maxelements = 80 * NODES / 100 ;
2018-12-03 12:40:13 -05:00
map - > maxdeleted = NODES - map - > maxelements - 1 ;
map - > elements = 0 ;
2010-01-09 02:19:25 +01:00
map - > lru_head = map - > lru_tail = NULL ;
return 0 ;
}
2010-01-14 18:54:53 +01:00
2018-12-03 12:40:13 -05:00
static inline void cacheset_destroy ( struct cache_set * cs , mpool_t * mempool )
{
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( mempool , cs - > data ) ;
2010-01-14 18:54:53 +01:00
cs - > data = NULL ;
}
2010-01-09 16:21:48 +01:00
# endif /* USE_LRUHASHCACHE */
2010-01-09 02:19:25 +01:00
2010-01-15 03:00:15 +01:00
/* SPLAY --------------------------------------------------------------------- */
2010-01-09 02:19:25 +01:00
# ifdef USE_SPLAY
2010-01-15 03:00:15 +01:00
struct node { /* a node */
2010-01-09 16:21:48 +01:00
int64_t digest [ 2 ] ;
2010-01-09 02:19:25 +01:00
struct node * left ;
struct node * right ;
2010-01-11 13:10:36 +01:00
struct node * up ;
2010-01-13 00:03:30 +01:00
struct node * next ;
struct node * prev ;
2010-01-10 20:24:09 +01:00
uint32_t size ;
2010-03-05 22:17:46 +01:00
uint32_t minrec ;
2010-01-09 02:19:25 +01:00
} ;
2010-01-15 03:00:15 +01:00
struct cache_set { /* a tree */
2010-01-09 02:19:25 +01:00
struct node * data ;
struct node * root ;
2010-01-13 00:03:30 +01:00
struct node * first ;
struct node * last ;
2010-01-09 02:19:25 +01:00
} ;
2010-01-15 03:00:15 +01:00
/* Allocates all the nodes and sets up the replacement chain */
2018-12-03 12:40:13 -05:00
static int cacheset_init ( struct cache_set * cs , mpool_t * mempool )
{
2010-01-13 00:03:30 +01:00
unsigned int i ;
2019-05-03 18:16:03 -04:00
cs - > data = MPOOL_CALLOC ( mempool , NODES , sizeof ( * cs - > data ) ) ;
2010-01-13 00:03:30 +01:00
cs - > root = NULL ;
2010-01-09 02:19:25 +01:00
2018-12-03 12:40:13 -05:00
if ( ! cs - > data )
return 1 ;
2010-01-13 00:03:30 +01:00
2018-12-03 12:40:13 -05:00
for ( i = 1 ; i < NODES ; i + + ) {
cs - > data [ i - 1 ] . next = & cs - > data [ i ] ;
cs - > data [ i ] . prev = & cs - > data [ i - 1 ] ;
2010-01-13 00:03:30 +01:00
}
cs - > first = cs - > data ;
2018-12-03 12:40:13 -05:00
cs - > last = & cs - > data [ NODES - 1 ] ;
2010-01-13 00:03:30 +01:00
2010-01-09 02:19:25 +01:00
return 0 ;
}
2010-01-15 03:00:15 +01:00
/* Frees all the nodes */
2018-12-03 12:40:13 -05:00
static inline void cacheset_destroy ( struct cache_set * cs , mpool_t * mempool )
{
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( mempool , cs - > data ) ;
2010-01-14 18:54:53 +01:00
cs - > data = NULL ;
}
2010-01-15 03:00:15 +01:00
/* The left/right cooser for the splay tree */
2018-12-03 12:40:13 -05:00
static inline int cmp ( int64_t * a , ssize_t sa , int64_t * b , ssize_t sb )
{
if ( a [ 1 ] < b [ 1 ] ) return - 1 ;
if ( a [ 1 ] > b [ 1 ] ) return 1 ;
if ( a [ 0 ] < b [ 0 ] ) return - 1 ;
if ( a [ 0 ] > b [ 0 ] ) return 1 ;
if ( sa < sb ) return - 1 ;
if ( sa > sb ) return 1 ;
2010-01-15 03:00:15 +01:00
return 0 ;
2010-01-09 16:21:48 +01:00
}
2010-01-09 02:19:25 +01:00
2010-01-15 03:00:15 +01:00
/* #define PRINT_TREE */
2010-01-14 04:38:31 +01:00
# ifdef PRINT_TREE
# define ptree printf
# else
2010-01-15 03:00:15 +01:00
# define ptree(...)
2010-01-14 04:38:31 +01:00
# endif
2010-01-15 03:00:15 +01:00
/* Debug function to print the tree and check its consistency */
/* #define CHECK_TREE */
2010-01-14 04:38:31 +01:00
# ifdef CHECK_TREE
2018-12-03 12:40:13 -05:00
static int printtree ( struct cache_set * cs , struct node * n , int d )
{
2010-01-14 04:38:31 +01:00
int i ;
int ab = 0 ;
2013-04-15 17:58:26 -04:00
if ( ( n = = NULL ) | | ( cs = = NULL ) | | ( cs - > data = = NULL ) ) return 0 ;
2018-12-03 12:40:13 -05:00
if ( n = = cs - > root ) {
ptree ( " -------------------------- \n " ) ;
}
ab | = printtree ( cs , n - > right , d + 1 ) ;
if ( n - > right ) {
if ( cmp ( n - > digest , n - > size , n - > right - > digest , n - > right - > size ) > = 0 ) {
for ( i = 0 ; i < d ; i + + ) ptree ( " " ) ;
ptree ( " ^^^^ %lld >= %lld \n " , n - > digest [ 1 ] , n - > right - > digest [ 1 ] ) ;
ab = 1 ;
}
}
for ( i = 0 ; i < d ; i + + ) ptree ( " " ) ;
ptree ( " %08x(%02u) \n " , n - > digest [ 1 ] > > 48 , n - cs - > data ) ;
if ( n - > left ) {
if ( cmp ( n - > digest , n - > size , n - > left - > digest , n - > left - > size ) < = 0 ) {
for ( i = 0 ; i < d ; i + + ) ptree ( " " ) ;
ptree ( " vvvv %lld <= %lld \n " , n - > digest [ 1 ] , n - > left - > digest [ 1 ] ) ;
ab = 1 ;
}
}
if ( d ) {
if ( ! n - > up ) {
printf ( " no parent, [node %02u]! \n " , n - cs - > data ) ;
ab = 1 ;
} else {
if ( n - > up - > left ! = n & & n - > up - > right ! = n ) {
printf ( " broken parent [node %02u, parent node %02u] \n " , n - cs - > data , n - > up - cs - > data ) ;
ab = 1 ;
}
}
2010-01-14 04:38:31 +01:00
} else {
2018-12-03 12:40:13 -05:00
if ( n - > up ) {
printf ( " root with a parent, [node %02u]! \n " , n - cs - > data ) ;
ab = 1 ;
}
2010-01-14 04:38:31 +01:00
}
2018-12-03 12:40:13 -05:00
ab | = printtree ( cs , n - > left , d + 1 ) ;
2010-01-14 04:38:31 +01:00
return ab ;
}
# else
2018-12-03 12:40:13 -05:00
# define printtree(a, b, c) (0)
2010-01-14 04:38:31 +01:00
# endif
2013-04-15 17:58:26 -04:00
/* For troubleshooting only; prints out one specific node */
/* #define PRINT_NODE */
# ifdef PRINT_NODE
2018-12-03 12:40:13 -05:00
static void printnode ( const char * prefix , struct cache_set * cs , struct node * n )
{
2013-04-15 17:58:26 -04:00
if ( ! prefix | | ! cs | | ! cs - > data ) {
printf ( " bad args! \n " ) ;
return ;
}
if ( ! n ) {
printf ( " no node! \n " ) ;
return ;
}
printf ( " %s node [%02u]: " , prefix , n - cs - > data ) ;
printf ( " size=%lu digest=%llx,%llx \n " , ( unsigned long ) ( n - > size ) , n - > digest [ 0 ] , n - > digest [ 1 ] ) ;
printf ( " \t left= " ) ;
2018-12-03 12:40:13 -05:00
if ( n - > left )
2013-04-15 17:58:26 -04:00
printf ( " %02u " , n - > left - cs - > data ) ;
else
printf ( " NULL " ) ;
printf ( " right= " ) ;
2018-12-03 12:40:13 -05:00
if ( n - > right )
2013-04-15 17:58:26 -04:00
printf ( " %02u " , n - > right - cs - > data ) ;
else
printf ( " NULL " ) ;
printf ( " up= " ) ;
2018-12-03 12:40:13 -05:00
if ( n - > up )
2013-04-15 17:58:26 -04:00
printf ( " %02u " , n - > up - cs - > data ) ;
else
printf ( " NULL " ) ;
printf ( " \t prev= " ) ;
2018-12-03 12:40:13 -05:00
if ( n - > prev )
2013-04-15 17:58:26 -04:00
printf ( " %02u " , n - > prev - cs - > data ) ;
else
printf ( " NULL " ) ;
printf ( " next= " ) ;
2018-12-03 12:40:13 -05:00
if ( n - > next )
2013-04-15 17:58:26 -04:00
printf ( " %02u \n " , n - > next - cs - > data ) ;
else
printf ( " NULL \n " ) ;
}
# else
2018-12-03 12:40:13 -05:00
# define printnode(a, b, c) (0)
2013-04-15 17:58:26 -04:00
# endif
/* #define PRINT_CHAINS */
# ifdef PRINT_CHAINS
/* For troubleshooting only, print the chain forwards and back */
2018-12-03 12:40:13 -05:00
static inline void printchain ( const char * prefix , struct cache_set * cs )
{
2013-04-15 17:58:26 -04:00
if ( ! cs | | ! cs - > data ) return ;
if ( prefix ) printf ( " %s: " , prefix ) ;
printf ( " chain by next: " ) ;
{
unsigned int i = 0 ;
struct node * x = cs - > first ;
2018-12-03 12:40:13 -05:00
while ( x ) {
2013-04-15 17:58:26 -04:00
printf ( " %02d, " , x - cs - > data ) ;
2018-12-03 12:40:13 -05:00
x = x - > next ;
2013-04-15 17:58:26 -04:00
i + + ;
}
printf ( " [count=%u] \n chain by prev: " , i ) ;
2018-12-03 12:40:13 -05:00
x = cs - > last ;
i = 0 ;
while ( x ) {
2013-04-15 17:58:26 -04:00
printf ( " %02d, " , x - cs - > data ) ;
2018-12-03 12:40:13 -05:00
x = x - > prev ;
2013-04-15 17:58:26 -04:00
i + + ;
}
printf ( " [count=%u] \n " , i ) ;
}
}
# else
2018-12-03 12:40:13 -05:00
# define printchain(a, b) (0)
2013-04-15 17:58:26 -04:00
# endif
2010-01-15 03:00:15 +01:00
/* Looks up a node and splays it up to the root of the tree */
2018-12-03 12:40:13 -05:00
static int splay ( int64_t * md5 , size_t len , struct cache_set * cs )
{
2010-03-05 22:17:46 +01:00
struct node next = { { 0 , 0 } , NULL , NULL , NULL , NULL , NULL , 0 , 0 } , * right = & next , * left = & next , * temp , * root = cs - > root ;
2010-01-14 04:38:31 +01:00
int comp , found = 0 ;
2010-01-11 13:10:36 +01:00
2018-12-03 12:40:13 -05:00
if ( ! root )
return 0 ;
2010-01-09 02:19:25 +01:00
2018-12-03 12:40:13 -05:00
while ( 1 ) {
comp = cmp ( md5 , len , root - > digest , root - > size ) ;
if ( comp < 0 ) {
if ( ! root - > left ) break ;
if ( cmp ( md5 , len , root - > left - > digest , root - > left - > size ) < 0 ) {
temp = root - > left ;
2010-01-09 02:19:25 +01:00
root - > left = temp - > right ;
2018-12-03 12:40:13 -05:00
if ( temp - > right ) temp - > right - > up = root ;
2010-01-09 02:19:25 +01:00
temp - > right = root ;
2018-12-03 12:40:13 -05:00
root - > up = temp ;
root = temp ;
if ( ! root - > left ) break ;
}
2010-01-09 02:19:25 +01:00
right - > left = root ;
2018-12-03 12:40:13 -05:00
root - > up = right ;
right = root ;
root = root - > left ;
} else if ( comp > 0 ) {
if ( ! root - > right ) break ;
if ( cmp ( md5 , len , root - > right - > digest , root - > right - > size ) > 0 ) {
temp = root - > right ;
2010-01-09 02:19:25 +01:00
root - > right = temp - > left ;
2018-12-03 12:40:13 -05:00
if ( temp - > left ) temp - > left - > up = root ;
2010-01-09 02:19:25 +01:00
temp - > left = root ;
2018-12-03 12:40:13 -05:00
root - > up = temp ;
root = temp ;
if ( ! root - > right ) break ;
}
left - > right = root ;
root - > up = left ;
left = root ;
root = root - > right ;
} else {
found = 1 ;
break ;
}
2010-01-09 02:19:25 +01:00
}
2010-01-09 16:21:48 +01:00
2010-01-09 02:19:25 +01:00
left - > right = root - > left ;
2018-12-03 12:40:13 -05:00
if ( root - > left ) root - > left - > up = left ;
2010-01-09 02:19:25 +01:00
right - > left = root - > right ;
2018-12-03 12:40:13 -05:00
if ( root - > right ) root - > right - > up = right ;
2010-01-09 02:19:25 +01:00
root - > left = next . right ;
2018-12-03 12:40:13 -05:00
if ( next . right ) next . right - > up = root ;
2010-01-09 02:19:25 +01:00
root - > right = next . left ;
2018-12-03 12:40:13 -05:00
if ( next . left ) next . left - > up = root ;
2010-01-11 18:37:54 +01:00
root - > up = NULL ;
2010-01-09 02:19:25 +01:00
cs - > root = root ;
2010-01-14 04:38:31 +01:00
return found ;
2010-01-09 02:19:25 +01:00
}
2010-01-15 03:00:15 +01:00
/* Looks up an hash in the tree and maintains the replacement chain */
2018-12-03 12:40:13 -05:00
static inline int cacheset_lookup ( struct cache_set * cs , unsigned char * md5 , size_t size , uint32_t reclevel )
{
2010-01-09 16:21:48 +01:00
int64_t hash [ 2 ] ;
2010-01-09 02:19:25 +01:00
memcpy ( hash , md5 , 16 ) ;
2018-12-03 12:40:13 -05:00
if ( splay ( hash , size , cs ) ) {
struct node * o = cs - > root - > prev , * p = cs - > root , * q = cs - > root - > next ;
2010-01-14 04:38:31 +01:00
# ifdef PRINT_CHAINS
2018-12-03 12:40:13 -05:00
printf ( " promoting %02d \n " , p - cs - > data ) ;
printchain ( " before " , cs ) ;
2010-01-14 04:38:31 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( q ) {
if ( o )
o - > next = q ;
else
cs - > first = q ;
q - > prev = o ;
cs - > last - > next = p ;
p - > prev = cs - > last ;
p - > next = NULL ;
cs - > last = p ;
}
2010-01-14 04:38:31 +01:00
# ifdef PRINT_CHAINS
2018-12-03 12:40:13 -05:00
printchain ( " after " , cs ) ;
2010-01-14 04:38:31 +01:00
# endif
2018-12-03 12:40:13 -05:00
if ( reclevel > = p - > minrec )
return 1 ;
2010-01-14 04:38:31 +01:00
}
return 0 ;
2010-01-09 02:19:25 +01:00
}
2010-01-15 03:00:15 +01:00
/* If the hash is present nothing happens.
Otherwise a new node is created for the hash picking one from the begin of the chain .
Used nodes are moved to the end of the chain */
2018-12-03 12:40:13 -05:00
static inline void cacheset_add ( struct cache_set * cs , unsigned char * md5 , size_t size , uint32_t reclevel )
{
2010-01-09 02:19:25 +01:00
struct node * newnode ;
2010-01-09 16:21:48 +01:00
int64_t hash [ 2 ] ;
2010-01-09 02:19:25 +01:00
memcpy ( hash , md5 , 16 ) ;
2018-12-03 12:40:13 -05:00
if ( splay ( hash , size , cs ) ) {
if ( cs - > root - > minrec > reclevel )
cs - > root - > minrec = reclevel ;
return ; /* Already there */
2010-03-05 22:17:46 +01:00
}
2010-01-13 00:03:30 +01:00
2010-01-14 04:38:31 +01:00
ptree ( " 1: \n " ) ;
2018-12-03 12:40:13 -05:00
if ( printtree ( cs , cs - > root , 0 ) ) {
cli_errmsg ( " cacheset_add: inconsistent tree before choosing newnode, good luck \n " ) ;
return ;
2010-01-14 04:38:31 +01:00
}
2010-01-13 00:03:30 +01:00
newnode = cs - > first ;
2018-12-03 12:40:13 -05:00
while ( newnode ) {
if ( ! newnode - > right & & ! newnode - > left )
2013-02-27 11:34:13 -05:00
break ;
2018-12-03 12:40:13 -05:00
if ( newnode - > next ) {
if ( newnode = = newnode - > next ) {
2013-04-15 17:58:26 -04:00
cli_errmsg ( " cacheset_add: cache chain in a bad state \n " ) ;
return ;
}
newnode = newnode - > next ;
2018-12-03 12:40:13 -05:00
} else {
cli_warnmsg ( " cacheset_add: end of chain reached \n " ) ;
return ;
2013-02-27 11:34:13 -05:00
}
2010-01-13 00:03:30 +01:00
}
2018-12-03 12:40:13 -05:00
if ( ! newnode ) {
cli_errmsg ( " cacheset_add: tree has got no end nodes \n " ) ;
return ;
}
if ( newnode - > up ) {
if ( newnode - > up - > left = = newnode )
newnode - > up - > left = NULL ;
else
newnode - > up - > right = NULL ;
}
if ( newnode - > prev )
newnode - > prev - > next = newnode - > next ;
if ( newnode - > next )
newnode - > next - > prev = newnode - > prev ;
if ( cs - > first = = newnode )
cs - > first = newnode - > next ;
newnode - > prev = cs - > last ;
newnode - > next = NULL ;
2010-01-13 00:03:30 +01:00
cs - > last - > next = newnode ;
2018-12-03 12:40:13 -05:00
cs - > last = newnode ;
2010-01-14 04:38:31 +01:00
ptree ( " 2: \n " ) ;
2018-12-03 12:40:13 -05:00
if ( printtree ( cs , cs - > root , 0 ) ) {
cli_errmsg ( " cacheset_add: inconsistent tree before adding newnode, good luck \n " ) ;
return ;
2010-01-14 04:38:31 +01:00
}
2010-01-09 02:19:25 +01:00
2018-12-03 12:40:13 -05:00
if ( ! cs - > root ) {
newnode - > left = NULL ;
newnode - > right = NULL ;
2010-01-09 02:19:25 +01:00
} else {
2018-12-03 12:40:13 -05:00
if ( cmp ( hash , size , cs - > root - > digest , cs - > root - > size ) < 0 ) {
newnode - > left = cs - > root - > left ;
newnode - > right = cs - > root ;
cs - > root - > left = NULL ;
} else {
newnode - > right = cs - > root - > right ;
newnode - > left = cs - > root ;
cs - > root - > right = NULL ;
}
if ( newnode - > left ) newnode - > left - > up = newnode ;
if ( newnode - > right ) newnode - > right - > up = newnode ;
2010-01-09 02:19:25 +01:00
}
newnode - > digest [ 0 ] = hash [ 0 ] ;
newnode - > digest [ 1 ] = hash [ 1 ] ;
2018-12-03 12:40:13 -05:00
newnode - > up = NULL ;
newnode - > size = size ;
newnode - > minrec = reclevel ;
cs - > root = newnode ;
2010-01-14 04:38:31 +01:00
ptree ( " 3: %lld \n " , hash [ 1 ] ) ;
2018-12-03 12:40:13 -05:00
if ( printtree ( cs , cs - > root , 0 ) ) {
cli_errmsg ( " cacheset_add: inconsistent tree after adding newnode, good luck \n " ) ;
return ;
2010-01-14 04:38:31 +01:00
}
2013-04-15 17:58:26 -04:00
printnode ( " newnode " , cs , newnode ) ;
2010-01-09 02:19:25 +01:00
}
2013-04-15 17:58:26 -04:00
2012-11-27 11:24:52 -05:00
/* If the hash is not present nothing happens other than splaying the tree.
2019-05-03 18:16:03 -04:00
Otherwise the identified node is removed from the tree and then placed back at
2012-11-27 11:24:52 -05:00
the front of the chain . */
2018-12-03 12:40:13 -05:00
static inline void cacheset_remove ( struct cache_set * cs , unsigned char * md5 , size_t size )
{
2012-11-27 11:24:52 -05:00
struct node * targetnode ;
struct node * reattachnode ;
int64_t hash [ 2 ] ;
memcpy ( hash , md5 , 16 ) ;
2018-12-03 12:40:13 -05:00
if ( splay ( hash , size , cs ) ! = 1 ) {
cli_dbgmsg ( " cacheset_remove: node not found in tree \n " ) ;
return ; /* No op */
2012-11-27 11:24:52 -05:00
}
ptree ( " cacheset_remove: node found and splayed to root \n " ) ;
targetnode = cs - > root ;
2013-04-15 17:58:26 -04:00
printnode ( " targetnode " , cs , targetnode ) ;
2012-11-27 11:24:52 -05:00
/* First fix the tree */
2018-12-03 12:40:13 -05:00
if ( targetnode - > left = = NULL ) {
2012-11-27 11:24:52 -05:00
/* At left edge so prune */
cs - > root = targetnode - > right ;
2018-12-03 12:40:13 -05:00
if ( cs - > root )
2012-11-27 11:24:52 -05:00
cs - > root - > up = NULL ;
2018-12-03 12:40:13 -05:00
} else {
2012-11-27 11:24:52 -05:00
/* new root will come from leftside tree */
2018-12-03 12:40:13 -05:00
cs - > root = targetnode - > left ;
2012-11-27 11:24:52 -05:00
cs - > root - > up = NULL ;
/* splay tree, expecting not found, bringing rightmost member to root */
splay ( hash , size , cs ) ;
2013-04-15 17:58:26 -04:00
2012-11-27 11:24:52 -05:00
if ( targetnode - > right ) {
/* reattach right tree to clean right-side attach point */
reattachnode = cs - > root ;
2018-12-03 12:40:13 -05:00
while ( reattachnode - > right )
2012-11-27 11:24:52 -05:00
reattachnode = reattachnode - > right ; /* shouldn't happen, but safer in case of dupe */
2018-12-03 12:40:13 -05:00
reattachnode - > right = targetnode - > right ;
2013-04-15 17:58:26 -04:00
targetnode - > right - > up = reattachnode ;
2012-11-27 11:24:52 -05:00
}
}
2018-12-03 12:40:13 -05:00
targetnode - > size = ( size_t ) 0 ;
2013-04-15 17:58:26 -04:00
targetnode - > digest [ 0 ] = 0 ;
targetnode - > digest [ 1 ] = 0 ;
2018-12-03 12:40:13 -05:00
targetnode - > up = NULL ;
targetnode - > left = NULL ;
targetnode - > right = NULL ;
2012-11-27 11:24:52 -05:00
/* Tree is fixed, so now fix chain around targetnode */
2018-12-03 12:40:13 -05:00
if ( targetnode - > prev )
2012-11-27 11:24:52 -05:00
targetnode - > prev - > next = targetnode - > next ;
2018-12-03 12:40:13 -05:00
if ( targetnode - > next )
2012-11-27 11:24:52 -05:00
targetnode - > next - > prev = targetnode - > prev ;
2018-12-03 12:40:13 -05:00
if ( cs - > last = = targetnode )
2012-11-27 11:24:52 -05:00
cs - > last = targetnode - > prev ;
2013-02-27 11:34:13 -05:00
/* Put targetnode at front of chain, if not there already */
2018-12-03 12:40:13 -05:00
if ( cs - > first ! = targetnode ) {
2013-02-27 11:34:13 -05:00
targetnode - > next = cs - > first ;
2018-12-03 12:40:13 -05:00
if ( cs - > first )
2013-02-27 11:34:13 -05:00
cs - > first - > prev = targetnode ;
cs - > first = targetnode ;
2012-11-27 11:24:52 -05:00
}
targetnode - > prev = NULL ;
2013-04-15 17:58:26 -04:00
printnode ( " root " , cs , cs - > root ) ;
printnode ( " first " , cs , cs - > first ) ;
printnode ( " last " , cs , cs - > last ) ;
printchain ( " remove (after) " , cs ) ;
2012-11-27 11:24:52 -05:00
}
2010-01-09 02:19:25 +01:00
# endif /* USE_SPLAY */
2010-01-08 01:39:25 +01:00
2010-01-15 03:00:15 +01:00
/* COMMON STUFF --------------------------------------------------------------------- */
2010-01-08 01:39:25 +01:00
2010-01-14 18:54:53 +01:00
struct CACHE {
2010-01-09 02:19:25 +01:00
struct cache_set cacheset ;
2010-05-07 10:07:48 +03:00
# ifdef CL_THREAD_SAFE
2010-01-09 02:19:25 +01:00
pthread_mutex_t mutex ;
2010-05-07 10:07:48 +03:00
# endif
2010-01-14 18:54:53 +01:00
} ;
2010-01-13 00:03:30 +01:00
2010-01-15 03:00:15 +01:00
/* Allocates the trees for the engine cache */
2018-12-03 12:40:13 -05:00
int cli_cache_init ( struct cl_engine * engine )
{
2010-11-04 21:14:14 +02:00
struct CACHE * cache ;
2010-01-14 18:54:53 +01:00
unsigned int i , j ;
2010-01-11 13:10:36 +01:00
2018-12-03 12:40:13 -05:00
if ( ! engine ) {
cli_errmsg ( " cli_cache_init: mpool malloc fail \n " ) ;
return 1 ;
2010-01-08 01:39:25 +01:00
}
2010-01-14 18:54:53 +01:00
2013-12-11 14:58:07 -05:00
if ( engine - > engine_options & ENGINE_OPTIONS_DISABLE_CACHE ) {
cli_dbgmsg ( " cli_cache_init: Caching disabled. \n " ) ;
return 0 ;
}
2019-05-03 18:16:03 -04:00
if ( ! ( cache = MPOOL_MALLOC ( engine - > mempool , sizeof ( struct CACHE ) * TREES ) ) ) {
2018-12-03 12:40:13 -05:00
cli_errmsg ( " cli_cache_init: mpool malloc fail \n " ) ;
return 1 ;
2010-01-08 01:39:25 +01:00
}
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < TREES ; i + + ) {
if ( pthread_mutex_init ( & cache [ i ] . mutex , NULL ) ) {
cli_errmsg ( " cli_cache_init: mutex init fail \n " ) ;
for ( j = 0 ; j < i ; j + + ) cacheset_destroy ( & cache [ j ] . cacheset , engine - > mempool ) ;
for ( j = 0 ; j < i ; j + + ) pthread_mutex_destroy ( & cache [ j ] . mutex ) ;
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( engine - > mempool , cache ) ;
2018-12-03 12:40:13 -05:00
return 1 ;
}
if ( cacheset_init ( & cache [ i ] . cacheset , engine - > mempool ) ) {
for ( j = 0 ; j < i ; j + + ) cacheset_destroy ( & cache [ j ] . cacheset , engine - > mempool ) ;
for ( j = 0 ; j < = i ; j + + ) pthread_mutex_destroy ( & cache [ j ] . mutex ) ;
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( engine - > mempool , cache ) ;
2018-12-03 12:40:13 -05:00
return 1 ;
}
2010-01-08 01:39:25 +01:00
}
2010-01-14 18:54:53 +01:00
engine - > cache = cache ;
2010-01-08 01:39:25 +01:00
return 0 ;
}
2010-01-15 03:00:15 +01:00
/* Frees the engine cache */
2018-12-03 12:40:13 -05:00
void cli_cache_destroy ( struct cl_engine * engine )
{
2010-11-04 21:14:14 +02:00
struct CACHE * cache ;
2010-01-14 18:54:53 +01:00
unsigned int i ;
2010-01-09 02:19:25 +01:00
2018-12-03 12:40:13 -05:00
if ( ! engine | | ! ( cache = engine - > cache ) )
return ;
2013-12-11 14:58:07 -05:00
2013-11-15 19:15:20 +00:00
if ( engine - > engine_options & ENGINE_OPTIONS_DISABLE_CACHE ) {
return ;
}
2018-12-03 12:40:13 -05:00
for ( i = 0 ; i < TREES ; i + + ) {
cacheset_destroy ( & cache [ i ] . cacheset , engine - > mempool ) ;
pthread_mutex_destroy ( & cache [ i ] . mutex ) ;
2010-01-14 18:54:53 +01:00
}
2019-05-03 18:16:03 -04:00
MPOOL_FREE ( engine - > mempool , cache ) ;
2010-01-14 18:54:53 +01:00
}
2010-01-15 03:00:15 +01:00
/* Looks up an hash in the proper tree */
2018-12-03 12:40:13 -05:00
static int cache_lookup_hash ( unsigned char * md5 , size_t len , struct CACHE * cache , uint32_t reclevel )
{
2010-01-08 01:39:25 +01:00
unsigned int key = getkey ( md5 ) ;
2018-12-03 12:40:13 -05:00
int ret = CL_VIRUS ;
2010-01-08 01:39:25 +01:00
struct CACHE * c ;
c = & cache [ key ] ;
2018-12-03 12:40:13 -05:00
if ( pthread_mutex_lock ( & c - > mutex ) ) {
cli_errmsg ( " cache_lookup_hash: cache_lookup_hash: mutex lock fail \n " ) ;
return ret ;
2010-01-08 01:39:25 +01:00
}
2010-01-09 02:19:25 +01:00
2013-04-15 17:58:26 -04:00
/* cli_warnmsg("cache_lookup_hash: key is %u\n", key); */
2010-03-05 22:17:46 +01:00
ret = ( cacheset_lookup ( & c - > cacheset , md5 , len , reclevel ) ) ? CL_CLEAN : CL_VIRUS ;
2010-01-09 02:19:25 +01:00
pthread_mutex_unlock ( & c - > mutex ) ;
2010-01-15 03:00:15 +01:00
/* if(ret == CL_CLEAN) cli_warnmsg("cached\n"); */
2010-01-08 01:39:25 +01:00
return ret ;
}
2010-01-15 03:00:15 +01:00
/* Adds an hash to the cache */
2018-12-03 12:40:13 -05:00
void cache_add ( unsigned char * md5 , size_t size , cli_ctx * ctx )
{
2010-01-08 01:39:25 +01:00
unsigned int key = getkey ( md5 ) ;
2010-03-05 22:17:46 +01:00
uint32_t level ;
2010-01-08 01:39:25 +01:00
struct CACHE * c ;
2018-12-03 12:40:13 -05:00
if ( ! ctx | | ! ctx - > engine | | ! ctx - > engine - > cache )
return ;
2013-12-11 14:58:07 -05:00
2013-11-15 19:15:20 +00:00
if ( ctx - > engine - > engine_options & ENGINE_OPTIONS_DISABLE_CACHE ) {
cli_dbgmsg ( " cache_add: Caching disabled. Not adding sample to cache. \n " ) ;
return ;
}
2018-12-03 12:40:13 -05:00
level = ( * ctx - > fmap & & ( * ctx - > fmap ) - > dont_cache_flag ) ? ctx - > recursion : 0 ;
2010-03-10 14:49:22 +02:00
if ( ctx - > found_possibly_unwanted & & ( level | | ! ctx - > recursion ) )
2018-12-03 12:40:13 -05:00
return ;
2018-07-20 22:28:48 -04:00
if ( SCAN_ALLMATCHES & & ( ctx - > num_viruses > 0 ) ) {
2018-12-03 12:40:13 -05:00
cli_dbgmsg ( " cache_add: alert found within same topfile, skipping cache \n " ) ;
return ;
2013-06-18 12:30:21 -04:00
}
2010-01-14 18:54:53 +01:00
c = & ctx - > engine - > cache [ key ] ;
2018-12-03 12:40:13 -05:00
if ( pthread_mutex_lock ( & c - > mutex ) ) {
cli_errmsg ( " cli_add: mutex lock fail \n " ) ;
return ;
2010-01-08 01:39:25 +01:00
}
2010-01-09 02:19:25 +01:00
2013-04-15 17:58:26 -04:00
/* cli_warnmsg("cache_add: key is %u\n", key); */
2010-01-14 18:54:53 +01:00
# ifdef USE_LRUHASHCACHE
2010-01-15 03:00:15 +01:00
cacheset_add ( & c - > cacheset , md5 , size , ctx - > engine - > mempool ) ;
2010-01-14 18:54:53 +01:00
# else
# ifdef USE_SPLAY
2010-03-05 22:17:46 +01:00
cacheset_add ( & c - > cacheset , md5 , size , level ) ;
2010-01-14 18:54:53 +01:00
# else
# error #define USE_SPLAY or USE_LRUHASHCACHE
# endif
# endif
2010-01-09 02:19:25 +01:00
2010-01-08 01:39:25 +01:00
pthread_mutex_unlock ( & c - > mutex ) ;
2010-03-05 22:17:46 +01:00
cli_dbgmsg ( " cache_add: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x (level %u) \n " , md5 [ 0 ] , md5 [ 1 ] , md5 [ 2 ] , md5 [ 3 ] , md5 [ 4 ] , md5 [ 5 ] , md5 [ 6 ] , md5 [ 7 ] , md5 [ 8 ] , md5 [ 9 ] , md5 [ 10 ] , md5 [ 11 ] , md5 [ 12 ] , md5 [ 13 ] , md5 [ 14 ] , md5 [ 15 ] , level ) ;
2010-01-08 01:39:25 +01:00
return ;
}
2012-11-27 11:24:52 -05:00
/* Removes a hash from the cache */
2018-12-03 12:40:13 -05:00
void cache_remove ( unsigned char * md5 , size_t size , const struct cl_engine * engine )
{
2012-11-27 11:24:52 -05:00
unsigned int key = getkey ( md5 ) ;
struct CACHE * c ;
2018-12-03 12:40:13 -05:00
if ( ! engine | | ! engine - > cache )
return ;
2013-12-11 14:58:07 -05:00
2013-11-15 19:15:20 +00:00
if ( engine - > engine_options & ENGINE_OPTIONS_DISABLE_CACHE ) {
cli_dbgmsg ( " cache_remove: Caching disabled. \n " ) ;
return ;
}
2013-04-15 17:58:26 -04:00
/* cli_warnmsg("cache_remove: key is %u\n", key); */
2012-11-27 16:17:31 -05:00
c = & engine - > cache [ key ] ;
2018-12-03 12:40:13 -05:00
if ( pthread_mutex_lock ( & c - > mutex ) ) {
cli_errmsg ( " cli_add: mutex lock fail \n " ) ;
return ;
2012-11-27 11:24:52 -05:00
}
# ifdef USE_LRUHASHCACHE
2012-11-27 16:17:31 -05:00
cacheset_remove ( & c - > cacheset , md5 , size , engine - > mempool ) ;
2012-11-27 11:24:52 -05:00
# else
# ifdef USE_SPLAY
cacheset_remove ( & c - > cacheset , md5 , size ) ;
# else
# error #define USE_SPLAY or USE_LRUHASHCACHE
# endif
# endif
pthread_mutex_unlock ( & c - > mutex ) ;
cli_dbgmsg ( " cache_remove: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x \n " , md5 [ 0 ] , md5 [ 1 ] , md5 [ 2 ] , md5 [ 3 ] , md5 [ 4 ] , md5 [ 5 ] , md5 [ 6 ] , md5 [ 7 ] , md5 [ 8 ] , md5 [ 9 ] , md5 [ 10 ] , md5 [ 11 ] , md5 [ 12 ] , md5 [ 13 ] , md5 [ 14 ] , md5 [ 15 ] ) ;
return ;
}
2015-11-04 14:46:46 -05:00
int cache_get_MD5 ( unsigned char * hash , cli_ctx * ctx )
{
2010-01-15 18:17:55 +02:00
fmap_t * map ;
size_t todo , at = 0 ;
2014-02-28 12:12:30 -05:00
void * hashctx ;
2013-11-15 19:15:20 +00:00
2018-12-03 12:40:13 -05:00
map = * ctx - > fmap ;
2010-01-15 18:17:55 +02:00
todo = map - > len ;
2014-02-28 12:12:30 -05:00
hashctx = cl_hash_init ( " md5 " ) ;
2014-02-13 13:05:50 -05:00
if ( ! ( hashctx ) )
return CL_VIRUS ;
2018-12-03 12:40:13 -05:00
while ( todo ) {
2014-02-08 00:31:12 -05:00
const void * buf ;
size_t readme = todo < FILEBUFF ? todo : FILEBUFF ;
2018-12-03 12:40:13 -05:00
if ( ! ( buf = fmap_need_off_once ( map , at , readme ) ) ) {
2014-02-28 12:12:30 -05:00
cl_hash_destroy ( hashctx ) ;
2014-02-08 00:31:12 -05:00
return CL_EREAD ;
2014-02-28 12:12:30 -05:00
}
2014-02-08 00:31:12 -05:00
todo - = readme ;
at + = readme ;
2014-07-10 18:11:49 -04:00
if ( cl_update_hash ( hashctx , ( void * ) buf , readme ) ) {
2014-02-28 12:12:30 -05:00
cl_hash_destroy ( hashctx ) ;
2014-02-08 00:31:12 -05:00
cli_errmsg ( " cache_check: error reading while generating hash! \n " ) ;
return CL_EREAD ;
}
2010-01-08 01:39:25 +01:00
}
2014-02-08 00:31:12 -05:00
2014-02-28 12:12:30 -05:00
cl_finish_hash ( hashctx , hash ) ;
2014-02-08 00:31:12 -05:00
2015-11-04 14:46:46 -05:00
return CL_CLEAN ;
}
/* Hashes a file onto the provided buffer and looks it up the cache.
Returns CL_VIRUS if found , CL_CLEAN if not FIXME or a recoverable error ,
and returns CL_EREAD if unrecoverable */
2018-12-03 12:40:13 -05:00
int cache_check ( unsigned char * hash , cli_ctx * ctx )
{
2015-11-04 14:46:46 -05:00
fmap_t * map ;
int ret ;
2018-12-03 12:40:13 -05:00
if ( ! ctx | | ! ctx - > engine | | ! ctx - > engine - > cache )
return CL_VIRUS ;
2015-11-04 14:46:46 -05:00
if ( ctx - > engine - > engine_options & ENGINE_OPTIONS_DISABLE_CACHE ) {
cli_dbgmsg ( " cache_check: Caching disabled. Returning CL_VIRUS. \n " ) ;
return CL_VIRUS ;
}
ret = cache_get_MD5 ( hash , ctx ) ;
if ( ret ! = CL_CLEAN )
return ret ;
2018-12-03 12:40:13 -05:00
2015-11-04 14:46:46 -05:00
map = * ctx - > fmap ;
2010-03-05 22:17:46 +01:00
ret = cache_lookup_hash ( hash , map - > len , ctx - > engine - > cache , ctx - > recursion ) ;
2010-03-05 17:11:45 +01:00
cli_dbgmsg ( " cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s \n " , hash [ 0 ] , hash [ 1 ] , hash [ 2 ] , hash [ 3 ] , hash [ 4 ] , hash [ 5 ] , hash [ 6 ] , hash [ 7 ] , hash [ 8 ] , hash [ 9 ] , hash [ 10 ] , hash [ 11 ] , hash [ 12 ] , hash [ 13 ] , hash [ 14 ] , hash [ 15 ] , ( ret = = CL_VIRUS ) ? " negative " : " positive " ) ;
return ret ;
2010-01-08 01:39:25 +01:00
}