/* gamin inotify backend
* Copyright (C) 2005 John McCutchan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "server_config.h"
#include <string.h>
/* Just include the local header to stop all the pain */
#include "local_inotify.h"
#if 0
#ifdef HAVE_SYS_INOTIFY_H
/* We don't actually include the libc header, because there has been
* problems with libc versions that was built without inotify support.
* Instead we use the local version.
*/
#include "local_inotify.h"
#elif defined (HAVE_LINUX_INOTIFY_H)
#include <linux/inotify.h>
#endif
#endif
#include "inotify-sub.h"
#include "inotify-helper.h"
#include "inotify-diag.h"
#ifdef GAMIN_DEBUG_API
#include "gam_debugging.h"
#endif
#include "gam_error.h"
#include "gam_event.h"
#include "gam_server.h"
#include "gam_subscription.h"
#include "gam_inotify.h"
/* Transforms a inotify event to a gamin event. */
static GaminEventType
ih_mask_to_EventType (guint32 mask)
{
mask &= ~IN_ISDIR;
switch (mask)
{
case IN_MODIFY:
return GAMIN_EVENT_CHANGED;
break;
case IN_ATTRIB:
return GAMIN_EVENT_CHANGED;
break;
case IN_MOVE_SELF:
case IN_MOVED_FROM:
case IN_DELETE:
case IN_DELETE_SELF:
return GAMIN_EVENT_DELETED;
break;
case IN_CREATE:
case IN_MOVED_TO:
return GAMIN_EVENT_CREATED;
break;
case IN_Q_OVERFLOW:
case IN_OPEN:
case IN_CLOSE_WRITE:
case IN_CLOSE_NOWRITE:
case IN_UNMOUNT:
case IN_ACCESS:
case IN_IGNORED:
default:
return -1;
break;
}
}
static void
gam_inotify_send_initial_events (const char *pathname, GamSubscription *sub, gboolean is_dir, gboolean was_missing)
{
GaminEventType gevent;
if (was_missing) {
gevent = GAMIN_EVENT_CREATED;
} else {
if (g_file_test (pathname, G_FILE_TEST_EXISTS))
gevent = GAMIN_EVENT_EXISTS;
else
gevent = GAMIN_EVENT_DELETED;
}
gam_server_emit_one_event (pathname, is_dir ? 1 : 0, gevent, sub, 1);
if (is_dir)
{
GDir *dir;
GError *err = NULL;
dir = g_dir_open (pathname, 0, &err);
if (dir)
{
const char *filename;
while ((filename = g_dir_read_name (dir)))
{
gchar *fullname = g_strdup_printf ("%s/%s", pathname, filename);
gboolean file_is_dir = FALSE;
struct stat fsb;
memset(&fsb, 0, sizeof (struct stat));
lstat(fullname, &fsb);
file_is_dir = (fsb.st_mode & S_IFDIR) != 0 ? TRUE : FALSE;
gam_server_emit_one_event (fullname, file_is_dir ? 1 : 0, gevent, sub, 1);
g_free (fullname);
}
g_dir_close (dir);
} else {
GAM_DEBUG (DEBUG_INFO, "unable to open directory %s: %s\n", pathname, err->message);
g_error_free (err);
}
}
if (!was_missing)
{
gam_server_emit_one_event (pathname, is_dir ? 1 : 0, GAMIN_EVENT_ENDEXISTS, sub, 1);
}
}
static void
gam_inotify_event_callback (const char *fullpath, guint32 mask, void *subdata)
{
GamSubscription *sub = (GamSubscription *)subdata;
GaminEventType gevent;
gevent = ih_mask_to_EventType (mask);
gam_server_emit_one_event (fullpath, gam_subscription_is_dir (sub), gevent, sub, 1);
}
static void
gam_inotify_found_callback (const char *fullpath, void *subdata)
{
GamSubscription *sub = (GamSubscription *)subdata;
gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), TRUE);
}
gboolean
gam_inotify_init (void)
{
gam_poll_basic_init ();
gam_server_install_kernel_hooks (GAMIN_K_INOTIFY2,
gam_inotify_add_subscription,
gam_inotify_remove_subscription,
gam_inotify_remove_all_for,
NULL, NULL);
return ih_startup (gam_inotify_event_callback,
gam_inotify_found_callback);
}
gboolean
gam_inotify_add_subscription (GamSubscription *sub)
{
ih_sub_t *isub = NULL;
gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
isub = ih_sub_new (gam_subscription_get_path (sub), gam_subscription_is_dir (sub), 0, sub);
if (!ih_sub_add (isub))
{
ih_sub_free (isub);
return FALSE;
}
gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), FALSE);
return TRUE;
}
static gboolean
gam_inotify_remove_sub_pred (ih_sub_t *sub, void *callerdata)
{
return sub->usersubdata == callerdata;
}
gboolean
gam_inotify_remove_subscription (GamSubscription *sub)
{
ih_sub_foreach_free (sub, gam_inotify_remove_sub_pred);
return TRUE;
}
static gboolean
gam_inotify_remove_listener_pred (ih_sub_t *sub, void *callerdata)
{
GamSubscription *gsub = (GamSubscription *)sub->usersubdata;
return gam_subscription_get_listener (gsub) == callerdata;
}
gboolean
gam_inotify_remove_all_for (GamListener *listener)
{
ih_sub_foreach_free (listener, gam_inotify_remove_listener_pred);
return TRUE;
}
void
gam_inotify_debug (void)
{
id_dump (NULL);
}
gboolean
gam_inotify_is_running (void)
{
return ih_running ();
}
syntax highlighted by Code2HTML, v. 0.9.1