void lllp_connected_cb(GObject *listener, GAsyncResult *res, gpointer pstore_library) {
	GtkListStore *store_library = GTK_LIST_STORE(pstore_library);
	GSocketConnection *connection;
	GSocketAddress *address;
	gchar *address_char;
	GInputStream *stream;
	GFile *output_file;
	GOutputStream *file_stream;
	gsize count;
	gboolean valid = FALSE;


	connection = g_socket_listener_accept_finish(G_SOCKET_LISTENER(listener), res, NULL, NULL);
	address = g_socket_connection_get_remote_address(connection, NULL);
	address_char = g_inet_address_to_string(g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(address)));
	printf("%s\n", address_char);

	output_file = g_file_new_for_path(address_char);
	g_file_delete(output_file, NULL, NULL);
	file_stream = (GOutputStream*)g_file_replace(output_file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, NULL);

	stream = g_io_stream_get_input_stream(G_IO_STREAM(connection));
	g_output_stream_splice(file_stream, stream, 
		G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE & G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, NULL);
	g_output_stream_close(file_stream, NULL, NULL);

	convert_library_to_list_store(store_library, address_char);

	printf("%s CONNECTED\n", address_char);

	g_socket_listener_accept_async(G_SOCKET_LISTENER(listener), NULL, lllp_connected_cb, store_library);
}
示例#2
0
static GBytes *
download_uri (SoupURI  *uri,
              GError  **error)
{
  g_autoptr(SoupSession) session = NULL;
  g_autoptr(SoupRequest) req = NULL;
  g_autoptr(GInputStream) input = NULL;
  g_autoptr(GOutputStream) out = NULL;

  g_assert (uri != NULL);

  session = get_soup_session ();

  req = soup_session_request_uri (session, uri, error);
  if (req == NULL)
    return NULL;

  input = soup_request_send (req, NULL, error);
  if (input == NULL)
    return NULL;

  out = g_memory_output_stream_new_resizable ();
  if (!g_output_stream_splice (out,
                               input,
                               G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
                               NULL,
                               error))
    return NULL;

  return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out));
}
static gboolean
decompress_all (GConverter   *converter,
                GBytes       *data,
                GBytes      **out_uncompressed,
                GCancellable *cancellable,
                GError      **error)
{
  gboolean ret = FALSE;
  g_autoptr(GMemoryInputStream) memin = (GMemoryInputStream*)g_memory_input_stream_new_from_bytes (data);
  g_autoptr(GMemoryOutputStream) memout = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
  g_autoptr(GInputStream) convin = g_converter_input_stream_new ((GInputStream*)memin, converter);

  {
    gssize n_bytes_written = g_output_stream_splice ((GOutputStream*)memout, convin,
                                                     G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                                                     G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                                                     cancellable, error);
      if (n_bytes_written < 0)
        goto out;
  }

  ret = TRUE;
  *out_uncompressed = g_memory_output_stream_steal_as_bytes (memout);
 out:
  return ret;
}
示例#4
0
static GBytes *
download_uri (const char *url,
              BuilderContext *context,
              GError **error)
{
  SoupSession *session;
  g_autoptr(SoupRequest) req = NULL;
  g_autoptr(GInputStream) input = NULL;
  g_autoptr(GOutputStream) out = NULL;

  session = builder_context_get_soup_session (context);

  req = soup_session_request (session, url, error);
  if (req == NULL)
    return NULL;

  input = soup_request_send (req, NULL, error);
  if (input == NULL)
    return NULL;

  out = g_memory_output_stream_new_resizable ();
  if (!g_output_stream_splice  (out,
                                input,
                                G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
                                NULL,
                                error))
    return NULL;

  return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out));
}
示例#5
0
/**
 * Read all input from @src, allocating a new #GVariant from it into
 * output variable @out_variant.  @src will be closed as a result.
 *
 * Note the returned @out_variant is not floating.
 */
gboolean
ot_util_variant_from_stream (GInputStream         *src,
                             const GVariantType   *type,
                             gboolean              trusted,
                             GVariant            **out_variant,
                             GCancellable         *cancellable,
                             GError              **error)
{
  gboolean ret = FALSE;
  gs_unref_object GMemoryOutputStream *data_stream = NULL;
  gs_unref_variant GVariant *ret_variant = NULL;

  data_stream = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);

  if (g_output_stream_splice ((GOutputStream*)data_stream, src,
                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                              cancellable, error) < 0)
    goto out;

  ret_variant = g_variant_new_from_data (type, g_memory_output_stream_get_data (data_stream),
                                         g_memory_output_stream_get_data_size (data_stream),
                                         trusted, (GDestroyNotify) g_object_unref, data_stream);
  data_stream = NULL; /* Transfer ownership */
  g_variant_ref_sink (ret_variant);

  ret = TRUE;
  ot_transfer_out_value (out_variant, &ret_variant);
 out:
  return ret;
}
示例#6
0
gboolean
ot_gio_splice_update_checksum (GOutputStream  *out,
                               GInputStream   *in,
                               GChecksum      *checksum,
                               GCancellable   *cancellable,
                               GError        **error)
{
  gboolean ret = FALSE;

  g_return_val_if_fail (out != NULL || checksum != NULL, FALSE);

  if (checksum != NULL)
    {
      gsize bytes_read, bytes_written;
      char buf[4096];
      do
        {
          if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
            goto out;
          if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum,
                                             cancellable, error))
            goto out;
        }
      while (bytes_read > 0);
    }
  else
    {
      if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
handle_userdata_script (MinCloudAgentApp      *self,
                        GInputStream               *instream,
                        GCancellable               *cancellable,
                        GError                    **error)
{
  gboolean ret = FALSE;
  gs_free char *tmppath = g_strdup ("/var/tmp/userdata-script.XXXXXX");
  gs_unref_object GOutputStream *outstream = NULL;
  int fd;

  fd = g_mkstemp_full (tmppath, O_WRONLY, 0700);
  if (fd == -1)
    {
      int errsv = errno;
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Failed to create temporary userdata script: %s",
                   g_strerror (errsv));
      goto out;
    }
  outstream = g_unix_output_stream_new (fd, TRUE);

  if (0 > g_output_stream_splice ((GOutputStream*)outstream, instream,
                                  G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET |
                                  G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
                                  self->cancellable, error))
    goto out;

  gs_log_structured_print_id_v (MCA_USERDATA_EXECUTING_ID,
                                "Executing user data script");

  if (!gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
                                      cancellable, error,
                                      tmppath,
                                      NULL))
    {
      gs_log_structured_print_id_v (MCA_USERDATA_FAILED_ID,
                                    "User data script failed");
      goto out;
    }

  gs_log_structured_print_id_v (MCA_USERDATA_SUCCESS_ID,
                                "User data script suceeded");
  
  if (!g_file_replace_contents (self->userdata_done_stamp, "done\n", 5,
                                NULL, FALSE, 0,
                                NULL, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  (void) unlink (tmppath);
  return ret;
}
示例#8
0
static gboolean
fetch_uri_contents_utf8_sync (OtPullData  *pull_data,
                              SoupURI     *uri,
                              char       **out_contents,
                              GCancellable  *cancellable,
                              GError     **error)
{
  gboolean ret = FALSE;
  const guint8 nulchar = 0;
  gs_free char *ret_contents = NULL;
  gs_unref_object GMemoryOutputStream *buf = NULL;
  OstreeFetchUriSyncData fetch_data = { 0, };

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  fetch_data.pull_data = pull_data;

  pull_data->fetching_sync_uri = uri;
  ostree_fetcher_stream_uri_async (pull_data->fetcher, uri, cancellable,
                                   fetch_uri_sync_on_complete, &fetch_data);

  run_mainloop_monitor_fetcher (pull_data);
  if (!fetch_data.result_stream)
    goto out;

  buf = (GMemoryOutputStream*)g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
  if (g_output_stream_splice ((GOutputStream*)buf, fetch_data.result_stream,
                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
                              cancellable, error) < 0)
    goto out;

  /* Add trailing NUL */
  if (!g_output_stream_write ((GOutputStream*)buf, &nulchar, 1, cancellable, error))
    goto out;

  if (!g_output_stream_close ((GOutputStream*)buf, cancellable, error))
    goto out;

  ret_contents = g_memory_output_stream_steal_data (buf);

  if (!g_utf8_validate (ret_contents, -1, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Invalid UTF-8");
      goto out;
    }

  ret = TRUE;
  ot_transfer_out_value (out_contents, &ret_contents);
 out:
  g_clear_object (&(fetch_data.result_stream));
  return ret;
}
示例#9
0
static GBytes *
read_gpg_data (GCancellable *cancellable,
               GError **error)
{
  g_autoptr(GInputStream) source_stream = NULL;
  g_autoptr(GOutputStream) mem_stream = NULL;
  guint n_keyrings = 0;
  g_autoptr(GPtrArray) streams = NULL;

  if (opt_gpg_file != NULL)
    n_keyrings = g_strv_length (opt_gpg_file);

  guint ii;

  streams = g_ptr_array_new_with_free_func (g_object_unref);

  for (ii = 0; ii < n_keyrings; ii++)
    {
      GInputStream *input_stream = NULL;

      if (strcmp (opt_gpg_file[ii], "-") == 0)
        {
          input_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE);
        }
      else
        {
          g_autoptr(GFile) file = g_file_new_for_path (opt_gpg_file[ii]);
          input_stream = G_INPUT_STREAM(g_file_read (file, cancellable, error));

          if (input_stream == NULL)
            return NULL;
        }

      /* Takes ownership. */
      g_ptr_array_add (streams, input_stream);
    }

  /* Chain together all the --keyring options as one long stream. */
  source_stream = (GInputStream *) xdg_app_chain_input_stream_new (streams);

  mem_stream = g_memory_output_stream_new_resizable ();
  if (g_output_stream_splice (mem_stream, source_stream, G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, cancellable, error) < 0)
    return NULL;

  return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (mem_stream));
}
示例#10
0
static VALUE
rg_splice(int argc, VALUE *argv, VALUE self)
{
        VALUE source, flags, cancellable;
        GError *error = NULL;
        gssize bytes_spliced;

        rb_scan_args(argc, argv, "12", &source, &flags, &cancellable);
        bytes_spliced = g_output_stream_splice(_SELF(self),
                                               RVAL2GINPUTSTREAM(source),
                                               RVAL2GOUTPUTSTREAMSPLICEFLAGSDEFAULT(flags),
                                               RVAL2GCANCELLABLE(cancellable),
                                               &error);
        if (bytes_spliced == -1)
                rbgio_raise_error(error);

        return GSSIZE2RVAL(bytes_spliced);
}
示例#11
0
static gboolean
cat_one_file (GFile         *f,
              GOutputStream *stdout_stream,
              GCancellable  *cancellable,
              GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GInputStream *in = NULL;
  
  in = (GInputStream*)g_file_read (f, cancellable, error);
  if (!in)
    goto out;

  if (!g_output_stream_splice (stdout_stream, in, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
                               cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
示例#12
0
bool gunzip_file(const char *path)
{
        GFile *in = NULL, *out = NULL;
        autofree(gchar) *newpath = NULL;
        autofree(GFileInputStream) *fis = NULL;
        autofree(GFileOutputStream) *fos = NULL;
        autofree(GOutputStream) *cos = NULL;
        autofree(GZlibDecompressor) *conv = NULL;
        gsize ret;

        newpath = g_strdup(path);

        if (g_str_has_suffix(newpath, ".gz")) {
                newpath = str_replace(newpath, ".gz", "");
        }

        in = g_file_new_for_path(path);
        out = g_file_new_for_path(newpath);

        fis = g_file_read(in, NULL, NULL);
        if (!fis) {
                return NULL;
        }
        fos = g_file_replace(out, NULL, FALSE, 0, NULL, NULL);
        if (!fos) {
                return NULL;
        }

        conv = g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
        cos = g_converter_output_stream_new(G_OUTPUT_STREAM(fos), G_CONVERTER(conv));
        if (!cos) {
                return NULL;
        }
        ret = g_output_stream_splice(cos, G_INPUT_STREAM(fis), G_OUTPUT_STREAM_SPLICE_NONE, NULL, NULL);
        return (ret > 0 ? true : false );
}
gboolean
_ostree_static_delta_part_open (GInputStream   *part_in,
                                GBytes         *inline_part_bytes,
                                OstreeStaticDeltaOpenFlags flags,
                                const char     *expected_checksum,
                                GVariant    **out_part,
                                GCancellable *cancellable,
                                GError      **error)
{
  gboolean ret = FALSE;
  const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0;
  const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0;
  gsize bytes_read;
  guint8 comptype;
  g_autoptr(GChecksum) checksum = NULL;
  g_autoptr(GInputStream) checksum_in = NULL;
  g_autoptr(GVariant) ret_part = NULL;
  GInputStream *source_in;

  /* We either take a fd or a GBytes reference */
  g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE);
  g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE);

  if (!skip_checksum)
    {
      checksum = g_checksum_new (G_CHECKSUM_SHA256);
      checksum_in = (GInputStream*)ostree_checksum_input_stream_new (part_in, checksum);
      source_in = checksum_in;
    }
  else
    {
      source_in = part_in;
    }

  { guint8 buf[1];
    /* First byte is compression type */
    if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read,
                                  cancellable, error))
      {
        g_prefix_error (error, "Reading initial compression flag byte: ");
      goto out;
      }
    comptype = buf[0];
  }

  switch (comptype)
    {
    case 0:
      if (!inline_part_bytes)
        {
          int part_fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)part_in);

          /* No compression, no checksums - a fast path */
          if (!ot_util_variant_map_fd (part_fd, 1, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0),
                                       trusted, &ret_part, error))
            goto out;
        }
      else
        {
          g_autoptr(GBytes) content_bytes = g_bytes_new_from_bytes (inline_part_bytes, 1,
                                                                    g_bytes_get_size (inline_part_bytes) - 1);
          ret_part = g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0),
                                               content_bytes, trusted);
          g_variant_ref_sink (ret_part);
        }

      if (!skip_checksum)
        g_checksum_update (checksum, g_variant_get_data (ret_part),
                           g_variant_get_size (ret_part));
      
      break;
    case 'x':
      {
        g_autofree char *tmppath = g_strdup ("/var/tmp/ostree-delta-XXXXXX");
        g_autoptr(GConverter) decomp = (GConverter*) _ostree_lzma_decompressor_new ();
        g_autoptr(GInputStream) convin = g_converter_input_stream_new (source_in, decomp);
        g_autoptr(GOutputStream) unpacked_out = NULL;
        glnx_fd_close int unpacked_fd = -1;
        gssize n_bytes_written;

        unpacked_fd = g_mkstemp_full (tmppath, O_RDWR | O_CLOEXEC, 0640);
        if (unpacked_fd < 0)
          {
            glnx_set_error_from_errno (error);
            goto out;
          }
        
        /* Now make it autocleanup on process exit - in the future, we
         * should consider caching unpacked deltas as well.
         */
        if (unlink (tmppath) < 0)
          {
            glnx_set_error_from_errno (error);
            goto out;
          }
        
        unpacked_out = g_unix_output_stream_new (unpacked_fd, FALSE);

        n_bytes_written = g_output_stream_splice (unpacked_out, convin,
                                                  G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                                                  G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                                                  cancellable, error);
        if (n_bytes_written < 0)
          goto out;

        if (!ot_util_variant_map_fd (unpacked_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_PART_PAYLOAD_FORMAT_V0),
                                     trusted, &ret_part, error))
          goto out;
      }
      break;
    default:
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Invalid compression type '%u'", comptype);
      goto out;
    }

  if (checksum)
    {
      const char *actual_checksum = g_checksum_get_string (checksum);
      g_assert (expected_checksum != NULL);
      if (strcmp (actual_checksum, expected_checksum) != 0)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                       "Checksum mismatch in static delta part; expected=%s actual=%s",
                       expected_checksum, actual_checksum);
          goto out;
        }
    }
        
  ret = TRUE;
  *out_part = g_steal_pointer (&ret_part);
 out:
  return ret;
}
示例#14
0
static gboolean
checkout_object_for_uncompressed_cache (OstreeRepo      *self,
                                        const char      *loose_path,
                                        GFileInfo       *src_info,
                                        GInputStream    *content,
                                        GCancellable    *cancellable,
                                        GError         **error)
{
  gboolean ret = FALSE;
  g_autofree char *temp_filename = NULL;
  g_autoptr(GOutputStream) temp_out = NULL;
  int fd;
  int res;
  guint32 file_mode;

  /* Don't make setuid files in uncompressed cache */
  file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode");
  file_mode &= ~(S_ISUID|S_ISGID);

  if (!gs_file_open_in_tmpdir_at (self->tmp_dir_fd, file_mode,
                                  &temp_filename, &temp_out,
                                  cancellable, error))
    goto out;

  if (g_output_stream_splice (temp_out, content, 0, cancellable, error) < 0)
    goto out;

  if (!g_output_stream_flush (temp_out, cancellable, error))
    goto out;

  fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)temp_out);

  if (!self->disable_fsync)
    {
      do
        res = fsync (fd);
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!g_output_stream_close (temp_out, cancellable, error))
    goto out;

  if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd,
                                            loose_path,
                                            cancellable, error))
    goto out;

  if (G_UNLIKELY (renameat (self->tmp_dir_fd, temp_filename,
                            self->uncompressed_objects_dir_fd, loose_path) == -1))
    {
      if (errno != EEXIST)
        {
          glnx_set_error_from_errno (error);
          g_prefix_error (error, "Storing file '%s': ", temp_filename);
          goto out;
        }
      else
        (void) unlinkat (self->tmp_dir_fd, temp_filename, 0);
    }

  ret = TRUE;
 out:
  return ret;
}
示例#15
0
static void
decompress_db (GFile *db, const char *path)
{
        GFile *db_decomp;
        GFile *db_decomp_tmp;
        GError *error = NULL;
        GZlibDecompressor *conv;
        GInputStream *instream;
        GInputStream *instream_conv;
        GOutputStream *outstream;
        char *tmp_db_path;

        instream = (GInputStream *) g_file_read (db, NULL, &error);
        if (!instream) {
                g_print ("Error opening file: %s", error->message);
                g_error_free (error);
                return;
        }

        conv = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
        instream_conv = (GInputStream *) g_converter_input_stream_new (instream, G_CONVERTER (conv));
        g_object_unref (instream);

        tmp_db_path = g_strdup_printf ("%s.%s", path, "tmp");
        db_decomp_tmp =  g_file_new_for_path (tmp_db_path);
        g_free (tmp_db_path);
        outstream = (GOutputStream *) g_file_replace (db_decomp_tmp,
                                                      NULL,
                                                      FALSE,
                                                      G_FILE_CREATE_NONE,
                                                      NULL,
                                                      &error);
        if (!outstream) {
                g_print ("Error creating file: %s\n", error->message);
                g_error_free (error);
                goto end;
        }

        if (g_output_stream_splice (outstream,
                                    instream_conv,
                                    0,
                                    NULL,
                                    &error) == -1) {
                g_print ("Error decompressing the database: %s\n", error->message);
                g_object_unref (outstream);
                g_error_free (error);
                goto end;
        }

        if (g_output_stream_close (outstream,
                                   NULL,
                                   &error) == FALSE) {
                g_print ("Error decompressing the database: %s\n", error->message);
                g_error_free (error);
        } else {
                db_decomp = g_file_new_for_path (path);
                if (g_file_move (db_decomp_tmp,
                                 db_decomp,
                                 G_FILE_COPY_OVERWRITE,
                                 NULL,
                                 NULL,
                                 NULL,
                                 &error) == FALSE) {
                        g_print ("Error moving the temporary database file to the" \
                                 " original database file: %s\n", error->message);
                        g_error_free (error);
                } else {
                        g_print ("Database updated\n");
                }

                g_object_unref (db_decomp);
        }
        g_object_unref (outstream);

end:
        g_object_unref (db_decomp_tmp);
        g_object_unref (conv);
        g_object_unref (instream_conv);
}
gboolean
rpmostree_compose_builtin_sign (int            argc,
                                char         **argv,
                                GCancellable  *cancellable,
                                GError       **error)
{
  gboolean ret = FALSE;
  GOptionContext *context = g_option_context_new ("- Use rpm-sign to sign an OSTree commit");
  gs_unref_object GFile *repopath = NULL;
  gs_unref_object OstreeRepo *repo = NULL;
  gs_unref_object GFile *tmp_commitdata_file = NULL;
  gs_unref_object GFileIOStream *tmp_sig_stream = NULL;
  gs_unref_object GFile *tmp_sig_file = NULL;
  gs_unref_object GFileIOStream *tmp_commitdata_stream = NULL;
  GOutputStream *tmp_commitdata_output = NULL;
  gs_unref_object GInputStream *commit_data = NULL;
  gs_free char *checksum = NULL;
  gs_unref_variant GVariant *commit_variant = NULL;
  gs_unref_bytes GBytes *commit_bytes = NULL;
  
  if (!rpmostree_option_context_parse (context, option_entries, &argc, &argv, error))
    goto out;

  if (!(opt_repo_path && opt_key_id && opt_rev))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Missing required argument");
      goto out;
    }

  repopath = g_file_new_for_path (opt_repo_path);
  repo = ostree_repo_new (repopath);
  if (!ostree_repo_open (repo, cancellable, error))
    goto out;

  if (!ostree_repo_resolve_rev (repo, opt_rev, FALSE, &checksum, error))
    goto out;

  if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
                                 checksum, &commit_variant, error))
    goto out;

  commit_bytes = g_variant_get_data_as_bytes (commit_variant);
  commit_data = (GInputStream*)g_memory_input_stream_new_from_bytes (commit_bytes);
  
  tmp_commitdata_file = g_file_new_tmp ("tmpsigXXXXXX", &tmp_commitdata_stream,
                                       error);
  if (!tmp_commitdata_file)
    goto out;

  tmp_commitdata_output = (GOutputStream*)g_io_stream_get_output_stream ((GIOStream*)tmp_commitdata_stream);
  if (g_output_stream_splice ((GOutputStream*)tmp_commitdata_output,
                              commit_data,
                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                              G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                              cancellable, error) < 0)
    goto out;

  tmp_sig_file = g_file_new_tmp ("tmpsigoutXXXXXX", &tmp_sig_stream, error);
  if (!tmp_sig_file)
    goto out;

  (void) g_io_stream_close ((GIOStream*)tmp_sig_stream, NULL, NULL);
                                  
  if (!gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_NULL,
                                      cancellable, error,
                                      "rpm-sign",
                                      "--key", opt_key_id,
                                      "--detachsign", gs_file_get_path_cached (tmp_commitdata_file),
                                      "--output", gs_file_get_path_cached (tmp_sig_file),
                                      NULL))
    goto out;

  {
    char *sigcontent = NULL;
    gsize len;
    gs_unref_bytes GBytes *sigbytes = NULL;

    if (!g_file_load_contents (tmp_sig_file, cancellable, &sigcontent, &len, NULL,
                               error))
      goto out;

    sigbytes = g_bytes_new_take (sigcontent, len);

    if (!ostree_repo_append_gpg_signature (repo, checksum, sigbytes,
                                           cancellable, error))
      goto out;
  }

  g_print ("Successfully signed OSTree commit=%s with key=%s\n",
           checksum, opt_key_id);
  
  ret = TRUE;
 out:
  if (tmp_commitdata_file)
    (void) gs_file_unlink (tmp_commitdata_file, NULL, NULL);
  if (tmp_sig_file)
    (void) gs_file_unlink (tmp_sig_file, NULL, NULL);
  return ret;
}
示例#17
0
static gboolean
write_regular_file_content (OstreeRepo            *self,
                            OstreeRepoCheckoutOptions *options,
                            GOutputStream         *output,
                            GFileInfo             *file_info,
                            GVariant              *xattrs,
                            GInputStream          *input,
                            GCancellable          *cancellable,
                            GError               **error)
{
  gboolean ret = FALSE;
  const OstreeRepoCheckoutMode mode = options->mode;
  int fd;
  int res;

  if (g_output_stream_splice (output, input, 0,
                              cancellable, error) < 0)
    goto out;

  if (!g_output_stream_flush (output, cancellable, error))
    goto out;

  fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)output);

  if (mode != OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      do
        res = fchown (fd,
                      g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
                      g_file_info_get_attribute_uint32 (file_info, "unix::gid"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }

      do
        res = fchmod (fd, g_file_info_get_attribute_uint32 (file_info, "unix::mode"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
              
      if (xattrs)
        {
          if (!glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error))
            goto out;
        }
    }
          
  if (fsync_is_enabled (self, options))
    {
      if (fsync (fd) == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }
          
  if (!g_output_stream_close (output, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
示例#18
0
/**
 * ot_file_replace_contents_at:
 * 
 * Like g_file_replace_contents(), except using a fd-relative
 * directory, and optionally enforces use of fdatasync().
 */
gboolean
ot_file_replace_contents_at (int             dfd,
                             const char     *path,
                             GBytes         *contents,
                             gboolean        datasync,
                             GCancellable   *cancellable,
                             GError        **error)
{
  gboolean ret = FALSE;
  int fd;
  g_autofree char *tmpname = NULL;
  g_autoptr(GOutputStream) stream = NULL;
  g_autoptr(GInputStream) instream = NULL;

  if (!gs_file_open_in_tmpdir_at (dfd, 0644,
                                  &tmpname, &stream,
                                  cancellable, error))
    goto out;

  g_assert (G_IS_FILE_DESCRIPTOR_BASED (stream));
  fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (stream));

  instream = g_memory_input_stream_new_from_bytes (contents);

  if (g_bytes_get_size (contents) > 0)
    {
      int r = posix_fallocate (fd, 0, g_bytes_get_size (contents));
      if (r != 0)
        {
          /* posix_fallocate is a weird deviation from errno standards */
          errno = r;
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (g_output_stream_splice (stream, instream, 0,
                              cancellable, error) < 0)
    goto out;

  if (datasync && fdatasync (fd) != 0)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  if (!g_output_stream_close (stream, cancellable, error))
    goto out;

  if (renameat (dfd, tmpname, dfd, path) == -1)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  g_clear_pointer (&tmpname, g_free);

  ret = TRUE;
 out:
  if (tmpname)
    (void) unlinkat (dfd, tmpname, 0);
  return ret;
}
示例#19
0
static gboolean
checkout_object_for_uncompressed_cache (OstreeRepo      *self,
                                        const char      *loose_path,
                                        GFileInfo       *src_info,
                                        GInputStream    *content,
                                        GCancellable    *cancellable,
                                        GError         **error)
{
  gboolean ret = FALSE;
  g_autofree char *temp_filename = NULL;
  g_autoptr(GOutputStream) temp_out = NULL;
  glnx_fd_close int fd = -1;
  int res;
  guint32 file_mode;

  /* Don't make setuid files in uncompressed cache */
  file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode");
  file_mode &= ~(S_ISUID|S_ISGID);

  if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY | O_CLOEXEC,
                                      &fd, &temp_filename,
                                      error))
    goto out;
  temp_out = g_unix_output_stream_new (fd, FALSE);

  if (g_output_stream_splice (temp_out, content, 0, cancellable, error) < 0)
    goto out;

  if (!g_output_stream_flush (temp_out, cancellable, error))
    goto out;

  if (!self->disable_fsync)
    {
      do
        res = fsync (fd);
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!g_output_stream_close (temp_out, cancellable, error))
    goto out;

  if (fchmod (fd, file_mode) < 0)
    {
      glnx_set_error_from_errno (error);
      goto out;
    }

  if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd,
                                            loose_path,
                                            cancellable, error))
    goto out;

  if (!glnx_link_tmpfile_at (self->tmp_dir_fd, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST,
                             fd, temp_filename,
                             self->uncompressed_objects_dir_fd, loose_path,
                             error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
示例#20
0
gboolean
ostree_create_file_from_input (GFile            *dest_file,
                               GFileInfo        *finfo,
                               GVariant         *xattrs,
                               GInputStream     *input,
                               GCancellable     *cancellable,
                               GError          **error)
{
  gboolean ret = FALSE;
  const char *dest_path;
  guint32 uid, gid, mode;
  ot_lobj GFileOutputStream *out = NULL;

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  if (finfo != NULL)
    {
      mode = g_file_info_get_attribute_uint32 (finfo, "unix::mode");
    }
  else
    {
      mode = S_IFREG | 0664;
    }
  dest_path = ot_gfile_get_path_cached (dest_file);

  if (S_ISDIR (mode))
    {
      if (mkdir (ot_gfile_get_path_cached (dest_file), mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISREG (mode))
    {
      out = g_file_create (dest_file, 0, cancellable, error);
      if (!out)
        goto out;

      if (input)
        {
          if (g_output_stream_splice ((GOutputStream*)out, input, 0,
                                      cancellable, error) < 0)
            goto out;
        }

      if (!g_output_stream_close ((GOutputStream*)out, NULL, error))
        goto out;
    }
  else if (S_ISLNK (mode))
    {
      const char *target = g_file_info_get_attribute_byte_string (finfo, "standard::symlink-target");
      if (symlink (target, dest_path) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISCHR (mode) || S_ISBLK (mode))
    {
      guint32 dev = g_file_info_get_attribute_uint32 (finfo, "unix::rdev");
      if (mknod (dest_path, mode, dev) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else if (S_ISFIFO (mode))
    {
      if (mkfifo (dest_path, mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          goto out;
        }
    }
  else
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Invalid mode %u", mode);
      goto out;
    }

  if (finfo != NULL)
    {
      uid = g_file_info_get_attribute_uint32 (finfo, "unix::uid");
      gid = g_file_info_get_attribute_uint32 (finfo, "unix::gid");
      
      if (lchown (dest_path, uid, gid) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          g_prefix_error (error, "lchown(%u, %u) failed: ", uid, gid);
          goto out;
        }
    }

  if (!S_ISLNK (mode))
    {
      if (chmod (dest_path, mode) < 0)
        {
          ot_util_set_error_from_errno (error, errno);
          g_prefix_error (error, "chmod(%u) failed: ", mode);
          goto out;
        }
    }

  if (xattrs != NULL)
    {
      if (!ostree_set_xattrs (dest_file, xattrs, cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  if (!ret && !S_ISDIR(mode))
    {
      (void) unlink (dest_path);
    }
  return ret;
}
/**
 * tmp_picasaweb_upload_async:
 *
 * Temporary solution to provide asynchronous uploading and stop
 * blocking the UI until gdata_picasaweb_service_upload_file_async()
 * becomes available (bgo #600262).  This method does the synchronous
 * file upload, but is run asynchronously via
 * g_simple_async_result_run_in_thread().
 *
 * This sets up a minimal #GDataPicasaWebFile entry, using the
 * basename of the filepath for the file's title (which is not the
 * caption, but might be something we would consider doing).  The
 * image file and the minimal entry are then uploaded to PicasaWeb's
 * default album of "Drop Box".  In the future, we might consider
 * adding an Album Chooser to the Preferences/login window, but only
 * if there's demand.
 **/
static void
tmp_picasaweb_upload_async (GSimpleAsyncResult *result, GObject *source_object, GCancellable *cancellable)
{
	GDataPicasaWebFile *new_file = NULL;
	XviewerPostasaPlugin *plugin = XVIEWER_POSTASA_PLUGIN (source_object);
	GDataPicasaWebService *service = plugin->priv->service;
	GDataPicasaWebFile *file_entry;
	PicasaWebUploadFileAsyncData *data;
#ifdef HAVE_LIBGDATA_0_8
	GDataUploadStream *upload_stream;
	GFileInputStream *in_stream;
	GFileInfo *file_info;
#endif
	gchar *filename;
	GError *error = NULL;

	data = (PicasaWebUploadFileAsyncData*)g_async_result_get_user_data (G_ASYNC_RESULT (result));

	/* get filename to set image title */
	file_entry = gdata_picasaweb_file_new (NULL);
	filename = g_file_get_basename (data->imgfile);
	gdata_entry_set_title (GDATA_ENTRY (file_entry), filename);
	g_free (filename);

#ifdef HAVE_LIBGDATA_0_8
	file_info = g_file_query_info (data->imgfile,
				      G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
				      G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
				      G_FILE_QUERY_INFO_NONE, cancellable,
				      &error);

	if (file_info == NULL)
		goto got_err;

	upload_stream = gdata_picasaweb_service_upload_file (service,
				      NULL /* Upload to Dropbox */, file_entry,
				      g_file_info_get_display_name (file_info),
				      g_file_info_get_content_type (file_info),
				      cancellable, &error);
	g_object_unref (file_info);

	if (upload_stream == NULL)
		goto got_err;

	in_stream = g_file_read (data->imgfile, cancellable, &error);

	if (in_stream == NULL) {
		g_object_unref (upload_stream);
		goto got_err;
	}

	if (g_output_stream_splice (G_OUTPUT_STREAM (upload_stream),
				    G_INPUT_STREAM (in_stream),
				    G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
				    G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
				    cancellable, &error) == -1)
	{
		g_object_unref (upload_stream);
		g_object_unref (in_stream);
		goto got_err;
	}


	new_file = gdata_picasaweb_service_finish_file_upload (service,
							       upload_stream,
							       &error);

	g_object_unref (upload_stream);
	g_object_unref (in_stream);
got_err:
	/* Jump here if any GIO/GData call doesn't return successfully.
	 * Error handling happens below. */

#else
	/* libgdata-0.6 */
	new_file = gdata_picasaweb_service_upload_file (service,
					       NULL /* Uploading to Drop Box */,
					       file_entry, data->imgfile,
					       cancellable, &error);
#endif
	g_object_unref (file_entry);

	if (new_file == NULL || error) {
		if (g_cancellable_is_cancelled (cancellable) == FALSE) {
			g_simple_async_result_set_from_error (result, error);
		}
		/* Clear errors always as cancelling creates errors too */
		g_clear_error (&error);
	} else {
		g_simple_async_result_set_op_res_gboolean (result, TRUE);
	}

	if (new_file != NULL)
		g_object_unref (new_file);
}
示例#22
0
static GFile *
create_temporary_file (GFile      *file,
                       GFileInfo  *file_info,
                       GError    **in_error)
{
	GInputStream *input_stream;
	GOutputStream *output_stream;
	GFile *tmp_file, *parent;
	gchar *dir, *name, *tmp_path;
	guint32 mode;
	gint fd;
	GError *error = NULL;

	if (!g_file_is_native (file)) {
		gchar *uri;

		uri = g_file_get_uri (file);
		g_warning ("Could not create temporary file, file is not native: '%s'", uri);
		g_free (uri);

		g_set_error (in_error,
		             G_IO_ERROR,
		             G_IO_ERROR_FAILED,
		             "Could not create temporary file, file is not native: '%s'",
		             uri);

		return NULL;
	}

	/* Create input stream */
	input_stream = G_INPUT_STREAM (g_file_read (file, NULL, &error));

	if (error) {
		g_critical ("Could not create temporary file, %s", error->message);
		g_propagate_error (in_error, error);
		return NULL;
	}

	/* Create output stream in a tmp file */
	parent = g_file_get_parent (file);
	dir = g_file_get_path (parent);
	g_object_unref (parent);

	name = g_file_get_basename (file);
	tmp_path = g_strdup_printf ("%s" G_DIR_SEPARATOR_S ".tracker-XXXXXX.%s",
	                            dir, name);
	g_free (dir);
	g_free (name);

	mode = g_file_info_get_attribute_uint32 (file_info,
	                                         G_FILE_ATTRIBUTE_UNIX_MODE);
	fd = g_mkstemp_full (tmp_path, O_WRONLY, mode);

	output_stream = g_unix_output_stream_new (fd, TRUE);

	/* Splice the original file into the tmp file */
	g_output_stream_splice (output_stream,
	                        input_stream,
	                        G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
	                        G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
	                        NULL, &error);

	g_object_unref (output_stream);
	g_object_unref (input_stream);

	tmp_file = g_file_new_for_path (tmp_path);
	g_free (tmp_path);

	if (error) {
		g_critical ("Could not copy temporary file, %s", error->message);
		g_propagate_error (in_error, error);
		g_file_delete (tmp_file, NULL, NULL);
		g_object_unref (tmp_file);

		return NULL;
	}

	return tmp_file;
}
示例#23
0
/**
 * as_get_yml_data_origin:
 *
 * Extract the data origin from the AppStream YAML file.
 * We don't use the #AsYAMLData loader, because it is much
 * slower than just loading the initial parts of the file and
 * extracting the origin manually.
 */
static gchar*
as_get_yml_data_origin (const gchar *fname)
{
	const gchar *data;
	GZlibDecompressor *zdecomp;
	g_autoptr(GFileInputStream) fistream = NULL;
	g_autoptr(GMemoryOutputStream) mem_os = NULL;
	g_autoptr(GInputStream) conv_stream = NULL;
	g_autoptr(GFile) file = NULL;
	g_autofree gchar *str = NULL;
	g_auto(GStrv) strv = NULL;
	GError *err;
	guint i;
	gchar *start, *end;
	gchar *origin = NULL;

	file = g_file_new_for_path (fname);
	fistream = g_file_read (file, NULL, &err);

	if (!fistream) {
		g_critical ("Unable to open file '%s' for reading: %s, skipping.", fname, err->message);
		g_error_free (err);
		return NULL;
	}

	mem_os = (GMemoryOutputStream*) g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
	zdecomp = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
	conv_stream = g_converter_input_stream_new (G_INPUT_STREAM (fistream), G_CONVERTER (zdecomp));
	g_object_unref (zdecomp);

	g_output_stream_splice (G_OUTPUT_STREAM (mem_os), conv_stream, 0, NULL, NULL);
	data = (const gchar*) g_memory_output_stream_get_data (mem_os);

	/* faster than a regular expression?
	 * Get the first YAML document, then extract the origin string.
	 */
	if (data == NULL)
		return NULL;
	/* start points to the start of the document, i.e. "File:" normally */
	start = g_strstr_len (data, 400, YAML_SEPARATOR) + YAML_SEPARATOR_LEN;
	if (start == NULL)
		return NULL;
	/* Find the end of the first document - can be NULL if there is only one,
	 * for example if we're given YAML for an empty archive */
	end = g_strstr_len (start, -1, YAML_SEPARATOR);
	str = g_strndup (start, strlen(start) - (end ? strlen(end) : 0));

	strv = g_strsplit (str, "\n", -1);
	for (i = 0; strv[i] != NULL; i++) {
		g_auto(GStrv) strv2 = NULL;
		if (!g_str_has_prefix (strv[i], "Origin:"))
			continue;

		strv2 = g_strsplit (strv[i], ":", 2);
		g_strstrip (strv2[1]);
		origin = g_strdup (strv2[1]);

		/* remove quotes, in case the string is quoted */
		if ((g_str_has_prefix (origin, "\"")) && (g_str_has_suffix (origin, "\""))) {
			g_autofree gchar *tmp = NULL;

			tmp = origin;
			origin = g_strndup (tmp + 1, strlen (tmp) - 2);
		}

		break;
	}

	return origin;
}
int
rpmostree_compose_builtin_sign (int            argc,
                                char         **argv,
                                GCancellable  *cancellable,
                                GError       **error)
{
  int exit_status = EXIT_FAILURE;
  GOptionContext *context = g_option_context_new ("- Use rpm-sign to sign an OSTree commit");
  g_autoptr(GFile) repopath = NULL;
  glnx_unref_object OstreeRepo *repo = NULL;
  g_autoptr(GFile) tmp_commitdata_file = NULL;
  g_autoptr(GFileIOStream) tmp_sig_stream = NULL;
  g_autoptr(GFile) tmp_sig_file = NULL;
  g_autoptr(GFileIOStream) tmp_commitdata_stream = NULL;
  GOutputStream *tmp_commitdata_output = NULL;
  g_autoptr(GInputStream) commit_data = NULL;
  g_autofree char *checksum = NULL;
  g_autoptr(GVariant) commit_variant = NULL;
  g_autoptr(GBytes) commit_bytes = NULL;
  
  if (!rpmostree_option_context_parse (context,
                                       option_entries,
                                       &argc, &argv,
                                       RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD,
                                       cancellable,
                                       NULL,
                                       error))
    goto out;

  if (!(opt_repo_path && opt_key_id && opt_rev))
    {
      rpmostree_usage_error (context, "Missing required argument", error);
      goto out;
    }

  repopath = g_file_new_for_path (opt_repo_path);
  repo = ostree_repo_new (repopath);
  if (!ostree_repo_open (repo, cancellable, error))
    goto out;

  if (!ostree_repo_resolve_rev (repo, opt_rev, FALSE, &checksum, error))
    goto out;

  if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
                                 checksum, &commit_variant, error))
    goto out;

  commit_bytes = g_variant_get_data_as_bytes (commit_variant);
  commit_data = (GInputStream*)g_memory_input_stream_new_from_bytes (commit_bytes);
  
  tmp_commitdata_file = g_file_new_tmp ("tmpsigXXXXXX", &tmp_commitdata_stream,
                                       error);
  if (!tmp_commitdata_file)
    goto out;

  tmp_commitdata_output = (GOutputStream*)g_io_stream_get_output_stream ((GIOStream*)tmp_commitdata_stream);
  if (g_output_stream_splice ((GOutputStream*)tmp_commitdata_output,
                              commit_data,
                              G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
                              G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
                              cancellable, error) < 0)
    goto out;

  tmp_sig_file = g_file_new_tmp ("tmpsigoutXXXXXX", &tmp_sig_stream, error);
  if (!tmp_sig_file)
    goto out;

  (void) g_io_stream_close ((GIOStream*)tmp_sig_stream, NULL, NULL);
                                  

  { const char *child_argv[] = { "rpm-sign",
                                 "--key", opt_key_id,
                                 "--detachsign", gs_file_get_path_cached (tmp_commitdata_file),
                                 "--output", gs_file_get_path_cached (tmp_sig_file),
                                 NULL };
    int estatus;
    
    if (!g_spawn_sync (NULL, (char**)child_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
                       NULL, NULL, &estatus, error))
      goto out;
    if (!g_spawn_check_exit_status (estatus, error))
      goto out;
  }

  {
    char *sigcontent = NULL;
    gsize len;
    g_autoptr(GBytes) sigbytes = NULL;

    if (!g_file_load_contents (tmp_sig_file, cancellable, &sigcontent, &len, NULL,
                               error))
      goto out;

    sigbytes = g_bytes_new_take (sigcontent, len);

    if (!ostree_repo_append_gpg_signature (repo, checksum, sigbytes,
                                           cancellable, error))
      goto out;
  }

  g_print ("Successfully signed OSTree commit=%s with key=%s\n",
           checksum, opt_key_id);
  
  exit_status = EXIT_SUCCESS;

 out:
  if (tmp_commitdata_file)
    (void) unlink (gs_file_get_path_cached (tmp_commitdata_file));
  if (tmp_sig_file)
    (void) unlink (gs_file_get_path_cached (tmp_sig_file));

  return exit_status;
}