Exemplo n.º 1
0
/**
 * _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);
}
Exemplo n.º 3
0
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);
}