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 ++ * Copyright (C) 2005 Jean-Yves Lefort + * + * 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 +#include ++#include +#include +#include +#include @@ -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; ++ struct stat sb; + -+ 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); ++ 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); ++static FileData * ++gam_kqueue_file_data_new (const char *path, const char *filename) ++{ ++ FileData *fdata; + -+ return lst; ++ 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); ++ ++ return fdata; +} + +static void -+gam_kqueue_cmplst(GSList *lst1, GSList *lst2, GSList **added, GSList **deleted) ++gam_kqueue_file_data_free (FileData *fdata) +{ -+ int found; -+ GSList *l; -+ -+ if (!lst1 && !lst2) -+ return; -+ -+ if (!lst1) { -+ *added = g_slist_copy(lst2); -+ return; -+ } -+ -+ if (!lst2) { -+ *deleted = g_slist_copy(lst1); -+ return; -+ } -+ -+ 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); -+ } -+ } -+ -+ 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); -+ } -+ } ++ 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; + -+ 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); ++ 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); ++ ++ 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); ++ dir = g_dir_open(data->path, 0, NULL); ++ if (dir) { ++ const char *entry; + -+ GAM_DEBUG(DEBUG_INFO, "kqueue emitting event %s for %s\n", gam_event_to_string(GAMIN_EVENT_DELETED) , event_path); -+ -+ 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); + } ++ } + -+ if (added) -+ g_slist_free(added); -+ if (deleted) -+ g_slist_free(deleted); ++ 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); ++ ++ 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_event_handler (gpointer user_data) ++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 (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;