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); }
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); }
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); }