[gamin] massive patch
- From: John McCutchan <ttb tentacle dhs org>
- To: gamin-list gnome org
- Subject: [gamin] massive patch
- Date: Mon, 15 Aug 2005 14:39:56 -0400
Yo,
So, over the last few days I have completed my big changes to gamin wrt
to the poll stuff. The test suite passes for both dnotify & inotify with
these changes. I'd like to get them in ASAP, so I can stop carrying all
this baggage.
It's pretty much what I discussed earlier:
- Separate generic poll stuff from dnotify specific poll stuff
- Poll backends are pluggable (only a dnotify-specific backend exists
now)
- Some refactoring
I'm attaching the patch, plus the new files. gam_poll.[ch] is now dead.
We now have:
gam_poll_generic.[ch]
all,busy,missing lists
current_time stuff
directory scanning code
gam_poll_dnotify.[ch]
dnotify specific poll stuff (flow control)
dnotify specific poll file
--
John McCutchan <ttb tentacle dhs org>
? .pc
? Makefile
? Makefile.in
? aclocal.m4
? autom4te.cache
? config.h
? config.h.in
? config.log
? config.status
? configure
? gamin.pc
? gamin.spec
? libtool
? patches
? stamp-h1
? doc/Makefile
? doc/Makefile.in
? lib/Makefile
? lib/Makefile.in
? libgamin/Makefile
? libgamin/Makefile.in
? libgamin/gam_error.c
? libgamin/gam_event.c
? libgamin/gamin
? python/Makefile
? python/Makefile.in
? python/gamin.pyc
? python/tests/Makefile
? python/tests/Makefile.in
? python/tests/python_diff
? python/tests/temp_dir
? server/Makefile
? server/Makefile.in
? server/gam_poll_defunct.c
? server/gam_poll_defunct.h
? server/gam_server
? tests/Makefile
? tests/Makefile.in
? tests/testgam
? tests/result/12
? tests/scenario/12.tst
Index: lib/gam_error.c
===================================================================
RCS file: /cvs/gnome/gamin/lib/gam_error.c,v
retrieving revision 1.7
diff -u -r1.7 gam_error.c
--- lib/gam_error.c 11 Aug 2005 18:41:43 -0000 1.7
+++ lib/gam_error.c 15 Aug 2005 18:38:56 -0000
@@ -3,6 +3,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <signal.h>
+#include <errno.h>
#include "gam_error.h"
typedef void (*signal_handler)(int);
@@ -119,6 +120,12 @@
va_end(args);
if (debug_out)
fflush(debug_out);
+}
+
+int
+gam_errno(void)
+{
+ return (errno);
}
/**
Index: lib/gam_error.h
===================================================================
RCS file: /cvs/gnome/gamin/lib/gam_error.h,v
retrieving revision 1.5
diff -u -r1.5 gam_error.h
--- lib/gam_error.h 5 Aug 2005 12:08:55 -0000 1.5
+++ lib/gam_error.h 15 Aug 2005 18:38:56 -0000
@@ -45,6 +45,8 @@
void gam_error(const char *file, int line, const char* function,
const char* format, ...);
+int gam_errno(void);
+
#ifdef GAM_DEBUG_ENABLED
#ifdef GAMIN_DEBUG_API
Index: server/Makefile.am
===================================================================
RCS file: /cvs/gnome/gamin/server/Makefile.am,v
retrieving revision 1.20
diff -u -r1.20 Makefile.am
--- server/Makefile.am 4 Aug 2005 16:45:25 -0000 1.20
+++ server/Makefile.am 15 Aug 2005 18:38:56 -0000
@@ -27,8 +27,10 @@
gam_node.h \
gam_tree.c \
gam_tree.h \
- gam_poll.c \
- gam_poll.h \
+ gam_poll_dnotify.c \
+ gam_poll_dnotify.h \
+ gam_poll_generic.c \
+ gam_poll_generic.h \
gam_pidname.c \
gam_pidname.h \
gam_channel.c \
Index: server/gam_dnotify.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_dnotify.c,v
retrieving revision 1.24
diff -u -r1.24 gam_dnotify.c
--- server/gam_dnotify.c 10 Aug 2005 18:01:58 -0000 1.24
+++ server/gam_dnotify.c 15 Aug 2005 18:38:56 -0000
@@ -25,7 +25,7 @@
#include <stdio.h>
#include <glib.h>
#include "gam_error.h"
-#include "gam_poll.h"
+#include "gam_poll_dnotify.h"
#include "gam_dnotify.h"
#include "gam_tree.h"
#include "gam_event.h"
@@ -312,7 +312,7 @@
GAM_DEBUG(DEBUG_INFO, "handling signal\n");
- gam_poll_scan_directory(data->path);
+ gam_poll_generic_scan_directory(data->path);
i++;
}
@@ -349,7 +349,7 @@
int fds[2];
GSource *source;
- g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE);
+ g_return_val_if_fail(gam_poll_dnotify_init (), FALSE);
if (pipe(fds) < 0) {
g_warning("Could not create pipe.\n");
Index: server/gam_dnotify.h
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_dnotify.h,v
retrieving revision 1.2
diff -u -r1.2 gam_dnotify.h
--- server/gam_dnotify.h 13 Jun 2005 09:13:45 -0000 1.2
+++ server/gam_dnotify.h 15 Aug 2005 18:38:56 -0000
@@ -3,7 +3,6 @@
#define __MD_DNOTIFY_H__
#include <glib.h>
-#include "gam_poll.h"
#include "gam_subscription.h"
G_BEGIN_DECLS
Index: server/gam_inotify.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v
retrieving revision 1.39
diff -u -r1.39 gam_inotify.c
--- server/gam_inotify.c 10 Aug 2005 15:34:19 -0000 1.39
+++ server/gam_inotify.c 15 Aug 2005 18:38:56 -0000
@@ -33,7 +33,7 @@
#include "gam_debugging.h"
#endif
#include "gam_error.h"
-#include "gam_poll.h"
+#include "gam_poll_generic.h"
#ifdef HAVE_LINUX_INOTIFY_H
#include <linux/inotify.h>
#else
@@ -932,7 +932,7 @@
event_queue = g_queue_new ();
events_to_process = g_queue_new ();
- gam_poll_init ();
+ gam_poll_generic_init ();
gam_server_install_kernel_hooks (GAMIN_K_INOTIFY2,
gam_inotify_add_subscription,
gam_inotify_remove_subscription,
Index: server/gam_inotify.h
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_inotify.h,v
retrieving revision 1.4
diff -u -r1.4 gam_inotify.h
--- server/gam_inotify.h 4 Aug 2005 16:50:53 -0000 1.4
+++ server/gam_inotify.h 15 Aug 2005 18:38:56 -0000
@@ -2,7 +2,6 @@
#define __GAM_INOTIFY_H__
#include <glib.h>
-#include "gam_poll.h"
#include "gam_subscription.h"
G_BEGIN_DECLS
Index: server/gam_node.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_node.c,v
retrieving revision 1.17
diff -u -r1.17 gam_node.c
--- server/gam_node.c 11 Aug 2005 18:41:43 -0000 1.17
+++ server/gam_node.c 15 Aug 2005 18:38:56 -0000
@@ -346,6 +346,35 @@
return node->pflags & flags;
}
+void
+gam_node_emit_event (GamNode *node, GaminEventType event)
+{
+ GList *l;
+ GamNode *parent;
+ GList *subs;
+ int is_dir_node = gam_node_is_dir(node);
+#ifdef VERBOSE_POLL
+ GAM_DEBUG(DEBUG_INFO, "Poll: emit events %d for %s\n", event, gam_node_get_path(node));
+#endif
+ subs = gam_node_get_subscriptions(node);
+
+ if (subs)
+ subs = g_list_copy(subs);
+
+ parent = gam_node_parent(node);
+ if (parent) {
+ GList *parent_subs = gam_node_get_subscriptions(parent);
+
+ for (l = parent_subs; l; l = l->next) {
+ if (!g_list_find(subs, l->data))
+ subs = g_list_prepend(subs, l->data);
+ }
+ }
+
+ gam_server_emit_event(gam_node_get_path(node), is_dir_node, event, subs, 0);
+
+ g_list_free(subs);
+}
/** @} */
Index: server/gam_node.h
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_node.h,v
retrieving revision 1.10
diff -u -r1.10 gam_node.h
--- server/gam_node.h 11 Aug 2005 18:41:43 -0000 1.10
+++ server/gam_node.h 15 Aug 2005 18:38:56 -0000
@@ -99,6 +99,8 @@
int flags);
+void gam_node_emit_event (GamNode *node, GaminEventType event);
+
G_END_DECLS
Index: server/gam_server.c
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_server.c,v
retrieving revision 1.40
diff -u -r1.40 gam_server.c
--- server/gam_server.c 11 Aug 2005 14:36:28 -0000 1.40
+++ server/gam_server.c 15 Aug 2005 18:38:56 -0000
@@ -32,7 +32,7 @@
#include "gam_server.h"
#include "gam_channel.h"
#include "gam_subscription.h"
-#include "gam_poll.h"
+#include "gam_poll_generic.h"
#ifdef ENABLE_INOTIFY
#include "gam_inotify.h"
#endif
@@ -63,6 +63,7 @@
static gboolean (*__gam_poll_add_subscription) (GamSubscription *sub) = NULL;
static gboolean (*__gam_poll_remove_subscription) (GamSubscription *sub) = NULL;
static gboolean (*__gam_poll_remove_all_for) (GamListener *listener) = NULL;
+static GaminEventType (*__gam_poll_file) (GamNode *node) = NULL;
#ifndef ENABLE_INOTIFY
/**
@@ -118,7 +119,7 @@
#ifdef ENABLE_DNOTIFY
gam_dnotify_debug ();
#endif
- gam_poll_debug();
+ gam_poll_generic_debug();
}
/**
@@ -163,7 +164,7 @@
#endif
}
- if (gam_poll_init()) {
+ if (gam_poll_generic_init()) {
GAM_DEBUG(DEBUG_INFO, "Using poll as backend\n");
return(TRUE);
}
@@ -407,12 +408,14 @@
gam_server_install_poll_hooks (GamPollHandler name,
gboolean (*add)(GamSubscription *sub),
gboolean (*remove)(GamSubscription *sub),
- gboolean (*remove_all)(GamListener *listener))
+ gboolean (*remove_all)(GamListener *listener),
+ GaminEventType (*poll_file)(GamNode *node))
{
__gam_poll_handler = name;
__gam_poll_add_subscription = add;
__gam_poll_remove_subscription = remove;
__gam_poll_remove_all_for = remove_all;
+ __gam_poll_file = poll_file;
}
GamKernelHandler
@@ -493,6 +496,15 @@
return __gam_poll_remove_all_for (listener);
return FALSE;
+}
+
+GaminEventType
+gam_poll_file (GamNode *node)
+{
+ if (__gam_poll_file)
+ return __gam_poll_file (node);
+
+ return 0;
}
/**
Index: server/gam_server.h
===================================================================
RCS file: /cvs/gnome/gamin/server/gam_server.h,v
retrieving revision 1.8
diff -u -r1.8 gam_server.h
--- server/gam_server.h 10 Aug 2005 15:34:19 -0000 1.8
+++ server/gam_server.h 15 Aug 2005 18:38:56 -0000
@@ -4,6 +4,7 @@
#include <glib.h>
#include "gam_connection.h"
#include "gam_subscription.h"
+#include "gam_node.h"
#ifdef __cplusplus
extern "C" {
@@ -20,7 +21,8 @@
typedef enum {
GAMIN_P_NONE = 0,
- GAMIN_P_DEFAULT = 1
+ GAMIN_P_DNOTIFY = 1,
+ GAMIN_P_BASIc = 2
} GamPollHandler;
typedef enum pollHandlerMode {
@@ -57,7 +59,8 @@
void gam_server_install_poll_hooks (GamPollHandler name,
gboolean (*add)(GamSubscription *sub),
gboolean (*remove)(GamSubscription *sub),
- gboolean (*remove_all)(GamListener *listener));
+ gboolean (*remove_all)(GamListener *listener),
+ GaminEventType (*poll_file)(GamNode *node));
GamKernelHandler gam_server_get_kernel_handler (void);
@@ -72,6 +75,7 @@
gboolean gam_poll_add_subscription (GamSubscription *sub);
gboolean gam_poll_remove_subscription (GamSubscription *sub);
gboolean gam_poll_remove_all_for (GamListener *listener);
+GaminEventType gam_poll_file (GamNode *node);
#ifdef __cplusplus
}
/* Gamin
* Copyright (C) 2003 James Willcox, Corey Bowers
* Copyright (C) 2004 Daniel Veillard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "server_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <glib.h>
#include "fam.h"
#include "gam_error.h"
#include "gam_tree.h"
#include "gam_poll_dnotify.h"
#include "gam_event.h"
#include "gam_server.h"
#include "gam_protocol.h"
#include "gam_event.h"
#include "gam_excludes.h"
static gboolean gam_poll_dnotify_add_subscription(GamSubscription * sub);
static gboolean gam_poll_dnotify_remove_subscription(GamSubscription * sub);
static gboolean gam_poll_dnotify_remove_all_for(GamListener * listener);
static GaminEventType gam_poll_dnotify_poll_file(GamNode * node);
static gboolean gam_poll_dnotify_scan_callback(gpointer data);
gboolean
gam_poll_dnotify_init ()
{
gam_poll_generic_init ();
gam_server_install_poll_hooks (GAMIN_P_DNOTIFY,
gam_poll_dnotify_add_subscription,
gam_poll_dnotify_remove_subscription,
gam_poll_dnotify_remove_all_for,
gam_poll_dnotify_poll_file);
g_timeout_add(1000, gam_poll_dnotify_scan_callback, NULL);
return TRUE;
}
/**
* gam_poll_delist_node:
* @node: the node to delist
*
* This function is called when kernel monitoring for a node should
* be turned off.
*/
static void
gam_poll_dnotify_delist_node(GamNode * node)
{
GList *subs;
const char *path;
path = gam_node_get_path(node);
if (gam_exclude_check(path) || gam_fs_get_mon_type (path) != GFS_MT_KERNEL)
return;
GAM_DEBUG(DEBUG_INFO, "poll-dnotify: Disabling kernel monitoring for %s\n", path);
subs = gam_node_get_subscriptions(node);
while (subs != NULL) {
gam_poll_generic_trigger_handler (path, GAMIN_DESACTIVATE, node);
subs = subs->next;
}
}
/**
* gam_poll_relist_node:
* @node: the node to delist
*
* This function is called when kernel monitoring for a node should
* be turned on (again).
*/
static void
gam_poll_dnotify_relist_node(GamNode * node)
{
GList *subs;
const char *path;
path = gam_node_get_path(node);
GAM_DEBUG(DEBUG_INFO, "poll-dnotify: Enabling kernel monitoring for %s\n", path);
if (gam_exclude_check(path) || gam_fs_get_mon_type(path) != GFS_MT_KERNEL)
return;
subs = gam_node_get_subscriptions(node);
while (subs != NULL) {
gam_poll_generic_trigger_handler (path, GAMIN_ACTIVATE, node);
subs = subs->next;
}
}
/**
* gam_poll_flowon_node:
* @node: the node to delist
*
* This function is called when kernel monitoring flow control for a
* node should be started
*/
static void
gam_poll_dnotify_flowon_node(GamNode * node)
{
const char *path;
path = gam_node_get_path(node);
if (gam_exclude_check(path) || gam_fs_get_mon_type(path) != GFS_MT_KERNEL)
return;
GAM_DEBUG(DEBUG_INFO, "poll-dnotify: Enabling flow control for %s\n", path);
gam_poll_generic_trigger_handler (path, GAMIN_FLOWCONTROLSTART, node);
}
/**
* gam_poll_flowoff_node:
* @node: the node to delist
*
* This function is called when kernel monitoring flow control for a
* node should be started
*/
static void
gam_poll_dnotify_flowoff_node(GamNode * node)
{
const char *path;
path = gam_node_get_path(node);
if (gam_exclude_check(path) || gam_fs_get_mon_type(path) != GFS_MT_KERNEL)
return;
GAM_DEBUG(DEBUG_INFO, "poll-dnotify: Disabling flow control for %s\n", path);
gam_poll_generic_trigger_handler (path, GAMIN_FLOWCONTROLSTOP, node);
}
static GaminEventType
gam_poll_dnotify_poll_file(GamNode * node)
{
GaminEventType event;
struct stat sbuf;
int stat_ret;
const char *path;
/* If not enough time has passed since the last time we polled this node, stop here */
if (node->lasttime && gam_poll_generic_get_delta_time (node->lasttime) < node->poll_time)
return 0;
path = gam_node_get_path(node);
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Poll: poll_file for %s called\n", path);
#endif
memset(&sbuf, 0, sizeof(struct stat));
if (node->lasttime == 0) {
GAM_DEBUG(DEBUG_INFO, "Poll: file is new\n");
stat_ret = stat(node->path, &sbuf);
if (stat_ret != 0)
gam_node_set_pflag (node, MON_MISSING);
else
gam_node_set_is_dir(node, (S_ISDIR(sbuf.st_mode) != 0));
if (gam_exclude_check(path) || gam_fs_get_mon_type (path) != GFS_MT_KERNEL)
gam_node_set_pflag (node, MON_NOKERNEL);
memcpy(&(node->sbuf), &(sbuf), sizeof(struct stat));
node->lasttime = gam_poll_generic_get_time ();
if (stat_ret == 0)
return 0;
else
return GAMIN_EVENT_DELETED;
}
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, " at %d delta %d : %d\n", current_time, current_time - node->lasttime, node->checks);
#endif
event = 0;
stat_ret = stat(node->path, &sbuf);
if (stat_ret != 0) {
if ((gam_errno() == ENOENT) && (!gam_node_has_pflag(node, MON_MISSING))) {
/* deleted */
gam_node_set_pflags (node, MON_MISSING);
gam_poll_generic_remove_busy(node);
if (gam_node_get_subscriptions(node) != NULL) {
gam_poll_dnotify_delist_node(node);
gam_poll_generic_add_missing(node);
}
event = GAMIN_EVENT_DELETED;
}
} else if (gam_node_has_pflag (node, MON_MISSING)) {
/* created */
gam_node_unset_pflag (node, MON_MISSING);
event = GAMIN_EVENT_CREATED;
#ifdef ST_MTIM_NSEC
} else if ((node->sbuf.st_mtim.tv_sec != sbuf.st_mtim.tv_sec) ||
(node->sbuf.st_mtim.tv_nsec != sbuf.st_mtim.tv_nsec) ||
(node->sbuf.st_size != sbuf.st_size) ||
(node->sbuf.st_ctim.tv_sec != sbuf.st_ctim.tv_sec) ||
(node->sbuf.st_ctim.tv_nsec != sbuf.st_ctim.tv_nsec))
{
event = GAMIN_EVENT_CHANGED;
} else {
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Poll: poll_file %s unchanged\n", path);
GAM_DEBUG(DEBUG_INFO, "%d %d : %d %d\n", node->sbuf.st_mtim.tv_sec, node->sbuf.st_mtim.tv_nsec, sbuf.st_mtim.tv_sec, sbuf.st_mtim.tv_nsec);
#endif
#else
} else if ((node->sbuf.st_mtime != sbuf.st_mtime) ||
(node->sbuf.st_size != sbuf.st_size) ||
(node->sbuf.st_ctime != sbuf.st_ctime))
{
event = GAMIN_EVENT_CHANGED;
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "%d : %d\n", node->sbuf.st_mtime, sbuf.st_mtime);
#endif
#endif
}
/*
* TODO: handle the case where a file/dir is removed and replaced by
* a dir/file
*/
if (stat_ret == 0)
gam_node_set_is_dir(node, (S_ISDIR(sbuf.st_mode) != 0));
memcpy(&(node->sbuf), &(sbuf), sizeof(struct stat));
node->sbuf.st_mtime = sbuf.st_mtime; // VALGRIND!
/*
* if kernel monitoring prohibited, stop here
*/
if (gam_node_has_pflag (node, MON_NOKERNEL))
return (event);
/*
* load control, switch back to poll on very busy resources
* and back when no update has happened in 5 seconds
*/
if (gam_poll_generic_get_time() == node->lasttime) {
if (!gam_node_has_pflag (node, MON_BUSY)) {
if (node->sbuf.st_mtime == gam_poll_generic_get_time())
node->checks++;
}
} else {
node->lasttime = gam_poll_generic_get_time();
if (gam_node_has_pflag (node, MON_BUSY)) {
if (event == 0)
node->checks++;
} else {
node->checks = 0;
}
}
if ((node->checks >= 4) && (!gam_node_has_pflag (node, MON_BUSY))) {
if ((gam_node_get_subscriptions(node) != NULL) &&
(!gam_exclude_check(node->path) && gam_fs_get_mon_type (node->path) == GFS_MT_KERNEL))
{
GAM_DEBUG(DEBUG_INFO, "switching %s back to polling\n", path);
gam_node_set_pflag (node, MON_BUSY);
node->checks = 0;
gam_poll_generic_add_busy(node);
gam_poll_dnotify_flowon_node(node);
/*
* DNotify can be nasty here, we will miss events for parent dir
* if we are not careful about it
*/
if (!gam_node_is_dir(node)) {
GamNode *parent = gam_node_parent(node);
if ((parent != NULL) &&
(gam_node_get_subscriptions(parent) != NULL))
{
gam_poll_generic_add_busy(parent);
/* gam_poll_flowon_node(parent); */
}
}
}
}
if ((event == 0) && gam_node_has_pflag (node, MON_BUSY) && (node->checks > 5))
{
if ((gam_node_get_subscriptions(node) != NULL) &&
(!gam_exclude_check(node->path) && gam_fs_get_mon_type (node->path) == GFS_MT_KERNEL))
{
GAM_DEBUG(DEBUG_INFO, "switching %s back to kernel monitoring\n", path);
gam_node_unset_pflag (node, MON_BUSY);
node->checks = 0;
gam_poll_generic_remove_busy(node);
gam_poll_dnotify_flowoff_node(node);
}
}
return (event);
}
/**
* node_add_subscription:
* @node: the node tree pointer
* @sub: the pointer to the subscription
*
* register a subscription for this node
*
* Returns 0 in case of success and -1 in case of failure
*/
static int
node_add_subscription(GamNode * node, GamSubscription * sub)
{
if ((node == NULL) || (sub == NULL))
return (-1);
if ((node->path == NULL) || (node->path[0] != '/'))
return (-1);
GAM_DEBUG(DEBUG_INFO, "node_add_subscription(%s)\n", node->path);
gam_node_add_subscription(node, sub);
if (gam_exclude_check(node->path) || gam_fs_get_mon_type (node->path) == GFS_MT_POLL) {
GAM_DEBUG(DEBUG_INFO, " gam_exclude_check: true\n");
if (node->lasttime == 0)
gam_poll_dnotify_poll_file(node);
gam_poll_generic_add_missing(node);
return (0);
}
gam_poll_generic_trigger_handler (node->path, GAMIN_ACTIVATE, node);
return (0);
}
/**
* node_remove_subscription:
* @node: the node tree pointer
* @sub: the pointer to the subscription
*
* Removes a subscription for this node
*
* Returns 0 in case of success and -1 in case of failure
*/
static int
node_remove_subscription(GamNode * node, GamSubscription * sub)
{
const char *path;
if ((node == NULL) || (sub == NULL))
return (-1);
if ((node->path == NULL) || (node->path[0] != '/'))
return (-1);
GAM_DEBUG(DEBUG_INFO, "node_remove_subscription(%s)\n", node->path);
gam_node_remove_subscription(node, sub);
path = node->path;
if (gam_exclude_check(path) || gam_fs_get_mon_type (path) == GFS_MT_POLL) {
GAM_DEBUG(DEBUG_INFO, " gam_exclude_check: true\n");
return (0);
}
if (node->pflags == MON_BUSY) {
GAM_DEBUG(DEBUG_INFO, " node is busy\n");
} else if (gam_node_has_pflags (node, MON_ALL_PFLAGS)) {
GAM_DEBUG(DEBUG_INFO, " node has flag %d\n", node->pflags);
return (0);
}
/* DNotify makes our life miserable here */
gam_poll_generic_trigger_handler (node->path, GAMIN_DESACTIVATE, node);
return (0);
}
static gboolean
node_remove_directory_subscription(GamNode * node, GamSubscription * sub)
{
GList *children, *l;
gboolean remove_dir;
GAM_DEBUG(DEBUG_INFO, "remove_directory_subscription %s\n",
gam_node_get_path(node));
node_remove_subscription(node, sub);
remove_dir = (gam_node_get_subscriptions(node) == NULL);
children = gam_tree_get_children(gam_poll_generic_get_tree(), node);
for (l = children; l; l = l->next) {
GamNode *child = (GamNode *) l->data;
if ((!gam_node_get_subscriptions(child)) && (remove_dir) &&
(!gam_tree_has_children(gam_poll_generic_get_tree(), child))) {
gam_poll_generic_unregister_node (child);
gam_tree_remove(gam_poll_generic_get_tree(), child);
} else {
remove_dir = FALSE;
}
}
g_list_free(children);
/*
* do not remove the directory if the parent has a directory subscription
*/
remove_dir = ((gam_node_get_subscriptions(node) == NULL) &&
(!gam_node_has_dir_subscriptions
(gam_node_parent(node))));
if (remove_dir) {
GAM_DEBUG(DEBUG_INFO, " => remove_dir %s\n",
gam_node_get_path(node));
}
return remove_dir;
}
/**
* Adds a subscription to be polled.
*
* @param sub a #GamSubscription to be polled
* @returns TRUE if adding the subscription succeeded, FALSE otherwise
*/
static gboolean
gam_poll_dnotify_add_subscription(GamSubscription * sub)
{
const char *path = gam_subscription_get_path (sub);
GamNode *node = gam_tree_get_at_path (gam_poll_generic_get_tree(), path);
int node_is_dir = FALSE;
gam_listener_add_subscription(gam_subscription_get_listener(sub), sub);
gam_poll_generic_update_time ();
if (!node)
{
node = gam_tree_add_at_path(gam_poll_generic_get_tree(), path, gam_subscription_is_dir(sub));
}
if (node_add_subscription(node, sub) < 0)
{
gam_error(DEBUG_INFO, "Failed to add subscription for: %s\n", path);
return FALSE;
}
node_is_dir = gam_node_is_dir(node);
if (node_is_dir)
{
gam_poll_generic_first_scan_dir(sub, node, path);
} else {
GaminEventType event;
event = gam_poll_dnotify_poll_file (node);
GAM_DEBUG(DEBUG_INFO, "New file subscription: %s event %d\n", path, event);
if ((event == 0) || (event == GAMIN_EVENT_EXISTS) ||
(event == GAMIN_EVENT_CHANGED) ||
(event == GAMIN_EVENT_CREATED))
{
if (gam_subscription_is_dir(sub)) {
/* we are watching a file but requested a directory */
gam_server_emit_one_event(path, node_is_dir, GAMIN_EVENT_DELETED, sub, 0);
} else {
gam_server_emit_one_event(path, node_is_dir, GAMIN_EVENT_EXISTS, sub, 0);
}
} else if (event != 0) {
gam_server_emit_one_event(path, node_is_dir, GAMIN_EVENT_DELETED, sub, 0);
}
gam_server_emit_one_event(path, node_is_dir, GAMIN_EVENT_ENDEXISTS, sub, 0);
}
if (gam_node_has_pflag (node, MON_MISSING) || gam_node_has_pflag (node, MON_NOKERNEL))
gam_poll_generic_add_missing(node);
if (!node_is_dir) {
char *parent;
parent = g_path_get_dirname(path);
node = gam_tree_get_at_path(gam_poll_generic_get_tree(), parent);
if (!node)
{
node = gam_tree_add_at_path(gam_poll_generic_get_tree(), parent, gam_subscription_is_dir (sub));
}
g_free(parent);
}
gam_poll_generic_add (node);
GAM_DEBUG(DEBUG_INFO, "Poll: added subscription\n");
return TRUE;
}
/**
* gam_poll_remove_subscription_real:
* @sub: a subscription
*
* Implements the removal of a subscription, including
* trimming the tree and deactivating the kernel back-end if needed.
*/
static void
gam_poll_dnotify_remove_subscription_real(GamSubscription * sub)
{
GamNode *node;
node = gam_tree_get_at_path(gam_poll_generic_get_tree(), gam_subscription_get_path(sub));
if (node != NULL) {
if (!gam_node_is_dir(node)) {
GAM_DEBUG(DEBUG_INFO, "Removing node sub: %s\n",
gam_subscription_get_path(sub));
node_remove_subscription(node, sub);
if (!gam_node_get_subscriptions(node)) {
GamNode *parent;
gam_poll_generic_unregister_node (node);
if (gam_tree_has_children(gam_poll_generic_get_tree(), node)) {
fprintf(stderr,
"node %s is not dir but has children\n",
gam_node_get_path(node));
} else {
parent = gam_node_parent(node);
if ((parent != NULL) &&
(!gam_node_has_dir_subscriptions(parent))) {
gam_tree_remove(gam_poll_generic_get_tree(), node);
gam_poll_generic_prune_tree(parent);
}
}
}
} else {
GAM_DEBUG(DEBUG_INFO, "Removing directory sub: %s\n",
gam_subscription_get_path(sub));
if (node_remove_directory_subscription(node, sub)) {
GamNode *parent;
gam_poll_generic_unregister_node (node);
parent = gam_node_parent(node);
if (!gam_tree_has_children(gam_poll_generic_get_tree(), node)) {
gam_tree_remove(gam_poll_generic_get_tree(), node);
}
gam_poll_generic_prune_tree(parent);
}
}
}
gam_subscription_free(sub);
}
/**
* Removes a subscription which was being polled.
*
* @param sub a #GamSubscription to remove
* @returns TRUE if removing the subscription succeeded, FALSE otherwise
*/
static gboolean
gam_poll_dnotify_remove_subscription(GamSubscription * sub)
{
GamNode *node;
node = gam_tree_get_at_path(gam_poll_generic_get_tree(), gam_subscription_get_path(sub));
if (node == NULL) {
/* free directly */
gam_subscription_free(sub);
return TRUE;
}
gam_subscription_cancel(sub);
GAM_DEBUG(DEBUG_INFO, "Tree has %d nodes\n", gam_tree_get_size(gam_poll_generic_get_tree()));
gam_poll_dnotify_remove_subscription_real(sub);
GAM_DEBUG(DEBUG_INFO, "Tree has %d nodes\n", gam_tree_get_size(gam_poll_generic_get_tree()));
GAM_DEBUG(DEBUG_INFO, "Poll: removed subscription\n");
return TRUE;
}
/**
* Stop polling all subscriptions for a given #GamListener.
*
* @param listener a #GamListener
* @returns TRUE if removing the subscriptions succeeded, FALSE otherwise
*/
static gboolean
gam_poll_dnotify_remove_all_for(GamListener * listener)
{
GList *subs, *l = NULL;
subs = gam_listener_get_subscriptions(listener);
for (l = subs; l; l = l->next) {
GamSubscription *sub = l->data;
g_assert(sub != NULL);
gam_poll_remove_subscription(sub);
}
if (subs) {
g_list_free(subs);
return TRUE;
} else
return FALSE;
}
static gboolean
gam_poll_dnotify_scan_callback(gpointer data)
{
int idx;
static int in_poll_callback = 0;
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "gam_poll_scan_callback(): %d, %d missing, %d busy\n", in_poll_callback, g_list_length(missing_resources), g_list_length(busy_resources));
#endif
if (in_poll_callback)
return TRUE;
in_poll_callback++;
gam_poll_generic_update_time ();
for (idx = 0;; idx++)
{
GamNode *node;
/*
* do not simply walk the list as it may be modified in the callback
*/
node = (GamNode *) g_list_nth_data(gam_poll_generic_get_missing_list(), idx);
if (node == NULL) {
#ifdef VERBOSE_POLL2
GAM_DEBUG(DEBUG_INFO, "missing list node %d == NULL\n", idx);
#endif
break;
}
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Checking missing file %s", node->path);
#endif
if (node->is_dir) {
gam_poll_generic_scan_directory_internal(node);
} else {
GaminEventType event;
event = gam_poll_dnotify_poll_file (node);
gam_node_emit_event(node, event);
}
/*
* if the resource exists again and is not in a special monitoring
* mode then switch back to dnotify for monitoring.
*/
if (!gam_node_has_pflags (node, MON_ALL_PFLAGS) && (!gam_exclude_check(node->path) && gam_fs_get_mon_type (node->path) == GFS_MT_KERNEL))
{
gam_poll_generic_remove_missing(node);
if (gam_node_get_subscriptions(node) != NULL) {
gam_poll_dnotify_relist_node(node);
}
}
}
for (idx = 0;; idx++)
{
GamNode *node;
/*
* do not simply walk the list as it may be modified in the callback
*/
node = (GamNode *) g_list_nth_data(gam_poll_generic_get_busy_list(), idx);
if (node == NULL)
{
#ifdef VERBOSE_POLL2
GAM_DEBUG(DEBUG_INFO, "busy list node %d == NULL\n", idx);
#endif
break;
}
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Checking busy file %s", node->path);
#endif
if (node->is_dir) {
gam_poll_generic_scan_directory_internal(node);
} else {
GaminEventType event;
event = gam_poll_dnotify_poll_file (node);
gam_node_emit_event(node, event);
}
/*
* if the resource exists again and is not in a special monitoring
* mode then switch back to dnotify for monitoring.
*/
if (!gam_node_has_pflags (node, MON_ALL_PFLAGS) && (!gam_exclude_check(node->path) && gam_fs_get_mon_type (node->path) == GFS_MT_KERNEL))
{
gam_poll_generic_remove_busy(node);
if (gam_node_get_subscriptions(node) != NULL) {
gam_poll_dnotify_flowoff_node(node);
}
}
}
in_poll_callback = 0;
return TRUE;
}
#ifndef __GAM_POLL_DNOTIFY_H
#define __GAM_POLL_DNOTIFY_H
#include "gam_poll_generic.h"
G_BEGIN_DECLS
gboolean gam_poll_dnotify_init (void);
G_END_DECLS
#endif
/* Gamin
* Copyright (C) 2003 James Willcox, Corey Bowers
* Copyright (C) 2004 Daniel Veillard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "server_config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <glib.h>
#include "fam.h"
#include "gam_error.h"
#include "gam_tree.h"
#include "gam_poll_generic.h"
#include "gam_event.h"
#include "gam_server.h"
#include "gam_protocol.h"
#include "gam_event.h"
#include "gam_excludes.h"
//#define VERBOSE_POLL
//#define VERBOSE_POLL2
#define DEFAULT_POLL_TIMEOUT 1
static GamTree * tree = NULL;
static GList * missing_resources = NULL;
static GList * busy_resources = NULL;
static GList * all_resources = NULL;
static GList * dead_resources = NULL;
static time_t current_time = 0;
gboolean
gam_poll_generic_init()
{
tree = gam_tree_new ();
gam_poll_generic_update_time ();
return TRUE;
}
static void
gam_poll_debug_node(GamNode * node, gpointer user_data)
{
if (node == NULL)
return;
GAM_DEBUG(DEBUG_INFO, "dir %d flags %d pflags %d nb subs %d : %s\n", node->is_dir, node->flags, node->pflags, g_list_length(node->subs), node->path);
}
void
gam_poll_generic_debug(void)
{
if (missing_resources != NULL) {
GAM_DEBUG(DEBUG_INFO, "Dumping poll missing resources\n");
g_list_foreach(missing_resources, (GFunc) gam_poll_debug_node, NULL);
} else {
GAM_DEBUG(DEBUG_INFO, "No poll missing resources\n");
}
if (busy_resources != NULL) {
GAM_DEBUG(DEBUG_INFO, "Dumping poll busy resources\n");
g_list_foreach(busy_resources, (GFunc) gam_poll_debug_node, NULL);
} else {
GAM_DEBUG(DEBUG_INFO, "No poll busy resources\n");
}
if (all_resources != NULL) {
GAM_DEBUG(DEBUG_INFO, "Dumping poll all resources\n");
g_list_foreach(all_resources, (GFunc) gam_poll_debug_node, NULL);
} else {
GAM_DEBUG(DEBUG_INFO, "No poll all resources\n");
}
}
/**
* gam_poll_generic_add_missing:
* @node: a missing node
*
* Add a missing node to the list for polling its creation.
*/
void
gam_poll_generic_add_missing(GamNode * node)
{
if (g_list_find(missing_resources, node) == NULL) {
missing_resources = g_list_prepend(missing_resources, node);
GAM_DEBUG(DEBUG_INFO, "Poll: adding missing node %s\n", gam_node_get_path(node));
}
}
/**
* gam_poll_generic_remove_missing:
* @node: a missing node
*
* Remove a missing node from the list.
*/
void
gam_poll_generic_remove_missing(GamNode * node)
{
g_assert (g_list_find (missing_resources, node));
GAM_DEBUG(DEBUG_INFO, "Poll: removing missing node %s\n", gam_node_get_path(node));
missing_resources = g_list_remove_all(missing_resources, node);
}
/**
* gam_poll_generic_add_busy:
* @node: a busy node
*
* Add a busy node to the list for polling its creation.
*/
void
gam_poll_generic_add_busy(GamNode * node)
{
if (g_list_find(busy_resources, node) == NULL) {
busy_resources = g_list_prepend(busy_resources, node);
GAM_DEBUG(DEBUG_INFO, "Poll: adding busy node %s\n", gam_node_get_path(node));
}
}
/**
* gam_poll_generic_remove_busy:
* @node: a busy node
*
* Remove a busy node from the list.
*/
void
gam_poll_generic_remove_busy(GamNode * node)
{
if (!g_list_find (busy_resources, node))
return;
GAM_DEBUG(DEBUG_INFO, "Poll: removing busy node %s\n", gam_node_get_path(node));
busy_resources = g_list_remove_all(busy_resources, node);
}
void
gam_poll_generic_add (GamNode * node)
{
if (g_list_find (all_resources, node) == NULL)
{
all_resources = g_list_prepend(all_resources, node);
GAM_DEBUG(DEBUG_INFO, "Poll: Adding node %s\n", gam_node_get_path (node));
}
}
void
gam_poll_generic_remove (GamNode * node)
{
g_assert (g_list_find (all_resources, node));
GAM_DEBUG(DEBUG_INFO, "Poll: removing node %s\n", gam_node_get_path(node));
all_resources = g_list_remove_all(all_resources, node);
}
time_t
gam_poll_generic_get_time()
{
return current_time;
}
void
gam_poll_generic_update_time()
{
current_time = time (NULL);
}
time_t
gam_poll_generic_get_delta_time(time_t pt)
{
if (current_time >= pt)
return current_time - pt;
/* FIXME: We have wrapped */
return 0;
}
static void
gam_poll_generic_trigger_file_handler (const char *path, pollHandlerMode mode, GamNode *node)
{
if (node->mon_type != GFS_MT_KERNEL)
return;
if (gam_server_get_kernel_handler() == GAMIN_K_DNOTIFY || gam_server_get_kernel_handler() == GAMIN_K_INOTIFY) {
if (gam_node_is_dir(node)) {
gam_kernel_file_handler (path, mode);
} else {
const char *dir = NULL;
GamNode *parent = gam_node_parent(node);
if (!parent)
return;
dir = parent->path;
switch (mode) {
case GAMIN_ACTIVATE:
GAM_DEBUG(DEBUG_INFO, "poll: Activating kernel monitoring on %s\n", dir);
gam_kernel_dir_handler (dir, mode);
break;
case GAMIN_DESACTIVATE:
GAM_DEBUG(DEBUG_INFO, "poll: Deactivating kernel monitoring on %s\n", dir);
gam_kernel_dir_handler (dir, mode);
break;
case GAMIN_FLOWCONTROLSTART:
if (!gam_node_has_pflag (parent, MON_BUSY)) {
GAM_DEBUG(DEBUG_INFO, "poll: marking busy on %s\n", dir);
gam_kernel_dir_handler (dir, mode);
gam_poll_generic_add_busy(parent);
gam_node_set_pflag (parent, MON_BUSY);
}
break;
case GAMIN_FLOWCONTROLSTOP:
if (gam_node_has_pflag (parent, MON_BUSY)) {
GAM_DEBUG(DEBUG_INFO, "poll: unmarking busy on %s\n", dir);
gam_kernel_dir_handler (dir, mode);
gam_poll_generic_remove_busy(parent);
gam_node_unset_pflag (parent, MON_BUSY);
}
break;
}
}
} else {
gam_kernel_file_handler (path, mode);
}
}
static void
gam_poll_generic_trigger_dir_handler (const char *path, pollHandlerMode mode, GamNode *node)
{
if (node->mon_type != GFS_MT_KERNEL)
return;
if (gam_server_get_kernel_handler() == GAMIN_K_DNOTIFY || gam_server_get_kernel_handler() == GAMIN_K_INOTIFY) {
if (gam_node_is_dir(node)) {
gam_kernel_dir_handler (path, mode);
} else {
gam_poll_generic_trigger_file_handler(path, mode, node);
}
} else {
gam_kernel_dir_handler (path, mode);
}
}
void
gam_poll_generic_trigger_handler(const char *path, pollHandlerMode mode, GamNode *node)
{
if (gam_node_is_dir(node))
gam_poll_generic_trigger_dir_handler(node->path, mode, node);
else
gam_poll_generic_trigger_file_handler(node->path, mode, node);
}
void
gam_poll_generic_scan_directory_internal (GamNode *dir_node)
{
GDir *dir;
const char *name, *dpath;
char *path;
GamNode *node;
GaminEventType event = 0, fevent;
GList *children, *l;
unsigned int exists = 0;
int is_dir_node;
if (dir_node == NULL)
return;
dpath = gam_node_get_path(dir_node);
if (dpath == NULL)
return;
if (!gam_node_get_subscriptions(dir_node))
goto scan_files;
event = gam_poll_file(dir_node);
if (event != 0)
gam_node_emit_event (dir_node, event);
dir = g_dir_open(dpath, 0, NULL);
if (dir == NULL) {
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Poll: directory %s is not readable or missing\n", dpath);
#endif
return;
}
exists = 1;
#ifdef VERBOSE_POLL
GAM_DEBUG(DEBUG_INFO, "Poll: scanning directory %s\n", dpath);
#endif
while ((name = g_dir_read_name(dir)) != NULL) {
path = g_build_filename(gam_node_get_path(dir_node), name, NULL);
node = gam_tree_get_at_path(tree, path);
if (!node) {
if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
node = gam_node_new(path, NULL, FALSE);
gam_tree_add(tree, dir_node, node);
gam_node_set_flag(node, FLAG_NEW_NODE);
} else {
node = gam_node_new(path, NULL, TRUE);
gam_tree_add(tree, dir_node, node);
gam_node_set_flag(node, FLAG_NEW_NODE);
}
}
g_free(path);
}
g_dir_close(dir);
scan_files:
/* FIXME: Shouldn't is_dir_node be assigned inside the loop? */
is_dir_node = gam_node_is_dir(dir_node);
children = gam_tree_get_children(tree, dir_node);
for (l = children; l; l = l->next) {
node = (GamNode *) l->data;
fevent = gam_poll_file(node);
if (gam_node_has_flag(node, FLAG_NEW_NODE)) {
if (is_dir_node && gam_node_get_subscriptions(node)) {
gam_node_unset_flag(node, FLAG_NEW_NODE);
gam_poll_generic_scan_directory_internal(node);
} else {
gam_node_unset_flag(node, FLAG_NEW_NODE);
fevent = GAMIN_EVENT_CREATED;
}
}
if (fevent != 0) {
gam_node_emit_event (node, fevent);
} else {
/* just send the EXIST events if the node exists */
if (!gam_node_has_pflag (node, MON_MISSING))
{
gam_server_emit_event(gam_node_get_path(node),
gam_node_is_dir(node),
GAMIN_EVENT_EXISTS, NULL, 0);
}
}
}
g_list_free(children);
}
/**
* Scans a directory for changes, and emits events if needed.
*
* @param path the path to the directory to be scanned
*/
void
gam_poll_generic_scan_directory(const char *path)
{
GamNode *node;
gam_poll_generic_update_time ();
node = gam_tree_get_at_path(tree, path);
if (node == NULL)
node = gam_tree_add_at_path(tree, path, TRUE);
if (node == NULL) {
gam_error(DEBUG_INFO, "gam_tree_add_at_path(%s) returned NULL\n", path);
return;
}
gam_poll_generic_scan_directory_internal(node);
}
/**
* First dir scanning on a new subscription, generates the Exists EndExists
* events.
*/
void
gam_poll_generic_first_scan_dir (GamSubscription * sub, GamNode * dir_node, const char *dpath)
{
GDir *dir;
char *path;
GList *subs;
int with_exists = 1;
const char *name;
GamNode *node;
GAM_DEBUG(DEBUG_INFO, "Looking for existing files in: %s\n", dpath);
if (gam_subscription_has_option(sub, GAM_OPT_NOEXISTS))
{
with_exists = 0;
GAM_DEBUG(DEBUG_INFO, " Exists not wanted\n");
}
subs = g_list_prepend(NULL, sub);
if (!g_file_test(dpath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
GAM_DEBUG(DEBUG_INFO, "Monitoring missing dir: %s\n", dpath);
gam_server_emit_event(dpath, 1, GAMIN_EVENT_DELETED, subs, 1);
stat(dir_node->path, &(dir_node->sbuf));
dir_node->lasttime = gam_poll_generic_get_time ();
if (g_file_test(dpath, G_FILE_TEST_EXISTS)) {
gam_node_set_pflags (dir_node, MON_WRONG_TYPE);
dir_node->is_dir = 0;
} else {
gam_node_set_pflags (dir_node, MON_MISSING);
gam_poll_generic_add_missing(dir_node);
}
goto done;
}
if (dir_node->lasttime == 0)
gam_poll_file(dir_node);
if (with_exists)
gam_server_emit_event(dpath, 1, GAMIN_EVENT_EXISTS, subs, 1);
dir = g_dir_open(dpath, 0, NULL);
if (dir == NULL) {
goto done;
}
while ((name = g_dir_read_name(dir)) != NULL)
{
path = g_build_filename(dpath, name, NULL);
node = gam_tree_get_at_path(tree, path);
if (!node)
{
GAM_DEBUG(DEBUG_INFO, "Unregistered node %s\n", path);
if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
node = gam_node_new(path, NULL, FALSE);
} else {
node = gam_node_new(path, NULL, TRUE);
}
stat(node->path, &(node->sbuf));
gam_node_set_is_dir(node, (S_ISDIR(node->sbuf.st_mode) != 0));
if (gam_exclude_check(path) || gam_fs_get_mon_type(path) != GFS_MT_KERNEL)
gam_node_set_pflag (node, MON_NOKERNEL);
node->lasttime = gam_poll_generic_get_time ();
gam_tree_add(tree, dir_node, node);
}
if (with_exists)
gam_server_emit_event(name, 1, GAMIN_EVENT_EXISTS, subs, 1);
g_free(path);
}
g_dir_close(dir);
done:
if (with_exists)
gam_server_emit_event(dpath, 1, GAMIN_EVENT_ENDEXISTS, subs, 1);
g_list_free(subs);
GAM_DEBUG(DEBUG_INFO, "Done scanning %s\n", dpath);
}
GamTree *
gam_poll_generic_get_tree()
{
return tree;
}
GList *
gam_poll_generic_get_missing_list (void)
{
return missing_resources;
}
GList *
gam_poll_generic_get_busy_list (void)
{
return busy_resources;
}
GList *
gam_poll_generic_get_all_list (void)
{
return all_resources;
}
GList *
gam_poll_generic_get_dead_list (void)
{
return dead_resources;
}
void
gam_poll_generic_unregister_node (GamNode * node)
{
if (missing_resources != NULL) {
gam_poll_generic_remove_missing(node);
}
if (busy_resources != NULL) {
gam_poll_generic_remove_busy(node);
}
if (all_resources != NULL) {
all_resources = g_list_remove(all_resources, node);
}
}
void
gam_poll_generic_prune_tree(GamNode * node)
{
/* don't prune the root */
if (gam_node_parent(node) == NULL)
return;
if (!gam_tree_has_children(tree, node) && !gam_node_get_subscriptions(node))
{
GamNode *parent;
GAM_DEBUG(DEBUG_INFO, "prune_tree: %s\n", gam_node_get_path(node));
parent = gam_node_parent(node);
gam_poll_generic_unregister_node(node);
gam_tree_remove(tree, node);
gam_poll_generic_prune_tree(parent);
}
}
#ifndef __GAM_POLL_GENERIC_H
#define __GAM_POLL_GENERIC_H
#include <glib.h>
#include "gam_server.h"
#include "gam_tree.h"
G_BEGIN_DECLS
gboolean gam_poll_generic_init (void);
void gam_poll_generic_debug (void);
void gam_poll_generic_add_missing (GamNode * node);
void gam_poll_generic_remove_missing (GamNode * node);
void gam_poll_generic_add_busy (GamNode * node);
void gam_poll_generic_remove_busy (GamNode * node);
void gam_poll_generic_add (GamNode * node);
void gam_poll_generic_remove (GamNode * node);
time_t gam_poll_generic_get_time (void);
void gam_poll_generic_update_time (void);
time_t gam_poll_generic_get_delta_time (time_t pt);
void gam_poll_generic_trigger_handler(const char *path, pollHandlerMode mode, GamNode *node);
void gam_poll_generic_scan_directory (const char *path);
void gam_poll_generic_scan_directory_internal (GamNode *dir_node);
void gam_poll_generic_first_scan_dir (GamSubscription * sub, GamNode * dir_node, const char *dpath);
GamTree * gam_poll_generic_get_tree (void);
GList * gam_poll_generic_get_missing_list (void);
GList * gam_poll_generic_get_busy_list (void);
GList * gam_poll_generic_get_all_list (void);
GList * gam_poll_generic_get_dead_list (void);
void gam_poll_generic_unregister_node (GamNode * node);
void gam_poll_generic_prune_tree (GamNode * node);
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]