gamin r329 - in trunk: . server
- From: halfline svn gnome org
- To: svn-commits-list gnome org
- Subject: gamin r329 - in trunk: . server
- Date: Sun, 6 Apr 2008 19:09:19 +0100 (BST)
Author: halfline
Date: Sun Apr 6 19:09:18 2008
New Revision: 329
URL: http://svn.gnome.org/viewvc/gamin?rev=329&view=rev
Log:
2008-04-04 Ray Strode <rstrode redhat com>
* server/inotify-path.c
(ip_watch_parent), (ip_start_watching), (ip_event_dispatch),
(ip_event_callback): If a file being watched doesn't exist
yet, then watch its parent to find out when it shows up
instead of polling (bug 476938).
Modified:
trunk/ChangeLog
trunk/server/inotify-path.c
Modified: trunk/server/inotify-path.c
==============================================================================
--- trunk/server/inotify-path.c (original)
+++ trunk/server/inotify-path.c Sun Apr 6 19:09:18 2008
@@ -40,6 +40,7 @@
#include <linux/inotify.h>
#endif
#endif
+#include <errno.h>
#include <string.h>
#include <glib.h>
#include "inotify-kernel.h"
@@ -136,6 +137,38 @@
g_hash_table_replace(wd_dir_hash, GINT_TO_POINTER(dir->wd), dir_list);
}
+static gint32
+ip_watch_parent (const char *path, guint mask, int *err, char **parent_path)
+{
+ gint32 wd;
+ gchar *path_copy;
+ gchar *p;
+
+ path_copy = g_strdup (path);
+
+ wd = -1;
+ do
+ {
+ p = g_strrstr (path_copy, G_DIR_SEPARATOR_S);
+
+ if (p == NULL)
+ return -1;
+
+ if (p != &path_copy[0])
+ *p = '\0';
+
+ wd = ik_watch (path_copy, mask, err);
+ }
+ while (wd < 0 && errno == ENOENT);
+
+ if (parent_path != NULL && wd >= 0)
+ *parent_path = path_copy;
+ else
+ g_free (path_copy);
+
+ return wd;
+}
+
gboolean ip_start_watching (ih_sub_t *sub)
{
gint32 wd;
@@ -156,8 +189,35 @@
IP_W("Trying to add inotify watch ");
wd = ik_watch (sub->dirname, IP_INOTIFY_MASK|IN_ONLYDIR|sub->extra_flags, &err);
- if (wd < 0)
- {
+
+ if (wd < 0 && errno == ENOENT)
+ {
+ char *parent_path;
+
+ IP_W("Directory '%s' does not yet exist, finding and watching existing parent\n",
+ sub->dirname);
+
+ parent_path = NULL;
+ wd = ip_watch_parent (sub->dirname,
+ IP_INOTIFY_MASK|IN_ONLYDIR|sub->extra_flags,
+ &err, &parent_path);
+
+ if (wd < 0)
+ {
+ g_assert (parent_path == NULL);
+ IP_W("Failed\n");
+ return FALSE;
+ }
+
+ IP_W("Found parent '%s', will watch it for now until '%s' becomes available\n",
+ parent_path, sub->dirname);
+
+ dir = ip_watched_dir_new (parent_path, wd);
+ g_free (parent_path);
+
+ ip_map_wd_dir (wd, dir);
+ ip_map_path_dir (parent_path, dir);
+ } else if (wd < 0) {
IP_W("Failed\n");
return FALSE;
} else {
@@ -294,6 +354,7 @@
static void ip_event_dispatch (GList *dir_list, GList *pair_dir_list, ik_event_t *event)
{
GList *dirl;
+ GList *subl, *resubscription_list;
if (!event)
return;
@@ -302,10 +363,16 @@
*
* Figure out how we will deliver move events
*/
+
+ resubscription_list = NULL;
for (dirl = dir_list; dirl; dirl = dirl->next)
{
- GList *subl;
ip_watched_dir_t *dir = dirl->data;
+ char *event_path;
+
+ event_path = g_build_filename (dir->path, event->name, NULL);
+
+
for (subl = dir->subs; subl; subl = subl->next)
{
@@ -315,23 +382,61 @@
* they need to match before the event could be delivered.
*/
if (event->name && sub->filename) {
- if (strcmp (event->name, sub->filename))
+
+ if (strcmp (event->name, sub->filename))
+ {
continue;
+ }
+
/* If the event doesn't have a filename, but the subscription does
* we shouldn't deliever the event */
} else if (sub->filename)
continue;
+ if (g_str_has_prefix (sub->dirname, event_path)) {
+
+ IP_W("Adding directory %s to resubscription list (because of event %s)",
+ sub->dirname, event_path);
+
+ resubscription_list = g_list_prepend (resubscription_list, sub);
+
+ if (strcmp (sub->dirname, event_path) == 0) {
+ char *subscription_dir;
+
+ IP_W("directory '%s' is now available!",
+ sub->dirname);
+
+ /* Normally, the subscription directory name,
+ * matches the directory getting watched. This
+ * isn't necessarily true, though, if we're watching
+ * a parent since the directory we're actually interested
+ * in doesn't exist anymore. When the directory we *are*
+ * interested in shows up, we find out relative to the
+ * directory we're watching. We need to fudge our subscription
+ * temporarily to account for that.
+ *
+ * FIXME: This is a hack, we should send the dirname that the
+ * event came from, along with the subscription, or store a
+ * full path in the event structure
+ */
+ subscription_dir = sub->dirname;
+ sub->dirname = dir->path;
+ event_callback (event, sub);
+ sub->dirname = subscription_dir;
+ }
+
+ continue;
+ }
+
event_callback (event, sub);
}
- }
- if (!event->pair)
- return;
+ g_free (event_path);
+ }
+ if (event->pair)
for (dirl = pair_dir_list; dirl; dirl = dirl->next)
{
- GList *subl;
ip_watched_dir_t *dir = dirl->data;
for (subl = dir->subs; subl; subl = subl->next)
@@ -352,6 +457,13 @@
event_callback (event->pair, sub);
}
}
+
+ for (subl = resubscription_list; subl; subl = subl->next)
+ {
+ ip_stop_watching (subl->data);
+ ip_start_watching (subl->data);
+ }
+ g_list_free (resubscription_list);
}
static void
@@ -371,8 +483,10 @@
if (event->pair)
pair_dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(event->pair->wd));
- if (event->mask & IP_INOTIFY_MASK)
+ if (event->mask & IP_INOTIFY_MASK) {
ip_event_dispatch (dir_list, pair_dir_list, event);
+ dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER(event->wd));
+ }
/* We have to manage the missing list when we get a DELETE event. */
if (event->mask & IN_DELETE_SELF || event->mask & IN_MOVE_SELF)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]