mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 22:52:09 +01:00
inotify: send CHANGES_DONE when new files 'appear'
We generally assume that an IN_CREATE event is the start of a series of events in which another process is doing this: fd = creat (...) -> IN_CREATE write (fd, ..) -> IN_MODIFY write (fd, ..) -> IN_MODIFY close (fd) -> IN_CLOSE_WRITE and as such, we use the CHANGES_DONE_HINT event after CREATED in order to show when this sequence of events has completed (ie: when we receive IN_CLOSE_WRITE when the user closes the file). Renaming a file into place is handled by IN_MOVED_FROM so we don't have to worry about that. There are many other cases, however, where a new file 'appears' in a directory in its completed form already, and the kernel reports IN_CREATE. Examples include mkdir, mknod, and the creation of hardlinks. In these cases, there is no corresponding IN_CLOSE_WRITE event and the CHANGES_DONE_HINT will have to be emitted by an arbitrary timeout. Try to detect some of these cases and report CHANGES_DONE_HINT immediately. This is not perfect. There are some cases that will not be reliably detected. An example is if the user makes a hardlink and then immediately deletes the original (before we can stat the new file). Another example is if the user creates a file with O_TMPFILE. In both of these cases, CHANGES_DONE_HINT will still eventually be delivered via the timeout.
This commit is contained in:
parent
2737ab3201
commit
3d2d4b8efe
@ -27,6 +27,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
/* Just include the local header to stop all the pain */
|
/* Just include the local header to stop all the pain */
|
||||||
#include <sys/inotify.h>
|
#include <sys/inotify.h>
|
||||||
#include <gio/glocalfilemonitor.h>
|
#include <gio/glocalfilemonitor.h>
|
||||||
@ -197,13 +198,49 @@ ih_event_callback (ik_event_t *event,
|
|||||||
/* unpaired event -- no 'other' field */
|
/* unpaired event -- no 'other' field */
|
||||||
g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask),
|
g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask),
|
||||||
event->name, NULL, NULL, event->timestamp);
|
event->name, NULL, NULL, event->timestamp);
|
||||||
|
|
||||||
|
if (event->mask & IN_CREATE)
|
||||||
|
{
|
||||||
|
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 send the
|
||||||
|
* CHANGES_DONE immediately so that the user isn't left waiting.
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/* if it doesn't look like the result of creat()... */
|
||||||
|
if (s != 0 || !S_ISREG (buf.st_mode) || buf.st_nlink != 1)
|
||||||
|
g_file_monitor_source_handle_event (sub->user_data, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT,
|
||||||
|
event->name, NULL, NULL, event->timestamp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ih_not_missing_callback (inotify_sub *sub)
|
ih_not_missing_callback (inotify_sub *sub)
|
||||||
{
|
{
|
||||||
|
gint now = g_get_monotonic_time ();
|
||||||
|
|
||||||
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_CREATED,
|
||||||
sub->filename, NULL, NULL, g_get_monotonic_time ());
|
sub->filename, NULL, NULL, now);
|
||||||
|
g_file_monitor_source_handle_event (sub->user_data, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT,
|
||||||
|
sub->filename, NULL, NULL, now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transforms a inotify event to a GVFS event. */
|
/* Transforms a inotify event to a GVFS event. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user