source: trunk/src/sh_fInotify.c@ 499

Last change on this file since 499 was 496, checked in by katerina, 9 years ago

Fix for ticket #393 (wrong policy assigned).

File size: 18.7 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2011 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20/***************************************************************************
21 *
22 * This file provides a module for samhain to use inotify for file checking.
23 *
24 */
25
26#include "config_xor.h"
27
28#if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE))
29
30#include "samhain.h"
31#include "sh_utils.h"
32#include "sh_modules.h"
33#include "sh_pthread.h"
34#include "sh_inotify.h"
35#include "sh_unix.h"
36#include "sh_hash.h"
37#include "sh_dbIO.h"
38#include "sh_files.h"
39#include "sh_ignore.h"
40
41#define FIL__ _("sh_fInotify.c")
42
43sh_watches sh_file_watches = SH_INOTIFY_INITIALIZER;
44
45#if defined(HAVE_SYS_INOTIFY_H)
46
47static sh_watches sh_file_missing = SH_INOTIFY_INITIALIZER;
48
49#include <sys/inotify.h>
50
51/* --- Configuration ------- */
52
53static int ShfInotifyActive = S_FALSE;
54static int ShfInotifyClose = S_FALSE; /* for reconf, mark instance for closing */
55
56static unsigned long ShfInotifyWatches = 0;
57
58static int sh_fInotify_active(const char *s)
59{
60 int value;
61
62 SL_ENTER(_("sh_fInotify_active"));
63 value = sh_util_flagval(s, &ShfInotifyActive);
64 if (value == 0 && ShfInotifyActive != S_FALSE)
65 {
66 sh.flag.inotify |= SH_INOTIFY_USE;
67 sh.flag.inotify |= SH_INOTIFY_DOSCAN;
68 sh.flag.inotify |= SH_INOTIFY_NEEDINIT;
69 }
70 if (value == 0 && ShfInotifyActive == S_FALSE)
71 {
72 sh.flag.inotify = 0;
73 }
74 SL_RETURN((value), _("sh_fInotify_active"));
75}
76
77static int sh_fInotify_watches(const char *s)
78{
79 int retval = -1;
80 char * foo;
81 unsigned long value;
82
83 SL_ENTER(_("sh_fInotify_watches"));
84
85 value = strtoul(s, &foo, 0);
86 if (*foo == '\0')
87 {
88 ShfInotifyWatches = (value > 2147483647) ? 2147483647 /* MAX_INT_32 */: value;
89 retval = 0;
90 }
91 SL_RETURN((retval), _("sh_fInotify_watches"));
92}
93
94
95sh_rconf sh_fInotify_table[] = {
96 {
97 N_("inotifyactive"),
98 sh_fInotify_active,
99 },
100 {
101 N_("inotifywatches"),
102 sh_fInotify_watches,
103 },
104 {
105 NULL,
106 NULL
107 }
108};
109
110/* --- End Configuration --- */
111
112static int sh_fInotify_init_internal(void);
113static int sh_fInotify_process(struct inotify_event * event);
114static int sh_fInotify_report(struct inotify_event * event, char * filename,
115 int class, unsigned long check_flags, int ftype, int rdepth);
116
117int sh_fInotify_init(struct mod_type * arg)
118{
119#ifndef HAVE_PTHREAD
120 (void) arg;
121 return SH_MOD_FAILED;
122#else
123
124 if (ShfInotifyActive == S_FALSE)
125 return SH_MOD_FAILED;
126
127 if (sh.flag.checkSum == SH_CHECK_INIT)
128 return SH_MOD_FAILED;
129
130 if (arg != NULL && arg->initval < 0 &&
131 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
132 {
133 /* Init from main thread */
134 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
135 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
136
137 if (0 == sh_pthread_create(sh_threaded_module_run, (void *)arg))
138 {
139 return SH_MOD_THREAD;
140 }
141 else
142 {
143 sh.flag.inotify = 0;
144 return SH_MOD_FAILED;
145 }
146 }
147 else if (arg != NULL && arg->initval < 0 &&
148 (sh.flag.isdaemon != S_TRUE && sh.flag.loop != S_TRUE))
149 {
150 sh.flag.inotify = 0;
151 return SH_MOD_FAILED;
152 }
153 else if (arg != NULL && arg->initval == SH_MOD_THREAD &&
154 (sh.flag.isdaemon == S_TRUE || sh.flag.loop == S_TRUE))
155 {
156 /* Reconfigure from main thread */
157
158 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
159 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
160 return SH_MOD_THREAD;
161 }
162
163 /* Within thread, init */
164 return sh_fInotify_init_internal();
165#endif
166}
167
168int sh_fInotify_run()
169{
170 ssize_t len = -1;
171 char * buffer;
172 static int count = 0;
173 static int count2 = 0;
174
175 if (ShfInotifyActive == S_FALSE)
176 {
177 return SH_MOD_FAILED;
178 }
179
180 if (ShfInotifyClose == S_TRUE)
181 {
182 ShfInotifyClose = S_FALSE;
183 sh_inotify_close();
184 }
185
186 if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
187 (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
188 {
189 if (0 != sh_fInotify_init_internal())
190 {
191 return SH_MOD_FAILED;
192 }
193 }
194
195 buffer = SH_ALLOC(16384);
196
197 /* Blocking read from inotify file descriptor.
198 */
199 len = sh_inotify_read_timeout(buffer, 16384, 1);
200
201 if (len > 0)
202 {
203 struct inotify_event *event;
204 int i = 0;
205
206 while (i < len)
207 {
208 event = (struct inotify_event *) &(buffer[i]);
209
210 sh_fInotify_process(event);
211
212 i += sizeof (struct inotify_event) + event->len;
213 }
214
215 if ( (sh.flag.inotify & SH_INOTIFY_DOSCAN) ||
216 (sh.flag.inotify & SH_INOTIFY_NEEDINIT))
217 {
218 if (0 != sh_fInotify_init_internal())
219 {
220 SH_FREE(buffer);
221 return SH_MOD_FAILED;
222 }
223 }
224 }
225
226 /* Re-scan 'dormant' list of sh_file_missing.
227 */
228 sh_inotify_recheck_watches (&sh_file_watches, &sh_file_missing);
229
230 ++count;
231 ++count2;
232
233 if (count >= 10)
234 {
235 count = 0; /* Re-expand glob patterns to discover added files. */
236 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
237 sh_files_check_globFilePatterns();
238 SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN; );
239 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
240 }
241
242 if (count2 >= 300)
243 {
244 count2 = 0; /* Update baseline database. */
245 if (sh.flag.checkSum == SH_CHECK_CHECK && sh.flag.update == S_TRUE)
246 sh_dbIO_writeout_update ();
247 }
248
249 SH_FREE(buffer);
250 return 0;
251}
252
253/* We block in the read() call on the inotify descriptor,
254 * so we always run.
255 */
256int sh_fInotify_timer(time_t tcurrent)
257{
258 (void) tcurrent;
259 return 1;
260}
261
262int sh_fInotify_cleanup()
263{
264 sh_inotify_purge_dormant(&sh_file_watches);
265 sh_inotify_remove(&sh_file_watches);
266 sh_inotify_init(&sh_file_watches);
267 return 0;
268}
269
270/* This runs in the main thread, so it won't close
271 * the (threadspecific) inotify instance.
272 */
273int sh_fInotify_reconf()
274{
275 sh.flag.inotify = 0;
276
277 ShfInotifyWatches = 0;
278 ShfInotifyActive = 0;
279
280 ShfInotifyClose = S_TRUE;
281
282 return sh_fInotify_cleanup();
283}
284
285#define PROC_WATCHES_MAX _("/proc/sys/fs/inotify/max_user_watches")
286
287static void sh_fInotify_set_nwatches()
288{
289 static int fails = 0;
290
291 if (ShfInotifyWatches == 0 || fails == 1)
292 return;
293
294 if (0 == access(PROC_WATCHES_MAX, R_OK|W_OK)) /* flawfinder: ignore */
295 {
296 FILE * fd;
297
298 if (NULL != (fd = fopen(PROC_WATCHES_MAX, "r+")))
299 {
300 char str[128];
301 char * ret;
302 char * ptr;
303 unsigned long wn;
304
305 str[0] = '\0';
306 ret = fgets(str, 128, fd);
307 if (ret && *str != '\0')
308 {
309 wn = strtoul(str, &ptr, 0);
310 if (*ptr == '\0' || *ptr == '\n')
311 {
312 if (wn < ShfInotifyWatches)
313 {
314 sl_snprintf(str, sizeof(str), "%lu\n", ShfInotifyWatches);
315 (void) fseek(fd, 0L, SEEK_SET);
316 fputs(str, fd);
317 }
318 sl_fclose(FIL__, __LINE__, fd);
319 return;
320 }
321 }
322 sl_fclose(FIL__, __LINE__, fd);
323 }
324 }
325 SH_MUTEX_LOCK(mutex_thread_nolog);
326 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
327 _("Cannot set max_user_watches"),
328 _("sh_fInotify_set_nwatches"));
329 SH_MUTEX_UNLOCK(mutex_thread_nolog);
330 fails = 1;
331 return;
332}
333
334/* The watch fd is thread specific. To have it in the fInotify thread,
335 * the main thread writes a list of files/dirs to watch, and here we
336 * now pop files from the list to add watches for them.
337 */
338static int sh_fInotify_init_internal()
339{
340 char * filename;
341 int class;
342 int type;
343 int rdepth;
344 unsigned long check_flags;
345 int retval;
346 int errnum;
347
348 if (ShfInotifyActive == S_FALSE)
349 return SH_MOD_FAILED;
350
351 /* Wait until file scan is finished.
352 */
353 while((sh.flag.inotify & SH_INOTIFY_DOSCAN) != 0)
354 {
355 retry_msleep(1,0);
356
357 if (ShfInotifyActive == S_FALSE)
358 return SH_MOD_FAILED;
359 }
360
361 sh_fInotify_set_nwatches();
362
363 while (NULL != (filename = sh_inotify_pop_dormant(&sh_file_watches,
364 &class, &check_flags,
365 &type, &rdepth)))
366 {
367 retval = sh_inotify_add_watch(filename, &sh_file_watches, &errnum,
368 class, check_flags, type, rdepth);
369
370 if (retval < 0)
371 {
372 char errbuf[SH_ERRBUF_SIZE];
373
374 sh_error_message(errnum, errbuf, sizeof(errbuf));
375
376 if ((errnum == ENOENT) || (errnum == EEXIST))
377 {
378 /* (1) Did it exist at init ?
379 */
380 if (sh_hash_have_it (filename) >= 0)
381 {
382 /* (2) Do we want to report on it ?
383 */
384 if (S_FALSE == sh_ignore_chk_del(filename))
385 {
386 char * epath = sh_util_safe_name (filename);
387
388 SH_MUTEX_LOCK(mutex_thread_nolog);
389 sh_error_handle( SH_ERR_ALL /* debug */,
390 FIL__, __LINE__, errnum, MSG_E_SUBGPATH,
391 errbuf, _("sh_fInotify_init_internal"), epath);
392 SH_MUTEX_UNLOCK(mutex_thread_nolog);
393 SH_FREE(epath);
394 }
395 }
396 }
397 else
398 {
399 SH_MUTEX_LOCK(mutex_thread_nolog);
400 sh_error_handle((-1), FIL__, __LINE__, errnum, MSG_E_SUBGEN,
401 errbuf, _("sh_fInotify_init_internal"));
402 SH_MUTEX_UNLOCK(mutex_thread_nolog);
403 }
404 }
405 SH_FREE(filename);
406 }
407
408 /* Need this because mod_check() may run after
409 * DOSCAN is finished, hence wouldn't call init().
410 */
411 SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_NEEDINIT; );
412
413 return 0;
414}
415
416static void sh_fInotify_logmask(struct inotify_event * event)
417{
418 char dbgbuf[256];
419
420 sl_strlcpy (dbgbuf, "inotify mask: ", sizeof(dbgbuf));
421
422 if (event->mask & IN_ACCESS) sl_strlcat(dbgbuf, "IN_ACCESS ", sizeof(dbgbuf));
423 if (event->mask & IN_ATTRIB) sl_strlcat(dbgbuf, "IN_ATTRIB ", sizeof(dbgbuf));
424 if (event->mask & IN_CLOSE_WRITE) sl_strlcat(dbgbuf, "IN_CLOSE_WRITE ", sizeof(dbgbuf));
425 if (event->mask & IN_CLOSE_NOWRITE) sl_strlcat(dbgbuf, "IN_CLOSE_NOWRITE ", sizeof(dbgbuf));
426 if (event->mask & IN_CREATE) sl_strlcat(dbgbuf, "IN_CREATE ", sizeof(dbgbuf));
427 if (event->mask & IN_DELETE) sl_strlcat(dbgbuf, "IN_DELETE ", sizeof(dbgbuf));
428 if (event->mask & IN_DELETE_SELF) sl_strlcat(dbgbuf, "IN_DELETE_SELF ", sizeof(dbgbuf));
429 if (event->mask & IN_MODIFY) sl_strlcat(dbgbuf, "IN_MODIFY ", sizeof(dbgbuf));
430 if (event->mask & IN_MOVE_SELF) sl_strlcat(dbgbuf, "IN_MOVE_SELF ", sizeof(dbgbuf));
431 if (event->mask & IN_MOVED_FROM) sl_strlcat(dbgbuf, "IN_MOVED_FROM ", sizeof(dbgbuf));
432 if (event->mask & IN_MOVED_TO) sl_strlcat(dbgbuf, "IN_MOVED_TO ", sizeof(dbgbuf));
433 if (event->mask & IN_OPEN) sl_strlcat(dbgbuf, "IN_OPEN ", sizeof(dbgbuf));
434 if (event->mask & IN_IGNORED) sl_strlcat(dbgbuf, "IN_IGNORED ", sizeof(dbgbuf));
435 if (event->mask & IN_ISDIR) sl_strlcat(dbgbuf, "IN_ISDIR ", sizeof(dbgbuf));
436 if (event->mask & IN_Q_OVERFLOW) sl_strlcat(dbgbuf, "IN_Q_OVERFLOW ", sizeof(dbgbuf));
437 if (event->mask & IN_UNMOUNT) sl_strlcat(dbgbuf, "IN_UNMOUNT ", sizeof(dbgbuf));
438
439 SH_MUTEX_LOCK(mutex_thread_nolog);
440 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, 0, MSG_E_SUBGEN,
441 dbgbuf, _("sh_fInotify_process"));
442 SH_MUTEX_UNLOCK(mutex_thread_nolog);
443}
444
445static int sh_fInotify_process(struct inotify_event * event)
446{
447 int class;
448 int ftype;
449 int rdepth;
450 unsigned long check_flags;
451 char * filename;
452 extern int flag_err_debug;
453
454 if (flag_err_debug == S_TRUE)
455 {
456 sh_fInotify_logmask(event);
457 }
458
459 if (event->wd >= 0)
460 {
461 filename = sh_inotify_search_item(&sh_file_watches, event->wd,
462 &class, &check_flags, &ftype, &rdepth);
463
464 if (filename)
465 {
466 sh_fInotify_report(event, filename, class, check_flags, ftype, rdepth);
467 SH_FREE(filename);
468 }
469 else if (sh.flag.inotify & SH_INOTIFY_NEEDINIT)
470 {
471 return 1;
472 }
473 else if ((event->mask & IN_UNMOUNT) == 0 && (event->mask & IN_IGNORED) == 0)
474 {
475 /* Remove watch ? Seems reasonable. */
476 sh_inotify_rm_watch(NULL, NULL, event->wd);
477
478 SH_MUTEX_LOCK(mutex_thread_nolog);
479 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, event->wd, MSG_E_SUBGEN,
480 _("Watch removed: file path unknown"),
481 _("sh_fInotify_process"));
482 SH_MUTEX_UNLOCK(mutex_thread_nolog);
483 }
484 }
485 else if ((event->mask & IN_Q_OVERFLOW) != 0)
486 {
487 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_DOSCAN; );
488 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
489
490 SH_MUTEX_LOCK(mutex_thread_nolog);
491 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, event->wd, MSG_E_SUBGEN,
492 _("Inotify queue overflow"),
493 _("sh_fInotify_process"));
494 SH_MUTEX_UNLOCK(mutex_thread_nolog);
495 return 1;
496 }
497
498 return 0;
499}
500
501void sh_fInotify_report_add(char * path, int class, unsigned long check_flags)
502{
503 if (S_FALSE == sh_ignore_chk_new(path))
504 {
505 int reported = 0;
506
507 sh_files_clear_file_reported(path);
508
509 sh_files_search_file(path, &class, &check_flags, &reported);
510
511 sh_files_filecheck (class, check_flags, path, NULL,
512 &reported, 0);
513 if (SH_FFLAG_REPORTED_SET(reported))
514 sh_files_set_file_reported(path);
515 }
516 return;
517}
518
519
520static void sh_fInotify_report_miss(char * name, int level)
521{
522 char * tmp = sh_util_safe_name (name);
523
524 SH_MUTEX_LOCK(mutex_thread_nolog);
525 if (!sh_global_check_silent)
526 sh_error_handle (level, FIL__, __LINE__, 0, MSG_FI_MISS, tmp);
527 SH_MUTEX_UNLOCK(mutex_thread_nolog);
528 ++sh.statistics.files_report;
529 SH_FREE(tmp);
530 return;
531}
532
533static int sh_fInotify_report_change (struct inotify_event * event,
534 char * path, char * filename,
535 int class, unsigned long check_flags, int ftype)
536{
537 int reported;
538 int ret;
539
540
541 if (S_FALSE == sh_ignore_chk_mod(path))
542 {
543 ret = sh_files_search_file(path, &class, &check_flags, &reported);
544
545 if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
546 {
547 ; /* do nothing, watch was for directory monitored as file only */
548 }
549 else
550 {
551 sh_files_filecheck (class, check_flags, filename,
552 (event->len > 0) ? event->name : NULL,
553 &reported, 0);
554 }
555 }
556 return 0;
557}
558
559
560static int sh_fInotify_report_missing (struct inotify_event * event,
561 char * path,
562 int class, unsigned long check_flags, int ftype)
563{
564 int reported;
565 int isdir = (event->mask & IN_ISDIR);
566 int level = (class == SH_LEVEL_ALLIGNORE) ?
567 ShDFLevel[class] :
568 ShDFLevel[(isdir == 0) ? SH_ERR_T_FILE : SH_ERR_T_DIR];
569
570 if (S_FALSE == sh_ignore_chk_del(path))
571 {
572 if (0 != hashreport_missing(path, level))
573 {
574 int ret = sh_files_search_file(path, &class, &check_flags, &reported);
575
576 if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
577 {
578 ; /* do nothing, watch was for directory monitored as file only */
579 }
580 else
581 {
582 /* Removal of a directory triggers:
583 * (1) IN_DELETE IN_ISDIR
584 * (2) IN_DELETE_SELF
585 */
586 if ((event->mask & IN_DELETE_SELF) == 0)
587 sh_fInotify_report_miss(path, level);
588 }
589 }
590 }
591
592 sh_hash_set_missing(path);
593
594 if (sh.flag.reportonce == S_TRUE)
595 sh_files_set_file_reported(path);
596
597 /* Move to 'dormant' list, if not file within directory.
598 */
599 if (event->len == 0)
600 sh_inotify_rm_watch(&sh_file_watches, &sh_file_missing, event->wd);
601
602 return 0;
603}
604
605static int sh_fInotify_report_added (struct inotify_event * event,
606 char * path, char * filename,
607 int class, unsigned long check_flags,
608 int ftype, int rdepth)
609{
610 if (S_FALSE == sh_ignore_chk_new(path))
611 {
612 int reported;
613 int ret;
614 int retD = 0;
615 int rdepthD = rdepth;
616
617 sh_files_clear_file_reported(path);
618
619 ret = sh_files_search_file(path, &class, &check_flags, &reported);
620
621 if ((ret == 0) && (event->len > 0) && (ftype == SH_INOTIFY_FILE))
622 {
623 ; /* do nothing, watch was for directory monitored as file only */
624 }
625 else
626 {
627 int classD = class;
628 int reportedD = reported;
629 unsigned long check_flagsD = check_flags;
630
631 if (event->mask & IN_ISDIR)
632 {
633 retD = sh_files_search_dir(path, &classD, &check_flagsD,
634 &reportedD, &rdepthD);
635 if (retD != 0)
636 {
637 if (ret == 0)
638 {
639 class = classD;
640 check_flags = check_flagsD;
641 }
642 }
643 }
644
645 sh_files_filecheck (class, check_flags, filename,
646 (event->len > 0) ? event->name : NULL,
647 &reported, 0);
648
649 if (event->mask & IN_ISDIR)
650 {
651 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_INSCAN; );
652 sh_files_checkdir (classD, check_flagsD, rdepthD,
653 path, (event->len > 0) ? event->name : NULL);
654 SH_INOTIFY_IFUSED( sh.flag.inotify &= ~SH_INOTIFY_INSCAN; );
655 SH_INOTIFY_IFUSED( sh.flag.inotify |= SH_INOTIFY_NEEDINIT; );
656 sh_dirs_reset ();
657 sh_files_reset ();
658 }
659
660 }
661
662 if (SH_FFLAG_REPORTED_SET(reported))
663 sh_files_set_file_reported(path);
664
665 if ((ret != 0) || (event->mask & IN_ISDIR))
666 {
667 sh_inotify_add_watch(path, &sh_file_watches, &ret,
668 class, check_flags,
669 (event->mask & IN_ISDIR)?SH_INOTIFY_DIR:SH_INOTIFY_FILE,
670 rdepthD);
671 }
672 }
673 return 0;
674}
675
676static int sh_fInotify_report(struct inotify_event * event, char * filename,
677 int class, unsigned long check_flags, int ftype, int rdepth)
678{
679 char * fullpath = NULL;
680 char * path;
681
682 if (event->len > 0)
683 {
684 fullpath = sh_util_strconcat(filename, "/", event->name, NULL);
685 path = fullpath;
686 }
687 else
688 {
689 path = filename;
690 }
691
692 if ( (event->mask & (IN_ATTRIB|IN_MODIFY)) != 0)
693 {
694 sh_fInotify_report_change (event, path, filename,
695 class, check_flags, ftype);
696 }
697 else if ((event->mask & (IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF|IN_MOVED_FROM)) != 0)
698 {
699 sh_fInotify_report_missing (event, path,
700 class, check_flags, ftype);
701 }
702 else if((event->mask & (IN_CREATE|IN_MOVED_TO)) != 0)
703 {
704 sh_fInotify_report_added (event, path, filename,
705 class, check_flags,
706 ftype, rdepth);
707 }
708
709 if (fullpath)
710 SH_FREE(fullpath);
711
712 return 0;
713}
714
715
716#endif
717
718#endif
Note: See TracBrowser for help on using the repository browser.