コード例 #1
0
ファイル: gsystem-file-utils.c プロジェクト: GNOME/libgsystem
/**
 * gs_file_create:
 * @file: Path to non-existent file
 * @mode: Unix access permissions
 * @out_stream: (out) (transfer full) (allow-none): Newly created output, or %NULL
 * @cancellable: a #GCancellable
 * @error: a #GError
 *
 * Like g_file_create(), except this function allows specifying the
 * access mode.  This allows atomically creating private files.
 */
gboolean
gs_file_create (GFile          *file,
                int             mode,
                GOutputStream **out_stream,
                GCancellable   *cancellable,
                GError        **error)
{
    gboolean ret = FALSE;
    int fd;
    GOutputStream *ret_stream = NULL;

    fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode);
    if (fd < 0)
    {
        gs_set_prefix_error_from_errno (error, errno, "open");
        goto out;
    }

    if (fchmod (fd, mode) < 0)
    {
        close (fd);
        gs_set_prefix_error_from_errno (error, errno, "fchmod");
        goto out;
    }

    ret_stream = g_unix_output_stream_new (fd, TRUE);

    ret = TRUE;
    gs_transfer_out_value (out_stream, &ret_stream);
out:
    g_clear_object (&ret_stream);
    return ret;
}
コード例 #2
0
gboolean
_rpmostree_file_load_contents_utf8_allow_noent (GFile          *path,
                                                char          **out_contents,
                                                GCancellable   *cancellable,
                                                GError        **error)
{
  gboolean ret = FALSE;
  GError *temp_error = NULL;
  gs_free char *ret_contents = NULL;

  ret_contents = gs_file_load_contents_utf8 (path, cancellable, &temp_error);
  if (!ret_contents)
    {
      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
          g_clear_error (&temp_error);
        }
      else
        {
          g_propagate_error (error, temp_error);
          goto out;
        }
    }

  ret = TRUE;
  gs_transfer_out_value (out_contents, &ret_contents);
 out:
  return ret;
}
コード例 #3
0
gboolean
_rpmostree_util_enumerate_directory_allow_noent (GFile               *dirpath,
						 const char          *queryargs,
						 GFileQueryInfoFlags  queryflags,
						 GFileEnumerator    **out_direnum,
						 GCancellable        *cancellable,
						 GError             **error)
{
  gboolean ret = FALSE;
  GError *temp_error = NULL;
  gs_unref_object GFileEnumerator *ret_direnum = NULL;

  ret_direnum = g_file_enumerate_children (dirpath, queryargs, queryflags,
                                           cancellable, &temp_error);
  if (!ret_direnum)
    {
      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
          g_clear_error (&temp_error);
          ret = TRUE;
        }
      else
        g_propagate_error (error, temp_error);

      goto out;
    }

  ret = TRUE;
  gs_transfer_out_value (out_direnum, &ret_direnum);
 out:
  return ret;
}
コード例 #4
0
gboolean
rpmostree_get_pkglist_for_root (GFile            *root,
                                HySack           *out_sack,
                                HyPackageList    *out_pkglist,
                                GCancellable     *cancellable,
                                GError          **error)
{
  gboolean ret = FALSE;
  int rc;
  _cleanup_hysack_ HySack sack = NULL;
  _cleanup_hyquery_ HyQuery query = NULL;
  _cleanup_hypackagelist_ HyPackageList pkglist = NULL;

#if BUILDOPT_HAWKEY_SACK_CREATE2
  sack = hy_sack_create (NULL, NULL,
                         gs_file_get_path_cached (root),
                         NULL,
                         HY_MAKE_CACHE_DIR);
#else
  sack = hy_sack_create (NULL, NULL,
                         gs_file_get_path_cached (root),
                         HY_MAKE_CACHE_DIR);
#endif
  if (sack == NULL)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Failed to create sack cache");
      goto out;
    }

  rc = hy_sack_load_system_repo (sack, NULL, 0);
  if (!hif_error_set_from_hawkey (rc, error))
    {
      g_prefix_error (error, "Failed to load system repo: ");
      goto out;
    }
  query = hy_query_create (sack);
  hy_query_filter (query, HY_PKG_REPONAME, HY_EQ, HY_SYSTEM_REPO_NAME);
  pkglist = hy_query_run (query);

  ret = TRUE;
  gs_transfer_out_value (out_sack, &sack);
  gs_transfer_out_value (out_pkglist, &pkglist);
 out:
  return ret;
}
コード例 #5
0
gboolean
rpmostree_db_option_context_parse (GOptionContext *context,
                                   const GOptionEntry *main_entries,
                                   int *argc, char ***argv,
                                   OstreeRepo **out_repo,
                                   GCancellable *cancellable, GError **error)
{
  gs_unref_object OstreeRepo *repo = NULL;
  gboolean success = FALSE;

  /* Entries are listed in --help output in the order added.  We add the
   * main entries ourselves so that we can add the --repo entry first. */

  g_option_context_add_main_entries (context, global_entries, NULL);

  if (!rpmostree_option_context_parse (context,
                                       main_entries,
                                       argc, argv,
                                       RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD,
                                       cancellable,
                                       NULL,
                                       error))
    goto out;

  if (opt_repo == NULL)
    {
      gs_unref_object OstreeSysroot *sysroot = NULL;

      sysroot = ostree_sysroot_new_default ();
      if (!ostree_sysroot_load (sysroot, cancellable, error))
        goto out;

      if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
        goto out;
    }
  else
    {
      gs_unref_object GFile *repo_file = g_file_new_for_path (opt_repo);

      repo = ostree_repo_new (repo_file);
      if (!ostree_repo_open (repo, cancellable, error))
        goto out;
    }

  if (rpmReadConfigFiles (NULL, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "rpm failed to init: %s", rpmlogMessage ());
      goto out;
    }

  gs_transfer_out_value (out_repo, &repo);

  success = TRUE;
out:
  return success;
}
コード例 #6
0
ファイル: gsystem-file-utils.c プロジェクト: GNOME/libgsystem
/**
 * gs_file_open_in_tmpdir_at:
 * @tmpdir_fd: Directory to place temporary file
 * @mode: Default mode (will be affected by umask)
 * @out_name: (out) (transfer full): Newly created file name
 * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
 * @cancellable:
 * @error:
 *
 * Like g_file_open_tmp(), except the file will be created in the
 * provided @tmpdir, and allows specification of the Unix @mode, which
 * means private files may be created.  Return values will be stored
 * in @out_name, and optionally @out_stream.
 */
gboolean
gs_file_open_in_tmpdir_at (int                tmpdir_fd,
                           int                mode,
                           char             **out_name,
                           GOutputStream    **out_stream,
                           GCancellable      *cancellable,
                           GError           **error)
{
    gboolean ret = FALSE;
    const int max_attempts = 128;
    int i;
    char *tmp_name = NULL;
    int fd;

    /* 128 attempts seems reasonable... */
    for (i = 0; i < max_attempts; i++)
    {
        g_free (tmp_name);
        tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL);

        do
            fd = openat (tmpdir_fd, tmp_name, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
        while (fd == -1 && errno == EINTR);
        if (fd < 0 && errno != EEXIST)
        {
            gs_set_prefix_error_from_errno (error, errno, "openat");
            goto out;
        }
        else if (fd != -1)
            break;
    }
    if (i == max_attempts)
    {
        g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                     "Exhausted attempts to open temporary file");
        goto out;
    }

    ret = TRUE;
    gs_transfer_out_value (out_name, &tmp_name);
    if (out_stream)
        *out_stream = g_unix_output_stream_new (fd, TRUE);
    else
        (void) close (fd);
out:
    g_free (tmp_name);
    return ret;
}
コード例 #7
0
ファイル: ostree-sysroot.c プロジェクト: resin-io/ostree
static gboolean
parse_origin (OstreeSysroot   *self,
              int              deployment_dfd,
              const char      *deployment_name,
              GKeyFile       **out_origin,
              GCancellable    *cancellable,
              GError         **error)
{
  gboolean ret = FALSE;
  g_autoptr(GKeyFile) ret_origin = NULL;
  g_autofree char *origin_path = g_strconcat ("../", deployment_name, ".origin", NULL);
  struct stat stbuf;
  g_autofree char *origin_contents = NULL;

  ret_origin = g_key_file_new ();
  
  if (fstatat (deployment_dfd, origin_path, &stbuf, 0) != 0)
    {
      if (errno == ENOENT)
        ;
      else
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }
  else
    {
      origin_contents = glnx_file_get_contents_utf8_at (deployment_dfd, origin_path,
                                                        NULL, cancellable, error);
      if (!origin_contents)
        goto out;

      if (!g_key_file_load_from_data (ret_origin, origin_contents, -1, 0, error))
        goto out;
    }

  ret = TRUE;
  gs_transfer_out_value (out_origin, &ret_origin);
 out:
  if (error)
    g_prefix_error (error, "Parsing %s: ", origin_path);
  if (ret_origin)
    g_key_file_unref (ret_origin);
  return ret;
}
コード例 #8
0
/* Given a directory @d, find the first child that is a directory,
 * returning it in @out_subdir.  If there are multiple directories,
 * return an error.
 */
static gboolean
find_ensure_one_subdirectory (GFile         *d,
                              GFile        **out_subdir,
                              GCancellable  *cancellable,
                              GError       **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFileEnumerator *direnum = NULL;
    gs_unref_object GFile *ret_subdir = NULL;

    direnum = g_file_enumerate_children (d, "standard::name,standard::type", 0,
                                         cancellable, error);
    if (!direnum)
        goto out;

    while (TRUE)
    {
        GFileInfo *file_info;
        GFile *child;

        if (!gs_file_enumerator_iterate (direnum, &file_info, &child,
                                         cancellable, error))
            goto out;
        if (!file_info)
            break;

        if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
            if (ret_subdir)
            {
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Multiple subdirectories found in: %s", gs_file_get_path_cached (d));
                goto out;
            }
            ret_subdir = g_object_ref (child);
        }
    }

    ret = TRUE;
    gs_transfer_out_value (out_subdir, &ret_subdir);
out:
    return ret;
}
/*
 * Generate a sorted array of [(checksum: str, size: uint64, names: array[string]), ...]
 * for regular file content.
 */
static gboolean
build_content_sizenames_filtered (OstreeRepo              *repo,
                                  GVariant                *commit,
                                  GHashTable              *include_only_objects,
                                  GPtrArray              **out_sizenames,
                                  GCancellable            *cancellable,
                                  GError                 **error)
{
  gboolean ret = FALSE;
  g_autoptr(GPtrArray) ret_sizenames =
    g_ptr_array_new_with_free_func (_ostree_delta_content_sizenames_free);
  g_autoptr(GHashTable) sizenames_map =
    g_hash_table_new_full (g_str_hash, g_str_equal, NULL, _ostree_delta_content_sizenames_free);
  ostree_cleanup_repo_commit_traverse_iter
    OstreeRepoCommitTraverseIter iter = { 0, };

  if (!ostree_repo_commit_traverse_iter_init_commit (&iter, repo, commit,
                                                     OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE,
                                                     error))
    goto out;

  if (!build_content_sizenames_recurse (repo, &iter, sizenames_map, include_only_objects,
                                        cancellable, error))
    goto out;

  { GHashTableIter hashiter;
    gpointer hkey, hvalue;

    g_hash_table_iter_init (&hashiter, sizenames_map);
    while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue))
      {
        g_hash_table_iter_steal (&hashiter);
        g_ptr_array_add (ret_sizenames, hvalue);
      }
  }

  g_ptr_array_sort (ret_sizenames, compare_sizenames);

  ret = TRUE;
  gs_transfer_out_value (out_sizenames, &ret_sizenames);
 out:
  return ret;
}
コード例 #10
0
ファイル: terminal-app.c プロジェクト: pledges/gnome-terminal
static gboolean
terminal_app_dbus_register (GApplication    *application,
                            GDBusConnection *connection,
                            const gchar     *object_path,
                            GError         **error)
{
  TerminalApp *app = TERMINAL_APP (application);
  gs_unref_object TerminalObjectSkeleton *object = NULL;
  gs_unref_object TerminalFactory *factory = NULL;

  if (!G_APPLICATION_CLASS (terminal_app_parent_class)->dbus_register (application,
                                                                       connection,
                                                                       object_path,
                                                                       error))
    return FALSE;

#ifdef ENABLE_SEARCH_PROVIDER
  if (g_settings_get_boolean (app->global_settings, TERMINAL_SETTING_SHELL_INTEGRATION_KEY)) {
    gs_unref_object TerminalSearchProvider *search_provider;

    search_provider = terminal_search_provider_new ();

    if (!terminal_search_provider_dbus_register (search_provider,
                                                 connection,
                                                 TERMINAL_SEARCH_PROVIDER_PATH,
                                                 error))
      return FALSE;

    gs_transfer_out_value (&app->search_provider, &search_provider);
  }
#endif /* ENABLE_SEARCH_PROVIDER */

  object = terminal_object_skeleton_new (TERMINAL_FACTORY_OBJECT_PATH);
  factory = terminal_factory_impl_new ();
  terminal_object_skeleton_set_factory (object, factory);

  app->object_manager = g_dbus_object_manager_server_new (TERMINAL_OBJECT_PATH_PREFIX);
  g_dbus_object_manager_server_export (app->object_manager, G_DBUS_OBJECT_SKELETON (object));

  /* And export the object */
  g_dbus_object_manager_server_set_connection (app->object_manager, connection);
  return TRUE;
}
コード例 #11
0
/**
 * ostree_repo_traverse_commit:
 * @repo: Repo
 * @commit_checksum: ASCII SHA256 checksum
 * @maxdepth: Traverse this many parent commits, -1 for unlimited
 * @out_reachable: (out) (transfer container) (element-type GVariant GVariant): Set of reachable objects
 * @cancellable: Cancellable
 * @error: Error
 *
 * Create a new set @out_reachable containing all objects reachable
 * from @commit_checksum, traversing @maxdepth parent commits.
 */
gboolean
ostree_repo_traverse_commit (OstreeRepo      *repo,
                             const char      *commit_checksum,
                             int              maxdepth,
                             GHashTable     **out_reachable,
                             GCancellable    *cancellable,
                             GError         **error)
{
  gboolean ret = FALSE;
  g_autoptr(GHashTable) ret_reachable =
    ostree_repo_traverse_new_reachable ();

  if (!ostree_repo_traverse_commit_union (repo, commit_checksum, maxdepth,
                                          ret_reachable, cancellable, error))
    goto out;

  ret = TRUE;
  gs_transfer_out_value (out_reachable, &ret_reachable);
 out:
  return ret;
}
コード例 #12
0
ファイル: ostree-sysroot.c プロジェクト: resin-io/ostree
/**
 * ostree_sysroot_query_bootloader:
 * @sysroot: Sysroot
 * @out_bootloader: (out) (transfer full) (allow-none): Return location for bootloader, may be %NULL
 * @cancellable: Cancellable
 * @error: Error
 */
gboolean
_ostree_sysroot_query_bootloader (OstreeSysroot     *sysroot,
                                  OstreeBootloader **out_bootloader,
                                  GCancellable      *cancellable,
                                  GError           **error)
{
  gboolean ret = FALSE;
  gboolean is_active;
  glnx_unref_object OstreeBootloader *ret_loader = NULL;

  ret_loader = (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
  if (!_ostree_bootloader_query (ret_loader, &is_active,
                                 cancellable, error))
    goto out;
  if (!is_active)
    {
      g_object_unref (ret_loader);
      ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot);
      if (!_ostree_bootloader_query (ret_loader, &is_active,
                                     cancellable, error))
        goto out;
    }
  if (!is_active)
    {
      g_object_unref (ret_loader);
      ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot);
      if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error))
        goto out;
    }
  if (!is_active)
    g_clear_object (&ret_loader);

  ret = TRUE;
  gs_transfer_out_value (out_bootloader, &ret_loader);
 out:
  return ret;
}
コード例 #13
0
ファイル: gsystem-file-utils.c プロジェクト: GNOME/libgsystem
/**
 * gs_file_open_in_tmpdir:
 * @tmpdir: Directory to place temporary file
 * @mode: Default mode (will be affected by umask)
 * @out_file: (out) (transfer full): Newly created file path
 * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
 * @cancellable:
 * @error:
 *
 * Like g_file_open_tmp(), except the file will be created in the
 * provided @tmpdir, and allows specification of the Unix @mode, which
 * means private files may be created.  Return values will be stored
 * in @out_file, and optionally @out_stream.
 */
gboolean
gs_file_open_in_tmpdir (GFile             *tmpdir,
                        int                mode,
                        GFile            **out_file,
                        GOutputStream    **out_stream,
                        GCancellable      *cancellable,
                        GError           **error)
{
    gboolean ret = FALSE;
    DIR *d = NULL;
    int dfd = -1;
    char *tmp_name = NULL;
    GOutputStream *ret_stream = NULL;

    d = opendir (gs_file_get_path_cached (tmpdir));
    if (!d)
    {
        gs_set_prefix_error_from_errno (error, errno, "opendir");
        goto out;
    }
    dfd = dirfd (d);

    if (!gs_file_open_in_tmpdir_at (dfd, mode, &tmp_name,
                                    out_stream ? &ret_stream : NULL,
                                    cancellable, error))
        goto out;

    ret = TRUE;
    *out_file = g_file_get_child (tmpdir, tmp_name);
    gs_transfer_out_value (out_stream, &ret_stream);
out:
    if (d) (void) closedir (d);
    g_clear_object (&ret_stream);
    g_free (tmp_name);
    return ret;
}
コード例 #14
0
ファイル: ostree-sysroot.c プロジェクト: resin-io/ostree
gboolean
_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
                                          int            bootversion,
                                          GPtrArray    **out_loader_configs,
                                          GCancellable  *cancellable,
                                          GError       **error)
{
  gboolean ret = FALSE;
  int fd; /* Temporary owned by iterator */
  g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion);
  g_autoptr(GPtrArray) ret_loader_configs = NULL;
  g_auto(GLnxDirFdIterator) dfd_iter = { 0, };

  if (!ensure_sysroot_fd (self, error))
    goto out;

  ret_loader_configs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);

  fd = glnx_opendirat_with_errno (self->sysroot_fd, entries_path, TRUE);
  if (fd == -1)
    {
      if (errno == ENOENT)
        goto done;
      else
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!glnx_dirfd_iterator_init_take_fd (fd, &dfd_iter, error))
    goto out;

  while (TRUE)
    {
      struct dirent *dent;
      struct stat stbuf;

      if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
        goto out;
          
      if (dent == NULL)
        break;

      if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }

      if (g_str_has_prefix (dent->d_name, "ostree-") &&
          g_str_has_suffix (dent->d_name, ".conf") &&
          S_ISREG (stbuf.st_mode))
        {
          glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new ();
  
          if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error))
            {
              g_prefix_error (error, "Parsing %s: ", dent->d_name);
              goto out;
            }

          g_ptr_array_add (ret_loader_configs, g_object_ref (config));
        }
    }

 done:
  gs_transfer_out_value (out_loader_configs, &ret_loader_configs);
  ret = TRUE;
 out:
  return ret;
}
コード例 #15
0
static gboolean
find_kernel_and_initramfs_in_bootdir (GFile       *bootdir,
                                      GFile      **out_kernel,
                                      GFile      **out_initramfs,
                                      GCancellable *cancellable,
                                      GError     **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFileEnumerator *direnum = NULL;
    gs_unref_object GFile *ret_kernel = NULL;
    gs_unref_object GFile *ret_initramfs = NULL;

    direnum = g_file_enumerate_children (bootdir, "standard::name", 0,
                                         cancellable, error);
    if (!direnum)
        goto out;

    while (TRUE)
    {
        const char *name;
        GFileInfo *file_info;
        GFile *child;

        if (!gs_file_enumerator_iterate (direnum, &file_info, &child,
                                         cancellable, error))
            goto out;
        if (!file_info)
            break;

        name = g_file_info_get_name (file_info);

        /* Current Fedora 23 kernel.spec installs as just vmlinuz */
        if (strcmp (name, "vmlinuz") == 0 || g_str_has_prefix (name, "vmlinuz-"))
        {
            if (ret_kernel)
            {
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Multiple vmlinuz- in %s",
                             gs_file_get_path_cached (bootdir));
                goto out;
            }
            ret_kernel = g_object_ref (child);
        }
        else if (g_str_has_prefix (name, "initramfs-"))
        {
            if (ret_initramfs)
            {
                g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                             "Multiple initramfs- in %s",
                             gs_file_get_path_cached (bootdir));
                goto out;
            }
            ret_initramfs = g_object_ref (child);
        }
    }

    ret = TRUE;
    gs_transfer_out_value (out_kernel, &ret_kernel);
    gs_transfer_out_value (out_initramfs, &ret_initramfs);
out:
    return ret;
}
コード例 #16
0
gboolean
rpmostree_db_option_context_parse (GOptionContext *context,
                                   const GOptionEntry *main_entries,
                                   int *argc, char ***argv,
                                   OstreeRepo **out_repo,
                                   GFile **out_rpmdbdir,
                                   gboolean *out_rpmdbdir_is_tmp,
                                   GCancellable *cancellable, GError **error)
{
  gs_unref_object OstreeRepo *repo = NULL;
  gs_unref_object GFile *rpmdbdir = NULL;
  gboolean rpmdbdir_is_tmp = FALSE;
  gboolean success = FALSE;

  /* Entries are listed in --help output in the order added.  We add the
   * main entries ourselves so that we can add the --repo entry first. */

  g_option_context_add_main_entries (context, global_entries, NULL);

  if (!rpmostree_option_context_parse (context, main_entries, argc, argv, error))
    goto out;

  if (opt_repo == NULL)
    {
      gs_unref_object OstreeSysroot *sysroot = NULL;

      sysroot = ostree_sysroot_new_default ();
      if (!ostree_sysroot_load (sysroot, cancellable, error))
        goto out;

      if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
        goto out;
    }
  else
    {
      gs_unref_object GFile *repo_file = g_file_new_for_path (opt_repo);

      repo = ostree_repo_new (repo_file);
      if (!ostree_repo_open (repo, cancellable, error))
        goto out;
    }

  if (rpmReadConfigFiles (NULL, NULL))
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "rpm failed to init: %s", rpmlogMessage ());
      goto out;
    }

  if (opt_rpmdbdir != NULL)
    {
      rpmdbdir = g_file_new_for_path (opt_rpmdbdir);
    }
  else
    {
      /* tmp on tmpfs is much faster than /var/tmp,
       * and the rpmdb itself shouldn't be too big. */
      gs_free char *tmpd = g_mkdtemp (g_strdup ("/tmp/rpm-ostree.XXXXXX"));
      rpmdbdir = g_file_new_for_path (tmpd);
      rpmdbdir_is_tmp = TRUE;
      ostree_repo_set_disable_fsync (repo, TRUE);
    }

  gs_transfer_out_value (out_repo, &repo);
  gs_transfer_out_value (out_rpmdbdir, &rpmdbdir);

  if (out_rpmdbdir_is_tmp != NULL)
    *out_rpmdbdir_is_tmp = rpmdbdir_is_tmp;

  success = TRUE;

out:
  return success;
}
コード例 #17
0
/**
 * ostree_repo_list_static_delta_names:
 * @self: Repo
 * @out_deltas: (out) (element-type utf8): String name of deltas (checksum-checksum.delta)
 * @cancellable: Cancellable
 * @error: Error
 *
 * This function synchronously enumerates all static deltas in the
 * repository, returning its result in @out_deltas.
 */ 
gboolean
ostree_repo_list_static_delta_names (OstreeRepo                  *self,
                                     GPtrArray                  **out_deltas,
                                     GCancellable                *cancellable,
                                     GError                     **error)
{
  gboolean ret = FALSE;
  gs_unref_ptrarray GPtrArray *ret_deltas = NULL;
  gs_unref_object GFileEnumerator *dir_enum = NULL;

  ret_deltas = g_ptr_array_new_with_free_func (g_free);

  if (g_file_query_exists (self->deltas_dir, NULL))
    {
      dir_enum = g_file_enumerate_children (self->deltas_dir, OSTREE_GIO_FAST_QUERYINFO,
                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                            NULL, error);
      if (!dir_enum)
        goto out;

      while (TRUE)
        {
          gs_unref_object GFileEnumerator *dir_enum2 = NULL;
          GFileInfo *file_info;
          GFile *child;

          if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
                                           NULL, error))
            goto out;
          if (file_info == NULL)
            break;

          if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
            continue;


          dir_enum2 = g_file_enumerate_children (child, OSTREE_GIO_FAST_QUERYINFO,
                                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                                 NULL, error);
          if (!dir_enum2)
            goto out;

          while (TRUE)
            {
              GFileInfo *file_info2;
              GFile *child2;
              const char *name1;
              const char *name2;

              if (!gs_file_enumerator_iterate (dir_enum2, &file_info2, &child2,
                                               NULL, error))
                goto out;
              if (file_info2 == NULL)
                break;

              if (g_file_info_get_file_type (file_info2) != G_FILE_TYPE_DIRECTORY)
                continue;

              name1 = gs_file_get_basename_cached (child);
              name2 = gs_file_get_basename_cached (child2);

              {
                gs_unref_object GFile *meta_path = g_file_get_child (child2, "superblock");

                if (g_file_query_exists (meta_path, NULL))
                  {
                    gs_free char *buf = g_strconcat (name1, name2, NULL);
                    GString *out = g_string_new ("");
                    char checksum[65];
                    guchar csum[32];
                    const char *dash = strchr (buf, '-');

                    ostree_checksum_b64_inplace_to_bytes (buf, csum);
                    ostree_checksum_inplace_from_bytes (csum, checksum);
                    g_string_append (out, checksum);
                    if (dash)
                      {
                        g_string_append_c (out, '-');
                        ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
                        ostree_checksum_inplace_from_bytes (csum, checksum);
                        g_string_append (out, checksum);
                      }

                    g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
                  }
              }
            }
        }
    }

  ret = TRUE;
  gs_transfer_out_value (out_deltas, &ret_deltas);
 out:
  return ret;
}
コード例 #18
0
static gboolean
compute_checksum_from_treefile_and_goal (RpmOstreeTreeComposeContext   *self,
                                         HyGoal                         goal,
                                         GFile                         *contextdir,
                                         JsonArray                     *add_files,
                                         char                        **out_checksum,
                                         GError                      **error)
{
  gboolean ret = FALSE;
  g_autofree char *ret_checksum = NULL;
  GChecksum *checksum = g_checksum_new (G_CHECKSUM_SHA256);
  
  /* Hash in the raw treefile; this means reordering the input packages
   * or adding a comment will cause a recompose, but let's be conservative
   * here.
   */
  { gsize len;
    const guint8* buf = g_bytes_get_data (self->serialized_treefile, &len);

    g_checksum_update (checksum, buf, len);
  }

  if (add_files)
    {
      guint i, len = json_array_get_length (add_files);
      for (i = 0; i < len; i++)
        {
          g_autoptr(GFile) srcfile = NULL;
          const char *src, *dest;
          JsonArray *add_el = json_array_get_array_element (add_files, i);
          g_autoptr(GFile) child = NULL;

          if (!add_el)
            {
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Element in add-files is not an array");
              goto out;
            }
          src = _rpmostree_jsonutil_array_require_string_element (add_el, 0, error);
          if (!src)
            goto out;

          dest = _rpmostree_jsonutil_array_require_string_element (add_el, 1, error);
          if (!dest)
            goto out;

          srcfile = g_file_resolve_relative_path (contextdir, src);

          if (!_rpmostree_util_update_checksum_from_file (checksum,
                                                          srcfile,
                                                          NULL,
                                                          error))
            goto out;

          g_checksum_update (checksum, (const guint8 *) dest, strlen (dest));
        }

    }

  /* FIXME; we should also hash the post script */

  /* Hash in each package */
  rpmostree_dnf_add_checksum_goal (checksum, goal);

  ret_checksum = g_strdup (g_checksum_get_string (checksum));

  ret = TRUE;
 out:
  gs_transfer_out_value (out_checksum, &ret_checksum);
  if (checksum) g_checksum_free (checksum);
  return ret;
}
コード例 #19
0
static gboolean
install_packages_in_root (RpmOstreeTreeComposeContext  *self,
                          RpmOstreeContext *ctx,
                          JsonObject      *treedata,
                          GFile           *yumroot,
                          char           **packages,
                          gboolean        *out_unmodified,
                          char           **out_new_inputhash,
                          GCancellable    *cancellable,
                          GError         **error)
{
  gboolean ret = FALSE;
  guint progress_sigid;
  GFile *contextdir = self->treefile_context_dirs->pdata[0];
  g_autoptr(RpmOstreeInstall) hifinstall = { 0, };
  DnfContext *hifctx;
  g_autofree char *ret_new_inputhash = NULL;
  g_autoptr(GKeyFile) treespec = g_key_file_new ();
  JsonArray *enable_repos = NULL;
  JsonArray *add_files = NULL;

  /* TODO - uncomment this once we have SELinux working */
#if 0
  g_autofree char *cache_repo_pathstr = glnx_fdrel_abspath (self->cachedir_dfd, "repo");
  g_autoptr(GFile) cache_repo_path = g_file_new_for_path (cache_repo_pathstr);
  glnx_unref_object OstreeRepo *ostreerepo = ostree_repo_new (cache_repo_path);

  if (!g_file_test (cache_repo_pathstr, G_FILE_TEST_EXISTS))
    {
      if (!ostree_repo_create (ostreerepo, OSTREE_REPO_MODE_BARE_USER, cancellable, error))
        goto out;
    }
#endif

  hifctx = rpmostree_context_get_hif (ctx);
  if (opt_proxy)
    dnf_context_set_http_proxy (hifctx, opt_proxy);

  /* Hack this here... see https://github.com/rpm-software-management/libhif/issues/53
   * but in the future we won't be using librpm at all for unpack/scripts, so it won't
   * matter.
   */
  { const char *debuglevel = getenv ("RPMOSTREE_RPM_VERBOSITY");
    if (!debuglevel)
      debuglevel = "info";
    dnf_context_set_rpm_verbosity (hifctx, debuglevel);
    rpmlogSetFile(NULL);
  }

  dnf_context_set_repo_dir (hifctx, gs_file_get_path_cached (contextdir));

  /* By default, retain packages in addition to metadata with --cachedir */
  if (opt_cachedir)
    dnf_context_set_keep_cache (hifctx, TRUE);
  if (opt_cache_only)
    dnf_context_set_cache_age (hifctx, G_MAXUINT);

  g_key_file_set_string (treespec, "tree", "ref", self->ref);
  g_key_file_set_string_list (treespec, "tree", "packages", (const char *const*)packages, g_strv_length (packages));

  /* Some awful code to translate between JSON and GKeyFile */
  if (json_object_has_member (treedata, "install-langs"))
    {
      JsonArray *a = json_object_get_array_member (treedata, "install-langs");
      if (!set_keyfile_string_array_from_json (treespec, "tree", "install-langs", a, error))
        goto out;
    }

  /* Bind the json \"repos\" member to the hif state, which looks at the
   * enabled= member of the repos file.  By default we forcibly enable
   * only repos which are specified, ignoring the enabled= flag.
   */
  if (!json_object_has_member (treedata, "repos"))
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Treefile is missing required \"repos\" member");
      goto out;
    }

  enable_repos = json_object_get_array_member (treedata, "repos");

  if (!set_keyfile_string_array_from_json (treespec, "tree", "repos", enable_repos, error))
    goto out;

  { gboolean docs = TRUE;

    if (!_rpmostree_jsonutil_object_get_optional_boolean_member (treedata,
                                                                 "documentation",
                                                                 &docs,
                                                                 error))
      goto out;

    if (!docs)
      g_key_file_set_boolean (treespec, "tree", "documentation", FALSE);
  }

  { g_autoptr(GError) tmp_error = NULL;
    g_autoptr(RpmOstreeTreespec) treespec_value = rpmostree_treespec_new_from_keyfile (treespec, &tmp_error);
    g_assert_no_error (tmp_error);
    
    if (!rpmostree_context_setup (ctx, gs_file_get_path_cached (yumroot), "/", treespec_value,
                                  cancellable, error))
      goto out;
  }

  /* --- Downloading metadata --- */
  if (!rpmostree_context_download_metadata (ctx, cancellable, error))
    goto out;

  if (!rpmostree_context_prepare_install (ctx, &hifinstall, cancellable, error))
    goto out;

  rpmostree_print_transaction (hifctx);

  if (json_object_has_member (treedata, "add-files"))
    add_files = json_object_get_array_member (treedata, "add-files");

  /* FIXME - just do a depsolve here before we compute download requirements */
  if (!compute_checksum_from_treefile_and_goal (self, dnf_context_get_goal (hifctx),
                                                contextdir, add_files,
                                                &ret_new_inputhash, error))
    goto out;

  /* Only look for previous checksum if caller has passed *out_unmodified */
  if (self->previous_checksum && out_unmodified != NULL)
    {
      g_autoptr(GVariant) commit_v = NULL;
      g_autoptr(GVariant) commit_metadata = NULL;
      const char *previous_inputhash = NULL;
      
      if (!ostree_repo_load_variant (self->repo, OSTREE_OBJECT_TYPE_COMMIT,
                                     self->previous_checksum,
                                     &commit_v, error))
        goto out;

      commit_metadata = g_variant_get_child_value (commit_v, 0);
      if (g_variant_lookup (commit_metadata, "rpmostree.inputhash", "&s", &previous_inputhash))
        {
          if (strcmp (previous_inputhash, ret_new_inputhash) == 0)
            {
              *out_unmodified = TRUE;
              ret = TRUE;
              goto out;
            }
        }
      else
        g_print ("Previous commit found, but without rpmostree.inputhash metadata key\n");
    }

  if (opt_dry_run)
    {
      ret = TRUE;
      goto out;
    }

  /* --- Downloading packages --- */
  if (!rpmostree_context_download (ctx, hifinstall, cancellable, error))
    goto out;
  
  { g_auto(GLnxConsoleRef) console = { 0, };
    glnx_unref_object DnfState *hifstate = dnf_state_new ();

    progress_sigid = g_signal_connect (hifstate, "percentage-changed",
                                     G_CALLBACK (on_hifstate_percentage_changed), 
                                     "Installing packages:");

    glnx_console_lock (&console);

    if (!dnf_transaction_commit (dnf_context_get_transaction (hifctx),
                                 dnf_context_get_goal (hifctx),
                                 hifstate,
                                 error))
      goto out;

    g_signal_handler_disconnect (hifstate, progress_sigid);
  }
      
  ret = TRUE;
  if (out_unmodified)
    *out_unmodified = FALSE;
  gs_transfer_out_value (out_new_inputhash, &ret_new_inputhash);
 out:
  return ret;
}
コード例 #20
0
ファイル: ostree-sysroot.c プロジェクト: resin-io/ostree
static gboolean
parse_deployment (OstreeSysroot       *self,
                  const char          *boot_link,
                  OstreeDeployment   **out_deployment,
                  GCancellable        *cancellable,
                  GError             **error)
{
  gboolean ret = FALSE;
  const char *relative_boot_link;
  glnx_unref_object OstreeDeployment *ret_deployment = NULL;
  int entry_boot_version;
  int treebootserial = -1;
  int deployserial = -1;
  g_autofree char *osname = NULL;
  g_autofree char *bootcsum = NULL;
  g_autofree char *treecsum = NULL;
  glnx_fd_close int deployment_dfd = -1;
  const char *deploy_basename;
  g_autofree char *treebootserial_target = NULL;
  g_autofree char *deploy_dir = NULL;
  GKeyFile *origin = NULL;

  if (!ensure_sysroot_fd (self, error))
    goto out;
      
  if (!parse_bootlink (boot_link, &entry_boot_version,
                       &osname, &bootcsum, &treebootserial,
                       error))
    goto out;

  relative_boot_link = boot_link;
  if (*relative_boot_link == '/')
    relative_boot_link++;

  treebootserial_target = glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link,
                                                  cancellable, error);
  if (!treebootserial_target)
    goto out;

  deploy_basename = glnx_basename (treebootserial_target);

  if (!_ostree_sysroot_parse_deploy_path_name (deploy_basename,
                                               &treecsum, &deployserial, error))
    goto out;

  if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE,
                       &deployment_dfd, error))
    goto out;

  if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
                     cancellable, error))
    goto out;

  ret_deployment = ostree_deployment_new (-1, osname, treecsum, deployserial,
                                          bootcsum, treebootserial);
  if (origin)
    ostree_deployment_set_origin (ret_deployment, origin);

  ret = TRUE;
  gs_transfer_out_value (out_deployment, &ret_deployment);
 out:
  if (origin)
    g_key_file_unref (origin);
  return ret;
}
/*
 * Build up a map of files with matching basenames and similar size,
 * and use it to find apparently similar objects.
 *
 * @new_reachable_regfile_content is a Set<checksum> of new regular
 * file objects.
 *
 * Currently, @out_modified_regfile_content will be a Map<to checksum,from checksum>;
 * however in the future it would be easy to have this function return
 * multiple candidate matches.  The hard part would be changing
 * the delta compiler to iterate over all matches, determine
 * a cost for each one, then pick the best.
 */
gboolean
_ostree_delta_compute_similar_objects (OstreeRepo                 *repo,
                                       GVariant                   *from_commit,
                                       GVariant                   *to_commit,
                                       GHashTable                 *new_reachable_regfile_content,
                                       guint                       similarity_percent_threshold,
                                       GHashTable                **out_modified_regfile_content,
                                       GCancellable               *cancellable,
                                       GError                    **error)
{
  gboolean ret = FALSE;
  g_autoptr(GHashTable) ret_modified_regfile_content =
    g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_ptr_array_unref);
  g_autoptr(GPtrArray) from_sizes = NULL;
  g_autoptr(GPtrArray) to_sizes = NULL;
  guint i, j;
  guint lower;
  guint upper;

  if (!build_content_sizenames_filtered (repo, from_commit, NULL,
                                         &from_sizes,
                                         cancellable, error))
    goto out;

  if (!build_content_sizenames_filtered (repo, to_commit, new_reachable_regfile_content,
                                         &to_sizes,
                                         cancellable, error))
    goto out;
  
  /* Iterate over all newly added objects, find objects which have
   * similar basename and sizes.
   *
   * Because the arrays are sorted by size, we can maintain a `lower`
   * bound on the original (from) objects to start searching.
   */
  lower = 0;
  upper = from_sizes->len;
  for (i = 0; i < to_sizes->len; i++)
    {
      OstreeDeltaContentSizeNames *to_sizenames = to_sizes->pdata[i];
      const guint64 min_threshold = to_sizenames->size *
        (1.0-similarity_percent_threshold/100.0);
      const guint64 max_threshold = to_sizenames->size *
        (1.0+similarity_percent_threshold/100.0);

      /* Don't build candidates for the empty object */
      if (to_sizenames->size == 0)
        continue;

      for (j = lower; j < upper; j++)
        {
          OstreeDeltaContentSizeNames *from_sizenames = from_sizes->pdata[j];

          /* Don't build candidates for the empty object */
          if (from_sizenames->size == 0)
            continue;

          if (from_sizenames->size < min_threshold)
            {
              lower++;
              continue;
            }

          if (from_sizenames->size > max_threshold)
            break;

          if (!string_array_nonempty_intersection (from_sizenames->basenames, to_sizenames->basenames))
            continue;
            
          /* Only one candidate right now */
          g_hash_table_insert (ret_modified_regfile_content,
                               g_strdup (to_sizenames->checksum),
                               g_strdup (from_sizenames->checksum));
          break;
        }
    }

  ret = TRUE;
  gs_transfer_out_value (out_modified_regfile_content, &ret_modified_regfile_content);
 out:
  return ret;
}