static void 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, 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); }
/** * handle_overwritten: * @data: a pointer to user data (#handle_context). * @path: file name of the overwritten file. * @node: inode number of the overwritten file. * * A callback function for the directory diff calculation routine, * produces G_FILE_MONITOR_EVENT_DELETED/CREATED event pair when * an overwrite occurs in the directory (see dep-list for details). **/ static void handle_overwritten (void *udata, const char *path, ino_t inode) { handle_ctx *ctx = NULL; (void) inode; ctx = (handle_ctx *) udata; g_assert (udata != NULL); g_assert (ctx->sub != NULL); g_assert (ctx->source != NULL); g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_DELETED, path, NULL, NULL, g_get_monotonic_time ()); g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_CREATED, path, NULL, NULL, g_get_monotonic_time ()); }
/** * handle_moved: * @udata: a pointer to user data (#handle_context). * @from_path: file name of the source file. * @from_inode: inode number of the source file. * @to_path: file name of the replaced file. * @to_inode: inode number of the replaced file. * * A callback function for the directory diff calculation routine, * produces G_FILE_MONITOR_EVENT_RENAMED event on a move. **/ static void handle_moved (void *udata, const char *from_path, ino_t from_inode, const char *to_path, ino_t to_inode) { handle_ctx *ctx = NULL; (void) from_inode; (void) to_inode; ctx = (handle_ctx *) udata; g_assert (udata != NULL); g_assert (ctx->sub != NULL); g_assert (ctx->source != NULL); g_file_monitor_source_handle_event (ctx->source, G_FILE_MONITOR_EVENT_RENAMED, from_path, to_path, NULL, g_get_monotonic_time ()); }
static gboolean g_fam_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_data) { gint64 now = g_source_get_time (fam_source); g_mutex_lock (&fam_lock); while (FAMPending (&fam_connection)) { const gchar *child; FAMEvent ev; if (FAMNextEvent (&fam_connection, &ev) != 1) { /* The daemon died. We're in a really bad situation now * because we potentially have a bunch of request structures * outstanding which no longer make any sense to anyone. * * The best thing that we can do is do nothing. Notification * won't work anymore for this process. */ g_mutex_unlock (&fam_lock); g_warning ("Lost connection to FAM (file monitoring) service. Expect no further file monitor events."); return FALSE; } /* We expect ev.filename to be a relative path for children in a * monitored directory, and an absolute path for a monitored file * or the directory itself. */ if (ev.filename[0] != '/') child = ev.filename; else child = NULL; switch (ev.code) { case FAMAcknowledge: g_source_unref (ev.userdata); break; case FAMChanged: g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now); break; case FAMDeleted: g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now); break; case FAMCreated: g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now); break; default: /* unknown type */ break; } } g_mutex_unlock (&fam_lock); return TRUE; }
static gboolean ih_event_callback (ik_event_t *event, inotify_sub *sub, gboolean file_event) { gboolean interesting; g_assert (!file_event); /* XXX hardlink support */ if (event->mask & IN_MOVE) { /* We either have a rename (in the same directory) or a move * (between different directories). */ if (event->pair && event->pair->wd == event->wd) { /* this is a rename */ interesting = g_file_monitor_source_handle_event (sub->user_data, G_FILE_MONITOR_EVENT_RENAMED, event->name, event->pair->name, NULL, event->timestamp); } else { GFile *other; if (event->pair) { const char *parent_dir; gchar *fullpath; parent_dir = _ip_get_path_for_wd (event->pair->wd); fullpath = _ih_fullpath_from_event (event->pair, parent_dir, NULL); other = g_file_new_for_path (fullpath); g_free (fullpath); } else other = NULL; /* this is either an incoming or outgoing move */ interesting = g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask), event->name, NULL, other, event->timestamp); if (other) g_object_unref (other); } } else /* unpaired event -- no 'other' field */ interesting = g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask), 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); } return interesting; }
/** * process_kqueue_notifications: * @gioc: unused. * @cond: unused. * @data: unused. * * Processes notifications, coming from the kqueue thread. * * Reads notifications from the command file descriptor, emits the * "changed" event on the appropriate monitor. * * A typical GIO Channel callback function. * * Returns: %TRUE **/ static gboolean process_kqueue_notifications (GIOChannel *gioc, GIOCondition cond, gpointer data) { struct kqueue_notification n; kqueue_sub *sub = NULL; GFileMonitorSource *source = NULL; GFileMonitorEvent mask = 0; g_assert (kqueue_socket_pair[0] != -1); if (!_ku_read (kqueue_socket_pair[0], &n, sizeof (struct kqueue_notification))) { KH_W ("Failed to read a kqueue notification, error %d", errno); return TRUE; } G_LOCK (hash_lock); sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd)); G_UNLOCK (hash_lock); if (sub == NULL) { KH_W ("Got a notification for a deleted or non-existing subscription %d", n.fd); return TRUE; } source = sub->user_data; g_assert (source != NULL); if (n.flags & (NOTE_DELETE | NOTE_REVOKE)) { if (sub->deps) { dl_free (sub->deps); sub->deps = NULL; } _km_add_missing (sub); if (!(n.flags & NOTE_REVOKE)) { /* Note that NOTE_REVOKE is issued by the kqueue thread * on EV_ERROR kevent. In this case, a file descriptor is * already closed from the kqueue thread, no need to close * it manually */ _kh_cancel_sub (sub); } } if (sub->is_dir && n.flags & (NOTE_WRITE | NOTE_EXTEND)) { _kh_dir_diff (sub, source); n.flags &= ~(NOTE_WRITE | NOTE_EXTEND); } if (n.flags) { gboolean done = FALSE; mask = convert_kqueue_events_to_gio (n.flags, &done); if (done == TRUE) g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ()); } return TRUE; }