예제 #1
0
static void
cockpit_fswrite_prepare (CockpitChannel *channel)
{
  CockpitFswrite *self = COCKPIT_FSWRITE (channel);
  const gchar *problem = "protocol-error";
  JsonObject *options;
  gchar *actual_tag = NULL;

  COCKPIT_CHANNEL_CLASS (cockpit_fswrite_parent_class)->prepare (channel);

  options = cockpit_channel_get_options (channel);
  if (!cockpit_json_get_string (options, "path", NULL, &self->path))
    {
      g_warning ("invalid \"path\" option for fswrite1 channel");
      goto out;
    }
  else if (self->path == NULL || g_str_equal (self->path, ""))
    {
      g_warning ("missing \"path\" option for fswrite1 channel");
      goto out;
    }

  if (!cockpit_json_get_string (options, "tag", NULL, &self->expected_tag))
    {
      g_warning ("%s: invalid \"tag\" option for fswrite1 channel", self->path);
      goto out;
    }

  actual_tag = cockpit_get_file_tag (self->path);
  if (self->expected_tag && g_strcmp0 (self->expected_tag, actual_tag))
    {
      problem = "change-conflict";
      goto out;
    }

  // TODO - delay the opening until the first content message.  That
  // way, we don't create a useless temporary file (which might even
  // fail).

  for (int i = 1; i < 10000; i++)
    {
      self->tmp_path = g_strdup_printf ("%s.%d", self->path, i);
      self->fd = open (self->tmp_path, O_WRONLY | O_CREAT | O_EXCL, 0666);
      if (self->fd >= 0 || errno != EEXIST)
        break;
      g_free (self->tmp_path);
      self->tmp_path = NULL;
    }

  problem = NULL;
  if (self->fd < 0)
    close_with_errno (self, "couldn't open unique file", errno);
  else
    cockpit_channel_ready (channel);

out:
  g_free (actual_tag);
  if (problem)
      cockpit_channel_close (channel, problem);
}
예제 #2
0
static void
cockpit_fswrite_eof (CockpitChannel *channel)
{
  CockpitFswrite *self = COCKPIT_FSWRITE (channel);
  const gchar *problem = NULL;
  JsonObject *options;

  /* Commit the changes when there was no problem  */
  if (xfsync (self->fd) < 0 || xclose (self->fd) < 0)
    {
      problem = prepare_for_close_with_errno (self, "couldn't sync", errno);
    }
  else
    {
      gchar *actual_tag = cockpit_get_file_tag (self->path);
      if (self->expected_tag && g_strcmp0 (self->expected_tag, actual_tag))
        {
          problem = "out-of-date";
        }
      else
        {
          options = cockpit_channel_close_options (channel);
          if (!self->got_content)
            {
              json_object_set_string_member (options, "tag", "-");
              if (unlink (self->path) < 0 && errno != ENOENT)
                problem = prepare_for_close_with_errno (self, "couldn't unlink", errno);
              unlink (self->tmp_path);
            }
          else
            {
              gchar *new_tag = cockpit_get_file_tag (self->tmp_path);
              json_object_set_string_member (options, "tag", new_tag);
              if (rename (self->tmp_path, self->path) < 0)
                problem = prepare_for_close_with_errno (self, "couldn't rename", errno);
              g_free (new_tag);
            }
        }
      g_free (actual_tag);
    }

  self->fd = -1;
  cockpit_channel_close (channel, problem);
}
예제 #3
0
void
cockpit_fswatch_emit_event (CockpitChannel    *channel,
                            GFile             *file,
                            GFile             *other_file,
                            GFileMonitorEvent  event_type)
{
  JsonObject *msg;
  GBytes *msg_bytes;

  msg = json_object_new ();
  json_object_set_string_member (msg, "event", event_type_to_string (event_type));
  if (file)
    {
      char *p = g_file_get_path (file);
      char *t = cockpit_get_file_tag (p);
      json_object_set_string_member (msg, "path", p);
      json_object_set_string_member (msg, "tag", t);
      if (event_type == G_FILE_MONITOR_EVENT_CREATED)
        {
          GError *error = NULL;
          GFileInfo *info = g_file_query_info (file,
                                               G_FILE_ATTRIBUTE_STANDARD_TYPE,
                                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                               NULL, &error);
          if (info)
            {
              json_object_set_string_member
                (msg, "type", cockpit_file_type_to_string (g_file_info_get_file_type (info)));
              g_object_unref (info);
            }

          g_clear_error (&error);
      }

      g_free (p);
      g_free (t);
    }
  if (other_file)
    {
      char *p = g_file_get_path (other_file);
      json_object_set_string_member (msg, "other", p);
      g_free (p);
    }
  msg_bytes = cockpit_json_write_bytes (msg);
  json_object_unref (msg);
  cockpit_channel_send (channel, msg_bytes, TRUE);
  g_bytes_unref (msg_bytes);
}