summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app-admin/gamin')
-rw-r--r--app-admin/gamin/ChangeLog12
-rw-r--r--app-admin/gamin/Manifest45
-rw-r--r--app-admin/gamin/files/digest-gamin-0.1.76
-rw-r--r--app-admin/gamin/files/gamin-0.1.7-sigaction.patch60
-rw-r--r--app-admin/gamin/files/gamin-dont-close-fd.patch72
-rw-r--r--app-admin/gamin/files/gamin-flush-buffer-on-reset.patch15
-rw-r--r--app-admin/gamin/files/gamin-inotify-fix.patch93
-rw-r--r--app-admin/gamin/files/gamin-new-inotify-backend.patch3643
-rw-r--r--app-admin/gamin/files/gamin-no-timers.patch284
-rw-r--r--app-admin/gamin/files/gamin-stdin-devnull.patch36
-rw-r--r--app-admin/gamin/files/gamin-timer-on-demand.patch73
-rw-r--r--app-admin/gamin/gamin-0.1.7.ebuild73
12 files changed, 0 insertions, 4412 deletions
diff --git a/app-admin/gamin/ChangeLog b/app-admin/gamin/ChangeLog
deleted file mode 100644
index 395bf44..0000000
--- a/app-admin/gamin/ChangeLog
+++ /dev/null
@@ -1,12 +0,0 @@
-# ChangeLog for app-admin/gamin
-# Copyright 1999-2006 Gentoo Foundation; Distributed under the GPL v2
-# $Header: $
-
- 18 Sep 2006; Mart Raudsepp <leio@gentoo.org> ChangeLog:
- Updates from Fedora that should bring the package close to the state of
- upstream right now. This solves gam_server waking up tens of times every
- second even if inotify is used, mostly thanks to the new inotify backend
- from upstream being more sane and closer to gnome-vfs code. Probably has
- more affect on kdelibs-3.5 than on GNOME-2.16 (gnome-vfs has a sane inotify
- backend already there, KDE seems to use FAM API at least here).
-
diff --git a/app-admin/gamin/Manifest b/app-admin/gamin/Manifest
deleted file mode 100644
index 665ce79..0000000
--- a/app-admin/gamin/Manifest
+++ /dev/null
@@ -1,45 +0,0 @@
-AUX gamin-0.1.7-sigaction.patch 2094 RMD160 4adb9ebdff2ff9fe4c0d187820257aeab39cb5f0 SHA1 7c2cdb5c946bfe102388a8e0c4cfb820afdb2fa0 SHA256 37b34efa0c7fe80cdda92b638f5663838d98547f511c77f07f86d58b5426a3a2
-MD5 c6bee72840f1ca2c4fb10fd4d0cba679 files/gamin-0.1.7-sigaction.patch 2094
-RMD160 4adb9ebdff2ff9fe4c0d187820257aeab39cb5f0 files/gamin-0.1.7-sigaction.patch 2094
-SHA256 37b34efa0c7fe80cdda92b638f5663838d98547f511c77f07f86d58b5426a3a2 files/gamin-0.1.7-sigaction.patch 2094
-AUX gamin-dont-close-fd.patch 1855 RMD160 f66ccd63aa54631c3dd8ce5bfbd7850527cfb424 SHA1 cb668a95dab4946f12e6fcfb3d9123419bd10a81 SHA256 4bca072677e94b7772ee84cfea5777fc3593ee018ca58c8f7e0db65024ad4fb8
-MD5 3e6228d3bcdf46459ae37963b7434287 files/gamin-dont-close-fd.patch 1855
-RMD160 f66ccd63aa54631c3dd8ce5bfbd7850527cfb424 files/gamin-dont-close-fd.patch 1855
-SHA256 4bca072677e94b7772ee84cfea5777fc3593ee018ca58c8f7e0db65024ad4fb8 files/gamin-dont-close-fd.patch 1855
-AUX gamin-flush-buffer-on-reset.patch 497 RMD160 452596c00ef970d278febf18a4b5289a65331993 SHA1 a847fb650609fa2ac671ed6c1b79db6ab9b5de9e SHA256 ee367da8774e43cfee29ea1ed3673fcb3ebf1e61ee6d3511ff5d5b5bb9676be1
-MD5 7c1341735c4ee16239713606f55c51d9 files/gamin-flush-buffer-on-reset.patch 497
-RMD160 452596c00ef970d278febf18a4b5289a65331993 files/gamin-flush-buffer-on-reset.patch 497
-SHA256 ee367da8774e43cfee29ea1ed3673fcb3ebf1e61ee6d3511ff5d5b5bb9676be1 files/gamin-flush-buffer-on-reset.patch 497
-AUX gamin-inotify-fix.patch 2900 RMD160 c6a4d843880bfd8781e98184bea8234edb401486 SHA1 b9e90827730740c62d6b636e6ceb97e1588146dc SHA256 5c6fafd88cd486392492d1f088460aeeb83e6570f0d746fc7d3dfc8e678091d3
-MD5 56cdf4d179fef49c08f0c8655a1dc441 files/gamin-inotify-fix.patch 2900
-RMD160 c6a4d843880bfd8781e98184bea8234edb401486 files/gamin-inotify-fix.patch 2900
-SHA256 5c6fafd88cd486392492d1f088460aeeb83e6570f0d746fc7d3dfc8e678091d3 files/gamin-inotify-fix.patch 2900
-AUX gamin-new-inotify-backend.patch 99430 RMD160 1df3158c04db0ed144c001cbcdb364a9b65ede85 SHA1 a7b6775699514a951a60d54beb102f56a80cbc1c SHA256 e13763617867afd9873c78b2d073e8ef6f4388837a0461cd9c600217a14897cf
-MD5 413015c52f80b43df66a7b2b5d2e8489 files/gamin-new-inotify-backend.patch 99430
-RMD160 1df3158c04db0ed144c001cbcdb364a9b65ede85 files/gamin-new-inotify-backend.patch 99430
-SHA256 e13763617867afd9873c78b2d073e8ef6f4388837a0461cd9c600217a14897cf files/gamin-new-inotify-backend.patch 99430
-AUX gamin-no-timers.patch 7904 RMD160 686a7a517da9e6951d8aeeb3c3b0eb8d71bd89cc SHA1 6d0b1aca14f339ac40b8a4ada439c7884b489eaf SHA256 6b3fd0a9e380238b02e0b9e811704385a98bf09ddcc550ab77e991a2b4166372
-MD5 4543065e8bd2ca72ca2e42177178621a files/gamin-no-timers.patch 7904
-RMD160 686a7a517da9e6951d8aeeb3c3b0eb8d71bd89cc files/gamin-no-timers.patch 7904
-SHA256 6b3fd0a9e380238b02e0b9e811704385a98bf09ddcc550ab77e991a2b4166372 files/gamin-no-timers.patch 7904
-AUX gamin-stdin-devnull.patch 941 RMD160 2387e8b830b03fca10f4aad4b0b94ab1b0386554 SHA1 516cf3bf0144dd2aab7294f2c102c7badb6b5a6e SHA256 d11e074d3f6f60bbc9c50fdfd26d10452efc6977069e1e7053b34c15c37f9749
-MD5 2916fe4b8475ff590dde1e3af2c31871 files/gamin-stdin-devnull.patch 941
-RMD160 2387e8b830b03fca10f4aad4b0b94ab1b0386554 files/gamin-stdin-devnull.patch 941
-SHA256 d11e074d3f6f60bbc9c50fdfd26d10452efc6977069e1e7053b34c15c37f9749 files/gamin-stdin-devnull.patch 941
-AUX gamin-timer-on-demand.patch 2158 RMD160 458e15efb47c34145a20a4c0ced4e317495184ac SHA1 4dd5d64bf4bfc2e12709a7fbd72ffa3db1524e06 SHA256 581406841da596fda8125d96ca6f118991f0e1242ff334e61f91f0eaf4f6d3c0
-MD5 1e32b6a24c047c3333c6a48cd6c5faf5 files/gamin-timer-on-demand.patch 2158
-RMD160 458e15efb47c34145a20a4c0ced4e317495184ac files/gamin-timer-on-demand.patch 2158
-SHA256 581406841da596fda8125d96ca6f118991f0e1242ff334e61f91f0eaf4f6d3c0 files/gamin-timer-on-demand.patch 2158
-DIST gamin-0.1.7-freebsd.patch.bz2 5217 RMD160 22ee7ccac4cca87188bf299404186d3c5ea08475 SHA1 31ca1fdf8e21f9a0ac3a98b7865e3ab0d3c6c471 SHA256 8c77200b1fac6f1a65819a38ab54767f8a25ffbe990cde5f500eec040d815fbf
-DIST gamin-0.1.7.tar.gz 542061 RMD160 440b6afc682806b33aa275e3b8a593dc7e3f93de SHA1 bde971a10a3510626d501db3a746370c8931612a SHA256 8272c64356e1310353f2411b2cabd211468edbf8ce312d58aeef55889e79361a
-EBUILD gamin-0.1.7.ebuild 2146 RMD160 b4102373b6cbb17b0ef61ea310c4daf9a118c4c1 SHA1 dbc1b31da24fd6ed35e0584bae8d7b9086efc762 SHA256 962656a3f618fdeccd796868128d83777c77b046b5e970b7e8fbd015c2751a6e
-MD5 3a4be71ee1f2bccb8e17bdafb1f6d7f7 gamin-0.1.7.ebuild 2146
-RMD160 b4102373b6cbb17b0ef61ea310c4daf9a118c4c1 gamin-0.1.7.ebuild 2146
-SHA256 962656a3f618fdeccd796868128d83777c77b046b5e970b7e8fbd015c2751a6e gamin-0.1.7.ebuild 2146
-MISC ChangeLog 618 RMD160 2997214c80b9bf3b8f89e1de953b007c8354b845 SHA1 25e513c5e550e474dece2fa2f4f6688bf8711adc SHA256 d2499af2b08e58ae58f2895d6a86d519b377de29502192162ee7498ad2c728ac
-MD5 f5bd40e6ef1b092c3077e84a3547f378 ChangeLog 618
-RMD160 2997214c80b9bf3b8f89e1de953b007c8354b845 ChangeLog 618
-SHA256 d2499af2b08e58ae58f2895d6a86d519b377de29502192162ee7498ad2c728ac ChangeLog 618
-MD5 469372237b50836ef50ad51b93c9bf96 files/digest-gamin-0.1.7 497
-RMD160 7062a11132fc5e1d4f3313ce32e42873ebf6d4f5 files/digest-gamin-0.1.7 497
-SHA256 65c5ef16d64495211c6d24b345c15af401df9ad0c4baad29eb3b2095421f6ef9 files/digest-gamin-0.1.7 497
diff --git a/app-admin/gamin/files/digest-gamin-0.1.7 b/app-admin/gamin/files/digest-gamin-0.1.7
deleted file mode 100644
index 8a5560f..0000000
--- a/app-admin/gamin/files/digest-gamin-0.1.7
+++ /dev/null
@@ -1,6 +0,0 @@
-MD5 fe942c8202fdee10e1bf139ae8a698a0 gamin-0.1.7-freebsd.patch.bz2 5217
-RMD160 22ee7ccac4cca87188bf299404186d3c5ea08475 gamin-0.1.7-freebsd.patch.bz2 5217
-SHA256 8c77200b1fac6f1a65819a38ab54767f8a25ffbe990cde5f500eec040d815fbf gamin-0.1.7-freebsd.patch.bz2 5217
-MD5 1a1991ffa749b7dc2cc0573d6a2867b8 gamin-0.1.7.tar.gz 542061
-RMD160 440b6afc682806b33aa275e3b8a593dc7e3f93de gamin-0.1.7.tar.gz 542061
-SHA256 8272c64356e1310353f2411b2cabd211468edbf8ce312d58aeef55889e79361a gamin-0.1.7.tar.gz 542061
diff --git a/app-admin/gamin/files/gamin-0.1.7-sigaction.patch b/app-admin/gamin/files/gamin-0.1.7-sigaction.patch
deleted file mode 100644
index 3457c3a..0000000
--- a/app-admin/gamin/files/gamin-0.1.7-sigaction.patch
+++ /dev/null
@@ -1,60 +0,0 @@
-diff -urN gamin-0.1.7/lib/gam_error.c /gnome/head/cvs/gamin/lib/gam_error.c
---- gamin-0.1.7/lib/gam_error.c 2005-09-08 09:46:45.000000000 +0200
-+++ /gnome/head/cvs/gamin/lib/gam_error.c 2006-06-01 11:59:14.000000000 +0200
-@@ -76,7 +76,7 @@
- gam_error_init(void)
- {
- if (initialized == 0) {
-- signal_handler prev;
-+ struct sigaction oldact;
-
- initialized = 1;
-
-@@ -89,11 +89,12 @@
- gam_error_handle_signal();
- }
-
-- prev = signal(SIGUSR2, gam_error_signal);
-- /* if there is already an handler switch back to the original
-- * to avoid disturbing the application behaviour */
-- if ((prev != SIG_IGN) && (prev != SIG_DFL) && (prev != NULL))
-- signal(SIGUSR2, prev);
-+ /* if there is already an handler, leave it as is to
-+ * avoid disturbing the application's behaviour */
-+ if (sigaction (SIGUSR2, NULL, &oldact) == 0) {
-+ if (oldact.sa_handler == NULL && oldact.sa_sigaction == NULL)
-+ signal(SIGUSR2, gam_error_signal);
-+ }
- }
- }
-
-diff -urN gamin-0.1.7/libgamin/gam_error.c /gnome/head/cvs/gamin/libgamin/gam_error.c
---- gamin-0.1.7/libgamin/gam_error.c 2005-10-25 16:16:51.000000000 +0200
-+++ /gnome/head/cvs/gamin/libgamin/gam_error.c 2006-06-01 12:00:09.000000000 +0200
-@@ -76,7 +76,7 @@
- gam_error_init(void)
- {
- if (initialized == 0) {
-- signal_handler prev;
-+ struct sigaction oldact;
-
- initialized = 1;
-
-@@ -89,11 +89,12 @@
- gam_error_handle_signal();
- }
-
-- prev = signal(SIGUSR2, gam_error_signal);
-- /* if there is already an handler switch back to the original
-- * to avoid disturbing the application behaviour */
-- if ((prev != SIG_IGN) && (prev != SIG_DFL) && (prev != NULL))
-- signal(SIGUSR2, prev);
-+ /* if there is already an handler, leave it as is to
-+ * avoid disturbing the application's behaviour */
-+ if (sigaction (SIGUSR2, NULL, &oldact) == 0) {
-+ if (oldact.sa_handler == NULL && oldact.sa_sigaction == NULL)
-+ signal(SIGUSR2, gam_error_signal);
-+ }
- }
- }
-
diff --git a/app-admin/gamin/files/gamin-dont-close-fd.patch b/app-admin/gamin/files/gamin-dont-close-fd.patch
deleted file mode 100644
index d95f599..0000000
--- a/app-admin/gamin/files/gamin-dont-close-fd.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-Index: libgamin/gam_api.c
-===================================================================
-RCS file: /cvs/gnome/gamin/libgamin/gam_api.c,v
-retrieving revision 1.39
-diff -u -p -r1.39 gam_api.c
---- libgamin/gam_api.c 5 Aug 2005 14:06:49 -0000 1.39
-+++ libgamin/gam_api.c 16 Aug 2006 14:59:27 -0000
-@@ -744,7 +744,6 @@ retry:
- return(0);
-
- failed:
-- close(fd);
- return (-1);
- }
-
-@@ -891,39 +890,38 @@ gamin_try_reconnect(GAMDataPtr conn, int
- /*
- * try to reopen a connection to the server
- */
-- close(fd);
- newfd = gamin_connect_unix_socket(socket_name);
--
- free(socket_name);
- if (newfd < 0) {
- return (-1);
- }
-
-- if (newfd != fd) {
-- /*
-- * reuse the same descriptor
-- */
-- ret = dup2(newfd, fd);
-- if (ret < 0) {
-- gam_error(DEBUG_INFO,
-- "Failed to reuse descriptor %d on reconnect\n",
-- fd);
-- close(newfd);
-- return (-1);
-- }
-- }
--
- /*
- * seems we managed to rebuild a connection to the server.
- * start the authentication again and resubscribe all existing
- * monitoring commands.
- */
-- ret = gamin_write_credential_byte(fd);
-+ ret = gamin_write_credential_byte(newfd);
- if (ret != 0) {
-- close(fd);
-+ close(newfd);
- return (-1);
- }
-
-+ /*
-+ * reuse the same descriptor. We never close the original fd, dup2
-+ * atomically overwrites it and closes the original. This way we
-+ * never leave the original fd closed, since that can cause trouble
-+ * if the app keeps the fd around.
-+ */
-+ ret = dup2(newfd, fd);
-+ close(newfd);
-+ if (ret < 0) {
-+ gam_error(DEBUG_INFO,
-+ "Failed to reuse descriptor %d on reconnect\n",
-+ fd);
-+ return (-1);
-+ }
-+
- nb_req = gamin_data_reset(conn, &reqs);
- if (reqs != NULL) {
- for (i = 0; i < nb_req;i++) {
diff --git a/app-admin/gamin/files/gamin-flush-buffer-on-reset.patch b/app-admin/gamin/files/gamin-flush-buffer-on-reset.patch
deleted file mode 100644
index e9f3253..0000000
--- a/app-admin/gamin/files/gamin-flush-buffer-on-reset.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-Index: libgamin/gam_data.c
-===================================================================
-RCS file: /cvs/gnome/gamin/libgamin/gam_data.c,v
-retrieving revision 1.18
-diff -u -p -r1.18 gam_data.c
---- libgamin/gam_data.c 11 Aug 2006 09:29:53 -0000 1.18
-+++ libgamin/gam_data.c 28 Aug 2006 09:25:26 -0000
-@@ -539,6 +539,7 @@ gamin_data_reset(GAMDataPtr conn, GAMReq
- conn->reqno = 1;
- conn->restarted = 1;
- conn->evn_ready = 0;
-+ conn->evn_read = 0;
- return(conn->req_nr);
- }
-
diff --git a/app-admin/gamin/files/gamin-inotify-fix.patch b/app-admin/gamin/files/gamin-inotify-fix.patch
deleted file mode 100644
index 26a3cce..0000000
--- a/app-admin/gamin/files/gamin-inotify-fix.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-Index: server/gam_connection.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_connection.c,v
-retrieving revision 1.31
-diff -u -p -r1.31 gam_connection.c
---- server/gam_connection.c 5 Sep 2006 14:26:56 -0000 1.31
-+++ server/gam_connection.c 8 Sep 2006 12:42:41 -0000
-@@ -108,7 +108,8 @@ gam_connection_close(GamConnDataPtr conn
- g_assert(conn->source);
-
- /* Kill the queue event source */
-- g_source_remove (conn->eq_source);
-+ if (conn->eq_source != 0)
-+ g_source_remove (conn->eq_source);
- /* Flush the event queue */
- gam_eq_flush (conn->eq, conn);
- /* Kill the event queue */
-Index: server/gam_inotify.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v
-retrieving revision 1.52
-diff -u -p -r1.52 gam_inotify.c
---- server/gam_inotify.c 5 Sep 2006 14:17:20 -0000 1.52
-+++ server/gam_inotify.c 8 Sep 2006 12:42:41 -0000
-@@ -161,6 +161,9 @@ 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))
-Index: server/inotify-helper.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/inotify-helper.c,v
-retrieving revision 1.1
-diff -u -p -r1.1 inotify-helper.c
---- server/inotify-helper.c 5 Sep 2006 00:49:00 -0000 1.1
-+++ server/inotify-helper.c 8 Sep 2006 12:42:41 -0000
-@@ -161,28 +161,21 @@ static void
- ih_sub_foreach_worker (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata), gboolean free)
- {
- GList *l = NULL;
-- GList *removed = NULL;
-+ GList *next = NULL;
-
- G_LOCK(inotify_lock);
-
-- for (l = sub_list; l; l = l->next)
-+ for (l = sub_list; l; l = next)
- {
- ih_sub_t *sub = l->data;
--
-+ next = l->next;
-+
- if (f(sub, callerdata))
- {
-- removed = g_list_prepend (removed, l);
-- ih_sub_cancel (sub);
-+ ih_sub_cancel (sub); /* Removes sub from sub_list */
- if (free)
- ih_sub_free (sub);
- }
-- }
--
-- for (l = removed; l ; l = l->next)
-- {
-- GList *llink = l->data;
-- sub_list = g_list_remove_link (sub_list, llink);
-- g_list_free_1 (llink);
- }
-
- G_UNLOCK(inotify_lock);
-Index: server/inotify-sub.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/inotify-sub.c,v
-retrieving revision 1.1
-diff -u -p -r1.1 inotify-sub.c
---- server/inotify-sub.c 5 Sep 2006 00:49:00 -0000 1.1
-+++ server/inotify-sub.c 8 Sep 2006 12:42:41 -0000
-@@ -71,9 +71,7 @@ gchar *ih_sub_get_dirname (gchar *pathna
- static
- gchar *ih_sub_get_filename (gchar *pathname)
- {
-- gchar *out;
-- // FIXME: return filename here
-- return out;
-+ return g_path_get_basename (pathname);
- }
-
- static
diff --git a/app-admin/gamin/files/gamin-new-inotify-backend.patch b/app-admin/gamin/files/gamin-new-inotify-backend.patch
deleted file mode 100644
index 5917559..0000000
--- a/app-admin/gamin/files/gamin-new-inotify-backend.patch
+++ /dev/null
@@ -1,3643 +0,0 @@
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-missing.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,34 @@
-+/* inotify-helper.h - GNOME VFS Monitor using inotify
-+
-+ Copyright (C) 2006 John McCutchan <john@johnmccutchan.com>
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Author: John McCutchan <ttb@tentacle.dhs.org>
-+*/
-+
-+
-+#ifndef __INOTIFY_MISSING_H
-+#define __INOTIFY_MISSING_H
-+
-+#include "inotify-sub.h"
-+
-+void im_startup (void (*missing_cb)(ih_sub_t *sub));
-+void im_add (ih_sub_t *sub);
-+void im_rm (ih_sub_t *sub);
-+void im_diag_dump (GIOChannel *ioc);
-+
-+#endif /* __INOTIFY_MISSING_H */
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-kernel.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,40 @@
-+/*
-+ Copyright (C) 2006 John McCutchan <john@johnmccutchan.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; version 2.
-+
-+ This program 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 General Public License version 2 for more details.
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software Foundation,
-+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+*/
-+
-+#ifndef __INOTIFY_KERNEL_H
-+#define __INOTIFY_KERNEL_H
-+
-+typedef struct ik_event_s {
-+ gint32 wd;
-+ guint32 mask;
-+ guint32 cookie;
-+ guint32 len;
-+ char * name;
-+ struct ik_event_s *pair;
-+} ik_event_t;
-+
-+gboolean ik_startup (void (*cb)(ik_event_t *event));
-+ik_event_t *ik_event_new_dummy (const char *name, gint32 wd, guint32 mask);
-+void ik_event_free (ik_event_t *event);
-+
-+gint32 ik_watch(const char *path, guint32 mask, int *err);
-+int ik_ignore(const char *path, gint32 wd);
-+
-+/* The miss count will probably be enflated */
-+void ik_move_stats (guint32 *matches, guint32 *misses);
-+const char *ik_mask_to_string (guint32 mask);
-+
-+#endif
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-diag.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,30 @@
-+/* inotify-helper.h - GNOME VFS Monitor using inotify
-+
-+ Copyright (C) 2006 John McCutchan <john@johnmccutchan.com>
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Author: John McCutchan <ttb@tentacle.dhs.org>
-+*/
-+
-+
-+#ifndef __INOTIFY_DIAG_H
-+#define __INOTIFY_DIAG_H
-+
-+void id_startup (void);
-+gboolean id_dump (gpointer userdata);
-+
-+#endif /* __INOTIFY_DIAG_H */
---- gamin-0.1.7/server/Makefile.am.new-inotify-backend 2005-08-26 13:52:19.000000000 +0200
-+++ gamin-0.1.7/server/Makefile.am 2006-09-05 11:01:21.000000000 +0200
-@@ -51,6 +51,12 @@
-
- if ENABLE_INOTIFY
- gam_server_SOURCES += gam_inotify.c gam_inotify.h \
-+ inotify-helper.c inotify-helper.h \
-+ inotify-kernel.c inotify-kernel.h \
-+ inotify-missing.c inotify-missing.h \
-+ inotify-path.c inotify-path.h \
-+ inotify-sub.c inotify-sub.h \
-+ inotify-diag.c inotify-diag.h \
- local_inotify.h local_inotify_syscalls.h
- endif
-
---- gamin-0.1.7/server/local_inotify_syscalls.h.new-inotify-backend 2005-08-17 15:50:04.000000000 +0200
-+++ gamin-0.1.7/server/local_inotify_syscalls.h 2006-09-05 11:01:21.000000000 +0200
-@@ -1,7 +1,9 @@
- #ifndef _LINUX_INOTIFY_SYSCALLS_H
- #define _LINUX_INOTIFY_SYSCALLS_H
-
-+#include <asm/types.h>
- #include <sys/syscall.h>
-+#include <unistd.h>
-
- #if defined(__i386__)
- # define __NR_inotify_init 291
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-kernel.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,685 @@
-+/*
-+ Copyright (C) 2006 John McCutchan <john@johnmccutchan.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; version 2.
-+
-+ This program 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 General Public License version 2 for more details.
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software Foundation,
-+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+*/
-+
-+#include "config.h"
-+
-+#include <stdio.h>
-+#include <sys/ioctl.h>
-+#include <unistd.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <glib.h>
-+#include "inotify-kernel.h"
-+
-+/* Just include the local headers to stop all the pain */
-+#include "local_inotify.h"
-+#include "local_inotify_syscalls.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"
-+#include "local_inotify_syscalls.h"
-+#elif defined (HAVE_LINUX_INOTIFY_H)
-+#include <linux/inotify.h>
-+#include "local_inotify_syscalls.h"
-+#endif
-+#endif
-+
-+/* Timings for pairing MOVED_TO / MOVED_FROM events */
-+#define PROCESS_EVENTS_TIME 1000 /* milliseconds (1 hz) */
-+#define DEFAULT_HOLD_UNTIL_TIME 0 /* 0 millisecond */
-+#define MOVE_HOLD_UNTIL_TIME 0 /* 0 milliseconds */
-+
-+static int inotify_instance_fd = -1;
-+static GQueue *events_to_process = NULL;
-+static GQueue *event_queue = NULL;
-+static GHashTable * cookie_hash = NULL;
-+static GIOChannel *inotify_read_ioc;
-+static GPollFD ik_poll_fd;
-+static gboolean ik_poll_fd_enabled = TRUE;
-+static void (*user_cb)(ik_event_t *event);
-+
-+static gboolean ik_read_callback (gpointer user_data);
-+static gboolean ik_process_eq_callback (gpointer user_data);
-+
-+static guint32 ik_move_matches = 0;
-+static guint32 ik_move_misses = 0;
-+
-+static gboolean process_eq_running = FALSE;
-+
-+/* We use the lock from inotify-helper.c
-+ *
-+ * There are two places that we take this lock
-+ *
-+ * 1) In ik_read_callback
-+ *
-+ * 2) ik_process_eq_callback.
-+ *
-+ *
-+ * The rest of locking is taken care of in inotify-helper.c
-+ */
-+G_LOCK_EXTERN (inotify_lock);
-+
-+typedef struct ik_event_internal {
-+ ik_event_t *event;
-+ gboolean seen;
-+ gboolean sent;
-+ GTimeVal hold_until;
-+ struct ik_event_internal *pair;
-+} ik_event_internal_t;
-+
-+/* In order to perform non-sleeping inotify event chunking we need
-+ * a custom GSource
-+ */
-+static gboolean
-+ik_source_prepare (GSource *source,
-+ gint *timeout)
-+{
-+ return FALSE;
-+}
-+
-+static gboolean
-+ik_source_timeout (gpointer data)
-+{
-+ GSource *source = (GSource *)data;
-+
-+ /* Re-active the PollFD */
-+ g_source_add_poll (source, &ik_poll_fd);
-+ g_source_unref (source);
-+ ik_poll_fd_enabled = TRUE;
-+
-+ return FALSE;
-+}
-+
-+#define MAX_PENDING_COUNT 2
-+#define PENDING_THRESHOLD(qsize) ((qsize) >> 1)
-+#define PENDING_MARGINAL_COST(p) ((unsigned int)(1 << (p)))
-+#define MAX_QUEUED_EVENTS 2048
-+#define AVERAGE_EVENT_SIZE sizeof (struct inotify_event) + 16
-+#define TIMEOUT_MILLISECONDS 10
-+static gboolean
-+ik_source_check (GSource *source)
-+{
-+ static int prev_pending = 0, pending_count = 0;
-+
-+ /* We already disabled the PollFD or
-+ * nothing to be read from inotify */
-+ if (!ik_poll_fd_enabled || !(ik_poll_fd.revents & G_IO_IN))
-+ {
-+ return FALSE;
-+ }
-+
-+ if (pending_count < MAX_PENDING_COUNT) {
-+ unsigned int pending;
-+
-+ if (ioctl (inotify_instance_fd, FIONREAD, &pending) == -1)
-+ goto do_read;
-+
-+ pending /= AVERAGE_EVENT_SIZE;
-+
-+ /* Don't wait if the number of pending events is too close
-+ * to the maximum queue size.
-+ */
-+ if (pending > PENDING_THRESHOLD (MAX_QUEUED_EVENTS))
-+ goto do_read;
-+
-+ /* With each successive iteration, the minimum rate for
-+ * further sleep doubles. */
-+ if (pending-prev_pending < PENDING_MARGINAL_COST(pending_count))
-+ goto do_read;
-+
-+ prev_pending = pending;
-+ pending_count++;
-+
-+ /* We are going to wait to read the events: */
-+
-+ /* Remove the PollFD from the source */
-+ g_source_remove_poll (source, &ik_poll_fd);
-+ /* To avoid threading issues we need to flag that we've done that */
-+ ik_poll_fd_enabled = FALSE;
-+ /* Set a timeout to re-add the PollFD to the source */
-+ g_source_ref (source);
-+ g_timeout_add (TIMEOUT_MILLISECONDS, ik_source_timeout, source);
-+
-+ return FALSE;
-+ }
-+
-+do_read:
-+ /* We are ready to read events from inotify */
-+
-+ prev_pending = 0;
-+ pending_count = 0;
-+
-+ return TRUE;
-+}
-+
-+static gboolean
-+ik_source_dispatch (GSource *source,
-+ GSourceFunc callback,
-+ gpointer user_data)
-+{
-+ if (callback)
-+ {
-+ return callback(user_data);
-+ }
-+ return TRUE;
-+}
-+
-+GSourceFuncs ik_source_funcs =
-+{
-+ ik_source_prepare,
-+ ik_source_check,
-+ ik_source_dispatch,
-+ NULL
-+};
-+
-+gboolean ik_startup (void (*cb)(ik_event_t *event))
-+{
-+ static gboolean initialized = FALSE;
-+ GSource *source;
-+
-+ user_cb = cb;
-+ /* Ignore multi-calls */
-+ if (initialized) {
-+ return inotify_instance_fd >= 0;
-+ }
-+
-+ initialized = TRUE;
-+ inotify_instance_fd = inotify_init ();
-+
-+ if (inotify_instance_fd < 0) {
-+ return FALSE;
-+ }
-+
-+ inotify_read_ioc = g_io_channel_unix_new(inotify_instance_fd);
-+ ik_poll_fd.fd = inotify_instance_fd;
-+ ik_poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
-+ g_io_channel_set_encoding(inotify_read_ioc, NULL, NULL);
-+ g_io_channel_set_flags(inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
-+
-+ source = g_source_new (&ik_source_funcs, sizeof(GSource));
-+ g_source_add_poll (source, &ik_poll_fd);
-+ g_source_set_callback(source, ik_read_callback, NULL, NULL);
-+ g_source_attach(source, NULL);
-+ g_source_unref (source);
-+
-+ cookie_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
-+ event_queue = g_queue_new ();
-+ events_to_process = g_queue_new ();
-+
-+ return TRUE;
-+}
-+
-+static ik_event_internal_t *ik_event_internal_new (ik_event_t *event)
-+{
-+ ik_event_internal_t *internal_event = g_new0(ik_event_internal_t, 1);
-+ GTimeVal tv;
-+
-+ g_assert (event);
-+
-+ g_get_current_time (&tv);
-+ g_time_val_add (&tv, DEFAULT_HOLD_UNTIL_TIME);
-+ internal_event->event = event;
-+ internal_event->hold_until = tv;
-+
-+ return internal_event;
-+}
-+
-+static ik_event_t *ik_event_new (char *buffer)
-+{
-+ struct inotify_event *kevent = (struct inotify_event *)buffer;
-+ g_assert (buffer);
-+ ik_event_t *event = g_new0(ik_event_t,1);
-+ event->wd = kevent->wd;
-+ event->mask = kevent->mask;
-+ event->cookie = kevent->cookie;
-+ event->len = kevent->len;
-+ if (event->len)
-+ event->name = g_strdup(kevent->name);
-+ else
-+ event->name = g_strdup("");
-+
-+ return event;
-+}
-+
-+ik_event_t *ik_event_new_dummy (const char *name, gint32 wd, guint32 mask)
-+{
-+ ik_event_t *event = g_new0(ik_event_t,1);
-+ event->wd = wd;
-+ event->mask = mask;
-+ event->cookie = 0;
-+ if (name)
-+ event->name = g_strdup(name);
-+ else
-+ event->name = g_strdup("");
-+
-+ event->len = strlen (event->name);
-+
-+ return event;
-+}
-+
-+void ik_event_free (ik_event_t *event)
-+{
-+ if (event->pair)
-+ ik_event_free (event->pair);
-+ g_free(event->name);
-+ g_free(event);
-+}
-+
-+gint32 ik_watch (const char *path, guint32 mask, int *err)
-+{
-+ gint32 wd = -1;
-+
-+ g_assert (path != NULL);
-+ g_assert (inotify_instance_fd >= 0);
-+
-+ wd = inotify_add_watch (inotify_instance_fd, path, mask);
-+
-+ if (wd < 0)
-+ {
-+ int e = errno;
-+ // FIXME: debug msg failed to add watch
-+ if (err)
-+ *err = e;
-+ return wd;
-+ }
-+
-+ g_assert (wd >= 0);
-+ return wd;
-+}
-+
-+int ik_ignore(const char *path, gint32 wd)
-+{
-+ g_assert (wd >= 0);
-+ g_assert (inotify_instance_fd >= 0);
-+
-+ if (inotify_rm_watch (inotify_instance_fd, wd) < 0)
-+ {
-+ //int e = errno;
-+ // failed to rm watch
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+void ik_move_stats (guint32 *matches, guint32 *misses)
-+{
-+ if (matches)
-+ *matches = ik_move_matches;
-+
-+ if (misses)
-+ *misses = ik_move_misses;
-+}
-+
-+const char *ik_mask_to_string (guint32 mask)
-+{
-+ gboolean is_dir = mask & IN_ISDIR;
-+ mask &= ~IN_ISDIR;
-+
-+ if (is_dir)
-+ {
-+ switch (mask)
-+ {
-+ case IN_ACCESS:
-+ return "ACCESS (dir)";
-+ break;
-+ case IN_MODIFY:
-+ return "MODIFY (dir)";
-+ break;
-+ case IN_ATTRIB:
-+ return "ATTRIB (dir)";
-+ break;
-+ case IN_CLOSE_WRITE:
-+ return "CLOSE_WRITE (dir)";
-+ break;
-+ case IN_CLOSE_NOWRITE:
-+ return "CLOSE_NOWRITE (dir)";
-+ break;
-+ case IN_OPEN:
-+ return "OPEN (dir)";
-+ break;
-+ case IN_MOVED_FROM:
-+ return "MOVED_FROM (dir)";
-+ break;
-+ case IN_MOVED_TO:
-+ return "MOVED_TO (dir)";
-+ break;
-+ case IN_DELETE:
-+ return "DELETE (dir)";
-+ break;
-+ case IN_CREATE:
-+ return "CREATE (dir)";
-+ break;
-+ case IN_DELETE_SELF:
-+ return "DELETE_SELF (dir)";
-+ break;
-+ case IN_UNMOUNT:
-+ return "UNMOUNT (dir)";
-+ break;
-+ case IN_Q_OVERFLOW:
-+ return "Q_OVERFLOW (dir)";
-+ break;
-+ case IN_IGNORED:
-+ return "IGNORED (dir)";
-+ break;
-+ default:
-+ return "UNKNOWN_EVENT (dir)";
-+ break;
-+
-+ }
-+ } else {
-+ switch (mask)
-+ {
-+ case IN_ACCESS:
-+ return "ACCESS";
-+ break;
-+ case IN_MODIFY:
-+ return "MODIFY";
-+ break;
-+ case IN_ATTRIB:
-+ return "ATTRIB";
-+ break;
-+ case IN_CLOSE_WRITE:
-+ return "CLOSE_WRITE";
-+ break;
-+ case IN_CLOSE_NOWRITE:
-+ return "CLOSE_NOWRITE";
-+ break;
-+ case IN_OPEN:
-+ return "OPEN";
-+ break;
-+ case IN_MOVED_FROM:
-+ return "MOVED_FROM";
-+ break;
-+ case IN_MOVED_TO:
-+ return "MOVED_TO";
-+ break;
-+ case IN_DELETE:
-+ return "DELETE";
-+ break;
-+ case IN_CREATE:
-+ return "CREATE";
-+ break;
-+ case IN_DELETE_SELF:
-+ return "DELETE_SELF";
-+ break;
-+ case IN_UNMOUNT:
-+ return "UNMOUNT";
-+ break;
-+ case IN_Q_OVERFLOW:
-+ return "Q_OVERFLOW";
-+ break;
-+ case IN_IGNORED:
-+ return "IGNORED";
-+ break;
-+ default:
-+ return "UNKNOWN_EVENT";
-+ break;
-+
-+ }
-+ }
-+}
-+
-+
-+static void ik_read_events (gsize *buffer_size_out, gchar **buffer_out)
-+{
-+ static gchar *buffer = NULL;
-+ static gsize buffer_size;
-+
-+ /* Initialize the buffer on our first call */
-+ if (buffer == NULL)
-+ {
-+ buffer_size = AVERAGE_EVENT_SIZE;
-+ buffer_size *= MAX_QUEUED_EVENTS;
-+ buffer = g_malloc (buffer_size);
-+
-+ if (!buffer) {
-+ *buffer_size_out = 0;
-+ *buffer_out = NULL;
-+ return;
-+ }
-+ }
-+
-+ *buffer_size_out = 0;
-+ *buffer_out = NULL;
-+
-+ memset(buffer, 0, buffer_size);
-+
-+ if (g_io_channel_read_chars (inotify_read_ioc, (char *)buffer, buffer_size, buffer_size_out, NULL) != G_IO_STATUS_NORMAL) {
-+ // error reading
-+ }
-+ *buffer_out = buffer;
-+}
-+
-+static gboolean ik_read_callback(gpointer user_data)
-+{
-+ gchar *buffer;
-+ gsize buffer_size, buffer_i, events;
-+
-+ G_LOCK(inotify_lock);
-+ ik_read_events (&buffer_size, &buffer);
-+
-+ buffer_i = 0;
-+ events = 0;
-+ while (buffer_i < buffer_size)
-+ {
-+ struct inotify_event *event;
-+ gsize event_size;
-+ event = (struct inotify_event *)&buffer[buffer_i];
-+ event_size = sizeof(struct inotify_event) + event->len;
-+ g_queue_push_tail (events_to_process, ik_event_internal_new (ik_event_new (&buffer[buffer_i])));
-+ buffer_i += event_size;
-+ events++;
-+ }
-+
-+ /* If the event process callback is off, turn it back on */
-+ if (!process_eq_running && events)
-+ {
-+ process_eq_running = TRUE;
-+ g_timeout_add (PROCESS_EVENTS_TIME, ik_process_eq_callback, NULL);
-+ }
-+
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+}
-+
-+static gboolean
-+g_timeval_lt(GTimeVal *val1, GTimeVal *val2)
-+{
-+ if (val1->tv_sec < val2->tv_sec)
-+ return TRUE;
-+
-+ if (val1->tv_sec > val2->tv_sec)
-+ return FALSE;
-+
-+ /* val1->tv_sec == val2->tv_sec */
-+ if (val1->tv_usec < val2->tv_usec)
-+ return TRUE;
-+
-+ return FALSE;
-+}
-+
-+static gboolean
-+g_timeval_eq(GTimeVal *val1, GTimeVal *val2)
-+{
-+ return (val1->tv_sec == val2->tv_sec) && (val1->tv_usec == val2->tv_usec);
-+}
-+
-+static void
-+ik_pair_events (ik_event_internal_t *event1, ik_event_internal_t *event2)
-+{
-+ g_assert (event1 && event2);
-+ /* We should only be pairing events that have the same cookie */
-+ g_assert (event1->event->cookie == event2->event->cookie);
-+ /* We shouldn't pair an event that already is paired */
-+ g_assert (event1->pair == NULL && event2->pair == NULL);
-+
-+ /* Pair the internal structures and the ik_event_t structures */
-+ event1->pair = event2;
-+ event1->event->pair = event2->event;
-+
-+ if (g_timeval_lt (&event1->hold_until, &event2->hold_until))
-+ event1->hold_until = event2->hold_until;
-+
-+ event2->hold_until = event1->hold_until;
-+}
-+
-+static void
-+ik_event_add_microseconds (ik_event_internal_t *event, glong ms)
-+{
-+ g_assert (event);
-+ g_time_val_add (&event->hold_until, ms);
-+}
-+
-+static gboolean
-+ik_event_ready (ik_event_internal_t *event)
-+{
-+ GTimeVal tv;
-+ g_assert (event);
-+
-+ g_get_current_time (&tv);
-+
-+ /* An event is ready if,
-+ *
-+ * it has no cookie -- there is nothing to be gained by holding it
-+ * or, it is already paired -- we don't need to hold it anymore
-+ * or, we have held it long enough
-+ */
-+ return event->event->cookie == 0 ||
-+ event->pair != NULL ||
-+ g_timeval_lt(&event->hold_until, &tv) || g_timeval_eq(&event->hold_until, &tv);
-+}
-+
-+static void
-+ik_pair_moves (gpointer data, gpointer user_data)
-+{
-+ ik_event_internal_t *event = (ik_event_internal_t *)data;
-+
-+ if (event->seen == TRUE || event->sent == TRUE)
-+ return;
-+
-+ if (event->event->cookie != 0)
-+ {
-+ /* When we get a MOVED_FROM event we delay sending the event by
-+ * MOVE_HOLD_UNTIL_TIME microseconds. We need to do this because a
-+ * MOVED_TO pair _might_ be coming in the near future */
-+ if (event->event->mask & IN_MOVED_FROM) {
-+ g_hash_table_insert (cookie_hash, GINT_TO_POINTER(event->event->cookie), event);
-+ // because we don't deliver move events there is no point in waiting for the match right now.
-+ ik_event_add_microseconds (event, MOVE_HOLD_UNTIL_TIME);
-+ } else if (event->event->mask & IN_MOVED_TO) {
-+ /* We need to check if we are waiting for this MOVED_TO events cookie to pair it with
-+ * a MOVED_FROM */
-+ ik_event_internal_t *match = NULL;
-+ match = g_hash_table_lookup (cookie_hash, GINT_TO_POINTER(event->event->cookie));
-+ if (match) {
-+ g_hash_table_remove (cookie_hash, GINT_TO_POINTER(event->event->cookie));
-+ ik_pair_events (match, event);
-+ }
-+ }
-+ }
-+ event->seen = TRUE;
-+}
-+
-+static void
-+ik_process_events ()
-+{
-+ g_queue_foreach (events_to_process, ik_pair_moves, NULL);
-+
-+ while (!g_queue_is_empty (events_to_process))
-+ {
-+ ik_event_internal_t *event = g_queue_peek_head (events_to_process);
-+
-+ /* This must have been sent as part of a MOVED_TO/MOVED_FROM */
-+ if (event->sent)
-+ {
-+ /* Pop event */
-+ g_queue_pop_head (events_to_process);
-+ /* Free the internal event structure */
-+ g_free (event);
-+ continue;
-+ }
-+
-+ /* The event isn't ready yet */
-+ if (!ik_event_ready (event)) {
-+ break;
-+ }
-+
-+ /* Pop it */
-+ event = g_queue_pop_head (events_to_process);
-+
-+ /* Check if this is a MOVED_FROM that is also sitting in the cookie_hash */
-+ if (event->event->cookie && event->pair == NULL &&
-+ g_hash_table_lookup (cookie_hash, GINT_TO_POINTER(event->event->cookie)))
-+ {
-+ g_hash_table_remove (cookie_hash, GINT_TO_POINTER(event->event->cookie));
-+ }
-+
-+ if (event->pair) {
-+ /* We send out paired MOVED_FROM/MOVED_TO events in the same event buffer */
-+ //g_assert (event->event->mask == IN_MOVED_FROM && event->pair->event->mask == IN_MOVED_TO);
-+ /* Copy the paired data */
-+ event->pair->sent = TRUE;
-+ event->sent = TRUE;
-+ ik_move_matches++;
-+ } else if (event->event->cookie) {
-+ /* If we couldn't pair a MOVED_FROM and MOVED_TO together, we change
-+ * the event masks */
-+ /* Changeing MOVED_FROM to DELETE and MOVED_TO to create lets us make
-+ * the gaurantee that you will never see a non-matched MOVE event */
-+
-+ if (event->event->mask & IN_MOVED_FROM) {
-+ event->event->mask = IN_DELETE|(event->event->mask & IN_ISDIR);
-+ ik_move_misses++; // not super accurate, if we aren't watching the destination it still counts as a miss
-+ }
-+ if (event->event->mask & IN_MOVED_TO)
-+ event->event->mask = IN_CREATE|(event->event->mask & IN_ISDIR);
-+ }
-+
-+ /* Push the ik_event_t onto the event queue */
-+ g_queue_push_tail (event_queue, event->event);
-+ /* Free the internal event structure */
-+ g_free (event);
-+ }
-+}
-+
-+gboolean ik_process_eq_callback (gpointer user_data)
-+{
-+ /* Try and move as many events to the event queue */
-+ G_LOCK(inotify_lock);
-+ ik_process_events ();
-+
-+ while (!g_queue_is_empty (event_queue))
-+ {
-+ ik_event_t *event = g_queue_pop_head (event_queue);
-+
-+ user_cb (event);
-+ }
-+
-+ if (g_queue_get_length (events_to_process) == 0)
-+ {
-+ process_eq_running = FALSE;
-+ G_UNLOCK(inotify_lock);
-+ return FALSE;
-+ } else {
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+ }
-+}
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-missing.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,158 @@
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-+
-+/* inotify-helper.c - Gnome VFS Monitor based on inotify.
-+
-+ Copyright (C) 2005 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Authors:
-+ John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+#include "config.h"
-+#include <glib.h>
-+#include "inotify-missing.h"
-+#include "inotify-path.h"
-+
-+#define SCAN_MISSING_TIME 4000 /* 1/4 Hz */
-+
-+static gboolean im_debug_enabled = FALSE;
-+#define IM_W if (im_debug_enabled) g_warning
-+
-+/* We put ih_sub_t's that are missing on this list */
-+static GList *missing_sub_list = NULL;
-+static gboolean im_scan_missing (gpointer user_data);
-+static gboolean scan_missing_running = FALSE;
-+static void (*missing_cb)(ih_sub_t *sub) = NULL;
-+
-+G_LOCK_EXTERN (inotify_lock);
-+
-+/* inotify_lock must be held before calling */
-+void im_startup (void (*callback)(ih_sub_t *sub))
-+{
-+ static gboolean initialized = FALSE;
-+
-+ if (!initialized) {
-+ initialized = TRUE;
-+ missing_cb = callback;
-+ }
-+}
-+
-+/* inotify_lock must be held before calling */
-+void im_add (ih_sub_t *sub)
-+{
-+ if (g_list_find (missing_sub_list, sub)) {
-+ IM_W("asked to add %s to missing list but it's already on the list!\n", sub->pathname);
-+ return;
-+ }
-+
-+ IM_W("adding %s to missing list\n", sub->dirname);
-+ missing_sub_list = g_list_prepend (missing_sub_list, sub);
-+
-+ /* If the timeout is turned off, we turn it back on */
-+ if (!scan_missing_running)
-+ {
-+ scan_missing_running = TRUE;
-+ g_timeout_add (SCAN_MISSING_TIME, im_scan_missing, NULL);
-+ }
-+}
-+
-+/* inotify_lock must be held before calling */
-+void im_rm (ih_sub_t *sub)
-+{
-+ GList *link;
-+
-+ link = g_list_find (missing_sub_list, sub);
-+
-+ if (!link) {
-+ IM_W("asked to remove %s from missing list but it isn't on the list!\n", sub->pathname);
-+ return;
-+ }
-+
-+ IM_W("removing %s from missing list\n", sub->dirname);
-+
-+ missing_sub_list = g_list_remove_link (missing_sub_list, link);
-+ g_list_free_1 (link);
-+}
-+
-+/* Scans the list of missing subscriptions checking if they
-+ * are available yet.
-+ */
-+static gboolean im_scan_missing (gpointer user_data)
-+{
-+ GList *nolonger_missing = NULL;
-+ GList *l;
-+
-+ G_LOCK(inotify_lock);
-+
-+ IM_W("scanning missing list with %d items\n", g_list_length (missing_sub_list));
-+ for (l = missing_sub_list; l; l = l->next)
-+ {
-+ ih_sub_t *sub = l->data;
-+ gboolean not_m = FALSE;
-+
-+ IM_W("checking %p\n", sub);
-+ g_assert (sub);
-+ g_assert (sub->dirname);
-+ not_m = ip_start_watching (sub);
-+
-+ if (not_m)
-+ {
-+ missing_cb (sub);
-+ IM_W("removed %s from missing list\n", sub->dirname);
-+ /* We have to build a list of list nodes to remove from the
-+ * missing_sub_list. We do the removal outside of this loop.
-+ */
-+ nolonger_missing = g_list_prepend (nolonger_missing, l);
-+ }
-+ }
-+
-+ for (l = nolonger_missing; l ; l = l->next)
-+ {
-+ GList *llink = l->data;
-+ missing_sub_list = g_list_remove_link (missing_sub_list, llink);
-+ g_list_free_1 (llink);
-+ }
-+
-+ g_list_free (nolonger_missing);
-+
-+ /* If the missing list is now empty, we disable the timeout */
-+ if (missing_sub_list == NULL)
-+ {
-+ scan_missing_running = FALSE;
-+ G_UNLOCK(inotify_lock);
-+ return FALSE;
-+ } else {
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+ }
-+}
-+
-+
-+/* inotify_lock must be held */
-+void
-+im_diag_dump (GIOChannel *ioc)
-+{
-+ GList *l;
-+ g_io_channel_write_chars (ioc, "missing list:\n", -1, NULL, NULL);
-+ for (l = missing_sub_list; l; l = l->next)
-+ {
-+ ih_sub_t *sub = l->data;
-+ g_io_channel_write_chars (ioc, sub->pathname, -1, NULL, NULL);
-+ g_io_channel_write_chars (ioc, "\n", -1, NULL, NULL);
-+ }
-+}
---- gamin-0.1.7/server/gam_inotify.c.new-inotify-backend 2005-10-25 16:16:28.000000000 +0200
-+++ gamin-0.1.7/server/gam_inotify.c 2006-09-05 12:13:38.000000000 +0200
-@@ -17,1582 +17,201 @@
- */
-
- #include "server_config.h"
--#define _GNU_SOURCE
--#include <errno.h>
--#include <stdio.h>
- #include <string.h>
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <sys/ioctl.h>
--#include <fcntl.h>
--#include <unistd.h>
--#include <asm/unistd.h>
--#include <time.h>
--#include <glib.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_poll_basic.h"
--#ifdef HAVE_LINUX_INOTIFY_H
--#include <linux/inotify.h>
--#else
--#include "local_inotify.h"
--#endif
--#include "local_inotify_syscalls.h"
--#include "gam_inotify.h"
--#include "gam_tree.h"
- #include "gam_event.h"
- #include "gam_server.h"
--#include "gam_event.h"
--#include "gam_fs.h"
--
--#define GAM_INOTIFY_SANITY
--#define GAM_INOTIFY_WD_MISSING -1
--#define GAM_INOTIFY_WD_PERM -2
--#define GAM_INOTIFY_WD_LINK -3
--
--/* Timings for pairing MOVED_TO / MOVED_FROM events */
--/* These numbers are in microseconds */
--#define DEFAULT_HOLD_UNTIL_TIME 1000 /* 1 ms */
--#define MOVE_HOLD_UNTIL_TIME 5000 /* 5 ms */
--
--/* Timings for main loop */
--/* These numbers are in milliseconds */
--#define SCAN_MISSING_TIME 1000 /* 1 Hz */
--#define SCAN_LINKS_TIME 1000 /* 1 Hz */
--#define PROCESS_EVENTS_TIME 33 /* 30 Hz */
--
--typedef struct {
-- /* The full pathname of this node */
-- char *path;
-- gboolean dir; /* Is this path a directory */
--
-- /* Inotify */
-- int wd;
--
-- /* State */
-- gboolean busy;
-- gboolean missing;
-- gboolean link;
-- gboolean permission; /* Exists, but don't have read access */
-- gboolean deactivated;
-- gboolean ignored;
-- int refcount;
--
-- /* Statistics */
-- int events;
-- int deactivated_events;
-- int ignored_events;
--
-- /* Gamin state */
-- GList *subs;
--} inotify_data_t;
--
--typedef struct _inotify_event_t {
-- gint wd;
-- gint mask;
-- gint cookie;
-- char *name;
-- gboolean seen;
-- gboolean sent;
-- GTimeVal hold_until;
-- struct _inotify_event_t *pair;
--} inotify_event_t;
--
--typedef struct {
-- char *path;
-- GTime last_scan_time;
-- GTime scan_interval;
-- gboolean permission;
--} inotify_missing_t;
--
--typedef struct {
-- char *path;
-- struct stat sbuf;
-- GTime last_scan_time;
-- GTime scan_interval;
--} inotify_links_t;
--
--static GHashTable * path_hash = NULL;
--static GHashTable * wd_hash = NULL;
--static GList * missing_list = NULL;
--static GList * links_list = NULL;
--static GHashTable * cookie_hash = NULL;
--static GQueue * event_queue = NULL;
--static GQueue * events_to_process = NULL;
--static GIOChannel * inotify_read_ioc = NULL;
--static int inotify_device_fd = -1;
--
--#define GAM_INOTIFY_MASK (IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|IN_CREATE|IN_DELETE_SELF|IN_UNMOUNT|IN_MOVE_SELF)
--
--static int gam_inotify_add_watch (const char *path, __u32 mask, int *err);
--static int gam_inotify_rm_watch (const char *path, __u32 wd);
--static void gam_inotify_read_events (gsize *buffer_size_out, gchar **buffer_out);
--
--static gboolean gam_inotify_is_missing (const char *path);
--static gboolean gam_inotify_nolonger_missing (const char *path);
--static void gam_inotify_add_missing (const char *path, gboolean perm);
--static void gam_inotify_rm_missing (const char *path);
--static gboolean gam_inotify_scan_missing (gpointer userdata);
--
--static gboolean gam_inotify_is_link (const char *path);
--static gboolean gam_inotify_nolonger_link (const char *path);
--static void gam_inotify_add_link (const char *path);
--static void gam_inotify_rm_link (const char *path);
--static gboolean gam_inotify_scan_links (gpointer userdata);
--static void gam_inotify_poll_link (inotify_links_t *links);
--
--static void gam_inotify_sanity_check (void);
--
--static gboolean g_timeval_lt (GTimeVal *val1, GTimeVal *val2);
--static gboolean g_timeval_eq (GTimeVal *val1, GTimeVal *val2);
--
--static void
--gam_inotify_data_debug (gpointer key, gpointer value, gpointer user_data)
--{
-- int busy;
-- int deactivated;
-- int ignored;
-- int missing;
-- int permission;
-- inotify_data_t *data = (inotify_data_t *)value;
--
-- if (!data)
-- return;
--
-- busy = data->busy;
-- deactivated = data->deactivated;
-- ignored = data->ignored;
-- missing = data->missing;
-- permission = data->permission;
--
-- GAM_DEBUG(DEBUG_INFO, "isub wd %d refs %d permission %d missing %d busy %d deactivated %d ignored %d events (%d:%d:%d): %s\n", data->wd, data->refcount, permission, missing, busy, deactivated, ignored, data->events, data->deactivated_events, data->ignored_events, data->path);
--}
--
--gboolean
--gam_inotify_is_running(void)
--{
-- return inotify_device_fd >= 0;
--}
--
--void
--gam_inotify_debug(void)
--{
-- if (inotify_device_fd == -1)
-- {
-- return;
-- }
--
-- if (path_hash == NULL)
-- return;
--
-- GAM_DEBUG(DEBUG_INFO, "Inotify device fd = %d\n", inotify_device_fd);
-- GAM_DEBUG(DEBUG_INFO, "Dumping inotify subscriptions\n");
-- g_hash_table_foreach (path_hash, gam_inotify_data_debug, NULL);
--}
--
--static const char *
--mask_to_string (int mask)
--{
-- mask &= ~IN_ISDIR;
-- switch (mask)
-- {
-- case IN_ACCESS:
-- return "ACCESS";
-- break;
-- case IN_MODIFY:
-- return "MODIFY";
-- break;
-- case IN_ATTRIB:
-- return "ATTRIB";
-- break;
-- case IN_CLOSE_WRITE:
-- return "CLOSE_WRITE";
-- break;
-- case IN_CLOSE_NOWRITE:
-- return "CLOSE_NOWRITE";
-- break;
-- case IN_OPEN:
-- return "OPEN";
-- break;
-- case IN_MOVED_FROM:
-- return "MOVED_FROM";
-- break;
-- case IN_MOVED_TO:
-- return "MOVED_TO";
-- break;
-- case IN_DELETE:
-- return "DELETE";
-- break;
-- case IN_CREATE:
-- return "CREATE";
-- break;
-- case IN_DELETE_SELF:
-- return "DELETE_SELF";
-- break;
-- case IN_UNMOUNT:
-- return "UNMOUNT";
-- break;
-- case IN_Q_OVERFLOW:
-- return "Q_OVERFLOW";
-- break;
-- case IN_IGNORED:
-- return "IGNORED";
-- break;
-- default:
-- return "UNKNOWN_EVENT";
-- break;
-- }
--}
--
--static GaminEventType
--mask_to_gam_event (gint mask)
--{
-- mask &= ~IN_ISDIR;
-- switch (mask)
-- {
-- case IN_MODIFY:
-- 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 GAMIN_EVENT_UNKNOWN;
-- break;
-- }
--}
--
--/* Called when a directory is being watched as a file */
--static GaminEventType
--gam_inotify_mask_to_gam_file_event (gint mask)
--{
-- mask &= ~IN_ISDIR;
-- switch (mask)
-- {
-- case IN_MOVED_FROM:
-- case IN_DELETE:
-- case IN_CREATE:
-- case IN_MOVED_TO:
-- return GAMIN_EVENT_CHANGED;
-- break;
-- case IN_MOVE_SELF:
-- case IN_DELETE_SELF:
-- return GAMIN_EVENT_DELETED;
-- break;
-- case IN_ATTRIB:
-- case IN_MODIFY:
-- 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 GAMIN_EVENT_UNKNOWN;
-- break;
-- }
--}
-+#include "gam_subscription.h"
-+#include "gam_inotify.h"
-
--/* Called when a file is watched as a directory */
-+/* Transforms a inotify event to a gamin event. */
- static GaminEventType
--gam_inotify_mask_to_gam_dir_event (gint mask)
-+ih_mask_to_EventType (guint32 mask)
- {
-- mask &= ~IN_ISDIR;
-- switch (mask)
-- {
-- case IN_MOVED_FROM:
-- case IN_DELETE:
-- case IN_CREATE:
-- case IN_MOVED_TO:
-- case IN_MOVE_SELF:
-- case IN_DELETE_SELF:
-- case IN_ATTRIB:
-- case IN_MODIFY:
-- 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 GAMIN_EVENT_UNKNOWN;
-+ 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 inotify_data_t *
--gam_inotify_data_new(const char *path, int wd, gboolean dir)
--{
-- inotify_data_t *data;
--
-- data = g_new0(inotify_data_t, 1);
--
-- data->path = g_strdup(path);
-- data->wd = wd;
-- data->busy = FALSE;
-- if (wd == GAM_INOTIFY_WD_MISSING)
-- data->missing = TRUE;
-- else
-- data->missing = FALSE;
-- if (wd == GAM_INOTIFY_WD_PERM)
-- data->permission = TRUE;
-- else
-- data->permission = FALSE;
-- if (wd == GAM_INOTIFY_WD_LINK)
-- data->link = TRUE;
-- else
-- data->link = FALSE;
-- data->deactivated = FALSE;
-- data->ignored = FALSE;
-- data->refcount = 1;
-- data->events = 0;
-- data->deactivated_events = 0;
-- data->ignored_events = 0;
-- data->dir = dir;
--
-- return data;
--}
--
--static void
--gam_inotify_data_free(inotify_data_t * data)
--{
-- if (data->refcount != 0)
-- GAM_DEBUG(DEBUG_INFO, "gam_inotify_data_free called with reffed data.\n");
--
-- g_free(data->path);
-- g_free(data);
--}
--
--static inotify_event_t *
--gam_inotify_event_new (struct inotify_event *event)
--{
-- inotify_event_t *gam_event;
-- GTimeVal tv;
--
-- gam_event = g_new0(inotify_event_t, 1);
--
-- gam_event->wd = event->wd;
-- gam_event->mask = event->mask;
-- gam_event->cookie = event->cookie;
--
-- if (event->len)
-- {
-- gam_event->name = g_strdup (event->name);
-- } else {
-- gam_event->name = g_strdup ("");
-- }
--
-- g_get_current_time (&tv);
-- g_time_val_add (&tv, DEFAULT_HOLD_UNTIL_TIME);
-- gam_event->hold_until = tv;
--
-- return gam_event;
--}
--
--static void
--gam_inotify_event_free (inotify_event_t *event)
--{
-- g_free (event->name);
-- g_free (event);
--}
--
--static void
--gam_inotify_event_pair_with (inotify_event_t *event1, inotify_event_t *event2)
--{
-- g_assert (event1 && event2);
-- /* We should only be pairing events that have the same cookie */
-- g_assert (event1->cookie == event2->cookie);
-- /* We shouldn't pair an event that already is paired */
-- g_assert (event1->pair == NULL && event2->pair == NULL);
-- event1->pair = event2;
-- event2->pair = event1;
--
-- GAM_DEBUG(DEBUG_INFO, "inotify: pairing a MOVE together\n");
-- if (g_timeval_lt (&event1->hold_until, &event2->hold_until))
-- event1->hold_until = event2->hold_until;
--
-- event2->hold_until = event1->hold_until;
--}
--
--static void
--gam_inotify_event_add_microseconds (inotify_event_t *event, glong ms)
--{
-- g_assert (event);
-- g_time_val_add (&event->hold_until, ms);
--}
--
--static gboolean
--gam_inotify_event_ready (inotify_event_t *event)
--{
-- GTimeVal tv;
-- g_assert (event);
--
-- g_get_current_time (&tv);
--
-- /* An event is ready if,
-- *
-- * it has no cookie -- there is nothing to be gained by holding it
-- * or, it is already paired -- we don't need to hold it anymore
-- * or, we have held it long enough
-- */
-- return event->cookie == 0 ||
-- event->pair != NULL ||
-- g_timeval_lt(&event->hold_until, &tv) || g_timeval_eq(&event->hold_until, &tv);
--}
--
- static void
--gam_inotify_emit_one_event (inotify_data_t *data, inotify_event_t *event, GamSubscription *sub)
-+gam_inotify_send_initial_events (const char *pathname, GamSubscription *sub, gboolean is_dir, gboolean was_missing)
- {
-- gint force = 1;
-- gint is_dir_node = 0;
- GaminEventType gevent;
-- gchar *fullpath = NULL;
-- gboolean watching_dir_as_file;
-- gboolean watching_file_as_dir;
-
-- g_assert (data && event);
-+ gevent = was_missing ? GAMIN_EVENT_CREATED : GAMIN_EVENT_EXISTS;
-
-- is_dir_node = event->mask & IN_ISDIR;
-- watching_dir_as_file = data->dir && !gam_subscription_is_dir (sub);
-- watching_file_as_dir = !data->dir && gam_subscription_is_dir (sub);
-+ gam_server_emit_one_event (pathname, is_dir ? 1 : 0, gevent, sub, 1);
-
-- if (watching_dir_as_file)
-+ if (is_dir)
- {
-- gevent = gam_inotify_mask_to_gam_file_event (event->mask);
-- fullpath = g_strdup (data->path);
-- } else if (watching_file_as_dir) {
-- gevent = gam_inotify_mask_to_gam_dir_event (event->mask);
-- fullpath = g_strdup (data->path);
-- } else {
-- gevent = mask_to_gam_event (event->mask);
-- if (strlen (event->name) == 0)
-- fullpath = g_strdup (data->path);
-- else
-- fullpath = g_strdup_printf ("%s/%s", data->path, event->name);
-- }
--
-- if (gevent == GAMIN_EVENT_UNKNOWN) {
-- GAM_DEBUG(DEBUG_INFO, "inotify: Not handling event %d\n", event->mask);
-- g_free (fullpath);
-- return;
-- }
--
-- GAM_DEBUG(DEBUG_INFO, "inotify: Emitting %s on %s\n", gam_event_to_string (gevent), fullpath);
-- gam_server_emit_one_event (fullpath, is_dir_node, gevent, sub, force);
-- g_free(fullpath);
--}
--
--static void
--gam_inotify_emit_events (inotify_data_t *data, inotify_event_t *event)
--{
-- GList *l;
--
-- if (!data||!event)
-- return;
--
-- for (l = data->subs; l; l = l->next) {
-- GamSubscription *sub = l->data;
-- gam_inotify_emit_one_event (data, event, sub);
-- }
--}
--
--static void
--gam_inotify_process_event (inotify_event_t *event)
--{
-- inotify_data_t *data = NULL;
--
-- data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event->wd));
--
-- if (!data)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: got %s event for unknown wd %d\n", mask_to_string (event->mask), event->wd);
-- return;
-- }
--
-- if (data->deactivated)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: ignoring event on temporarily deactivated watch %s\n", data->path);
-- data->deactivated_events++;
-- return;
-- }
--
-- if (data->ignored) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: got event on ignored watch %s\n", data->path);
-- data->ignored_events++;
-- return;
-- }
--
-- if (event->mask & IN_IGNORED)
-- {
-- data->ignored = TRUE;
-- data->ignored_events++;
-- return;
-- }
--
-- if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: resource %s went away. Adding it to missing list\n", data->path);
-- /* Remove the wd from the hash table */
-- g_hash_table_remove (wd_hash, GINT_TO_POINTER(data->wd));
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyDelete, data->path, 0);
--#endif
-- /* Send delete event */
-- gam_inotify_emit_events (data, event);
-- data->events++;
-- /* Set state bits in struct */
-- data->wd = GAM_INOTIFY_WD_MISSING;
-- data->missing = TRUE;
-- data->permission = FALSE;
-- data->dir = FALSE;
-- /* Add path to missing list */
-- gam_inotify_add_missing (data->path, FALSE);
-- return;
-- }
--
-- if (event->mask & GAM_INOTIFY_MASK)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: got %s on = %s/%s\n", mask_to_string (event->mask), data->path, event->name);
-- gam_inotify_emit_events (data, event);
-- data->events++;
-- return;
-- }
--
-- if (event->mask & IN_Q_OVERFLOW)
-- {
-- /* At this point we have missed some events, and no longer have a consistent
-- * view of the filesystem.
-- */
-- // XXX: Kill server and hope for the best?
-- // XXX: Or we could send_initial_events , does this work for FAM?
-- GAM_DEBUG (DEBUG_INFO, "inotify: DANGER, queue over flowed! Events have been missed.\n");
-- return;
-- }
--
-- GAM_DEBUG(DEBUG_INFO, "inotify: error event->mask = %d\n", event->mask);
--}
--
--static void
--gam_inotify_pair_moves (gpointer data, gpointer user_data)
--{
-- inotify_event_t *event = (inotify_event_t *)data;
--
-- if (event->seen == TRUE || event->sent == TRUE)
-- return;
-+ GDir *dir;
-+ GError *err = NULL;
-+ dir = g_dir_open (pathname, 0, &err);
-+ if (dir)
-+ {
-+ const char *filename;
-
-- if (event->cookie != 0)
-- {
-- if (event->mask & IN_MOVED_FROM) {
-- g_hash_table_insert (cookie_hash, GINT_TO_POINTER(event->cookie), event);
-- gam_inotify_event_add_microseconds (event, MOVE_HOLD_UNTIL_TIME);
-- } else if (event->mask & IN_MOVED_TO) {
-- inotify_event_t *match = NULL;
-- match = g_hash_table_lookup (cookie_hash, GINT_TO_POINTER(event->cookie));
-- if (match) {
-- g_hash_table_remove (cookie_hash, GINT_TO_POINTER(event->cookie));
-- gam_inotify_event_pair_with (match, event);
-+ 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);
- }
-- }
-- }
-- event->seen = TRUE;
--}
--
--static void
--gam_inotify_process_internal ()
--{
-- int ecount = 0;
-- g_queue_foreach (events_to_process, gam_inotify_pair_moves, NULL);
-
-- while (!g_queue_is_empty (events_to_process))
-- {
-- inotify_event_t *event = g_queue_peek_head (events_to_process);
--
-- if (!gam_inotify_event_ready (event)) {
-- GAM_DEBUG(DEBUG_INFO, "inotify: event not ready\n");
-- break;
-- }
--
-- /* Pop it */
-- event = g_queue_pop_head (events_to_process);
-- /* This must have been sent as part of a MOVED_TO/MOVED_FROM */
-- if (event->sent)
-- continue;
--
-- /* Check if this is a MOVED_FROM that is also sitting in the cookie_hash */
-- if (event->cookie && event->pair == NULL &&
-- g_hash_table_lookup (cookie_hash, GINT_TO_POINTER(event->cookie)))
-- {
-- g_hash_table_remove (cookie_hash, GINT_TO_POINTER(event->cookie));
-- event->sent = TRUE;
-- }
--
-- g_queue_push_tail (event_queue, event);
-- ecount++;
-- if (event->pair) {
-- // if this event has a pair
-- event->pair->sent = TRUE;
-- g_queue_push_tail (event_queue, event->pair);
-- ecount++;
-+ g_dir_close (dir);
-+ } else {
-+ GAM_DEBUG (DEBUG_INFO, "unable to open directory %s: %s\n", pathname, err->message);
-+ g_error_free (err);
- }
-
- }
-- if (ecount)
-- GAM_DEBUG(DEBUG_INFO, "inotify: moved %d events to event queue\n", ecount);
--}
-
--static gboolean
--gam_inotify_process_event_queue (gpointer data)
--{
-- /* Try and move as many events to the event queue */
-- gam_inotify_process_internal ();
--
-- /* Send the events on the event queue to gam clients */
-- while (!g_queue_is_empty (event_queue))
-+ if (!was_missing)
- {
-- inotify_event_t *event = g_queue_pop_head (event_queue);
-- g_assert (event);
-- gam_inotify_process_event (event);
-- gam_inotify_event_free (event);
-+ gam_server_emit_one_event (pathname, is_dir ? 1 : 0, GAMIN_EVENT_ENDEXISTS, sub, 1);
- }
-
-- return TRUE;
--}
--
--static gboolean
--gam_inotify_read_handler(gpointer user_data)
--{
-- gchar *buffer;
-- gsize buffer_size, buffer_i, events;
--
-- gam_inotify_read_events (&buffer_size, &buffer);
--
-- buffer_i = 0;
-- events = 0;
-- while (buffer_i < buffer_size)
-- {
-- struct inotify_event *event;
-- gsize event_size;
-- event = (struct inotify_event *)&buffer[buffer_i];
-- event_size = sizeof(struct inotify_event) + event->len;
-- g_queue_push_tail (events_to_process, gam_inotify_event_new (event));
-- buffer_i += event_size;
-- events++;
-- }
--
-- GAM_DEBUG(DEBUG_INFO, "inotify recieved %d events\n", events);
-- return TRUE;
- }
-
- static void
--gam_inotify_send_initial_events (inotify_data_t *data, GamSubscription *sub)
-+gam_inotify_event_callback (const char *fullpath, guint32 mask, void *subdata)
- {
-+ GamSubscription *sub = (GamSubscription *)subdata;
- GaminEventType gevent;
-- gboolean is_dir = FALSE;
-- gboolean was_missing = data->missing;
-- gboolean was_permission = data->permission;
-- gboolean exists = FALSE;
--#if 0
-- gboolean watching_dir_as_file = data->dir && !gam_subscription_is_dir (sub);
--#endif
-- gboolean watching_file_as_dir = FALSE;
--
-- struct stat sb;
-- memset(&sb, 0, sizeof (struct stat));
--
-- exists = lstat (data->path, &sb) >= 0;
-- is_dir = (exists && (sb.st_mode & S_IFDIR) != 0) ? TRUE : FALSE;
--
-- if (was_missing) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: Sending initial events for %s -- WAS_MISSING\n", data->path);
-- } else if (was_permission) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: Sending initial events for %s -- WAS_PERMISSION\n", data->path);
-- } else {
-- GAM_DEBUG (DEBUG_INFO, "inotify: Sending initial events for %s\n", data->path);
-- }
--
-- if (data->wd >= 0)
-- watching_file_as_dir = !data->dir && gam_subscription_is_dir (sub);
-- else
-- watching_file_as_dir = FALSE;
--
-- if (!watching_file_as_dir && exists)
-- {
-- gevent = was_permission ? GAMIN_EVENT_EXISTS : was_missing ? GAMIN_EVENT_CREATED : GAMIN_EVENT_EXISTS;
--
-- gam_server_emit_one_event (data->path, is_dir ? 1 : 0, gevent, sub, 1);
-
-- if (is_dir)
-- {
-- GDir *dir;
-- GError *err = NULL;
-- dir = g_dir_open (data->path, 0, &err);
-- if (dir)
-- {
-- const char *filename;
--
-- while ((filename = g_dir_read_name (dir)))
-- {
-- gchar *fullname = g_strdup_printf ("%s/%s", data->path, 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", data->path, err->message);
-- g_error_free (err);
-- }
-+ gevent = ih_mask_to_EventType (mask);
-
-- }
--
-- if (!was_missing)
-- {
-- gam_server_emit_one_event (data->path, is_dir ? 1 : 0, GAMIN_EVENT_ENDEXISTS, sub, 1);
-- }
--
-- } else {
-- gam_server_emit_one_event (data->path, is_dir ? 1 : 0, GAMIN_EVENT_DELETED, sub, 1);
-- gam_server_emit_one_event (data->path, is_dir ? 1 : 0, GAMIN_EVENT_ENDEXISTS, sub, 1);
-- }
-+ gam_server_emit_one_event (fullpath, gam_subscription_is_dir (sub), gevent, sub, 1);
- }
-
- static void
--gam_inotify_send_initial_events_all (inotify_data_t *data)
--{
-- GList *l;
--
-- if (!data)
-- return;
--
-- for (l = data->subs; l; l = l->next) {
-- GamSubscription *sub = l->data;
-- gam_inotify_send_initial_events (data, sub);
-- }
--
--}
--
--/**
-- * Adds a subscription to be monitored.
-- *
-- * @param sub a #GamSubscription to be polled
-- * @returns TRUE if adding the subscription succeeded, FALSE otherwise
-- */
--gboolean
--gam_inotify_add_subscription(GamSubscription * sub)
--{
-- const char *path = gam_subscription_get_path (sub);
-- inotify_data_t *data = g_hash_table_lookup (path_hash, path);
-- int wd, err;
--
--
-- if (data)
-- {
-- data->subs = g_list_prepend (data->subs, sub);
-- data->refcount++;
-- gam_inotify_send_initial_events (data, sub);
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyChange, path, data->refcount);
--#endif
-- gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
-- return TRUE;
-- }
--
-- wd = gam_inotify_add_watch (path, GAM_INOTIFY_MASK, &err);
-- if (wd < 0) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: could not add watch for %s\n", path);
-- if (err == EACCES) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: adding %s to missing list PERM\n", path);
-- } else {
-- GAM_DEBUG (DEBUG_INFO, "inotify: adding %s to missing list MISSING\n", path);
-- }
-- data = gam_inotify_data_new (path, err == EACCES ? GAM_INOTIFY_WD_PERM : GAM_INOTIFY_WD_MISSING, FALSE);
-- gam_inotify_add_missing (path, err == EACCES ? TRUE : FALSE);
-- } else if (gam_inotify_is_link (path)) {
-- /* The file turned out to be a link, cancel the watch, and add it to the links list */
-- gam_inotify_rm_watch (path, wd);
-- GAM_DEBUG (DEBUG_INFO, "inotify: could not add watch for %s\n", path);
-- GAM_DEBUG (DEBUG_INFO, "inotify: adding %s to links list\n", path);
-- data = gam_inotify_data_new (path, GAM_INOTIFY_WD_LINK, FALSE);
-- gam_inotify_add_link (path);
-- } else {
-- struct stat sbuf;
-- memset(&sbuf, 0, sizeof (struct stat));
-- lstat (path, &sbuf);
-- /* Just in case,
-- * Clear this path off the missing list */
-- gam_inotify_rm_missing (path);
-- data = gam_inotify_data_new (path, wd, sbuf.st_mode & S_IFDIR);
-- g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
-- }
--
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyCreate, path, 0);
--#endif
-- gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
--
-- g_hash_table_insert(path_hash, data->path, data);
-- data->subs = g_list_prepend (data->subs, sub);
-- gam_inotify_send_initial_events (data, sub);
-- return TRUE;
--}
--
--/**
-- * Removes a subscription which was being monitored.
-- *
-- * @param sub a #GamSubscription to remove
-- * @returns TRUE if removing the subscription succeeded, FALSE otherwise
-- */
--gboolean
--gam_inotify_remove_subscription(GamSubscription * sub)
-+gam_inotify_found_callback (const char *fullpath, void *subdata)
- {
-- const char *path = gam_subscription_get_path (sub);
-- inotify_data_t *data = g_hash_table_lookup (path_hash, path);
--
-- g_assert (g_list_find (data->subs, sub));
--
-- data->subs = g_list_remove_all (data->subs, sub);
-- data->refcount--;
-- /* No one is watching this path anymore */
-- if (!data->subs && data->refcount == 0)
-- {
-- if (data->link)
-- {
-- g_assert (data->wd == GAM_INOTIFY_WD_LINK);
-- g_assert (data->missing == FALSE && data->permission == FALSE);
-- g_hash_table_remove (path_hash, data->path);
-- gam_inotify_rm_link (data->path);
-- } else if (data->missing) {
-- g_assert (data->wd == GAM_INOTIFY_WD_MISSING);
-- g_assert (data->link == FALSE && data->permission == FALSE);
-- g_hash_table_remove (path_hash, data->path);
-- gam_inotify_rm_missing (data->path);
-- } else if (data->permission) {
-- g_assert (data->wd == GAM_INOTIFY_WD_PERM);
-- g_assert (data->link == FALSE && data->missing == FALSE);
-- g_hash_table_remove (path_hash, data->path);
-- gam_inotify_rm_missing (data->path);
-- } else {
-- g_hash_table_remove (wd_hash, GINT_TO_POINTER(data->wd));
-- g_hash_table_remove (path_hash, data->path);
-- gam_inotify_rm_watch (data->path, data->wd);
-- }
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyDelete, path, 0);
--#endif
-- gam_inotify_data_free (data);
-- } else {
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyChange, path, data->refcount);
--#endif
-- }
--
-- gam_subscription_cancel (sub);
-+ GamSubscription *sub = (GamSubscription *)subdata;
-
-- return TRUE;
-+ gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), TRUE);
- }
-
--/**
-- * Stop monitoring all subscriptions for a given listener.
-- *
-- * @param listener a #GamListener
-- * @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
-- */
--gboolean
--gam_inotify_remove_all_for(GamListener * listener)
--{
-- GList *subs;
-- GList *l;
-- gboolean success = TRUE;
--
-- subs = gam_listener_get_subscriptions(listener);
--
-- for (l = subs; l != NULL; l = l->next)
-- if (!gam_inotify_remove_subscription(l->data))
-- success = FALSE;
-
-- g_list_free(subs);
--
-- return success;
--}
--
--/**
-- * Initializes the inotify backend. This must be called before
-- * any other functions in this module.
-- *
-- * @returns TRUE if initialization succeeded, FALSE otherwise
-- */
- gboolean
--gam_inotify_init(void)
-+gam_inotify_init (void)
- {
-- GSource *source;
--
-- inotify_device_fd = inotify_init ();
--
-- if (inotify_device_fd < 0) {
-- GAM_DEBUG(DEBUG_INFO, "Could not initialize inotify\n");
-- return FALSE;
-- }
--
-- inotify_read_ioc = g_io_channel_unix_new(inotify_device_fd);
--
-- g_io_channel_set_encoding(inotify_read_ioc, NULL, NULL);
-- g_io_channel_set_flags(inotify_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
--
-- source = g_io_create_watch(inotify_read_ioc,
-- G_IO_IN | G_IO_HUP | G_IO_ERR);
-- g_source_set_callback(source, gam_inotify_read_handler, NULL, NULL);
-- g_source_attach(source, NULL);
-- g_source_unref (source);
-- g_timeout_add (SCAN_MISSING_TIME, gam_inotify_scan_missing, NULL);
-- g_timeout_add (SCAN_LINKS_TIME, gam_inotify_scan_links, NULL);
-- g_timeout_add (PROCESS_EVENTS_TIME, gam_inotify_process_event_queue, NULL);
--
-- path_hash = g_hash_table_new(g_str_hash, g_str_equal);
-- wd_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
-- cookie_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
-- event_queue = g_queue_new ();
-- events_to_process = g_queue_new ();
--
-- gam_poll_basic_init ();
-- gam_server_install_kernel_hooks (GAMIN_K_INOTIFY2,
-+ gam_server_install_kernel_hooks (GAMIN_K_INOTIFY2,
- gam_inotify_add_subscription,
- gam_inotify_remove_subscription,
-- gam_inotify_remove_all_for, NULL, NULL);
--
-- GAM_DEBUG(DEBUG_INFO, "inotify backend initialized\n");
--
--
-- return TRUE;
--}
--
--int gam_inotify_add_watch (const char *path, __u32 mask, int *err)
--{
-- int wd = -1;
--
-- g_assert (path != NULL);
-- g_assert (inotify_device_fd >= 0);
--
-- wd = inotify_add_watch (inotify_device_fd, path, mask);
--
-- if (wd < 0)
-- {
-- int e = errno;
-- GAM_DEBUG (DEBUG_INFO, "inotify: failed to add watch for %s\n", path);
-- GAM_DEBUG (DEBUG_INFO, "inotify: reason %d = %s\n", e, strerror (e));
-- if (err)
-- *err = e;
-- return wd;
-- }
-- else
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: success adding watch for %s (wd = %d)\n", path, wd);
-- }
--
-- g_assert (wd >= 0);
--
-- return wd;
--}
--
--int gam_inotify_rm_watch (const char *path, __u32 wd)
--{
-- g_assert (wd >= 0);
--
-- if (inotify_rm_watch (inotify_device_fd, wd) < 0)
-- {
-- int e = errno;
-- GAM_DEBUG (DEBUG_INFO, "inotify: failed to rm watch for %s (wd = %d)\n", path, wd);
-- GAM_DEBUG (DEBUG_INFO, "inotify: reason = %s\n", strerror (e));
-- return -1;
-- }
-- else
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify: success removing watch for %s (wd = %d)\n", path, wd);
-- }
--
-- return 0;
--}
--
--/* Code below based on beagle inotify glue code. I assume it was written by Robert Love */
--#define MAX_PENDING_COUNT 5
--#define PENDING_THRESHOLD(qsize) ((qsize) >> 1)
--#define PENDING_MARGINAL_COST(p) ((unsigned int)(1 << (p)))
--#define MAX_QUEUED_EVENTS 8192
--#define AVERAGE_EVENT_SIZE sizeof (struct inotify_event) + 16
--#define PENDING_PAUSE_MICROSECONDS 8000
--
--void gam_inotify_read_events (gsize *buffer_size_out, gchar **buffer_out)
--{
-- static int prev_pending = 0, pending_count = 0;
-- static gchar *buffer = NULL;
-- static gsize buffer_size;
--
--
-- /* Initialize the buffer on our first read() */
-- if (buffer == NULL)
-- {
-- buffer_size = AVERAGE_EVENT_SIZE;
-- buffer_size *= MAX_QUEUED_EVENTS;
-- buffer = g_malloc (buffer_size);
--
-- if (!buffer) {
-- *buffer_size_out = 0;
-- *buffer_out = NULL;
-- GAM_DEBUG (DEBUG_INFO, "inotify: could not allocate read buffer\n");
-- return;
-- }
-- }
--
-- *buffer_size_out = 0;
-- *buffer_out = NULL;
--
-- while (pending_count < MAX_PENDING_COUNT) {
-- unsigned int pending;
--
-- if (ioctl (inotify_device_fd, FIONREAD, &pending) == -1)
-- break;
--
-- pending /= AVERAGE_EVENT_SIZE;
--
-- /* Don't wait if the number of pending events is too close
-- * to the maximum queue size.
-- */
--
-- if (pending > PENDING_THRESHOLD (MAX_QUEUED_EVENTS))
-- break;
--
-- /* With each successive iteration, the minimum rate for
-- * further sleep doubles. */
--
-- if (pending-prev_pending < PENDING_MARGINAL_COST(pending_count))
-- break;
--
-- prev_pending = pending;
-- pending_count++;
--
-- /* We sleep for a bit and try again */
-- g_usleep (PENDING_PAUSE_MICROSECONDS);
-- }
--
-- memset(buffer, 0, buffer_size);
--
-- if (g_io_channel_read_chars (inotify_read_ioc, (char *)buffer, buffer_size, buffer_size_out, NULL) != G_IO_STATUS_NORMAL) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: failed to read from buffer\n");
-- }
-- *buffer_out = buffer;
--
-- prev_pending = 0;
-- pending_count = 0;
--}
--
--gboolean gam_inotify_is_missing (const char *path)
--{
-- struct stat sbuf;
--
-- /* If the file doesn't exist, it is missing. */
-- if (lstat (path, &sbuf) < 0)
-- return TRUE;
--
-- /* If we can't read the file, it is missing. */
-- if (access (path, R_OK) < 0)
-- return TRUE;
--
-- return FALSE;
--}
--
--static gint missing_list_compare (gconstpointer a, gconstpointer b)
--{
-- const inotify_missing_t *missing = NULL;
-+ gam_inotify_remove_all_for,
-+ NULL, NULL);
-
-- g_assert (a);
-- g_assert (b);
-- missing = a;
-- g_assert (missing->path);
--
-- return strcmp (missing->path, b);
--}
--
--static void gam_inotify_add_missing (const char *path, gboolean perm)
--{
-- inotify_missing_t *missing = NULL;
--
-- g_assert (path);
--
-- missing = g_new0 (inotify_missing_t, 1);
--
-- g_assert (missing);
--
-- missing->path = g_strdup (path);
-- missing->scan_interval = gam_fs_get_poll_timeout (path);
-- missing->last_scan_time = time (NULL);
-- missing->permission = perm;
--
-- GAM_DEBUG (DEBUG_INFO, "inotify-missing: add - %s\n", path);
--
-- missing_list = g_list_prepend (missing_list, missing);
--}
--
--static void gam_inotify_rm_missing (const char *path)
--{
-- GList *node = NULL;
-- inotify_missing_t *missing = NULL;
--
-- g_assert (path && *path);
--
-- node = g_list_find_custom (missing_list, path, missing_list_compare);
--
-- if (!node)
-- return;
--
-- GAM_DEBUG (DEBUG_INFO, "inotify-missing: rm - %s\n", path);
-- missing = node->data;
-- g_free (missing->path);
-- g_free (missing);
--
-- missing_list = g_list_remove_link (missing_list, node);
--}
--
--static gboolean gam_inotify_nolonger_missing (const char *path)
--{
-- int wd = -1, err;
-- inotify_data_t *data = NULL;
-- struct stat sbuf;
-- memset(&sbuf, 0, sizeof (struct stat));
--
-- data = g_hash_table_lookup (path_hash, path);
-- if (!data) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: Could not find missing %s in hash table.\n", path);
-- return FALSE;
-- }
--
-- g_assert ((data->missing == TRUE || data->permission == TRUE) && data->link == FALSE);
--
-- wd = gam_inotify_add_watch (path, GAM_INOTIFY_MASK,&err);
-- if (wd < 0) {
-- /* Check if we don't have access to the new file */
-- if (err == EACCES)
-- {
-- data->wd = GAM_INOTIFY_WD_PERM;
-- data->permission = TRUE;
-- data->missing = FALSE;
-- } else {
-- data->wd = GAM_INOTIFY_WD_MISSING;
-- data->permission = FALSE;
-- data->missing = TRUE;
-- }
-- return FALSE;
-- } else if (gam_inotify_is_link (path)) {
-- GAM_DEBUG(DEBUG_INFO, "inotify: Missing resource %s exists now BUT IT IS A LINK\n", path);
-- /* XXX: See NOTE1 */
-- if (g_hash_table_lookup (wd_hash, GINT_TO_POINTER(wd)) == NULL)
-- gam_inotify_rm_watch (path, wd);
-- data->missing = FALSE;
-- data->permission = FALSE;
-- data->link = TRUE;
-- data->wd = GAM_INOTIFY_WD_LINK;
-- gam_inotify_add_link (path);
-- gam_inotify_send_initial_events_all (data);
-- return TRUE;
-- }
--
--
-- GAM_DEBUG(DEBUG_INFO, "inotify: Missing resource %s exists now\n", path);
--
-- lstat (path, &sbuf);
-- data->dir = (sbuf.st_mode & S_IFDIR);
-- data->wd = wd;
-- g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
-- gam_inotify_send_initial_events_all (data);
-- data->missing = FALSE;
-- data->permission = FALSE;
--
-- return TRUE;
-+ return ih_startup (gam_inotify_event_callback,
-+ gam_inotify_found_callback);
- }
-
--/* This function is called once per second in the main loop*/
--static gboolean gam_inotify_scan_missing (gpointer userdata)
-+gboolean
-+gam_inotify_add_subscription (GamSubscription *sub)
- {
-- guint i;
-+ ih_sub_t *isub = NULL;
-+ isub = ih_sub_new (gam_subscription_get_path (sub), gam_subscription_is_dir (sub), 0, sub);
-
-- gam_inotify_sanity_check ();
-- /* We have to walk the list like this because entries might be removed while we walk the list */
-- for (i = 0; ; i++)
-+ if (!ih_sub_add (isub))
- {
-- inotify_missing_t *missing = g_list_nth_data (missing_list, i);
--
-- if (!missing)
-- break;
--
-- /* Not enough time has passed since the last scan */
-- if (time(NULL) - missing->last_scan_time < missing->scan_interval)
-- continue;
--
-- missing->last_scan_time = time(NULL);
-- if (!gam_inotify_is_missing (missing->path))
-- {
-- if (gam_inotify_nolonger_missing (missing->path))
-- {
--#ifdef GAMIN_DEBUG_API
-- gam_debug_report(GAMDnotifyCreate, missing->path, 0);
--#endif
-- gam_inotify_rm_missing (missing->path);
-- }
-- }
-- }
--
-- gam_inotify_sanity_check ();
-- return TRUE;
--}
--
--
--static gboolean
--gam_inotify_is_link (const char *path)
--{
-- struct stat sbuf;
--
-- if (lstat(path, &sbuf) < 0)
-- return FALSE;
--
-- return S_ISLNK(sbuf.st_mode) != 0;
--}
--
--static gboolean
--gam_inotify_nolonger_link (const char *path)
--{
-- int wd = -1, err;
-- inotify_data_t *data = NULL;
-- struct stat sbuf;
-- memset(&sbuf, 0, sizeof (struct stat));
--
-- GAM_DEBUG(DEBUG_INFO, "inotify: link resource %s no longer a link\n", path);
-- data = g_hash_table_lookup (path_hash, path);
-- if (!data) {
-- GAM_DEBUG (DEBUG_INFO, "inotify: Could not find link %s in hash table.\n", path);
-+ ih_sub_free (isub);
- return FALSE;
- }
-
-- g_assert (data->link == TRUE && data->missing == FALSE && data->permission == FALSE);
--
-- wd = gam_inotify_add_watch (path, GAM_INOTIFY_MASK, &err);
-- if (wd < 0) {
-- /* The file must not exist anymore, so we add it to the missing list */
-- data->link = FALSE;
-- /* Check if we don't have access to the new file */
-- if (err == EACCES)
-- {
-- data->wd = GAM_INOTIFY_WD_PERM;
-- data->permission = TRUE;
-- data->missing = FALSE;
-- } else {
-- data->wd = GAM_INOTIFY_WD_MISSING;
-- data->permission = FALSE;
-- data->missing = TRUE;
-- }
--
-- gam_server_emit_event (path, data->dir, GAMIN_EVENT_DELETED, data->subs, 1);
-- gam_inotify_add_missing (path, data->permission);
-- return TRUE;
-- } else if (gam_inotify_is_link (path)) {
-- GAM_DEBUG(DEBUG_INFO, "inotify: Link resource %s re-appeared as a link...\n", path);
-- /* NOTE1: This is tricky, because inotify works on the inode level and
-- * we are dealing with a link, we can be watching the same inode
-- * from two different paths (the wd's will be the same). So,
-- * if the wd isn't in the hash table, we can remvoe the watch,
-- * otherwise we just leave the watch. This should probably be
-- * handled by ref counting
-- */
-- if (g_hash_table_lookup (wd_hash, GINT_TO_POINTER(wd)) == NULL)
-- gam_inotify_rm_watch (path, wd);
-- data->missing = FALSE;
-- data->permission = FALSE;
-- data->link = TRUE;
-- data->wd = GAM_INOTIFY_WD_LINK;
-- gam_inotify_send_initial_events_all (data);
-- return FALSE;
-- }
-+ gam_inotify_send_initial_events (gam_subscription_get_path (sub), sub, gam_subscription_is_dir (sub), FALSE);
-
-- lstat (path, &sbuf);
-- data->dir = (sbuf.st_mode & S_IFDIR);
-- data->wd = wd;
-- g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data);
-- gam_inotify_send_initial_events_all (data);
-- data->missing = FALSE;
-- data->permission = FALSE;
- return TRUE;
- }
-
--static gint links_list_compare (gconstpointer a, gconstpointer b)
--{
-- const inotify_links_t *links = NULL;
--
-- g_assert (a);
-- g_assert (b);
-- links = a;
-- g_assert (links->path);
--
-- return strcmp (links->path, b);
--}
--
--static void
--gam_inotify_add_link (const char *path)
--{
-- inotify_links_t *links = NULL;
-- struct stat sbuf;
--
-- g_assert (path);
--
-- links = g_new0 (inotify_links_t, 1);
--
-- g_assert (links);
--
-- GAM_DEBUG (DEBUG_INFO, "inotify-link: add - %s\n", path);
-- links->path = g_strdup (path);
-- links->scan_interval = gam_fs_get_poll_timeout (path);
-- links->last_scan_time = 0;
-- lstat(path, &sbuf);
-- links->sbuf = sbuf;
-- links_list = g_list_prepend (links_list, links);
--}
--
--static void
--gam_inotify_rm_link (const char *path)
-+static gboolean
-+gam_inotify_remove_sub_pred (ih_sub_t *sub, void *callerdata)
- {
-- GList *node = NULL;
-- inotify_links_t *links = NULL;
--
-- g_assert (path && *path);
--
-- node = g_list_find_custom (links_list, path, links_list_compare);
--
-- if (!node)
-- return;
--
-- GAM_DEBUG (DEBUG_INFO, "inotify-link: rm - %s\n", path);
-- links = node->data;
-- g_free (links->path);
-- g_free (links);
--
-- links_list = g_list_remove_link (links_list, node);
--
-+ return sub->usersubdata == callerdata;
- }
-
--static gboolean
--gam_inotify_scan_links (gpointer userdata)
-+gboolean
-+gam_inotify_remove_subscription (GamSubscription *sub)
- {
-- guint i;
--
-- gam_inotify_sanity_check ();
-- /* We have to walk the list like this because entries might be removed while we walk the list */
-- for (i = 0; ; i++)
-- {
-- inotify_links_t *links = g_list_nth_data (links_list, i);
--
-- if (!links)
-- break;
--
-- /* Not enough time has passed since the last scan */
-- if (time(NULL) - links->last_scan_time < links->scan_interval)
-- continue;
--
-- links->last_scan_time = time(NULL);
-- if (!gam_inotify_is_link (links->path))
-- {
-- if (gam_inotify_nolonger_link (links->path))
-- {
-- gam_inotify_rm_link (links->path);
-- }
-- } else {
-- gam_inotify_poll_link (links);
-- }
--
-- }
-+ ih_sub_foreach_free (sub, gam_inotify_remove_sub_pred);
-
-- gam_inotify_sanity_check ();
- return TRUE;
- }
-
- static gboolean
--gam_inotify_stat_changed (struct stat sbuf1, struct stat sbuf2)
--{
--#ifdef ST_MTIM_NSEC
-- return ((sbuf1.st_mtim.tv_sec != sbuf2.st_mtim.tv_sec) ||
-- (sbuf1.st_mtim.tv_nsec != sbuf2.st_mtim.tv_nsec) ||
-- (sbuf1.st_size != sbuf2.st_size) ||
-- (sbuf1.st_ctim.tv_sec != sbuf2.st_ctim.tv_sec) ||
-- (sbuf1.st_ctim.tv_nsec != sbuf2.st_ctim.tv_nsec));
--#else
-- return ((sbuf1.st_mtime != sbuf2.st_mtime) ||
-- (sbuf1.st_size != sbuf2.st_size) ||
-- (sbuf1.st_ctime != sbuf2.st_ctime));
--#endif
--}
--
--static void
--gam_inotify_poll_link (inotify_links_t *links)
--{
-- struct stat sbuf;
-- g_assert (links);
--
-- /* Next time around, we will detect the deletion, and send the event */
-- if (lstat (links->path, &sbuf) < 0)
-- return;
--
-- if (gam_inotify_stat_changed (sbuf, links->sbuf))
-- {
-- inotify_data_t *data = g_hash_table_lookup (path_hash, links->path);
-- g_assert (data);
-- gam_server_emit_event (data->path, data->dir, GAMIN_EVENT_CHANGED, data->subs, 1);
-- }
--
-- links->sbuf = sbuf;
--}
--
--static void
--gam_inotify_wd_check (gpointer key, gpointer value, gpointer user_data)
--{
-- gint wd = GPOINTER_TO_INT(key);
-- inotify_data_t *data = (inotify_data_t *)value;
-- if (wd < 0)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: FAILURE wd hash for %s key < 0\n", data->path);
-- }
-- if (data->wd < 0)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: FAILURE wd hash for %s value < 0\n", data->path);
-- }
-- if (data->wd != wd)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: FAILURE wd hash value & key don't match\n");
-- }
--}
--
--static void
--gam_inotify_wd_hash_sanity_check (void)
--{
-- g_hash_table_foreach (wd_hash, gam_inotify_wd_check, NULL);
--}
--
--static void
--gam_inotify_missing_check (gpointer data, gpointer user_data)
-+gam_inotify_remove_listener_pred (ih_sub_t *sub, void *callerdata)
- {
-- inotify_missing_t *missing = data;
-- inotify_data_t *idata = NULL;
--
-- if (!missing)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: Missing check called with NULL argument\n");
-- return;
-- }
--
-- if (!missing->path)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: Missing entry missing path name\n");
-- return;
-- }
--
-- idata = g_hash_table_lookup (path_hash, missing->path);
--
-- if (!idata)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: Could not find %s in path hash table\n", missing->path);
-- return;
-- }
--
-- if (idata->wd != GAM_INOTIFY_WD_MISSING && idata->wd != GAM_INOTIFY_WD_PERM)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->wd != GAM_INOTIFY_WD_(MISSING/PERM) for path in missing list\n");
-- return;
-- }
--
-- if (idata->missing != TRUE && idata->permission != TRUE)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->missing/permission != TRUE for path in missing list\n");
-- return;
-- }
--
-- if (idata->missing == TRUE && idata->wd != GAM_INOTIFY_WD_MISSING)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->missing == TRUE && idata->wd != GAM_INOTIFY_WD_MISSING\n");
-- return;
-- }
--
-- if (idata->permission == TRUE && idata->wd != GAM_INOTIFY_WD_PERM)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->permission == TRUE && idata->wd != GAM_INOTIFY_WD_PERM\n");
-- return;
-- }
-+ GamSubscription *gsub = (GamSubscription *)sub->usersubdata;
-
-- if (idata->wd == GAM_INOTIFY_WD_MISSING && idata->missing != TRUE)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->missing == FALSE && idata->wd == GAM_INOTIFY_WD_MISSING\n");
-- return;
-- }
--
-- if (idata->wd == GAM_INOTIFY_WD_PERM && idata->permission != TRUE)
-- {
-- GAM_DEBUG (DEBUG_INFO, "inotify-sanity: data->permission != TRUE && idata->wd == GAM_INOTIFY_WD_PERM\n");
-- return;
-- }
-+ return gam_subscription_get_listener (gsub) == callerdata;
- }
-
--static void
--gam_inotify_missing_list_sanity_check (void)
-+gboolean
-+gam_inotify_remove_all_for (GamListener *listener)
- {
-- g_list_foreach (missing_list, gam_inotify_missing_check, NULL);
--}
--
-+ ih_sub_foreach_free (listener, gam_inotify_remove_listener_pred);
-
--static void
--gam_inotify_sanity_check (void)
--{
--#ifdef GAM_INOTIFY_SANITY
-- gam_inotify_wd_hash_sanity_check ();
-- gam_inotify_missing_list_sanity_check ();
--#endif
-+ return TRUE;
- }
-
--static gboolean
--g_timeval_lt(GTimeVal *val1, GTimeVal *val2)
-+void
-+gam_inotify_debug (void)
- {
-- if (val1->tv_sec < val2->tv_sec)
-- return TRUE;
--
-- if (val1->tv_sec > val2->tv_sec)
-- return FALSE;
--
-- /* val1->tv_sec == val2->tv_sec */
-- if (val1->tv_usec < val2->tv_usec)
-- return TRUE;
--
-- return FALSE;
-+ id_dump (NULL);
- }
-
--static gboolean
--g_timeval_eq(GTimeVal *val1, GTimeVal *val2)
-+gboolean
-+gam_inotify_is_running (void)
- {
-- return (val1->tv_sec == val2->tv_sec) && (val1->tv_usec == val2->tv_usec);
-+ return ih_running ();
- }
--
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-sub.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,121 @@
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-+
-+/* inotify-helper.c - Gnome VFS Monitor based on inotify.
-+
-+ Copyright (C) 2006 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Authors:
-+ John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+#include "config.h"
-+#include <string.h>
-+#include <glib.h>
-+#include "gam_subscription.h"
-+#include "inotify-sub.h"
-+
-+static gboolean is_debug_enabled = FALSE;
-+#define IS_W if (is_debug_enabled) g_warning
-+
-+static void ih_sub_setup (ih_sub_t *sub);
-+
-+ih_sub_t *
-+ih_sub_new (const char *pathname, gboolean is_dir, guint32 flags, void *userdata)
-+{
-+ ih_sub_t *sub = NULL;
-+
-+ sub = g_new0 (ih_sub_t, 1);
-+ sub->usersubdata = userdata;
-+ sub->is_dir = is_dir;
-+ sub->extra_flags = flags;
-+ sub->pathname = g_strdup (pathname);
-+
-+ IS_W("new subscription for %s being setup\n", sub->pathname);
-+
-+ ih_sub_setup (sub);
-+ return sub;
-+}
-+
-+void
-+ih_sub_free (ih_sub_t *sub)
-+{
-+ if (sub->filename)
-+ g_free (sub->filename);
-+ if (sub->dirname)
-+ g_free (sub->dirname);
-+ g_free (sub->pathname);
-+ g_free (sub);
-+}
-+
-+static
-+gchar *ih_sub_get_dirname (gchar *pathname)
-+{
-+ return g_path_get_dirname (pathname);
-+}
-+
-+static
-+gchar *ih_sub_get_filename (gchar *pathname)
-+{
-+ gchar *out;
-+ // FIXME: return filename here
-+ return out;
-+}
-+
-+static
-+void ih_sub_fix_dirname (ih_sub_t *sub)
-+{
-+ size_t len = 0;
-+
-+ g_assert (sub->dirname);
-+
-+ len = strlen (sub->dirname);
-+
-+ /* We need to strip a trailing slash
-+ * to get the correct behaviour
-+ * out of the kernel
-+ */
-+ if (sub->dirname[len] == '/')
-+ sub->dirname[len] = '\0';
-+}
-+
-+/*
-+ * XXX: Currently we just follow the gnome vfs monitor type flags when
-+ * deciding how to treat the path. In the future we could try
-+ * and determine whether the path points to a directory or a file but
-+ * that is racey.
-+ */
-+static void
-+ih_sub_setup (ih_sub_t *sub)
-+{
-+ if (sub->is_dir)
-+ {
-+ sub->dirname = g_strdup (sub->pathname);
-+ sub->filename = NULL;
-+ } else {
-+ sub->dirname = ih_sub_get_dirname (sub->pathname);
-+ sub->filename = ih_sub_get_filename (sub->pathname);
-+ }
-+
-+ ih_sub_fix_dirname (sub);
-+
-+ IS_W("sub->dirname = %s\n", sub->dirname);
-+ if (sub->filename)
-+ {
-+ IS_W("sub->filename = %s\n", sub->filename);
-+ }
-+}
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-helper.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,234 @@
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-+
-+/* inotify-helper.c - Gnome VFS Monitor based on inotify.
-+
-+ Copyright (C) 2005 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Authors:
-+ John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+#include "config.h"
-+#include <errno.h>
-+#include <time.h>
-+#include <string.h>
-+#include <sys/ioctl.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-helper.h"
-+#include "inotify-missing.h"
-+#include "inotify-path.h"
-+#include "inotify-diag.h"
-+
-+static gboolean ih_debug_enabled = FALSE;
-+#define IH_W if (ih_debug_enabled) g_warning
-+
-+static void ih_event_callback (ik_event_t *event, ih_sub_t *sub);
-+static void ih_found_callback (ih_sub_t *sub);
-+
-+/* We share this lock with inotify-kernel.c and inotify-missing.c
-+ *
-+ * inotify-kernel.c takes the lock when it reads events from
-+ * the kernel and when it processes those events
-+ *
-+ * inotify-missing.c takes the lock when it is scanning the missing
-+ * list.
-+ *
-+ * We take the lock in all public functions
-+ */
-+G_LOCK_DEFINE (inotify_lock);
-+static GList *sub_list = NULL;
-+static gboolean initialized = FALSE;
-+static event_callback_t user_ecb = NULL;
-+static found_callback_t user_fcb = NULL;
-+
-+/**
-+ * Initializes the inotify backend. This must be called before
-+ * any other functions in this module.
-+ *
-+ * @returns TRUE if initialization succeeded, FALSE otherwise
-+ */
-+gboolean
-+ih_startup (event_callback_t ecb,
-+ found_callback_t fcb)
-+{
-+ static gboolean result = FALSE;
-+
-+ G_LOCK(inotify_lock);
-+
-+ if (initialized == TRUE) {
-+ G_UNLOCK(inotify_lock);
-+ return result;
-+ }
-+
-+ initialized = TRUE;
-+
-+ result = ip_startup (ih_event_callback);
-+ if (!result) {
-+ g_warning( "Could not initialize inotify\n");
-+ G_UNLOCK(inotify_lock);
-+ return FALSE;
-+ }
-+ user_ecb = ecb;
-+ user_fcb = fcb;
-+ im_startup (ih_found_callback);
-+ id_startup ();
-+
-+ IH_W ("started gnome-vfs inotify backend\n");
-+
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+}
-+
-+gboolean
-+ih_running (void)
-+{
-+ return initialized;
-+}
-+
-+/**
-+ * Adds a subscription to be monitored.
-+ */
-+gboolean
-+ih_sub_add (ih_sub_t * sub)
-+{
-+ G_LOCK(inotify_lock);
-+
-+ g_assert (g_list_find (sub_list, sub) == NULL);
-+
-+ // make sure that sub isn't on sub_list first.
-+ if (!ip_start_watching (sub))
-+ {
-+ im_add (sub);
-+ }
-+
-+ sub_list = g_list_prepend (sub_list, sub);
-+
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+}
-+
-+/**
-+ * Cancels a subscription which was being monitored.
-+ */
-+gboolean
-+ih_sub_cancel (ih_sub_t * sub)
-+{
-+ G_LOCK(inotify_lock);
-+
-+
-+ if (!sub->cancelled)
-+ {
-+ IH_W("cancelling %s\n", sub->pathname);
-+ g_assert (g_list_find (sub_list, sub) != NULL);
-+ sub->cancelled = TRUE;
-+ im_rm (sub);
-+ ip_stop_watching (sub);
-+ sub_list = g_list_remove (sub_list, sub);
-+ }
-+
-+ G_UNLOCK(inotify_lock);
-+ return TRUE;
-+}
-+
-+static void
-+ih_sub_foreach_worker (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata), gboolean free)
-+{
-+ GList *l = NULL;
-+ GList *removed = NULL;
-+
-+ G_LOCK(inotify_lock);
-+
-+ for (l = sub_list; l; l = l->next)
-+ {
-+ ih_sub_t *sub = l->data;
-+
-+ if (f(sub, callerdata))
-+ {
-+ removed = g_list_prepend (removed, l);
-+ ih_sub_cancel (sub);
-+ if (free)
-+ ih_sub_free (sub);
-+ }
-+ }
-+
-+ for (l = removed; l ; l = l->next)
-+ {
-+ GList *llink = l->data;
-+ sub_list = g_list_remove_link (sub_list, llink);
-+ g_list_free_1 (llink);
-+ }
-+
-+ G_UNLOCK(inotify_lock);
-+}
-+
-+void
-+ih_sub_foreach (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata))
-+{
-+ ih_sub_foreach_worker (callerdata, f, FALSE);
-+}
-+
-+void
-+ih_sub_foreach_free (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata))
-+{
-+ ih_sub_foreach_worker (callerdata, f, TRUE);
-+}
-+
-+static void ih_event_callback (ik_event_t *event, ih_sub_t *sub)
-+{
-+ gchar *fullpath;
-+ if (event->name)
-+ {
-+ fullpath = g_strdup_printf ("%s/%s", sub->dirname, event->name);
-+ } else {
-+ fullpath = g_strdup_printf ("%s/", sub->dirname);
-+ }
-+
-+ user_ecb (fullpath, event->mask, sub->usersubdata);
-+ g_free(fullpath);
-+}
-+
-+static void ih_found_callback (ih_sub_t *sub)
-+{
-+ gchar *fullpath;
-+
-+ if (sub->filename)
-+ {
-+ fullpath = g_strdup_printf ("%s/%s", sub->dirname, sub->filename);
-+ if (!g_file_test (fullpath, G_FILE_TEST_EXISTS)) {
-+ g_free (fullpath);
-+ return;
-+ }
-+ } else {
-+ fullpath = g_strdup_printf ("%s/", sub->dirname);
-+ }
-+
-+ user_fcb (fullpath, sub->usersubdata);
-+ g_free(fullpath);
-+}
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-diag.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,67 @@
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-+
-+/* inotify-helper.c - Gnome VFS Monitor based on inotify.
-+
-+ Copyright (C) 2005 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Authors:
-+ John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+#include "config.h"
-+#include <glib.h>
-+#include <sys/types.h>
-+#include <unistd.h>
-+#include "inotify-missing.h"
-+#include "inotify-path.h"
-+#include "inotify-diag.h"
-+
-+#define DIAG_DUMP_TIME 20000 /* 20 seconds */
-+G_LOCK_EXTERN (inotify_lock);
-+
-+gboolean id_dump (gpointer userdata)
-+{
-+ G_LOCK (inotify_lock);
-+ GIOChannel *ioc = NULL;
-+ pid_t pid = getpid();
-+ char *fname = g_strdup_printf("/tmp/gvfsid.%d", pid);
-+ ioc = g_io_channel_new_file (fname, "w", NULL);
-+ g_free (fname);
-+ if (!ioc)
-+ {
-+ G_UNLOCK (inotify_lock);
-+ return TRUE;
-+ }
-+
-+ im_diag_dump (ioc);
-+
-+ g_io_channel_shutdown (ioc, TRUE, NULL);
-+ g_io_channel_unref (ioc);
-+ G_UNLOCK (inotify_lock);
-+ return TRUE;
-+}
-+
-+void id_startup ()
-+{
-+ if (!g_getenv ("GNOME_VFS_INOTIFY_DIAG"))
-+ {
-+ return;
-+ }
-+
-+ g_timeout_add (DIAG_DUMP_TIME, id_dump, NULL);
-+}
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-path.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,27 @@
-+/*
-+ Copyright (C) 2006 John McCutchan <john@johnmccutchan.com>
-+
-+ This program is free software; you can redistribute it and/or modify
-+ it under the terms of the GNU General Public License as published by
-+ the Free Software Foundation; version 2.
-+
-+ This program 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 General Public License version 2 for more details.
-+ You should have received a copy of the GNU General Public License
-+ along with this program; if not, write to the Free Software Foundation,
-+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-+*/
-+
-+#ifndef __INOTIFY_PATH_H
-+#define __INOTIFY_PATH_H
-+
-+#include "inotify-kernel.h"
-+#include "inotify-sub.h"
-+
-+gboolean ip_startup (void (*event_cb)(ik_event_t *event, ih_sub_t *sub));
-+gboolean ip_start_watching (ih_sub_t *sub);
-+gboolean ip_stop_watching (ih_sub_t *sub);
-+
-+#endif
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-path.c 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,387 @@
-+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-+
-+/* inotify-helper.c - Gnome VFS Monitor based on inotify.
-+
-+ Copyright (C) 2006 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Authors:
-+ John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+#include "config.h"
-+
-+/* Don't put conflicting kernel types in the global namespace: */
-+#define __KERNEL_STRICT_NAMES
-+
-+#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 <string.h>
-+#include <glib.h>
-+#include "inotify-kernel.h"
-+#include "inotify-path.h"
-+#include "inotify-missing.h"
-+
-+#define IP_INOTIFY_MASK (IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|IN_CREATE|IN_DELETE_SELF|IN_UNMOUNT|IN_MOVE_SELF)
-+
-+typedef struct ip_watched_dir_s {
-+ char *path;
-+ /* TODO: We need to maintain a tree of watched directories
-+ * so that we can deliver move/delete events to sub folders.
-+ * Or the application could do it...
-+ */
-+ struct ip_watched_dir_s *parent;
-+ GList * children;
-+
-+ /* Inotify state */
-+ gint32 wd;
-+
-+ /* List of inotify subscriptions */
-+ GList *subs;
-+} ip_watched_dir_t;
-+
-+static gboolean ip_debug_enabled = FALSE;
-+#define IP_W if (ip_debug_enabled) g_warning
-+
-+/* path -> ip_watched_dir */
-+static GHashTable * path_dir_hash = NULL;
-+/* ih_sub_t * -> ip_watched_dir *
-+ *
-+ * Each subscription is attached to a watched directory or it is on
-+ * the missing list
-+ */
-+static GHashTable * sub_dir_hash = NULL;
-+/* This hash holds GLists of ip_watched_dir_t *'s
-+ * We need to hold a list because symbolic links can share
-+ * the same wd
-+ */
-+static GHashTable * wd_dir_hash = NULL;
-+
-+static ip_watched_dir_t * ip_watched_dir_new (const char *path, int wd);
-+static void ip_watched_dir_free (ip_watched_dir_t *dir);
-+static void ip_event_callback (ik_event_t *event);
-+
-+static void (*event_callback)(ik_event_t *event, ih_sub_t *sub);
-+
-+gboolean ip_startup (void (*cb)(ik_event_t *event, ih_sub_t *sub))
-+{
-+ static gboolean initialized = FALSE;
-+ static gboolean result = FALSE;
-+
-+ if (initialized == TRUE) {
-+ return result;
-+ }
-+
-+ initialized = TRUE;
-+ event_callback = cb;
-+ result = ik_startup (ip_event_callback);
-+
-+ if (!result) {
-+ return FALSE;
-+ }
-+
-+ path_dir_hash = g_hash_table_new(g_str_hash, g_str_equal);
-+ sub_dir_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
-+ wd_dir_hash = g_hash_table_new(g_direct_hash, g_direct_equal);
-+
-+ return TRUE;
-+}
-+
-+static void
-+ip_map_path_dir (const char *path, ip_watched_dir_t *dir)
-+{
-+ g_assert (path && dir);
-+ g_hash_table_insert(path_dir_hash, dir->path, dir);
-+}
-+
-+static void
-+ip_map_sub_dir (ih_sub_t *sub, ip_watched_dir_t *dir)
-+{
-+ /* Associate subscription and directory */
-+ g_assert (dir && sub);
-+ g_hash_table_insert (sub_dir_hash, sub, dir);
-+ dir->subs = g_list_prepend (dir->subs, sub);
-+}
-+
-+static void
-+ip_map_wd_dir (gint32 wd, ip_watched_dir_t *dir)
-+{
-+ g_assert (wd >= 0 && dir);
-+ GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(wd));
-+ dir_list = g_list_prepend (dir_list, dir);
-+ g_hash_table_replace(wd_dir_hash, GINT_TO_POINTER(dir->wd), dir_list);
-+}
-+
-+gboolean ip_start_watching (ih_sub_t *sub)
-+{
-+ gint32 wd;
-+ int err;
-+ ip_watched_dir_t *dir;
-+
-+ g_assert (sub);
-+ g_assert (!sub->cancelled);
-+ g_assert (sub->dirname);
-+
-+ IP_W("Starting to watch %s\n", sub->dirname);
-+ dir = g_hash_table_lookup (path_dir_hash, sub->dirname);
-+ if (dir)
-+ {
-+ IP_W("Already watching\n");
-+ goto out;
-+ }
-+
-+ IP_W("Trying to add inotify watch ");
-+ wd = ik_watch (sub->dirname, IP_INOTIFY_MASK|IN_ONLYDIR|sub->extra_flags, &err);
-+ if (wd < 0)
-+ {
-+ IP_W("Failed\n");
-+ return FALSE;
-+ } else {
-+ /* Create new watched directory and associate it with the
-+ * wd hash and path hash
-+ */
-+ IP_W("Success\n");
-+ dir = ip_watched_dir_new (sub->dirname, wd);
-+ ip_map_wd_dir (wd, dir);
-+ ip_map_path_dir (sub->dirname, dir);
-+ }
-+
-+out:
-+ ip_map_sub_dir (sub, dir);
-+
-+ return TRUE;
-+}
-+
-+static void
-+ip_unmap_path_dir (const char *path, ip_watched_dir_t *dir)
-+{
-+ g_assert (path && dir);
-+ g_hash_table_remove (path_dir_hash, dir->path);
-+}
-+
-+static void
-+ip_unmap_wd_dir (gint32 wd, ip_watched_dir_t *dir)
-+{
-+ GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(wd));
-+ if (!dir_list)
-+ return;
-+ g_assert (wd >= 0 && dir);
-+ dir_list = g_list_remove (dir_list, dir);
-+ if (dir_list == NULL) {
-+ g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER(dir->wd));
-+ } else {
-+ g_hash_table_replace (wd_dir_hash, GINT_TO_POINTER(dir->wd), dir_list);
-+ }
-+}
-+
-+static void
-+ip_unmap_wd (gint32 wd)
-+{
-+ GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(wd));
-+ if (!dir_list)
-+ return;
-+ g_assert (wd >= 0);
-+ g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER(wd));
-+ g_list_free (dir_list);
-+}
-+
-+static void
-+ip_unmap_sub_dir (ih_sub_t *sub, ip_watched_dir_t *dir)
-+{
-+ g_assert (sub && dir);
-+ g_hash_table_remove (sub_dir_hash, sub);
-+ dir->subs = g_list_remove (dir->subs, sub);
-+}
-+
-+static void
-+ip_unmap_all_subs (ip_watched_dir_t *dir)
-+{
-+ GList *l = NULL;
-+
-+ for (l = dir->subs; l; l = l->next)
-+ {
-+ ih_sub_t *sub = l->data;
-+ g_hash_table_remove (sub_dir_hash, sub);
-+ }
-+ g_list_free (dir->subs);
-+ dir->subs = NULL;
-+}
-+
-+gboolean ip_stop_watching (ih_sub_t *sub)
-+{
-+ ip_watched_dir_t *dir = NULL;
-+
-+ dir = g_hash_table_lookup (sub_dir_hash, sub);
-+ if (!dir) {
-+ return TRUE;
-+ }
-+
-+ ip_unmap_sub_dir (sub, dir);
-+
-+ /* No one is subscribing to this directory any more */
-+ if (dir->subs == NULL) {
-+ ik_ignore (dir->path, dir->wd);
-+ ip_unmap_wd_dir (dir->wd, dir);
-+ ip_unmap_path_dir (dir->path, dir);
-+ ip_watched_dir_free (dir);
-+ }
-+
-+ return TRUE;
-+}
-+
-+
-+static ip_watched_dir_t *
-+ip_watched_dir_new (const char *path, gint32 wd)
-+{
-+ ip_watched_dir_t *dir = g_new0(ip_watched_dir_t, 1);
-+
-+ dir->path = g_strdup(path);
-+ dir->wd = wd;
-+
-+ return dir;
-+}
-+
-+static void
-+ip_watched_dir_free (ip_watched_dir_t * dir)
-+{
-+ g_assert (dir->subs == 0);
-+ g_free(dir->path);
-+ g_free(dir);
-+}
-+
-+static void ip_wd_delete (gpointer data, gpointer user_data)
-+{
-+ ip_watched_dir_t *dir = data;
-+ GList *l = NULL;
-+
-+ for (l = dir->subs; l; l = l->next)
-+ {
-+ ih_sub_t *sub = l->data;
-+
-+ /* Add subscription to missing list */
-+ im_add (sub);
-+ }
-+ ip_unmap_all_subs (dir);
-+ /* Unassociate the path and the directory */
-+ ip_unmap_path_dir (dir->path, dir);
-+ ip_watched_dir_free (dir);
-+}
-+
-+static void ip_event_dispatch (GList *dir_list, GList *pair_dir_list, ik_event_t *event)
-+{
-+ GList *dirl;
-+
-+ if (!event)
-+ return;
-+
-+ /* TODO:
-+ *
-+ * Figure out how we will deliver move events
-+ */
-+ for (dirl = dir_list; dirl; dirl = dirl->next)
-+ {
-+ GList *subl;
-+ ip_watched_dir_t *dir = dirl->data;
-+
-+ for (subl = dir->subs; subl; subl = subl->next)
-+ {
-+ ih_sub_t *sub = subl->data;
-+
-+ /* If the event and the subscription have a filename
-+ * they need to match before the event could be delivered.
-+ */
-+ if (event->name && sub->filename) {
-+ if (strcmp (event->name, sub->filename))
-+ continue;
-+ /* If the event doesn't have a filename, but the subscription does
-+ * we shouldn't deliever the event */
-+ } else if (sub->filename)
-+ continue;
-+
-+ event_callback (event, sub);
-+ }
-+ }
-+
-+ if (!event->pair)
-+ return;
-+
-+ for (dirl = pair_dir_list; dirl; dirl = dirl->next)
-+ {
-+ GList *subl;
-+ ip_watched_dir_t *dir = dirl->data;
-+
-+ for (subl = dir->subs; subl; subl = subl->next)
-+ {
-+ ih_sub_t *sub = subl->data;
-+
-+ /* If the event and the subscription have a filename
-+ * they need to match before the event could be delivered.
-+ */
-+ if (event->pair->name && sub->filename) {
-+ if (strcmp (event->pair->name, sub->filename))
-+ continue;
-+ /* If the event doesn't have a filename, but the subscription does
-+ * we shouldn't deliever the event */
-+ } else if (sub->filename)
-+ continue;
-+
-+ event_callback (event->pair, sub);
-+ }
-+ }
-+}
-+
-+static void
-+ip_event_callback (ik_event_t *event)
-+{
-+ GList *dir_list = NULL;
-+ GList *pair_dir_list = NULL;
-+
-+ dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(event->wd));
-+
-+ /* We can ignore IN_IGNORED events */
-+ if (event->mask & IN_IGNORED) {
-+ ik_event_free (event);
-+ return;
-+ }
-+
-+ if (event->pair)
-+ pair_dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(event->pair->wd));
-+
-+ if (event->mask & IP_INOTIFY_MASK)
-+ ip_event_dispatch (dir_list, pair_dir_list, event);
-+
-+ /* We have to manage the missing list when we get a DELETE event. */
-+ if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF)
-+ {
-+ /* Add all subscriptions to missing list */
-+ g_list_foreach (dir_list, ip_wd_delete, NULL);
-+ /* Unmap all directories attached to this wd */
-+ ip_unmap_wd (event->wd);
-+ }
-+
-+ ik_event_free (event);
-+}
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-helper.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,45 @@
-+/* inotify-helper.h - GNOME VFS Monitor using inotify
-+
-+ Copyright (C) 2005 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Author: John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+
-+#ifndef __INOTIFY_HELPER_H
-+#define __INOTIFY_HELPER_H
-+
-+#include "inotify-sub.h"
-+#include "inotify-kernel.h"
-+
-+typedef void (*event_callback_t)(const char *fullpath, guint32 mask, void *subdata);
-+typedef void (*found_callback_t)(const char *fullpath, void *subdata);
-+
-+gboolean ih_startup (event_callback_t ecb,
-+ found_callback_t fcb);
-+gboolean ih_running (void);
-+gboolean ih_sub_add (ih_sub_t *sub);
-+gboolean ih_sub_cancel (ih_sub_t *sub);
-+
-+/* Return FALSE from 'f' if the subscription should be cancelled */
-+void ih_sub_foreach (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata));
-+
-+/* Return FALSE from 'f' if the subscription should be cancelled and free'd */
-+void ih_sub_foreach_free (void *callerdata, gboolean (*f)(ih_sub_t *sub, void *callerdata));
-+
-+#endif /* __INOTIFY_HELPER_H */
---- /dev/null 2006-08-28 15:22:40.902752500 +0200
-+++ gamin-0.1.7/server/inotify-sub.h 2006-09-05 11:01:21.000000000 +0200
-@@ -0,0 +1,42 @@
-+/* inotify-helper.h - GNOME VFS Monitor using inotify
-+
-+ Copyright (C) 2006 John McCutchan
-+
-+ The Gnome Library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Library General Public License as
-+ published by the Free Software Foundation; either version 2 of the
-+ License, or (at your option) any later version.
-+
-+ The Gnome 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
-+ Library General Public License for more details.
-+
-+ You should have received a copy of the GNU Library General Public
-+ License along with the Gnome Library; see the file COPYING.LIB. If not,
-+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ Boston, MA 02111-1307, USA.
-+
-+ Author: John McCutchan <john@johnmccutchan.com>
-+*/
-+
-+
-+#ifndef __INOTIFY_SUB_H
-+#define __INOTIFY_SUB_H
-+
-+#include "gam_subscription.h"
-+
-+typedef struct {
-+ gboolean is_dir;
-+ char *pathname;
-+ char *dirname;
-+ char *filename;
-+ guint32 extra_flags;
-+ gboolean cancelled;
-+ void *usersubdata;
-+} ih_sub_t;
-+
-+ih_sub_t *ih_sub_new (const char *pathname, gboolean is_dir, guint32 flags, void *userdata);
-+void ih_sub_free (ih_sub_t *sub);
-+
-+#endif /* __INOTIFY_SUB_H */
---- gamin-0.1.7/server/local_inotify.h.new-inotify-backend 2005-08-17 15:50:04.000000000 +0200
-+++ gamin-0.1.7/server/local_inotify.h 2006-09-05 11:01:21.000000000 +0200
-@@ -47,6 +47,9 @@
- #define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
-
- /* special flags */
-+#define IN_ONLYDIR 0x01000000 /* only watch the path if it is a directory */
-+#define IN_DONT_FOLLOW 0x02000000 /* don't follow a sym link */
-+#define IN_MASK_ADD 0x20000000 /* add to the mask of an already existing watch */
- #define IN_ISDIR 0x40000000 /* event occurred against dir */
- #define IN_ONESHOT 0x80000000 /* only send event once */
-
diff --git a/app-admin/gamin/files/gamin-no-timers.patch b/app-admin/gamin/files/gamin-no-timers.patch
deleted file mode 100644
index b2e2135..0000000
--- a/app-admin/gamin/files/gamin-no-timers.patch
+++ /dev/null
@@ -1,284 +0,0 @@
-Index: lib/gam_error.c
-===================================================================
-RCS file: /cvs/gnome/gamin/lib/gam_error.c,v
-retrieving revision 1.11
-diff -u -p -r1.11 gam_error.c
---- lib/gam_error.c 19 Apr 2006 08:28:14 -0000 1.11
-+++ lib/gam_error.c 5 Sep 2006 14:02:43 -0000
-@@ -18,6 +18,7 @@
- typedef void (*signal_handler) (int);
-
- extern void gam_show_debug(void);
-+extern void gam_got_signal (void);
-
- int gam_debug_active = 0;
- static int initialized = 0;
-@@ -60,11 +61,13 @@ gam_error_handle_signal(void)
- }
- }
-
-+
- static void
- gam_error_signal(int no)
- {
- got_signal = !got_signal;
- gam_debug_active = -1; /* force going into gam_debug() */
-+ gam_got_signal ();
- }
-
- /**
-Index: libgamin/gam_api.c
-===================================================================
-RCS file: /cvs/gnome/gamin/libgamin/gam_api.c,v
-retrieving revision 1.40
-diff -u -p -r1.40 gam_api.c
---- libgamin/gam_api.c 16 Aug 2006 15:42:44 -0000 1.40
-+++ libgamin/gam_api.c 5 Sep 2006 14:02:43 -0000
-@@ -87,6 +87,13 @@ void
- gam_show_debug(void) {
- }
-
-+void gam_got_signal(void);
-+
-+void
-+gam_got_signal(void) {
-+}
-+
-+
- /************************************************************************
- * *
- * Path for the socket connection *
-Index: server/gam_connection.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_connection.c,v
-retrieving revision 1.29
-diff -u -p -r1.29 gam_connection.c
---- server/gam_connection.c 22 Sep 2005 08:09:03 -0000 1.29
-+++ server/gam_connection.c 5 Sep 2006 14:02:43 -0000
-@@ -42,6 +42,9 @@ struct GamConnData {
- guint eq_source; /* the event queue GSource id */
- };
-
-+static void gam_cancel_server_timeout (void);
-+
-+
- static const char *
- gam_reqtype_to_string (GAMReqType type)
- {
-@@ -126,6 +129,9 @@ gam_connection_close(GamConnDataPtr conn
- g_free(conn->pidname);
- g_free(conn);
-
-+ if (gamConnList == NULL && gam_server_use_timeout ())
-+ gam_schedule_server_timeout ();
-+
- return (0);
- }
-
-@@ -196,6 +202,8 @@ gam_connection_new(GMainLoop *loop, GIOC
- ret->eq_source = g_timeout_add (100 /* ms */, gam_connection_eq_flush, ret);
- gamConnList = g_list_prepend(gamConnList, ret);
-
-+ gam_cancel_server_timeout ();
-+
- GAM_DEBUG(DEBUG_INFO, "Created connection %d\n", ret->fd);
-
- return (ret);
-@@ -683,7 +691,9 @@ gam_send_ack(GamConnDataPtr conn, int re
- * *
- ************************************************************************/
-
--#define MAX_IDLE_TIMEOUT 30
-+#define MAX_IDLE_TIMEOUT_MSEC (30*1000) /* 30 seconds */
-+
-+static guint server_timeout_id = 0;
-
- /**
- * gam_connections_check:
-@@ -692,27 +702,33 @@ gam_send_ack(GamConnDataPtr conn, int re
- * shuts the server down if there have been no outstanding connections
- * for a while.
- */
--gboolean
-+static gboolean
- gam_connections_check(void)
- {
-- static time_t timeout;
--
-- if (g_list_first(gamConnList) != NULL) {
-- if (timeout != 0) {
-- GAM_DEBUG(DEBUG_INFO, "New active connection\n");
-- }
-- timeout = 0;
-- return (TRUE);
-- }
-- if (timeout == 0) {
-- GAM_DEBUG(DEBUG_INFO, "No more active connections\n");
-- timeout = time(NULL);
-- } else if (time(NULL) - timeout > MAX_IDLE_TIMEOUT) {
-+ server_timeout_id = 0;
-+
-+ if (gamConnList == NULL) {
- GAM_DEBUG(DEBUG_INFO, "Exiting on timeout\n");
- gam_shutdown();
- exit(0);
- }
-- return (TRUE);
-+ return (FALSE);
-+}
-+
-+static void
-+gam_cancel_server_timeout (void)
-+{
-+ if (server_timeout_id)
-+ g_source_remove (server_timeout_id);
-+ server_timeout_id = 0;
-+}
-+
-+void
-+gam_schedule_server_timeout (void)
-+{
-+ gam_cancel_server_timeout ();
-+ server_timeout_id =
-+ g_timeout_add(MAX_IDLE_TIMEOUT_MSEC, (GSourceFunc) gam_connections_check, NULL);
- }
-
- /**
-Index: server/gam_connection.h
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_connection.h,v
-retrieving revision 1.6
-diff -u -p -r1.6 gam_connection.h
---- server/gam_connection.h 4 Aug 2005 16:45:25 -0000 1.6
-+++ server/gam_connection.h 5 Sep 2006 14:02:43 -0000
-@@ -25,7 +25,7 @@ typedef enum {
-
- int gam_connections_init (void);
- int gam_connections_close (void);
--gboolean gam_connections_check (void);
-+void gam_schedule_server_timeout (void);
-
- GamConnDataPtr gam_connection_new (GMainLoop *loop,
- GIOChannel *source);
-Index: server/gam_server.c
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_server.c,v
-retrieving revision 1.42
-diff -u -p -r1.42 gam_server.c
---- server/gam_server.c 8 Sep 2005 10:12:03 -0000 1.42
-+++ server/gam_server.c 5 Sep 2006 14:02:44 -0000
-@@ -279,6 +279,17 @@ static GHashTable *listeners = NULL;
- static GIOChannel *socket = NULL;
-
- /**
-+ * gam_server_use_timeout:
-+ *
-+ * Returns TRUE if idle server should exit after a timeout.
-+ */
-+gboolean
-+gam_server_use_timeout (void)
-+{
-+ return !no_timeout;
-+}
-+
-+/**
- * gam_server_emit_one_event:
- * @path: the file/directory path
- * @event: the event type
-@@ -507,6 +519,58 @@ gam_poll_file (GamNode *node)
- return 0;
- }
-
-+#ifdef GAM_DEBUG_ENABLED
-+
-+static GIOChannel *pipe_read_ioc = NULL;
-+static GIOChannel *pipe_write_ioc = NULL;
-+
-+static gboolean
-+gam_error_signal_pipe_handler(gpointer user_data)
-+{
-+ char buf[5000];
-+
-+ if (pipe_read_ioc)
-+ g_io_channel_read_chars(pipe_read_ioc, buf, sizeof(buf), NULL, NULL);
-+
-+ gam_error_check();
-+}
-+
-+static void
-+gam_setup_error_handler (void)
-+{
-+ int signal_pipe[2];
-+ GSource *source;
-+
-+ if (pipe(signal_pipe) != -1) {
-+ pipe_read_ioc = g_io_channel_unix_new(signal_pipe[0]);
-+ pipe_write_ioc = g_io_channel_unix_new(signal_pipe[1]);
-+
-+ g_io_channel_set_flags(pipe_read_ioc, G_IO_FLAG_NONBLOCK, NULL);
-+ g_io_channel_set_flags(pipe_write_ioc, G_IO_FLAG_NONBLOCK, NULL);
-+
-+ source = g_io_create_watch(pipe_read_ioc, G_IO_IN | G_IO_HUP | G_IO_ERR);
-+ g_source_set_callback(source, gam_error_signal_pipe_handler, NULL, NULL);
-+
-+ g_source_attach(source, NULL);
-+ g_source_unref(source);
-+ }
-+}
-+#endif
-+
-+void
-+gam_got_signal()
-+{
-+#ifdef GAM_DEBUG_ENABLED
-+ /* Wake up main loop */
-+ if (pipe_write_ioc) {
-+ g_io_channel_write_chars(pipe_write_ioc, "a", 1, NULL, NULL);
-+ g_io_channel_flush(pipe_write_ioc, NULL);
-+ }
-+#endif
-+}
-+
-+
-+
- /**
- * gam_server_init:
- * @loop: the main event loop of the daemon
-@@ -533,11 +597,11 @@ gam_server_init(GMainLoop * loop, const
- * Register the timeout checking function
- */
- if (no_timeout == 0)
-- g_timeout_add(1000, (GSourceFunc) gam_connections_check, NULL);
-+ gam_schedule_server_timeout ();
- #ifdef GAM_DEBUG_ENABLED
-- g_timeout_add(1000, (GSourceFunc) gam_error_check, NULL);
-+ gam_setup_error_handler ();
- #endif
--
-+
- return TRUE;
- }
-
-Index: server/gam_server.h
-===================================================================
-RCS file: /cvs/gnome/gamin/server/gam_server.h,v
-retrieving revision 1.11
-diff -u -p -r1.11 gam_server.h
---- server/gam_server.h 16 Aug 2005 20:44:17 -0000 1.11
-+++ server/gam_server.h 5 Sep 2006 14:02:44 -0000
-@@ -33,6 +33,7 @@ typedef enum pollHandlerMode {
- } pollHandlerMode;
-
- gboolean gam_init_subscriptions (void);
-+gboolean gam_server_use_timeout (void);
- gboolean gam_add_subscription (GamSubscription *sub);
- gboolean gam_remove_subscription (GamSubscription *sub);
- int gam_server_num_listeners (void);
-@@ -48,6 +49,7 @@ void gam_server_emit_event
- int force);
- void gam_shutdown (void);
- void gam_show_debug (void);
-+void gam_got_signal (void);
-
- void gam_server_install_kernel_hooks (GamKernelHandler name,
- gboolean (*add)(GamSubscription *sub),
diff --git a/app-admin/gamin/files/gamin-stdin-devnull.patch b/app-admin/gamin/files/gamin-stdin-devnull.patch
deleted file mode 100644
index 77c078c..0000000
--- a/app-admin/gamin/files/gamin-stdin-devnull.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-Index: libgamin/gam_fork.c
-===================================================================
-RCS file: /cvs/gnome/gamin/libgamin/gam_fork.c,v
-retrieving revision 1.11
-diff -u -p -r1.11 gam_fork.c
---- libgamin/gam_fork.c 27 Oct 2005 10:58:50 -0000 1.11
-+++ libgamin/gam_fork.c 22 Aug 2006 14:59:11 -0000
-@@ -67,6 +67,7 @@ gamin_fork_server(const char *fam_client
- /* Become a daemon */
- pid = fork();
- if (pid == 0) {
-+ int fd;
- long open_max;
- long i;
-
-@@ -75,6 +76,20 @@ gamin_fork_server(const char *fam_client
- for (i = 0; i < open_max; i++)
- fcntl (i, F_SETFD, FD_CLOEXEC);
-
-+ /* /dev/null for stdin, stdout, stderr */
-+ fd = open ("/dev/null", O_RDONLY);
-+ if (fd != -1) {
-+ dup2 (fd, 0);
-+ close (fd);
-+ }
-+
-+ fd = open ("/dev/null", O_WRONLY);
-+ if (fd != -1) {
-+ dup2 (fd, 1);
-+ dup2 (fd, 2);
-+ close (fd);
-+ }
-+
- setsid();
- if (fork() == 0) {
- #ifdef HAVE_SETENV
diff --git a/app-admin/gamin/files/gamin-timer-on-demand.patch b/app-admin/gamin/files/gamin-timer-on-demand.patch
deleted file mode 100644
index 3375bd5..0000000
--- a/app-admin/gamin/files/gamin-timer-on-demand.patch
+++ /dev/null
@@ -1,73 +0,0 @@
---- gamin-0.1.7/server/gam_eq.c.timer-on-demand 2005-08-05 11:57:48.000000000 +0200
-+++ gamin-0.1.7/server/gam_eq.c 2006-09-05 10:57:06.000000000 +0200
-@@ -119,9 +119,10 @@
- gam_eq_event_free (event);
- }
-
--void
-+gboolean
- gam_eq_flush (gam_eq_t *eq, GamConnDataPtr conn)
- {
-+ gboolean done_work = FALSE;
- if (!eq)
- return;
-
-@@ -130,8 +131,10 @@
- #endif
- while (!g_queue_is_empty (eq->event_queue))
- {
-+ done_work = TRUE;
- gam_eq_event_t *event = g_queue_pop_head (eq->event_queue);
- g_assert (event);
- gam_eq_flush_callback (eq, event, conn);
- }
-+ return done_work;
- }
---- gamin-0.1.7/server/gam_connection.c.timer-on-demand 2005-09-22 10:10:55.000000000 +0200
-+++ gamin-0.1.7/server/gam_connection.c 2006-09-05 10:57:06.000000000 +0200
-@@ -159,12 +159,15 @@
- static gboolean
- gam_connection_eq_flush (gpointer data)
- {
-+ gboolean work;
- GamConnDataPtr conn = (GamConnDataPtr)data;
- if (!conn)
- return FALSE;
-
-- gam_eq_flush (conn->eq, conn);
-- return TRUE;
-+ work = gam_eq_flush (conn->eq, conn);
-+ if (!work)
-+ conn->eq_source = 0;
-+ return work;
- }
-
- /**
-@@ -193,7 +196,7 @@
- ret->loop = loop;
- ret->source = source;
- ret->eq = gam_eq_new ();
-- ret->eq_source = g_timeout_add (100 /* ms */, gam_connection_eq_flush, ret);
-+ ret->eq_source = g_timeout_add (100 /* 100 milisecond */, gam_connection_eq_flush, ret);
- gamConnList = g_list_prepend(gamConnList, ret);
-
- GAM_DEBUG(DEBUG_INFO, "Created connection %d\n", ret->fd);
-@@ -620,6 +623,8 @@
- g_assert (conn->eq);
-
- gam_eq_queue (conn->eq, reqno, event, path, len);
-+ if (!conn->eq_source)
-+ conn->eq_source = g_timeout_add (100 /* 100 milisecond */, gam_connection_eq_flush, conn);
- }
-
-
---- gamin-0.1.7/server/gam_eq.h.timer-on-demand 2006-09-05 11:00:12.000000000 +0200
-+++ gamin-0.1.7/server/gam_eq.h 2006-09-05 11:00:46.000000000 +0200
-@@ -9,6 +9,6 @@
- void gam_eq_free (gam_eq_t *eq);
- void gam_eq_queue (gam_eq_t *eq, int reqno, int event, const char *path, int len);
- guint gam_eq_size (gam_eq_t *eq);
--void gam_eq_flush (gam_eq_t *eq, GamConnDataPtr conn);
-+gboolean gam_eq_flush (gam_eq_t *eq, GamConnDataPtr conn);
-
- #endif
diff --git a/app-admin/gamin/gamin-0.1.7.ebuild b/app-admin/gamin/gamin-0.1.7.ebuild
deleted file mode 100644
index eea8abe..0000000
--- a/app-admin/gamin/gamin-0.1.7.ebuild
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Header: /var/cvsroot/gentoo-x86/app-admin/gamin/gamin-0.1.7.ebuild,v 1.15 2006/03/31 23:53:04 flameeyes Exp $
-
-inherit autotools eutils libtool
-
-DESCRIPTION="Library providing the FAM File Alteration Monitor API"
-HOMEPAGE="http://www.gnome.org/~veillard/gamin/"
-SRC_URI="http://www.gnome.org/~veillard/gamin/sources/${P}.tar.gz
- kernel_FreeBSD? ( mirror://gentoo/${P}-freebsd.patch.bz2 )"
-
-LICENSE="LGPL-2"
-SLOT="0"
-KEYWORDS="alpha amd64 arm hppa ia64 m68k mips ppc ppc64 s390 sh sparc x86 ~x86-fbsd"
-IUSE="debug doc"
-
-RDEPEND=">=dev-libs/glib-2
- !app-admin/fam"
-
-DEPEND="${RDEPEND}
- dev-util/pkgconfig"
-
-PROVIDE="virtual/fam"
-
-src_unpack() {
- unpack ${A}
-
- cd ${S}
-
- # Patches from Fedora Core 6 - http://cvs.fedora.redhat.com/viewcvs/rpms/gamin/devel/gamin.spec?rev=1.53&view=auto
- # They should be all upstream now, but "cvs diff -rTAG -Ddate" hates me and loaning these separate patches is easier
- epatch "${FILESDIR}/${PN}-dont-close-fd.patch"
- epatch "${FILESDIR}/${PN}-stdin-devnull.patch"
- epatch "${FILESDIR}/${PN}-flush-buffer-on-reset.patch"
- epatch "${FILESDIR}/${PN}-0.1.7-sigaction.patch"
- epatch "${FILESDIR}/${PN}-new-inotify-backend.patch"
- epatch "${FILESDIR}/${PN}-inotify-fix.patch"
- epatch "${FILESDIR}/${PN}-timer-on-demand.patch"
- epatch "${FILESDIR}/${PN}-no-timers.patch"
-
- use kernel_FreeBSD && epatch "${DISTDIR}/${P}-freebsd.patch.bz2"
-
- # Do not remove
- elibtoolize
-
- # New inotify backend changes Makefile.am (maybe others do too)
- eautoreconf
-}
-
-src_compile() {
- econf \
- $(use_enable kernel_linux inotify) \
- $(use_enable debug) \
- $(use_enable debug debug-api) \
- || die "econf failed"
-
- emake || die "emake failed"
-}
-
-src_install() {
- make DESTDIR="${D}" install || die
-
- dodoc AUTHORS ChangeLog README TODO NEWS doc/*txt
- use doc && dohtml doc/*
-}
-
-pkg_postinst() {
- if use kernel_linux; then
- einfo "It is strongly suggested you use Gamin with an inotify enabled"
- einfo "kernel for best performance. For this release of gamin you need"
- einfo "at least gentoo-sources-2.6.13 or later."
- fi
-}