Exemple #1
0
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);
}
Exemple #2
0
/**
 * 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 ());
}
Exemple #3
0
/**
 * 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 ());
}
Exemple #4
0
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;
}
Exemple #5
0
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;
}
Exemple #6
0
/**
 * 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;
}