1 /*******************************************************************************
2 Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 *******************************************************************************/
22
23 #include "config.h"
24
25 #include <sys/types.h>
26 #include <sys/event.h>
27 #include <sys/time.h>
28 #include <sys/socket.h>
29 #include <sys/stat.h>
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <string.h>
34
35 #include <glib-object.h>
36 #include <glib/gfileutils.h>
37 #include <gio/gfilemonitor.h>
38 #include <gio/glocalfilemonitor.h>
39 #include <gio/giomodule.h>
40 #include <gio/gpollfilemonitor.h>
41 #include <gio/gfile.h>
42 #include <glib-unix.h>
43 #include "glib-private.h"
44
45 #include "kqueue-helper.h"
46 #include "dep-list.h"
47
48 G_LOCK_DEFINE_STATIC (kq_lock);
49 static GSource *kq_source;
50 static int kq_queue = -1;
51
52 #define G_TYPE_KQUEUE_FILE_MONITOR (g_kqueue_file_monitor_get_type ())
53 #define G_KQUEUE_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
54 G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor))
55
56 /* C11 allows type redefinition, but GLib is configured to use C89, which causes
57 * clang to show warnings when we use a C11 feature. Since the C89 requirement
58 * is mostly used to support MSVC, we simply ignore the warning here because
59 * this file is never going to be useful on Windows. */
60 #ifdef __clang__
61 #pragma clang diagnostic push
62 #pragma clang diagnostic ignored "-Wtypedef-redefinition"
63 #endif
64
65 typedef GLocalFileMonitorClass GKqueueFileMonitorClass;
66
67 /* When the file we are monitoring is a directory, sub_dir is subscribed to the
68 * directory itself and sub_file is NULL.
69 *
70 * When the file we are monitoring is a regular file, sub_dir is subscribed to
71 * the directory containing the file and sub_file is subscribed to the file
72 * being monitored. We have to monitor both because it is possible that the
73 * file chosen for monitoring doesn't exist when the file monitor is started.
74 * We monitor on its parent in order to get notification when it is created.
75 *
76 * To distinguish between a directory monitor and a regular file monitor, check
77 * whether sub_file is NULL. */
78 struct _GKqueueFileMonitor
79 {
80 GLocalFileMonitor parent_instance;
81
82 kqueue_sub *sub_dir;
83 kqueue_sub *sub_file;
84 #ifndef O_EVTONLY
85 GFileMonitor *fallback;
86 GFile *fbfile;
87 #endif
88 };
89
90 #ifdef __clang__
91 #pragma clang diagnostic pop
92 #endif
93
94 GType g_kqueue_file_monitor_get_type (void);
95 G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
96 g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
97 g_define_type_id,
98 "kqueue",
99 20))
100
101 #ifndef O_EVTONLY
102 #define O_KQFLAG O_RDONLY
103 #else
104 #define O_KQFLAG O_EVTONLY
105 #endif
106
107 static inline unsigned int
note_all(void)108 note_all (void)
109 {
110 unsigned int notes = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE;
111 #ifdef NOTE_TRUNCATE
112 notes |= NOTE_TRUNCATE;
113 #endif
114 #ifdef NOTE_CLOSE_WRITE
115 notes |= NOTE_CLOSE_WRITE;
116 #endif
117 return notes;
118 }
119
120 static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor);
121 static gboolean g_kqueue_file_monitor_is_supported (void);
122
123 static kqueue_sub *_kqsub_new (gchar *, gchar *, GKqueueFileMonitor *, GFileMonitorSource *);
124 static void _kqsub_free (kqueue_sub *);
125 static void _kqsub_cancel (kqueue_sub *);
126
127
128 #ifndef O_EVTONLY
129 static void
_fallback_callback(GFileMonitor * unused,GFile * first,GFile * second,GFileMonitorEvent event,gpointer udata)130 _fallback_callback (GFileMonitor *unused,
131 GFile *first,
132 GFile *second,
133 GFileMonitorEvent event,
134 gpointer udata)
135 {
136 GKqueueFileMonitor *kq_mon = G_KQUEUE_FILE_MONITOR (udata);
137
138 g_file_monitor_emit_event (G_FILE_MONITOR (kq_mon), first, second, event);
139 }
140
141 /*
142 * _ke_is_excluded:
143 * @full_path - a path to file to check.
144 *
145 * Returns: TRUE if the file should be excluded from the kqueue-powered
146 * monitoring, FALSE otherwise.
147 **/
148 static gboolean
_ke_is_excluded(const char * full_path)149 _ke_is_excluded (const char *full_path)
150 {
151 GFile *f = NULL;
152 GMount *mount = NULL;
153
154 f = g_file_new_for_path (full_path);
155
156 if (f != NULL) {
157 mount = g_file_find_enclosing_mount (f, NULL, NULL);
158 g_object_unref (f);
159 }
160
161 if (mount != NULL && (g_str_has_prefix (full_path, "/media/") || g_str_has_prefix (full_path, "/run/media/")))
162 {
163 g_warning ("Excluding %s from kernel notification, falling back to poll", full_path);
164 if (mount)
165 g_object_unref (mount);
166 return TRUE;
167 }
168
169 return FALSE;
170 }
171 #endif /* !O_EVTONLY */
172
173 static void
g_kqueue_file_monitor_finalize(GObject * object)174 g_kqueue_file_monitor_finalize (GObject *object)
175 {
176 GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (object);
177
178 if (kqueue_monitor->sub_dir)
179 {
180 _kqsub_cancel (kqueue_monitor->sub_dir);
181 _kqsub_free (kqueue_monitor->sub_dir);
182 kqueue_monitor->sub_dir = NULL;
183 }
184
185 if (kqueue_monitor->sub_file)
186 {
187 _kqsub_cancel (kqueue_monitor->sub_file);
188 _kqsub_free (kqueue_monitor->sub_file);
189 kqueue_monitor->sub_file = NULL;
190 }
191
192 #ifndef O_EVTONLY
193 if (kqueue_monitor->fallback)
194 g_object_unref (kqueue_monitor->fallback);
195
196 if (kqueue_monitor->fbfile)
197 g_object_unref (kqueue_monitor->fbfile);
198 #endif
199
200 if (G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize)
201 (*G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (object);
202 }
203
204 static void
g_kqueue_file_monitor_start(GLocalFileMonitor * local_monitor,const gchar * dirname,const gchar * basename,const gchar * filename,GFileMonitorSource * source)205 g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor,
206 const gchar *dirname,
207 const gchar *basename,
208 const gchar *filename,
209 GFileMonitorSource *source)
210 {
211 GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor);
212 kqueue_sub *sub_dir = NULL, *sub_file = NULL;
213 gchar *path_dir, *path_file, *file_basename;
214
215 /* There are three possible cases here:
216 *
217 * 1. Directory: dirname != NULL, basename == NULL, filename == NULL
218 * 2. Regular file: dirname != NULL, basename != NULL, filename == NULL
219 * 3. Hard links: dirname == NULL, basename == NULL, filename != NULL
220 *
221 * Note that we don't distinguish between case 2 and 3. Kqueue monitors
222 * files based on file descriptors, so we always receive events come from
223 * hard links.
224 */
225 if (filename != NULL)
226 {
227 path_dir = g_path_get_dirname (filename);
228 path_file = g_strdup (filename);
229 file_basename = g_path_get_basename (filename);
230 }
231 else
232 {
233 path_dir = g_strdup (dirname);
234 if (basename != NULL)
235 {
236 path_file = g_build_filename (dirname, basename, NULL);
237 file_basename = g_strdup (basename);
238 }
239 else
240 {
241 path_file = NULL;
242 file_basename = NULL;
243 }
244 }
245
246 #ifndef O_EVTONLY
247 if (_ke_is_excluded (path_dir))
248 {
249 GFile *file;
250 if (path_file != NULL)
251 file = g_file_new_for_path (path_file);
252 else
253 file = g_file_new_for_path (path_dir);
254 g_free (path_dir);
255 g_free (path_file);
256 g_free (file_basename);
257 kqueue_monitor->fbfile = file;
258 kqueue_monitor->fallback = _g_poll_file_monitor_new (file);
259 g_signal_connect (kqueue_monitor->fallback, "changed",
260 G_CALLBACK (_fallback_callback), kqueue_monitor);
261 return;
262 }
263 #endif
264
265 /* For a directory monitor, create a subscription object anyway.
266 * It will be used for directory diff calculation routines.
267 * Wait, directory diff in a GKqueueFileMonitor?
268 * Yes, it is. When a file monitor is started on a non-existent
269 * file, GIO uses a GKqueueFileMonitor object for that. If a directory
270 * will be created under that path, GKqueueFileMonitor will have to
271 * handle the directory notifications. */
272 sub_dir = _kqsub_new (g_steal_pointer (&path_dir), NULL,
273 kqueue_monitor, source);
274 if (!_kqsub_start_watching (sub_dir))
275 _km_add_missing (sub_dir);
276
277 /* Unlike GInotifyFileMonitor, which always uses a directory monitor
278 * regardless of the type of the file being monitored, kqueue doesn't
279 * give us events generated by files under it when we are monitoring
280 * a directory. We have to monitor the file itself to know changes which
281 * was made to the file itself. */
282 if (path_file != NULL)
283 {
284 sub_file = _kqsub_new (g_steal_pointer (&path_file),
285 g_steal_pointer (&file_basename),
286 kqueue_monitor, source);
287 if (!_kqsub_start_watching (sub_file))
288 _km_add_missing (sub_file);
289 }
290
291 kqueue_monitor->sub_dir = sub_dir;
292 kqueue_monitor->sub_file = sub_file;
293 g_clear_pointer (&path_dir, g_free);
294 g_clear_pointer (&path_file, g_free);
295 g_clear_pointer (&file_basename, g_free);
296 }
297
298 static void
g_kqueue_file_monitor_class_init(GKqueueFileMonitorClass * klass)299 g_kqueue_file_monitor_class_init (GKqueueFileMonitorClass *klass)
300 {
301 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
302 GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
303 GLocalFileMonitorClass *local_file_monitor_class = G_LOCAL_FILE_MONITOR_CLASS (klass);
304
305 gobject_class->finalize = g_kqueue_file_monitor_finalize;
306 file_monitor_class->cancel = g_kqueue_file_monitor_cancel;
307
308 local_file_monitor_class->is_supported = g_kqueue_file_monitor_is_supported;
309 local_file_monitor_class->start = g_kqueue_file_monitor_start;
310 local_file_monitor_class->mount_notify = TRUE; /* TODO: ??? */
311 }
312
313 static void
g_kqueue_file_monitor_init(GKqueueFileMonitor * monitor)314 g_kqueue_file_monitor_init (GKqueueFileMonitor *monitor)
315 {
316 }
317
318 static gboolean
g_kqueue_file_monitor_callback(gint fd,GIOCondition condition,gpointer user_data)319 g_kqueue_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_data)
320 {
321 gint64 now = g_source_get_time (kq_source);
322 kqueue_sub *sub;
323 GFileMonitorSource *source;
324 struct kevent ev;
325 struct timespec ts;
326
327 memset (&ts, 0, sizeof(ts));
328
329 /* We must hold the global lock before accessing any kqueue_sub because it is
330 * possible for other threads to call g_kqueue_file_monitor_cancel, which may
331 * free the kqueue_sub struct we are accessing. */
332 G_LOCK (kq_lock);
333
334 while (kevent(fd, NULL, 0, &ev, 1, &ts) > 0)
335 {
336 if (ev.filter != EVFILT_VNODE || ev.udata == NULL)
337 continue;
338
339 sub = ev.udata;
340 source = sub->source;
341
342 /* When we are monitoring a regular file which already exists, ignore
343 * events generated by its parent directory. This has to be the first
344 * check to prevent the following code to emit useless events */
345 if (sub->is_dir && sub->mon->sub_file != NULL && sub->mon->sub_file->fd != -1)
346 continue;
347
348 if (ev.flags & EV_ERROR)
349 ev.fflags = NOTE_REVOKE;
350
351 if (sub->is_dir && ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
352 {
353 /* If we are monitoring on a non-existent regular file, trigger the
354 * rescan of missing files immediately so we don't have to wait for
355 * 4 seconds for discovering missing files. We pass the sub_file
356 * corresponding to the GKqueueFileMonitor to 'check_this_sub_only'
357 * argument to prevent _km_scan_missing from emitting 'CREATED'
358 * events because _kh_dir_diff will do it for us. */
359 if (sub->mon->sub_file != NULL && sub->mon->sub_file->fd == -1)
360 _km_scan_missing (sub->mon->sub_file);
361
362 /* If we are monitoring a regular file, don't emit 'DELETED' events
363 * from the directory monitor because it will be emitted from the
364 * file itself when a NOTE_DELETE is reported on sub_file. */
365 _kh_dir_diff (sub, sub->mon->sub_file == NULL);
366
367 #ifdef NOTE_TRUNCATE
368 ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND | NOTE_TRUNCATE);
369 #else
370 ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND);
371 #endif
372 }
373
374 /* Here starts the long section of mapping kqueue events to
375 * GFileMonitorEvent. Since kqueue can return multiple events in a
376 * single kevent struct, we must use 'if' instead of 'else if'. */
377 if (ev.fflags & NOTE_DELETE)
378 {
379 struct stat st;
380 if (fstat (sub->fd, &st) < 0)
381 st.st_nlink = 0;
382
383 g_file_monitor_source_handle_event (source,
384 G_FILE_MONITOR_EVENT_DELETED,
385 sub->basename, NULL, NULL, now);
386
387 /* If the last reference to the file was removed, delete the
388 * subscription from kqueue and add it to the missing list.
389 * If you are monitoring a file which has hard link count higher
390 * than 1, it is possible for the same file to emit 'DELETED'
391 * events multiple times. */
392 if (st.st_nlink == 0)
393 {
394 _kqsub_cancel (sub);
395 _km_add_missing (sub);
396 }
397 }
398 if (ev.fflags & NOTE_REVOKE)
399 {
400 g_file_monitor_source_handle_event (source,
401 G_FILE_MONITOR_EVENT_UNMOUNTED,
402 sub->basename, NULL, NULL, now);
403 _kqsub_cancel (sub);
404 _km_add_missing (sub);
405 }
406 if (ev.fflags & NOTE_ATTRIB)
407 {
408 g_file_monitor_source_handle_event (source,
409 G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED,
410 sub->basename, NULL, NULL, now);
411 }
412 #ifdef NOTE_TRUNCATE
413 if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND | NOTE_TRUNCATE))
414 #else
415 if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
416 #endif
417 {
418 g_file_monitor_source_handle_event (source,
419 G_FILE_MONITOR_EVENT_CHANGED,
420 sub->basename, NULL, NULL, now);
421 }
422 if (ev.fflags & NOTE_RENAME)
423 {
424 /* Since there’s apparently no way to get the new name of the
425 * file out of kqueue(), all we can do is say that this one has
426 * been deleted. */
427 g_file_monitor_source_handle_event (source,
428 G_FILE_MONITOR_EVENT_DELETED,
429 sub->basename, NULL, NULL, now);
430 }
431 #ifdef NOTE_CLOSE_WRITE
432 if (ev.fflags & NOTE_CLOSE_WRITE)
433 {
434 g_file_monitor_source_handle_event (source,
435 G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT,
436 sub->basename, NULL, NULL, now);
437 }
438 #endif
439
440 /* Handle the case when a file is created again shortly after it was
441 * deleted. It has to be the last check because 'DELETED' must happen
442 * before 'CREATED'. */
443 if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE))
444 _km_scan_missing (NULL);
445 }
446
447 G_UNLOCK (kq_lock);
448
449 return TRUE;
450 }
451
452 static gboolean
g_kqueue_file_monitor_is_supported(void)453 g_kqueue_file_monitor_is_supported (void)
454 {
455 int errsv;
456
457 G_LOCK (kq_lock);
458
459 if (kq_queue == -1)
460 {
461 kq_queue = kqueue ();
462 errsv = errno;
463
464 if (kq_queue == -1)
465 {
466 g_warning ("Unable to create a kqueue: %s", g_strerror (errsv));
467 G_UNLOCK (kq_lock);
468 return FALSE;
469 }
470
471 kq_source = g_unix_fd_source_new (kq_queue, G_IO_IN);
472 g_source_set_callback (kq_source, (GSourceFunc) g_kqueue_file_monitor_callback, NULL, NULL);
473 g_source_attach (kq_source, GLIB_PRIVATE_CALL (g_get_worker_context) ());
474 }
475
476 G_UNLOCK (kq_lock);
477
478 return TRUE;
479 }
480
481 static gboolean
g_kqueue_file_monitor_cancel(GFileMonitor * monitor)482 g_kqueue_file_monitor_cancel (GFileMonitor *monitor)
483 {
484 GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor);
485
486 /* We must hold the global lock before calling _kqsub_cancel. However, we
487 * cannot call G_LOCK in _kqsub_cancel because it is also used by
488 * g_kqueue_file_monitor_callback, which already holds the lock itself. */
489 G_LOCK (kq_lock);
490
491 if (kqueue_monitor->sub_dir)
492 {
493 _kqsub_cancel (kqueue_monitor->sub_dir);
494 _kqsub_free (kqueue_monitor->sub_dir);
495 kqueue_monitor->sub_dir = NULL;
496 }
497 if (kqueue_monitor->sub_file)
498 {
499 _kqsub_cancel (kqueue_monitor->sub_file);
500 _kqsub_free (kqueue_monitor->sub_file);
501 kqueue_monitor->sub_file = NULL;
502 }
503
504 G_UNLOCK (kq_lock);
505
506 #ifndef O_EVTONLY
507 if (kqueue_monitor->fallback)
508 {
509 g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor);
510 g_file_monitor_cancel (kqueue_monitor->fallback);
511 }
512 #endif
513
514 if (G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel)
515 (*G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (monitor);
516
517 return TRUE;
518 }
519
520 static kqueue_sub *
_kqsub_new(gchar * filename,gchar * basename,GKqueueFileMonitor * mon,GFileMonitorSource * source)521 _kqsub_new (gchar *filename, gchar *basename, GKqueueFileMonitor *mon, GFileMonitorSource *source)
522 {
523 kqueue_sub *sub;
524
525 sub = g_slice_new (kqueue_sub);
526 sub->filename = filename;
527 sub->basename = basename;
528 sub->mon = mon;
529 g_source_ref ((GSource *) source);
530 sub->source = source;
531 sub->fd = -1;
532 sub->deps = NULL;
533 sub->is_dir = 0;
534
535 return sub;
536 }
537
538 static void
_kqsub_free(kqueue_sub * sub)539 _kqsub_free (kqueue_sub *sub)
540 {
541 g_assert (sub->deps == NULL);
542 g_assert (sub->fd == -1);
543
544 g_source_unref ((GSource *) sub->source);
545 g_free (sub->filename);
546 g_free (sub->basename);
547 g_slice_free (kqueue_sub, sub);
548 }
549
550 static void
_kqsub_cancel(kqueue_sub * sub)551 _kqsub_cancel (kqueue_sub *sub)
552 {
553 /* WARNING: Before calling this function, you must hold a lock on kq_lock
554 * or you will cause use-after-free in g_kqueue_file_monitor_callback. */
555
556 struct kevent ev;
557
558 /* Remove the event and close the file descriptor to automatically
559 * delete pending events. */
560 if (sub->fd != -1)
561 {
562 EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, note_all (), 0, sub);
563 if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
564 {
565 g_warning ("Unable to remove event for %s: %s", sub->filename, g_strerror (errno));
566 }
567 close (sub->fd);
568 sub->fd = -1;
569 }
570
571 _km_remove (sub);
572
573 if (sub->deps)
574 {
575 dl_free (sub->deps);
576 sub->deps = NULL;
577 }
578 }
579
580 gboolean
_kqsub_start_watching(kqueue_sub * sub)581 _kqsub_start_watching (kqueue_sub *sub)
582 {
583 struct stat st;
584 struct kevent ev;
585
586 sub->fd = open (sub->filename, O_KQFLAG);
587 if (sub->fd == -1)
588 return FALSE;
589
590 if (fstat (sub->fd, &st) == -1)
591 {
592 g_warning ("fstat failed for %s: %s", sub->filename, g_strerror (errno));
593 close (sub->fd);
594 sub->fd = -1;
595 return FALSE;
596 }
597
598 sub->is_dir = (st.st_mode & S_IFDIR) ? 1 : 0;
599 if (sub->is_dir)
600 {
601 if (sub->deps)
602 dl_free (sub->deps);
603
604 sub->deps = dl_listing (sub->filename);
605 }
606
607 EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, note_all (), 0, sub);
608 if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
609 {
610 g_warning ("Unable to add event for %s: %s", sub->filename, g_strerror (errno));
611 close (sub->fd);
612 sub->fd = -1;
613 return FALSE;
614 }
615
616 return TRUE;
617 }
618