From 999608656e8dfef743135f52bd3af70951c7af75 Mon Sep 17 00:00:00 2001 From: freetz Date: Thu, 14 Apr 2005 19:17:28 +0000 Subject: - for inotify 0.22 Changed files: gamin-inotify-redux-3.patch -> 1.1 diff --git a/gamin-inotify-redux-3.patch b/gamin-inotify-redux-3.patch new file mode 100644 index 0000000..4637d15 --- /dev/null +++ b/gamin-inotify-redux-3.patch @@ -0,0 +1,964 @@ +Index: server/gam_debugging.h +=================================================================== +RCS file: /cvs/gnome/gamin/server/gam_debugging.h,v +retrieving revision 1.2 +diff -u -r1.2 gam_debugging.h +--- server/gam_debugging.h 23 Mar 2005 09:50:11 -0000 1.2 ++++ server/gam_debugging.h 14 Apr 2005 16:44:34 -0000 +@@ -12,7 +12,12 @@ + GAMDnotifyDelete=2, + GAMDnotifyChange=3, + GAMDnotifyFlowOn=4, +- GAMDnotifyFlowOff=5 ++ GAMDnotifyFlowOff=5, ++ GAMinotifyCreate=6, ++ GAMinotifyDelete=7, ++ GAMinotifyChange=8, ++ GAMinotifyFlowOn=9, ++ GAMinotifyFlowOff=10 + } GAMDebugEvent; + + void gam_debug_add(GamConnDataPtr conn, const char *value, int options); +Index: server/gam_inotify.c +=================================================================== +RCS file: /cvs/gnome/gamin/server/gam_inotify.c,v +retrieving revision 1.17 +diff -u -r1.17 gam_inotify.c +--- server/gam_inotify.c 7 Apr 2005 09:11:17 -0000 1.17 ++++ server/gam_inotify.c 14 Apr 2005 16:44:34 -0000 +@@ -1,5 +1,8 @@ +-/* +- * Copyright (C) 2004 John McCutchan, James Willcox, Corey Bowers ++/* gamin inotify backend ++ * Copyright (C) 2005 John McCutchan ++ * ++ * Based off of code, ++ * Copyright (C) 2003 James Willcox, Corey Bowers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -14,261 +17,404 @@ + * 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. +- * TODO: +- * - *properly* Handle removal of subscriptions when we get IGNORE event +- * - this backend does not produce the same events as the dnotify/poll backend. +- * for example, the dp backend allows for watching non-exist files/folders, +- * and be notified when they are created. there are more places where +- * the events are not consistent. + */ + + + #include + #define _GNU_SOURCE + #include +-#include + #include + #include ++#include + #include +-#include + #include ++#include "gam_error.h" ++#include "gam_poll.h" + #ifdef HAVE_LINUX_INOTIFY_H + #include + #else + #include "local_inotify.h" + #endif +-#include "gam_error.h" + #include "gam_inotify.h" + #include "gam_tree.h" + #include "gam_event.h" + #include "gam_server.h" + #include "gam_event.h" ++#ifdef GAMIN_DEBUG_API ++#include "gam_debugging.h" ++#endif ++ ++#define MIN_POLL_TIME 1.0 + + typedef struct { + char *path; +- char *path_file; + int wd; + int refcount; + GList *subs; +-} INotifyData; ++ int busy; ++ ++ gboolean dirty; ++ GTimer *poll_timer; ++} inotify_data_t; + + static GHashTable *path_hash = NULL; + static GHashTable *wd_hash = NULL; +- +-static GList *new_subs = NULL; +- +-G_LOCK_DEFINE_STATIC(new_subs); +-static GList *removed_subs = NULL; +- +-G_LOCK_DEFINE_STATIC(removed_subs); ++static GList *dirty_list = NULL; + + G_LOCK_DEFINE_STATIC(inotify); ++ + static GIOChannel *inotify_read_ioc = NULL; + + static gboolean have_consume_idler = FALSE; + +-int fd = -1; // the device fd ++static int inotify_device_fd = -1; ++ ++static guint should_poll_mask = IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE_SUBDIR|IN_DELETE_FILE|IN_CREATE_SUBDIR|IN_CREATE_FILE|IN_DELETE_SELF|IN_UNMOUNT; ++ ++static void print_mask(int mask) ++{ ++ if (mask & IN_ACCESS) ++ { ++ GAM_DEBUG(DEBUG_INFO, "ACCESS\n"); ++ } ++ if (mask & IN_MODIFY) ++ { ++ GAM_DEBUG(DEBUG_INFO, "MODIFY\n"); ++ } ++ if (mask & IN_ATTRIB) ++ { ++ GAM_DEBUG(DEBUG_INFO, "ATTRIB\n"); ++ } ++ if (mask & IN_CLOSE_WRITE) ++ { ++ GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n"); ++ } ++ if (mask & IN_CLOSE_NOWRITE) ++ { ++ GAM_DEBUG(DEBUG_INFO, "CLOSE_WRITE\n"); ++ } ++ if (mask & IN_OPEN) ++ { ++ GAM_DEBUG(DEBUG_INFO, "OPEN\n"); ++ } ++ if (mask & IN_MOVED_FROM) ++ { ++ GAM_DEBUG(DEBUG_INFO, "MOVE_FROM\n"); ++ } ++ if (mask & IN_MOVED_TO) ++ { ++ GAM_DEBUG(DEBUG_INFO, "MOVE_TO\n"); ++ } ++ if (mask & IN_DELETE_SUBDIR) ++ { ++ GAM_DEBUG(DEBUG_INFO, "DELETE_SUBDIR\n"); ++ } ++ if (mask & IN_DELETE_FILE) ++ { ++ GAM_DEBUG(DEBUG_INFO, "DELETE_FILE\n"); ++ } ++ if (mask & IN_CREATE_SUBDIR) ++ { ++ GAM_DEBUG(DEBUG_INFO, "CREATE_SUBDIR\n"); ++ } ++ if (mask & IN_CREATE_FILE) ++ { ++ GAM_DEBUG(DEBUG_INFO, "CREATE_FILE\n"); ++ } ++ if (mask & IN_DELETE_SELF) ++ { ++ GAM_DEBUG(DEBUG_INFO, "DELETE_SELF\n"); ++ } ++ if (mask & IN_UNMOUNT) ++ { ++ GAM_DEBUG(DEBUG_INFO, "UNMOUNT\n"); ++ } ++ if (mask & IN_Q_OVERFLOW) ++ { ++ GAM_DEBUG(DEBUG_INFO, "Q_OVERFLOW\n"); ++ } ++ if (mask & IN_IGNORED) ++ { ++ GAM_DEBUG(DEBUG_INFO, "IGNORED\n"); ++ } ++} + +-static INotifyData * +-gam_inotify_data_new(const char *path, char *path_file, int wd) ++static inotify_data_t * ++gam_inotify_data_new(const char *path, int wd) + { +- INotifyData *data; ++ inotify_data_t *data; + +- data = g_new0(INotifyData, 1); ++ data = g_new0(inotify_data_t, 1); + data->path = g_strdup(path); +- data->path_file = path_file; + data->wd = wd; ++ data->busy = 0; + data->refcount = 1; +- data->subs = NULL; ++ data->dirty = FALSE; ++ data->poll_timer = g_timer_new (); + + return data; + } + + static void +-gam_inotify_data_free(INotifyData * data) ++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->path_file); ++ g_timer_destroy (data->poll_timer); + g_free(data); + } + + static void +-gam_inotify_add_rm_handler(const char *path, GamSubscription * sub, +- pollHandlerMode mode) ++gam_inotify_directory_handler_internal(const char *path, pollHandlerMode mode) + { +- INotifyData *data; ++ inotify_data_t *data; ++ int path_fd; ++ int path_wd; + struct inotify_watch_request iwr; +- struct stat st; +- char *path_file; +- char *path_t; +- int wd, r; + ++ ++ switch (mode) { ++ case GAMIN_ACTIVATE: ++ GAM_DEBUG(DEBUG_INFO, "Adding %s to inotify\n", path); ++ break; ++ case GAMIN_DESACTIVATE: ++ GAM_DEBUG(DEBUG_INFO, "Removing %s from inotify\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 inotify operation %d for %s\n", ++ mode, path); ++ return; ++ } + G_LOCK(inotify); + + if (mode == GAMIN_ACTIVATE) { +- GList *subs; +- +- subs = NULL; +- subs = g_list_append(subs, sub); +- + if ((data = g_hash_table_lookup(path_hash, path)) != NULL) { + data->refcount++; +- data->subs = g_list_prepend(data->subs, sub); ++ GAM_DEBUG(DEBUG_INFO, " found incremented refcount: %d\n", ++ data->refcount); + G_UNLOCK(inotify); ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyChange, path, data->refcount); ++#endif + GAM_DEBUG(DEBUG_INFO, "inotify updated refcount\n"); +- /* +- * hum might need some work to check if the path is a dir, +- * setting 0 and forcing to bypass checks right now. +- */ +- gam_server_emit_event(path, 0, GAMIN_EVENT_EXISTS, subs, 1); +- gam_server_emit_event(path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1); + return; + } + +- { +- if (stat(path, &st)) { +- G_UNLOCK(inotify); +- return; +- } +- +- path_t = g_strdup(path); +- path_file = NULL; +- +- if (S_ISREG(st.st_mode)) { +- char *ch; +- +- ch = strrchr(path_t, '/'); +- if (!ch) { +- g_free(path_t); +- G_UNLOCK(inotify); +- return; +- } +- path_file = g_strdup(++ch); +- *ch = '\0'; +- } +- +- +- int file_fd = open(path_t, O_RDONLY); ++ path_fd = open(path, O_RDONLY); + +- g_free(path_t); +- if (file_fd < 0) { +- G_UNLOCK(inotify); +- return; +- } +- +- iwr.fd = file_fd; +- iwr.mask = 0xffffffff; // all events +- wd = ioctl(fd, INOTIFY_WATCH, &iwr); +- close(file_fd); +- } +- +- if (wd < 0) { ++ if (path_fd < 0) { + G_UNLOCK(inotify); + return; + } + +- data = gam_inotify_data_new(path, path_file, wd); +- path_file = NULL; +- data->subs = g_list_prepend(data->subs, sub); ++ iwr.fd = path_fd; ++ iwr.mask = should_poll_mask; ++ path_wd = ioctl (inotify_device_fd, INOTIFY_WATCH, &iwr); ++ close (path_fd); ++ ++ data = gam_inotify_data_new(path, path_wd); + g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), data); + g_hash_table_insert(path_hash, data->path, data); + +- GAM_DEBUG(DEBUG_INFO, "added inotify watch for %s\n", path); +- +- gam_server_emit_event(path, 0, GAMIN_EVENT_EXISTS, subs, 1); +- gam_server_emit_event(path, 0, GAMIN_EVENT_ENDEXISTS, subs, 1); ++ GAM_DEBUG(DEBUG_INFO, "activated inotify for %s\n", path); ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyCreate, path, 0); ++#endif + } else if (mode == GAMIN_DESACTIVATE) { +- data = g_hash_table_lookup(path_hash, path); ++ char *dir = (char *) path; + +- if (!data) { +- G_UNLOCK(inotify); +- return; +- } ++ 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(inotify); ++ return; ++ } ++ GAM_DEBUG(DEBUG_INFO, " not found using parent\n"); ++ } + +- if (g_list_find(data->subs, sub)) { +- data->subs = g_list_remove_all(data->subs, sub); +- } + data->refcount--; + GAM_DEBUG(DEBUG_INFO, "inotify decremeneted refcount for %s\n", + path); + + if (data->refcount == 0) { +- r = ioctl(fd, INOTIFY_IGNORE, &data->wd); +- if (r < 0) { +- GAM_DEBUG(DEBUG_INFO, +- "INOTIFY_IGNORE failed for %s (wd = %d)\n", +- data->path, data->wd); ++ int wd = data->wd; ++ ++ GAM_DEBUG(DEBUG_INFO, "removed inotify watch for %s\n", data->path); ++ ++ g_hash_table_remove(path_hash, data->path); ++ g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); ++ gam_inotify_data_free(data); ++ ++ if (ioctl (inotify_device_fd, INOTIFY_IGNORE, &wd) < 0) { ++ GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd); ++ } ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyDelete, dir, 0); ++#endif ++ } else { ++ GAM_DEBUG(DEBUG_INFO, " found decremented refcount: %d\n", ++ data->refcount); ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyChange, dir, data->refcount); ++#endif ++ } ++ 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(inotify); ++ return; + } +- GAM_DEBUG(DEBUG_INFO, "removed inotify watch for %s\n", +- data->path); +- g_hash_table_remove(path_hash, data->path); +- g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); +- gam_inotify_data_free(data); ++ GAM_DEBUG(DEBUG_INFO, " not found using parent\n"); + } ++ if (data != NULL) { ++ if (mode == GAMIN_FLOWCONTROLSTART) { ++ if (data->wd >= 0) { ++ if (ioctl (inotify_device_fd, INOTIFY_IGNORE, &data->wd) < 0) { ++ GAM_DEBUG (DEBUG_INFO, "INOTIFY_IGNORE failed for %s (wd = %d)\n", data->path, data->wd); ++ } ++ g_hash_table_remove(wd_hash, GINT_TO_POINTER(data->wd)); ++ data->wd = -1; ++ GAM_DEBUG(DEBUG_INFO, "deactivated inotify for %s\n", ++ data->path); ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyFlowOn, dir, 0); ++#endif ++ } ++ data->busy++; ++ } else { ++ if (data->busy > 0) { ++ data->busy--; ++ if (data->busy == 0) { ++ path_fd = open(data->path, O_RDONLY); ++ if (path_fd < 0) { ++ G_UNLOCK(inotify); ++ GAM_DEBUG(DEBUG_INFO, ++ "Failed to reactivate inotify for %s\n", ++ data->path); ++ ++ if ((dir != path) && (dir != NULL)) ++ g_free(dir); ++ return; ++ } ++ ++ iwr.fd = path_fd; ++ iwr.mask = 0xffffffff; ++ path_wd = ioctl (inotify_device_fd, INOTIFY_WATCH, &iwr); ++ close (path_fd); ++ ++ data->wd = path_wd; ++ ++ g_hash_table_insert(wd_hash, GINT_TO_POINTER(data->wd), ++ data); ++ GAM_DEBUG(DEBUG_INFO, "Reactivated inotify for %s\n", ++ data->path); ++#ifdef GAMIN_DEBUG_API ++ gam_debug_report(GAMinotifyFlowOff, path, 0); ++#endif ++ } ++ } ++ } ++ } ++ if ((dir != path) && (dir != NULL)) ++ g_free(dir); + } else { +- GAM_DEBUG(DEBUG_INFO, "Inotify: unimplemented mode request %d\n", +- mode); ++ GAM_DEBUG(DEBUG_INFO, "Unimplemented operation\n"); + } ++ + G_UNLOCK(inotify); + } + +-static GaminEventType +-inotify_event_to_gamin_event(int mask) ++static void ++gam_inotify_directory_handler(const char *path, pollHandlerMode mode) + { +- switch (mask) { +- case IN_ATTRIB: +- case IN_MODIFY: +- return GAMIN_EVENT_CHANGED; +- break; +- case IN_MOVED_TO: +- case IN_CREATE_SUBDIR: +- case IN_CREATE_FILE: +- return GAMIN_EVENT_CREATED; +- break; +- case IN_MOVED_FROM: +- case IN_DELETE_SUBDIR: +- case IN_DELETE_FILE: +- return GAMIN_EVENT_DELETED; +- break; +- default: +- return GAMIN_EVENT_UNKNOWN; ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_directory_handler %s : %d\n", ++ path, mode); ++ ++ if ((mode == GAMIN_DESACTIVATE) || ++ (g_file_test(path, G_FILE_TEST_IS_DIR))) { ++ gam_inotify_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_inotify_directory_handler_internal(dir, mode); ++ g_free(dir); + } + } + + static void +-gam_inotify_emit_event(INotifyData * data, struct inotify_event *event) ++gam_inotify_file_handler(const char *path, pollHandlerMode mode) + { +- GaminEventType gevent; +- char *event_path; +- +- if (!data || !event) +- return; +- gevent = inotify_event_to_gamin_event(event->mask); ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_file_handler %s : %d\n", path, mode); ++ ++ if (g_file_test(path, G_FILE_TEST_IS_DIR)) { ++ gam_inotify_directory_handler_internal(path, mode); ++ } else { ++ char *dir; + +- // gamins event vocabulary is very small compared to inotify +- // so we often will receieve events that have no equivelant +- // in gamin +- if (gevent == GAMIN_EVENT_UNKNOWN) { +- return; ++ dir = g_path_get_dirname(path); ++ GAM_DEBUG(DEBUG_INFO, " not a dir using parent %s\n", dir); ++ gam_inotify_directory_handler_internal(dir, mode); ++ g_free(dir); + } +- if (event->name[0] != '\0' && !data->path_file) { +- int pathlen = strlen(data->path); ++} + +- if (data->path[pathlen - 1] == '/') { +- event_path = g_strconcat(data->path, event->name, NULL); +- } else { +- event_path = g_strconcat(data->path, "/", event->name, NULL); +- } +- } else { +- event_path = g_strdup(data->path); +- } ++/* Must be called with inotify lock locked */ ++static void ++gam_inotify_dirty_list_cleaner () ++{ ++ GList *l; ++ ++ /* Here we walk the old dirty list and create a new one. ++ * if we don't poll a node on the old list, we add it to the new one */ ++ ++ l = dirty_list; ++ dirty_list = NULL; + +- GAM_DEBUG(DEBUG_INFO, "inotify emitting event %s for %s\n", +- gam_event_to_string(gevent), event_path); ++ for (l = l; l; l = l->next) { ++ inotify_data_t *data = l->data; + +- gam_server_emit_event(event_path, 0, gevent, data->subs, 1); ++ g_assert (data->dirty); ++ ++ if (g_timer_elapsed (data->poll_timer, NULL) >= MIN_POLL_TIME) { ++ data->dirty = FALSE; ++ gam_poll_scan_directory (data->path); ++ } else { ++ dirty_list = g_list_append (dirty_list, data); ++ } ++ } + +- g_free(event_path); ++ g_list_free (l); + } + + static gboolean +@@ -276,71 +422,76 @@ + { + char *buffer; + int buffer_size; ++ int events; + gsize buffer_i, read_size; + + G_LOCK(inotify); + +- if (ioctl(fd, FIONREAD, &buffer_size) < 0) { +- G_UNLOCK(inotify); +- GAM_DEBUG(DEBUG_INFO, "inotify FIONREAD < 0. kaboom!\n"); +- return FALSE; ++#if 0 ++ gam_inotify_dirty_list_cleaner (); ++#endif ++ ++ if (ioctl(inotify_device_fd, FIONREAD, &buffer_size) < 0) { ++ G_UNLOCK(inotify); ++ GAM_DEBUG(DEBUG_INFO, "inotify FIONREAD < 0. kaboom!\n"); ++ return FALSE; + } + + buffer = g_malloc(buffer_size); + +- if (g_io_channel_read_chars +- (inotify_read_ioc, (char *) buffer, buffer_size, &read_size, +- NULL) != G_IO_STATUS_NORMAL) { +- G_UNLOCK(inotify); +- GAM_DEBUG(DEBUG_INFO, +- "inotify failed to read events from inotify fd.\n"); +- g_free(buffer); +- return FALSE; ++ if (g_io_channel_read_chars(inotify_read_ioc, (char *)buffer, buffer_size, &read_size, NULL) != G_IO_STATUS_NORMAL) { ++ G_UNLOCK(inotify); ++ GAM_DEBUG(DEBUG_INFO, "inotify failed to read events from inotify fd.\n"); ++ g_free (buffer); ++ return FALSE; + } + + buffer_i = 0; ++ events = 0; + while (buffer_i < read_size) { +- struct inotify_event *event; +- gsize event_size; +- INotifyData *data; +- +- event = (struct inotify_event *) &buffer[buffer_i]; +- event_size = sizeof(struct inotify_event) + event->len; +- +- data = g_hash_table_lookup(wd_hash, GINT_TO_POINTER(event->wd)); +- if (!data) { +- GAM_DEBUG(DEBUG_INFO, "inotify can't find wd %d\n", event->wd); +- GAM_DEBUG(DEBUG_INFO, +- "weird things have happened to inotify.\n"); +- } else { +- /* Do the shit with the event */ +- if (event->mask == IN_IGNORED) { +- GList *l; +- +- l = data->subs; +- data->subs = NULL; +- for (l = l; l; l = l->next) { +- GamSubscription *sub = l->data; +- +- gam_inotify_remove_subscription(sub); +- } +- } else { +- if (data->path_file) { +- if (event->name[0] != '\0') { +- int pathlen = strlen(data->path_file); +- +- if (strcmp(data->path_file, event->name)) { +- buffer_i += event_size; +- continue; +- } +- } +- } +- gam_inotify_emit_event(data, event); +- } +- } ++ struct inotify_event *event; ++ gsize event_size; ++ inotify_data_t *data; ++ ++ event = (struct inotify_event *)&buffer[buffer_i]; ++ event_size = sizeof(struct inotify_event) + event->len; ++ ++ data = g_hash_table_lookup (wd_hash, GINT_TO_POINTER(event->wd)); ++ if (!data) { ++ GAM_DEBUG(DEBUG_INFO, "inotify can't find wd %d\n", event->wd); ++ } else { ++ if (event->mask == IN_IGNORED || event->mask == IN_UNMOUNT) { ++ GList *l; ++ ++ l = data->subs; ++ data->subs = NULL; ++ for (l = l; l; l = l->next) { ++ GamSubscription *sub = l->data; ++ gam_inotify_remove_subscription (sub); ++ } ++ } else if (event->mask != IN_Q_OVERFLOW) { ++ if (event->mask & should_poll_mask) { ++ GAM_DEBUG(DEBUG_INFO, "inotify requesting poll for %s\n", data->path); ++ GAM_DEBUG(DEBUG_INFO, "poll was requested for event = "); ++ print_mask (event->mask); ++ gam_poll_scan_directory (data->path); ++#if 0 ++ /* if node isn't dirty */ ++ if (!data->dirty) { ++ /* Put this node on the dirty list */ ++ data->dirty = TRUE; ++ g_timer_start(data->poll_timer); ++ dirty_list = g_list_append (dirty_list, data); ++ } ++#endif ++ } ++ } ++ } + + buffer_i += event_size; ++ events++; + } ++ GAM_DEBUG(DEBUG_INFO, "inotify recieved %d events\n", events); + + g_free(buffer); + G_UNLOCK(inotify); +@@ -348,48 +499,12 @@ + return TRUE; + } + ++ + static gboolean + gam_inotify_consume_subscriptions_real(gpointer data) + { +- GList *subs, *l; +- +- G_LOCK(new_subs); +- if (new_subs) { +- subs = new_subs; +- new_subs = NULL; +- G_UNLOCK(new_subs); +- +- for (l = subs; l; l = l->next) { +- GamSubscription *sub = l->data; +- +- GAM_DEBUG(DEBUG_INFO, "called gam_inotify_add_handler()\n"); +- gam_inotify_add_rm_handler(gam_subscription_get_path(sub), sub, +- TRUE); +- } +- +- } else { +- G_UNLOCK(new_subs); +- } +- +- G_LOCK(removed_subs); +- if (removed_subs) { +- subs = removed_subs; +- removed_subs = NULL; +- G_UNLOCK(removed_subs); +- +- for (l = subs; l; l = l->next) { +- GamSubscription *sub = l->data; +- +- GAM_DEBUG(DEBUG_INFO, "called gam_inotify_rm_handler()\n"); +- gam_inotify_add_rm_handler(gam_subscription_get_path(sub), sub, +- FALSE); +- } +- } else { +- G_UNLOCK(removed_subs); +- } +- +- GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n"); +- ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions_real()\n"); ++ gam_poll_consume_subscriptions(); + have_consume_idler = FALSE; + return FALSE; + } +@@ -402,30 +517,31 @@ + if (have_consume_idler) + return; + ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_consume_subscriptions()\n"); + have_consume_idler = TRUE; +- + source = g_idle_source_new(); + g_source_set_callback(source, gam_inotify_consume_subscriptions_real, + NULL, NULL); +- + g_source_attach(source, NULL); + } + + /** +- * @defgroup inotify inotify backend ++ * @defgroup inotify inotify Backend + * @ingroup Backends + * @brief inotify backend API + * + * Since version 2.6.X, Linux kernels have included the Linux Inode + * Notification system (inotify). This backend uses inotify to know when +- * files are changed/created/deleted. ++ * files are changed/created/deleted. Since inotify can't watch files/dirs that ++ * don't exist we still have to cache stat() information. For this, ++ * we can just use the code in the polling backend. + * + * @{ + */ + + + /** +- * Initializes the inotify system. This must be called before ++ * Initializes the inotify backend. This must be called before + * any other functions in this module. + * + * @returns TRUE if initialization succeeded, FALSE otherwise +@@ -435,14 +551,16 @@ + { + GSource *source; + +- fd = open("/dev/inotify", O_RDONLY); ++ inotify_device_fd = open("/dev/inotify", O_RDONLY); + +- if (fd < 0) { +- GAM_DEBUG(DEBUG_INFO, "Could not open /dev/inotify\n"); +- return FALSE; ++ if (inotify_device_fd < 0) { ++ GAM_DEBUG(DEBUG_INFO, "Could not open /dev/inotify\n"); ++ return FALSE; + } + +- inotify_read_ioc = g_io_channel_unix_new(fd); ++ g_return_val_if_fail(gam_poll_init_full(FALSE), FALSE); ++ ++ inotify_read_ioc = g_io_channel_unix_new(inotify_device_fd); + + /* For binary data */ + g_io_channel_set_encoding(inotify_read_ioc, NULL, NULL); +@@ -450,13 +568,15 @@ + 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_IO_IN | G_IO_HUP | G_IO_ERR); + g_source_set_callback(source, gam_inotify_read_handler, NULL, NULL); + + g_source_attach(source, 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); ++ gam_poll_set_directory_handler(gam_inotify_directory_handler); ++ gam_poll_set_file_handler(gam_inotify_file_handler); + + GAM_DEBUG(DEBUG_INFO, "inotify initialized\n"); + +@@ -476,15 +596,14 @@ + gboolean + gam_inotify_add_subscription(GamSubscription * sub) + { +- gam_listener_add_subscription(gam_subscription_get_listener(sub), sub); +- +- G_LOCK(new_subs); +- new_subs = g_list_prepend(new_subs, sub); +- G_UNLOCK(new_subs); +- +- GAM_DEBUG(DEBUG_INFO, "inotify_add_sub\n"); ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_add_subscription\n"); ++ if (!gam_poll_add_subscription(sub)) { ++ return FALSE; ++ } + + gam_inotify_consume_subscriptions(); ++ ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_add_subscription: done\n"); + return TRUE; + } + +@@ -497,26 +616,15 @@ + gboolean + gam_inotify_remove_subscription(GamSubscription * sub) + { +- G_LOCK(new_subs); +- if (g_list_find(new_subs, sub)) { +- GAM_DEBUG(DEBUG_INFO, "removed sub found on new_subs\n"); +- new_subs = g_list_remove_all(new_subs, sub); +- G_UNLOCK(new_subs); +- return TRUE; +- } +- G_UNLOCK(new_subs); +- +- gam_subscription_cancel(sub); +- gam_listener_remove_subscription(gam_subscription_get_listener(sub), +- sub); +- +- G_LOCK(removed_subs); +- removed_subs = g_list_prepend(removed_subs, sub); +- G_UNLOCK(removed_subs); ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_remove_subscription\n"); ++ ++ if (!gam_poll_remove_subscription(sub)) { ++ return FALSE; ++ } + +- GAM_DEBUG(DEBUG_INFO, "inotify_remove_sub\n"); + gam_inotify_consume_subscriptions(); + ++ GAM_DEBUG(DEBUG_INFO, "gam_inotify_remove_subscription: done\n"); + return TRUE; + } + +@@ -529,26 +637,13 @@ + gboolean + gam_inotify_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_inotify_remove_subscription(sub); +- +- } +- +- if (subs) { +- g_list_free(subs); +- gam_inotify_consume_subscriptions(); +- return TRUE; +- } else { ++ if (!gam_poll_remove_all_for(listener)) { + return FALSE; + } ++ ++ gam_inotify_consume_subscriptions(); ++ ++ return TRUE; + } + + /** @} */ +Index: server/gam_inotify.h +=================================================================== +RCS file: /cvs/gnome/gamin/server/gam_inotify.h,v +retrieving revision 1.1 +diff -u -r1.1 gam_inotify.h +--- server/gam_inotify.h 27 Jul 2004 10:24:43 -0000 1.1 ++++ server/gam_inotify.h 14 Apr 2005 16:44:34 -0000 +@@ -1,6 +1,5 @@ +- +-#ifndef __MD_INOTIFY_H__ +-#define __MD_INOTIFY_H__ ++#ifndef __GAM_INOTIFY_H__ ++#define __GAM_INOTIFY_H__ + + #include + #include "gam_poll.h" +@@ -15,4 +14,4 @@ + + G_END_DECLS + +-#endif /* __MD_INOTIFY_H__ */ ++#endif /* __GAM_INOTIFY_H__ */ + -- cgit v0.10.2