|
Packit |
ae235b |
/*
|
|
Packit |
ae235b |
Copyright (C) 2005 John McCutchan
|
|
Packit |
ae235b |
Copyright © 2015 Canonical Limited
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
This library is free software; you can redistribute it and/or
|
|
Packit |
ae235b |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
ae235b |
License as published by the Free Software Foundation; either
|
|
Packit |
ae235b |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
This library is distributed in the hope that it will be useful,
|
|
Packit |
ae235b |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
ae235b |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
ae235b |
Lesser General Public License for more details.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
ae235b |
along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
Authors:
|
|
Packit |
ae235b |
Ryan Lortie <desrt@desrt.ca>
|
|
Packit |
ae235b |
John McCutchan <john@johnmccutchan.com>
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "config.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include <stdio.h>
|
|
Packit |
ae235b |
#include <sys/ioctl.h>
|
|
Packit |
ae235b |
#include <unistd.h>
|
|
Packit |
ae235b |
#include <errno.h>
|
|
Packit |
ae235b |
#include <string.h>
|
|
Packit |
ae235b |
#include <glib.h>
|
|
Packit |
ae235b |
#include "inotify-kernel.h"
|
|
Packit |
ae235b |
#include <sys/inotify.h>
|
|
Packit |
ae235b |
#include <glib/glib-unix.h>
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
#include "glib-private.h"
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* From inotify(7) */
|
|
Packit |
ae235b |
#define MAX_EVENT_SIZE (sizeof(struct inotify_event) + NAME_MAX + 1)
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Amount of time to sleep on receipt of uninteresting events */
|
|
Packit |
ae235b |
#define BOREDOM_SLEEP_TIME (100 * G_TIME_SPAN_MILLISECOND)
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Define limits on the maximum amount of time and maximum amount of
|
|
Packit |
ae235b |
* interceding events between FROM/TO that can be merged.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
#define MOVE_PAIR_DELAY (10 * G_TIME_SPAN_MILLISECOND)
|
|
Packit |
ae235b |
#define MOVE_PAIR_DISTANCE (100)
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* We use the lock from inotify-helper.c
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* We only have to take it on our read callback.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* The rest of locking is taken care of in inotify-helper.c
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
G_LOCK_EXTERN (inotify_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static ik_event_t *
|
|
Packit |
ae235b |
ik_event_new (struct inotify_event *kevent,
|
|
Packit |
ae235b |
gint64 now)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
ik_event_t *event = g_new0 (ik_event_t, 1);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
event->wd = kevent->wd;
|
|
Packit |
ae235b |
event->mask = kevent->mask;
|
|
Packit |
ae235b |
event->cookie = kevent->cookie;
|
|
Packit |
ae235b |
event->len = kevent->len;
|
|
Packit |
ae235b |
event->timestamp = now;
|
|
Packit |
ae235b |
if (event->len)
|
|
Packit |
ae235b |
event->name = g_strdup (kevent->name);
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
event->name = NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return event;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
void
|
|
Packit |
ae235b |
_ik_event_free (ik_event_t *event)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (event->pair)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
event->pair->pair = NULL;
|
|
Packit |
ae235b |
_ik_event_free (event->pair);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_free (event->name);
|
|
Packit |
ae235b |
g_free (event);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
typedef struct
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GSource source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
GQueue queue;
|
|
Packit |
ae235b |
gpointer fd_tag;
|
|
Packit |
ae235b |
gint fd;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
GHashTable *unmatched_moves;
|
|
Packit |
ae235b |
gboolean is_bored;
|
|
Packit |
ae235b |
} InotifyKernelSource;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static InotifyKernelSource *inotify_source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gint64
|
|
Packit |
ae235b |
ik_source_get_dispatch_time (InotifyKernelSource *iks)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
ik_event_t *head;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
head = g_queue_peek_head (&iks->queue);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* nothing in the queue: not ready */
|
|
Packit |
ae235b |
if (!head)
|
|
Packit |
ae235b |
return -1;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* if it's not an unpaired move, it is ready now */
|
|
Packit |
ae235b |
if (~head->mask & IN_MOVED_FROM || head->pair)
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* if the queue is too long then it's ready now */
|
|
Packit |
ae235b |
if (iks->queue.length > MOVE_PAIR_DISTANCE)
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* otherwise, it's ready after the delay */
|
|
Packit |
ae235b |
return head->timestamp + MOVE_PAIR_DELAY;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
ik_source_can_dispatch_now (InotifyKernelSource *iks,
|
|
Packit |
ae235b |
gint64 now)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gint64 dispatch_time;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
dispatch_time = ik_source_get_dispatch_time (iks);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return 0 <= dispatch_time && dispatch_time <= now;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gsize
|
|
Packit |
ae235b |
ik_source_read_some_events (InotifyKernelSource *iks,
|
|
Packit |
ae235b |
gchar *buffer,
|
|
Packit |
ae235b |
gsize buffer_len)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gssize result;
|
|
Packit |
ae235b |
int errsv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
again:
|
|
Packit |
ae235b |
result = read (iks->fd, buffer, buffer_len);
|
|
Packit |
ae235b |
errsv = errno;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (result < 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (errsv == EINTR)
|
|
Packit |
ae235b |
goto again;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (errsv == EAGAIN)
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_error ("inotify read(): %s", g_strerror (errsv));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else if (result == 0)
|
|
Packit |
ae235b |
g_error ("inotify unexpectedly hit eof");
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return result;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gchar *
|
|
Packit |
ae235b |
ik_source_read_all_the_events (InotifyKernelSource *iks,
|
|
Packit |
ae235b |
gchar *buffer,
|
|
Packit |
ae235b |
gsize buffer_len,
|
|
Packit |
ae235b |
gsize *length_out)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gsize n_read;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
n_read = ik_source_read_some_events (iks, buffer, buffer_len);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Check if we might have gotten another event if we had passed in a
|
|
Packit |
ae235b |
* bigger buffer...
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
if (n_read + MAX_EVENT_SIZE > buffer_len)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gchar *new_buffer;
|
|
Packit |
ae235b |
guint n_readable;
|
|
Packit |
ae235b |
gint result;
|
|
Packit |
ae235b |
int errsv;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* figure out how many more bytes there are to read */
|
|
Packit |
ae235b |
result = ioctl (iks->fd, FIONREAD, &n_readable);
|
|
Packit |
ae235b |
errsv = errno;
|
|
Packit |
ae235b |
if (result != 0)
|
|
Packit |
ae235b |
g_error ("inotify ioctl(FIONREAD): %s", g_strerror (errsv));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (n_readable != 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* there is in fact more data. allocate a new buffer, copy
|
|
Packit |
ae235b |
* the existing data, and then append the remaining.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
new_buffer = g_malloc (n_read + n_readable);
|
|
Packit |
ae235b |
memcpy (new_buffer, buffer, n_read);
|
|
Packit |
ae235b |
n_read += ik_source_read_some_events (iks, new_buffer + n_read, n_readable);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
buffer = new_buffer;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* There may be new events in the buffer that were added after
|
|
Packit |
ae235b |
* the FIONREAD was performed, but we can't risk getting into
|
|
Packit |
ae235b |
* a loop. We'll get them next time.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
*length_out = n_read;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return buffer;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static gboolean
|
|
Packit |
ae235b |
ik_source_dispatch (GSource *source,
|
|
Packit |
ae235b |
GSourceFunc func,
|
|
Packit |
ae235b |
gpointer user_data)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
InotifyKernelSource *iks = (InotifyKernelSource *) source;
|
|
Packit |
ae235b |
gboolean (*user_callback) (ik_event_t *event) = (void *) func;
|
|
Packit |
ae235b |
gboolean interesting = FALSE;
|
|
Packit |
ae235b |
gint64 now;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
now = g_source_get_time (source);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (iks->is_bored || g_source_query_unix_fd (source, iks->fd_tag))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gchar stack_buffer[4096];
|
|
Packit |
ae235b |
gsize buffer_len;
|
|
Packit |
ae235b |
gchar *buffer;
|
|
Packit |
ae235b |
gsize offset;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* We want to read all of the available events.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* We need to do it in a finite number of steps so that we don't
|
|
Packit |
ae235b |
* get caught in a loop of read() with another process
|
|
Packit |
ae235b |
* continuously adding events each time we drain them.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* In the normal case we will have only a few events in the queue,
|
|
Packit |
ae235b |
* so start out by reading into a small stack-allocated buffer.
|
|
Packit |
ae235b |
* Even though we're on a fresh stack frame, there is no need to
|
|
Packit |
ae235b |
* pointlessly blow up with the size of the worker thread stack
|
|
Packit |
ae235b |
* with a huge buffer here.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* If the result is large enough to cause us to suspect that
|
|
Packit |
ae235b |
* another event may be pending then we allocate a buffer on the
|
|
Packit |
ae235b |
* heap that can hold all of the events and read (once!) into that
|
|
Packit |
ae235b |
* buffer.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
buffer = ik_source_read_all_the_events (iks, stack_buffer, sizeof stack_buffer, &buffer_len);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
offset = 0;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
while (offset < buffer_len)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
struct inotify_event *kevent = (struct inotify_event *) (buffer + offset);
|
|
Packit |
ae235b |
ik_event_t *event;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
event = ik_event_new (kevent, now);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
offset += sizeof (struct inotify_event) + event->len;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (event->mask & IN_MOVED_TO)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
ik_event_t *pair;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
pair = g_hash_table_lookup (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
|
Packit |
ae235b |
if (pair != NULL)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_assert (!pair->pair);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_hash_table_remove (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
|
Packit |
ae235b |
event->is_second_in_pair = TRUE;
|
|
Packit |
ae235b |
event->pair = pair;
|
|
Packit |
ae235b |
pair->pair = event;
|
|
Packit |
ae235b |
continue;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
interesting = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
else if (event->mask & IN_MOVED_FROM)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gboolean new;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
new = g_hash_table_insert (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie), event);
|
|
Packit |
ae235b |
if G_UNLIKELY (!new)
|
|
Packit |
ae235b |
g_warning ("inotify: got IN_MOVED_FROM event with already-pending cookie %#x", event->cookie);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
interesting = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_queue_push_tail (&iks->queue, event);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (buffer_len == 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* We can end up reading nothing if we arrived here due to a
|
|
Packit |
ae235b |
* boredom timer but the stream of events stopped meanwhile.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* In that case, we need to switch back to polling the file
|
|
Packit |
ae235b |
* descriptor in the usual way.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
g_assert (iks->is_bored);
|
|
Packit |
ae235b |
interesting = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (buffer != stack_buffer)
|
|
Packit |
ae235b |
g_free (buffer);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
while (ik_source_can_dispatch_now (iks, now))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
ik_event_t *event;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* callback will free the event */
|
|
Packit |
ae235b |
event = g_queue_pop_head (&iks->queue);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (event->mask & IN_MOVED_FROM && !event->pair)
|
|
Packit |
ae235b |
g_hash_table_remove (iks->unmatched_moves, GUINT_TO_POINTER (event->cookie));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_LOCK (inotify_lock);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
interesting |= (* user_callback) (event);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
G_UNLOCK (inotify_lock);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* The queue gets blocked iff we have unmatched moves */
|
|
Packit |
ae235b |
g_assert ((iks->queue.length > 0) == (g_hash_table_size (iks->unmatched_moves) > 0));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
/* Here's where we decide what will wake us up next.
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* If the last event was interesting then we will wake up on the fd or
|
|
Packit |
ae235b |
* when the timeout is reached on an unpaired move (if any).
|
|
Packit |
ae235b |
*
|
|
Packit |
ae235b |
* If the last event was uninteresting then we will wake up after the
|
|
Packit |
ae235b |
* shorter of the boredom sleep or any timeout for a unpaired move.
|
|
Packit |
ae235b |
*/
|
|
Packit |
ae235b |
if (interesting)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (iks->is_bored)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_source_modify_unix_fd (source, iks->fd_tag, G_IO_IN);
|
|
Packit |
ae235b |
iks->is_bored = FALSE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_set_ready_time (source, ik_source_get_dispatch_time (iks));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
else
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
guint64 dispatch_time = ik_source_get_dispatch_time (iks);
|
|
Packit |
ae235b |
guint64 boredom_time = now + BOREDOM_SLEEP_TIME;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (!iks->is_bored)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_source_modify_unix_fd (source, iks->fd_tag, 0);
|
|
Packit |
ae235b |
iks->is_bored = TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_set_ready_time (source, MIN (dispatch_time, boredom_time));
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return TRUE;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
static InotifyKernelSource *
|
|
Packit |
ae235b |
ik_source_new (gboolean (* callback) (ik_event_t *event))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
static GSourceFuncs source_funcs = {
|
|
Packit |
ae235b |
NULL, NULL,
|
|
Packit |
ae235b |
ik_source_dispatch
|
|
Packit |
ae235b |
/* should have a finalize, but it will never happen */
|
|
Packit |
ae235b |
};
|
|
Packit |
ae235b |
InotifyKernelSource *iks;
|
|
Packit |
ae235b |
GSource *source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
source = g_source_new (&source_funcs, sizeof (InotifyKernelSource));
|
|
Packit |
ae235b |
iks = (InotifyKernelSource *) source;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_set_name (source, "inotify kernel source");
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
iks->unmatched_moves = g_hash_table_new (NULL, NULL);
|
|
Packit |
ae235b |
iks->fd = inotify_init1 (IN_CLOEXEC);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (iks->fd < 0)
|
|
Packit |
ae235b |
iks->fd = inotify_init ();
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (iks->fd >= 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
GError *error = NULL;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_unix_set_fd_nonblocking (iks->fd, TRUE, &error);
|
|
Packit |
ae235b |
g_assert_no_error (error);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
iks->fd_tag = g_source_add_unix_fd (source, iks->fd, G_IO_IN);
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_set_callback (source, (GSourceFunc) callback, NULL, NULL);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_source_attach (source, GLIB_PRIVATE_CALL (g_get_worker_context) ());
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return iks;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
gboolean
|
|
Packit |
ae235b |
_ik_startup (gboolean (*cb)(ik_event_t *event))
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
if (g_once_init_enter (&inotify_source))
|
|
Packit |
ae235b |
g_once_init_leave (&inotify_source, ik_source_new (cb));
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return inotify_source->fd >= 0;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
gint32
|
|
Packit |
ae235b |
_ik_watch (const char *path,
|
|
Packit |
ae235b |
guint32 mask,
|
|
Packit |
ae235b |
int *err)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
gint32 wd = -1;
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (path != NULL);
|
|
Packit |
ae235b |
g_assert (inotify_source && inotify_source->fd >= 0);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
wd = inotify_add_watch (inotify_source->fd, path, mask);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (wd < 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
int e = errno;
|
|
Packit |
ae235b |
/* FIXME: debug msg failed to add watch */
|
|
Packit |
ae235b |
if (err)
|
|
Packit |
ae235b |
*err = e;
|
|
Packit |
ae235b |
return wd;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
g_assert (wd >= 0);
|
|
Packit |
ae235b |
return wd;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
int
|
|
Packit |
ae235b |
_ik_ignore (const char *path,
|
|
Packit |
ae235b |
gint32 wd)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
g_assert (wd >= 0);
|
|
Packit |
ae235b |
g_assert (inotify_source && inotify_source->fd >= 0);
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
if (inotify_rm_watch (inotify_source->fd, wd) < 0)
|
|
Packit |
ae235b |
{
|
|
Packit |
ae235b |
/* int e = errno; */
|
|
Packit |
ae235b |
/* failed to rm watch */
|
|
Packit |
ae235b |
return -1;
|
|
Packit |
ae235b |
}
|
|
Packit |
ae235b |
|
|
Packit |
ae235b |
return 0;
|
|
Packit |
ae235b |
}
|