aboutsummaryrefslogtreecommitdiff
path: root/devel/gamin
diff options
context:
space:
mode:
authorJoe Marcus Clarke <marcus@FreeBSD.org>2005-04-07 01:18:24 +0000
committerJoe Marcus Clarke <marcus@FreeBSD.org>2005-04-07 01:18:24 +0000
commit179b70aa163601c07e125523df06e401f4451d1f (patch)
treee73033d4e937f7abeb126e5110256499d187846c /devel/gamin
parent40bda7dba8415cb47f0185042bd527b1401b2b5f (diff)
downloadports-179b70aa163601c07e125523df06e401f4451d1f.tar.gz
ports-179b70aa163601c07e125523df06e401f4451d1f.zip
* When a file monitored with kqueue is moved or removed, gamin does
not monitor it anymore. The patch fixes the issue by adding moved/removed files to the exist_list, so that gamin detects when they are recreated * No CHANGED event is emitted for the files contained in a monitored directory, because kqueue can't do that. The patch adds periodic polling for these files * Instead of calling kevent() every second, the patch uses an I/O watch (g_io_add_watch()) PR: 79605 Submitted by: Jean-Yves Lefort <jylefort@brutele.be>
Notes
Notes: svn path=/head/; revision=132661
Diffstat (limited to 'devel/gamin')
-rw-r--r--devel/gamin/Makefile2
-rw-r--r--devel/gamin/files/patch-server_gam_kqueue.c286
2 files changed, 186 insertions, 102 deletions
diff --git a/devel/gamin/Makefile b/devel/gamin/Makefile
index 1bf34abb76b0..5ce791dcfc23 100644
--- a/devel/gamin/Makefile
+++ b/devel/gamin/Makefile
@@ -7,7 +7,7 @@
PORTNAME= gamin
PORTVERSION= 0.0.26
-PORTREVISION?= 8
+PORTREVISION?= 9
CATEGORIES?= devel
MASTER_SITES= http://www.gnome.org/~veillard/gamin/sources/
diff --git a/devel/gamin/files/patch-server_gam_kqueue.c b/devel/gamin/files/patch-server_gam_kqueue.c
index 3e5fe770e78d..cb20830e0363 100644
--- a/devel/gamin/files/patch-server_gam_kqueue.c
+++ b/devel/gamin/files/patch-server_gam_kqueue.c
@@ -1,8 +1,9 @@
---- server/gam_kqueue.c.orig Thu Mar 31 20:39:54 2005
-+++ server/gam_kqueue.c Fri Apr 1 01:09:11 2005
-@@ -0,0 +1,636 @@
+--- server/gam_kqueue.c.orig Wed Apr 6 22:46:40 2005
++++ server/gam_kqueue.c Wed Apr 6 22:47:16 2005
+@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2005 Joe Marcus Clarke <marcus@FreeBSD.org>
++ * Copyright (C) 2005 Jean-Yves Lefort <jylefort@brutele.be>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -22,6 +23,7 @@
+
+#include <config.h>
+#include <sys/types.h>
++#include <sys/stat.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <fcntl.h>
@@ -47,6 +49,23 @@
+ GSList *dirlist;
+} KQueueData;
+
++typedef struct
++{
++ ino_t ino;
++ mode_t mode;
++ uid_t uid;
++ gid_t gid;
++ time_t mtime;
++ time_t ctime;
++ off_t size;
++} MiniStat;
++
++typedef struct {
++ char *pathname;
++ char *filename; /* pointer into pathname */
++ MiniStat sb;
++} FileData;
++
+static GHashTable *dir_path_hash = NULL;
+static GHashTable *file_path_hash = NULL;
+static GHashTable *fd_hash = NULL;
@@ -80,70 +99,43 @@
+ return data;
+}
+
-+static GSList *
-+gam_kqueue_lsdir(const char *path)
++static void
++gam_kqueue_mini_stat (const char *pathname, MiniStat *mini_sb)
+{
-+ GDir *dir;
-+ GSList *lst = NULL;
-+ const gchar *entry;
-+
-+ if (!path)
-+ return NULL;
-+
-+ dir = g_dir_open(path, 0, NULL);
-+ if (!dir)
-+ return NULL;
-+
-+ entry = g_dir_read_name(dir);
-+
-+ while (entry) {
-+ lst = g_slist_prepend(lst, g_strdup(entry));
-+ entry = g_dir_read_name(dir);
++ struct stat sb;
++
++ if (lstat(pathname, &sb) == 0) {
++ mini_sb->ino = sb.st_ino;
++ mini_sb->mode = sb.st_mode;
++ mini_sb->uid = sb.st_uid;
++ mini_sb->gid = sb.st_gid;
++ mini_sb->mtime = sb.st_mtime;
++ mini_sb->ctime = sb.st_ctime;
++ mini_sb->size = sb.st_size;
++ } else {
++ memset(mini_sb, 0, sizeof(*mini_sb));
+ }
-+
-+ g_dir_close(dir);
-+
-+ return lst;
+}
+
-+static void
-+gam_kqueue_cmplst(GSList *lst1, GSList *lst2, GSList **added, GSList **deleted)
++static FileData *
++gam_kqueue_file_data_new (const char *path, const char *filename)
+{
-+ int found;
-+ GSList *l;
++ FileData *fdata;
+
-+ if (!lst1 && !lst2)
-+ return;
-+
-+ if (!lst1) {
-+ *added = g_slist_copy(lst2);
-+ return;
-+ }
-+
-+ if (!lst2) {
-+ *deleted = g_slist_copy(lst1);
-+ return;
-+ }
++ fdata = g_new(FileData, 1);
++ fdata->pathname = g_build_filename(path, filename, NULL);
++ fdata->filename = strrchr(fdata->pathname, G_DIR_SEPARATOR);
++ fdata->filename = fdata->filename ? fdata->filename + 1 : fdata->pathname;
++ gam_kqueue_mini_stat(fdata->pathname, &fdata->sb);
+
-+ for (l = lst1; l; l = l->next) {
-+ found = 0;
-+ if (g_slist_find_custom(lst2, l->data, (GCompareFunc)strcmp)) {
-+ found = 1;
-+ }
-+ if (found == 0) {
-+ *deleted = g_slist_prepend(*deleted, l->data);
-+ }
-+ }
++ return fdata;
++}
+
-+ for (l = lst2; l; l = l->next) {
-+ found = 0;
-+ if (g_slist_find_custom(lst1, l->data, (GCompareFunc)strcmp)) {
-+ found = 1;
-+ }
-+ if (found == 0) {
-+ *added = g_slist_prepend(*added, l->data);
-+ }
-+ }
++static void
++gam_kqueue_file_data_free (FileData *fdata)
++{
++ g_free(fdata->pathname);
++ g_free(fdata);
+}
+
+static void
@@ -151,7 +143,7 @@
+{
+ g_free(data->path);
+ if (data->dirlist) {
-+ g_slist_foreach(data->dirlist, (GFunc)g_free, NULL);
++ g_slist_foreach(data->dirlist, (GFunc)gam_kqueue_file_data_free, NULL);
+ g_slist_free(data->dirlist);
+ }
+ if (data->subs) {
@@ -160,6 +152,12 @@
+ g_free(data);
+}
+
++static int
++gam_kqueue_dirlist_find (FileData *fdata, const char *filename)
++{
++ return strcmp(fdata->filename, filename);
++}
++
+static void
+gam_kqueue_add_rm_handler(const char *path, GamSubscription *sub, gboolean added, gboolean was_missing)
+{
@@ -230,21 +228,29 @@
+ gam_server_emit_event (path, isdir, GAMIN_EVENT_CREATED, subs, 1);
+ }
+ if (gam_subscription_is_dir(sub) && isdir) {
-+ GSList *l;
++ GDir *dir;
+
+ data->isdir = TRUE;
-+ data->dirlist = gam_kqueue_lsdir(path);
++ data->dirlist = NULL;
+
-+ for (l = data->dirlist; l; l = l->next) {
-+ char *tmpentry;
++ dir = g_dir_open(path, 0, NULL);
++ if (dir) {
++ const char *entry;
++
++ while ((entry = g_dir_read_name(dir))) {
++ FileData *fdata;
++
++ fdata = gam_kqueue_file_data_new(path, entry);
++ data->dirlist = g_slist_prepend(data->dirlist, fdata);
+
-+ tmpentry = g_build_filename(path, l->data, NULL);
-+ if (!was_missing) {
-+ gam_server_emit_event (tmpentry,
-+ g_file_test(tmpentry, G_FILE_TEST_IS_DIR),
-+ GAMIN_EVENT_EXISTS, subs, 1);
++ if (!was_missing) {
++ gam_server_emit_event(fdata->pathname,
++ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR),
++ GAMIN_EVENT_EXISTS, subs, 1);
++ }
+ }
-+ g_free(tmpentry);
++
++ g_dir_close(dir);
+ }
+ }
+
@@ -332,44 +338,50 @@
+ isdir = g_file_test(data->path, G_FILE_TEST_IS_DIR);
+
+ if (gevent == GAMIN_EVENT_CHANGED && data->isdir) {
-+ GSList *dirlist = NULL, *added = NULL, *deleted = NULL;
++ GSList *dirlist = NULL;
+ GSList *l;
++ GDir *dir;
+
-+ dirlist = gam_kqueue_lsdir(data->path);
-+ gam_kqueue_cmplst(data->dirlist, dirlist, &added, &deleted);
-+ if (added || deleted) {
-+ for (l = deleted; l; l = l->next) {
-+ data->dirlist = g_slist_remove(data->dirlist, l->data);
-+ event_path = g_build_filename(data->path, l->data, NULL);
-+ g_free(l->data);
-+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
-+
-+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED) , event_path);
++ dir = g_dir_open(data->path, 0, NULL);
++ if (dir) {
++ const char *entry;
+
-+ gam_server_emit_event (event_path, isdir,
-+ GAMIN_EVENT_DELETED, data->subs, 1);
-+ g_free(event_path);
++ while ((entry = g_dir_read_name(dir))) {
++ dirlist = g_slist_prepend(dirlist, g_strdup(entry));
+ }
+
-+ for (l = added; l; l = l->next) {
-+ dirlist = g_slist_remove(dirlist, l->data);
-+ data->dirlist = g_slist_prepend(data->dirlist,
-+ g_strdup(l->data));
-+ event_path = g_build_filename(data->path, l->data, NULL);
-+ g_free(l->data);
-+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
++ g_dir_close(dir);
++ }
+
-+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CREATED) , event_path);
++ for (l = dirlist; l; l = l->next) {
++ if (! g_slist_find_custom(data->dirlist, l->data, (GCompareFunc) gam_kqueue_dirlist_find)) {
++ FileData *fdata;
+
-+ gam_server_emit_event (event_path, isdir,
-+ GAMIN_EVENT_CREATED, data->subs, 1);
-+ g_free(event_path);
++ fdata = gam_kqueue_file_data_new(data->path, l->data);
++ data->dirlist = g_slist_prepend(data->dirlist, fdata);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CREATED), fdata->pathname);
++ gam_server_emit_event(fdata->pathname,
++ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR),
++ GAMIN_EVENT_CREATED, data->subs, 1);
+ }
++ }
++
++ iterate:
++ for (l = data->dirlist; l; l = l->next) {
++ FileData *fdata = l->data;
++
++ if (! g_slist_find_custom(dirlist, fdata->filename, (GCompareFunc) strcmp)) {
++ data->dirlist = g_slist_remove(data->dirlist, fdata);
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED), fdata->pathname);
++ gam_server_emit_event(fdata->pathname,
++ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR),
++ GAMIN_EVENT_DELETED, data->subs, 1);
+
-+ if (added)
-+ g_slist_free(added);
-+ if (deleted)
-+ g_slist_free(deleted);
++ gam_kqueue_file_data_free(fdata);
++ goto iterate; /* list changed, start again */
++ }
+ }
+
+ if (dirlist) {
@@ -380,6 +392,22 @@
+ }
+ else {
+ event_path = g_strdup (data->path);
++
++ if (gevent == GAMIN_EVENT_DELETED
++ || gevent == GAMIN_EVENT_ENDEXISTS
++ || gevent == GAMIN_EVENT_MOVED) {
++ /* close and move to exist_list, to catch next creation */
++ close(data->fd);
++ if (data->isdir) {
++ g_hash_table_remove(dir_path_hash, data->path);
++ }
++ else {
++ g_hash_table_remove(file_path_hash, data->path);
++ }
++ g_hash_table_remove(fd_hash, GINT_TO_POINTER(data->fd));
++
++ exist_list = g_slist_append(exist_list, data);
++ }
+ }
+
+ isdir = g_file_test(event_path, G_FILE_TEST_IS_DIR);
@@ -418,8 +446,51 @@
+ return TRUE;
+}
+
++static void
++gam_kqueue_dirlist_check_cb (const char *path, KQueueData *data, gpointer user_data)
++{
++ GSList *l;
++
++ for (l = data->dirlist; l; l = l->next) {
++ FileData *fdata = l->data;
++ MiniStat sb;
++
++ gam_kqueue_mini_stat(fdata->pathname, &sb);
++
++ if (sb.mtime != fdata->sb.mtime
++ || sb.ctime != fdata->sb.ctime
++ || sb.size != fdata->sb.size
++ || sb.mode != fdata->sb.mode
++ || sb.uid != fdata->sb.uid
++ || sb.gid != fdata->sb.gid
++ || sb.ino != fdata->sb.ino)
++ {
++ memcpy(&fdata->sb, &sb, sizeof(sb));
++
++ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_CHANGED), fdata->pathname);
++ gam_server_emit_event(fdata->pathname,
++ g_file_test(fdata->pathname, G_FILE_TEST_IS_DIR),
++ GAMIN_EVENT_CHANGED, data->subs, 1);
++ }
++ }
++}
++
++static gboolean
++gam_kqueue_dirlist_check (gpointer user_data)
++{
++ G_LOCK(kqueue);
++
++ GAM_DEBUG(DEBUG_INFO, "gam_kqueue_dirlist_check()\n");
++
++ g_hash_table_foreach(dir_path_hash, (GHFunc) gam_kqueue_dirlist_check_cb, NULL);
++
++ G_UNLOCK(kqueue);
++
++ return TRUE;
++}
++
+static gboolean
-+gam_kqueue_event_handler (gpointer user_data)
++gam_kqueue_event_handler (GIOChannel *source, GIOCondition condition, gpointer user_data)
+{
+ KQueueData *data;
+ struct kevent ev[1];
@@ -531,6 +602,8 @@
+gboolean
+gam_kqueue_init(void)
+{
++ GIOChannel *channel;
++
+ kq = kqueue();
+ if (kq == -1) {
+ GAM_DEBUG(DEBUG_INFO, "Could not initialize a new kqueue\n");
@@ -538,12 +611,23 @@
+ }
+
+ g_timeout_add(1000, gam_kqueue_exist_check, NULL);
-+ g_timeout_add(1000, gam_kqueue_event_handler, NULL);
++
++ channel = g_io_channel_unix_new(kq);
++ g_io_add_watch(channel, G_IO_IN, gam_kqueue_event_handler, NULL);
+
+ dir_path_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ file_path_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ fd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
+
++ /*
++ * gam_kqueue_dirlist_check() has to lstat() every file in every
++ * monitored directory. This can easily become an intensive task
++ * if a few large directories are monitored (for instance a mail
++ * checker monitoring a couple of MH folders), therefore we use a
++ * reasonable poll interval (6 seconds, same as FAM's default).
++ */
++ g_timeout_add(6000, gam_kqueue_dirlist_check, NULL);
++
+ GAM_DEBUG(DEBUG_INFO, "kqueue initialized\n");
+
+ gam_backend_add_subscription = gam_kqueue_add_subscription;