diff options
author | 2007-02-04 04:56:48 +0000 | |
---|---|---|
committer | 2007-02-04 04:56:48 +0000 | |
commit | 2c1ef51163eb62f1ec8cf47cc134a84ae23adaf5 (patch) | |
tree | ffc6d5298830e05194d9b80c388433b009db2c50 | |
parent | Update to the newer version, keeping the wakeup fix and in-process applets on... (diff) | |
download | gnome-perf-2c1ef51163eb62f1ec8cf47cc134a84ae23adaf5.tar.gz gnome-perf-2c1ef51163eb62f1ec8cf47cc134a84ae23adaf5.tar.bz2 gnome-perf-2c1ef51163eb62f1ec8cf47cc134a84ae23adaf5.zip |
Remove gamin from here. Version 0.1.8 in portage should contain all the perf and wakeup fixes and more
-rw-r--r-- | app-admin/gamin/ChangeLog | 12 | ||||
-rw-r--r-- | app-admin/gamin/Manifest | 45 | ||||
-rw-r--r-- | app-admin/gamin/files/digest-gamin-0.1.7 | 6 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-0.1.7-sigaction.patch | 60 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-dont-close-fd.patch | 72 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-flush-buffer-on-reset.patch | 15 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-inotify-fix.patch | 93 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-new-inotify-backend.patch | 3643 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-no-timers.patch | 284 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-stdin-devnull.patch | 36 | ||||
-rw-r--r-- | app-admin/gamin/files/gamin-timer-on-demand.patch | 73 | ||||
-rw-r--r-- | app-admin/gamin/gamin-0.1.7.ebuild | 73 |
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 -} |