source: trunk/src/sh_fInotify.c @ 433

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

Fix for ticket #338 (steady growth of memory usage).

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