source: trunk/src/sh_fInotify.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

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