Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / glocalfilemonitor.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * SPDX-License-Identifier: LGPL-2.1-or-later
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include "gioenumtypes.h"
26 #include "glocalfilemonitor.h"
27 #include "giomodule-priv.h"
28 #include "gioerror.h"
29 #include "glibintl.h"
30 #include "glocalfile.h"
31 #include "glib-private.h"
32
33 #include <string.h>
34
35 #define DEFAULT_RATE_LIMIT                           800 * G_TIME_SPAN_MILLISECOND
36 #define VIRTUAL_CHANGES_DONE_DELAY                     2 * G_TIME_SPAN_SECOND
37
38 /* GFileMonitorSource is a GSource responsible for emitting the changed
39  * signals in the owner-context of the GFileMonitor.
40  *
41  * It contains functionality for cross-thread queuing of events.  It
42  * also handles merging of CHANGED events and emission of CHANGES_DONE
43  * events.
44  *
45  * We use the "priv" pointer in the external struct to store it.
46  */
47 struct _GFileMonitorSource {
48   GSource       source;
49
50   GMutex        lock;
51   GWeakRef      instance_ref;
52   GFileMonitorFlags flags;
53   gchar        *dirname;
54   gchar        *basename;
55   gchar        *filename;
56   GSequence    *pending_changes; /* sorted by ready time */
57   GHashTable   *pending_changes_table;
58   GQueue        event_queue;
59   gint64        rate_limit;
60 };
61
62 /* PendingChange is a struct to keep track of a file that needs to have
63  * (at least) a CHANGES_DONE_HINT event sent for it in the near future.
64  *
65  * If 'dirty' is TRUE then a CHANGED event also needs to be sent.
66  *
67  * last_emission is the last time a CHANGED event was emitted.  It is
68  * used to calculate the time to send the next event.
69  */
70 typedef struct {
71   gchar    *child;
72   guint64   last_emission : 63;
73   guint64   dirty         :  1;
74 } PendingChange;
75
76 /* QueuedEvent is a signal that will be sent immediately, as soon as the
77  * source gets a chance to dispatch.  The existence of any queued event
78  * implies that the source is ready now.
79  */
80 typedef struct
81 {
82   GFileMonitorEvent event_type;
83   GFile *child;
84   GFile *other;
85 } QueuedEvent;
86
87 static gint64
88 pending_change_get_ready_time (const PendingChange *change,
89                                GFileMonitorSource  *fms)
90 {
91   if (change->dirty)
92     return change->last_emission + fms->rate_limit;
93   else
94     return change->last_emission + VIRTUAL_CHANGES_DONE_DELAY;
95 }
96
97 static int
98 pending_change_compare_ready_time (gconstpointer a_p,
99                                    gconstpointer b_p,
100                                    gpointer      user_data)
101 {
102   GFileMonitorSource *fms = user_data;
103   const PendingChange *a = a_p;
104   const PendingChange *b = b_p;
105   gint64 ready_time_a;
106   gint64 ready_time_b;
107
108   ready_time_a = pending_change_get_ready_time (a, fms);
109   ready_time_b = pending_change_get_ready_time (b, fms);
110
111   if (ready_time_a < ready_time_b)
112     return -1;
113   else
114     return ready_time_a > ready_time_b;
115 }
116
117 static void
118 pending_change_free (gpointer data)
119 {
120   PendingChange *change = data;
121
122   g_free (change->child);
123
124   g_slice_free (PendingChange, change);
125 }
126
127 static void
128 queued_event_free (QueuedEvent *event)
129 {
130   g_object_unref (event->child);
131   if (event->other)
132     g_object_unref (event->other);
133
134   g_slice_free (QueuedEvent, event);
135 }
136
137 static gint64
138 g_file_monitor_source_get_ready_time (GFileMonitorSource *fms)
139 {
140   GSequenceIter *iter;
141
142   if (fms->event_queue.length)
143     return 0;
144
145   iter = g_sequence_get_begin_iter (fms->pending_changes);
146   if (g_sequence_iter_is_end (iter))
147     return -1;
148
149   return pending_change_get_ready_time (g_sequence_get (iter), fms);
150 }
151
152 static void
153 g_file_monitor_source_update_ready_time (GFileMonitorSource *fms)
154 {
155   g_source_set_ready_time ((GSource *) fms, g_file_monitor_source_get_ready_time (fms));
156 }
157
158 static GSequenceIter *
159 g_file_monitor_source_find_pending_change (GFileMonitorSource *fms,
160                                            const gchar        *child)
161 {
162   return g_hash_table_lookup (fms->pending_changes_table, child);
163 }
164
165 static void
166 g_file_monitor_source_add_pending_change (GFileMonitorSource *fms,
167                                           const gchar        *child,
168                                           gint64              now)
169 {
170   PendingChange *change;
171   GSequenceIter *iter;
172
173   change = g_slice_new (PendingChange);
174   change->child = g_strdup (child);
175   change->last_emission = now;
176   change->dirty = FALSE;
177
178   iter = g_sequence_insert_sorted (fms->pending_changes, change, pending_change_compare_ready_time, fms);
179   g_hash_table_insert (fms->pending_changes_table, change->child, iter);
180 }
181
182 static gboolean
183 g_file_monitor_source_set_pending_change_dirty (GFileMonitorSource *fms,
184                                                 GSequenceIter      *iter)
185 {
186   PendingChange *change;
187
188   change = g_sequence_get (iter);
189
190   /* if it was already dirty then this change is 'uninteresting' */
191   if (change->dirty)
192     return FALSE;
193
194   change->dirty = TRUE;
195
196   g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
197
198   return TRUE;
199 }
200
201 static gboolean
202 g_file_monitor_source_get_pending_change_dirty (GFileMonitorSource *fms,
203                                                 GSequenceIter      *iter)
204 {
205   PendingChange *change;
206
207   change = g_sequence_get (iter);
208
209   return change->dirty;
210 }
211
212 static void
213 g_file_monitor_source_remove_pending_change (GFileMonitorSource *fms,
214                                              GSequenceIter      *iter,
215                                              const gchar        *child)
216 {
217   /* must remove the hash entry first -- its key is owned by the data
218    * which will be freed when removing the sequence iter
219    */
220   g_hash_table_remove (fms->pending_changes_table, child);
221   g_sequence_remove (iter);
222 }
223
224 static void
225 g_file_monitor_source_queue_event (GFileMonitorSource *fms,
226                                    GFileMonitorEvent   event_type,
227                                    const gchar        *child,
228                                    GFile              *other)
229 {
230   QueuedEvent *event;
231
232   event = g_slice_new (QueuedEvent);
233   event->event_type = event_type;
234   if (child != NULL && fms->dirname != NULL)
235     event->child = g_local_file_new_from_dirname_and_basename (fms->dirname, child);
236   else if (child != NULL)
237     {
238       gchar *dirname = g_path_get_dirname (fms->filename);
239       event->child = g_local_file_new_from_dirname_and_basename (dirname, child);
240       g_free (dirname);
241     }
242   else if (fms->dirname)
243     event->child = _g_local_file_new (fms->dirname);
244   else if (fms->filename)
245     event->child = _g_local_file_new (fms->filename);
246   event->other = other;
247   if (other)
248     g_object_ref (other);
249
250   g_queue_push_tail (&fms->event_queue, event);
251 }
252
253 static gboolean
254 g_file_monitor_source_file_changed (GFileMonitorSource *fms,
255                                     const gchar        *child,
256                                     gint64              now)
257 {
258   GSequenceIter *pending;
259   gboolean interesting;
260
261   pending = g_file_monitor_source_find_pending_change (fms, child);
262
263   /* If there is no pending change, emit one and create a record,
264    * else: just mark the existing record as dirty.
265    */
266   if (!pending)
267     {
268       g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
269       g_file_monitor_source_add_pending_change (fms, child, now);
270       interesting = TRUE;
271     }
272   else
273     interesting = g_file_monitor_source_set_pending_change_dirty (fms, pending);
274
275   g_file_monitor_source_update_ready_time (fms);
276
277   return interesting;
278 }
279
280 static void
281 g_file_monitor_source_file_changes_done (GFileMonitorSource *fms,
282                                          const gchar        *child)
283 {
284   GSequenceIter *pending;
285
286   pending = g_file_monitor_source_find_pending_change (fms, child);
287   if (pending)
288     {
289       /* If it is dirty, make sure we push out the last CHANGED event */
290       if (g_file_monitor_source_get_pending_change_dirty (fms, pending))
291         g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, child, NULL);
292
293       g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
294       g_file_monitor_source_remove_pending_change (fms, pending, child);
295     }
296 }
297
298 static void
299 g_file_monitor_source_file_created (GFileMonitorSource *fms,
300                                     const gchar        *child,
301                                     gint64              event_time)
302 {
303   /* Unlikely, but if we have pending changes for this filename, make
304    * sure we flush those out first, before creating the new ones.
305    */
306   g_file_monitor_source_file_changes_done (fms, child);
307
308   /* Emit CREATE and add a pending changes record */
309   g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
310   g_file_monitor_source_add_pending_change (fms, child, event_time);
311 }
312
313 static void
314 g_file_monitor_source_send_event (GFileMonitorSource *fms,
315                                   GFileMonitorEvent   event_type,
316                                   const gchar        *child,
317                                   GFile              *other)
318 {
319   /* always flush any pending changes before we queue a new event */
320   g_file_monitor_source_file_changes_done (fms, child);
321   g_file_monitor_source_queue_event (fms, event_type, child, other);
322 }
323
324 static void
325 g_file_monitor_source_send_synthetic_created (GFileMonitorSource *fms,
326                                               const gchar        *child)
327 {
328   g_file_monitor_source_file_changes_done (fms, child);
329   g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
330   g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
331 }
332
333 #ifndef G_DISABLE_ASSERT
334 static gboolean
335 is_basename (const gchar *name)
336 {
337   if (name[0] == '.' && ((name[1] == '.' && name[2] == '\0') || name[1] == '\0'))
338     return FALSE;
339
340   return !strchr (name, '/');
341 }
342 #endif  /* !G_DISABLE_ASSERT */
343
344 gboolean
345 g_file_monitor_source_handle_event (GFileMonitorSource *fms,
346                                     GFileMonitorEvent   event_type,
347                                     const gchar        *child,
348                                     const gchar        *rename_to,
349                                     GFile              *other,
350                                     gint64              event_time)
351 {
352   gboolean interesting = TRUE;
353
354   g_assert (!child || is_basename (child));
355   g_assert (!rename_to || is_basename (rename_to));
356
357   if (fms->basename && (!child || !g_str_equal (child, fms->basename))
358                     && (!rename_to || !g_str_equal (rename_to, fms->basename)))
359     return TRUE;
360
361   g_mutex_lock (&fms->lock);
362
363   /* NOTE:
364    *
365    * We process events even if the file monitor has already been disposed.
366    * The reason is that we must not take a reference to the instance here as
367    * destroying it from the event handling thread will lead to a deadlock when
368    * taking the lock in _ih_sub_cancel.
369    *
370    * This results in seemingly-unbounded growth of the `event_queue` with the
371    * calls to `g_file_monitor_source_queue_event()`. However, each of those sets
372    * the ready time on the #GSource, which means that it will be dispatched in
373    * a subsequent iteration of the #GMainContext it’s attached to. At that
374    * point, `g_file_monitor_source_dispatch()` will return %FALSE, and this will
375    * trigger finalisation of the source. That will clear the `event_queue`.
376    *
377    * If the source is no longer attached, this will return early to prevent
378    * unbounded queueing.
379    */
380   if (g_source_is_destroyed ((GSource *) fms))
381     {
382       g_mutex_unlock (&fms->lock);
383       return TRUE;
384     }
385
386   switch (event_type)
387     {
388     case G_FILE_MONITOR_EVENT_CREATED:
389       g_assert (!other && !rename_to);
390       g_file_monitor_source_file_created (fms, child, event_time);
391       break;
392
393     case G_FILE_MONITOR_EVENT_CHANGED:
394       g_assert (!other && !rename_to);
395       interesting = g_file_monitor_source_file_changed (fms, child, event_time);
396       break;
397
398     case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
399       g_assert (!other && !rename_to);
400       g_file_monitor_source_file_changes_done (fms, child);
401       break;
402
403     case G_FILE_MONITOR_EVENT_MOVED_IN:
404       g_assert (!rename_to);
405       if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
406         g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_IN, child, other);
407       else
408         g_file_monitor_source_send_synthetic_created (fms, child);
409       break;
410
411     case G_FILE_MONITOR_EVENT_MOVED_OUT:
412       g_assert (!rename_to);
413       if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
414         g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_OUT, child, other);
415       else if (other && (fms->flags & G_FILE_MONITOR_SEND_MOVED))
416         g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED, child, other);
417       else
418         g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
419       break;
420
421     case G_FILE_MONITOR_EVENT_RENAMED:
422       g_assert (!other && rename_to);
423       if (fms->flags & (G_FILE_MONITOR_WATCH_MOVES | G_FILE_MONITOR_SEND_MOVED))
424         {
425           GFile *other_file;
426           const gchar *dirname;
427           gchar *allocated_dirname = NULL;
428           GFileMonitorEvent event;
429
430           event = (fms->flags & G_FILE_MONITOR_WATCH_MOVES) ? G_FILE_MONITOR_EVENT_RENAMED : G_FILE_MONITOR_EVENT_MOVED;
431
432           if (fms->dirname != NULL)
433             dirname = fms->dirname;
434           else
435             {
436               allocated_dirname = g_path_get_dirname (fms->filename);
437               dirname = allocated_dirname;
438             }
439
440           other_file = g_local_file_new_from_dirname_and_basename (dirname, rename_to);
441           g_file_monitor_source_file_changes_done (fms, rename_to);
442           g_file_monitor_source_send_event (fms, event, child, other_file);
443
444           g_object_unref (other_file);
445           g_free (allocated_dirname);
446         }
447       else
448         {
449           g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
450           g_file_monitor_source_send_synthetic_created (fms, rename_to);
451         }
452       break;
453
454     case G_FILE_MONITOR_EVENT_DELETED:
455     case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
456     case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
457     case G_FILE_MONITOR_EVENT_UNMOUNTED:
458       g_assert (!other && !rename_to);
459       g_file_monitor_source_send_event (fms, event_type, child, NULL);
460       break;
461
462     case G_FILE_MONITOR_EVENT_MOVED:
463       /* was never available in this API */
464     default:
465       g_assert_not_reached ();
466     }
467
468   g_file_monitor_source_update_ready_time (fms);
469
470   g_mutex_unlock (&fms->lock);
471
472   return interesting;
473 }
474
475 static gint64
476 g_file_monitor_source_get_rate_limit (GFileMonitorSource *fms)
477 {
478   gint64 rate_limit;
479
480   g_mutex_lock (&fms->lock);
481   rate_limit = fms->rate_limit;
482   g_mutex_unlock (&fms->lock);
483
484   return rate_limit;
485 }
486
487 static gboolean
488 g_file_monitor_source_set_rate_limit (GFileMonitorSource *fms,
489                                       gint64              rate_limit)
490 {
491   gboolean changed;
492
493   g_mutex_lock (&fms->lock);
494
495   if (rate_limit != fms->rate_limit)
496     {
497       fms->rate_limit = rate_limit;
498
499       g_sequence_sort (fms->pending_changes, pending_change_compare_ready_time, fms);
500       g_file_monitor_source_update_ready_time (fms);
501
502       changed = TRUE;
503     }
504   else
505     changed = FALSE;
506
507   g_mutex_unlock (&fms->lock);
508
509   return changed;
510 }
511
512 static gboolean
513 g_file_monitor_source_dispatch (GSource     *source,
514                                 GSourceFunc  callback,
515                                 gpointer     user_data)
516 {
517   GFileMonitorSource *fms = (GFileMonitorSource *) source;
518   QueuedEvent *event;
519   GQueue event_queue;
520   gint64 now;
521   GFileMonitor *instance = NULL;
522
523   /* make sure the monitor still exists */
524   instance = g_weak_ref_get (&fms->instance_ref);
525   if (instance == NULL)
526     return FALSE;
527
528   now = g_source_get_time (source);
529
530   /* Acquire the lock once and grab all events in one go, handling the
531    * queued events first.  This avoids strange possibilities in cases of
532    * long delays, such as CHANGED events coming before CREATED events.
533    *
534    * We do this by converting the applicable pending changes into queued
535    * events (after the ones already queued) and then stealing the entire
536    * event queue in one go.
537    */
538   g_mutex_lock (&fms->lock);
539
540   /* Create events for any pending changes that are due to fire */
541   while (!g_sequence_is_empty (fms->pending_changes))
542     {
543       GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
544       PendingChange *pending = g_sequence_get (iter);
545
546       /* We've gotten to a pending change that's not ready.  Stop. */
547       if (pending_change_get_ready_time (pending, fms) > now)
548         break;
549
550       if (pending->dirty)
551         {
552           /* It's time to send another CHANGED and update the record */
553           g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
554           pending->last_emission = now;
555           pending->dirty = FALSE;
556
557           g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
558         }
559       else
560         {
561           /* It's time to send CHANGES_DONE and remove the pending record */
562           g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
563           g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
564         }
565     }
566
567   /* Steal the queue */
568   memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
569   memset (&fms->event_queue, 0, sizeof fms->event_queue);
570
571   g_file_monitor_source_update_ready_time (fms);
572
573   g_mutex_unlock (&fms->lock);
574   g_clear_object (&instance);
575
576   /* We now have our list of events to deliver */
577   while ((event = g_queue_pop_head (&event_queue)))
578     {
579       /* an event handler could destroy 'instance', so check each time */
580       instance = g_weak_ref_get (&fms->instance_ref);
581       if (instance != NULL)
582         g_file_monitor_emit_event (instance, event->child, event->other, event->event_type);
583
584       g_clear_object (&instance);
585       queued_event_free (event);
586     }
587
588   return TRUE;
589 }
590
591 static void
592 g_file_monitor_source_dispose (GFileMonitorSource *fms)
593 {
594   GHashTableIter iter;
595   gpointer seqiter;
596   QueuedEvent *event;
597
598   g_mutex_lock (&fms->lock);
599
600   g_hash_table_iter_init (&iter, fms->pending_changes_table);
601   while (g_hash_table_iter_next (&iter, NULL, &seqiter))
602     {
603       g_hash_table_iter_remove (&iter);
604       g_sequence_remove (seqiter);
605     }
606
607   while ((event = g_queue_pop_head (&fms->event_queue)))
608     queued_event_free (event);
609
610   g_assert (g_sequence_is_empty (fms->pending_changes));
611   g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
612   g_assert (fms->event_queue.length == 0);
613   g_weak_ref_set (&fms->instance_ref, NULL);
614
615   g_file_monitor_source_update_ready_time (fms);
616
617   g_source_destroy ((GSource *) fms);
618
619   g_mutex_unlock (&fms->lock);
620 }
621
622 static void
623 g_file_monitor_source_finalize (GSource *source)
624 {
625   GFileMonitorSource *fms = (GFileMonitorSource *) source;
626
627   /* should already have been cleared in dispose of the monitor */
628   g_assert (g_weak_ref_get (&fms->instance_ref) == NULL);
629   g_weak_ref_clear (&fms->instance_ref);
630
631   g_assert (g_sequence_is_empty (fms->pending_changes));
632   g_assert (g_hash_table_size (fms->pending_changes_table) == 0);
633   g_assert (fms->event_queue.length == 0);
634
635   g_hash_table_unref (fms->pending_changes_table);
636   g_sequence_free (fms->pending_changes);
637
638   g_free (fms->dirname);
639   g_free (fms->basename);
640   g_free (fms->filename);
641
642   g_mutex_clear (&fms->lock);
643 }
644
645 static guint
646 str_hash0 (gconstpointer str)
647 {
648   return str ? g_str_hash (str) : 0;
649 }
650
651 static gboolean
652 str_equal0 (gconstpointer a,
653             gconstpointer b)
654 {
655   return g_strcmp0 (a, b) == 0;
656 }
657
658 static GFileMonitorSource *
659 g_file_monitor_source_new (gpointer           instance,
660                            const gchar       *filename,
661                            gboolean           is_directory,
662                            GFileMonitorFlags  flags)
663 {
664   static GSourceFuncs source_funcs = {
665     NULL, NULL,
666     g_file_monitor_source_dispatch,
667     g_file_monitor_source_finalize,
668     NULL, NULL
669   };
670   GFileMonitorSource *fms;
671   GSource *source;
672
673   source = g_source_new (&source_funcs, sizeof (GFileMonitorSource));
674   fms = (GFileMonitorSource *) source;
675
676   g_source_set_static_name (source, "GFileMonitorSource");
677
678   g_mutex_init (&fms->lock);
679   g_weak_ref_init (&fms->instance_ref, instance);
680   fms->pending_changes = g_sequence_new (pending_change_free);
681   fms->pending_changes_table = g_hash_table_new (str_hash0, str_equal0);
682   fms->rate_limit = DEFAULT_RATE_LIMIT;
683   fms->flags = flags;
684
685   if (is_directory)
686     {
687       fms->dirname = g_strdup (filename);
688       fms->basename = NULL;
689       fms->filename = NULL;
690     }
691   else if (flags & G_FILE_MONITOR_WATCH_HARD_LINKS)
692     {
693       fms->dirname = NULL;
694       fms->basename = NULL;
695       fms->filename = g_strdup (filename);
696     }
697   else
698     {
699       fms->dirname = g_path_get_dirname (filename);
700       fms->basename = g_path_get_basename (filename);
701       fms->filename = NULL;
702     }
703
704   return fms;
705 }
706
707 G_DEFINE_ABSTRACT_TYPE (GLocalFileMonitor, g_local_file_monitor, G_TYPE_FILE_MONITOR)
708
709 enum {
710   PROP_0,
711   PROP_RATE_LIMIT,
712 };
713
714 static void
715 g_local_file_monitor_get_property (GObject *object, guint prop_id,
716                                    GValue *value, GParamSpec *pspec)
717 {
718   GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
719   gint64 rate_limit;
720
721   g_assert (prop_id == PROP_RATE_LIMIT);
722
723   rate_limit = g_file_monitor_source_get_rate_limit (monitor->source);
724   rate_limit /= G_TIME_SPAN_MILLISECOND;
725
726   g_value_set_int (value, rate_limit);
727 }
728
729 static void
730 g_local_file_monitor_set_property (GObject *object, guint prop_id,
731                                    const GValue *value, GParamSpec *pspec)
732 {
733   GLocalFileMonitor *monitor = G_LOCAL_FILE_MONITOR (object);
734   gint64 rate_limit;
735
736   g_assert (prop_id == PROP_RATE_LIMIT);
737
738   rate_limit = g_value_get_int (value);
739   rate_limit *= G_TIME_SPAN_MILLISECOND;
740
741   if (g_file_monitor_source_set_rate_limit (monitor->source, rate_limit))
742     g_object_notify (object, "rate-limit");
743 }
744
745 #ifndef G_OS_WIN32
746 static void
747 g_local_file_monitor_mounts_changed (GUnixMountMonitor *mount_monitor,
748                                      gpointer           user_data)
749 {
750   GLocalFileMonitor *local_monitor = user_data;
751   GUnixMountEntry *mount;
752   gboolean is_mounted;
753   GFile *file;
754
755   /* Emulate unmount detection */
756   mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
757
758   is_mounted = mount != NULL;
759
760   if (mount)
761     g_unix_mount_free (mount);
762
763   if (local_monitor->was_mounted != is_mounted)
764     {
765       if (local_monitor->was_mounted && !is_mounted)
766         {
767           file = g_file_new_for_path (local_monitor->source->dirname);
768           g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor), file, NULL, G_FILE_MONITOR_EVENT_UNMOUNTED);
769           g_object_unref (file);
770         }
771       local_monitor->was_mounted = is_mounted;
772     }
773 }
774 #endif
775
776 static void
777 g_local_file_monitor_start (GLocalFileMonitor *local_monitor,
778                             const gchar       *filename,
779                             gboolean           is_directory,
780                             GFileMonitorFlags  flags,
781                             GMainContext      *context)
782 {
783   GLocalFileMonitorClass *class = G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor);
784   GFileMonitorSource *source;
785
786   g_return_if_fail (G_IS_LOCAL_FILE_MONITOR (local_monitor));
787
788   g_assert (!local_monitor->source);
789
790   source = g_file_monitor_source_new (local_monitor, filename, is_directory, flags);
791   local_monitor->source = source; /* owns the ref */
792
793   if (is_directory && !class->mount_notify && (flags & G_FILE_MONITOR_WATCH_MOUNTS))
794     {
795 #ifdef G_OS_WIN32
796       /*claim everything was mounted */
797       local_monitor->was_mounted = TRUE;
798 #else
799       GUnixMountEntry *mount;
800
801       /* Emulate unmount detection */
802
803       mount = g_unix_mount_at (local_monitor->source->dirname, NULL);
804
805       local_monitor->was_mounted = mount != NULL;
806
807       if (mount)
808         g_unix_mount_free (mount);
809
810       local_monitor->mount_monitor = g_unix_mount_monitor_get ();
811       g_signal_connect_object (local_monitor->mount_monitor, "mounts-changed",
812                                G_CALLBACK (g_local_file_monitor_mounts_changed), local_monitor,
813                                G_CONNECT_DEFAULT);
814 #endif
815     }
816
817   g_source_attach ((GSource *) source, context);
818
819   G_LOCAL_FILE_MONITOR_GET_CLASS (local_monitor)->start (local_monitor,
820                                                          source->dirname, source->basename, source->filename,
821                                                          source);
822 }
823
824 static void
825 g_local_file_monitor_dispose (GObject *object)
826 {
827   GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
828
829   g_file_monitor_source_dispose (local_monitor->source);
830
831   G_OBJECT_CLASS (g_local_file_monitor_parent_class)->dispose (object);
832 }
833
834 static void
835 g_local_file_monitor_finalize (GObject *object)
836 {
837   GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (object);
838
839   g_source_unref ((GSource *) local_monitor->source);
840
841   G_OBJECT_CLASS (g_local_file_monitor_parent_class)->finalize (object);
842 }
843
844 static void
845 g_local_file_monitor_init (GLocalFileMonitor* local_monitor)
846 {
847 }
848
849 static void g_local_file_monitor_class_init (GLocalFileMonitorClass *class)
850 {
851   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
852
853   gobject_class->get_property = g_local_file_monitor_get_property;
854   gobject_class->set_property = g_local_file_monitor_set_property;
855   gobject_class->dispose = g_local_file_monitor_dispose;
856   gobject_class->finalize = g_local_file_monitor_finalize;
857
858   g_object_class_override_property (gobject_class, PROP_RATE_LIMIT, "rate-limit");
859 }
860
861 static GLocalFileMonitor *
862 g_local_file_monitor_new (gboolean   is_remote_fs,
863                           gboolean   is_directory,
864                           GError   **error)
865 {
866   GType type = G_TYPE_INVALID;
867
868   if (is_remote_fs)
869     type = _g_io_module_get_default_type (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
870                                           "GIO_USE_FILE_MONITOR",
871                                           G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
872
873   /* Fallback rather to poll file monitor for remote files, see gfile.c. */
874   if (type == G_TYPE_INVALID && (!is_remote_fs || is_directory))
875     type = _g_io_module_get_default_type (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
876                                           "GIO_USE_FILE_MONITOR",
877                                           G_STRUCT_OFFSET (GLocalFileMonitorClass, is_supported));
878
879   if (type == G_TYPE_INVALID)
880     {
881       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
882                            _("Unable to find default local file monitor type"));
883       return NULL;
884     }
885
886   return g_object_new (type, NULL);
887 }
888
889 GFileMonitor *
890 g_local_file_monitor_new_for_path (const gchar        *pathname,
891                                    gboolean            is_directory,
892                                    GFileMonitorFlags   flags,
893                                    GError            **error)
894 {
895   GLocalFileMonitor *monitor;
896   gboolean is_remote_fs;
897
898   is_remote_fs = g_local_file_is_nfs_home (pathname);
899
900   monitor = g_local_file_monitor_new (is_remote_fs, is_directory, error);
901
902   if (monitor)
903     g_local_file_monitor_start (monitor, pathname, is_directory, flags, g_main_context_get_thread_default ());
904
905   return G_FILE_MONITOR (monitor);
906 }
907
908 GFileMonitor *
909 g_local_file_monitor_new_in_worker (const gchar           *pathname,
910                                     gboolean               is_directory,
911                                     GFileMonitorFlags      flags,
912                                     GFileMonitorCallback   callback,
913                                     gpointer               user_data,
914                                     GClosureNotify         destroy_user_data,
915                                     GError               **error)
916 {
917   GLocalFileMonitor *monitor;
918   gboolean is_remote_fs;
919
920   is_remote_fs = g_local_file_is_nfs_home (pathname);
921
922   monitor = g_local_file_monitor_new (is_remote_fs, is_directory, error);
923
924   if (monitor)
925     {
926       if (callback)
927         g_signal_connect_data (monitor, "changed", G_CALLBACK (callback),
928                                user_data, destroy_user_data, G_CONNECT_DEFAULT);
929
930       g_local_file_monitor_start (monitor, pathname, is_directory, flags, GLIB_PRIVATE_CALL(g_get_worker_context) ());
931     }
932
933   return G_FILE_MONITOR (monitor);
934 }