/** * _kh_start_watching: * @sub: a #kqueue_sub * * Starts watching on a subscription. * * Returns: %TRUE on success, %FALSE otherwise. **/ gboolean _kh_start_watching (kqueue_sub *sub) { g_assert (kqueue_socket_pair[0] != -1); g_assert (sub != NULL); g_assert (sub->filename != NULL); /* kqueue requires a file descriptor to monitor. Sad but true */ #if defined (O_EVTONLY) sub->fd = open (sub->filename, O_EVTONLY); #else sub->fd = open (sub->filename, O_RDONLY); #endif if (sub->fd == -1) { KH_W ("failed to open file %s (error %d)", sub->filename, errno); return FALSE; } _ku_file_information (sub->fd, &sub->is_dir, NULL); if (sub->is_dir) { /* I know, it is very bad to make such decisions in this way and here. * We already do have an user_data at the #kqueue_sub, and it may point to * GKqueueFileMonitor or GKqueueDirectoryMonitor. For a directory case, * we need to scan in contents for the further diffs. Ideally this process * should be delegated to the GKqueueDirectoryMonitor, but for now I will * do it in a dirty way right here. */ if (sub->deps) dl_free (sub->deps); sub->deps = dl_listing (sub->filename); } G_LOCK (hash_lock); g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub); G_UNLOCK (hash_lock); _kqueue_thread_push_fd (sub->fd); /* Bump the kqueue thread. It will pick up a new sub entry to monitor */ if (!_ku_write (kqueue_socket_pair[0], "A", 1)) KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno); return TRUE; }
/** * Detect and notify about the changes in the watched directory. * * This function is top-level and it operates with other specific routines * to notify about different sets of events in a different conditions. * * @param[in] wrk A pointer to #worker. * @param[in] w A pointer to #watch. * @param[in] event A pointer to the received kqueue event. **/ void produce_directory_diff (worker *wrk, watch *w, struct kevent *event) { assert (wrk != NULL); assert (w != NULL); assert (event != NULL); assert (w->type == WATCH_USER); assert (w->is_directory); dep_list *was = NULL, *now = NULL; was = dl_shallow_copy (w->deps); now = dl_listing (w->filename); if (now == NULL && errno != ENOENT) { /* Why do I skip ENOENT? Because the directory could be deleted at this * point */ perror_msg ("Failed to create a listing for directory %s", w->filename); dl_shallow_free (was); return; } dl_shallow_free (w->deps); w->deps = now; bulk_events be; memset (&be, 0, sizeof (be)); handle_context ctx; memset (&ctx, 0, sizeof (ctx)); ctx.wrk = wrk; ctx.w = w; ctx.be = &be; dl_calculate (was, now, &cbs, &ctx); if (be.memory) { safe_write (wrk->io[KQUEUE_FD], be.memory, be.size); free (be.memory); } dl_free (was); }
void _kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source) { dep_list *was; handle_ctx ctx; g_assert (sub != NULL); g_assert (source != NULL); memset (&ctx, 0, sizeof (handle_ctx)); ctx.sub = sub; ctx.source = source; was = sub->deps; sub->deps = dl_listing (sub->filename); dl_calculate (was, sub->deps, &cbs, &ctx); dl_free (was); }