summaryrefslogtreecommitdiff
path: root/gio
diff options
context:
space:
mode:
Diffstat (limited to 'gio')
-rw-r--r--gio/kqueue/gkqueuefilemonitor.c286
-rw-r--r--gio/kqueue/kqueue-helper.c21
-rw-r--r--gio/kqueue/kqueue-helper.h13
-rw-r--r--gio/kqueue/kqueue-missing.c39
4 files changed, 284 insertions, 75 deletions
diff --git a/gio/kqueue/gkqueuefilemonitor.c b/gio/kqueue/gkqueuefilemonitor.c
index d6fea41cf..816647512 100644
--- a/gio/kqueue/gkqueuefilemonitor.c
+++ b/gio/kqueue/gkqueuefilemonitor.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <glib-object.h>
+#include <glib/gfileutils.h>
#include <gio/gfilemonitor.h>
#include <gio/glocalfilemonitor.h>
#include <gio/giomodule.h>
@@ -52,19 +53,44 @@ static int kq_queue = -1;
#define G_KQUEUE_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor))
+/* C11 allows type redefinition, but GLib is configured to use C89, which causes
+ * clang to show warnings when we use a C11 feature. Since the C89 requirement
+ * is mostly used to support MSVC, we simply ignore the warning here because
+ * this file is never going to be useful on Windows. */
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wtypedef-redefinition"
+#endif
+
typedef GLocalFileMonitorClass GKqueueFileMonitorClass;
-typedef struct
+/* When the file we are monitoring is a directory, sub_dir is subscribed to the
+ * directory itself and sub_file is NULL.
+ *
+ * When the file we are monitoring is a regular file, sub_dir is subscribed to
+ * the directory containing the file and sub_file is subscribed to the file
+ * being monitored. We have to monitor both because it is possible that the
+ * file chosen for monitoring doesn't exist when the file monitor is started.
+ * We monitor on its parent in order to get notification when it is created.
+ *
+ * To distinguish between a directory monitor and a regular file monitor, check
+ * whether sub_file is NULL. */
+typedef struct _GKqueueFileMonitor
{
GLocalFileMonitor parent_instance;
- kqueue_sub *sub;
+ kqueue_sub *sub_dir;
+ kqueue_sub *sub_file;
#ifndef O_EVTONLY
GFileMonitor *fallback;
GFile *fbfile;
#endif
} GKqueueFileMonitor;
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
GType g_kqueue_file_monitor_get_type (void);
G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR,
g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
@@ -78,12 +104,23 @@ G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL
#define O_KQFLAG O_EVTONLY
#endif
-#define NOTE_ALL (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME)
+static inline unsigned int
+note_all (void)
+{
+ unsigned int notes = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME;
+#ifdef NOTE_TRUNCATE
+ notes |= NOTE_TRUNCATE;
+#endif
+#ifdef NOTE_CLOSE_WRITE
+ notes |= NOTE_CLOSE_WRITE;
+#endif
+ return notes;
+}
static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor);
static gboolean g_kqueue_file_monitor_is_supported (void);
-static kqueue_sub *_kqsub_new (const gchar *, GLocalFileMonitor *, GFileMonitorSource *);
+static kqueue_sub *_kqsub_new (gchar *, gchar *, GKqueueFileMonitor *, GFileMonitorSource *);
static void _kqsub_free (kqueue_sub *);
static gboolean _kqsub_cancel (kqueue_sub *);
@@ -138,11 +175,18 @@ g_kqueue_file_monitor_finalize (GObject *object)
{
GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (object);
- if (kqueue_monitor->sub)
+ if (kqueue_monitor->sub_dir)
+ {
+ _kqsub_cancel (kqueue_monitor->sub_dir);
+ _kqsub_free (kqueue_monitor->sub_dir);
+ kqueue_monitor->sub_dir = NULL;
+ }
+
+ if (kqueue_monitor->sub_file)
{
- _kqsub_cancel (kqueue_monitor->sub);
- _kqsub_free (kqueue_monitor->sub);
- kqueue_monitor->sub = NULL;
+ _kqsub_cancel (kqueue_monitor->sub_file);
+ _kqsub_free (kqueue_monitor->sub_file);
+ kqueue_monitor->sub_file = NULL;
}
#ifndef O_EVTONLY
@@ -165,17 +209,51 @@ g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor,
GFileMonitorSource *source)
{
GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor);
- kqueue_sub *sub;
- const gchar *path;
-
- path = filename;
- if (path == NULL)
- path = dirname;
+ kqueue_sub *sub_dir = NULL, *sub_file = NULL;
+ gchar *path_dir, *path_file, *file_basename;
+
+ /* There are three possible cases here:
+ *
+ * 1. Directory: dirname != NULL, basename == NULL, filename == NULL
+ * 2. Regular file: dirname != NULL, basename != NULL, filename == NULL
+ * 3. Hard links: dirname == NULL, basename == NULL, filename != NULL
+ *
+ * Note that we don't distinguish between case 2 and 3. Kqueue monitors
+ * files based on file descriptors, so we always receive events come from
+ * hard links.
+ */
+ if (filename != NULL)
+ {
+ path_dir = g_path_get_dirname (filename);
+ path_file = g_strdup (filename);
+ file_basename = g_path_get_basename (filename);
+ }
+ else
+ {
+ path_dir = g_strdup (dirname);
+ if (basename != NULL)
+ {
+ path_file = g_build_filename (dirname, basename, NULL);
+ file_basename = g_strdup (basename);
+ }
+ else
+ {
+ path_file = NULL;
+ file_basename = NULL;
+ }
+ }
#ifndef O_EVTONLY
- if (_ke_is_excluded (path))
+ if (_ke_is_excluded (path_dir))
{
- GFile *file = g_file_new_for_path (path);
+ GFile *file;
+ if (path_file != NULL)
+ file = g_file_new_for_path (path_file);
+ else
+ file = g_file_new_for_path (path_dir);
+ g_free (path_dir);
+ g_free (path_file);
+ g_free (file_basename);
kqueue_monitor->fbfile = file;
kqueue_monitor->fallback = _g_poll_file_monitor_new (file);
g_signal_connect (kqueue_monitor->fallback, "changed",
@@ -191,13 +269,30 @@ g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor,
* file, GIO uses a GKqueueFileMonitor object for that. If a directory
* will be created under that path, GKqueueFileMonitor will have to
* handle the directory notifications. */
- sub = _kqsub_new (path, local_monitor, source);
- if (sub == NULL)
- return;
+ sub_dir = _kqsub_new (g_steal_pointer (&path_dir), NULL,
+ kqueue_monitor, source);
+ if (!_kqsub_start_watching (sub_dir))
+ _km_add_missing (sub_dir);
+
+ /* Unlike GInotifyFileMonitor, which always uses a directory monitor
+ * regardless of the type of the file being monitored, kqueue doesn't
+ * give us events generated by files under it when we are monitoring
+ * a directory. We have to monitor the file itself to know changes which
+ * was made to the file itself. */
+ if (path_file != NULL)
+ {
+ sub_file = _kqsub_new (g_steal_pointer (&path_file),
+ g_steal_pointer (&file_basename),
+ kqueue_monitor, source);
+ if (!_kqsub_start_watching (sub_file))
+ _km_add_missing (sub_file);
+ }
- kqueue_monitor->sub = sub;
- if (!_kqsub_start_watching (sub))
- _km_add_missing (sub);
+ kqueue_monitor->sub_dir = sub_dir;
+ kqueue_monitor->sub_file = sub_file;
+ g_clear_pointer (&path_dir, g_free);
+ g_clear_pointer (&path_file, g_free);
+ g_clear_pointer (&file_basename, g_free);
}
static void
@@ -230,59 +325,127 @@ g_kqueue_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_d
struct timespec ts;
memset (&ts, 0, sizeof(ts));
+
+ /* We must hold the global lock before accessing any kqueue_sub because it is
+ * possible for other threads to call g_kqueue_file_monitor_cancel, which may
+ * free the kqueue_sub struct we are accessing. */
+ G_LOCK (kq_lock);
+
while (kevent(fd, NULL, 0, &ev, 1, &ts) > 0)
{
- GFileMonitorEvent mask = 0;
-
if (ev.filter != EVFILT_VNODE || ev.udata == NULL)
continue;
- sub = ev.udata;
+ sub = ev.udata;
source = sub->source;
+ /* When we are monitoring a regular file which already exists, ignore
+ * events generated by its parent directory. This has to be the first
+ * check to prevent the following code to emit useless events */
+ if (sub->is_dir && sub->mon->sub_file != NULL && sub->mon->sub_file->fd != -1)
+ continue;
+
if (ev.flags & EV_ERROR)
ev.fflags = NOTE_REVOKE;
- if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE))
- {
- _kqsub_cancel (sub);
- _km_add_missing (sub);
- }
-
if (sub->is_dir && ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
{
- _kh_dir_diff (sub);
+ /* If we are monitoring on a non-existent regular file, trigger the
+ * rescan of missing files immediately so we don't have to wait for
+ * 4 seconds for discovering missing files. We pass the sub_file
+ * corresponding to the GKqueueFileMonitor to 'check_this_sub_only'
+ * argument to prevent _km_scan_missing from emiting 'CREATED'
+ * events because _kh_dir_diff will do it for us. */
+ if (sub->mon->sub_file != NULL && sub->mon->sub_file->fd == -1)
+ _km_scan_missing (sub->mon->sub_file);
+
+ /* If we are monitoring a regular file, don't emit 'DELETED' events
+ * from the directory monitor because it will be emitted from the
+ * file itself when a NOTE_DELETE is reported on sub_file. */
+ _kh_dir_diff (sub, sub->mon->sub_file == NULL);
+
+#ifdef NOTE_TRUNCATE
+ ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND | NOTE_TRUNCATE);
+#else
ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND);
+#endif
}
+ /* Here starts the long section of mapping kqueue events to
+ * GFileMonitorEvent. Since kqueue can return multiple events in a
+ * single kevent struct, we must use 'if' instead of 'else if'. */
if (ev.fflags & NOTE_DELETE)
{
- mask = G_FILE_MONITOR_EVENT_DELETED;
+ struct stat st;
+ if (fstat (sub->fd, &st) < 0)
+ st.st_nlink = 0;
+
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_DELETED,
+ sub->basename, NULL, NULL, now);
+
+ /* If the last reference to the file was removed, delete the
+ * subscription from kqueue and add it to the missing list.
+ * If you are monitoring a file which has hard link count higher
+ * than 1, it is possible for the same file to emit 'DELETED'
+ * events multiple times. */
+ if (st.st_nlink == 0)
+ {
+ _kqsub_cancel (sub);
+ _km_add_missing (sub);
+ }
}
- else if (ev.fflags & NOTE_ATTRIB)
+ if (ev.fflags & NOTE_REVOKE)
+ {
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_UNMOUNTED,
+ sub->basename, NULL, NULL, now);
+ _kqsub_cancel (sub);
+ _km_add_missing (sub);
+ }
+ if (ev.fflags & NOTE_ATTRIB)
{
- mask = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED,
+ sub->basename, NULL, NULL, now);
}
- else if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
+#ifdef NOTE_TRUNCATE
+ if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND | NOTE_TRUNCATE))
+#else
+ if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND))
+#endif
{
- mask = G_FILE_MONITOR_EVENT_CHANGED;
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_CHANGED,
+ sub->basename, NULL, NULL, now);
}
- else if (ev.fflags & NOTE_RENAME)
+ if (ev.fflags & NOTE_RENAME)
{
/* Since there’s apparently no way to get the new name of the
* file out of kqueue(), all we can do is say that this one has
* been deleted. */
- mask = G_FILE_MONITOR_EVENT_DELETED;
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_DELETED,
+ sub->basename, NULL, NULL, now);
}
- else if (ev.fflags & NOTE_REVOKE)
+#ifdef NOTE_CLOSE_WRITE
+ if (ev.fflags & NOTE_CLOSE_WRITE)
{
- mask = G_FILE_MONITOR_EVENT_UNMOUNTED;
+ g_file_monitor_source_handle_event (source,
+ G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT,
+ sub->basename, NULL, NULL, now);
}
+#endif
- if (mask)
- g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, now);
+ /* Handle the case when a file is created again shortly after it was
+ * deleted. It has to be the last check because 'DELETED' must happen
+ * before 'CREATED'. */
+ if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE))
+ _km_scan_missing (NULL);
}
+ G_UNLOCK (kq_lock);
+
return TRUE;
}
@@ -320,14 +483,28 @@ g_kqueue_file_monitor_cancel (GFileMonitor *monitor)
{
GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor);
- if (kqueue_monitor->sub)
+ /* We must hold the global lock before calling _kqsub_cancel. However, we
+ * cannot call G_LOCK in _kqsub_cancel because it is also used by
+ * g_kqueue_file_monitor_callback, which already holds the lock itself. */
+ G_LOCK (kq_lock);
+
+ if (kqueue_monitor->sub_dir)
{
- _kqsub_cancel (kqueue_monitor->sub);
- _kqsub_free (kqueue_monitor->sub);
- kqueue_monitor->sub = NULL;
+ _kqsub_cancel (kqueue_monitor->sub_dir);
+ _kqsub_free (kqueue_monitor->sub_dir);
+ kqueue_monitor->sub_dir = NULL;
}
+ if (kqueue_monitor->sub_file)
+ {
+ _kqsub_cancel (kqueue_monitor->sub_file);
+ _kqsub_free (kqueue_monitor->sub_file);
+ kqueue_monitor->sub_file = NULL;
+ }
+
+ G_UNLOCK (kq_lock);
+
#ifndef O_EVTONLY
- else if (kqueue_monitor->fallback)
+ if (kqueue_monitor->fallback)
{
g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor);
g_file_monitor_cancel (kqueue_monitor->fallback);
@@ -341,12 +518,13 @@ g_kqueue_file_monitor_cancel (GFileMonitor *monitor)
}
static kqueue_sub *
-_kqsub_new (const gchar *filename, GLocalFileMonitor *mon, GFileMonitorSource *source)
+_kqsub_new (gchar *filename, gchar *basename, GKqueueFileMonitor *mon, GFileMonitorSource *source)
{
kqueue_sub *sub;
sub = g_slice_new (kqueue_sub);
- sub->filename = g_strdup (filename);
+ sub->filename = filename;
+ sub->basename = basename;
sub->mon = mon;
g_source_ref ((GSource *) source);
sub->source = source;
@@ -365,19 +543,23 @@ _kqsub_free (kqueue_sub *sub)
g_source_unref ((GSource *) sub->source);
g_free (sub->filename);
+ g_free (sub->basename);
g_slice_free (kqueue_sub, sub);
}
static gboolean
_kqsub_cancel (kqueue_sub *sub)
{
+ /* WARNING: Before calling this function, you must hold a lock on kq_lock
+ * or you will cause use-after-free in g_kqueue_file_monitor_callback. */
+
struct kevent ev;
/* Remove the event and close the file descriptor to automatically
* delete pending events. */
if (sub->fd != -1)
{
- EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, sub);
+ EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, note_all (), 0, sub);
if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
{
g_warning ("Unable to remove event for %s: %s", sub->filename, g_strerror (errno));
@@ -425,7 +607,7 @@ _kqsub_start_watching (kqueue_sub *sub)
sub->deps = dl_listing (sub->filename);
}
- EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0, sub);
+ EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, note_all (), 0, sub);
if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1)
{
g_warning ("Unable to add event for %s: %s", sub->filename, g_strerror (errno));
diff --git a/gio/kqueue/kqueue-helper.c b/gio/kqueue/kqueue-helper.c
index 497c30b15..36a5b58a7 100644
--- a/gio/kqueue/kqueue-helper.c
+++ b/gio/kqueue/kqueue-helper.c
@@ -25,6 +25,7 @@
#include <sys/event.h>
#include <sys/time.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <gio/glocalfile.h>
#include <gio/glocalfilemonitor.h>
#include <gio/gfile.h>
@@ -38,6 +39,7 @@
typedef struct {
kqueue_sub *sub;
GFileMonitorSource *source;
+ gboolean handle_deleted;
} handle_ctx;
/**
@@ -53,6 +55,9 @@ static void
handle_created (void *udata, const char *path, ino_t inode)
{
handle_ctx *ctx = NULL;
+ gint64 now;
+ gchar *fullname;
+ struct stat st;
(void) inode;
ctx = (handle_ctx *) udata;
@@ -60,8 +65,16 @@ handle_created (void *udata, const char *path, ino_t inode)
g_assert (ctx->sub != NULL);
g_assert (ctx->source != NULL);
+ now = g_get_monotonic_time ();
g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED, path,
- NULL, NULL, g_get_monotonic_time ());
+ NULL, NULL, now);
+
+ /* Copied from ih_event_callback to report 'CHANGES_DONE_HINT' earlier. */
+ fullname = g_build_filename (ctx->sub->filename, path, NULL);
+ if (stat (fullname, &st) != 0 || !S_ISREG (st.st_mode) || st.st_nlink != 1)
+ g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, path,
+ NULL, NULL, now);
+ g_free (fullname);
}
/**
@@ -84,6 +97,9 @@ handle_deleted (void *udata, const char *path, ino_t inode)
g_assert (ctx->sub != NULL);
g_assert (ctx->source != NULL);
+ if (!ctx->handle_deleted)
+ return;
+
g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED, path,
NULL, NULL, g_get_monotonic_time ());
}
@@ -161,7 +177,7 @@ static const traverse_cbs cbs = {
void
-_kh_dir_diff (kqueue_sub *sub)
+_kh_dir_diff (kqueue_sub *sub, gboolean handle_deleted)
{
dep_list *was;
handle_ctx ctx;
@@ -169,6 +185,7 @@ _kh_dir_diff (kqueue_sub *sub)
memset (&ctx, 0, sizeof (handle_ctx));
ctx.sub = sub;
ctx.source = sub->source;
+ ctx.handle_deleted = handle_deleted;
was = sub->deps;
sub->deps = dl_listing (sub->filename);
diff --git a/gio/kqueue/kqueue-helper.h b/gio/kqueue/kqueue-helper.h
index 38a32a2f9..418b38c08 100644
--- a/gio/kqueue/kqueue-helper.h
+++ b/gio/kqueue/kqueue-helper.h
@@ -28,26 +28,33 @@
#include "dep-list.h"
+typedef struct _GKqueueFileMonitor GKqueueFileMonitor;
+
/**
* kqueue_sub:
+ * @mon: a pointer to the GKqueueFileMonitor which holds this subscription
* @filename: a name of the file to monitor
* @fd: the associated file descriptor (used by kqueue)
*
- * Represents a subscription on a file or directory.
+ * Represents a subscription on a file or directory. To check whether a
+ * subscription is active, check the fd field. If fd is not -1, it is an
+ * active subscription which can emit events from kqueue.
*/
typedef struct
{
- GLocalFileMonitor *mon;
+ GKqueueFileMonitor *mon;
GFileMonitorSource *source;
gchar* filename;
+ gchar* basename;
int fd;
dep_list* deps;
int is_dir;
} kqueue_sub;
gboolean _kqsub_start_watching (kqueue_sub *sub);
-void _kh_dir_diff (kqueue_sub *sub);
+void _kh_dir_diff (kqueue_sub *sub, gboolean handle_deleted);
void _km_add_missing (kqueue_sub *sub);
+gboolean _km_scan_missing (kqueue_sub *check_this_sub_only);
void _km_remove (kqueue_sub *sub);
#endif /* __KQUEUE_HELPER_H */
diff --git a/gio/kqueue/kqueue-missing.c b/gio/kqueue/kqueue-missing.c
index 93135b962..a08f3a736 100644
--- a/gio/kqueue/kqueue-missing.c
+++ b/gio/kqueue/kqueue-missing.c
@@ -21,16 +21,13 @@
*******************************************************************************/
#include <glib.h>
+#include "glib-private.h"
#include "kqueue-helper.h"
#define SCAN_MISSING_TIME 4 /* 1/4 Hz */
-void _kh_file_appeared_cb (kqueue_sub *sub);
-
-static gboolean km_scan_missing (gpointer user_data);
-
static gboolean km_debug_enabled = FALSE;
#define KM_W if (km_debug_enabled) g_warning
@@ -40,6 +37,12 @@ G_LOCK_DEFINE_STATIC (missing_lock);
static volatile gboolean scan_missing_running = FALSE;
+static gboolean
+_km_scan_missing_cb (gpointer user_data)
+{
+ return _km_scan_missing (NULL);
+}
+
/**
* _km_add_missing:
* @sub: a #kqueue_sub
@@ -77,10 +80,10 @@ _km_add_missing (kqueue_sub *sub)
* Signals that a missing file has finally appeared in the filesystem.
* Emits %G_FILE_MONITOR_EVENT_CREATED.
**/
-void
+static void
_kh_file_appeared_cb (kqueue_sub *sub)
{
- GFile *child;
+ gint64 now = g_get_monotonic_time ();
g_assert (sub != NULL);
g_assert (sub->filename);
@@ -88,18 +91,14 @@ _kh_file_appeared_cb (kqueue_sub *sub)
if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS))
return;
- child = g_file_new_for_path (sub->filename);
-
- g_file_monitor_emit_event (G_FILE_MONITOR (sub->mon),
- child,
- NULL,
- G_FILE_MONITOR_EVENT_CREATED);
-
- g_object_unref (child);
+ g_file_monitor_source_handle_event (sub->source, G_FILE_MONITOR_EVENT_CREATED,
+ sub->basename, NULL, NULL, now);
+ g_file_monitor_source_handle_event (sub->source, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT,
+ sub->basename, NULL, NULL, now);
}
/**
- * km_scan_missing:
+ * _km_scan_missing:
* @user_data: unused
*
* The core missing files watching routine.
@@ -110,8 +109,8 @@ _kh_file_appeared_cb (kqueue_sub *sub)
*
* Returns: %FALSE if no missing files left, %TRUE otherwise.
**/
-static gboolean
-km_scan_missing (gpointer user_data)
+gboolean
+_km_scan_missing (kqueue_sub *check_this_sub_only)
{
GSList *head;
GSList *not_missing = NULL;
@@ -128,10 +127,14 @@ km_scan_missing (gpointer user_data)
g_assert (sub != NULL);
g_assert (sub->filename != NULL);
+ if (check_this_sub_only != NULL && sub != check_this_sub_only)
+ continue;
+
if (_kqsub_start_watching (sub))
{
KM_W ("file %s now exists, starting watching", sub->filename);
- _kh_file_appeared_cb (sub);
+ if (check_this_sub_only == NULL)
+ _kh_file_appeared_cb (sub);
not_missing = g_slist_prepend (not_missing, head);
}
}