... | ... |
@@ -37,11 +37,15 @@ |
37 | 37 |
HANDLE reload_event; |
38 | 38 |
volatile LONG reload_waiters = 0; |
39 | 39 |
|
40 |
+HANDLE monitor_event; |
|
41 |
+HANDLE monitor_hdl = NULL; |
|
42 |
+ |
|
40 | 43 |
HANDLE engine_mutex; |
41 | 44 |
/* protects the following items */ |
42 | 45 |
struct cl_engine *engine = NULL; |
43 | 46 |
char dbdir[PATH_MAX]; |
44 | 47 |
char tmpdir[PATH_MAX]; |
48 |
+FILETIME last_chk_time = {0, 0}; |
|
45 | 49 |
/* end of protected items */ |
46 | 50 |
|
47 | 51 |
typedef struct { |
... | ... |
@@ -69,6 +73,68 @@ BOOL minimal_definitions = FALSE; |
69 | 69 |
cl_error_t prescan_cb(int fd, void *context); |
70 | 70 |
cl_error_t postscan_cb(int fd, int result, const char *virname, void *context); |
71 | 71 |
|
72 |
+ |
|
73 |
+DWORD WINAPI monitor_thread(VOID *p) { |
|
74 |
+ char watchme[PATH_MAX]; |
|
75 |
+ HANDLE harr[2], fff; |
|
76 |
+ |
|
77 |
+ if(lock_engine()) { |
|
78 |
+ logg("monitor_thread: failed to lock engine\n"); |
|
79 |
+ return 0; |
|
80 |
+ } |
|
81 |
+ |
|
82 |
+ snprintf(watchme, sizeof(watchme), "%s\\forcerld", dbdir); |
|
83 |
+ watchme[sizeof(watchme)-1] = '\0'; |
|
84 |
+ |
|
85 |
+ harr[0] = monitor_event; |
|
86 |
+ harr[1] = FindFirstChangeNotification(dbdir, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE); |
|
87 |
+ |
|
88 |
+ logg("monitor_thread: watching directory changes on %s\n", dbdir); |
|
89 |
+ |
|
90 |
+ unlock_engine(); |
|
91 |
+ |
|
92 |
+ if(harr[1] == INVALID_HANDLE_VALUE) { |
|
93 |
+ logg("monitor_thread: failed to monitor directory changes on %s\n", dbdir); |
|
94 |
+ return 0; |
|
95 |
+ } |
|
96 |
+ |
|
97 |
+ while(1) { |
|
98 |
+ WIN32_FIND_DATA wfd; |
|
99 |
+ SYSTEMTIME st; |
|
100 |
+ |
|
101 |
+ switch(WaitForMultipleObjects(2, harr, FALSE, INFINITE)) { |
|
102 |
+ case WAIT_OBJECT_0: |
|
103 |
+ logg("monitor_thread: terminating upon request\n"); |
|
104 |
+ FindCloseChangeNotification(fff); |
|
105 |
+ return 0; |
|
106 |
+ case WAIT_OBJECT_0 + 1: |
|
107 |
+ break; |
|
108 |
+ default: |
|
109 |
+ logg("monitor_thread: unexpected wait failure - %u\n", GetLastError()); |
|
110 |
+ Sleep(1000); |
|
111 |
+ continue; |
|
112 |
+ } |
|
113 |
+ FindNextChangeNotification(fff); |
|
114 |
+ if((fff = FindFirstFile(watchme, &wfd)) == INVALID_HANDLE_VALUE) { |
|
115 |
+ logg("monitor_thread: failed to find %s - %u\n", watchme, GetLastError()); |
|
116 |
+ continue; |
|
117 |
+ } |
|
118 |
+ FindClose(fff); |
|
119 |
+ |
|
120 |
+ GetSystemTime(&st); |
|
121 |
+ SystemTimeToFileTime(&st, &wfd.ftCreationTime); |
|
122 |
+ if(CompareFileTime(&wfd.ftLastWriteTime, &wfd.ftCreationTime) > 0) |
|
123 |
+ wfd.ftLastWriteTime = wfd.ftCreationTime; |
|
124 |
+ if(CompareFileTime(&wfd.ftLastWriteTime, &last_chk_time) <= 0) |
|
125 |
+ continue; |
|
126 |
+ |
|
127 |
+ logg("monitor_thread: reload requested!\n"); |
|
128 |
+ Scan_ReloadDatabase(); |
|
129 |
+ GetSystemTime(&st); |
|
130 |
+ SystemTimeToFileTime(&st, &last_chk_time); /* FIXME: small race here */ |
|
131 |
+ } |
|
132 |
+} |
|
133 |
+ |
|
72 | 134 |
static wchar_t *threat_type(const char *virname) { |
73 | 135 |
if(!virname) |
74 | 136 |
return NULL; |
... | ... |
@@ -169,7 +235,14 @@ BOOL interface_setup(void) { |
169 | 169 |
CloseHandle(engine_mutex); |
170 | 170 |
return FALSE; |
171 | 171 |
} |
172 |
+ if(!(monitor_event = CreateEvent(NULL, TRUE, FALSE, NULL))) { |
|
173 |
+ CloseHandle(reload_event); |
|
174 |
+ CloseHandle(engine_mutex); |
|
175 |
+ return FALSE; |
|
176 |
+ } |
|
172 | 177 |
if(!(instance_mutex = CreateMutex(NULL, FALSE, NULL))) { |
178 |
+ CloseHandle(monitor_event); |
|
179 |
+ CloseHandle(reload_event); |
|
173 | 180 |
CloseHandle(engine_mutex); |
174 | 181 |
return FALSE; |
175 | 182 |
} |
... | ... |
@@ -182,11 +255,35 @@ static int sigload_callback(const char *type, const char *name, void *context) { |
182 | 182 |
return 0; |
183 | 183 |
} |
184 | 184 |
|
185 |
+ |
|
186 |
+/* Must be called with engine_mutex locked ! */ |
|
187 |
+static void touch_last_update(void) { |
|
188 |
+ char touchme[PATH_MAX]; |
|
189 |
+ HANDLE h; |
|
190 |
+ |
|
191 |
+ snprintf(touchme, sizeof(touchme), "%s\\lastupd", dbdir); |
|
192 |
+ touchme[sizeof(touchme)-1] = '\0'; |
|
193 |
+ if((h = CreateFile(touchme, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) { |
|
194 |
+ DWORD d; |
|
195 |
+ snprintf(touchme, sizeof(touchme), "w00t!"); |
|
196 |
+ touchme[sizeof(touchme)-1] = '\0'; |
|
197 |
+ if(WriteFile(h, touchme, strlen(touchme), &d, NULL)) { |
|
198 |
+ /* SetEndOfFile(h); */ |
|
199 |
+ GetFileTime(h, NULL, NULL, &last_chk_time); |
|
200 |
+ } |
|
201 |
+ CloseHandle(h); |
|
202 |
+ } else |
|
203 |
+ logg("touch_lastcheck: failed to touch lastreload\n"); |
|
204 |
+} |
|
205 |
+ |
|
206 |
+ |
|
185 | 207 |
/* Must be called with engine_mutex locked ! */ |
186 | 208 |
static int load_db(void) { |
187 |
- int ret; |
|
188 |
- size_t used, total; |
|
189 | 209 |
unsigned int signo = 0; |
210 |
+ size_t used, total; |
|
211 |
+ int ret; |
|
212 |
+ |
|
213 |
+ |
|
190 | 214 |
INFN(); |
191 | 215 |
|
192 | 216 |
cl_engine_set_clcb_sigload(engine, sigload_callback, NULL); |
... | ... |
@@ -203,10 +300,11 @@ static int load_db(void) { |
203 | 203 |
} |
204 | 204 |
|
205 | 205 |
logg("load_db: loaded %d signatures\n", signo); |
206 |
- if (!mpool_getstats(engine, &used, &total)) { |
|
207 |
- logg("load_db: memory %.3f MB / %.3f MB\n", |
|
208 |
- used/(1024*1024.0), total/(1024*1024.0)); |
|
209 |
- } |
|
206 |
+ if (!mpool_getstats(engine, &used, &total)) |
|
207 |
+ logg("load_db: memory %.3f MB / %.3f MB\n", used/(1024*1024.0), total/(1024*1024.0)); |
|
208 |
+ |
|
209 |
+ touch_last_update(); |
|
210 |
+ |
|
210 | 211 |
WIN(); |
211 | 212 |
} |
212 | 213 |
|
... | ... |
@@ -257,6 +355,11 @@ int CLAMAPI Scan_Initialize(const wchar_t *pEnginesFolder, const wchar_t *pTempR |
257 | 257 |
} |
258 | 258 |
ret = load_db(); |
259 | 259 |
unlock_engine(); |
260 |
+ |
|
261 |
+ ResetEvent(monitor_event); |
|
262 |
+ if(!(monitor_hdl = CreateThread(NULL, 0, monitor_thread, NULL, 0, NULL))) |
|
263 |
+ logg("!Falied to start db monitoring thread\n"); |
|
264 |
+ |
|
260 | 265 |
logg("Scan_Initialize: returning %d\n", ret); |
261 | 266 |
return ret; |
262 | 267 |
} |
... | ... |
@@ -287,6 +390,15 @@ int CLAMAPI Scan_Uninitialize(void) { |
287 | 287 |
} |
288 | 288 |
unlock_instances(); |
289 | 289 |
free_engine_and_unlock(); |
290 |
+ |
|
291 |
+ if(monitor_hdl) { |
|
292 |
+ SetEvent(monitor_event); |
|
293 |
+ if(WaitForSingleObject(monitor_hdl, 60000) != WAIT_OBJECT_0) { |
|
294 |
+ logg("Scan_Uninitialize: forcibly terminating monitor thread after 60 seconds\n"); |
|
295 |
+ TerminateThread(monitor_hdl, 0); |
|
296 |
+ } |
|
297 |
+ } |
|
298 |
+ monitor_hdl = NULL; |
|
290 | 299 |
WIN(); |
291 | 300 |
} |
292 | 301 |
|
... | ... |
@@ -825,10 +937,6 @@ CLAMAPI void Scan_ReloadDatabase(void) { |
825 | 825 |
continue; |
826 | 826 |
} |
827 | 827 |
logg("Scan_ReloadDatabase: Now idle, acquiring engine lock\n"); |
828 |
- if(lock_engine()) { |
|
829 |
- logg("!Scan_ReloadDatabase: failed to lock engine\n"); |
|
830 |
- break; |
|
831 |
- } |
|
832 | 828 |
if(lock_engine()) { |
833 | 829 |
logg("!Scan_ReloadDatabase: failed to lock engine\n"); |
834 | 830 |
break; |
... | ... |
@@ -861,7 +969,6 @@ CLAMAPI void Scan_ReloadDatabase(void) { |
861 | 861 |
|
862 | 862 |
// NEW STUFF // |
863 | 863 |
if(!(engine = cl_engine_new())) { |
864 |
- unlock_engine(); |
|
865 | 864 |
logg("!Scan_ReloadDatabase: Not enough memory for a new engine\n"); |
866 | 865 |
unlock_instances(); |
867 | 866 |
unlock_engine(); |