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