Index: server/gam_inotify.c =================================================================== RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v retrieving revision 1.13 retrieving revision 1.15 diff -u -r1.13 -r1.15 --- server/gam_inotify.c 2005/02/10 22:51:00 1.13 +++ server/gam_inotify.c 2005/03/22 14:23:25 1.15 @@ -88,7 +88,8 @@ } static void -gam_inotify_add_rm_handler(const char *path, GamSubscription *sub, gboolean added) +gam_inotify_add_rm_handler(const char *path, GamSubscription *sub, + pollHandlerMode mode) { INotifyData *data; struct inotify_watch_request iwr; @@ -96,7 +97,7 @@ G_LOCK(inotify); - if (added) { + if (mode == GAMIN_ACTIVATE) { GList *subs; subs = NULL; @@ -116,11 +117,19 @@ return; } - iwr.name = g_strdup(path); - iwr.mask = 0xffffffff; // all events + { + int file = open(path, O_RDONLY); - wd = ioctl(fd, INOTIFY_WATCH, &iwr); - g_free(iwr.name); + if (file < 0) { + G_UNLOCK(inotify); + return; + } + + iwr.fd = file; + iwr.mask = 0xffffffff; // all events + wd = ioctl(fd, INOTIFY_WATCH, &iwr); + close (file); + } if (wd < 0) { G_UNLOCK(inotify); @@ -136,7 +145,7 @@ gam_server_emit_event (path, 0, GAMIN_EVENT_EXISTS, subs, 1); gam_server_emit_event (path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1); - } else { + } else if (mode == GAMIN_DESACTIVATE) { data = g_hash_table_lookup(path_hash, path); if (!data) { @@ -160,6 +169,8 @@ g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); gam_inotify_data_free(data); } + } else { + GAM_DEBUG(DEBUG_INFO, "Inotify: unimplemented mode request %d\n", mode); } G_UNLOCK(inotify); } Index: server/local_inotify.h =================================================================== RCS file: /cvs/gnome/gamin/server/local_inotify.h,v retrieving revision 1.5 diff -u -r1.5 local_inotify.h --- server/local_inotify.h 10 Feb 2005 22:51:00 -0000 1.5 +++ server/local_inotify.h 16 Mar 2005 21:22:32 -0000 @@ -17,11 +17,11 @@ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd. */ struct inotify_event { - __s32 wd; /* watch descriptor */ - __u32 mask; /* watch mask */ - __u32 cookie; /* cookie used for synchronizing two events */ - size_t len; /* length (including nulls) of name */ - char name[0]; /* stub for possible name */ + __s32 wd; /* watch descriptor */ + __u32 mask; /* watch mask */ + __u32 cookie; /* cookie to synchronize two events */ + __u32 len; /* length (including nulls) of name */ + char name[0]; /* stub for possible name */ }; /* @@ -30,8 +30,8 @@ * Pass to the inotify device via the INOTIFY_WATCH ioctl */ struct inotify_watch_request { - char *name; /* directory name */ - __u32 mask; /* event mask */ + int fd; /* fd of filename to watch */ + __u32 mask; /* event mask */ }; /* the following are legal, implemented events */ @@ -67,12 +67,7 @@ #include #include #include - -struct inotify_inode_data { - struct list_head watches; /* list of watches on this inode */ - spinlock_t lock; /* lock protecting the struct */ - atomic_t count; /* ref count */ -}; +#include #ifdef CONFIG_INOTIFY @@ -82,7 +77,7 @@ const char *); extern void inotify_super_block_umount(struct super_block *); extern void inotify_inode_is_dead(struct inode *); -extern __u32 inotify_get_cookie(void); +extern u32 inotify_get_cookie(void); #else @@ -106,7 +101,7 @@ { } -static inline __u32 inotify_get_cookie(void) +static inline u32 inotify_get_cookie(void) { return 0; } Index: server/gam_poll.h =================================================================== RCS file: /cvs/gnome/gamin/server/gam_poll.h,v retrieving revision 1.3 retrieving revision 1.5 diff -u -r1.3 -r1.5 --- server/gam_poll.h 2005/01/27 23:00:31 1.3 +++ server/gam_poll.h 2005/03/22 14:23:25 1.5 @@ -8,7 +8,16 @@ G_BEGIN_DECLS -typedef void (*GamPollHandler) (const char *path, gboolean added); +enum pollHandlerMode { + GAMIN_ACTIVATE = 1, /* Activate kernel monitoring */ + GAMIN_DESACTIVATE = 2, /* Desactivate kernel monitoring */ + GAMIN_FLOWCONTROLSTART = 3, /* Request flow control start */ + GAMIN_FLOWCONTROLSTOP = 4 /* Request flow control stop */ +}; +typedef enum pollHandlerMode pollHandlerMode; + +typedef void (*GamPollHandler) (const char *path, + pollHandlerMode mode); gboolean gam_poll_init_full (gboolean start_scan_thread); @@ -25,8 +34,6 @@ void gam_poll_scan_directory (const char *path); -void gam_poll_add_missing (GamNode *node); -void gam_poll_remove_missing (GamNode *node); void gam_poll_consume_subscriptions (void); G_END_DECLS Index: server/gam_poll.c =================================================================== RCS file: /cvs/gnome/gamin/server/gam_poll.c,v retrieving revision 1.42 retrieving revision 1.46 diff -u -r1.42 -r1.46 --- server/gam_poll.c 2005/03/15 11:49:54 1.42 +++ server/gam_poll.c 2005/03/23 11:01:47 1.46 @@ -63,6 +63,7 @@ static GamTree *tree = NULL; static GList *new_subs = NULL; static GList *missing_resources = NULL; +static GList *busy_resources = NULL; static GList *all_resources = NULL; static GamPollHandler dir_handler = NULL; static GamPollHandler file_handler = NULL; @@ -78,20 +79,104 @@ return(errno); } +/** + * gam_poll_add_missing: + * @node: a missing node + * + * Add a missing node to the list for polling its creation. + */ +static void +gam_poll_add_missing(GamNode *node) { + GAM_DEBUG(DEBUG_INFO, "Poll adding missing node %s\n", + gam_node_get_path(node)); + if (g_list_find(missing_resources, node) == NULL) { + missing_resources = g_list_prepend(missing_resources, node); + } else { + GAM_DEBUG(DEBUG_INFO, " already registered\n"); + } +} + +/** + * gam_poll_remove_missing: + * @node: a missing node + * + * Remove a missing node from the list. + */ +static void +gam_poll_remove_missing(GamNode *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_add_busy: + * @node: a busy node + * + * Add a busy node to the list for polling its creation. + */ +static void +gam_poll_add_busy(GamNode *node) { + GAM_DEBUG(DEBUG_INFO, "Poll adding busy node %s\n", + gam_node_get_path(node)); + if (g_list_find(busy_resources, node) == NULL) { + busy_resources = g_list_prepend(busy_resources, node); + } else { + GAM_DEBUG(DEBUG_INFO, " already registered\n"); + } +} + +/** + * gam_poll_remove_busy: + * @node: a busy node + * + * Remove a busy node from the list. + */ +static void +gam_poll_remove_busy(GamNode *node) { + GAM_DEBUG(DEBUG_INFO, "Poll removing busy node %s\n", + gam_node_get_path(node)); + busy_resources = g_list_remove_all(busy_resources, node); +} + +/** + * trigger_dir_handler: + * @path: path to the directory + * @mode: type of kernel monitoring action + * + * Interface to the kernel monitoring layer for directories + */ static void -trigger_dir_handler(const char *path, gboolean added) +trigger_dir_handler(const char *path, pollHandlerMode mode) { if (dir_handler != NULL) - (*dir_handler) (path, added); + (*dir_handler) (path, mode); } +/** + * trigger_file_handler: + * @path: path to the file + * @mode: type of kernel monitoring action + * + * Interface to the kernel monitoring layer for files + */ static void -trigger_file_handler(const char *path, gboolean added) +trigger_file_handler(const char *path, pollHandlerMode mode) { if (file_handler != NULL) - (*file_handler) (path, added); + (*file_handler) (path, mode); } +/** + * 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) { @@ -114,13 +199,23 @@ } if (gam_node_is_dir(node)) - trigger_dir_handler(node->path, TRUE); + trigger_dir_handler(node->path, GAMIN_ACTIVATE); else - trigger_file_handler(node->path, TRUE); + trigger_file_handler(node->path, GAMIN_ACTIVATE); 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) { @@ -145,24 +240,33 @@ /* DNotify makes our life miserable here */ if (gam_subscription_is_dir(sub)) { if (gam_node_is_dir(node)) - trigger_dir_handler(path, FALSE); + trigger_dir_handler(path, GAMIN_DESACTIVATE); else { char *dir; dir = g_path_get_dirname(path); - trigger_file_handler(dir, FALSE); + trigger_file_handler(dir, GAMIN_DESACTIVATE); g_free(dir); } } else { if (gam_node_is_dir(node)) - trigger_dir_handler(path, FALSE); + trigger_dir_handler(path, GAMIN_DESACTIVATE); else - trigger_file_handler(path, FALSE); + trigger_file_handler(path, GAMIN_DESACTIVATE); } return(0); } +/** + * gam_poll_data_new: + * @path: the path + * + * Creates a new data block for that path + * + * Returns the pointer to the block or NULL in case of failure + */ + static GamPollData * gam_poll_data_new(const char *path) { @@ -189,13 +293,28 @@ return data; } +/** + * gam_poll_data_destroy: + * @data: pointer to the data block + * + * Destroys a data block. + */ + +static void +gam_poll_data_destroy(GamPollData * data) +{ + if (data != NULL) { + if (data->path != NULL) + g_free(data->path); + g_free(data); + } +} + static void -gam_poll_emit_event(GamNode * node, GaminEventType event, - GList * exist_subs) +gam_poll_emit_event(GamNode * node, GaminEventType event) { GList *l; GamNode *parent; - GamPollData *data; GList *subs; int is_dir_node = gam_node_is_dir(node); @@ -215,44 +334,11 @@ } } - if (exist_subs) { - - data = gam_node_get_data(node); - - for (l = subs; l; l = l->next) { - GamSubscription *sub = l->data; - GaminEventType new_event = event; - GList *tmp; - - if (g_list_find(exist_subs, sub)) { - if ((data) && (!(data->flags & MON_MISSING))) - new_event = GAMIN_EVENT_EXISTS; - else - continue; - } - - tmp = g_list_prepend(NULL, sub); - gam_server_emit_event(gam_node_get_path(node), is_dir_node, - new_event, tmp, 0); - g_list_free(tmp); - - } - } else { - - gam_server_emit_event(gam_node_get_path(node), is_dir_node, event, - subs, 0); - } + gam_server_emit_event(gam_node_get_path(node), is_dir_node, event, subs, 0); g_list_free(subs); } -static void -gam_poll_data_destroy(GamPollData * data) -{ - g_free(data->path); - g_free(data); -} - /** * gam_poll_delist_node: * @node: the node to delist @@ -263,16 +349,20 @@ static void gam_poll_delist_node(GamNode * node) { GList *subs; + const char *path; - GAM_DEBUG(DEBUG_INFO, "gam_poll_delist_node %s\n", - gam_node_get_path(node)); + path = gam_node_get_path(node); + GAM_DEBUG(DEBUG_INFO, "gam_poll_delist_node %s\n", path); + + if (gam_exclude_check(path)) + return; subs = gam_node_get_subscriptions(node); while (subs != NULL) { if (gam_node_is_dir(node)) - trigger_dir_handler(gam_node_get_path(node), FALSE); + trigger_dir_handler(path, GAMIN_DESACTIVATE); else - trigger_file_handler(gam_node_get_path(node), FALSE); + trigger_file_handler(path, GAMIN_DESACTIVATE); subs = subs->next; } } @@ -287,20 +377,68 @@ static void gam_poll_relist_node(GamNode * node) { GList *subs; + const char *path; - GAM_DEBUG(DEBUG_INFO, "gam_poll_relist_node %s\n", - gam_node_get_path(node)); + path = gam_node_get_path(node); + GAM_DEBUG(DEBUG_INFO, "gam_poll_relist_node %s\n", path); + + if (gam_exclude_check(path)) + return; subs = gam_node_get_subscriptions(node); while (subs != NULL) { if (gam_node_is_dir(node)) - trigger_dir_handler(gam_node_get_path(node), TRUE); + trigger_dir_handler(path, GAMIN_ACTIVATE); else - trigger_file_handler(gam_node_get_path(node), TRUE); + trigger_file_handler(path, GAMIN_ACTIVATE); 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_flowon_node(GamNode * node) { + const char *path; + + path = gam_node_get_path(node); + GAM_DEBUG(DEBUG_INFO, "gam_poll_flowon_node %s\n",path); + + if (gam_exclude_check(path)) + return; + + if (gam_node_is_dir(node)) + trigger_dir_handler(path, GAMIN_FLOWCONTROLSTART); + else + trigger_file_handler(path, GAMIN_FLOWCONTROLSTART); +} + +/** + * 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_flowoff_node(GamNode * node) { + const char *path; + + path = gam_node_get_path(node); + GAM_DEBUG(DEBUG_INFO, "gam_poll_flowoff_node %s\n", path); + if (gam_exclude_check(path)) + return; + + if (gam_node_is_dir(node)) + trigger_dir_handler(path, GAMIN_FLOWCONTROLSTOP); + else + trigger_file_handler(path, GAMIN_FLOWCONTROLSTOP); +} static GaminEventType poll_file(GamNode * node) @@ -350,6 +488,7 @@ /* deleted */ data->flags = MON_MISSING; + gam_poll_remove_busy(node); if (gam_node_get_subscriptions(node) != NULL) { gam_poll_delist_node(node); gam_poll_add_missing(node); @@ -398,7 +537,7 @@ /* * load control, switch back to poll on very busy resources - * and back when no update has happened in 10 seconds + * and back when no update has happened in 5 seconds */ if (current_time == data->lasttime) { if (!(data->flags & MON_BUSY)) { @@ -416,24 +555,38 @@ } if ((data->checks >= 4) && (!(data->flags & MON_BUSY))) { - if (gam_node_get_subscriptions(node) != NULL) { + if ((gam_node_get_subscriptions(node) != NULL) && + (!gam_exclude_check(data->path))) { GAM_DEBUG(DEBUG_INFO, "switching %s back to polling\n", path); data->flags |= MON_BUSY; data->checks = 0; - gam_poll_add_missing(node); - gam_poll_delist_node(node); + gam_poll_add_busy(node); + gam_poll_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_add_busy(parent); + /* gam_poll_flowon_node(parent); */ + } + } } } - if ((event == 0) && (data->flags & MON_BUSY) && (data->checks > 10)) { + if ((event == 0) && (data->flags & MON_BUSY) && (data->checks > 5)) { if ((gam_node_get_subscriptions(node) != NULL) && (!gam_exclude_check(data->path))) { GAM_DEBUG(DEBUG_INFO, "switching %s back to kernel monitoring\n", path); data->flags &= ~MON_BUSY; data->checks = 0; - gam_poll_remove_missing(node); - gam_poll_relist_node(node); + gam_poll_remove_busy(node); + gam_poll_flowoff_node(node); } } @@ -466,7 +619,7 @@ event = poll_file(dir_node); if (event != 0) - gam_poll_emit_event(dir_node, event, NULL); + gam_poll_emit_event(dir_node, event); dir = g_dir_open(dpath, 0, NULL); @@ -523,7 +676,7 @@ } if (fevent != 0) { - gam_poll_emit_event(node, fevent, NULL); + gam_poll_emit_event(node, fevent); } else { GamPollData *data; @@ -562,6 +715,9 @@ if (missing_resources != NULL) { gam_poll_remove_missing (child); } + if (busy_resources != NULL) { + gam_poll_remove_busy (child); + } gam_tree_remove(tree, child); } else { remove_dir = FALSE; @@ -579,8 +735,9 @@ static int in_poll_callback = 0; #ifdef VERBOSE_POLL - GAM_DEBUG(DEBUG_INFO, "gam_poll_scan_callback(): %d, %d items\n", - in_poll_callback, g_list_length(missing_resources)); + 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); @@ -620,7 +777,7 @@ GaminEventType event; event = poll_file(node); - gam_poll_emit_event(node, event, NULL); + gam_poll_emit_event(node, event); } /* @@ -635,6 +792,52 @@ } } + for (idx = 0;;idx++) { + GamPollData *data; + GamNode *node; + + /* + * do not simply walk the list as it may be modified in the callback + */ + node = (GamNode *) g_list_nth_data(busy_resources, idx); + + if (node == NULL) { +#ifdef VERBOSE_POLL + GAM_DEBUG(DEBUG_INFO, " node %d == NULL\n", idx); +#endif + break; + } + data = gam_node_get_data(node); + if (data == NULL) { +#ifdef VERBOSE_POLL + GAM_DEBUG(DEBUG_INFO, " data %d == NULL\n", idx); +#endif + break; + } + +#ifdef VERBOSE_POLL + GAM_DEBUG(DEBUG_INFO, "Checking busy file %s", data->path); +#endif + if (node->is_dir) { + gam_poll_scan_directory_internal(node); + } else { + GaminEventType event; + + event = poll_file(node); + gam_poll_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 ((data->flags == 0) && (!gam_exclude_check(data->path))) { + gam_poll_remove_busy(node); + if (gam_node_get_subscriptions(node) != NULL) { + gam_poll_flowoff_node(node); + } + } + } in_poll_callback = 0; return(TRUE); } @@ -656,10 +859,13 @@ parent = gam_node_parent(node); if (missing_resources != NULL) { - gam_poll_remove_missing(node); + gam_poll_remove_missing(node); + } + if (busy_resources != NULL) { + gam_poll_remove_busy(node); } if (all_resources != NULL) { - all_resources = g_list_remove (all_resources, node); + all_resources = g_list_remove (all_resources, node); } gam_tree_remove(tree, node); prune_tree(parent); @@ -741,57 +947,6 @@ return(TRUE); } - -/** - * @defgroup Polling Polling Backend - * @ingroup Backends - * @brief Polling backend API - * - * This is the default backend used in Gamin. It basically just calls - * stat() on files/directories every so often to see when things change. The - * statting happens in a separate thread, controllable with arguments to - * #gam_poll_init_full(). - * - * @{ - */ - - -/** - * gam_poll_add_missing: - * @node: a missing node - * - * Add a missing node to the list for polling its creation. - */ -void -gam_poll_add_missing(GamNode *node) { -#if 0 - fprintf(stderr, "Adding %s to polling\n", gam_node_get_path(node)); -#endif - GAM_DEBUG(DEBUG_INFO, "Poll adding missing node %s\n", - gam_node_get_path(node)); - if (g_list_find(missing_resources, node) == NULL) { - missing_resources = g_list_prepend(missing_resources, node); - } else { - GAM_DEBUG(DEBUG_INFO, " already registered\n"); - } -} - -/** - * gam_poll_remove_missing: - * @node: a missing node - * - * Remove a missing node from the list. - */ -void -gam_poll_remove_missing(GamNode *node) { -#if 0 - fprintf(stderr, "Removing %s from polling\n", gam_node_get_path(node)); -#endif - GAM_DEBUG(DEBUG_INFO, "Poll removing missing node %s\n", - gam_node_get_path(node)); - missing_resources = g_list_remove_all(missing_resources, node); -} - /** * Initializes the polling system. This must be called before * any other functions in this module. @@ -889,6 +1044,9 @@ if (missing_resources != NULL) { gam_poll_remove_missing(node); } + if (busy_resources != NULL) { + gam_poll_remove_busy(node); + } if (all_resources != NULL) { all_resources = g_list_remove(all_resources, node); } @@ -912,6 +1070,9 @@ if (missing_resources != NULL) { gam_poll_remove_missing(node); } + if (busy_resources != NULL) { + gam_poll_remove_busy(node); + } if (all_resources != NULL) { all_resources = g_list_remove(all_resources, node); } Index: server/gam_dnotify.c =================================================================== RCS file: /cvs/gnome/gamin/server/gam_dnotify.c,v retrieving revision 1.13 retrieving revision 1.16 diff -u -r1.13 -r1.16 --- server/gam_dnotify.c 2005/02/17 16:19:45 1.13 +++ server/gam_dnotify.c 2005/03/23 09:50:11 1.16 @@ -42,6 +42,7 @@ char *path; int fd; int refcount; + int busy; } DNotifyData; static GHashTable *path_hash = NULL; @@ -65,6 +66,7 @@ data = g_new0(DNotifyData, 1); data->path = g_strdup(path); data->fd = fd; + data->busy = 0; data->refcount = 1; return data; @@ -78,20 +80,33 @@ } static void -gam_dnotify_directory_handler_internal(const char *path, gboolean added) +gam_dnotify_directory_handler_internal(const char *path, pollHandlerMode mode) { DNotifyData *data; int fd; - if (added) { - GAM_DEBUG(DEBUG_INFO, "Adding %s to dnotify\n", path); - } else { - GAM_DEBUG(DEBUG_INFO, "Removing %s from dnotify\n", path); + switch (mode) { + case GAMIN_ACTIVATE: + GAM_DEBUG(DEBUG_INFO, "Adding %s to dnotify\n", path); + break; + case GAMIN_DESACTIVATE: + GAM_DEBUG(DEBUG_INFO, "Removing %s from dnotify\n", path); + break; + case GAMIN_FLOWCONTROLSTART: + GAM_DEBUG(DEBUG_INFO, "Start flow control for %s\n", path); + break; + case GAMIN_FLOWCONTROLSTOP: + GAM_DEBUG(DEBUG_INFO, "Stop flow control for %s\n", path); + break; + default: + gam_error(DEBUG_INFO, "Unknown DNotify operation %d for %s\n", + mode, path); + return; } G_LOCK(dnotify); - if (added) { + if (mode == GAMIN_ACTIVATE) { if ((data = g_hash_table_lookup(path_hash, path)) != NULL) { data->refcount++; @@ -123,8 +138,8 @@ #ifdef GAMIN_DEBUG_API gam_debug_report(GAMDnotifyCreate, path, 0); #endif - } else { - char *dir = path; + } else if (mode == GAMIN_DESACTIVATE) { + char *dir = (char *) path; data = g_hash_table_lookup(path_hash, path); @@ -165,42 +180,109 @@ } if ((dir != path) && (dir != NULL)) g_free(dir); + } else if ((mode == GAMIN_FLOWCONTROLSTART) || + (mode == GAMIN_FLOWCONTROLSTOP)) { + char *dir = (char *) path; + + data = g_hash_table_lookup(path_hash, path); + if (!data) { + dir = g_path_get_dirname(path); + data = g_hash_table_lookup(path_hash, dir); + + if (!data) { + GAM_DEBUG(DEBUG_INFO, " not found !!!\n"); + + if (dir != NULL) + g_free(dir); + G_UNLOCK(dnotify); + return; + } + GAM_DEBUG(DEBUG_INFO, " not found using parent\n"); + } + if (data != NULL) { + if (mode == GAMIN_FLOWCONTROLSTART) { + if (data->fd >= 0) { + close(data->fd); + g_hash_table_remove(fd_hash, GINT_TO_POINTER(data->fd)); + data->fd = -1; + GAM_DEBUG(DEBUG_INFO, "deactivated DNotify for %s\n", + data->path); +#ifdef GAMIN_DEBUG_API + gam_debug_report(GAMDnotifyFlowOn, dir, 0); +#endif + } + data->busy++; + } else { + if (data->busy > 0) { + data->busy--; + if (data->busy == 0) { + fd = open(data->path, O_RDONLY); + if (fd < 0) { + G_UNLOCK(dnotify); + GAM_DEBUG(DEBUG_INFO, + "Failed to reactivate DNotify for %s\n", + data->path); + if ((dir != path) && (dir != NULL)) + g_free(dir); + return; + } + data->fd = fd; + g_hash_table_insert(fd_hash, GINT_TO_POINTER(data->fd), + data); + fcntl(fd, F_SETSIG, SIGRTMIN); + fcntl(fd, F_NOTIFY, + DN_MODIFY | DN_CREATE | DN_DELETE | DN_RENAME | + DN_ATTRIB | DN_MULTISHOT); + GAM_DEBUG(DEBUG_INFO, "Reactivated DNotify for %s\n", + data->path); +#ifdef GAMIN_DEBUG_API + gam_debug_report(GAMDnotifyFlowOff, path, 0); +#endif + } + } + } + } + if ((dir != path) && (dir != NULL)) + g_free(dir); + } else { + GAM_DEBUG(DEBUG_INFO, "Unimplemented operation\n"); } G_UNLOCK(dnotify); } static void -gam_dnotify_directory_handler(const char *path, gboolean added) +gam_dnotify_directory_handler(const char *path, pollHandlerMode mode) { GAM_DEBUG(DEBUG_INFO, "gam_dnotify_directory_handler %s : %d\n", - path, added); + path, mode); - if ((!added) || (g_file_test(path, G_FILE_TEST_IS_DIR))) { - gam_dnotify_directory_handler_internal(path, added); + if ((mode == GAMIN_DESACTIVATE) || + (g_file_test(path, G_FILE_TEST_IS_DIR))) { + gam_dnotify_directory_handler_internal(path, mode); } else { char *dir; dir = g_path_get_dirname(path); GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir); - gam_dnotify_directory_handler_internal(dir, added); + gam_dnotify_directory_handler_internal(dir, mode); g_free(dir); } } static void -gam_dnotify_file_handler(const char *path, gboolean added) +gam_dnotify_file_handler(const char *path, pollHandlerMode mode) { - GAM_DEBUG(DEBUG_INFO, "gam_dnotify_file_handler %s : %d\n", path, added); + GAM_DEBUG(DEBUG_INFO, "gam_dnotify_file_handler %s : %d\n", path, mode); if (g_file_test(path, G_FILE_TEST_IS_DIR)) { - gam_dnotify_directory_handler_internal(path, added); + gam_dnotify_directory_handler_internal(path, mode); } else { char *dir; dir = g_path_get_dirname(path); GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir); - gam_dnotify_directory_handler_internal(dir, added); + gam_dnotify_directory_handler_internal(dir, mode); g_free(dir); } } Index: server/gam_debugging.c =================================================================== RCS file: /cvs/gnome/gamin/server/gam_debugging.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- server/gam_debugging.c 2005/02/17 11:51:39 1.1 +++ server/gam_debugging.c 2005/03/23 09:50:11 1.2 @@ -53,6 +53,8 @@ case GAMDnotifyCreate: case GAMDnotifyDelete: case GAMDnotifyChange: + case GAMDnotifyFlowOn: + case GAMDnotifyFlowOff: connlist = gamDebugNotify; break; } Index: server/gam_debugging.h =================================================================== RCS file: /cvs/gnome/gamin/server/gam_debugging.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- server/gam_debugging.h 2005/02/17 11:51:39 1.1 +++ server/gam_debugging.h 2005/03/23 09:50:11 1.2 @@ -10,7 +10,9 @@ typedef enum { GAMDnotifyCreate=1, GAMDnotifyDelete=2, - GAMDnotifyChange=3 + GAMDnotifyChange=3, + GAMDnotifyFlowOn=4, + GAMDnotifyFlowOff=5 } GAMDebugEvent; void gam_debug_add(GamConnDataPtr conn, const char *value, int options); Index: libgamin/gam_api.c =================================================================== RCS file: /cvs/gnome/gamin/libgamin/gam_api.c,v retrieving revision 1.30 retrieving revision 1.32 diff -u -r1.30 -r1.32 --- libgamin/gam_api.c 2005/02/17 11:51:38 1.30 +++ libgamin/gam_api.c 2005/03/25 10:07:46 1.32 @@ -13,6 +13,7 @@ #include #include #include +#include #include "fam.h" #include "gam_protocol.h" #include "gam_data.h" @@ -181,7 +182,6 @@ snprintf(path, MAXPATHLEN, "/tmp/fam-%s", user); path[MAXPATHLEN] = 0; ret = strdup(path); - free(user); return (ret); } @@ -421,9 +421,35 @@ { char data[2] = { 0, 0 }; int written; +#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS) + struct { + struct cmsghdr hdr; + struct cmsgcred cred; + } cmsg; + struct iovec iov; + struct msghdr msg; + + iov.iov_base = &data[0]; + iov.iov_len = 1; + + memset (&msg, 0, sizeof (msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof (cmsg); + memset (&cmsg, 0, sizeof (cmsg)); + cmsg.hdr.cmsg_len = sizeof (cmsg); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; +#endif retry: +#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS) + written = sendmsg(fd, &msg, 0); +#else written = write(fd, &data[0], 1); +#endif if (written < 0) { if (errno == EINTR) goto retry; @@ -616,8 +642,10 @@ gid_t c_gid; #ifdef HAVE_CMSGCRED - char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))]; - struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem; + struct { + struct cmsghdr hdr; + struct cmsgcred cred; + } cmsg; #endif s_uid = getuid(); @@ -642,9 +670,9 @@ msg.msg_iovlen = 1; #ifdef HAVE_CMSGCRED - memset(cmsgmem, 0, sizeof(cmsgmem)); - msg.msg_control = cmsgmem; - msg.msg_controllen = sizeof(cmsgmem); + memset(&cmsg, 0, sizeof(cmsg)); + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof(cmsg); #endif retry: @@ -661,7 +689,7 @@ goto failed; } #ifdef HAVE_CMSGCRED - if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) { + if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) { GAM_DEBUG(DEBUG_INFO, "Message from recvmsg() was not SCM_CREDS\n"); goto failed; @@ -687,13 +715,9 @@ goto failed; } #elif defined(HAVE_CMSGCRED) - struct cmsgcred *cred; - - cred = (struct cmsgcred *) CMSG_DATA(cmsg); - - c_pid = cred->cmcred_pid; - c_uid = cred->cmcred_euid; - c_gid = cred->cmcred_groups[0]; + c_pid = cmsg.cred.cmcred_pid; + c_uid = cmsg.cred.cmcred_euid; + c_gid = cmsg.cred.cmcred_groups[0]; #else /* !SO_PEERCRED && !HAVE_CMSGCRED */ GAM_DEBUG(DEBUG_INFO, "Socket credentials not supported on this OS\n"); Index: server/gam_channel.c =================================================================== RCS file: /cvs/gnome/gamin/server/gam_channel.c,v retrieving revision 1.10 retrieving revision 1.12 diff -u -r1.10 -r1.12 --- server/gam_channel.c 2005/01/28 15:58:22 1.10 +++ server/gam_channel.c 2005/03/25 10:07:47 1.12 @@ -6,6 +6,7 @@ #include #include #include +#include #include "gam_error.h" #include "gam_connection.h" #include "gam_channel.h" @@ -49,8 +50,10 @@ gid_t c_gid; #ifdef HAVE_CMSGCRED - char cmsgmem[CMSG_SPACE(sizeof(struct cmsgcred))]; - struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem; + struct { + struct cmsghdr hdr; + struct cmsgcred cred; + } cmsg; #endif s_uid = getuid(); @@ -75,9 +78,9 @@ msg.msg_iovlen = 1; #ifdef HAVE_CMSGCRED - memset(cmsgmem, 0, sizeof(cmsgmem)); - msg.msg_control = cmsgmem; - msg.msg_controllen = sizeof(cmsgmem); + memset(&cmsg, 0, sizeof(cmsg)); + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof(cmsg); #endif retry: @@ -94,7 +97,7 @@ goto failed; } #ifdef HAVE_CMSGCRED - if (cmsg->cmsg_len < sizeof(cmsgmem) || cmsg->cmsg_type != SCM_CREDS) { + if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) { GAM_DEBUG(DEBUG_INFO, "Message from recvmsg() was not SCM_CREDS\n"); goto failed; @@ -120,13 +123,9 @@ goto failed; } #elif defined(HAVE_CMSGCRED) - struct cmsgcred *cred; - - cred = (struct cmsgcred *) CMSG_DATA(cmsg); - - c_pid = cred->cmcred_pid; - c_uid = cred->cmcred_euid; - c_gid = cred->cmcred_groups[0]; + c_pid = cmsg.cred.cmcred_pid; + c_uid = cmsg.cred.cmcred_euid; + c_gid = cmsg.cred.cmcred_groups[0]; #else /* !SO_PEERCRED && !HAVE_CMSGCRED */ GAM_DEBUG(DEBUG_INFO, "Socket credentials not supported on this OS\n"); @@ -305,6 +304,7 @@ gam_client_id = g_getenv("GAM_CLIENT_ID"); if (gam_client_id == NULL) { GAM_DEBUG(DEBUG_INFO, "Error getting GAM_CLIENT_ID\n"); + gam_client_id = ""; } } else { gam_client_id = session; Index: configure.in =================================================================== RCS file: /cvs/gnome/gamin/configure.in,v retrieving revision 1.41 retrieving revision 1.42 diff -u -r1.41 -r1.42 --- configure.in 2005/03/15 12:47:25 1.41 +++ configure.in 2005/03/25 10:07:46 1.42 @@ -149,7 +149,7 @@ AM_CONDITIONAL(GAMIN_DEBUG, test x$debug = xyes) debug_api=no -if test "`hostname`" == "paphio" -a "`pwd`" == "/u/veillard/gamin" +if test "`hostname`" = "paphio" -a "`pwd`" = "/u/veillard/gamin" then debug_api=yes fi @@ -403,7 +403,7 @@ AC_SUBST(PYTHON_VERSION) AC_SUBST(PYTHON_SUBDIR) AC_SUBST(PYTHON_INCLUDES) -AC_SUBST(PYTHON_PYTHON_SITE_PACKAGES) +AC_SUBST(PYTHON_SITE_PACKAGES) dnl ==========================================================================