clsync
Loading...
Searching...
No Matches
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
39
40struct 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;
50 struct monobj *parent;
51
52 // Case specific stuff
53 union {
54 // For directories only, for original (not dupes) obj_p only
56 // For duplicates only, see _kqueue_handle_oneevent_dircontent()
57 struct monobj *origin;
58 };
59};
60typedef struct monobj monobj_t;
61
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
86indexes_t *indexes_p;
87
88static 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 )
103
104 if ( is_deleted )
106
107 return r.u.i;
108}
109
110extern int kqueue_sync ( ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p );
111extern int kqueue_unmark ( ctx_t *ctx_p, monobj_t *obj_p );
112
113void 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}
125gboolean unmarkchild_for_foreach ( gpointer _obj_p, gpointer _value, gpointer _ctx_p )
126{
127 unmarkchild ( _obj_p );
128 return FALSE;
129}
130
131void 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
159static 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
195static int monobj_fdcmp ( gconstpointer a, gconstpointer b, gpointer _ctx_p )
196{
197 return ( ( monobj_t * ) a )->fd - ( ( monobj_t * ) b )->fd;
198}
199
200int 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
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
275void 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 ];
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
325monobj_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
383monobj_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
414monobj_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
491int 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
532int 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!
549char *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
591int 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
634static 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
673void 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
681gpointer 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
692gboolean 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
752int 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
782int 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
uint32_t adler32_calc(const unsigned char *const data, uint32_t len)
Calculated Adler32 value for char array.
Definition calc.c:41
enum eventobjtype eventobjtype_t
Definition clsync.h:37
@ EOT_DIR
Definition clsync.h:33
@ EOT_DOESNTEXIST
Definition clsync.h:31
@ EOT_FILE
Definition clsync.h:32
#define KQUEUE_EVENTLISTSIZE
#define ALLOC_PORTION
@ CANCEL_SYSCALLS
Definition ctx.h:128
@ CSC_MON_STAT
Definition ctx.h:310
#define error(...)
Definition error.h:36
#define debug(debug_level,...)
Definition error.h:50
#define critical_on(cond)
Definition error.h:33
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
gpointer monobj_dup(gpointer _obj_p)
Definition mon_kqueue.c:681
int kqueue_mark(ctx_t *ctx_p, monobj_t *obj_p)
Definition mon_kqueue.c:220
static int monobj_fdcmp(gconstpointer a, gconstpointer b, gpointer _ctx_p)
Definition mon_kqueue.c:195
void child_free(monobj_t *node)
Definition mon_kqueue.c:275
void monobj_freedup(gpointer _obj_p)
Definition mon_kqueue.c:673
static uint32_t recognize_event(uint32_t event, int is_dir)
Definition mon_kqueue.c:88
kqueue_status
Definition mon_kqueue.c:32
@ KQUEUE_STATUS_UNKNOWN
Definition mon_kqueue.c:33
@ KQUEUE_STATUS_DEAD
Definition mon_kqueue.c:36
@ KQUEUE_STATUS_RUNNING
Definition mon_kqueue.c:34
@ KQUEUE_STATUS_DEINIT
Definition mon_kqueue.c:35
monobj_t * kqueue_add_watch_path(ctx_t *ctx_p, indexes_t *indexes_p, const char *const path)
Definition mon_kqueue.c:414
int _kqueue_handle_oneevent_dircontent(ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *obj_p)
Definition mon_kqueue.c:701
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
int kqueue_sync(ctx_t *ctx_p, indexes_t *indexes_p, struct kevent *ev_p, monobj_t *obj_p)
Definition mon_kqueue.c:591
int kqueue_wait(ctx_t *ctx_p, struct indexes *indexes_p, struct timeval *tv_p)
Definition mon_kqueue.c:532
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
void unmarkchild(gpointer _obj_p)
Definition mon_kqueue.c:113
int kqueue_handle(ctx_t *ctx_p, indexes_t *indexes_p)
Definition mon_kqueue.c:782
int kqueue_unmark(ctx_t *ctx_p, monobj_t *obj_p)
Definition mon_kqueue.c:279
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
gboolean unmarkchild_for_foreach(gpointer _obj_p, gpointer _value, gpointer _ctx_p)
Definition mon_kqueue.c:125
int kqueue_deinit(ctx_t *ctx_p)
Definition mon_kqueue.c:827
gboolean unmarkdupchild(gpointer _obj_p, gpointer value, gpointer _ctx_p)
Definition mon_kqueue.c:692
int kqueue_add_watch_dir(ctx_t *ctx_p, indexes_t *indexes_p, const char *const accpath)
Definition mon_kqueue.c:491
char * kqueue_getpath(ctx_t *ctx_p, indexes_t *indexes_p, monobj_t *obj_p)
Definition mon_kqueue.c:549
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
ctx_t * ctx_p
Definition mon_kqueue.c:85
static gint monobj_filecmp(gconstpointer _a, gconstpointer _b, gpointer _ctx_p)
Definition mon_kqueue.c:159
void monobj_free(void *monobj_p)
Definition mon_kqueue.c:131
int kqueue_init()
struct stat64 stat64_t
Definition port-hacks.h:65
Definition ctx.h:315
void * fsmondata
Definition ctx.h:419
char * watchdir
Definition ctx.h:345
dev_t st_dev
Definition ctx.h:335
int flags[(1<< 10)]
Definition ctx.h:338
GHashTable * fpath2ei_ht
Definition indexes.h:37
GTree * fd_btree
Definition mon_kqueue.c:72
size_t eventlist_count
Definition mon_kqueue.c:69
monobj_t ** obj_p_by_clid
Definition mon_kqueue.c:70
size_t changelist_alloced
Definition mon_kqueue.c:66
size_t changelist_used
Definition mon_kqueue.c:67
struct kevent eventlist[256]
Definition mon_kqueue.c:68
GTree * file_btree
Definition mon_kqueue.c:71
struct kevent * changelist
Definition mon_kqueue.c:65
uint32_t name_hash
Definition mon_kqueue.c:47
char * name
Definition mon_kqueue.c:45
unsigned char type
Definition mon_kqueue.c:48
struct monobj * parent
Definition mon_kqueue.c:50
ino_t inode
Definition mon_kqueue.c:41
GTree * children_tree
Definition mon_kqueue.c:55
int dir_fd
Definition mon_kqueue.c:44
size_t name_len
Definition mon_kqueue.c:46
struct monobj * origin
Definition mon_kqueue.c:57
size_t changelist_id
Definition mon_kqueue.c:49
int fd
Definition mon_kqueue.c:43
dev_t device
Definition mon_kqueue.c:42
union recognize_event_return::@6 u
eventobjtype_t objtype_old
Definition mon_bsm.c:63
eventobjtype_t objtype_new
Definition mon_bsm.c:64
struct recognize_event_return::@6::@7 v
int sync_prequeue_unload(ctx_t *ctx_p, indexes_t *indexes_p)
Definition sync.c:2564
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