1/*
2   Copyright (C) 2005 John McCutchan
3
4   The Gnome Library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Library General Public License as
6   published by the Free Software Foundation; either version 2 of the
7   License, or (at your option) any later version.
8
9   The Gnome Library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Library General Public License for more details.
13
14   You should have received a copy of the GNU Library General Public
15   License along with the Gnome Library; see the file COPYING.LIB.  If not,
16   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17   Boston, MA 02111-1307, USA.
18
19   Authors:.
20		John McCutchan <john@johnmccutchan.com>
21*/
22
23#include "config.h"
24
25#include <stdio.h>
26#include <sys/ioctl.h>
27#include <unistd.h>
28#include <errno.h>
29#include <string.h>
30#include <glib.h>
31#include "inotify-kernel.h"
32#include <sys/inotify.h>
33
34/* Timings for pairing MOVED_TO / MOVED_FROM events */
35#define PROCESS_EVENTS_TIME 1000 /* milliseconds (1 hz) */
36#define DEFAULT_HOLD_UNTIL_TIME 0 /* 0 millisecond */
37#define MOVE_HOLD_UNTIL_TIME 0 /* 0 milliseconds */
38
39static int inotify_instance_fd = -1;
40static GQueue *events_to_process = NULL;
41static GQueue *event_queue = NULL;
42static GHashTable * cookie_hash = NULL;
43static GIOChannel *inotify_read_ioc;
44static GPollFD ik_poll_fd;
45static gboolean ik_poll_fd_enabled = TRUE;
46static void (*user_cb)(ik_event_t *event);
47
48static gboolean ik_read_callback (gpointer user_data);
49static gboolean ik_process_eq_callback (gpointer user_data);
50
51static guint32 ik_move_matches = 0;
52static guint32 ik_move_misses = 0;
53
54static gboolean process_eq_running = FALSE;
55
56/* We use the lock from inotify-helper.c
57 *
58 * There are two places that we take this lock
59 *
60 * 1) In ik_read_callback
61 *
62 * 2) ik_process_eq_callback.
63 *
64 *
65 * The rest of locking is taken care of in inotify-helper.c
66 */
67G_LOCK_EXTERN (inotify_lock);
68
69typedef struct ik_event_internal {
70  ik_event_t *event;
71  gboolean seen;
72  gboolean sent;
73  GTimeVal hold_until;
74  struct ik_event_internal *pair;
75} ik_event_internal_t;
76
77/* In order to perform non-sleeping inotify event chunking we need
78 * a custom GSource
79 */
80static gboolean
81ik_source_prepare (GSource *source,
82		   gint    *timeout)
83{
84  return FALSE;
85}
86
87static gboolean
88ik_source_timeout (gpointer data)
89{
90  GSource *source = (GSource *)data;
91
92  /* Re-active the PollFD */
93  g_source_add_poll (source, &ik_poll_fd);
94  g_source_unref (source);
95  ik_poll_fd_enabled = TRUE;
96
97  return FALSE;
98}
99
100#define MAX_PENDING_COUNT 2
101#define PENDING_THRESHOLD(qsize) ((qsize) >> 1)
102#define PENDING_MARGINAL_COST(p) ((unsigned int)(1 << (p)))
103#define MAX_QUEUED_EVENTS 2048
104#define AVERAGE_EVENT_SIZE sizeof (struct inotify_event) + 16
105#define TIMEOUT_MILLISECONDS 10
106
107static gboolean
108ik_source_check (GSource *source)
109{
110  static int prev_pending = 0, pending_count = 0;
111
112  /* We already disabled the PollFD or
113   * nothing to be read from inotify */
114  if (!ik_poll_fd_enabled || !(ik_poll_fd.revents & G_IO_IN))
115    return FALSE;
116
117  if (pending_count < MAX_PENDING_COUNT)
118    {
119      unsigned int pending;
120
121      if (ioctl (inotify_instance_fd, FIONREAD, &pending) == -1)
122	goto do_read;
123
124      pending /= AVERAGE_EVENT_SIZE;
125
126      /* Don't wait if the number of pending events is too close
127       * to the maximum queue size.
128       */
129      if (pending > PENDING_THRESHOLD (MAX_QUEUED_EVENTS))
130	goto do_read;
131
132      /* With each successive iteration, the minimum rate for
133       * further sleep doubles.
134       */
135      if (pending-prev_pending < PENDING_MARGINAL_COST (pending_count))
136	goto do_read;
137
138      prev_pending = pending;
139      pending_count++;
140
141      /* We are going to wait to read the events: */
142
143      /* Remove the PollFD from the source */
144      g_source_remove_poll (source, &ik_poll_fd);
145      /* To avoid threading issues we need to flag that we've done that */
146      ik_poll_fd_enabled = FALSE;
147      /* Set a timeout to re-add the PollFD to the source */
148      g_source_ref (source);
149      g_timeout_add (TIMEOUT_MILLISECONDS, ik_source_timeout, source);
150
151      return FALSE;
152    }
153
154do_read:
155  /* We are ready to read events from inotify */
156
157  prev_pending = 0;
158  pending_count = 0;
159
160  return TRUE;
161}
162
163static gboolean
164ik_source_dispatch (GSource     *source,
165		    GSourceFunc  callback,
166		    gpointer     user_data)
167{
168  if (callback)
169    return callback (user_data);
170  return TRUE;
171}
172
173static GSourceFuncs ik_source_funcs =
174{
175  ik_source_prepare,
176  ik_source_check,
177  ik_source_dispatch,
178  NULL
179};
180
181gboolean _ik_startup (void (*cb)(ik_event_t *event))
182{
183  static gboolean initialized = FALSE;
184  GSource *source;
185
186  user_cb = cb;
187  /* Ignore multi-calls */
188  if (initialized)
189    return inotify_instance_fd >= 0;
190
191  initialized = TRUE;
192  inotify_instance_fd = inotify_init ();
193
194  if (inotify_instance_fd < 0)
195    return FALSE;
196
197  inotify_read_ioc = g_io_channel_unix_new (inotify_instance_fd);
198  ik_poll_fd.fd = inotify_instance_fd;
199  ik_poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
200  g_io_channel_set_encoding (inotify_read_ioc, NULL, NULL);
201  g_io_channel_set_flags (inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
202
203  source = g_source_new (&ik_source_funcs, sizeof (GSource));
204  g_source_add_poll (source, &ik_poll_fd);
205  g_source_set_callback (source, ik_read_callback, NULL, NULL);
206  g_source_attach (source, NULL);
207  g_source_unref (source);
208
209  cookie_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
210  event_queue = g_queue_new ();
211  events_to_process = g_queue_new ();
212
213  return TRUE;
214}
215
216static ik_event_internal_t *
217ik_event_internal_new (ik_event_t *event)
218{
219  ik_event_internal_t *internal_event = g_new0 (ik_event_internal_t, 1);
220  GTimeVal tv;
221
222  g_assert (event);
223
224  g_get_current_time (&tv);
225  g_time_val_add (&tv, DEFAULT_HOLD_UNTIL_TIME);
226  internal_event->event = event;
227  internal_event->hold_until = tv;
228
229  return internal_event;
230}
231
232static ik_event_t *
233ik_event_new (char *buffer)
234{
235  struct inotify_event *kevent = (struct inotify_event *)buffer;
236  ik_event_t *event = g_new0 (ik_event_t, 1);
237
238  g_assert (buffer);
239
240  event->wd = kevent->wd;
241  event->mask = kevent->mask;
242  event->cookie = kevent->cookie;
243  event->len = kevent->len;
244  if (event->len)
245    event->name = g_strdup (kevent->name);
246  else
247    event->name = g_strdup ("");
248
249  return event;
250}
251
252ik_event_t *
253_ik_event_new_dummy (const char *name,
254                     gint32      wd,
255                     guint32     mask)
256{
257  ik_event_t *event = g_new0 (ik_event_t, 1);
258  event->wd = wd;
259  event->mask = mask;
260  event->cookie = 0;
261  if (name)
262    event->name = g_strdup (name);
263  else
264    event->name = g_strdup("");
265
266  event->len = strlen (event->name);
267
268  return event;
269}
270
271void
272_ik_event_free (ik_event_t *event)
273{
274  if (event->pair)
275    _ik_event_free (event->pair);
276  g_free (event->name);
277  g_free (event);
278}
279
280gint32
281_ik_watch (const char *path,
282           guint32     mask,
283           int        *err)
284{
285  gint32 wd = -1;
286
287  g_assert (path != NULL);
288  g_assert (inotify_instance_fd >= 0);
289
290  wd = inotify_add_watch (inotify_instance_fd, path, mask);
291
292  if (wd < 0)
293    {
294      int e = errno;
295      /* FIXME: debug msg failed to add watch */
296      if (err)
297	*err = e;
298      return wd;
299    }
300
301  g_assert (wd >= 0);
302  return wd;
303}
304
305int
306_ik_ignore (const char *path,
307            gint32      wd)
308{
309  g_assert (wd >= 0);
310  g_assert (inotify_instance_fd >= 0);
311
312  if (inotify_rm_watch (inotify_instance_fd, wd) < 0)
313    {
314      /* int e = errno; */
315      /* failed to rm watch */
316      return -1;
317    }
318
319  return 0;
320}
321
322void
323_ik_move_stats (guint32 *matches,
324                guint32 *misses)
325{
326  if (matches)
327    *matches = ik_move_matches;
328
329  if (misses)
330    *misses = ik_move_misses;
331}
332
333const char *
334_ik_mask_to_string (guint32 mask)
335{
336  gboolean is_dir = mask & IN_ISDIR;
337  mask &= ~IN_ISDIR;
338
339  if (is_dir)
340    {
341      switch (mask)
342	{
343	case IN_ACCESS:
344	  return "ACCESS (dir)";
345	case IN_MODIFY:
346	  return "MODIFY (dir)";
347	case IN_ATTRIB:
348	  return "ATTRIB (dir)";
349	case IN_CLOSE_WRITE:
350	  return "CLOSE_WRITE (dir)";
351	case IN_CLOSE_NOWRITE:
352	  return "CLOSE_NOWRITE (dir)";
353	case IN_OPEN:
354	  return "OPEN (dir)";
355	case IN_MOVED_FROM:
356	  return "MOVED_FROM (dir)";
357	case IN_MOVED_TO:
358	  return "MOVED_TO (dir)";
359	case IN_DELETE:
360	  return "DELETE (dir)";
361	case IN_CREATE:
362	  return "CREATE (dir)";
363	case IN_DELETE_SELF:
364	  return "DELETE_SELF (dir)";
365	case IN_UNMOUNT:
366	  return "UNMOUNT (dir)";
367	case IN_Q_OVERFLOW:
368	  return "Q_OVERFLOW (dir)";
369	case IN_IGNORED:
370	  return "IGNORED (dir)";
371	default:
372	  return "UNKNOWN_EVENT (dir)";
373	}
374    }
375  else
376    {
377      switch (mask)
378	{
379	case IN_ACCESS:
380	  return "ACCESS";
381	case IN_MODIFY:
382	  return "MODIFY";
383	case IN_ATTRIB:
384	  return "ATTRIB";
385	case IN_CLOSE_WRITE:
386	  return "CLOSE_WRITE";
387	case IN_CLOSE_NOWRITE:
388	  return "CLOSE_NOWRITE";
389	case IN_OPEN:
390	  return "OPEN";
391	case IN_MOVED_FROM:
392	  return "MOVED_FROM";
393	case IN_MOVED_TO:
394	  return "MOVED_TO";
395	case IN_DELETE:
396	  return "DELETE";
397	case IN_CREATE:
398	  return "CREATE";
399	case IN_DELETE_SELF:
400	  return "DELETE_SELF";
401	case IN_UNMOUNT:
402	  return "UNMOUNT";
403	case IN_Q_OVERFLOW:
404	  return "Q_OVERFLOW";
405	case IN_IGNORED:
406	  return "IGNORED";
407	default:
408	  return "UNKNOWN_EVENT";
409	}
410    }
411}
412
413
414static void
415ik_read_events (gsize  *buffer_size_out,
416                gchar **buffer_out)
417{
418  static gchar *buffer = NULL;
419  static gsize buffer_size;
420
421  /* Initialize the buffer on our first call */
422  if (buffer == NULL)
423    {
424      buffer_size = AVERAGE_EVENT_SIZE;
425      buffer_size *= MAX_QUEUED_EVENTS;
426      buffer = g_malloc (buffer_size);
427    }
428
429  *buffer_size_out = 0;
430  *buffer_out = NULL;
431
432  memset (buffer, 0, buffer_size);
433
434  if (g_io_channel_read_chars (inotify_read_ioc, (char *)buffer, buffer_size, buffer_size_out, NULL) != G_IO_STATUS_NORMAL) {
435    /* error reading */
436  }
437  *buffer_out = buffer;
438}
439
440static gboolean
441ik_read_callback (gpointer user_data)
442{
443  gchar *buffer;
444  gsize buffer_size, buffer_i, events;
445
446  G_LOCK (inotify_lock);
447  ik_read_events (&buffer_size, &buffer);
448
449  buffer_i = 0;
450  events = 0;
451  while (buffer_i < buffer_size)
452    {
453      struct inotify_event *event;
454      gsize event_size;
455      event = (struct inotify_event *)&buffer[buffer_i];
456      event_size = sizeof(struct inotify_event) + event->len;
457      g_queue_push_tail (events_to_process, ik_event_internal_new (ik_event_new (&buffer[buffer_i])));
458      buffer_i += event_size;
459      events++;
460    }
461
462  /* If the event process callback is off, turn it back on */
463  if (!process_eq_running && events)
464    {
465      process_eq_running = TRUE;
466      g_timeout_add (PROCESS_EVENTS_TIME, ik_process_eq_callback, NULL);
467    }
468
469  G_UNLOCK (inotify_lock);
470
471  return TRUE;
472}
473
474static gboolean
475g_timeval_lt (GTimeVal *val1,
476              GTimeVal *val2)
477{
478  if (val1->tv_sec < val2->tv_sec)
479    return TRUE;
480
481  if (val1->tv_sec > val2->tv_sec)
482    return FALSE;
483
484  /* val1->tv_sec == val2->tv_sec */
485  if (val1->tv_usec < val2->tv_usec)
486    return TRUE;
487
488  return FALSE;
489}
490
491static gboolean
492g_timeval_eq (GTimeVal *val1,
493              GTimeVal *val2)
494{
495  return (val1->tv_sec == val2->tv_sec) && (val1->tv_usec == val2->tv_usec);
496}
497
498static void
499ik_pair_events (ik_event_internal_t *event1,
500                ik_event_internal_t *event2)
501{
502  g_assert (event1 && event2);
503  /* We should only be pairing events that have the same cookie */
504  g_assert (event1->event->cookie == event2->event->cookie);
505  /* We shouldn't pair an event that already is paired */
506  g_assert (event1->pair == NULL && event2->pair == NULL);
507
508  /* Pair the internal structures and the ik_event_t structures */
509  event1->pair = event2;
510  event1->event->pair = event2->event;
511
512  if (g_timeval_lt (&event1->hold_until, &event2->hold_until))
513    event1->hold_until = event2->hold_until;
514
515  event2->hold_until = event1->hold_until;
516}
517
518static void
519ik_event_add_microseconds (ik_event_internal_t *event,
520                           glong                ms)
521{
522  g_assert (event);
523  g_time_val_add (&event->hold_until, ms);
524}
525
526static gboolean
527ik_event_ready (ik_event_internal_t *event)
528{
529  GTimeVal tv;
530  g_assert (event);
531
532  g_get_current_time (&tv);
533
534  /* An event is ready if,
535   *
536   * it has no cookie -- there is nothing to be gained by holding it
537   * or, it is already paired -- we don't need to hold it anymore
538   * or, we have held it long enough
539   */
540  return
541    event->event->cookie == 0 ||
542    event->pair != NULL ||
543    g_timeval_lt (&event->hold_until, &tv) ||
544    g_timeval_eq (&event->hold_until, &tv);
545}
546
547static void
548ik_pair_moves (gpointer data,
549               gpointer user_data)
550{
551  ik_event_internal_t *event = (ik_event_internal_t *)data;
552
553  if (event->seen == TRUE || event->sent == TRUE)
554    return;
555
556  if (event->event->cookie != 0)
557    {
558      /* When we get a MOVED_FROM event we delay sending the event by
559       * MOVE_HOLD_UNTIL_TIME microseconds. We need to do this because a
560       * MOVED_TO pair _might_ be coming in the near future */
561      if (event->event->mask & IN_MOVED_FROM)
562	{
563	  g_hash_table_insert (cookie_hash, GINT_TO_POINTER (event->event->cookie), event);
564	  /* because we don't deliver move events there is no point in waiting for the match right now. */
565	  ik_event_add_microseconds (event, MOVE_HOLD_UNTIL_TIME);
566	}
567      else if (event->event->mask & IN_MOVED_TO)
568	{
569	  /* We need to check if we are waiting for this MOVED_TO events cookie to pair it with
570	   * a MOVED_FROM */
571	  ik_event_internal_t *match = NULL;
572	  match = g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie));
573	  if (match)
574	    {
575	      g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie));
576	      ik_pair_events (match, event);
577	    }
578	}
579    }
580  event->seen = TRUE;
581}
582
583static void
584ik_process_events (void)
585{
586  g_queue_foreach (events_to_process, ik_pair_moves, NULL);
587
588  while (!g_queue_is_empty (events_to_process))
589    {
590      ik_event_internal_t *event = g_queue_peek_head (events_to_process);
591
592      /* This must have been sent as part of a MOVED_TO/MOVED_FROM */
593      if (event->sent)
594	{
595	  /* Pop event */
596	  g_queue_pop_head (events_to_process);
597	  /* Free the internal event structure */
598	  g_free (event);
599	  continue;
600	}
601
602      /* The event isn't ready yet */
603      if (!ik_event_ready (event))
604	break;
605
606      /* Pop it */
607      event = g_queue_pop_head (events_to_process);
608
609      /* Check if this is a MOVED_FROM that is also sitting in the cookie_hash */
610      if (event->event->cookie && event->pair == NULL &&
611	  g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie)))
612	g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie));
613
614      if (event->pair)
615	{
616	  /* We send out paired MOVED_FROM/MOVED_TO events in the same event buffer */
617	  /* g_assert (event->event->mask == IN_MOVED_FROM && event->pair->event->mask == IN_MOVED_TO); */
618	  /* Copy the paired data */
619	  event->pair->sent = TRUE;
620	  event->sent = TRUE;
621	  ik_move_matches++;
622	}
623      else if (event->event->cookie)
624	{
625	  /* If we couldn't pair a MOVED_FROM and MOVED_TO together, we change
626	   * the event masks */
627	  /* Changeing MOVED_FROM to DELETE and MOVED_TO to create lets us make
628	   * the gaurantee that you will never see a non-matched MOVE event */
629
630	  if (event->event->mask & IN_MOVED_FROM)
631	    {
632	      event->event->mask = IN_DELETE|(event->event->mask & IN_ISDIR);
633	      ik_move_misses++; /* not super accurate, if we aren't watching the destination it still counts as a miss */
634	    }
635	  if (event->event->mask & IN_MOVED_TO)
636	    event->event->mask = IN_CREATE|(event->event->mask & IN_ISDIR);
637	}
638
639      /* Push the ik_event_t onto the event queue */
640      g_queue_push_tail (event_queue, event->event);
641      /* Free the internal event structure */
642      g_free (event);
643    }
644}
645
646static gboolean
647ik_process_eq_callback (gpointer user_data)
648{
649  gboolean res;
650
651  /* Try and move as many events to the event queue */
652  G_LOCK (inotify_lock);
653  ik_process_events ();
654
655  while (!g_queue_is_empty (event_queue))
656    {
657      ik_event_t *event = g_queue_pop_head (event_queue);
658
659      user_cb (event);
660    }
661
662  res = TRUE;
663
664  if (g_queue_get_length (events_to_process) == 0)
665    {
666      process_eq_running = FALSE;
667      res = FALSE;
668    }
669
670  G_UNLOCK (inotify_lock);
671
672  return res;
673}
674