From fd1e9938b36677587dfe9960dacb678bbd3981bf Mon Sep 17 00:00:00 2001 From: Cosimo Alfarano Date: Wed, 19 Jan 2011 19:08:15 +0000 Subject: [PATCH] Send CHANGES_DONE_HINT on file moves if no IN_CLOSE_WRITE is emitted This patch makes GFileMonitor to emit EVENT_CHANGES_DONE_HINT when EVENT_CREATED is emitted but the file is not opened for writing. On file moves across different mounted volumes, inotify will always emit IN_CREATE and IN_CLOSE_WRITE (plus other events). This translates into GIO's _EVENT_CREATED and _EVENT_CHANGES_DONE_HINT. On file moves across the same mounted volumes, inotify will emit IN_MOVED_FROM/IN_MOVED_TO which will be translated into _EVENT_DELETED/_EVENT_CREATED GIO's side. No _EVENT_CHANGES_DONE_HINT is emited afterwards. Under such circumstances a file indexer does not know when actually the file is ready to be indexed, either waiting too much or triggering the indexing twice. On small devices it's not advisable. Bug: https://bugzilla.gnome.org/show_bug.cgi?id=640077 Bug-NB: NB#219982 Reviewed-by: Simon McVittie Reviewed-by: Tomas Bzatek --- gio/inotify/inotify-helper.c | 24 ++++++++++++++++++++++++ gio/inotify/inotify-kernel.c | 4 +++- gio/inotify/inotify-kernel.h | 8 ++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/gio/inotify/inotify-helper.c b/gio/inotify/inotify-helper.c index f567e1b5f..6ee0b4b83 100644 --- a/gio/inotify/inotify-helper.c +++ b/gio/inotify/inotify-helper.c @@ -190,6 +190,30 @@ ih_event_callback (ik_event_t *event, g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data), child, other, eflags); + /* For paired moves or moves whose mask has been changed from IN_MOVED_TO to + * IN_CREATE, notify also that it's probably the last change to the file, + * emitting CHANGES_DONE_HINT. + * The first (first part of the if's guard below) is the case of a normal + * move within the monitored tree and in the same mounted volume. + * The latter (second part of the guard) is the case of a move within the + * same mounted volume, but from a not monitored directory. + * + * It's not needed in cases like moves across mounted volumes as the IN_CREATE + * will be followed by a IN_MODIFY and IN_CLOSE_WRITE events. + * Also not needed if sub->pair_moves is set as EVENT_MOVED will be emitted + * instead of EVENT_CREATED which implies no further modification will be + * applied to the file + * See: https://bugzilla.gnome.org/show_bug.cgi?id=640077 + */ + if ((!sub->pair_moves && + event->is_second_in_pair && (event->mask & IN_MOVED_TO)) || + (!ih_event_is_paired_move (event) && + (event->original_mask & IN_MOVED_TO) && (event->mask & IN_CREATE))) + { + g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data), + child, NULL, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT); + } + g_object_unref (child); if (other) g_object_unref (other); diff --git a/gio/inotify/inotify-kernel.c b/gio/inotify/inotify-kernel.c index e712ee75c..5cfb69242 100644 --- a/gio/inotify/inotify-kernel.c +++ b/gio/inotify/inotify-kernel.c @@ -516,6 +516,7 @@ ik_pair_events (ik_event_internal_t *event1, /* Pair the internal structures and the ik_event_t structures */ event1->pair = event2; event1->event->pair = event2->event; + event2->event->is_second_in_pair = TRUE; if (g_timeval_lt (&event1->hold_until, &event2->hold_until)) event1->hold_until = event2->hold_until; @@ -634,7 +635,8 @@ ik_process_events (void) * the event masks */ /* Changeing MOVED_FROM to DELETE and MOVED_TO to create lets us make * the gaurantee that you will never see a non-matched MOVE event */ - + event->event->original_mask = event->event->mask; + if (event->event->mask & IN_MOVED_FROM) { event->event->mask = IN_DELETE|(event->event->mask & IN_ISDIR); diff --git a/gio/inotify/inotify-kernel.h b/gio/inotify/inotify-kernel.h index b406d71d5..104a189e6 100644 --- a/gio/inotify/inotify-kernel.h +++ b/gio/inotify/inotify-kernel.h @@ -26,9 +26,17 @@ typedef struct ik_event_s { gint32 wd; guint32 mask; + guint32 original_mask; guint32 cookie; guint32 len; char * name; + /* TRUE if this event is the last element of a pair + * (e.g., MOVE_TO in a pair of MOVE_FROM, MOVE_TO events) */ + gboolean is_second_in_pair; + /* if event1 and event2 are two paired events + * (e.g., MOVE_FROM and MOVE_TO events related to the same file move), + * then event1->pair == event2 and event2->pair == NULL. + * It will result also in event1->pair->is_second_in_pair == TRUE */ struct ik_event_s *pair; } ik_event_t;