Blame src/builder-utils.c

rpm-build c487f7
/* builder-utils.c
rpm-build c487f7
 *
rpm-build c487f7
 * Copyright (C) 2015 Red Hat, Inc
rpm-build c487f7
 *
rpm-build c487f7
 * This file is free software; you can redistribute it and/or modify it
rpm-build c487f7
 * under the terms of the GNU Lesser General Public License as
rpm-build c487f7
 * published by the Free Software Foundation; either version 2 of the
rpm-build c487f7
 * License, or (at your option) any later version.
rpm-build c487f7
 *
rpm-build c487f7
 * This file is distributed in the hope that it will be useful, but
rpm-build c487f7
 * WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build c487f7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
rpm-build c487f7
 * Lesser General Public License for more details.
rpm-build c487f7
 *
rpm-build c487f7
 * You should have received a copy of the GNU Lesser General Public License
rpm-build c487f7
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
rpm-build c487f7
 *
rpm-build c487f7
 * Authors:
rpm-build c487f7
 *       Alexander Larsson <alexl@redhat.com>
rpm-build c487f7
 */
rpm-build c487f7
rpm-build c487f7
#include "config.h"
rpm-build c487f7
rpm-build c487f7
#include <stdlib.h>
rpm-build c487f7
#include <libelf.h>
rpm-build c487f7
#include <gelf.h>
rpm-build c487f7
#include <dwarf.h>
rpm-build c487f7
#include <sys/mman.h>
rpm-build c487f7
#include <sys/uio.h>
rpm-build c487f7
#include <stdio.h>
rpm-build c487f7
rpm-build c487f7
#include <string.h>
rpm-build c487f7
rpm-build c487f7
#include <glib-unix.h>
rpm-build c487f7
#include <gio/gunixfdlist.h>
rpm-build c487f7
#include <gio/gunixoutputstream.h>
rpm-build c487f7
#include <gio/gunixinputstream.h>
rpm-build c487f7
rpm-build c487f7
#include "builder-flatpak-utils.h"
rpm-build c487f7
#include "builder-utils.h"
rpm-build c487f7
rpm-build c487f7
G_DEFINE_QUARK (builder-curl-error, builder_curl_error)
rpm-build c487f7
G_DEFINE_QUARK (builder-yaml-parse-error, builder_yaml_parse_error)
rpm-build c487f7
rpm-build c487f7
#ifdef FLATPAK_BUILDER_ENABLE_YAML
rpm-build c487f7
#include <yaml.h>
rpm-build c487f7
rpm-build c487f7
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (yaml_parser_t, yaml_parser_delete)
rpm-build c487f7
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (yaml_document_t, yaml_document_delete)
rpm-build c487f7
#endif
rpm-build c487f7
rpm-build c487f7
char *
rpm-build c487f7
builder_uri_to_filename (const char *uri)
rpm-build c487f7
{
rpm-build c487f7
  GString *s;
rpm-build c487f7
  const char *p;
rpm-build c487f7
rpm-build c487f7
  s = g_string_new ("");
rpm-build c487f7
rpm-build c487f7
  for (p = uri; *p != 0; p++)
rpm-build c487f7
    {
rpm-build c487f7
      if (*p == '/' || *p == ':')
rpm-build c487f7
        {
rpm-build c487f7
          while (p[1] == '/' || p[1] == ':')
rpm-build c487f7
            p++;
rpm-build c487f7
          g_string_append_c (s, '_');
rpm-build c487f7
        }
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          g_string_append_c (s, *p);
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return g_string_free (s, FALSE);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static const char *
rpm-build c487f7
inplace_basename (const char *path)
rpm-build c487f7
{
rpm-build c487f7
  const char *last_slash;
rpm-build c487f7
rpm-build c487f7
  last_slash = strrchr (path, '/');
rpm-build c487f7
  if (last_slash)
rpm-build c487f7
    path = last_slash + 1;
rpm-build c487f7
rpm-build c487f7
  return path;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
/* Adds all matches of path to prefix. There can be multiple, because
rpm-build c487f7
 * e.g matching "a/b/c" against "/a" matches both "a/b" and "a/b/c"
rpm-build c487f7
 *
rpm-build c487f7
 * If pattern starts with a slash, then match on the entire
rpm-build c487f7
 * path, otherwise just the basename.
rpm-build c487f7
 */
rpm-build c487f7
void
rpm-build c487f7
flatpak_collect_matches_for_path_pattern (const char *path,
rpm-build c487f7
                                          const char *pattern,
rpm-build c487f7
                                          const char *add_prefix,
rpm-build c487f7
                                          GHashTable *to_remove_ht)
rpm-build c487f7
{
rpm-build c487f7
  const char *rest;
rpm-build c487f7
rpm-build c487f7
  if (pattern[0] != '/')
rpm-build c487f7
    {
rpm-build c487f7
      rest = flatpak_path_match_prefix (pattern, inplace_basename (path));
rpm-build c487f7
      if (rest != NULL)
rpm-build c487f7
        g_hash_table_insert (to_remove_ht, g_strconcat (add_prefix ? add_prefix : "", path, NULL), GINT_TO_POINTER (1));
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      /* Absolute pathname match. This can actually match multiple
rpm-build c487f7
       * files, as a prefix match should remove all files below that
rpm-build c487f7
       * (in this module) */
rpm-build c487f7
rpm-build c487f7
      rest = flatpak_path_match_prefix (pattern, path);
rpm-build c487f7
      while (rest != NULL)
rpm-build c487f7
        {
rpm-build c487f7
          const char *slash;
rpm-build c487f7
          g_autofree char *prefix = g_strndup (path, rest - path);
rpm-build c487f7
          g_hash_table_insert (to_remove_ht, g_strconcat (add_prefix ? add_prefix : "", prefix, NULL), GINT_TO_POINTER (1));
rpm-build c487f7
          while (*rest == '/')
rpm-build c487f7
            rest++;
rpm-build c487f7
          if (*rest == 0)
rpm-build c487f7
            break;
rpm-build c487f7
          slash = strchr (rest, '/');
rpm-build c487f7
          rest = slash ? slash : rest + strlen (rest);
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
flatpak_matches_path_pattern (const char *path,
rpm-build c487f7
                              const char *pattern)
rpm-build c487f7
{
rpm-build c487f7
  if (pattern[0] != '/')
rpm-build c487f7
    path = inplace_basename (path);
rpm-build c487f7
rpm-build c487f7
  return flatpak_path_match_prefix (pattern, path) != NULL;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
strip (GError **error,
rpm-build c487f7
       ...)
rpm-build c487f7
{
rpm-build c487f7
  gboolean res;
rpm-build c487f7
  va_list ap;
rpm-build c487f7
rpm-build c487f7
  va_start (ap, error);
rpm-build c487f7
  res = flatpak_spawn (NULL, NULL, 0, error, "strip", ap);
rpm-build c487f7
  va_end (ap);
rpm-build c487f7
rpm-build c487f7
  return res;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
eu_strip (GError **error,
rpm-build c487f7
          ...)
rpm-build c487f7
{
rpm-build c487f7
  gboolean res;
rpm-build c487f7
  va_list ap;
rpm-build c487f7
rpm-build c487f7
  va_start (ap, error);
rpm-build c487f7
  res = flatpak_spawn (NULL, NULL, 0, error, "eu-strip", ap);
rpm-build c487f7
  va_end (ap);
rpm-build c487f7
rpm-build c487f7
  return res;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
eu_elfcompress (GError **error,
rpm-build c487f7
                ...)
rpm-build c487f7
{
rpm-build c487f7
  gboolean res;
rpm-build c487f7
  va_list ap;
rpm-build c487f7
rpm-build c487f7
  va_start (ap, error);
rpm-build c487f7
  res = flatpak_spawn (NULL, NULL, 0, error, "eu-elfcompress", ap);
rpm-build c487f7
  va_end (ap);
rpm-build c487f7
rpm-build c487f7
  return res;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
elf_has_symtab (Elf *elf)
rpm-build c487f7
{
rpm-build c487f7
  Elf_Scn *scn;
rpm-build c487f7
  GElf_Shdr shdr;
rpm-build c487f7
rpm-build c487f7
  scn = NULL;
rpm-build c487f7
  while ((scn = elf_nextscn (elf, scn)) != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      if (gelf_getshdr (scn, &shdr) == NULL)
rpm-build c487f7
        continue;
rpm-build c487f7
rpm-build c487f7
      if (shdr.sh_type != SHT_SYMTAB)
rpm-build c487f7
        continue;
rpm-build c487f7
rpm-build c487f7
      return TRUE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return FALSE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
is_elf_file (const char *path,
rpm-build c487f7
             gboolean   *is_shared,
rpm-build c487f7
             gboolean   *is_stripped)
rpm-build c487f7
{
rpm-build c487f7
  g_autofree char *filename = g_path_get_basename (path);
rpm-build c487f7
  struct stat stbuf;
rpm-build c487f7
rpm-build c487f7
  if (lstat (path, &stbuf) == -1)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!S_ISREG (stbuf.st_mode))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  /* Self-extracting .zip files can be ELF-executables, but shouldn't be
rpm-build c487f7
     treated like them - for example, stripping them breaks their
rpm-build c487f7
     operation */
rpm-build c487f7
  if (g_str_has_suffix (filename, ".zip"))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if ((strstr (filename, ".so.") != NULL ||
rpm-build c487f7
       g_str_has_suffix (filename, ".so")) ||
rpm-build c487f7
      (stbuf.st_mode & 0111) != 0)
rpm-build c487f7
    {
rpm-build c487f7
      glnx_fd_close int fd = -1;
rpm-build c487f7
rpm-build c487f7
      fd = open (path, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
rpm-build c487f7
      if (fd >= 0)
rpm-build c487f7
        {
rpm-build c487f7
          Elf *elf;
rpm-build c487f7
          GElf_Ehdr ehdr;
rpm-build c487f7
          gboolean res = FALSE;
rpm-build c487f7
rpm-build c487f7
          if (elf_version (EV_CURRENT) == EV_NONE )
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
          elf = elf_begin (fd, ELF_C_READ, NULL);
rpm-build c487f7
          if (elf == NULL)
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
          if (elf_kind (elf) == ELF_K_ELF &&
rpm-build c487f7
              gelf_getehdr (elf, &ehdr))
rpm-build c487f7
            {
rpm-build c487f7
              if (is_shared)
rpm-build c487f7
                *is_shared = ehdr.e_type == ET_DYN;
rpm-build c487f7
              if (is_stripped)
rpm-build c487f7
                *is_stripped = !elf_has_symtab (elf);
rpm-build c487f7
rpm-build c487f7
              res = TRUE;
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          elf_end (elf);
rpm-build c487f7
          return res;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return FALSE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
directory_is_empty (const char *path)
rpm-build c487f7
{
rpm-build c487f7
  GDir *dir;
rpm-build c487f7
  gboolean empty;
rpm-build c487f7
rpm-build c487f7
  dir = g_dir_open (path, 0, NULL);
rpm-build c487f7
  if (g_dir_read_name (dir) == NULL)
rpm-build c487f7
    empty = TRUE;
rpm-build c487f7
  else
rpm-build c487f7
    empty = FALSE;
rpm-build c487f7
rpm-build c487f7
  g_dir_close (dir);
rpm-build c487f7
rpm-build c487f7
  return empty;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
migrate_locale_dir (GFile      *source_dir,
rpm-build c487f7
                    GFile      *separate_dir,
rpm-build c487f7
                    const char *subdir,
rpm-build c487f7
                    GError    **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFileEnumerator) dir_enum = NULL;
rpm-build c487f7
  GFileInfo *next;
rpm-build c487f7
  GError *temp_error = NULL;
rpm-build c487f7
rpm-build c487f7
  dir_enum = g_file_enumerate_children (source_dir, "standard::name,standard::type",
rpm-build c487f7
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
rpm-build c487f7
                                        NULL, NULL);
rpm-build c487f7
  if (!dir_enum)
rpm-build c487f7
    return TRUE;
rpm-build c487f7
rpm-build c487f7
  while ((next = g_file_enumerator_next_file (dir_enum, NULL, &temp_error)))
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GFileInfo) child_info = next;
rpm-build c487f7
      g_autoptr(GFile) locale_subdir = NULL;
rpm-build c487f7
rpm-build c487f7
      if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
rpm-build c487f7
        {
rpm-build c487f7
          g_autoptr(GFile) child = NULL;
rpm-build c487f7
          const char *name = g_file_info_get_name (child_info);
rpm-build c487f7
          g_autofree char *language = g_strdup (name);
rpm-build c487f7
          g_autofree char *relative = NULL;
rpm-build c487f7
          g_autofree char *target = NULL;
rpm-build c487f7
          char *c;
rpm-build c487f7
rpm-build c487f7
          c = strchr (language, '@');
rpm-build c487f7
          if (c != NULL)
rpm-build c487f7
            *c = 0;
rpm-build c487f7
          c = strchr (language, '_');
rpm-build c487f7
          if (c != NULL)
rpm-build c487f7
            *c = 0;
rpm-build c487f7
          c = strchr (language, '.');
rpm-build c487f7
          if (c != NULL)
rpm-build c487f7
            *c = 0;
rpm-build c487f7
rpm-build c487f7
          /* We ship english and C locales always */
rpm-build c487f7
          if (strcmp (language, "C") == 0 ||
rpm-build c487f7
              strcmp (language, "en") == 0)
rpm-build c487f7
            continue;
rpm-build c487f7
rpm-build c487f7
          child = g_file_get_child (source_dir, g_file_info_get_name (child_info));
rpm-build c487f7
rpm-build c487f7
          relative = g_build_filename (language, subdir, name, NULL);
rpm-build c487f7
          locale_subdir = g_file_resolve_relative_path (separate_dir, relative);
rpm-build c487f7
          if (!flatpak_mkdir_p (locale_subdir, NULL, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
          if (!flatpak_cp_a (child, locale_subdir,
rpm-build c487f7
                             FLATPAK_CP_FLAGS_MERGE | FLATPAK_CP_FLAGS_MOVE,
rpm-build c487f7
                             NULL, NULL, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
          target = g_build_filename ("../../share/runtime/locale", relative, NULL);
rpm-build c487f7
rpm-build c487f7
          if (!g_file_make_symbolic_link (child, target,
rpm-build c487f7
                                          NULL, error))
rpm-build c487f7
            return FALSE;
rpm-build c487f7
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (temp_error != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_propagate_error (error, temp_error);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_migrate_locale_dirs (GFile   *root_dir,
rpm-build c487f7
                             GError **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFile) separate_dir = NULL;
rpm-build c487f7
  g_autoptr(GFile) lib_locale_dir = NULL;
rpm-build c487f7
  g_autoptr(GFile) share_locale_dir = NULL;
rpm-build c487f7
rpm-build c487f7
  lib_locale_dir = g_file_resolve_relative_path (root_dir, "lib/locale");
rpm-build c487f7
  share_locale_dir = g_file_resolve_relative_path (root_dir, "share/locale");
rpm-build c487f7
  separate_dir = g_file_resolve_relative_path (root_dir, "share/runtime/locale");
rpm-build c487f7
rpm-build c487f7
  if (!migrate_locale_dir (lib_locale_dir, separate_dir, "lib", error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!migrate_locale_dir (share_locale_dir, separate_dir, "share", error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#ifdef FLATPAK_BUILDER_ENABLE_YAML
rpm-build c487f7
rpm-build c487f7
static JsonNode *
rpm-build c487f7
parse_yaml_node_to_json (yaml_document_t *doc, yaml_node_t *node)
rpm-build c487f7
{
rpm-build c487f7
  JsonNode *json = json_node_alloc ();
rpm-build c487f7
  const char *scalar = NULL;
rpm-build c487f7
  g_autoptr(JsonArray) array = NULL;
rpm-build c487f7
  g_autoptr(JsonObject) object = NULL;
rpm-build c487f7
  yaml_node_item_t *item = NULL;
rpm-build c487f7
  yaml_node_pair_t *pair = NULL;
rpm-build c487f7
rpm-build c487f7
  switch (node->type)
rpm-build c487f7
    {
rpm-build c487f7
    case YAML_NO_NODE:
rpm-build c487f7
      json_node_init_null (json);
rpm-build c487f7
      break;
rpm-build c487f7
    case YAML_SCALAR_NODE:
rpm-build c487f7
      scalar = (gchar *) node->data.scalar.value;
rpm-build c487f7
      if (node->data.scalar.style == YAML_PLAIN_SCALAR_STYLE)
rpm-build c487f7
        {
rpm-build c487f7
          if (strcmp (scalar, "true") == 0)
rpm-build c487f7
            {
rpm-build c487f7
              json_node_init_boolean (json, TRUE);
rpm-build c487f7
              break;
rpm-build c487f7
            }
rpm-build c487f7
          else if (strcmp (scalar, "false") == 0)
rpm-build c487f7
            {
rpm-build c487f7
              json_node_init_boolean (json, FALSE);
rpm-build c487f7
              break;
rpm-build c487f7
            }
rpm-build c487f7
          else if (strcmp (scalar, "null") == 0)
rpm-build c487f7
            {
rpm-build c487f7
              json_node_init_null (json);
rpm-build c487f7
              break;
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          if (*scalar != '\0')
rpm-build c487f7
            {
rpm-build c487f7
              gchar *endptr;
rpm-build c487f7
              gint64 num = g_ascii_strtoll (scalar, &endptr, 10);
rpm-build c487f7
              if (*endptr == '\0')
rpm-build c487f7
                {
rpm-build c487f7
                  json_node_init_int (json, num);
rpm-build c487f7
                  break;
rpm-build c487f7
                }
rpm-build c487f7
              // Make sure that N.N, N., and .N (where N is a digit) are picked up as numbers.
rpm-build c487f7
              else if (*endptr == '.' && (endptr != scalar || endptr[1] != '\0'))
rpm-build c487f7
                {
rpm-build c487f7
                  g_ascii_strtoll (endptr + 1, &endptr, 10);
rpm-build c487f7
                  if (*endptr == '\0')
rpm-build c487f7
                    g_warning ("%zu:%zu: '%s' will be parsed as a number by many YAML parsers",
rpm-build c487f7
                               node->start_mark.line + 1, node->start_mark.column + 1, scalar);
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      json_node_init_string (json, scalar);
rpm-build c487f7
      break;
rpm-build c487f7
    case YAML_SEQUENCE_NODE:
rpm-build c487f7
      array = json_array_new ();
rpm-build c487f7
      for (item = node->data.sequence.items.start; item < node->data.sequence.items.top; item++)
rpm-build c487f7
        {
rpm-build c487f7
          yaml_node_t *child = yaml_document_get_node (doc, *item);
rpm-build c487f7
          if (child != NULL)
rpm-build c487f7
            json_array_add_element (array, parse_yaml_node_to_json (doc, child));
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      json_node_init_array (json, array);
rpm-build c487f7
      break;
rpm-build c487f7
    case YAML_MAPPING_NODE:
rpm-build c487f7
      object = json_object_new ();
rpm-build c487f7
      for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++)
rpm-build c487f7
        {
rpm-build c487f7
          yaml_node_t *key = yaml_document_get_node (doc, pair->key);
rpm-build c487f7
          yaml_node_t *value = yaml_document_get_node (doc, pair->value);
rpm-build c487f7
rpm-build c487f7
          g_warn_if_fail (key->type == YAML_SCALAR_NODE);
rpm-build c487f7
          json_object_set_member (object, (gchar *) key->data.scalar.value,
rpm-build c487f7
                                  parse_yaml_node_to_json (doc, value));
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      json_node_init_object (json, object);
rpm-build c487f7
      break;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return json;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static JsonNode *
rpm-build c487f7
parse_yaml_to_json (const gchar *contents,
rpm-build c487f7
                    GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  if (error)
rpm-build c487f7
    *error = NULL;
rpm-build c487f7
rpm-build c487f7
  g_auto(yaml_parser_t) parser = {0};
rpm-build c487f7
  g_auto(yaml_document_t) doc = {{0}};
rpm-build c487f7
rpm-build c487f7
  if (!yaml_parser_initialize (&parser))
rpm-build c487f7
    g_error ("yaml_parser_initialize is out of memory.");
rpm-build c487f7
  yaml_parser_set_input_string (&parser, (yaml_char_t *) contents, strlen (contents));
rpm-build c487f7
rpm-build c487f7
  if (!yaml_parser_load (&parser, &doc))
rpm-build c487f7
    {
rpm-build c487f7
      g_set_error (error, BUILDER_YAML_PARSE_ERROR, parser.error, "%zu:%zu: %s", parser.problem_mark.line + 1,
rpm-build c487f7
                   parser.problem_mark.column + 1, parser.problem);
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  yaml_node_t *root = yaml_document_get_root_node (&doc;;
rpm-build c487f7
  if (root == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_set_error (error, BUILDER_YAML_PARSE_ERROR, YAML_PARSER_ERROR,
rpm-build c487f7
                   "Document has no root node.");
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return parse_yaml_node_to_json (&doc, root);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#else // FLATPAK_BUILDER_ENABLE_YAML
rpm-build c487f7
rpm-build c487f7
static JsonNode *
rpm-build c487f7
parse_yaml_to_json (const gchar *contents,
rpm-build c487f7
                    GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_set_error (error, BUILDER_YAML_PARSE_ERROR, 0, "flatpak-builder was not compiled with YAML support.");
rpm-build c487f7
  return NULL;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#endif  // FLATPAK_BUILDER_ENABLE_YAML
rpm-build c487f7
rpm-build c487f7
JsonNode *
rpm-build c487f7
builder_json_node_from_data (const char *relpath,
rpm-build c487f7
                             const char *contents,
rpm-build c487f7
                             GError    **error)
rpm-build c487f7
{
rpm-build c487f7
  if (g_str_has_suffix (relpath, ".yaml") || g_str_has_suffix (relpath, ".yml"))
rpm-build c487f7
    return parse_yaml_to_json (contents, error);
rpm-build c487f7
  else
rpm-build c487f7
    return json_from_string (contents, error);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GObject *
rpm-build c487f7
builder_gobject_from_data (GType       gtype,
rpm-build c487f7
                           const char *relpath,
rpm-build c487f7
                           const char *contents,
rpm-build c487f7
                           GError    **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(JsonNode) json = builder_json_node_from_data (relpath, contents, error);
rpm-build c487f7
  if (json != NULL)
rpm-build c487f7
    return json_gobject_deserialize (gtype, json);
rpm-build c487f7
  else
rpm-build c487f7
    return NULL;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/*
rpm-build c487f7
 * This code is based on debugedit.c from rpm, which has this copyright:
rpm-build c487f7
 *
rpm-build c487f7
 *
rpm-build c487f7
 * Copyright (C) 2001, 2002, 2003, 2005, 2007, 2009, 2010, 2011 Red Hat, Inc.
rpm-build c487f7
 * Written by Alexander Larsson <alexl@redhat.com>, 2002
rpm-build c487f7
 * Based on code by Jakub Jelinek <jakub@redhat.com>, 2001.
rpm-build c487f7
 *
rpm-build c487f7
 * This program is free software; you can redistribute it and/or modify
rpm-build c487f7
 * it under the terms of the GNU General Public License as published by
rpm-build c487f7
 * the Free Software Foundation; either version 2, or (at your option)
rpm-build c487f7
 * any later version.
rpm-build c487f7
 *
rpm-build c487f7
 * This program is distributed in the hope that it will be useful,
rpm-build c487f7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
rpm-build c487f7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
rpm-build c487f7
 * GNU General Public License for more details.
rpm-build c487f7
 *
rpm-build c487f7
 * You should have received a copy of the GNU General Public License
rpm-build c487f7
 * along with this program; if not, write to the Free Software Foundation,
rpm-build c487f7
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
#define DW_TAG_partial_unit 0x3c
rpm-build c487f7
#define DW_FORM_sec_offset 0x17
rpm-build c487f7
#define DW_FORM_exprloc 0x18
rpm-build c487f7
#define DW_FORM_flag_present 0x19
rpm-build c487f7
#define DW_FORM_ref_sig8 0x20
rpm-build c487f7
rpm-build c487f7
/* keep uptodate with changes to debug_sections */
rpm-build c487f7
#define DEBUG_INFO 0
rpm-build c487f7
#define DEBUG_ABBREV 1
rpm-build c487f7
#define DEBUG_LINE 2
rpm-build c487f7
#define DEBUG_ARANGES 3
rpm-build c487f7
#define DEBUG_PUBNAMES 4
rpm-build c487f7
#define DEBUG_PUBTYPES 5
rpm-build c487f7
#define DEBUG_MACINFO 6
rpm-build c487f7
#define DEBUG_LOC 7
rpm-build c487f7
#define DEBUG_STR 8
rpm-build c487f7
#define DEBUG_FRAME 9
rpm-build c487f7
#define DEBUG_RANGES 10
rpm-build c487f7
#define DEBUG_TYPES 11
rpm-build c487f7
#define DEBUG_MACRO 12
rpm-build c487f7
#define DEBUG_GDB_SCRIPT 13
rpm-build c487f7
#define NUM_DEBUG_SECTIONS 14
rpm-build c487f7
rpm-build c487f7
static const char * debug_section_names[] = {
rpm-build c487f7
  ".debug_info",
rpm-build c487f7
  ".debug_abbrev",
rpm-build c487f7
  ".debug_line",
rpm-build c487f7
  ".debug_aranges",
rpm-build c487f7
  ".debug_pubnames",
rpm-build c487f7
  ".debug_pubtypes",
rpm-build c487f7
  ".debug_macinfo",
rpm-build c487f7
  ".debug_loc",
rpm-build c487f7
  ".debug_str",
rpm-build c487f7
  ".debug_frame",
rpm-build c487f7
  ".debug_ranges",
rpm-build c487f7
  ".debug_types",
rpm-build c487f7
  ".debug_macro",
rpm-build c487f7
  ".debug_gdb_scripts",
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
typedef struct
rpm-build c487f7
{
rpm-build c487f7
  unsigned char *data;
rpm-build c487f7
  Elf_Data      *elf_data;
rpm-build c487f7
  size_t         size;
rpm-build c487f7
  int            sec, relsec;
rpm-build c487f7
} debug_section_t;
rpm-build c487f7
rpm-build c487f7
typedef struct
rpm-build c487f7
{
rpm-build c487f7
  Elf            *elf;
rpm-build c487f7
  GElf_Ehdr       ehdr;
rpm-build c487f7
  Elf_Scn       **scns;
rpm-build c487f7
  const char     *filename;
rpm-build c487f7
  int             lastscn;
rpm-build c487f7
  debug_section_t debug_sections[NUM_DEBUG_SECTIONS];
rpm-build c487f7
  GElf_Shdr      *shdr;
rpm-build c487f7
} DebuginfoData;
rpm-build c487f7
rpm-build c487f7
typedef struct
rpm-build c487f7
{
rpm-build c487f7
  unsigned char *ptr;
rpm-build c487f7
  uint32_t       addend;
rpm-build c487f7
} REL;
rpm-build c487f7
rpm-build c487f7
#define read_uleb128(ptr) ({            \
rpm-build c487f7
    unsigned int ret = 0;                 \
rpm-build c487f7
    unsigned int c;                       \
rpm-build c487f7
    int shift = 0;                        \
rpm-build c487f7
    do                                    \
rpm-build c487f7
    {                                   \
rpm-build c487f7
      c = *ptr++;                       \
rpm-build c487f7
      ret |= (c & 0x7f) << shift;       \
rpm-build c487f7
      shift += 7;                       \
rpm-build c487f7
    } while (c & 0x80);                 \
rpm-build c487f7
                                        \
rpm-build c487f7
    if (shift >= 35)                      \
rpm-build c487f7
      ret = UINT_MAX;                     \
rpm-build c487f7
    ret;                                  \
rpm-build c487f7
  })
rpm-build c487f7
rpm-build c487f7
static uint16_t (*do_read_16)(unsigned char *ptr);
rpm-build c487f7
static uint32_t (*do_read_32) (unsigned char *ptr);
rpm-build c487f7
rpm-build c487f7
static int ptr_size;
rpm-build c487f7
static int cu_version;
rpm-build c487f7
rpm-build c487f7
static inline uint16_t
rpm-build c487f7
buf_read_ule16 (unsigned char *data)
rpm-build c487f7
{
rpm-build c487f7
  return data[0] | (data[1] << 8);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static inline uint16_t
rpm-build c487f7
buf_read_ube16 (unsigned char *data)
rpm-build c487f7
{
rpm-build c487f7
  return data[1] | (data[0] << 8);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static inline uint32_t
rpm-build c487f7
buf_read_ule32 (unsigned char *data)
rpm-build c487f7
{
rpm-build c487f7
  return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static inline uint32_t
rpm-build c487f7
buf_read_ube32 (unsigned char *data)
rpm-build c487f7
{
rpm-build c487f7
  return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#define read_1(ptr) *ptr++
rpm-build c487f7
rpm-build c487f7
#define read_16(ptr) ({                                 \
rpm-build c487f7
    uint16_t ret = do_read_16 (ptr);                      \
rpm-build c487f7
    ptr += 2;                                             \
rpm-build c487f7
    ret;                                                  \
rpm-build c487f7
  })
rpm-build c487f7
rpm-build c487f7
#define read_32(ptr) ({                                 \
rpm-build c487f7
    uint32_t ret = do_read_32 (ptr);                      \
rpm-build c487f7
    ptr += 4;                                             \
rpm-build c487f7
    ret;                                                  \
rpm-build c487f7
  })
rpm-build c487f7
rpm-build c487f7
REL *relptr, *relend;
rpm-build c487f7
int reltype;
rpm-build c487f7
rpm-build c487f7
#define do_read_32_relocated(ptr) ({                    \
rpm-build c487f7
    uint32_t dret = do_read_32 (ptr);                     \
rpm-build c487f7
    if (relptr)                                           \
rpm-build c487f7
    {                                                   \
rpm-build c487f7
      while (relptr < relend && relptr->ptr < ptr)      \
rpm-build c487f7
        ++relptr;                                       \
rpm-build c487f7
      if (relptr < relend && relptr->ptr == ptr)        \
rpm-build c487f7
      {                                               \
rpm-build c487f7
        if (reltype == SHT_REL)                       \
rpm-build c487f7
          dret += relptr->addend;                     \
rpm-build c487f7
        else                                          \
rpm-build c487f7
          dret = relptr->addend;                      \
rpm-build c487f7
      }                                               \
rpm-build c487f7
    }                                                   \
rpm-build c487f7
    dret;                                                 \
rpm-build c487f7
  })
rpm-build c487f7
rpm-build c487f7
#define read_32_relocated(ptr) ({                       \
rpm-build c487f7
    uint32_t ret = do_read_32_relocated (ptr);            \
rpm-build c487f7
    ptr += 4;                                             \
rpm-build c487f7
    ret;                                                  \
rpm-build c487f7
  })
rpm-build c487f7
rpm-build c487f7
struct abbrev_attr
rpm-build c487f7
{
rpm-build c487f7
  unsigned int attr;
rpm-build c487f7
  unsigned int form;
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
struct abbrev_tag
rpm-build c487f7
{
rpm-build c487f7
  unsigned int       tag;
rpm-build c487f7
  int                nattr;
rpm-build c487f7
  struct abbrev_attr attr[0];
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
static GHashTable *
rpm-build c487f7
read_abbrev (DebuginfoData *data, unsigned char *ptr)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *h;
rpm-build c487f7
  unsigned int attr, entry, form;
rpm-build c487f7
  struct abbrev_tag *t;
rpm-build c487f7
  int size;
rpm-build c487f7
rpm-build c487f7
  h = g_hash_table_new_full (g_direct_hash, g_direct_equal,
rpm-build c487f7
                             NULL, g_free);
rpm-build c487f7
rpm-build c487f7
  while ((attr = read_uleb128 (ptr)) != 0)
rpm-build c487f7
    {
rpm-build c487f7
      size = 10;
rpm-build c487f7
      entry = attr;
rpm-build c487f7
      t = g_malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
rpm-build c487f7
      t->tag = read_uleb128 (ptr);
rpm-build c487f7
      t->nattr = 0;
rpm-build c487f7
      ++ptr; /* skip children flag.  */
rpm-build c487f7
      while ((attr = read_uleb128 (ptr)) != 0)
rpm-build c487f7
        {
rpm-build c487f7
          if (t->nattr == size)
rpm-build c487f7
            {
rpm-build c487f7
              size += 10;
rpm-build c487f7
              t = g_realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
rpm-build c487f7
            }
rpm-build c487f7
          form = read_uleb128 (ptr);
rpm-build c487f7
          if (form == 2 || (form > DW_FORM_flag_present && form != DW_FORM_ref_sig8))
rpm-build c487f7
            g_warning ("%s: Unknown DWARF DW_FORM_%d", data->filename, form);
rpm-build c487f7
rpm-build c487f7
          t->attr[t->nattr].attr = attr;
rpm-build c487f7
          t->attr[t->nattr++].form = form;
rpm-build c487f7
        }
rpm-build c487f7
      if (read_uleb128 (ptr) != 0)
rpm-build c487f7
        g_warning ("%s: DWARF abbreviation does not end with 2 zeros", data->filename);
rpm-build c487f7
      g_hash_table_insert (h, GINT_TO_POINTER (entry), t);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return h;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#define IS_DIR_SEPARATOR(c) ((c) == '/')
rpm-build c487f7
rpm-build c487f7
static char *
rpm-build c487f7
canonicalize_path (const char *s, char *d)
rpm-build c487f7
{
rpm-build c487f7
  char *rv = d;
rpm-build c487f7
  char *droot;
rpm-build c487f7
rpm-build c487f7
  if (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
    {
rpm-build c487f7
      *d++ = *s++;
rpm-build c487f7
      if (IS_DIR_SEPARATOR (*s) && !IS_DIR_SEPARATOR (s[1]))
rpm-build c487f7
        /* Special case for "//foo" meaning a Posix namespace  escape.  */
rpm-build c487f7
        *d++ = *s++;
rpm-build c487f7
      while (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
        s++;
rpm-build c487f7
    }
rpm-build c487f7
  droot = d;
rpm-build c487f7
rpm-build c487f7
  while (*s)
rpm-build c487f7
    {
rpm-build c487f7
      /* At this point, we're always at the beginning of a path segment.  */
rpm-build c487f7
rpm-build c487f7
      if (s[0] == '.' && (s[1] == 0 || IS_DIR_SEPARATOR (s[1])))
rpm-build c487f7
        {
rpm-build c487f7
          s++;
rpm-build c487f7
          if (*s)
rpm-build c487f7
            while (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
              ++s;
rpm-build c487f7
        }
rpm-build c487f7
      else if (s[0] == '.' && s[1] == '.' &&
rpm-build c487f7
               (s[2] == 0 || IS_DIR_SEPARATOR (s[2])))
rpm-build c487f7
        {
rpm-build c487f7
          char *pre = d - 1; /* includes slash */
rpm-build c487f7
          while (droot < pre && IS_DIR_SEPARATOR (*pre))
rpm-build c487f7
            pre--;
rpm-build c487f7
          if (droot <= pre && !IS_DIR_SEPARATOR (*pre))
rpm-build c487f7
            {
rpm-build c487f7
              while (droot < pre && !IS_DIR_SEPARATOR (*pre))
rpm-build c487f7
                pre--;
rpm-build c487f7
              /* pre now points to the slash */
rpm-build c487f7
              if (droot < pre)
rpm-build c487f7
                pre++;
rpm-build c487f7
              if (pre + 3 == d && pre[0] == '.' && pre[1] == '.')
rpm-build c487f7
                {
rpm-build c487f7
                  *d++ = *s++;
rpm-build c487f7
                  *d++ = *s++;
rpm-build c487f7
                }
rpm-build c487f7
              else
rpm-build c487f7
                {
rpm-build c487f7
                  d = pre;
rpm-build c487f7
                  s += 2;
rpm-build c487f7
                  if (*s)
rpm-build c487f7
                    while (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
                      s++;
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
          else
rpm-build c487f7
            {
rpm-build c487f7
              *d++ = *s++;
rpm-build c487f7
              *d++ = *s++;
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          while (*s && !IS_DIR_SEPARATOR (*s))
rpm-build c487f7
            *d++ = *s++;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      if (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
        {
rpm-build c487f7
          *d++ = *s++;
rpm-build c487f7
          while (IS_DIR_SEPARATOR (*s))
rpm-build c487f7
            s++;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
  while (droot < d && IS_DIR_SEPARATOR (d[-1]))
rpm-build c487f7
    --d;
rpm-build c487f7
  if (d == rv)
rpm-build c487f7
    *d++ = '.';
rpm-build c487f7
  *d = 0;
rpm-build c487f7
rpm-build c487f7
  return rv;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
handle_dwarf2_line (DebuginfoData *data, uint32_t off, char *comp_dir, GHashTable *files, GError **error)
rpm-build c487f7
{
rpm-build c487f7
  unsigned char *ptr = data->debug_sections[DEBUG_LINE].data, *dir;
rpm-build c487f7
  unsigned char **dirt;
rpm-build c487f7
  unsigned char *endsec = ptr + data->debug_sections[DEBUG_LINE].size;
rpm-build c487f7
  unsigned char *endcu, *endprol;
rpm-build c487f7
  unsigned char opcode_base;
rpm-build c487f7
  uint32_t value, dirt_cnt;
rpm-build c487f7
  size_t comp_dir_len = !comp_dir ? 0 : strlen (comp_dir);
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
  /* XXX: RhBug:929365, should we error out instead of ignoring? */
rpm-build c487f7
  if (ptr == NULL)
rpm-build c487f7
    return TRUE;
rpm-build c487f7
rpm-build c487f7
  ptr += off;
rpm-build c487f7
rpm-build c487f7
  endcu = ptr + 4;
rpm-build c487f7
  endcu += read_32 (ptr);
rpm-build c487f7
  if (endcu == ptr + 0xffffffff)
rpm-build c487f7
    return flatpak_fail (error, "%s: 64-bit DWARF not supported", data->filename);
rpm-build c487f7
rpm-build c487f7
  if (endcu > endsec)
rpm-build c487f7
    return flatpak_fail (error, "%s: .debug_line CU does not fit into section", data->filename);
rpm-build c487f7
rpm-build c487f7
  value = read_16 (ptr);
rpm-build c487f7
  if (value != 2 && value != 3 && value != 4)
rpm-build c487f7
    return flatpak_fail (error, "%s: DWARF version %d unhandled", data->filename, value);
rpm-build c487f7
rpm-build c487f7
  endprol = ptr + 4;
rpm-build c487f7
  endprol += read_32 (ptr);
rpm-build c487f7
  if (endprol > endcu)
rpm-build c487f7
    return flatpak_fail (error, "%s: .debug_line CU prologue does not fit into CU", data->filename);
rpm-build c487f7
rpm-build c487f7
  opcode_base = ptr[4 + (value >= 4)];
rpm-build c487f7
  ptr = dir = ptr + 4 + (value >= 4) + opcode_base;
rpm-build c487f7
rpm-build c487f7
  /* dir table: */
rpm-build c487f7
  value = 1;
rpm-build c487f7
  while (*ptr != 0)
rpm-build c487f7
    {
rpm-build c487f7
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
rpm-build c487f7
      ++value;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  dirt = (unsigned char **) alloca (value * sizeof (unsigned char *));
rpm-build c487f7
  dirt[0] = (unsigned char *) ".";
rpm-build c487f7
  dirt_cnt = 1;
rpm-build c487f7
  ptr = dir;
rpm-build c487f7
  while (*ptr != 0)
rpm-build c487f7
    {
rpm-build c487f7
      dirt[dirt_cnt++] = ptr;
rpm-build c487f7
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
rpm-build c487f7
    }
rpm-build c487f7
  ptr++;
rpm-build c487f7
rpm-build c487f7
  /* file table: */
rpm-build c487f7
  while (*ptr != 0)
rpm-build c487f7
    {
rpm-build c487f7
      char *s, *file;
rpm-build c487f7
      size_t file_len, dir_len;
rpm-build c487f7
rpm-build c487f7
      file = (char *) ptr;
rpm-build c487f7
      ptr = (unsigned char *) strchr ((char *) ptr, 0) + 1;
rpm-build c487f7
      value = read_uleb128 (ptr);
rpm-build c487f7
rpm-build c487f7
      if (value >= dirt_cnt)
rpm-build c487f7
        return flatpak_fail (error, "%s: Wrong directory table index %u",  data->filename, value);
rpm-build c487f7
rpm-build c487f7
      file_len = strlen (file);
rpm-build c487f7
      dir_len = strlen ((char *) dirt[value]);
rpm-build c487f7
      s = g_malloc (comp_dir_len + 1 + file_len + 1 + dir_len + 1);
rpm-build c487f7
      if (*file == '/')
rpm-build c487f7
        {
rpm-build c487f7
          memcpy (s, file, file_len + 1);
rpm-build c487f7
        }
rpm-build c487f7
      else if (*dirt[value] == '/')
rpm-build c487f7
        {
rpm-build c487f7
          memcpy (s, dirt[value], dir_len);
rpm-build c487f7
          s[dir_len] = '/';
rpm-build c487f7
          memcpy (s + dir_len + 1, file, file_len + 1);
rpm-build c487f7
        }
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          char *p = s;
rpm-build c487f7
          if (comp_dir_len != 0)
rpm-build c487f7
            {
rpm-build c487f7
              memcpy (s, comp_dir, comp_dir_len);
rpm-build c487f7
              s[comp_dir_len] = '/';
rpm-build c487f7
              p += comp_dir_len + 1;
rpm-build c487f7
            }
rpm-build c487f7
          memcpy (p, dirt[value], dir_len);
rpm-build c487f7
          p[dir_len] = '/';
rpm-build c487f7
          memcpy (p + dir_len + 1, file, file_len + 1);
rpm-build c487f7
        }
rpm-build c487f7
      canonicalize_path (s, s);
rpm-build c487f7
rpm-build c487f7
      g_hash_table_insert (files, s, NULL);
rpm-build c487f7
rpm-build c487f7
      (void) read_uleb128 (ptr);
rpm-build c487f7
      (void) read_uleb128 (ptr);
rpm-build c487f7
    }
rpm-build c487f7
  ++ptr;
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static unsigned char *
rpm-build c487f7
handle_attributes (DebuginfoData *data, unsigned char *ptr, struct abbrev_tag *t, GHashTable *files, GError **error)
rpm-build c487f7
{
rpm-build c487f7
  int i;
rpm-build c487f7
  uint32_t list_offs;
rpm-build c487f7
  int found_list_offs;
rpm-build c487f7
  g_autofree char *comp_dir = NULL;
rpm-build c487f7
rpm-build c487f7
  comp_dir = NULL;
rpm-build c487f7
  list_offs = 0;
rpm-build c487f7
  found_list_offs = 0;
rpm-build c487f7
  for (i = 0; i < t->nattr; ++i)
rpm-build c487f7
    {
rpm-build c487f7
      uint32_t form = t->attr[i].form;
rpm-build c487f7
      size_t len = 0;
rpm-build c487f7
rpm-build c487f7
      while (1)
rpm-build c487f7
        {
rpm-build c487f7
          if (t->attr[i].attr == DW_AT_stmt_list)
rpm-build c487f7
            {
rpm-build c487f7
              if (form == DW_FORM_data4 ||
rpm-build c487f7
                  form == DW_FORM_sec_offset)
rpm-build c487f7
                {
rpm-build c487f7
                  list_offs = do_read_32_relocated (ptr);
rpm-build c487f7
                  found_list_offs = 1;
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          if (t->attr[i].attr == DW_AT_comp_dir)
rpm-build c487f7
            {
rpm-build c487f7
              if (form == DW_FORM_string)
rpm-build c487f7
                {
rpm-build c487f7
                  g_free (comp_dir);
rpm-build c487f7
                  comp_dir = g_strdup ((char *) ptr);
rpm-build c487f7
                }
rpm-build c487f7
              else if (form == DW_FORM_strp &&
rpm-build c487f7
                       data->debug_sections[DEBUG_STR].data)
rpm-build c487f7
                {
rpm-build c487f7
                  char *dir;
rpm-build c487f7
rpm-build c487f7
                  dir = (char *) data->debug_sections[DEBUG_STR].data
rpm-build c487f7
                        + do_read_32_relocated (ptr);
rpm-build c487f7
rpm-build c487f7
                  g_free (comp_dir);
rpm-build c487f7
                  comp_dir = g_strdup (dir);
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
          else if ((t->tag == DW_TAG_compile_unit ||
rpm-build c487f7
                    t->tag == DW_TAG_partial_unit) &&
rpm-build c487f7
                   t->attr[i].attr == DW_AT_name &&
rpm-build c487f7
                   form == DW_FORM_strp &&
rpm-build c487f7
                   data->debug_sections[DEBUG_STR].data)
rpm-build c487f7
            {
rpm-build c487f7
              char *name;
rpm-build c487f7
rpm-build c487f7
              name = (char *) data->debug_sections[DEBUG_STR].data
rpm-build c487f7
                     + do_read_32_relocated (ptr);
rpm-build c487f7
              if (*name == '/' && comp_dir == NULL)
rpm-build c487f7
                {
rpm-build c487f7
                  char *enddir = strrchr (name, '/');
rpm-build c487f7
rpm-build c487f7
                  if (enddir != name)
rpm-build c487f7
                    {
rpm-build c487f7
                      comp_dir = g_malloc (enddir - name + 1);
rpm-build c487f7
                      memcpy (comp_dir, name, enddir - name);
rpm-build c487f7
                      comp_dir[enddir - name] = '\0';
rpm-build c487f7
                    }
rpm-build c487f7
                  else
rpm-build c487f7
                    {
rpm-build c487f7
                      comp_dir = g_strdup ("/");
rpm-build c487f7
                    }
rpm-build c487f7
                }
rpm-build c487f7
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          switch (form)
rpm-build c487f7
            {
rpm-build c487f7
            case DW_FORM_ref_addr:
rpm-build c487f7
              if (cu_version == 2)
rpm-build c487f7
                ptr += ptr_size;
rpm-build c487f7
              else
rpm-build c487f7
                ptr += 4;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_flag_present:
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_addr:
rpm-build c487f7
              ptr += ptr_size;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_ref1:
rpm-build c487f7
            case DW_FORM_flag:
rpm-build c487f7
            case DW_FORM_data1:
rpm-build c487f7
              ++ptr;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_ref2:
rpm-build c487f7
            case DW_FORM_data2:
rpm-build c487f7
              ptr += 2;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_ref4:
rpm-build c487f7
            case DW_FORM_data4:
rpm-build c487f7
            case DW_FORM_sec_offset:
rpm-build c487f7
              ptr += 4;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_ref8:
rpm-build c487f7
            case DW_FORM_data8:
rpm-build c487f7
            case DW_FORM_ref_sig8:
rpm-build c487f7
              ptr += 8;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_sdata:
rpm-build c487f7
            case DW_FORM_ref_udata:
rpm-build c487f7
            case DW_FORM_udata:
rpm-build c487f7
              (void) read_uleb128 (ptr);
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_strp:
rpm-build c487f7
              ptr += 4;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_string:
rpm-build c487f7
              ptr = (unsigned char *) strchr ((char *) ptr, '\0') + 1;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_indirect:
rpm-build c487f7
              form = read_uleb128 (ptr);
rpm-build c487f7
              continue;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_block1:
rpm-build c487f7
              len = *ptr++;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_block2:
rpm-build c487f7
              len = read_16 (ptr);
rpm-build c487f7
              form = DW_FORM_block1;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_block4:
rpm-build c487f7
              len = read_32 (ptr);
rpm-build c487f7
              form = DW_FORM_block1;
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            case DW_FORM_block:
rpm-build c487f7
            case DW_FORM_exprloc:
rpm-build c487f7
              len = read_uleb128 (ptr);
rpm-build c487f7
              form = DW_FORM_block1;
rpm-build c487f7
              g_assert (len < UINT_MAX);
rpm-build c487f7
              break;
rpm-build c487f7
rpm-build c487f7
            default:
rpm-build c487f7
              g_warning ("%s: Unknown DWARF DW_FORM_%d", data->filename, form);
rpm-build c487f7
              return NULL;
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          if (form == DW_FORM_block1)
rpm-build c487f7
            ptr += len;
rpm-build c487f7
rpm-build c487f7
          break;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  /* Ensure the CU current directory will exist even if only empty.  Source
rpm-build c487f7
     filenames possibly located in its parent directories refer relatively to
rpm-build c487f7
     it and the debugger (GDB) cannot safely optimize out the missing
rpm-build c487f7
     CU current dir subdirectories.  */
rpm-build c487f7
  if (comp_dir)
rpm-build c487f7
    g_hash_table_insert (files, g_strdup (comp_dir), NULL);
rpm-build c487f7
rpm-build c487f7
  if (found_list_offs &&
rpm-build c487f7
      !handle_dwarf2_line (data, list_offs, comp_dir, files, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return ptr;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static int
rpm-build c487f7
rel_cmp (const void *a, const void *b)
rpm-build c487f7
{
rpm-build c487f7
  REL *rela = (REL *) a, *relb = (REL *) b;
rpm-build c487f7
rpm-build c487f7
  if (rela->ptr < relb->ptr)
rpm-build c487f7
    return -1;
rpm-build c487f7
rpm-build c487f7
  if (rela->ptr > relb->ptr)
rpm-build c487f7
    return 1;
rpm-build c487f7
rpm-build c487f7
  return 0;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
handle_dwarf2_section (DebuginfoData *data, GHashTable *files, GError **error)
rpm-build c487f7
{
rpm-build c487f7
  Elf_Data *e_data;
rpm-build c487f7
  int i;
rpm-build c487f7
  debug_section_t *debug_sections;
rpm-build c487f7
rpm-build c487f7
  ptr_size = 0;
rpm-build c487f7
rpm-build c487f7
  if (data->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
rpm-build c487f7
    {
rpm-build c487f7
      do_read_16 = buf_read_ule16;
rpm-build c487f7
      do_read_32 = buf_read_ule32;
rpm-build c487f7
    }
rpm-build c487f7
  else if (data->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
rpm-build c487f7
    {
rpm-build c487f7
      do_read_16 = buf_read_ube16;
rpm-build c487f7
      do_read_32 = buf_read_ube32;
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      return flatpak_fail (error, "%s: Wrong ELF data encoding", data->filename);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  debug_sections = data->debug_sections;
rpm-build c487f7
rpm-build c487f7
  if (debug_sections[DEBUG_INFO].data != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      unsigned char *ptr, *endcu, *endsec;
rpm-build c487f7
      uint32_t value;
rpm-build c487f7
      struct abbrev_tag *t;
rpm-build c487f7
      g_autofree REL *relbuf = NULL;
rpm-build c487f7
rpm-build c487f7
      if (debug_sections[DEBUG_INFO].relsec)
rpm-build c487f7
        {
rpm-build c487f7
          Elf_Scn *scn;
rpm-build c487f7
          int ndx, maxndx;
rpm-build c487f7
          GElf_Rel rel;
rpm-build c487f7
          GElf_Rela rela;
rpm-build c487f7
          GElf_Sym sym;
rpm-build c487f7
          GElf_Addr base = data->shdr[debug_sections[DEBUG_INFO].sec].sh_addr;
rpm-build c487f7
          Elf_Data *symdata = NULL;
rpm-build c487f7
          int rtype;
rpm-build c487f7
rpm-build c487f7
          i = debug_sections[DEBUG_INFO].relsec;
rpm-build c487f7
          scn = data->scns[i];
rpm-build c487f7
          e_data = elf_getdata (scn, NULL);
rpm-build c487f7
          g_assert (e_data != NULL && e_data->d_buf != NULL);
rpm-build c487f7
          g_assert (elf_getdata (scn, e_data) == NULL);
rpm-build c487f7
          g_assert (e_data->d_off == 0);
rpm-build c487f7
          g_assert (e_data->d_size == data->shdr[i].sh_size);
rpm-build c487f7
          maxndx = data->shdr[i].sh_size / data->shdr[i].sh_entsize;
rpm-build c487f7
          relbuf = g_malloc (maxndx * sizeof (REL));
rpm-build c487f7
          reltype = data->shdr[i].sh_type;
rpm-build c487f7
rpm-build c487f7
          symdata = elf_getdata (data->scns[data->shdr[i].sh_link], NULL);
rpm-build c487f7
          g_assert (symdata != NULL && symdata->d_buf != NULL);
rpm-build c487f7
          g_assert (elf_getdata (data->scns[data->shdr[i].sh_link], symdata) == NULL);
rpm-build c487f7
          g_assert (symdata->d_off == 0);
rpm-build c487f7
          g_assert (symdata->d_size == data->shdr[data->shdr[i].sh_link].sh_size);
rpm-build c487f7
rpm-build c487f7
          for (ndx = 0, relend = relbuf; ndx < maxndx; ++ndx)
rpm-build c487f7
            {
rpm-build c487f7
              if (data->shdr[i].sh_type == SHT_REL)
rpm-build c487f7
                {
rpm-build c487f7
                  gelf_getrel (e_data, ndx, &rel;;
rpm-build c487f7
                  rela.r_offset = rel.r_offset;
rpm-build c487f7
                  rela.r_info = rel.r_info;
rpm-build c487f7
                  rela.r_addend = 0;
rpm-build c487f7
                }
rpm-build c487f7
              else
rpm-build c487f7
                {
rpm-build c487f7
                  gelf_getrela (e_data, ndx, &rela);
rpm-build c487f7
                }
rpm-build c487f7
              gelf_getsym (symdata, ELF64_R_SYM (rela.r_info), &sym);
rpm-build c487f7
              /* Relocations against section symbols are uninteresting
rpm-build c487f7
                 in REL.  */
rpm-build c487f7
              if (data->shdr[i].sh_type == SHT_REL && sym.st_value == 0)
rpm-build c487f7
                continue;
rpm-build c487f7
              /* Only consider relocations against .debug_str, .debug_line
rpm-build c487f7
                 and .debug_abbrev.  */
rpm-build c487f7
              if (sym.st_shndx != debug_sections[DEBUG_STR].sec &&
rpm-build c487f7
                  sym.st_shndx != debug_sections[DEBUG_LINE].sec &&
rpm-build c487f7
                  sym.st_shndx != debug_sections[DEBUG_ABBREV].sec)
rpm-build c487f7
                continue;
rpm-build c487f7
              rela.r_addend += sym.st_value;
rpm-build c487f7
              rtype = ELF64_R_TYPE (rela.r_info);
rpm-build c487f7
              switch (data->ehdr.e_machine)
rpm-build c487f7
                {
rpm-build c487f7
                case EM_SPARC:
rpm-build c487f7
                case EM_SPARC32PLUS:
rpm-build c487f7
                case EM_SPARCV9:
rpm-build c487f7
                  if (rtype != R_SPARC_32 && rtype != R_SPARC_UA32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_386:
rpm-build c487f7
                  if (rtype != R_386_32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_PPC:
rpm-build c487f7
                case EM_PPC64:
rpm-build c487f7
                  if (rtype != R_PPC_ADDR32 && rtype != R_PPC_UADDR32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_S390:
rpm-build c487f7
                  if (rtype != R_390_32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_IA_64:
rpm-build c487f7
                  if (rtype != R_IA64_SECREL32LSB)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_X86_64:
rpm-build c487f7
                  if (rtype != R_X86_64_32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                case EM_ALPHA:
rpm-build c487f7
                  if (rtype != R_ALPHA_REFLONG)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
#if defined(EM_AARCH64) && defined(R_AARCH64_ABS32)
rpm-build c487f7
                case EM_AARCH64:
rpm-build c487f7
                  if (rtype != R_AARCH64_ABS32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
#endif
rpm-build c487f7
                case EM_68K:
rpm-build c487f7
                  if (rtype != R_68K_32)
rpm-build c487f7
                    goto fail;
rpm-build c487f7
                  break;
rpm-build c487f7
rpm-build c487f7
                default:
rpm-build c487f7
fail:
rpm-build c487f7
                  return flatpak_fail (error, "%s: Unhandled relocation %d in .debug_info section",
rpm-build c487f7
                                       data->filename, rtype);
rpm-build c487f7
                }
rpm-build c487f7
              relend->ptr = debug_sections[DEBUG_INFO].data
rpm-build c487f7
                            + (rela.r_offset - base);
rpm-build c487f7
              relend->addend = rela.r_addend;
rpm-build c487f7
              ++relend;
rpm-build c487f7
            }
rpm-build c487f7
          if (relbuf == relend)
rpm-build c487f7
            {
rpm-build c487f7
              g_free (relbuf);
rpm-build c487f7
              relbuf = NULL;
rpm-build c487f7
              relend = NULL;
rpm-build c487f7
            }
rpm-build c487f7
          else
rpm-build c487f7
            {
rpm-build c487f7
              qsort (relbuf, relend - relbuf, sizeof (REL), rel_cmp);
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      ptr = debug_sections[DEBUG_INFO].data;
rpm-build c487f7
      relptr = relbuf;
rpm-build c487f7
      endsec = ptr + debug_sections[DEBUG_INFO].size;
rpm-build c487f7
      while (ptr != NULL && ptr < endsec)
rpm-build c487f7
        {
rpm-build c487f7
          g_autoptr(GHashTable) abbrev = NULL;
rpm-build c487f7
rpm-build c487f7
          if (ptr + 11 > endsec)
rpm-build c487f7
            return flatpak_fail (error, "%s: .debug_info CU header too small", data->filename);
rpm-build c487f7
rpm-build c487f7
          endcu = ptr + 4;
rpm-build c487f7
          endcu += read_32 (ptr);
rpm-build c487f7
          if (endcu == ptr + 0xffffffff)
rpm-build c487f7
            return flatpak_fail (error, "%s: 64-bit DWARF not supported", data->filename);
rpm-build c487f7
rpm-build c487f7
          if (endcu > endsec)
rpm-build c487f7
            return flatpak_fail (error, "%s: .debug_info too small", data->filename);
rpm-build c487f7
rpm-build c487f7
          cu_version = read_16 (ptr);
rpm-build c487f7
          if (cu_version != 2 && cu_version != 3 && cu_version != 4)
rpm-build c487f7
            return flatpak_fail (error, "%s: DWARF version %d unhandled", data->filename, cu_version);
rpm-build c487f7
rpm-build c487f7
          value = read_32_relocated (ptr);
rpm-build c487f7
          if (value >= debug_sections[DEBUG_ABBREV].size)
rpm-build c487f7
            {
rpm-build c487f7
              if (debug_sections[DEBUG_ABBREV].data == NULL)
rpm-build c487f7
                return flatpak_fail (error, "%s: .debug_abbrev not present", data->filename);
rpm-build c487f7
              else
rpm-build c487f7
                return flatpak_fail (error, "%s: DWARF CU abbrev offset too large", data->filename);
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          if (ptr_size == 0)
rpm-build c487f7
            {
rpm-build c487f7
              ptr_size = read_1 (ptr);
rpm-build c487f7
              if (ptr_size != 4 && ptr_size != 8)
rpm-build c487f7
                return flatpak_fail (error, "%s: Invalid DWARF pointer size %d", data->filename, ptr_size);
rpm-build c487f7
            }
rpm-build c487f7
          else if (read_1 (ptr) != ptr_size)
rpm-build c487f7
            {
rpm-build c487f7
              return flatpak_fail (error, "%s: DWARF pointer size differs between CUs", data->filename);
rpm-build c487f7
            }
rpm-build c487f7
rpm-build c487f7
          abbrev = read_abbrev (data,
rpm-build c487f7
                                debug_sections[DEBUG_ABBREV].data + value);
rpm-build c487f7
rpm-build c487f7
          while (ptr < endcu)
rpm-build c487f7
            {
rpm-build c487f7
              guint entry = read_uleb128 (ptr);
rpm-build c487f7
              if (entry == 0)
rpm-build c487f7
                continue;
rpm-build c487f7
              t = g_hash_table_lookup (abbrev, GINT_TO_POINTER (entry));
rpm-build c487f7
              if (t == NULL)
rpm-build c487f7
                {
rpm-build c487f7
                  g_warning ("%s: Could not find DWARF abbreviation %d", data->filename, entry);
rpm-build c487f7
                }
rpm-build c487f7
              else
rpm-build c487f7
                {
rpm-build c487f7
                  ptr = handle_attributes (data, ptr, t, files, error);
rpm-build c487f7
                  if (ptr == NULL)
rpm-build c487f7
                    return FALSE;
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static const char *
rpm-build c487f7
strptr (Elf_Scn **scns, GElf_Shdr *shdr, int sec, off_t offset)
rpm-build c487f7
{
rpm-build c487f7
  Elf_Scn *scn;
rpm-build c487f7
  Elf_Data *data;
rpm-build c487f7
rpm-build c487f7
  scn = scns[sec];
rpm-build c487f7
  if (offset >= 0 && (GElf_Addr) offset < shdr[sec].sh_size)
rpm-build c487f7
    {
rpm-build c487f7
      data = NULL;
rpm-build c487f7
      while ((data = elf_rawdata (scn, data)) != NULL)
rpm-build c487f7
        {
rpm-build c487f7
          if (data->d_buf &&
rpm-build c487f7
              offset >= data->d_off &&
rpm-build c487f7
              offset < data->d_off + data->d_size)
rpm-build c487f7
            return (const char *) data->d_buf + (offset - data->d_off);
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return NULL;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
char **
rpm-build c487f7
builder_get_debuginfo_file_references (const char *filename, GError **error)
rpm-build c487f7
{
rpm-build c487f7
  Elf *elf = NULL;
rpm-build c487f7
  GElf_Ehdr ehdr;
rpm-build c487f7
  int i, j;
rpm-build c487f7
  glnx_fd_close int fd = -1;
rpm-build c487f7
  DebuginfoData data = { 0 };
rpm-build c487f7
  g_autofree GElf_Shdr *shdr = NULL;
rpm-build c487f7
  g_autofree Elf_Scn **scns = NULL;
rpm-build c487f7
  debug_section_t *debug_sections;
rpm-build c487f7
rpm-build c487f7
  g_autoptr(GHashTable) files = NULL;
rpm-build c487f7
  char **res;
rpm-build c487f7
rpm-build c487f7
  fd = open (filename, O_RDONLY);
rpm-build c487f7
  if (fd == -1)
rpm-build c487f7
    {
rpm-build c487f7
      glnx_set_error_from_errno (error);
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  elf = elf_begin (fd, ELF_C_RDWR_MMAP, NULL);
rpm-build c487f7
  if (elf == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      flatpak_fail (error, "cannot open ELF file: %s", elf_errmsg (-1));
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (elf_kind (elf) != ELF_K_ELF)
rpm-build c487f7
    {
rpm-build c487f7
      flatpak_fail (error, "\"%s\" is not an ELF file", filename);
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (gelf_getehdr (elf, &ehdr) == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      flatpak_fail (error, "cannot get the ELF header: %s", elf_errmsg (-1));
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC && ehdr.e_type != ET_REL)
rpm-build c487f7
    {
rpm-build c487f7
      flatpak_fail (error, "\"%s\" is not a shared library", filename);
rpm-build c487f7
      return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT);
rpm-build c487f7
rpm-build c487f7
  shdr = g_new0 (GElf_Shdr, ehdr.e_shnum);
rpm-build c487f7
  scns =  g_new0 (Elf_Scn *, ehdr.e_shnum);
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < ehdr.e_shnum; ++i)
rpm-build c487f7
    {
rpm-build c487f7
      scns[i] = elf_getscn (elf, i);
rpm-build c487f7
      gelf_getshdr (scns[i], &shdr[i]);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  data.elf = elf;
rpm-build c487f7
  data.ehdr = ehdr;
rpm-build c487f7
  data.shdr = shdr;
rpm-build c487f7
  data.scns = scns;
rpm-build c487f7
  data.filename = filename;
rpm-build c487f7
rpm-build c487f7
  /* Locate all debug sections */
rpm-build c487f7
  debug_sections = data.debug_sections;
rpm-build c487f7
  for (i = 1; i < ehdr.e_shnum; ++i)
rpm-build c487f7
    {
rpm-build c487f7
      if (!(shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) && shdr[i].sh_size)
rpm-build c487f7
        {
rpm-build c487f7
          const char *name = strptr (scns, shdr, ehdr.e_shstrndx, shdr[i].sh_name);
rpm-build c487f7
rpm-build c487f7
          if (g_str_has_prefix (name, ".debug_"))
rpm-build c487f7
            {
rpm-build c487f7
              for (j = 0; j < NUM_DEBUG_SECTIONS; ++j)
rpm-build c487f7
                {
rpm-build c487f7
                  if (strcmp (name, debug_section_names[j]) == 0)
rpm-build c487f7
                    {
rpm-build c487f7
                      Elf_Scn *scn = scns[i];
rpm-build c487f7
                      Elf_Data *e_data;
rpm-build c487f7
rpm-build c487f7
                      if (debug_sections[j].data)
rpm-build c487f7
                        g_warning ("%s: Found two copies of %s section", filename, name);
rpm-build c487f7
rpm-build c487f7
                      e_data = elf_rawdata (scn, NULL);
rpm-build c487f7
                      g_assert (e_data != NULL && e_data->d_buf != NULL);
rpm-build c487f7
                      g_assert (elf_rawdata (scn, e_data) == NULL);
rpm-build c487f7
                      g_assert (e_data->d_off == 0);
rpm-build c487f7
                      g_assert (e_data->d_size == shdr[i].sh_size);
rpm-build c487f7
                      debug_sections[j].data = e_data->d_buf;
rpm-build c487f7
                      debug_sections[j].elf_data = e_data;
rpm-build c487f7
                      debug_sections[j].size = e_data->d_size;
rpm-build c487f7
                      debug_sections[j].sec = i;
rpm-build c487f7
                      break;
rpm-build c487f7
                    }
rpm-build c487f7
                }
rpm-build c487f7
rpm-build c487f7
              if (j == NUM_DEBUG_SECTIONS)
rpm-build c487f7
                g_warning ("%s: Unknown debugging section %s", filename, name);
rpm-build c487f7
            }
rpm-build c487f7
          else if (ehdr.e_type == ET_REL &&
rpm-build c487f7
                   ((shdr[i].sh_type == SHT_REL && g_str_has_prefix (name, ".rel.debug_")) ||
rpm-build c487f7
                    (shdr[i].sh_type == SHT_RELA && g_str_has_prefix (name, ".rela.debug_"))))
rpm-build c487f7
            {
rpm-build c487f7
              for (j = 0; j < NUM_DEBUG_SECTIONS; ++j)
rpm-build c487f7
                if (strcmp (name + sizeof (".rel") - 1
rpm-build c487f7
                            + (shdr[i].sh_type == SHT_RELA),
rpm-build c487f7
                            debug_section_names[j]) == 0)
rpm-build c487f7
                  {
rpm-build c487f7
                    debug_sections[j].relsec = i;
rpm-build c487f7
                    break;
rpm-build c487f7
                  }
rpm-build c487f7
            }
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
rpm-build c487f7
  if (!handle_dwarf2_section (&data, files, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  if (elf_end (elf) < 0)
rpm-build c487f7
    g_warning ("elf_end failed: %s", elf_errmsg (elf_errno ()));
rpm-build c487f7
rpm-build c487f7
  res = (char **) g_hash_table_get_keys_as_array (files, NULL);
rpm-build c487f7
  g_hash_table_steal_all (files);
rpm-build c487f7
  return res;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
typedef struct {
rpm-build c487f7
  GDBusConnection *connection;
rpm-build c487f7
  GMainLoop *loop;
rpm-build c487f7
  GError    *splice_error;
rpm-build c487f7
  guint32 client_pid;
rpm-build c487f7
  guint32 exit_status;
rpm-build c487f7
  int refs;
rpm-build c487f7
} HostCommandCallData;
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
host_command_call_exit (HostCommandCallData *data)
rpm-build c487f7
{
rpm-build c487f7
  data->refs--;
rpm-build c487f7
  if (data->refs == 0)
rpm-build c487f7
    g_main_loop_quit (data->loop);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
output_spliced_cb (GObject      *obj,
rpm-build c487f7
                   GAsyncResult *result,
rpm-build c487f7
                   gpointer      user_data)
rpm-build c487f7
{
rpm-build c487f7
  HostCommandCallData *data = user_data;
rpm-build c487f7
rpm-build c487f7
  g_output_stream_splice_finish (G_OUTPUT_STREAM (obj), result, &data->splice_error);
rpm-build c487f7
  host_command_call_exit (data);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
host_command_exited_cb (GDBusConnection *connection,
rpm-build c487f7
                        const gchar     *sender_name,
rpm-build c487f7
                        const gchar     *object_path,
rpm-build c487f7
                        const gchar     *interface_name,
rpm-build c487f7
                        const gchar     *signal_name,
rpm-build c487f7
                        GVariant        *parameters,
rpm-build c487f7
                        gpointer         user_data)
rpm-build c487f7
{
rpm-build c487f7
  guint32 client_pid, exit_status;
rpm-build c487f7
  HostCommandCallData *data = (HostCommandCallData *)user_data;
rpm-build c487f7
rpm-build c487f7
  if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)")))
rpm-build c487f7
    return;
rpm-build c487f7
rpm-build c487f7
  g_variant_get (parameters, "(uu)", &client_pid, &exit_status);
rpm-build c487f7
rpm-build c487f7
  if (client_pid == data->client_pid)
rpm-build c487f7
    {
rpm-build c487f7
      g_debug ("host_command_exited_cb %d %d\n", client_pid, exit_status);
rpm-build c487f7
      data->exit_status = exit_status;
rpm-build c487f7
      host_command_call_exit (data);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
sigterm_handler (gpointer user_data)
rpm-build c487f7
{
rpm-build c487f7
  HostCommandCallData *data = (HostCommandCallData *)user_data;
rpm-build c487f7
rpm-build c487f7
  g_dbus_connection_call_sync (data->connection,
rpm-build c487f7
                               "org.freedesktop.Flatpak",
rpm-build c487f7
                               "/org/freedesktop/Flatpak/Development",
rpm-build c487f7
                               "org.freedesktop.Flatpak.Development",
rpm-build c487f7
                               "HostCommandSignal",
rpm-build c487f7
                               g_variant_new ("(uub)", data->client_pid, SIGTERM, TRUE),
rpm-build c487f7
                               NULL,
rpm-build c487f7
                               G_DBUS_CALL_FLAGS_NONE, -1,
rpm-build c487f7
                               NULL, NULL);
rpm-build c487f7
rpm-build c487f7
  kill (getpid (), SIGKILL);
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
sigint_handler (gpointer user_data)
rpm-build c487f7
{
rpm-build c487f7
  HostCommandCallData *data = (HostCommandCallData *)user_data;
rpm-build c487f7
rpm-build c487f7
  g_dbus_connection_call_sync (data->connection,
rpm-build c487f7
                               "org.freedesktop.Flatpak",
rpm-build c487f7
                               "/org/freedesktop/Flatpak/Development",
rpm-build c487f7
                               "org.freedesktop.Flatpak.Development",
rpm-build c487f7
                               "HostCommandSignal",
rpm-build c487f7
                               g_variant_new ("(uub)", data->client_pid, SIGINT, TRUE),
rpm-build c487f7
                               NULL,
rpm-build c487f7
                               G_DBUS_CALL_FLAGS_NONE, -1,
rpm-build c487f7
                               NULL, NULL);
rpm-build c487f7
rpm-build c487f7
  kill (getpid (), SIGKILL);
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_host_spawnv (GFile                *dir,
rpm-build c487f7
                     char                **output,
rpm-build c487f7
                     GSubprocessFlags      flags,
rpm-build c487f7
                     GError              **error,
rpm-build c487f7
                     const gchar * const  *argv)
rpm-build c487f7
{
rpm-build c487f7
  static FlatpakHostCommandFlags cmd_flags = FLATPAK_HOST_COMMAND_FLAGS_CLEAR_ENV | FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS;
rpm-build c487f7
  guint32 client_pid;
rpm-build c487f7
  GVariantBuilder *fd_builder = g_variant_builder_new (G_VARIANT_TYPE("a{uh}"));
rpm-build c487f7
  GVariantBuilder *env_builder = g_variant_builder_new (G_VARIANT_TYPE("a{ss}"));
rpm-build c487f7
  g_autoptr(GUnixFDList) fd_list = g_unix_fd_list_new ();
rpm-build c487f7
  gint stdout_handle, stdin_handle, stderr_handle = -1;
rpm-build c487f7
  g_autoptr(GDBusConnection) connection = NULL;
rpm-build c487f7
  g_autoptr(GVariant) ret = NULL;
rpm-build c487f7
  g_autoptr(GMainLoop) loop = NULL;
rpm-build c487f7
  g_auto(GStrv) env_vars = NULL;
rpm-build c487f7
  guint subscription;
rpm-build c487f7
  HostCommandCallData data = { NULL };
rpm-build c487f7
  guint sigterm_id = 0, sigint_id = 0;
rpm-build c487f7
  g_autofree gchar *commandline = NULL;
rpm-build c487f7
  g_autoptr(GOutputStream) out = NULL;
rpm-build c487f7
  g_autoptr(GFile) cwd = NULL;
rpm-build c487f7
  g_autoptr(GError) local_error = NULL;
rpm-build c487f7
  glnx_fd_close int blocking_stdin_fd = -1;
rpm-build c487f7
  int pipefd[2];
rpm-build c487f7
  int stdin_fd;
rpm-build c487f7
  int i;
rpm-build c487f7
rpm-build c487f7
  if (error == NULL)
rpm-build c487f7
    error = &local_error;
rpm-build c487f7
rpm-build c487f7
  if (dir == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      g_autofree char *current_dir = g_get_current_dir ();
rpm-build c487f7
      cwd = g_file_new_for_path (current_dir);
rpm-build c487f7
      dir = cwd;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  commandline = flatpak_quote_argv ((const char **) argv);
rpm-build c487f7
  g_debug ("Running '%s' on host", commandline);
rpm-build c487f7
rpm-build c487f7
  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
rpm-build c487f7
  if (connection == NULL)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  loop = g_main_loop_new (NULL, FALSE);
rpm-build c487f7
  data.connection = connection;
rpm-build c487f7
  data.loop = loop;
rpm-build c487f7
  data.refs = 1;
rpm-build c487f7
rpm-build c487f7
  subscription = g_dbus_connection_signal_subscribe (connection,
rpm-build c487f7
                                                     NULL,
rpm-build c487f7
                                                     "org.freedesktop.Flatpak.Development",
rpm-build c487f7
                                                     "HostCommandExited",
rpm-build c487f7
                                                     "/org/freedesktop/Flatpak/Development",
rpm-build c487f7
                                                     NULL,
rpm-build c487f7
                                                     G_DBUS_SIGNAL_FLAGS_NONE,
rpm-build c487f7
                                                     host_command_exited_cb,
rpm-build c487f7
                                                     &data, NULL);
rpm-build c487f7
rpm-build c487f7
  if ((flags & G_SUBPROCESS_FLAGS_STDIN_INHERIT) != 0)
rpm-build c487f7
    stdin_fd = 0;
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      blocking_stdin_fd = open ("/dev/null", O_RDONLY| O_CLOEXEC);
rpm-build c487f7
      if (blocking_stdin_fd == -1)
rpm-build c487f7
        {
rpm-build c487f7
          glnx_set_error_from_errno (error);
rpm-build c487f7
          return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
      stdin_fd = blocking_stdin_fd;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  stdin_handle = g_unix_fd_list_append (fd_list, stdin_fd, error);
rpm-build c487f7
  if (stdin_handle == -1)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (output)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GInputStream) in = NULL;
rpm-build c487f7
rpm-build c487f7
      if (pipe2 (pipefd, O_CLOEXEC) != 0)
rpm-build c487f7
        {
rpm-build c487f7
          glnx_set_error_from_errno (error);
rpm-build c487f7
          return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      data.refs++;
rpm-build c487f7
      in = g_unix_input_stream_new (pipefd[0], TRUE);
rpm-build c487f7
      out = g_memory_output_stream_new_resizable ();
rpm-build c487f7
      g_output_stream_splice_async (out,
rpm-build c487f7
                                    in,
rpm-build c487f7
                                    G_OUTPUT_STREAM_SPLICE_NONE,
rpm-build c487f7
                                    0,
rpm-build c487f7
                                    NULL,
rpm-build c487f7
                                    output_spliced_cb,
rpm-build c487f7
                                    &data);
rpm-build c487f7
      stdout_handle = g_unix_fd_list_append (fd_list, pipefd[1], error);
rpm-build c487f7
      close (pipefd[1]);
rpm-build c487f7
      if (stdout_handle == -1)
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      stdout_handle = g_unix_fd_list_append (fd_list, 1, error);
rpm-build c487f7
      if (stdout_handle == -1)
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_variant_builder_add (fd_builder, "{uh}", 0, stdin_handle);
rpm-build c487f7
  g_variant_builder_add (fd_builder, "{uh}", 1, stdout_handle);
rpm-build c487f7
rpm-build c487f7
  if ((flags & G_SUBPROCESS_FLAGS_STDERR_SILENCE) == 0)
rpm-build c487f7
    {
rpm-build c487f7
      stderr_handle = g_unix_fd_list_append (fd_list, 2, error);
rpm-build c487f7
      if (stderr_handle == -1)
rpm-build c487f7
        return FALSE;
rpm-build c487f7
      g_variant_builder_add (fd_builder, "{uh}", 2, stderr_handle);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  env_vars = g_listenv ();
rpm-build c487f7
  for (i = 0; env_vars[i] != NULL; i++)
rpm-build c487f7
    {
rpm-build c487f7
      const char *env_var = env_vars[i];
rpm-build c487f7
      if (strcmp (env_var, "LANGUAGE") != 0)
rpm-build c487f7
        g_variant_builder_add (env_builder, "{ss}", env_var, g_getenv (env_var));
rpm-build c487f7
    }
rpm-build c487f7
  g_variant_builder_add (env_builder, "{ss}", "LANGUAGE", "C");
rpm-build c487f7
rpm-build c487f7
  sigterm_id = g_unix_signal_add (SIGTERM, sigterm_handler, &data);
rpm-build c487f7
  sigint_id = g_unix_signal_add (SIGINT, sigint_handler, &data);
rpm-build c487f7
rpm-build c487f7
try_again:
rpm-build c487f7
  ret = g_dbus_connection_call_with_unix_fd_list_sync (connection,
rpm-build c487f7
                                                       "org.freedesktop.Flatpak",
rpm-build c487f7
                                                       "/org/freedesktop/Flatpak/Development",
rpm-build c487f7
                                                       "org.freedesktop.Flatpak.Development",
rpm-build c487f7
                                                       "HostCommand",
rpm-build c487f7
                                                       g_variant_new ("(^ay^aay@a{uh}@a{ss}u)",
rpm-build c487f7
                                                                      dir ? flatpak_file_get_path_cached (dir) : "",
rpm-build c487f7
                                                                      argv,
rpm-build c487f7
                                                                      g_variant_builder_end (fd_builder),
rpm-build c487f7
                                                                      g_variant_builder_end (env_builder),
rpm-build c487f7
                                                                      cmd_flags),
rpm-build c487f7
                                                       G_VARIANT_TYPE ("(u)"),
rpm-build c487f7
                                                       G_DBUS_CALL_FLAGS_NONE, -1,
rpm-build c487f7
                                                       fd_list, NULL,
rpm-build c487f7
                                                       NULL, error);
rpm-build c487f7
rpm-build c487f7
  if (ret == NULL)
rpm-build c487f7
    {
rpm-build c487f7
      /* If we are talking to a session-helper that is pre-1.2 we wont have
rpm-build c487f7
       * access to FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS and will get an
rpm-build c487f7
       * invalid-args reply. Try again without the flag.
rpm-build c487f7
       */
rpm-build c487f7
      if ((cmd_flags & FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS) != 0 &&
rpm-build c487f7
          g_error_matches (*error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS))
rpm-build c487f7
        {
rpm-build c487f7
          cmd_flags &= ~FLATPAK_HOST_COMMAND_FLAGS_WATCH_BUS;
rpm-build c487f7
          g_clear_error (error);
rpm-build c487f7
          goto try_again;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
  g_variant_get (ret, "(u)", &client_pid);
rpm-build c487f7
  data.client_pid = client_pid;
rpm-build c487f7
rpm-build c487f7
  /* Drop the FDList immediately or splice_async() may not
rpm-build c487f7
   * complete when the peer process exists, causing us to hang.
rpm-build c487f7
   */
rpm-build c487f7
  g_clear_object (&fd_list);
rpm-build c487f7
rpm-build c487f7
  g_main_loop_run (loop);
rpm-build c487f7
rpm-build c487f7
  g_source_remove (sigterm_id);
rpm-build c487f7
  g_source_remove (sigint_id);
rpm-build c487f7
  g_dbus_connection_signal_unsubscribe (connection, subscription);
rpm-build c487f7
rpm-build c487f7
  if (!g_spawn_check_exit_status (data.exit_status, error))
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (out)
rpm-build c487f7
    {
rpm-build c487f7
      if (data.splice_error)
rpm-build c487f7
        {
rpm-build c487f7
          g_propagate_error (error, data.splice_error);
rpm-build c487f7
          return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      /* Null terminate */
rpm-build c487f7
      g_output_stream_write (out, "\0", 1, NULL, NULL);
rpm-build c487f7
      g_output_stream_close (out, NULL, NULL);
rpm-build c487f7
      *output = g_memory_output_stream_steal_data (G_MEMORY_OUTPUT_STREAM (out));
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/* Similar to flatpak_spawnv, except uses the session helper HostCommand operation
rpm-build c487f7
   if in a sandbox */
rpm-build c487f7
gboolean
rpm-build c487f7
builder_maybe_host_spawnv (GFile                *dir,
rpm-build c487f7
                           char                **output,
rpm-build c487f7
                           GSubprocessFlags      flags,
rpm-build c487f7
                           GError              **error,
rpm-build c487f7
                           const gchar * const  *argv)
rpm-build c487f7
{
rpm-build c487f7
  if (flatpak_is_in_sandbox ())
rpm-build c487f7
    return builder_host_spawnv (dir, output, flags, error, argv);
rpm-build c487f7
rpm-build c487f7
  return flatpak_spawnv (dir, output, flags, error, argv);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
/**
rpm-build c487f7
 * builder_get_all_checksums:
rpm-build c487f7
 *
rpm-build c487f7
 * Collect all the non-empty/null checksums into a single array with
rpm-build c487f7
 * their type.
rpm-build c487f7
 *
rpm-build c487f7
 * The checksum are returned in order such that the first one is the
rpm-build c487f7
 * one to use by default if using a single one. That is typically the
rpm-build c487f7
 * longest checksum except it defaults to sha256 if set because
rpm-build c487f7
 * that was historically the one flatpak-builder used
rpm-build c487f7
 */
rpm-build c487f7
gsize
rpm-build c487f7
builder_get_all_checksums (const char *checksums[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                           GChecksumType checksums_type[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                           const char *md5,
rpm-build c487f7
                           const char *sha1,
rpm-build c487f7
                           const char *sha256,
rpm-build c487f7
                           const char *sha512)
rpm-build c487f7
{
rpm-build c487f7
  gsize i = 0;
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
  if (sha256 != NULL && *sha256 != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_assert (i < BUILDER_CHECKSUMS_LEN);
rpm-build c487f7
      checksums[i] = sha256;
rpm-build c487f7
      checksums_type[i] = G_CHECKSUM_SHA256;
rpm-build c487f7
      i++;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (sha512 != NULL && *sha512 != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_assert (i < BUILDER_CHECKSUMS_LEN);
rpm-build c487f7
      checksums[i] = sha512;
rpm-build c487f7
      checksums_type[i] = G_CHECKSUM_SHA512;
rpm-build c487f7
      i++;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (sha1 != NULL && *sha1 != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_assert (i < BUILDER_CHECKSUMS_LEN);
rpm-build c487f7
      checksums[i] = sha1;
rpm-build c487f7
      checksums_type[i] = G_CHECKSUM_SHA1;
rpm-build c487f7
      i++;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (md5 != NULL && *md5 != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_assert (i < BUILDER_CHECKSUMS_LEN);
rpm-build c487f7
      checksums[i] = md5;
rpm-build c487f7
      checksums_type[i] = G_CHECKSUM_MD5;
rpm-build c487f7
      i++;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_assert (i < BUILDER_CHECKSUMS_LEN);
rpm-build c487f7
  checksums[i++] = 0;
rpm-build c487f7
rpm-build c487f7
  return i;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
compare_checksum (const char *name,
rpm-build c487f7
                  const char *expected_checksum,
rpm-build c487f7
                  GChecksumType checksum_type,
rpm-build c487f7
                  const char *measured_checksum,
rpm-build c487f7
                  GError **error)
rpm-build c487f7
{
rpm-build c487f7
  const char *type_names[] = { "md5", "sha1", "sha256", "sha512", "sha384" }; /* In GChecksumType order */
rpm-build c487f7
  const char *type_name;
rpm-build c487f7
rpm-build c487f7
  if (checksum_type < G_N_ELEMENTS (type_names))
rpm-build c487f7
    type_name = type_names[checksum_type];
rpm-build c487f7
  else
rpm-build c487f7
    type_name = "unknown";
rpm-build c487f7
rpm-build c487f7
  if (strcmp (expected_checksum, measured_checksum) != 0)
rpm-build c487f7
    {
rpm-build c487f7
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
rpm-build c487f7
                   "Wrong %s checksum for %s, expected %s, was %s", type_name, name,
rpm-build c487f7
                   expected_checksum, measured_checksum);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
#define GET_BUFFER_SIZE 8192
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_verify_checksums (const char *name,
rpm-build c487f7
                          GFile *file,
rpm-build c487f7
                          const char *checksums[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                          GChecksumType checksums_type[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                          GError **error)
rpm-build c487f7
{
rpm-build c487f7
  gsize i;
rpm-build c487f7
rpm-build c487f7
  for (i = 0; checksums[i] != NULL; i++)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GFileInputStream) stream = NULL;
rpm-build c487f7
rpm-build c487f7
      stream = g_file_read (file, NULL, error);
rpm-build c487f7
rpm-build c487f7
      if (stream == NULL)
rpm-build c487f7
        return FALSE;
rpm-build c487f7
rpm-build c487f7
      gssize bytes_read;
rpm-build c487f7
      guchar buffer[GET_BUFFER_SIZE];
rpm-build c487f7
      GChecksum *checksum = NULL;
rpm-build c487f7
      const char *checksum_string = NULL;
rpm-build c487f7
      gboolean is_valid;
rpm-build c487f7
rpm-build c487f7
      checksum = g_checksum_new (checksums_type[i]);
rpm-build c487f7
rpm-build c487f7
      while ((bytes_read = g_input_stream_read (G_INPUT_STREAM(stream),
rpm-build c487f7
                                                buffer, GET_BUFFER_SIZE,
rpm-build c487f7
                                                NULL, error)) > 0)
rpm-build c487f7
        {
rpm-build c487f7
          g_checksum_update (checksum, buffer, bytes_read);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      if (bytes_read < 0)
rpm-build c487f7
        {
rpm-build c487f7
          is_valid = FALSE;
rpm-build c487f7
        }
rpm-build c487f7
      else
rpm-build c487f7
        {
rpm-build c487f7
          checksum_string = g_checksum_get_string (checksum);
rpm-build c487f7
          is_valid = compare_checksum (name, checksums[i], checksums_type[i],
rpm-build c487f7
                                       checksum_string, error);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      g_checksum_free (checksum);
rpm-build c487f7
rpm-build c487f7
      if (!is_valid)
rpm-build c487f7
        return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
typedef struct {
rpm-build c487f7
  GOutputStream  *out;
rpm-build c487f7
  GChecksum     **checksums;
rpm-build c487f7
  gsize           n_checksums;
rpm-build c487f7
  GError        **error;
rpm-build c487f7
} CURLWriteData;
rpm-build c487f7
rpm-build c487f7
static gsize
rpm-build c487f7
builder_curl_write_cb (gpointer *buffer,
rpm-build c487f7
                       gsize     size,
rpm-build c487f7
                       gsize     nmemb,
rpm-build c487f7
                       gpointer *userdata)
rpm-build c487f7
{
rpm-build c487f7
  gsize bytes_written;
rpm-build c487f7
  CURLWriteData *write_data = (CURLWriteData *) userdata;
rpm-build c487f7
rpm-build c487f7
  flatpak_write_update_checksum (write_data->out, buffer, size * nmemb, &bytes_written,
rpm-build c487f7
                                 write_data->checksums, write_data->n_checksums,
rpm-build c487f7
                                 NULL, write_data->error);
rpm-build c487f7
rpm-build c487f7
  return bytes_written;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static gboolean
rpm-build c487f7
builder_download_uri_curl (SoupURI        *uri,
rpm-build c487f7
                           CURL           *session,
rpm-build c487f7
                           GOutputStream  *out,
rpm-build c487f7
                           GChecksum     **checksums,
rpm-build c487f7
                           gsize           n_checksums,
rpm-build c487f7
                           GError        **error)
rpm-build c487f7
{
rpm-build c487f7
  CURLcode retcode;
rpm-build c487f7
  CURLWriteData write_data;
rpm-build c487f7
  static gchar error_buffer[CURL_ERROR_SIZE];
rpm-build c487f7
  g_autofree gchar *url = soup_uri_to_string (uri, FALSE);
rpm-build c487f7
rpm-build c487f7
  curl_easy_setopt (session, CURLOPT_URL, url);
rpm-build c487f7
  curl_easy_setopt (session, CURLOPT_WRITEFUNCTION, builder_curl_write_cb);
rpm-build c487f7
  curl_easy_setopt (session, CURLOPT_WRITEDATA, &write_data);
rpm-build c487f7
  curl_easy_setopt (session, CURLOPT_ERRORBUFFER, error_buffer);
rpm-build c487f7
rpm-build c487f7
  write_data.out = out;
rpm-build c487f7
  write_data.checksums = checksums;
rpm-build c487f7
  write_data.n_checksums = n_checksums;
rpm-build c487f7
  write_data.error = error;
rpm-build c487f7
rpm-build c487f7
  *error_buffer = '\0';
rpm-build c487f7
  retcode = curl_easy_perform (session);
rpm-build c487f7
rpm-build c487f7
  if (retcode != CURLE_OK)
rpm-build c487f7
    {
rpm-build c487f7
      g_set_error_literal (error, BUILDER_CURL_ERROR, retcode,
rpm-build c487f7
                           *error_buffer ? error_buffer : curl_easy_strerror (retcode));
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_download_uri (SoupURI        *uri,
rpm-build c487f7
                      GFile          *dest,
rpm-build c487f7
                      const char     *checksums[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                      GChecksumType   checksums_type[BUILDER_CHECKSUMS_LEN],
rpm-build c487f7
                      CURL           *curl_session,
rpm-build c487f7
                      GError        **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GFileOutputStream) out = NULL;
rpm-build c487f7
  g_autoptr(GFile) tmp = NULL;
rpm-build c487f7
  g_autoptr(GFile) dir = NULL;
rpm-build c487f7
  g_autoptr(GPtrArray) checksum_array = g_ptr_array_new_with_free_func ((GDestroyNotify)g_checksum_free);
rpm-build c487f7
  g_autofree char *basename = g_file_get_basename (dest);
rpm-build c487f7
  g_autofree char *template = g_strconcat (".", basename, "XXXXXX", NULL);
rpm-build c487f7
  gsize i;
rpm-build c487f7
rpm-build c487f7
  for (i = 0; checksums[i] != NULL; i++)
rpm-build c487f7
    g_ptr_array_add (checksum_array,
rpm-build c487f7
                     g_checksum_new (checksums_type[i]));
rpm-build c487f7
rpm-build c487f7
  dir = g_file_get_parent (dest);
rpm-build c487f7
  g_mkdir_with_parents (flatpak_file_get_path_cached (dir), 0755);
rpm-build c487f7
rpm-build c487f7
  tmp = flatpak_file_new_tmp_in (dir, template, error);
rpm-build c487f7
  if (tmp == NULL)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  out = g_file_replace (tmp, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
rpm-build c487f7
                        NULL, error);
rpm-build c487f7
  if (out == NULL)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
rpm-build c487f7
  if (!builder_download_uri_curl (uri,
rpm-build c487f7
                                  curl_session,
rpm-build c487f7
                                  G_OUTPUT_STREAM (out),
rpm-build c487f7
                                  (GChecksum **)checksum_array->pdata,
rpm-build c487f7
                                  checksum_array->len,
rpm-build c487f7
                                  error))
rpm-build c487f7
    {
rpm-build c487f7
      unlink (flatpak_file_get_path_cached (tmp));
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  /* Manually close to flush and detect write errors */
rpm-build c487f7
  if (!g_output_stream_close (G_OUTPUT_STREAM (out), NULL, error))
rpm-build c487f7
    {
rpm-build c487f7
      unlink (flatpak_file_get_path_cached (tmp));
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  for (i = 0; checksums[i] != NULL; i++)
rpm-build c487f7
    {
rpm-build c487f7
      const char *checksum = g_checksum_get_string (g_ptr_array_index (checksum_array, i));
rpm-build c487f7
      if (!compare_checksum (basename, checksums[i], checksums_type[i], checksum, error))
rpm-build c487f7
        {
rpm-build c487f7
          unlink (flatpak_file_get_path_cached (tmp));
rpm-build c487f7
          return FALSE;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (rename (flatpak_file_get_path_cached (tmp), flatpak_file_get_path_cached (dest)) != 0)
rpm-build c487f7
    {
rpm-build c487f7
      glnx_set_error_from_errno (error);
rpm-build c487f7
      return FALSE;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return TRUE;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
typedef struct {
rpm-build c487f7
  GParamSpec *pspec;
rpm-build c487f7
  JsonNode *data;
rpm-build c487f7
} BuilderXProperty;
rpm-build c487f7
rpm-build c487f7
static BuilderXProperty *
rpm-build c487f7
builder_x_property_new (const char *name)
rpm-build c487f7
{
rpm-build c487f7
  BuilderXProperty *property = g_new0 (BuilderXProperty, 1);
rpm-build c487f7
  property->pspec = g_param_spec_boxed (name, "", "", JSON_TYPE_NODE, G_PARAM_READWRITE | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB);
rpm-build c487f7
rpm-build c487f7
  return property;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
builder_x_property_free (BuilderXProperty *prop)
rpm-build c487f7
{
rpm-build c487f7
  g_param_spec_unref (prop->pspec);
rpm-build c487f7
  if (prop->data)
rpm-build c487f7
    json_node_unref (prop->data);
rpm-build c487f7
  g_free (prop);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static const char *
rpm-build c487f7
builder_x_property_get_name (BuilderXProperty *prop)
rpm-build c487f7
{
rpm-build c487f7
  return g_param_spec_get_name (prop->pspec);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GParamSpec *
rpm-build c487f7
builder_serializable_find_property (JsonSerializable *serializable,
rpm-build c487f7
                                    const char       *name)
rpm-build c487f7
{
rpm-build c487f7
  GParamSpec *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (serializable), name);
rpm-build c487f7
rpm-build c487f7
  if (pspec == NULL &&
rpm-build c487f7
      g_str_has_prefix (name, "x-"))
rpm-build c487f7
    {
rpm-build c487f7
      GHashTable *x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
      BuilderXProperty *prop;
rpm-build c487f7
rpm-build c487f7
      if (x_props == NULL)
rpm-build c487f7
        {
rpm-build c487f7
          x_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify)builder_x_property_free);
rpm-build c487f7
          g_object_set_data_full (G_OBJECT (serializable), "flatpak-x-props", x_props, (GDestroyNotify)g_hash_table_unref);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      prop = g_hash_table_lookup (x_props, name);
rpm-build c487f7
      if (prop == NULL)
rpm-build c487f7
        {
rpm-build c487f7
          prop = builder_x_property_new (name);
rpm-build c487f7
          g_hash_table_insert (x_props, (char *)builder_x_property_get_name (prop), prop);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      pspec = prop->pspec;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (pspec == NULL &&
rpm-build c487f7
      !g_str_has_prefix (name, "__") &&
rpm-build c487f7
      !g_str_has_prefix (name, "//"))
rpm-build c487f7
    g_warning ("Unknown property %s for type %s", name, g_type_name_from_instance ((GTypeInstance *)serializable));
rpm-build c487f7
rpm-build c487f7
  return pspec;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GParamSpec **
rpm-build c487f7
builder_serializable_list_properties (JsonSerializable *serializable,
rpm-build c487f7
                                      guint            *n_pspecs)
rpm-build c487f7
{
rpm-build c487f7
  GPtrArray *res = g_ptr_array_new ();
rpm-build c487f7
  guint n_normal, i;
rpm-build c487f7
  g_autofree GParamSpec **normal = NULL;
rpm-build c487f7
  GHashTable *x_props;
rpm-build c487f7
rpm-build c487f7
  normal = g_object_class_list_properties (G_OBJECT_GET_CLASS (serializable), &n_normal);
rpm-build c487f7
rpm-build c487f7
  for (i = 0; i < n_normal; i++)
rpm-build c487f7
    g_ptr_array_add (res, normal[i]);
rpm-build c487f7
rpm-build c487f7
  x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
  if (x_props)
rpm-build c487f7
    {
rpm-build c487f7
      GLNX_HASH_TABLE_FOREACH_V (x_props, BuilderXProperty *, prop)
rpm-build c487f7
        {
rpm-build c487f7
          g_ptr_array_add (res, prop->pspec);
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (n_pspecs)
rpm-build c487f7
    *n_pspecs = res->len;
rpm-build c487f7
rpm-build c487f7
  g_ptr_array_add (res, NULL);
rpm-build c487f7
rpm-build c487f7
  return (GParamSpec **)g_ptr_array_free (res, FALSE);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
builder_serializable_deserialize_property (JsonSerializable *serializable,
rpm-build c487f7
                                           const gchar      *property_name,
rpm-build c487f7
                                           GValue           *value,
rpm-build c487f7
                                           GParamSpec       *pspec,
rpm-build c487f7
                                           JsonNode         *property_node)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
rpm-build c487f7
  if (x_props)
rpm-build c487f7
    {
rpm-build c487f7
      BuilderXProperty *prop = g_hash_table_lookup (x_props, property_name);
rpm-build c487f7
      if (prop)
rpm-build c487f7
        {
rpm-build c487f7
          g_value_set_boxed (value, property_node);
rpm-build c487f7
          return TRUE;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return json_serializable_default_deserialize_property (serializable, property_name, value, pspec, property_node);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
JsonNode *
rpm-build c487f7
builder_serializable_serialize_property (JsonSerializable *serializable,
rpm-build c487f7
                                         const gchar      *property_name,
rpm-build c487f7
                                         const GValue     *value,
rpm-build c487f7
                                         GParamSpec       *pspec)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
rpm-build c487f7
  if (x_props)
rpm-build c487f7
    {
rpm-build c487f7
      BuilderXProperty *prop = g_hash_table_lookup (x_props, property_name);
rpm-build c487f7
      if (prop)
rpm-build c487f7
        return g_value_dup_boxed (value);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return json_serializable_default_serialize_property (serializable, property_name, value, pspec);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_serializable_set_property (JsonSerializable *serializable,
rpm-build c487f7
                                   GParamSpec       *pspec,
rpm-build c487f7
                                   const GValue     *value)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
rpm-build c487f7
  if (x_props)
rpm-build c487f7
    {
rpm-build c487f7
      BuilderXProperty *prop = g_hash_table_lookup (x_props, g_param_spec_get_name (pspec));
rpm-build c487f7
      if (prop)
rpm-build c487f7
        {
rpm-build c487f7
          prop->data = g_value_dup_boxed (value);
rpm-build c487f7
          return;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_object_set_property (G_OBJECT (serializable), pspec->name, value);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_serializable_get_property (JsonSerializable *serializable,
rpm-build c487f7
                                   GParamSpec       *pspec,
rpm-build c487f7
                                   GValue           *value)
rpm-build c487f7
{
rpm-build c487f7
  GHashTable *x_props = g_object_get_data (G_OBJECT (serializable), "flatpak-x-props");
rpm-build c487f7
rpm-build c487f7
  if (x_props)
rpm-build c487f7
    {
rpm-build c487f7
      BuilderXProperty *prop = g_hash_table_lookup (x_props, g_param_spec_get_name (pspec));
rpm-build c487f7
      if (prop)
rpm-build c487f7
        {
rpm-build c487f7
          g_value_set_boxed (value, prop->data);
rpm-build c487f7
          return;
rpm-build c487f7
        }
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_object_get_property (G_OBJECT (serializable), pspec->name, value);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
builder_set_term_title (const gchar *format,
rpm-build c487f7
                        ...)
rpm-build c487f7
{
rpm-build c487f7
  g_autofree gchar *message = NULL;
rpm-build c487f7
  va_list args;
rpm-build c487f7
rpm-build c487f7
  if (isatty (STDOUT_FILENO) != 1)
rpm-build c487f7
    return;
rpm-build c487f7
rpm-build c487f7
  va_start (args, format);
rpm-build c487f7
  message = g_strdup_vprintf (format, args);
rpm-build c487f7
  va_end (args);
rpm-build c487f7
rpm-build c487f7
  g_print ("\033]2;flatpak-builder: %s\007", message);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
typedef struct
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *current;
rpm-build c487f7
} XmlData;
rpm-build c487f7
rpm-build c487f7
FlatpakXml *
rpm-build c487f7
flatpak_xml_new (const gchar *element_name)
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *node = g_new0 (FlatpakXml, 1);
rpm-build c487f7
rpm-build c487f7
  node->element_name = g_strdup (element_name);
rpm-build c487f7
  return node;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
FlatpakXml *
rpm-build c487f7
flatpak_xml_new_text (const gchar *text)
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *node = g_new0 (FlatpakXml, 1);
rpm-build c487f7
rpm-build c487f7
  node->text = g_strdup (text);
rpm-build c487f7
  return node;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
flatpak_xml_add (FlatpakXml *parent, FlatpakXml *node)
rpm-build c487f7
{
rpm-build c487f7
  node->parent = parent;
rpm-build c487f7
rpm-build c487f7
  if (parent->first_child == NULL)
rpm-build c487f7
    parent->first_child = node;
rpm-build c487f7
  else
rpm-build c487f7
    parent->last_child->next_sibling = node;
rpm-build c487f7
  parent->last_child = node;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
xml_start_element (GMarkupParseContext *context,
rpm-build c487f7
                   const gchar         *element_name,
rpm-build c487f7
                   const gchar        **attribute_names,
rpm-build c487f7
                   const gchar        **attribute_values,
rpm-build c487f7
                   gpointer             user_data,
rpm-build c487f7
                   GError             **error)
rpm-build c487f7
{
rpm-build c487f7
  XmlData *data = user_data;
rpm-build c487f7
  FlatpakXml *node;
rpm-build c487f7
rpm-build c487f7
  node = flatpak_xml_new (element_name);
rpm-build c487f7
  node->attribute_names = g_strdupv ((char **) attribute_names);
rpm-build c487f7
  node->attribute_values = g_strdupv ((char **) attribute_values);
rpm-build c487f7
rpm-build c487f7
  flatpak_xml_add (data->current, node);
rpm-build c487f7
  data->current = node;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
xml_end_element (GMarkupParseContext *context,
rpm-build c487f7
                 const gchar         *element_name,
rpm-build c487f7
                 gpointer             user_data,
rpm-build c487f7
                 GError             **error)
rpm-build c487f7
{
rpm-build c487f7
  XmlData *data = user_data;
rpm-build c487f7
rpm-build c487f7
  data->current = data->current->parent;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
xml_text (GMarkupParseContext *context,
rpm-build c487f7
          const gchar         *text,
rpm-build c487f7
          gsize                text_len,
rpm-build c487f7
          gpointer             user_data,
rpm-build c487f7
          GError             **error)
rpm-build c487f7
{
rpm-build c487f7
  XmlData *data = user_data;
rpm-build c487f7
  FlatpakXml *node;
rpm-build c487f7
rpm-build c487f7
  node = flatpak_xml_new (NULL);
rpm-build c487f7
  node->text = g_strndup (text, text_len);
rpm-build c487f7
  flatpak_xml_add (data->current, node);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static void
rpm-build c487f7
xml_passthrough (GMarkupParseContext *context,
rpm-build c487f7
                 const gchar         *passthrough_text,
rpm-build c487f7
                 gsize                text_len,
rpm-build c487f7
                 gpointer             user_data,
rpm-build c487f7
                 GError             **error)
rpm-build c487f7
{
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
static GMarkupParser xml_parser = {
rpm-build c487f7
  xml_start_element,
rpm-build c487f7
  xml_end_element,
rpm-build c487f7
  xml_text,
rpm-build c487f7
  xml_passthrough,
rpm-build c487f7
  NULL
rpm-build c487f7
};
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
flatpak_xml_free (FlatpakXml *node)
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *child;
rpm-build c487f7
rpm-build c487f7
  if (node == NULL)
rpm-build c487f7
    return;
rpm-build c487f7
rpm-build c487f7
  child = node->first_child;
rpm-build c487f7
  while (child != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      FlatpakXml *next = child->next_sibling;
rpm-build c487f7
      flatpak_xml_free (child);
rpm-build c487f7
      child = next;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  g_free (node->element_name);
rpm-build c487f7
  g_free (node->text);
rpm-build c487f7
  g_strfreev (node->attribute_names);
rpm-build c487f7
  g_strfreev (node->attribute_values);
rpm-build c487f7
  g_free (node);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
void
rpm-build c487f7
flatpak_xml_to_string (FlatpakXml *node, GString *res)
rpm-build c487f7
{
rpm-build c487f7
  int i;
rpm-build c487f7
  FlatpakXml *child;
rpm-build c487f7
rpm-build c487f7
  if (node->parent == NULL)
rpm-build c487f7
    g_string_append (res, "\n");
rpm-build c487f7
rpm-build c487f7
  if (node->element_name)
rpm-build c487f7
    {
rpm-build c487f7
      if (node->parent != NULL)
rpm-build c487f7
        {
rpm-build c487f7
          g_string_append (res, "<");
rpm-build c487f7
          g_string_append (res, node->element_name);
rpm-build c487f7
          if (node->attribute_names)
rpm-build c487f7
            {
rpm-build c487f7
              for (i = 0; node->attribute_names[i] != NULL; i++)
rpm-build c487f7
                {
rpm-build c487f7
                  g_string_append_printf (res, " %s=\"%s\"",
rpm-build c487f7
                                          node->attribute_names[i],
rpm-build c487f7
                                          node->attribute_values[i]);
rpm-build c487f7
                }
rpm-build c487f7
            }
rpm-build c487f7
          if (node->first_child == NULL)
rpm-build c487f7
            g_string_append (res, "/>");
rpm-build c487f7
          else
rpm-build c487f7
            g_string_append (res, ">");
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      child = node->first_child;
rpm-build c487f7
      while (child != NULL)
rpm-build c487f7
        {
rpm-build c487f7
          flatpak_xml_to_string (child, res);
rpm-build c487f7
          child = child->next_sibling;
rpm-build c487f7
        }
rpm-build c487f7
      if (node->parent != NULL)
rpm-build c487f7
        {
rpm-build c487f7
          if (node->first_child != NULL)
rpm-build c487f7
            g_string_append_printf (res, "</%s>", node->element_name);
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
    }
rpm-build c487f7
  else if (node->text)
rpm-build c487f7
    {
rpm-build c487f7
      g_autofree char *escaped = g_markup_escape_text (node->text, -1);
rpm-build c487f7
      g_string_append (res, escaped);
rpm-build c487f7
    }
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
FlatpakXml *
rpm-build c487f7
flatpak_xml_unlink (FlatpakXml *node,
rpm-build c487f7
                    FlatpakXml *prev_sibling)
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *parent = node->parent;
rpm-build c487f7
rpm-build c487f7
  if (parent == NULL)
rpm-build c487f7
    return node;
rpm-build c487f7
rpm-build c487f7
  if (parent->first_child == node)
rpm-build c487f7
    parent->first_child = node->next_sibling;
rpm-build c487f7
rpm-build c487f7
  if (parent->last_child == node)
rpm-build c487f7
    parent->last_child = prev_sibling;
rpm-build c487f7
rpm-build c487f7
  if (prev_sibling)
rpm-build c487f7
    prev_sibling->next_sibling = node->next_sibling;
rpm-build c487f7
rpm-build c487f7
  node->parent = NULL;
rpm-build c487f7
  node->next_sibling = NULL;
rpm-build c487f7
rpm-build c487f7
  return node;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
FlatpakXml *
rpm-build c487f7
flatpak_xml_find (FlatpakXml  *node,
rpm-build c487f7
                  const char  *type,
rpm-build c487f7
                  FlatpakXml **prev_child_out)
rpm-build c487f7
{
rpm-build c487f7
  FlatpakXml *child = NULL;
rpm-build c487f7
  FlatpakXml *prev_child = NULL;
rpm-build c487f7
rpm-build c487f7
  child = node->first_child;
rpm-build c487f7
  prev_child = NULL;
rpm-build c487f7
  while (child != NULL)
rpm-build c487f7
    {
rpm-build c487f7
      FlatpakXml *next = child->next_sibling;
rpm-build c487f7
rpm-build c487f7
      if (g_strcmp0 (child->element_name, type) == 0)
rpm-build c487f7
        {
rpm-build c487f7
          if (prev_child_out)
rpm-build c487f7
            *prev_child_out = prev_child;
rpm-build c487f7
          return child;
rpm-build c487f7
        }
rpm-build c487f7
rpm-build c487f7
      prev_child = child;
rpm-build c487f7
      child = next;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  return NULL;
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
rpm-build c487f7
FlatpakXml *
rpm-build c487f7
flatpak_xml_parse (GInputStream *in,
rpm-build c487f7
                   gboolean      compressed,
rpm-build c487f7
                   GCancellable *cancellable,
rpm-build c487f7
                   GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GInputStream) real_in = NULL;
rpm-build c487f7
  g_autoptr(FlatpakXml) xml_root = NULL;
rpm-build c487f7
  XmlData data = { 0 };
rpm-build c487f7
  char buffer[32 * 1024];
rpm-build c487f7
  gssize len;
rpm-build c487f7
  g_autoptr(GMarkupParseContext) ctx = NULL;
rpm-build c487f7
rpm-build c487f7
  if (compressed)
rpm-build c487f7
    {
rpm-build c487f7
      g_autoptr(GZlibDecompressor) decompressor = NULL;
rpm-build c487f7
      decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
rpm-build c487f7
      real_in = g_converter_input_stream_new (in, G_CONVERTER (decompressor));
rpm-build c487f7
    }
rpm-build c487f7
  else
rpm-build c487f7
    {
rpm-build c487f7
      real_in = g_object_ref (in);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  xml_root = flatpak_xml_new ("root");
rpm-build c487f7
  data.current = xml_root;
rpm-build c487f7
rpm-build c487f7
  ctx = g_markup_parse_context_new (&xml_parser,
rpm-build c487f7
                                    G_MARKUP_PREFIX_ERROR_POSITION,
rpm-build c487f7
                                    &data,
rpm-build c487f7
                                    NULL);
rpm-build c487f7
rpm-build c487f7
  while ((len = g_input_stream_read (real_in, buffer, sizeof (buffer),
rpm-build c487f7
                                     cancellable, error)) > 0)
rpm-build c487f7
    {
rpm-build c487f7
      if (!g_markup_parse_context_parse (ctx, buffer, len, error))
rpm-build c487f7
        return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (len < 0)
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return g_steal_pointer (&xml_root);
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GBytes *
rpm-build c487f7
flatpak_read_stream (GInputStream *in,
rpm-build c487f7
                     gboolean      null_terminate,
rpm-build c487f7
                     GError      **error)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GOutputStream) mem_stream = NULL;
rpm-build c487f7
rpm-build c487f7
  mem_stream = g_memory_output_stream_new_resizable ();
rpm-build c487f7
  if (g_output_stream_splice (mem_stream, in,
rpm-build c487f7
                              0, NULL, error) < 0)
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  if (null_terminate)
rpm-build c487f7
    {
rpm-build c487f7
      if (!g_output_stream_write (G_OUTPUT_STREAM (mem_stream), "\0", 1, NULL, error))
rpm-build c487f7
        return NULL;
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (!g_output_stream_close (G_OUTPUT_STREAM (mem_stream), NULL, error))
rpm-build c487f7
    return NULL;
rpm-build c487f7
rpm-build c487f7
  return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (mem_stream));
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GVariant *
rpm-build c487f7
flatpak_variant_uncompress (GVariant *variant,
rpm-build c487f7
                            const GVariantType *type)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GInputStream) input_stream = NULL;
rpm-build c487f7
  g_autoptr(GZlibDecompressor) decompressor = NULL;
rpm-build c487f7
  g_autoptr(GInputStream) converter = NULL;
rpm-build c487f7
  g_autoptr(GBytes) decompressed_bytes = NULL;
rpm-build c487f7
  const guint8 *compressed;
rpm-build c487f7
  gsize compressed_size;
rpm-build c487f7
rpm-build c487f7
  g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTESTRING));
rpm-build c487f7
rpm-build c487f7
  compressed = g_variant_get_data (variant);
rpm-build c487f7
  compressed_size = g_variant_get_size (variant);
rpm-build c487f7
rpm-build c487f7
  input_stream = g_memory_input_stream_new_from_data (compressed, compressed_size, NULL);
rpm-build c487f7
  decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
rpm-build c487f7
  converter = g_converter_input_stream_new (G_INPUT_STREAM (input_stream), G_CONVERTER (decompressor));
rpm-build c487f7
  decompressed_bytes = flatpak_read_stream (converter, FALSE, NULL);
rpm-build c487f7
  return g_variant_ref_sink (g_variant_new_from_bytes (type, decompressed_bytes, TRUE));
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
GVariant *
rpm-build c487f7
flatpak_variant_compress (GVariant *variant)
rpm-build c487f7
{
rpm-build c487f7
  g_autoptr(GInputStream) input_stream = NULL;
rpm-build c487f7
  g_autoptr(GZlibCompressor) compressor = NULL;
rpm-build c487f7
  g_autoptr(GInputStream) converter = NULL;
rpm-build c487f7
  g_autoptr(GBytes) compressed_bytes = NULL;
rpm-build c487f7
  const guint8 *decompressed;
rpm-build c487f7
  gsize decompressed_size;
rpm-build c487f7
rpm-build c487f7
  decompressed = g_variant_get_data (variant);
rpm-build c487f7
  decompressed_size = g_variant_get_size (variant);
rpm-build c487f7
rpm-build c487f7
  input_stream = g_memory_input_stream_new_from_data (decompressed, decompressed_size, NULL);
rpm-build c487f7
  compressor = g_zlib_compressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP, -1);
rpm-build c487f7
  converter = g_converter_input_stream_new (G_INPUT_STREAM (input_stream), G_CONVERTER (compressor));
rpm-build c487f7
  compressed_bytes = flatpak_read_stream (converter, FALSE, NULL);
rpm-build c487f7
rpm-build c487f7
  return g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, compressed_bytes, TRUE));
rpm-build c487f7
}
rpm-build c487f7
rpm-build c487f7
gboolean
rpm-build c487f7
flatpak_version_check (int major,
rpm-build c487f7
                       int minor,
rpm-build c487f7
                       int micro)
rpm-build c487f7
{
rpm-build c487f7
  static int flatpak_major = 0;
rpm-build c487f7
  static int flatpak_minor = 0;
rpm-build c487f7
  static int flatpak_micro = 0;
rpm-build c487f7
rpm-build c487f7
  if (flatpak_major == 0 &&
rpm-build c487f7
      flatpak_minor == 0 &&
rpm-build c487f7
      flatpak_micro == 0)
rpm-build c487f7
    {
rpm-build c487f7
      const char * argv[] = { "flatpak", "--version", NULL };
rpm-build c487f7
      g_autoptr(GSubprocess) subp = NULL;
rpm-build c487f7
      g_autofree char *out = NULL;
rpm-build c487f7
rpm-build c487f7
      subp = g_subprocess_newv (argv, G_SUBPROCESS_FLAGS_STDOUT_PIPE, NULL);
rpm-build c487f7
      g_subprocess_communicate_utf8 (subp, NULL, NULL, &out, NULL, NULL);
rpm-build c487f7
rpm-build c487f7
      if (sscanf (out, "Flatpak %d.%d.%d", &flatpak_major, &flatpak_minor, &flatpak_micro) != 3)
rpm-build c487f7
        g_warning ("Failed to get flatpak version");
rpm-build c487f7
rpm-build c487f7
      g_debug ("Using Flatpak version %d.%d.%d", flatpak_major, flatpak_minor, flatpak_micro);
rpm-build c487f7
    }
rpm-build c487f7
rpm-build c487f7
  if (flatpak_major > major)
rpm-build c487f7
    return TRUE;
rpm-build c487f7
  if (flatpak_major < major)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
  if (flatpak_minor > minor)
rpm-build c487f7
    return TRUE;
rpm-build c487f7
  if (flatpak_minor < minor)
rpm-build c487f7
    return FALSE;
rpm-build c487f7
  if (flatpak_micro >= micro)
rpm-build c487f7
    return TRUE;
rpm-build c487f7
rpm-build c487f7
  return FALSE;
rpm-build c487f7
}