diff --git a/gio/gio.c b/gio/gio.c index 0f06649b1..ad2de1cc0 100644 --- a/gio/gio.c +++ b/gio/gio.c @@ -67,6 +67,10 @@ gio_watch_callback (GFileMonitor *monitor, g_assert (!other); g_print ("%s: deleted", child_str); break; + case G_FILE_MONITOR_EVENT_APPEARED: + g_assert (!other); + g_print ("%s: appeared", child_str); + break; case G_FILE_MONITOR_EVENT_CREATED: g_assert (!other); g_print ("%s: created", child_str); diff --git a/gio/gioenums.h b/gio/gioenums.h index 9fd563dcc..f78d1a023 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -422,6 +422,7 @@ typedef enum { G_FILE_MONITOR_EVENT_PRE_UNMOUNT, G_FILE_MONITOR_EVENT_UNMOUNTED, G_FILE_MONITOR_EVENT_MOVED, + G_FILE_MONITOR_EVENT_APPEARED, G_FILE_MONITOR_EVENT_RENAMED, G_FILE_MONITOR_EVENT_MOVED_IN, G_FILE_MONITOR_EVENT_MOVED_OUT diff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c index 44b24a641..8a7603786 100644 --- a/gio/glocalfilemonitor.c +++ b/gio/glocalfilemonitor.c @@ -387,6 +387,14 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, } break; + case G_FILE_MONITOR_EVENT_APPEARED: + g_assert (!other && !rename_to); + if (fms->flags & G_FILE_MONITOR_WATCH_MOVES) + g_file_monitor_source_send_event (fms, event_type, child, NULL); + else + g_file_monitor_source_send_synthetic_created (fms, child); + break; + case G_FILE_MONITOR_EVENT_DELETED: case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: diff --git a/gio/inotify/inotify-helper.c b/gio/inotify/inotify-helper.c index 843db2655..c4c1bede8 100644 --- a/gio/inotify/inotify-helper.c +++ b/gio/inotify/inotify-helper.c @@ -27,6 +27,7 @@ #include #include #include +#include /* Just include the local header to stop all the pain */ #include #include @@ -193,8 +194,42 @@ ih_event_callback (ik_event_t *event, g_object_unref (other); } } + else if (event->mask & IN_CREATE) + { + GFileMonitorEvent event_type; + const gchar *parent_dir; + gchar *fullname; + struct stat buf; + gint s; + + /* The kernel reports IN_CREATE for two types of events: + * + * - creat(), in which case IN_CLOSE_WRITE will come soon; or + * - link(), mkdir(), mknod(), etc., in which case it won't + * + * We can attempt to detect the second case and turn it into an + * APPEARED event so that the user isn't expecting CHANGES_DONE. + * + * The detection for link() is not 100% reliable since the link + * count could be 1 if the original link was deleted or if + * O_TMPFILE was being used, but in that case the virtual + * CHANGES_DONE will be emitted to close the loop. + */ + + parent_dir = _ip_get_path_for_wd (event->wd); + fullname = _ih_fullpath_from_event (event, parent_dir, NULL); + s = stat (fullname, &buf); + g_free (fullname); + + /* does it look like the result of creat()? */ + if (s == 0 && S_ISREG (buf.st_mode) && buf.st_nlink == 1) + event_type = G_FILE_MONITOR_EVENT_CREATED; + else + event_type = G_FILE_MONITOR_EVENT_APPEARED; + + g_file_monitor_source_handle_event (sub->user_data, event_type, event->name, NULL, NULL, event->timestamp); + } else - /* unpaired event -- no 'other' field */ g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask), event->name, NULL, NULL, event->timestamp); } @@ -202,7 +237,7 @@ ih_event_callback (ik_event_t *event, static void ih_not_missing_callback (inotify_sub *sub) { - g_file_monitor_source_handle_event (sub->user_data, G_FILE_MONITOR_EVENT_CREATED, + g_file_monitor_source_handle_event (sub->user_data, G_FILE_MONITOR_EVENT_APPEARED, sub->filename, NULL, NULL, g_get_monotonic_time ()); }