コード例 #1
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;
  GFile *file = NULL;
  gchar *fpath = NULL;

  (void) inode;
  ctx = (handle_ctx *) udata;
  g_assert (udata != NULL);
  g_assert (ctx->sub != NULL);
  g_assert (ctx->monitor != NULL);

  fpath = _ku_path_concat (ctx->sub->filename, path);
  if (fpath == NULL)
    {
      KH_W ("Failed to allocate a string for a new event");
      return;
    }

  file = g_file_new_for_path (fpath);
  g_file_monitor_emit_event (ctx->monitor,
                             file,
                             NULL,
                             G_FILE_MONITOR_EVENT_DELETED);
  g_file_monitor_emit_event (ctx->monitor,
                             file,
                             NULL,
                             G_FILE_MONITOR_EVENT_CREATED);

  g_free (fpath);
  g_object_unref (file);
}
コード例 #2
0
static void
ih_event_callback (ik_event_t  *event, 
                   inotify_sub *sub,
		   gboolean     file_event)
{
  gchar *fullpath;
  GFileMonitorEvent eflags;
  GFile* child;
  GFile* other;

  eflags = ih_mask_to_EventFlags (event->mask);
  fullpath = _ih_fullpath_from_event (event, sub->dirname,
				      file_event ? sub->filename : NULL);
  child = g_file_new_for_path (fullpath);
  g_free (fullpath);

  if (ih_event_is_paired_move (event) && sub->pair_moves)
    {
      const char *parent_dir = (char *) _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);
      eflags = G_FILE_MONITOR_EVENT_MOVED;
      event->pair = NULL; /* prevents the paired event to be emitted as well */
    }
  else
    other = NULL;

  g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
			     child, other, eflags);

  /* For paired moves or moves whose mask has been changed from IN_MOVED_TO to
   * IN_CREATE, notify also that it's probably the last change to the file,
   * emitting CHANGES_DONE_HINT.
   * The first (first part of the if's guard below) is the case of a normal
   * move within the monitored tree and in the same mounted volume.
   * The latter (second part of the guard) is the case of a move within the
   * same mounted volume, but from a not monitored directory.
   *
   * It's not needed in cases like moves across mounted volumes as the IN_CREATE
   * will be followed by a IN_MODIFY and IN_CLOSE_WRITE events.
   * Also not needed if sub->pair_moves is set as EVENT_MOVED will be emitted
   * instead of EVENT_CREATED which implies no further modification will be
   * applied to the file
   * See: https://bugzilla.gnome.org/show_bug.cgi?id=640077
   */
  if ((!sub->pair_moves &&
        event->is_second_in_pair && (event->mask & IN_MOVED_TO)) ||
      (!ih_event_is_paired_move (event) &&
       (event->original_mask & IN_MOVED_TO) && (event->mask & IN_CREATE)))
    {
      g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
          child, NULL, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
    }

  g_object_unref (child);
  if (other)
    g_object_unref (other);
}
コード例 #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_MOVED 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;
  GFile *file = NULL;
  GFile *other = NULL;
  gchar *path = NULL;
  gchar *npath = NULL;

  (void) from_inode;
  (void) to_inode;

  ctx = (handle_ctx *) udata;
  g_assert (udata != NULL);
  g_assert (ctx->sub != NULL);
  g_assert (ctx->monitor != NULL);


  path = _ku_path_concat (ctx->sub->filename, from_path);
  npath = _ku_path_concat (ctx->sub->filename, to_path);
  if (path == NULL || npath == NULL)
    {
      KH_W ("Failed to allocate strings for event");
      return;
    }

  file = g_file_new_for_path (path);
  other = g_file_new_for_path (npath);

  if (ctx->sub->pair_moves)
    {
      g_file_monitor_emit_event (ctx->monitor,
                                 file,
                                 other,
                                 G_FILE_MONITOR_EVENT_MOVED);
    }
  else
    {
      g_file_monitor_emit_event (ctx->monitor,
                                 file,
                                 NULL,
                                 G_FILE_MONITOR_EVENT_DELETED);
      g_file_monitor_emit_event (ctx->monitor,
                                 other,
                                 NULL,
                                 G_FILE_MONITOR_EVENT_CREATED);
    }

  g_free (path);
  g_free (npath);

  g_object_unref (file);
  g_object_unref (other);
}
コード例 #4
0
static void
g_local_file_monitor_mounts_changed (GUnixMountMonitor *mount_monitor,
                                     gpointer           user_data)
{
  GLocalFileMonitor *local_monitor = user_data;
  GUnixMountEntry *mount;
  gboolean is_mounted;
  GFile *file;

  /* Emulate unmount detection */
  mount = g_unix_mount_at (local_monitor->source->dirname, NULL);

  is_mounted = mount != NULL;

  if (mount)
    g_unix_mount_free (mount);

  if (local_monitor->was_mounted != is_mounted)
    {
      if (local_monitor->was_mounted && !is_mounted)
        {
          file = g_file_new_for_path (local_monitor->source->dirname);
          g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor), file, NULL, G_FILE_MONITOR_EVENT_UNMOUNTED);
          g_object_unref (file);
        }
      local_monitor->was_mounted = is_mounted;
    }
}
コード例 #5
0
static void
thunar_uca_provider_child_watch (ThunarUcaProvider *uca_provider,
                                 gint               exit_status)

{
  GFileMonitor *monitor;
  GFile        *file;

  g_return_if_fail (THUNAR_UCA_IS_PROVIDER (uca_provider));

  GDK_THREADS_ENTER ();

  /* verify that we still have a valid child_watch_path */
  if (G_LIKELY (uca_provider->child_watch_path != NULL))
    {
      /* determine the corresponding file */
      file = g_file_new_for_path (uca_provider->child_watch_path);

      /* schedule a changed notification on the path */
      monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL);

      if (monitor != NULL)
        {
          g_file_monitor_emit_event (monitor, file, file, G_FILE_MONITOR_EVENT_CHANGED);
          g_object_unref (monitor);
        }

      /* release the file */
      g_object_unref (file);
    }

  thunar_uca_provider_child_watch_destroy (uca_provider, NULL);

  GDK_THREADS_LEAVE ();
}
コード例 #6
0
static void
ih_not_missing_callback (inotify_sub *sub)
{
  gchar *fullpath;
  GFileMonitorEvent eflags;
  guint32 mask;
  GFile* child;

  if (sub->filename)
    {
      fullpath = g_strdup_printf ("%s/%s", sub->dirname, sub->filename);
      g_warning ("Missing callback called fullpath = %s\n", fullpath);
      if (!g_file_test (fullpath, G_FILE_TEST_EXISTS))
	{
	  g_free (fullpath);
	  return;
	}
      mask = IN_CREATE;
    }
  else
    {
      fullpath = g_strdup_printf ("%s", sub->dirname);
      mask = IN_CREATE|IN_ISDIR;
    }

  eflags = ih_mask_to_EventFlags (mask);
  child = g_file_new_for_path (fullpath);
  g_free (fullpath);

  g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
			     child, NULL, eflags);

  g_object_unref (child);
}
コード例 #7
0
static void
ih_event_callback (ik_event_t  *event,
                   inotify_sub *sub)
{
    gchar *fullpath;
    GFileMonitorEvent eflags;
    GFile* parent;
    GFile* child;

    eflags = ih_mask_to_EventFlags (event->mask);
    parent = g_file_new_for_path (sub->dirname);
    if (event->name)
        fullpath = g_strdup_printf ("%s/%s", sub->dirname, event->name);
    else
        fullpath = g_strdup_printf ("%s/", sub->dirname);

    child = g_file_new_for_path (fullpath);
    g_free (fullpath);

    g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
                               child, NULL, eflags);

    g_object_unref (child);
    g_object_unref (parent);
}
コード例 #8
0
ファイル: fen-node.c プロジェクト: Andais/glib
static void
node_emit_one_event(node_t *f, GList *subs, node_t *other, int event)
{
    GList* idx;
    
    FN_W ("%s %s %d\n", __func__, NODE_NAME(f), event);

#ifdef GIO_COMPILATION
    for (idx = subs; idx; idx = idx->next) {
        g_file_monitor_emit_event(G_FILE_MONITOR(idx->data), f->gfile,
          (other == NULL ? NULL : other->gfile), event);
    }
#else
    for (idx = subs; idx; idx = idx->next) {
        gam_server_emit_one_event(NODE_NAME(f), gam_subscription_is_dir(idx->data), event, idx->data, 1);
    }
#endif
}
コード例 #9
0
ファイル: kqueue-helper.c プロジェクト: johne53/MB3Glib
/**
 * _kh_file_appeared_cb:
 * @sub: a #kqueue_sub
 *
 * A callback function for kqueue-missing subsystem.
 *
 * Signals that a missing file has finally appeared in the filesystem.
 * Emits %G_FILE_MONITOR_EVENT_CREATED.
 **/
void
_kh_file_appeared_cb (kqueue_sub *sub)
{
  GFile* child;

  g_assert (sub != NULL);
  g_assert (sub->filename);

  if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS))
    return;

  child = g_file_new_for_path (sub->filename);

  g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
                             child,
                             NULL,
                             G_FILE_MONITOR_EVENT_CREATED);

  g_object_unref (child);
}
コード例 #10
0
static void
mounts_changed (GUnixMountMonitor *mount_monitor,
                gpointer           user_data)
{
  GLocalDirectoryMonitor *local_monitor = user_data;
  GUnixMountEntry *mount;
  gboolean is_mounted;
  GFile *file;
  
  /* Emulate unmount detection */
#ifdef G_OS_WIN32
  mount = NULL;
  /*claim everything was mounted */
  is_mounted = TRUE;
#else  
  mount = g_unix_mount_at (local_monitor->dirname, NULL);
  
  is_mounted = mount != NULL;
  
  if (mount)
    g_unix_mount_free (mount);
#endif

  if (local_monitor->was_mounted != is_mounted)
    {
      if (local_monitor->was_mounted && !is_mounted)
        {
          file = g_file_new_for_path (local_monitor->dirname);
          g_file_monitor_emit_event (G_FILE_MONITOR (local_monitor),
				     file, NULL,
				     G_FILE_MONITOR_EVENT_UNMOUNTED);
          g_object_unref (file);
        }
      local_monitor->was_mounted = is_mounted;
    }
}
コード例 #11
0
static void CALLBACK 
g_win32_directory_monitor_callback (DWORD        error,
				    DWORD        nBytes,
				    LPOVERLAPPED lpOverlapped)
{
  gulong offset;
  PFILE_NOTIFY_INFORMATION pfile_notify_walker;
  glong file_name_len;
  gchar *file_name;
  gchar *path;
  GFile *file;
  GWin32DirectoryMonitorPrivate *priv = (GWin32DirectoryMonitorPrivate *) lpOverlapped;

  static GFileMonitorEvent events[] =
    {
      0, 
      G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_ADDED            */
      G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_REMOVED          */
      G_FILE_MONITOR_EVENT_CHANGED, /* FILE_ACTION_MODIFIED         */
      G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_RENAMED_OLD_NAME */
      G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_RENAMED_NEW_NAME */
    };

  /* If priv->self is NULL the GWin32DirectoryMonitor object has been destroyed. */
  if (priv->self == NULL ||
      g_file_monitor_is_cancelled (priv->self) ||
      priv->file_notify_buffer == NULL)
    {
      g_free (priv->file_notify_buffer);
      g_free (priv);
      return;
    }

  offset = 0;
  do {
    pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)(priv->file_notify_buffer + offset);
    if (pfile_notify_walker->Action > 0)
      {
	file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
	path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
	file = g_file_new_for_path (path);
	g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
	g_object_unref (file);
	g_free (path);
	g_free (file_name);
      }
    offset += pfile_notify_walker->NextEntryOffset;
  } while (pfile_notify_walker->NextEntryOffset);

  ReadDirectoryChangesW (priv->hDirectory,
			 (gpointer)priv->file_notify_buffer,
			 priv->buffer_allocated_bytes,
			 FALSE, 
			 FILE_NOTIFY_CHANGE_FILE_NAME |
			 FILE_NOTIFY_CHANGE_DIR_NAME |
			 FILE_NOTIFY_CHANGE_ATTRIBUTES |
			 FILE_NOTIFY_CHANGE_SIZE,
			 &priv->buffer_filled_bytes,
			 &priv->overlapped,
			 g_win32_directory_monitor_callback);
}
コード例 #12
0
static gboolean
g_file_monitor_source_dispatch (GSource     *source,
                                GSourceFunc  callback,
                                gpointer     user_data)
{
  GFileMonitorSource *fms = (GFileMonitorSource *) source;
  QueuedEvent *event;
  GQueue event_queue;
  gint64 now;

  /* make sure the monitor still exists */
  if (!fms->instance)
    return FALSE;

  now = g_source_get_time (source);

  /* Acquire the lock once and grab all events in one go, handling the
   * queued events first.  This avoids strange possibilities in cases of
   * long delays, such as CHANGED events coming before CREATED events.
   *
   * We do this by converting the applicable pending changes into queued
   * events (after the ones already queued) and then stealing the entire
   * event queue in one go.
   */
  g_mutex_lock (&fms->lock);

  /* Create events for any pending changes that are due to fire */
  while (!g_sequence_is_empty (fms->pending_changes))
    {
      GSequenceIter *iter = g_sequence_get_begin_iter (fms->pending_changes);
      PendingChange *pending = g_sequence_get (iter);

      /* We've gotten to a pending change that's not ready.  Stop. */
      if (pending_change_get_ready_time (pending, fms) > now)
        break;

      if (pending->dirty)
        {
          /* It's time to send another CHANGED and update the record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGED, pending->child, NULL);
          pending->last_emission = now;
          pending->dirty = FALSE;

          g_sequence_sort_changed (iter, pending_change_compare_ready_time, fms);
        }
      else
        {
          /* It's time to send CHANGES_DONE and remove the pending record */
          g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, pending->child, NULL);
          g_file_monitor_source_remove_pending_change (fms, iter, pending->child);
        }
    }

  /* Steal the queue */
  memcpy (&event_queue, &fms->event_queue, sizeof event_queue);
  memset (&fms->event_queue, 0, sizeof fms->event_queue);

  g_file_monitor_source_update_ready_time (fms);

  g_mutex_unlock (&fms->lock);

  /* We now have our list of events to deliver */
  while ((event = g_queue_pop_head (&event_queue)))
    {
      /* an event handler could destroy 'instance', so check each time */
      if (fms->instance)
        g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type);

      queued_event_free (event);
    }

  return TRUE;
}
コード例 #13
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;
  GFileMonitor *monitor = 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;
    }

  monitor = G_FILE_MONITOR (sub->user_data);
  g_assert (monitor != 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, monitor);  
      n.flags &= ~(NOTE_WRITE | NOTE_EXTEND);
    }

  if (n.flags)
    {
      gboolean done = FALSE;
      mask = convert_kqueue_events_to_gio (n.flags, &done);
      if (done == TRUE)
        {
          GFile *file = g_file_new_for_path (sub->filename);
          g_file_monitor_emit_event (monitor, file, NULL, mask);
          g_object_unref (file);
        }
    }

  return TRUE;
}