clsync
mon_kqueue.c
Go to the documentation of this file.
1 /*
2  clsync - file tree sync utility based on inotify/kqueue
3 
4  Copyright (C) 2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "common.h"
21 
22 #include <glib.h>
23 
24 #include "error.h"
25 #include "sync.h"
26 #include "indexes.h"
27 #include "fileutils.h"
28 #include "calc.h"
29 #include "glibex.h"
30 #include "mon_kqueue.h"
31 
37 };
39 
40 struct monobj {
41  ino_t inode;
42  dev_t device;
43  int fd;
44  int dir_fd;
45  char *name;
46  size_t name_len;
47  uint32_t name_hash;
48  unsigned char type;
49  size_t changelist_id;
50  struct monobj *parent;
51 
52  // Case specific stuff
53  union {
54  // For directories only, for original (not dupes) obj_p only
55  GTree *children_tree;
56  // For duplicates only, see _kqueue_handle_oneevent_dircontent()
57  struct monobj *origin;
58  };
59 };
60 typedef struct monobj monobj_t;
61 
62 struct kqueue_data {
63  int kqueue_d;
64 
65  struct kevent *changelist;
70  monobj_t **obj_p_by_clid; // An associative array to get the monobj pointer by an changelist_id
71  GTree *file_btree;
72  GTree *fd_btree;
73 };
74 
76  union {
77  struct {
80  } v;
81  uint32_t i;
82  } u;
83 };
84 
86 indexes_t *indexes_p;
87 
88 static inline uint32_t recognize_event ( uint32_t event, int is_dir )
89 {
90  struct recognize_event_return r = {{{0}}};
91  eventobjtype_t type;
92  int is_created;
93  int is_deleted;
94  type = ( is_dir ? EOT_DIR : EOT_FILE );
95  is_created = event & ( NOTE_LINK );
96  is_deleted = event & ( NOTE_DELETE );
97  debug ( 4, "type == %x; is_created == %x; is_deleted == %x", type, is_created, is_deleted );
98  r.u.v.objtype_old = type;
99  r.u.v.objtype_new = type;
100 
101  if ( is_created )
102  r.u.v.objtype_old = EOT_DOESNTEXIST;
103 
104  if ( is_deleted )
105  r.u.v.objtype_new = EOT_DOESNTEXIST;
106 
107  return r.u.i;
108 }
109 
110 extern int kqueue_sync ( ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p );
111 extern int kqueue_unmark ( ctx_t *ctx_p, monobj_t *obj_p );
112 
113 void unmarkchild ( gpointer _obj_p )
114 {
115  monobj_t *obj_p = _obj_p;
116  static struct kevent ev = {0};
117  debug ( 10, "Calling kqueue_sync() on \"%s\" (obj_p: %p; dir_fd: %i; fd: %i)", obj_p->name, obj_p, obj_p->dir_fd, obj_p->fd );
118  ev.ident = obj_p->fd;
119  ev.fflags = NOTE_DELETE;
120  critical_on ( kqueue_sync ( ctx_p, indexes_p, &ev, obj_p ) );
121  debug ( 4, "Unmarking the child \"%s\" (dir_fd: %i; fd: %i)", obj_p->name, obj_p->dir_fd, obj_p->fd );
122  kqueue_unmark ( ctx_p, obj_p );
123  return;
124 }
125 gboolean unmarkchild_for_foreach ( gpointer _obj_p, gpointer _value, gpointer _ctx_p )
126 {
127  unmarkchild ( _obj_p );
128  return FALSE;
129 }
130 
131 void monobj_free ( void *monobj_p )
132 {
133  monobj_t *obj_p = monobj_p;
134  debug ( 20, "obj_p == %p; obj_p->fd == %i; obj_p->name == \"%s\"", obj_p, obj_p->fd, obj_p->name );
135 
137  if ( obj_p->children_tree != NULL ) {
138  debug ( 20, "Removing children" );
139 
140  if ( g_tree_nnodes ( obj_p->children_tree ) ) {
141  g_tree_foreach ( obj_p->children_tree, unmarkchild_for_foreach, ctx_p );
142  g_tree_destroy ( obj_p->children_tree );
143  }
144  }
145 
146  if ( obj_p->parent != NULL ) {
147  monobj_t *parent = obj_p->parent;
148  debug ( 20, "Removing the obj from parent->children_tree (obj_p == %p; parent == %p; parent->children_tree == %p)", obj_p, parent, parent->children_tree );
149  g_tree_remove ( parent->children_tree, obj_p );
150  }
151  }
152 
153  debug ( 20, "free()-s" );
154  free ( obj_p->name );
155  free ( obj_p );
156  return;
157 }
158 
159 static gint monobj_filecmp ( gconstpointer _a, gconstpointer _b, gpointer _ctx_p )
160 {
161 #ifdef VERYPARANOID
162  critical_on ( _a == NULL );
163  critical_on ( _b == NULL );
164 #endif
165  const monobj_t *a = _a, *b = _b;
166  debug ( 95, "a == %p; b == %p", a, b );
167  int diff_inode = a->inode - b->inode;
168  debug ( 90, "diff_inode = %i", diff_inode );
169 
170  if ( diff_inode )
171  return diff_inode;
172 
173  int diff_device = a->device - b->device;
174  debug ( 50, "diff_device = %i", diff_device );
175 
176  if ( diff_device )
177  return diff_device;
178 
179  int diff_dir_fd = a->dir_fd - b->dir_fd;
180  debug ( 50, "diff_dir_fd = %i (%i - %i)", diff_dir_fd, a->dir_fd, b->dir_fd );
181 
182  if ( diff_dir_fd )
183  return diff_dir_fd;
184 
185  int diff_name_hash = a->name_hash - b->name_hash;
186  debug ( 50, "diff_name_hash = %i", diff_name_hash );
187 
188  if ( diff_name_hash )
189  return diff_name_hash;
190 
191  debug ( 10, "strcmp(\"%s\", \"%s\") = %i", a->name, b->name, strcmp ( a->name, b->name ) );
192  return strcmp ( a->name, b->name );
193 }
194 
195 static int monobj_fdcmp ( gconstpointer a, gconstpointer b, gpointer _ctx_p )
196 {
197  return ( ( monobj_t * ) a )->fd - ( ( monobj_t * ) b )->fd;
198 }
199 
200 int kqueue_init ( ctx_t *_ctx_p )
201 {
202  struct kqueue_data *mondata;
203  debug ( 9, "_ctx_p == %p", _ctx_p );
204  ctx_p = _ctx_p;
205  indexes_p = ctx_p->indexes_p;
206  ctx_p->fsmondata = xcalloc ( 1, sizeof ( struct kqueue_data ) );
207 
208  if ( ctx_p->fsmondata == NULL )
209  return -1;
210 
211  struct kqueue_data *dat = ctx_p->fsmondata;
212  dat->kqueue_d = kqueue();
214  mondata->file_btree = g_tree_new_full ( monobj_filecmp, _ctx_p, monobj_free, NULL );
215  mondata->fd_btree = g_tree_new_full ( monobj_fdcmp, _ctx_p, NULL, NULL );
217  return 0;
218 }
219 
220 int kqueue_mark ( ctx_t *ctx_p, monobj_t *obj_p )
221 {
222  struct kqueue_data *dat = ctx_p->fsmondata;
223 #ifdef VERYPARANOID
224 
225  if ( obj_p == NULL ) {
226  errno = EINVAL;
227  return -1;
228  }
229 
230 #endif
231  debug ( 9, "" );
232 
233  if ( obj_p->dir_fd == -1 )
234  obj_p->fd = open ( ctx_p->watchdir, O_RDONLY | O_NOFOLLOW );
235  else
236  obj_p->fd = openat ( obj_p->dir_fd, obj_p->name, O_RDONLY | O_NOFOLLOW );
237 
238  debug ( 4, "obj_p-> (%p): dir_fd == %i; name == \"%s\"; fd == %i; type == %i (isdir == %i)", obj_p, obj_p->dir_fd, obj_p->name, obj_p->fd, obj_p->type, obj_p->type == DT_DIR );
239 
240  if ( obj_p->fd == -1 ) {
241  debug ( 2, "File/dir \"%s\" disappeared. Skipping", obj_p->name );
242  return 0;
243  }
244 
245  if ( dat->changelist_used >= dat->changelist_alloced ) {
247  dat->changelist = xrealloc ( dat->changelist, dat->changelist_alloced * sizeof ( *dat->changelist ) );
248  dat->obj_p_by_clid = xrealloc ( dat->obj_p_by_clid, dat->changelist_alloced * sizeof ( *dat->obj_p_by_clid ) );
249  }
250 
251  switch ( obj_p->type ) {
252  case DT_DIR:
253  EV_SET ( &dat->changelist[dat->changelist_used], obj_p->fd,
254  EVFILT_VNODE,
255  EV_ADD | EV_CLEAR,
256  NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_DELETE,
257  0, 0 );
258  break;
259 
260  default:
261  EV_SET ( &dat->changelist[dat->changelist_used], obj_p->fd,
262  EVFILT_VNODE,
263  EV_ADD | EV_CLEAR,
264  NOTE_WRITE | NOTE_ATTRIB | NOTE_DELETE,
265  0, 0 );
266  break;
267  }
268 
269  obj_p->changelist_id = dat->changelist_used++;
270  dat->obj_p_by_clid[obj_p->changelist_id] = obj_p;
271  return 0;
272 }
273 
274 
275 void child_free ( monobj_t *node )
276 {
277  critical_on ( kqueue_unmark ( ctx_p, node ) );
278 }
280 {
281  int changelist_id_last;
282  debug ( 20, "obj_p == %p", obj_p );
283  struct kqueue_data *dat = ctx_p->fsmondata;
284 #ifdef VERYPARANOID
285 
286  if ( obj_p == NULL ) {
287  errno = EINVAL;
288  return -1;
289  }
290 
291 #endif
292  debug ( 30, "dat->changelist_used == %i", dat->changelist_used );
293 
294  if ( dat->changelist_used ) {
295  dat->changelist_used--;
296  changelist_id_last = dat->changelist_used;
297  debug ( 30, "Checking: (obj_p->changelist_id [%i] < changelist_id_last [%i]) == %i", obj_p->changelist_id, changelist_id_last, ( obj_p->changelist_id < changelist_id_last ) );
298 #ifdef PARANOID
299  critical_on ( obj_p->changelist_id > changelist_id_last );
300 #endif
301 
302  if ( obj_p->changelist_id < changelist_id_last ) {
303  debug ( 20, "dat->changelist: moving %i -> %i", changelist_id_last, obj_p->changelist_id );
304  dat->obj_p_by_clid[ obj_p->changelist_id ] = dat->obj_p_by_clid[ changelist_id_last ];
305  dat->obj_p_by_clid[ obj_p->changelist_id ]->changelist_id = obj_p->changelist_id;
306  memcpy ( &dat->changelist[obj_p->changelist_id], &dat->changelist[changelist_id_last], sizeof ( *dat->changelist ) );
307  debug ( 30,
308  "dat->obj_p_by_clid[ obj_p->changelist_id ] == %p; "
309  "dat->obj_p_by_clid[ obj_p->changelist_id ]->fd == %i; "
310  "dat->obj_p_by_clid[ obj_p->changelist_id ]->name == \"%s\"",
311  dat->obj_p_by_clid[ obj_p->changelist_id ],
312  dat->obj_p_by_clid[ obj_p->changelist_id ]->fd,
313  dat->obj_p_by_clid[ obj_p->changelist_id ]->name
314  );
315  }
316  }
317 
318  close ( obj_p->fd );
319  debug ( 20, "Removing the obj itself" );
320  g_tree_remove ( dat->fd_btree, obj_p );
321  g_tree_remove ( dat->file_btree, obj_p );
322  return 0;
323 }
324 
325 monobj_t *kqueue_start_watch ( ctx_t *ctx_p, ino_t inode, dev_t device, int dir_fd, const char *const fname, size_t name_len, unsigned char type )
326 {
327  monobj_t *obj_p, *parent, parent_pattern;
328  struct kqueue_data *dat = ctx_p->fsmondata;
329  debug ( 3, "(ctx_p, %i, \"%s\", %u, %u)", dir_fd, fname, name_len, type );
330 #ifdef VERYPARANOID
331  obj_p = xcalloc ( sizeof ( *obj_p ), 1 );
332 #else
333  obj_p = xmalloc ( sizeof ( *obj_p ) );
334 #endif
335  obj_p->inode = inode;
336  obj_p->device = device;
337  obj_p->dir_fd = dir_fd;
338  obj_p->name_len = name_len;
339  obj_p->name = xmalloc ( obj_p->name_len + 1 );
340  obj_p->type = type;
341  memcpy ( obj_p->name, fname, obj_p->name_len + 1 );
342  obj_p->name_hash = adler32_calc ( ( const unsigned char * ) fname, name_len );
343  parent = NULL;
344  parent_pattern.fd = dir_fd;
345  parent = g_tree_lookup ( dat->fd_btree, &parent_pattern );
346 
347  if ( parent != NULL ) {
348  obj_p->parent = parent;
349  debug ( 20, "Adding a child for dir_fd == %i", dir_fd );
350  g_tree_replace ( parent->children_tree, obj_p, obj_p );
351  debug ( 25, "parent->children_tree == %p", parent->children_tree );
352  }
353 
354  debug ( 20, "parent == %p; obj_p == %p", parent, obj_p );
355 
356  switch ( type ) {
357  case DT_DIR:
358  obj_p->children_tree = g_tree_new_full ( monobj_filecmp, ctx_p, NULL, NULL );
359  debug ( 25, "dir_p->children_tree == %p", obj_p->children_tree );
360 
361  case DT_UNKNOWN:
362  case DT_REG:
363  if ( kqueue_mark ( ctx_p, obj_p ) ) {
364  error ( "Got error while kqueue_mark()" );
365  free ( obj_p->name );
366  free ( obj_p );
367  return NULL;
368  }
369 
370  break;
371 
372  default:
373  debug ( 4, "I won't open() this object due to it's type == %u.", type );
374  break;
375  }
376 
377  debug ( 8, "storing: inode == %u; device == %u; dir_fd == %i; fd == %i; parent == %p", obj_p->inode, obj_p->device, obj_p->dir_fd, obj_p->fd, parent );
378  g_tree_replace ( dat->file_btree, obj_p, obj_p );
379  g_tree_replace ( dat->fd_btree, obj_p, obj_p );
380  return obj_p;
381 }
382 
383 monobj_t *kqueue_add_watch_direntry ( ctx_t *ctx_p, indexes_t *indexes_p, struct dirent *entry, monobj_t *dir_obj_p )
384 {
385  struct kqueue_data *dat = ctx_p->fsmondata;
386  monobj_t *obj_p;
387  uint32_t name_hash;
388 #ifdef VERYPARANOID
389  critical_on ( entry == NULL );
390 #endif
391  size_t name_len = strlen ( entry->d_name );
392  name_hash = adler32_calc ( ( unsigned char * ) entry->d_name, name_len );
393  {
394  monobj_t obj;
395  obj.inode = entry->d_ino;
396  obj.device = dir_obj_p->device;
397  obj.dir_fd = dir_obj_p->fd;
398  obj.name_hash = name_hash;
399 
400  if ( ( obj_p = g_tree_lookup ( dat->file_btree, &obj ) ) != NULL )
401  return obj_p;
402  }
403 
404  if ( ( obj_p = kqueue_start_watch ( ctx_p, entry->d_ino, dir_obj_p->device, dir_obj_p->fd, entry->d_name, name_len, entry->d_type ) ) == NULL )
405  error ( "Got error while kqueue_start_watch()" );
406 
407  obj_p->inode = entry->d_ino;
408  obj_p->device = dir_obj_p->device;
409  obj_p->dir_fd = dir_obj_p->fd;
410  obj_p->name_hash = name_hash;
411  return obj_p;
412 }
413 
414 monobj_t *kqueue_add_watch_path ( ctx_t *ctx_p, indexes_t *indexes_p, const char *const path )
415 {
416  struct stat st;
417  struct kqueue_data *dat = ctx_p->fsmondata;
418  monobj_t *obj_p = NULL;
419  uint32_t name_hash;
420  const char *file_name;
421  int dir_fd;
422  size_t name_len;
423 #ifdef VERYPARANOID
424 
425  if ( path == NULL ) {
426  errno = EINVAL;
427  return NULL;
428  }
429 
430 #endif
431  debug ( 6, "(ctx_p, indexes_p, \"%s\")", path );
432  {
433  char *dir_path, *ptr;
434  ptr = strrchr ( path, '/' );
435 
436  if ( ptr == NULL ) {
437  file_name = path;
438  dir_fd = indexes_fpath2wd ( indexes_p, "" );
439  } else {
440  dir_path = strdup ( path );
441  dir_path[ptr - path] = 0;
442  dir_fd = indexes_fpath2wd ( indexes_p, dir_path );
443 
444  if ( dir_fd == -1 ) {
445  if ( strcmp ( ctx_p->watchdir, path ) ) {
446  errno = ENOENT;
447  error ( "Cannot find file descriptor of directory \"%s\"", dir_path );
448  return NULL;
449  }
450  }
451 
452  free ( dir_path );
453  file_name = &ptr[1];
454  }
455 
456  name_len = strlen ( file_name );
457  name_hash = adler32_calc ( ( unsigned char * ) file_name, name_len );
458  }
459  lstat ( path, &st );
460  {
461  monobj_t obj;
462  obj.inode = st.st_ino;
463  obj.device = st.st_dev;
464  obj.dir_fd = dir_fd;
465  obj.name_hash = name_hash;
466  obj.name = ( char * ) file_name;
467 
468  if ( ( obj_p = g_tree_lookup ( dat->file_btree, &obj ) ) != NULL )
469  return obj_p;
470  }
471  debug ( 9, "not monitored file/dir \"%s\", yet.", file_name );
472  {
473  const char *name_start;
474  name_start = strrchr ( path, '/' );
475 
476  if ( name_start == NULL )
477  name_start = path;
478  else
479  name_start++;
480 
481  if ( ( obj_p = kqueue_start_watch ( ctx_p, st.st_ino, st.st_dev, dir_fd, file_name, name_len, ( st.st_mode & S_IFMT ) == S_IFDIR ? DT_DIR : DT_REG ) ) == NULL )
482  error ( "Got error while kqueue_start_watch()" );
483  }
484  obj_p->inode = st.st_ino;
485  obj_p->device = st.st_dev;
486  obj_p->dir_fd = dir_fd;
487  obj_p->name_hash = name_hash;
488  return obj_p;
489 }
490 
491 int kqueue_add_watch_dir ( ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath )
492 {
493  DIR *dir;
494  monobj_t *dir_obj_p = NULL;
495  struct dirent *entry;
496 #ifdef VERYPARANOID
497 
498  if ( accpath == NULL ) {
499  errno = EINVAL;
500  return -1;
501  }
502 
503 #endif
504  debug ( 5, "(ctx_p, indexes_p, \"%s\")", accpath );
505 
506  if ( ( dir_obj_p = kqueue_add_watch_path ( ctx_p, indexes_p, accpath ) ) == NULL ) {
507  error ( "Got error while kqueue_add_watch_path(ctx_p, \"%s\")", accpath );
508  return -1;
509  }
510 
511  dir = fdopendir ( dir_obj_p->fd );
512 
513  if ( dir == NULL )
514  return -1;
515 
516  while ( ( entry = readdir ( dir ) ) ) {
517  if ( !memcmp ( entry->d_name, ".", 2 ) )
518  continue;
519 
520  if ( !memcmp ( entry->d_name, "..", 3 ) )
521  continue;
522 
523  if ( kqueue_add_watch_direntry ( ctx_p, indexes_p, entry, dir_obj_p ) == NULL ) {
524  error ( "Got error while kqueue_add_watch_direntry(ctx_p, indexes_p, entry {->d_name == \"%s\"}, %u)", entry->d_name, dir_obj_p->fd );
525  return -1;
526  }
527  }
528 
529  return dir_obj_p->fd;
530 }
531 
532 int kqueue_wait ( ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p )
533 {
534  struct kqueue_data *dat = ctx_p->fsmondata;
535  struct timespec ts;
536  debug ( 3, "tv_p->: tv_sec == %li; tv_usec == %li", tv_p->tv_sec, tv_p->tv_usec );
537 #ifdef PARANOID
538 
539  if ( tv_p == NULL )
540  return dat->eventlist_count = kevent ( dat->kqueue_d, dat->changelist, dat->changelist_used, dat->eventlist, KQUEUE_EVENTLISTSIZE, NULL );
541 
542 #endif
543  ts.tv_sec = tv_p->tv_sec;
544  ts.tv_nsec = tv_p->tv_usec * 1000;
545  return dat->eventlist_count = kevent ( dat->kqueue_d, dat->changelist, dat->changelist_used, dat->eventlist, KQUEUE_EVENTLISTSIZE, &ts );
546 }
547 
548 // Not a thread-safe function!
549 char *kqueue_getpath ( ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *obj_p )
550 {
551  char *dirpath;
552  size_t dirpath_len;
553  static char filepath[PATH_MAX + 2];
554  size_t filepath_len;
555  dirpath = indexes_wd2fpath ( indexes_p, obj_p->fd );
556 
557  if ( dirpath != NULL )
558  return strdup ( dirpath );
559 
560  if ( obj_p->dir_fd == -1 ) {
561  errno = ENOENT;
562  error ( "Cannot find fd of parent directory of \"%s\"", obj_p->name );
563  return NULL;
564  }
565 
566  dirpath = indexes_wd2fpath ( indexes_p, obj_p->dir_fd );
567 
568  if ( dirpath == NULL ) {
569  errno = ENOENT;
570  error ( "Cannot find directory with fd == %u", obj_p->dir_fd );
571  return NULL;
572  }
573 
574  dirpath_len = strlen ( dirpath );
575  filepath_len = dirpath_len + obj_p->name_len + 1;
576 #ifdef PARANOID
577 
578  if ( filepath_len + 1 >= PATH_MAX ) {
579  errno = ENAMETOOLONG;
580  error ( "Too long file path: \"%s/%s\"", dirpath, obj_p->name );
581  return NULL;
582  }
583 
584 #endif
585  memcpy ( filepath, dirpath, dirpath_len );
586  filepath[dirpath_len] = '/';
587  memcpy ( &filepath[dirpath_len + 1], obj_p->name, obj_p->name_len + 1 );
588  return filepath;
589 }
590 
591 int kqueue_sync ( ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p )
592 {
593  stat64_t lst, *lst_p;
594  char *path_full = kqueue_getpath ( ctx_p, indexes_p, obj_p );
595 #ifdef PARANOID
596 
597  if ( path_full == NULL ) {
598  error ( "Cannot get full path for \"%s\" (fd: %u)", obj_p->name, obj_p->fd );
599  return -1;
600  }
601 
602 #endif
603  debug ( 8, "path_full = \"%s\"", path_full );
604  mode_t st_mode;
605  size_t st_size;
606 
607  if ( ( ev_p->fflags == NOTE_DELETE ) || ( ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT ) || lstat64 ( path_full, &lst ) ) {
608  debug ( 2, "Cannot or cancelled lstat64(\"%s\", lst). The object had been deleted (%i) or option \"--cancel-syscalls=mon_stat\" (%i) is set.", path_full, ev_p->fflags == NOTE_DELETE, ctx_p->flags[CANCEL_SYSCALLS]&CSC_MON_STAT );
609  st_mode = ( obj_p->type == DT_DIR ? S_IFDIR : S_IFREG );
610  st_size = 0;
611  lst_p = NULL;
612  } else {
613  st_mode = lst.st_mode;
614  st_size = lst.st_size;
615  lst_p = &lst;
616  }
617 
618  {
619  char *path_rel = NULL;
620  size_t path_rel_len = 0;
621  struct recognize_event_return r;
622  r.u.i = recognize_event ( ev_p->fflags, obj_p->type == DT_DIR );
623  int ret = sync_prequeue_loadmark ( 1, ctx_p, indexes_p, path_full, NULL, lst_p, r.u.v.objtype_old, r.u.v.objtype_new, ev_p->fflags, ev_p->ident, st_mode, st_size, &path_rel, &path_rel_len, NULL );
624 
625  if ( path_rel != NULL )
626  free ( path_rel );
627 
628  return ret;
629  }
630 
631  return 0;
632 }
633 
634 static inline int _kqueue_handle_oneevent_dircontent_item ( struct kqueue_data *dat, ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *dir_obj_p, struct dirent *entry, void *children_notfound )
635 {
636  static monobj_t obj, *obj_p;
637  struct kevent ev = {0};
638  debug ( 9, "\"%s\"", entry->d_name );
639  obj.type = entry->d_type;
640  obj.inode = entry->d_ino;
641  obj.device = dir_obj_p->device;
642  obj.dir_fd = dir_obj_p->fd;
643  obj.name = entry->d_name;
644  obj.name_len = strlen ( entry->d_name );
645  obj.name_hash = adler32_calc ( ( unsigned char * ) entry->d_name, obj.name_len );
646  debug ( 20, "Checking if the object is already monitored (obj_p == %p)", obj_p );
647 
648  if ( ( obj_p = g_tree_lookup ( dat->file_btree, &obj ) ) != NULL ) {
649  debug ( 20, "Marking the the object is found" );
650  g_tree_remove ( children_notfound, obj_p );
651  return 0;
652  }
653 
654  debug ( 20, "Calling kqueue_start_watch() on the object" );
655 
656  if ( ( obj_p = kqueue_start_watch ( ctx_p, entry->d_ino, dir_obj_p->device, dir_obj_p->fd, obj.name, obj.name_len, obj.type ) ) == NULL ) {
657  error ( "Got error while kqueue_start_watch()" );
658  return -1;
659  }
660 
661  debug ( 20, "Calling kqueue_sync() for the object" );
662  ev.ident = obj_p->fd;
663  ev.fflags = NOTE_LINK;
664 
665  if ( kqueue_sync ( ctx_p, indexes_p, &ev, obj_p ) ) {
666  error ( "Got error while kqueue_sync()" );
667  return -1;
668  }
669 
670  return 0;
671 }
672 
673 void monobj_freedup ( gpointer _obj_p )
674 {
675  monobj_t *obj_p = _obj_p;
676  free ( obj_p->name );
677  free ( obj_p );
678  return;
679 }
680 
681 gpointer monobj_dup ( gpointer _obj_p )
682 {
683  monobj_t *src = _obj_p, *dst;
684  dst = xmalloc ( sizeof ( *src ) );
685  memcpy ( dst, src, sizeof ( *src ) );
686  dst->name = xmalloc ( src->name_len + 2 );
687  memcpy ( dst->name, src->name, src->name_len + 1 );
688  dst->origin = src;
689  return dst;
690 }
691 
692 gboolean unmarkdupchild ( gpointer _obj_p, gpointer value, gpointer _ctx_p )
693 {
694  monobj_t *dupobj_p = _obj_p;
695  monobj_t *obj_p = dupobj_p->origin;
696 // ctx_t *ctx_p = _ctx_p;
697  unmarkchild ( obj_p );
698  return FALSE;
699 }
700 
702 {
703  DIR *dir;
704  GTree *children_tree_dup;
705  struct dirent *entry;
706  struct kqueue_data *dat = ctx_p->fsmondata;
707  debug ( 8, "obj_p == %p; obj_p->dir_fd == %i", obj_p, obj_p->dir_fd );
708  debug ( 20, "open*()-ing the directory" );
709  int fd;
710 
711  if ( obj_p->dir_fd == -1 )
712  fd = open ( ctx_p->watchdir, O_RDONLY | O_PATH );
713  else
714  fd = openat ( obj_p->dir_fd, obj_p->name, O_RDONLY | O_PATH );
715 
716  debug ( 20, "fdopendir()-ing the directory" );
717  dir = fdopendir ( fd );
718 
719  if ( dir == NULL ) {
720  debug ( 20, "dir == NULL. return 0" );
721  return 0;
722  }
723 
724  debug ( 20, "tdup()-ing the children_tree == %p", obj_p->children_tree );
725  children_tree_dup = g_tree_dup ( obj_p->children_tree, monobj_filecmp, ctx_p, monobj_freedup, NULL, monobj_dup, NULL );
726  debug ( 8, "children_count == %i", g_tree_nnodes ( children_tree_dup ) );
727  debug ( 20, "reading the directory" );
728 
729  while ( ( entry = readdir ( dir ) ) ) {
730  debug ( 10, "file/dir: \"%s\"", entry->d_name );
731 
732  if ( !memcmp ( entry->d_name, ".", 2 ) )
733  continue;
734 
735  if ( !memcmp ( entry->d_name, "..", 3 ) )
736  continue;
737 
738  if ( _kqueue_handle_oneevent_dircontent_item ( dat, ctx_p, indexes_p, obj_p, entry, children_tree_dup ) ) {
739  error ( "Got error while _kqueue_handle_oneevent_dircontent_item(ctx_p, obj_p, entry {->d_name == \"%s\"})", entry->d_name );
740  return -1;
741  }
742  }
743 
744  debug ( 20, "searching for deleted objects from the directory" );
745  g_tree_foreach ( children_tree_dup, unmarkdupchild, ctx_p );
746  g_tree_destroy ( children_tree_dup );
747  debug ( 20, "end" );
748  closedir ( dir );
749  return 0;
750 }
751 
752 int kqueue_handle_oneevent ( ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p )
753 {
754 #ifdef VERYPARANOID
755 
756  if ( ev_p == NULL ) {
757  errno = EINVAL;
758  return -1;
759  }
760 
761  if ( obj_p == NULL ) {
762  errno = EINVAL;
763  return -1;
764  }
765 
766 #endif
767  debug ( 9, "obj_p->: name == \"%s\"; dir_fd == %i; type == 0x%x (isdir == %i); fd = %i. ev_p->fflags == 0x%x", obj_p->name, obj_p->dir_fd, obj_p->type, obj_p->type == DT_DIR, obj_p->fd, ev_p->fflags );
768  int ret = 0;
769 
770  if ( obj_p->type == DT_DIR && ( ev_p->fflags & ( NOTE_EXTEND | NOTE_WRITE ) ) )
771  ret |= _kqueue_handle_oneevent_dircontent ( ctx_p, indexes_p, obj_p );
772 
773  if ( ev_p->fflags & ( NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB | NOTE_DELETE | NOTE_RENAME ) )
774  ret |= kqueue_sync ( ctx_p, indexes_p, ev_p, obj_p );
775 
776  if ( ev_p->fflags & NOTE_DELETE )
777  ret |= kqueue_unmark ( ctx_p, obj_p );
778 
779  return ret;
780 }
781 
782 int kqueue_handle ( ctx_t *ctx_p, indexes_t *indexes_p )
783 {
784  static struct timeval tv = {0};
785  struct kqueue_data *dat = ctx_p->fsmondata;
786  debug ( 3, "dat->eventlist_count == %i", dat->eventlist_count );
787 
788  if ( dat->eventlist_count == 0 )
789  return 0;
790 
791  int count = 0;
792 
793  do {
794  int i = 0;
795 #ifdef PARANOID
796  g_hash_table_remove_all ( indexes_p->fpath2ei_ht );
797 #endif
798 
799  while ( i < dat->eventlist_count ) {
800  struct kevent *ev_p = &dat->eventlist[i++];
801  monobj_t obj;
802  obj.fd = ev_p->ident;
803  monobj_t *obj_p = g_tree_lookup ( dat->fd_btree, &obj );
804 
805  if ( obj_p == NULL ) {
806  debug ( 3, "Cannot find internal structure for fd == %u. Skipping the event.", ev_p->ident );
807  continue;
808  }
809 
810  if ( kqueue_handle_oneevent ( ctx_p, indexes_p, ev_p, obj_p ) ) {
811  error ( "Got error from kqueue_handle_oneevent()" );
812  return -1;
813  }
814 
815  count++;
816  }
817 
818  // Globally queueing captured events:
819  // Moving events from local queue to global ones
820  sync_prequeue_unload ( ctx_p, indexes_p );
821  dat->eventlist_count = 0;
822  } while ( kqueue_wait ( ctx_p, indexes_p, &tv ) );
823 
824  return count;
825 }
826 
828 {
830  struct kqueue_data *dat = ctx_p->fsmondata;
831  debug ( 3, "dat->eventlist_count == %i", dat->eventlist_count );
832  g_tree_destroy ( dat->file_btree );
833  g_tree_destroy ( dat->fd_btree );
835  return 0;
836 }
837 
monobj_freedup
void monobj_freedup(gpointer _obj_p)
Definition: mon_kqueue.c:673
recognize_event_return::u
union recognize_event_return::@6 u
recognize_event_return::v
struct recognize_event_return::@6::@7 v
sync_prequeue_unload
int sync_prequeue_unload(ctx_t *ctx_p, indexes_t *indexes_p)
Definition: sync.c:2564
unmarkchild_for_foreach
gboolean unmarkchild_for_foreach(gpointer _obj_p, gpointer _value, gpointer _ctx_p)
Definition: mon_kqueue.c:125
ctx
Definition: ctx.h:315
KQUEUE_STATUS_DEAD
@ KQUEUE_STATUS_DEAD
Definition: mon_kqueue.c:36
close
close(fd_w)
ALLOC_PORTION
#define ALLOC_PORTION
Definition: configuration.h:117
kqueue_data::file_btree
GTree * file_btree
Definition: mon_kqueue.c:71
kqueue_init
int kqueue_init(ctx_t *_ctx_p)
Definition: mon_kqueue.c:200
monobj_filecmp
static gint monobj_filecmp(gconstpointer _a, gconstpointer _b, gpointer _ctx_p)
Definition: mon_kqueue.c:159
sync.h
EOT_DOESNTEXIST
@ EOT_DOESNTEXIST
Definition: clsync.h:31
monobj::type
unsigned char type
Definition: mon_kqueue.c:48
kqueue_data::kqueue_d
int kqueue_d
Definition: mon_kqueue.c:63
eventobjtype_t
enum eventobjtype eventobjtype_t
Definition: clsync.h:37
_kqueue_handle_oneevent_dircontent
int _kqueue_handle_oneevent_dircontent(ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *obj_p)
Definition: mon_kqueue.c:701
ctx::fsmondata
void * fsmondata
Definition: ctx.h:419
kqueue_getpath
char * kqueue_getpath(ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *obj_p)
Definition: mon_kqueue.c:549
recognize_event_return
Definition: mon_bsm.c:61
sync_prequeue_loadmark
int sync_prequeue_loadmark(int monitored, ctx_t *ctx_p, indexes_t *indexes_p, const char *path_full, const char *path_rel, stat64_t *lst_p, eventobjtype_t objtype_old, eventobjtype_t objtype_new, uint32_t event_mask, int event_wd, mode_t st_mode, off_t st_size, char **path_buf_p, size_t *path_buf_len_p, eventinfo_t *evinfo)
Definition: sync.c:2143
glibex.h
monobj::fd
int fd
Definition: mon_kqueue.c:43
indexes
Definition: indexes.h:34
kqueue_data::eventlist
struct kevent eventlist[256]
Definition: mon_kqueue.c:68
kqueue_data::fd_btree
GTree * fd_btree
Definition: mon_kqueue.c:72
kqueue_wait
int kqueue_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
Definition: mon_kqueue.c:532
kqueue_add_watch_dir
int kqueue_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
Definition: mon_kqueue.c:491
fileutils.h
monobj::name_len
size_t name_len
Definition: mon_kqueue.c:46
event
Definition: mon_gio.c:41
unmarkdupchild
gboolean unmarkdupchild(gpointer _obj_p, gpointer value, gpointer _ctx_p)
Definition: mon_kqueue.c:692
ctx::flags
int flags[(1<< 10)]
Definition: ctx.h:338
adler32_calc
uint32_t adler32_calc(const unsigned char *const data, uint32_t len)
Calculated Adler32 value for char array.
Definition: calc.c:41
CSC_MON_STAT
@ CSC_MON_STAT
Definition: ctx.h:310
unmarkchild
void unmarkchild(gpointer _obj_p)
Definition: mon_kqueue.c:113
kqueue_add_watch_direntry
monobj_t * kqueue_add_watch_direntry(ctx_t *ctx_p, indexes_t *indexes_p, struct dirent *entry, monobj_t *dir_obj_p)
Definition: mon_kqueue.c:383
monobj_free
void monobj_free(void *monobj_p)
Definition: mon_kqueue.c:131
recognize_event_return::objtype_new
eventobjtype_t objtype_new
Definition: mon_bsm.c:64
kqueue_handle_oneevent
int kqueue_handle_oneevent(ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p)
Definition: mon_kqueue.c:752
CANCEL_SYSCALLS
@ CANCEL_SYSCALLS
Definition: ctx.h:128
calc.h
recognize_event_return::i
uint32_t i
Definition: mon_kqueue.c:81
monobj::parent
struct monobj * parent
Definition: mon_kqueue.c:50
kqueue_data::changelist_used
size_t changelist_used
Definition: mon_kqueue.c:67
kqueue_data
Definition: mon_kqueue.c:62
KQUEUE_EVENTLISTSIZE
#define KQUEUE_EVENTLISTSIZE
Definition: configuration.h:133
error
#define error(...)
Definition: error.h:36
indexes.h
monobj::origin
struct monobj * origin
Definition: mon_kqueue.c:57
error.h
kqueue_mark
int kqueue_mark(ctx_t *ctx_p, monobj_t *obj_p)
Definition: mon_kqueue.c:220
monobj_fdcmp
static int monobj_fdcmp(gconstpointer a, gconstpointer b, gpointer _ctx_p)
Definition: mon_kqueue.c:195
debug
#define debug(debug_level,...)
Definition: error.h:50
mon_kqueue.h
child_free
void child_free(monobj_t *node)
Definition: mon_kqueue.c:275
KQUEUE_STATUS_UNKNOWN
@ KQUEUE_STATUS_UNKNOWN
Definition: mon_kqueue.c:33
monobj::name_hash
uint32_t name_hash
Definition: mon_kqueue.c:47
KQUEUE_STATUS_RUNNING
@ KQUEUE_STATUS_RUNNING
Definition: mon_kqueue.c:34
kqueue_status
kqueue_status
Definition: mon_kqueue.c:32
kqueue_data::obj_p_by_clid
monobj_t ** obj_p_by_clid
Definition: mon_kqueue.c:70
kqueue_handle
int kqueue_handle(ctx_t *ctx_p, indexes_t *indexes_p)
Definition: mon_kqueue.c:782
recognize_event_return::objtype_old
eventobjtype_t objtype_old
Definition: mon_bsm.c:63
common.h
ctx::watchdir
char * watchdir
Definition: ctx.h:345
kqueue_start_watch
monobj_t * kqueue_start_watch(ctx_t *ctx_p, ino_t inode, dev_t device, int dir_fd, const char *const fname, size_t name_len, unsigned char type)
Definition: mon_kqueue.c:325
monobj::device
dev_t device
Definition: mon_kqueue.c:42
monobj::children_tree
GTree * children_tree
Definition: mon_kqueue.c:55
kqueue_deinit
int kqueue_deinit(ctx_t *ctx_p)
Definition: mon_kqueue.c:827
mondata
Definition: mon_bsm.c:40
recognize_event
static uint32_t recognize_event(uint32_t event, int is_dir)
Definition: mon_kqueue.c:88
kqueue_add_watch_path
monobj_t * kqueue_add_watch_path(ctx_t *ctx_p, indexes_t *indexes_p, const char *const path)
Definition: mon_kqueue.c:414
monobj
Definition: mon_kqueue.c:40
kqueue_data::changelist_alloced
size_t changelist_alloced
Definition: mon_kqueue.c:66
monobj::inode
ino_t inode
Definition: mon_kqueue.c:41
kqueue_data::changelist
struct kevent * changelist
Definition: mon_kqueue.c:65
stat64_t
struct stat64 stat64_t
Definition: port-hacks.h:65
kqueue_data::eventlist_count
size_t eventlist_count
Definition: mon_kqueue.c:69
monobj::name
char * name
Definition: mon_kqueue.c:45
ctx::st_dev
dev_t st_dev
Definition: ctx.h:335
indexes::fpath2ei_ht
GHashTable * fpath2ei_ht
Definition: indexes.h:37
critical_on
#define critical_on(cond)
Definition: error.h:33
monobj::changelist_id
size_t changelist_id
Definition: mon_kqueue.c:49
EOT_FILE
@ EOT_FILE
Definition: clsync.h:32
KQUEUE_STATUS_DEINIT
@ KQUEUE_STATUS_DEINIT
Definition: mon_kqueue.c:35
monobj::dir_fd
int dir_fd
Definition: mon_kqueue.c:44
EOT_DIR
@ EOT_DIR
Definition: clsync.h:33
kqueue_unmark
int kqueue_unmark(ctx_t *ctx_p, monobj_t *obj_p)
Definition: mon_kqueue.c:279
ctx_p
ctx_t * ctx_p
Definition: mon_kqueue.c:85
monobj_dup
gpointer monobj_dup(gpointer _obj_p)
Definition: mon_kqueue.c:681
g_tree_dup
GTree * g_tree_dup(GTree *src, GCompareDataFunc key_compare_func, gpointer key_compare_data, GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func, GDupFunc key_dup_funct, GDupFunc value_dup_funct)
Definition: glibex.c:62
kqueue_sync
int kqueue_sync(ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p)
Definition: mon_kqueue.c:591
_kqueue_handle_oneevent_dircontent_item
static int _kqueue_handle_oneevent_dircontent_item(struct kqueue_data *dat, ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *dir_obj_p, struct dirent *entry, void *children_notfound)
Definition: mon_kqueue.c:634