Exemple #1
0
/**
 * ostree_repo_checkout_gc:
 * @self: Repo
 * @cancellable: Cancellable
 * @error: Error
 *
 * Call this after finishing a succession of checkout operations; it
 * will delete any currently-unused uncompressed objects from the
 * cache.
 */
gboolean
ostree_repo_checkout_gc (OstreeRepo        *self,
                         GCancellable      *cancellable,
                         GError           **error)
{
  gboolean ret = FALSE;
  g_autoptr(GHashTable) to_clean_dirs = NULL;
  GHashTableIter iter;
  gpointer key, value;

  g_mutex_lock (&self->cache_lock);
  to_clean_dirs = self->updated_uncompressed_dirs;
  self->updated_uncompressed_dirs = g_hash_table_new (NULL, NULL);
  g_mutex_unlock (&self->cache_lock);

  if (to_clean_dirs)
    g_hash_table_iter_init (&iter, to_clean_dirs);
  while (to_clean_dirs && g_hash_table_iter_next (&iter, &key, &value))
    {
      g_autoptr(GFile) objdir = NULL;
      g_autoptr(GFileEnumerator) enumerator = NULL;
      g_autofree char *objdir_name = NULL;

      objdir_name = g_strdup_printf ("%02x", GPOINTER_TO_UINT (key));
      objdir = g_file_get_child (self->uncompressed_objects_dir, objdir_name);

      enumerator = g_file_enumerate_children (objdir, "standard::name,standard::type,unix::inode,unix::nlink", 
                                              G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                              cancellable, 
                                              error);
      if (!enumerator)
        goto out;
  
      while (TRUE)
        {
          GFileInfo *file_info;
          guint32 nlinks;

          if (!gs_file_enumerator_iterate (enumerator, &file_info, NULL,
                                           cancellable, error))
            goto out;
          if (file_info == NULL)
            break;
          
          nlinks = g_file_info_get_attribute_uint32 (file_info, "unix::nlink");
          if (nlinks == 1)
            {
              g_autoptr(GFile) objpath = NULL;
              objpath = g_file_get_child (objdir, g_file_info_get_name (file_info));
              if (!gs_file_unlink (objpath, cancellable, error))
                goto out;
            }
        }
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
list_all_deployment_directories (OstreeSysroot       *self,
                                 GPtrArray          **out_deployments,
                                 GCancellable        *cancellable,
                                 GError             **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFileEnumerator *dir_enum = NULL;
    gs_unref_object GFile *deploydir = NULL;
    gs_unref_ptrarray GPtrArray *ret_deployments = NULL;
    GError *temp_error = NULL;

    deploydir = g_file_resolve_relative_path (self->path, "ostree/deploy");

    ret_deployments = g_ptr_array_new_with_free_func (g_object_unref);

    dir_enum = g_file_enumerate_children (deploydir, OSTREE_GIO_FAST_QUERYINFO,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          cancellable, &temp_error);
    if (!dir_enum)
    {
        if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
            g_clear_error (&temp_error);
            goto done;
        }
        else
        {
            g_propagate_error (error, temp_error);
            goto out;
        }
    }

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

        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;

        if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments,
                cancellable, error))
            goto out;
    }

done:
    ret = TRUE;
    ot_transfer_out_value (out_deployments, &ret_deployments);
out:
    return ret;
}
static gboolean
relabel_recursively (OstreeSePolicy *sepolicy,
                     GFile          *dir,
                     GFileInfo      *dir_info,
                     GPtrArray      *path_parts,
                     GCancellable   *cancellable,
                     GError        **error)
{
  gboolean ret = FALSE;
  g_autoptr(GFileEnumerator) direnum = NULL;

  if (!relabel_one_path (sepolicy, dir, dir_info, path_parts,
                         cancellable, error))
    goto out;

  direnum = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable, error);
  if (!direnum)
    goto out;
  
  while (TRUE)
    {
      GFileInfo *file_info;
      GFile *child;
      GFileType ftype;

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

      g_ptr_array_add (path_parts, (char*)gs_file_get_basename_cached (child));

      ftype = g_file_info_get_file_type (file_info);
      if (ftype == G_FILE_TYPE_DIRECTORY)
        {
          if (!relabel_recursively (sepolicy, child, file_info, path_parts,
                                    cancellable, error))
            goto out;
        }
      else
        {
          if (!relabel_one_path (sepolicy, child, file_info, path_parts,
                                 cancellable, error))
            goto out;
        }

      g_ptr_array_remove_index (path_parts, path_parts->len - 1);
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
enumerate_refs_recurse (OstreeRepo    *repo,
                        const char    *remote,
                        GFile         *base,
                        GFile         *dir,
                        GHashTable    *refs,
                        GCancellable  *cancellable,
                        GError       **error)
{
    gboolean ret = FALSE;
    g_autoptr(GFileEnumerator) enumerator = NULL;

    enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                            cancellable, error);
    if (!enumerator)
        goto out;

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

        if (!gs_file_enumerator_iterate (enumerator, &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)
        {
            if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error))
                goto out;
        }
        else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
        {
            if (!add_ref_to_set (remote, base, child, refs,
                                 cancellable, error))
                goto out;
        }
    }

    ret = TRUE;
out:
    return ret;
}
/* 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;
}
static gboolean
clean_yumdb_extraneous_files (GFile         *dir,
                              GCancellable  *cancellable,
                              GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFileEnumerator *direnum = NULL;

  direnum = g_file_enumerate_children (dir, "standard::name,standard::type",
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       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 (!clean_yumdb_extraneous_files (child, cancellable, error))
            goto out;
        }
      else if (strcmp (g_file_info_get_name (file_info), "var_uuid") == 0 ||
               strcmp (g_file_info_get_name (file_info), "from_repo_timestamp") == 0 ||
               strcmp (g_file_info_get_name (file_info), "from_repo_revision") == 0)
        {
          if (!g_file_delete (child, cancellable, error))
            goto out;
        }
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
find_ref_in_remotes (OstreeRepo         *self,
                     const char         *rev,
                     GFile             **out_file,
                     GError            **error)
{
    gboolean ret = FALSE;
    g_autoptr(GFileEnumerator) dir_enum = NULL;
    g_autoptr(GFile) ret_file = NULL;

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

    while (TRUE)
    {
        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;

        g_clear_object (&ret_file);
        ret_file = g_file_resolve_relative_path (child, rev);
        if (!g_file_query_exists (ret_file, NULL))
            g_clear_object (&ret_file);
        else
            break;
    }

    ret = TRUE;
    ot_transfer_out_value (out_file, &ret_file);
out:
    return ret;
}
static gboolean
dir_contains_uid_or_gid (GFile         *root,
                         guint32        id,
                         const char    *attr,
                         gboolean      *out_found_match,
                         GCancellable  *cancellable,
                         GError       **error)
{
  gboolean ret = FALSE;
  g_autoptr(GFileInfo) file_info = NULL;
  guint32 type;
  guint32 tid;
  gboolean found_match = FALSE;

  /* zero it out, just to be sure */
  *out_found_match = found_match;

  file_info = g_file_query_info (root, OSTREE_GIO_FAST_QUERYINFO,
                                 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                 cancellable, error);
  if (!file_info)
    goto out;

  type = g_file_info_get_file_type (file_info);

  switch (type)
    {
    case G_FILE_TYPE_DIRECTORY:
    case G_FILE_TYPE_SYMBOLIC_LINK:
    case G_FILE_TYPE_REGULAR:
    case G_FILE_TYPE_SPECIAL:
      tid = g_file_info_get_attribute_uint32 (file_info, attr);
      if (tid == id)
        found_match = TRUE;
      break;

    case G_FILE_TYPE_UNKNOWN:
    case G_FILE_TYPE_SHORTCUT:
    case G_FILE_TYPE_MOUNTABLE:
      g_assert_not_reached ();
      break;
    }

  /* Now recurse for dirs. */
  if (!found_match && type == G_FILE_TYPE_DIRECTORY)
    {
      g_autoptr(GFileEnumerator) dir_enum = NULL;
      g_autoptr(GFileInfo) child_info = NULL;

      dir_enum = g_file_enumerate_children (root, OSTREE_GIO_FAST_QUERYINFO, 
                                            G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                            NULL, 
                                            error);
      if (!dir_enum)
        goto out;
  
      while (TRUE)
        {
          GFileInfo *file_info;
          GFile *child;

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

          if (!dir_contains_uid_or_gid (child, id, attr, &found_match,
                                        cancellable, error))
            goto out;

          if (found_match)
            break;
        }
    }
  
  ret = TRUE;
  *out_found_match = found_match;
 out:
  return ret;
}
static gboolean
cp_internal (GFile         *src,
             GFile         *dest,
             GsCpMode       mode,
             GCancellable  *cancellable,
             GError       **error)
{
  gboolean ret = FALSE;
  GFileEnumerator *enumerator = NULL;
  GFileInfo *src_info = NULL;
  GFile *dest_child = NULL;
  int dest_dfd = -1;
  int r;

  enumerator = g_file_enumerate_children (src, "standard::type,standard::name,unix::uid,unix::gid,unix::mode",
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          cancellable, error);
  if (!enumerator)
    goto out;

  src_info = g_file_query_info (src, "standard::name,unix::mode,unix::uid,unix::gid," \
                                "time::modified,time::modified-usec,time::access,time::access-usec",
                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                cancellable, error);
  if (!src_info)
    goto out;

  do
    r = mkdir (gs_file_get_path_cached (dest), 0755);
  while (G_UNLIKELY (r == -1 && errno == EINTR));
  if (r == -1)
    {
      gs_set_error_from_errno (error, errno);
      goto out;
    }

  if (mode != GS_CP_MODE_NONE)
    {
      if (!gs_file_open_dir_fd (dest, &dest_dfd,
                                cancellable, error))
        goto out;

      do
        r = fchown (dest_dfd,
                    g_file_info_get_attribute_uint32 (src_info, "unix::uid"),
                    g_file_info_get_attribute_uint32 (src_info, "unix::gid"));
      while (G_UNLIKELY (r == -1 && errno == EINTR));
      if (r == -1)
        {
          gs_set_error_from_errno (error, errno);
          goto out;
        }

      do
        r = fchmod (dest_dfd, g_file_info_get_attribute_uint32 (src_info, "unix::mode"));
      while (G_UNLIKELY (r == -1 && errno == EINTR));

      {
        GError *temp_error = NULL;
        if (!copy_xattrs_from_file_to_fd (src, dest_dfd, cancellable, &temp_error))
          {
            if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED) ||
                g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
              {
                g_clear_error (&temp_error);
              }
            else
              {
                g_propagate_error (error, temp_error);
                goto out;
              }
          }
      }

      if (dest_dfd != -1)
        {
          (void) close (dest_dfd);
          dest_dfd = -1;
        }
    }

  while (TRUE)
    {
      GFileInfo *file_info = NULL;
      GFile *src_child = NULL;

      if (!gs_file_enumerator_iterate (enumerator, &file_info, &src_child,
                                       cancellable, error))
        goto out;
      if (!file_info)
        break;

      if (dest_child) g_object_unref (dest_child);
      dest_child = g_file_get_child (dest, g_file_info_get_name (file_info));

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
          if (!cp_internal (src_child, dest_child, mode,
                            cancellable, error))
            goto out;
        }
      else
        {
          gboolean did_link = FALSE;
          (void) unlink (gs_file_get_path_cached (dest_child));
          if (mode == GS_CP_MODE_HARDLINK)
            {
              if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1)
                {
                  if (!(errno == EMLINK || errno == EXDEV || errno == EPERM))
                    {
                      gs_set_error_from_errno (error, errno);
                      goto out;
                    }
                  /* We failed to hardlink; fall back to copying all; this will
                   * affect subsequent directory copies too.
                   */
                  mode = GS_CP_MODE_COPY_ALL;
                }
              else
                did_link = TRUE;
            }
          if (!did_link)
            {
              GFileCopyFlags copyflags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS;
              if (mode == GS_CP_MODE_COPY_ALL)
                copyflags |= G_FILE_COPY_ALL_METADATA;
              if (!g_file_copy (src_child, dest_child, copyflags,
                                cancellable, NULL, NULL, error))
                goto out;
            }
        }
    }

  ret = TRUE;
 out:
  if (dest_dfd != -1)
    (void) close (dest_dfd);
  g_clear_object (&src_info);
  g_clear_object (&enumerator);
  g_clear_object (&dest_child);
  return ret;
}
static gboolean
migrate_rpm_and_yumdb (GFile          *targetroot,
                       GFile          *yumroot,
                       GCancellable   *cancellable,
                       GError        **error)

{
  gboolean ret = FALSE;
  gs_unref_object GFile *usrbin_rpm =
    g_file_resolve_relative_path (targetroot, "usr/bin/rpm");
  gs_unref_object GFile *legacyrpm_path =
    g_file_resolve_relative_path (yumroot, "var/lib/rpm");
  gs_unref_object GFile *newrpm_path =
    g_file_resolve_relative_path (targetroot, "usr/share/rpm");
  gs_unref_object GFile *src_yum_rpmdb_indexes =
    g_file_resolve_relative_path (yumroot, "var/lib/yum");
  gs_unref_object GFile *target_yum_rpmdb_indexes =
    g_file_resolve_relative_path (targetroot, "usr/share/yumdb");
  gs_unref_object GFile *yumroot_yumlib =
    g_file_get_child (yumroot, "var/lib/yum");
  gs_unref_object GFileEnumerator *direnum = NULL;

  direnum = g_file_enumerate_children (legacyrpm_path, "standard::name",
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       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);

      if (g_str_has_prefix (name, "__db.") ||
          strcmp (name, ".dbenv.lock") == 0 ||
          strcmp (name, ".rpm.lock") == 0)
        {
          if (!gs_file_unlink (child, cancellable, error))
            goto out;
        }
    }

  (void) g_file_enumerator_close (direnum, cancellable, error);
    
  g_print ("Placing RPM db in /usr/share/rpm\n");
  if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error))
    goto out;
    
  /* Move the yum database to usr/share/yumdb; disabled for now due
   * to bad conflict with OSTree's current
   * one-http-request-per-file.
   */
#if 0
  if (g_file_query_exists (src_yum_rpmdb_indexes, NULL))
    {
      g_print ("Moving %s to %s\n", gs_file_get_path_cached (src_yum_rpmdb_indexes),
               gs_file_get_path_cached (target_yum_rpmdb_indexes));
      if (!gs_file_rename (src_yum_rpmdb_indexes, target_yum_rpmdb_indexes,
                           cancellable, error))
        goto out;
        
      if (!clean_yumdb_extraneous_files (target_yum_rpmdb_indexes, cancellable, error))
        goto out;
    }
#endif

  /* Remove /var/lib/yum; we don't want it here. */
  if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error))
    goto out;

  ret = TRUE;
 out:
  return ret;
}
static gboolean
workaround_selinux_cross_labeling_recurse (GFile         *dir,
                                           GCancellable  *cancellable,
                                           GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFileEnumerator *direnum = NULL;

  direnum = g_file_enumerate_children (dir, "standard::name,standard::type,time::modified,time::access",
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable, error);
  if (!direnum)
    goto out;

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

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

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
          if (!workaround_selinux_cross_labeling_recurse (child, cancellable, error))
            goto out;
        }
      else if (g_str_has_suffix (name, ".bin"))
        {
          const char *lastdot;
          gs_free char *nonbin_name = NULL;
          gs_unref_object GFile *nonbin_path = NULL;
          guint64 mtime = g_file_info_get_attribute_uint64 (file_info, "time::modified");
          guint64 atime = g_file_info_get_attribute_uint64 (file_info, "time::access");
          struct utimbuf times;

          lastdot = strrchr (name, '.');
          g_assert (lastdot);

          nonbin_name = g_strndup (name, lastdot - name);
          nonbin_path = g_file_get_child (dir, nonbin_name);

          times.actime = (time_t)atime;
          times.modtime = ((time_t)mtime) + 60;

          g_print ("Setting mtime of '%s' to newer than '%s'\n",
                   gs_file_get_path_cached (nonbin_path),
                   gs_file_get_path_cached (child));
          if (utime (gs_file_get_path_cached (nonbin_path), &times) == -1)
            {
              int errsv = errno;
              g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "utime(%s): %s", gs_file_get_path_cached (nonbin_path),
                           strerror (errsv));
              goto out;
            }
        }
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
convert_var_to_tmpfiles_d (GOutputStream *tmpfiles_out,
                           GFile         *yumroot,
                           GFile         *dir,
                           GCancellable  *cancellable,
                           GError       **error)
{
  gboolean ret = FALSE;
  gs_unref_object GFileEnumerator *direnum = NULL;
  gsize bytes_written;

  direnum = g_file_enumerate_children (dir, "standard::name,standard::type,unix::mode,standard::symlink-target,unix::uid,unix::gid",
                                       G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                       cancellable, error);
  if (!direnum)
    {
      g_prefix_error (error, "Enumerating /var in '%s'", gs_file_get_path_cached (dir));
      goto out;
    }

  while (TRUE)
    {
      GFileInfo *file_info;
      GFile *child;
      GString *tmpfiles_d_buf;
      gs_free char *tmpfiles_d_line = NULL;
      char filetype_c;
      gs_free char *relpath = NULL;

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

      switch (g_file_info_get_file_type (file_info))
        {
        case G_FILE_TYPE_DIRECTORY:
          filetype_c = 'd';
          break;
        case G_FILE_TYPE_SYMBOLIC_LINK:
          filetype_c = 'L';
          break;
        default:
          g_print ("Ignoring non-directory/non-symlink '%s'\n",
                   gs_file_get_path_cached (child));
          continue;
        }

      tmpfiles_d_buf = g_string_new ("");
      g_string_append_c (tmpfiles_d_buf, filetype_c);
      g_string_append_c (tmpfiles_d_buf, ' ');

      relpath = g_file_get_relative_path (yumroot, child);
      g_assert (relpath);
      
      g_string_append_c (tmpfiles_d_buf, '/');
      g_string_append (tmpfiles_d_buf, relpath);

      if (filetype_c == 'd')
        {
          guint mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
          mode &= ~S_IFMT;
          g_string_append_printf (tmpfiles_d_buf, " 0%02o", mode);
          g_string_append_printf (tmpfiles_d_buf, " %d %d - -",
                                  g_file_info_get_attribute_uint32 (file_info, "unix::uid"),
                                  g_file_info_get_attribute_uint32 (file_info, "unix::gid"));

          if (!convert_var_to_tmpfiles_d (tmpfiles_out, yumroot, child,
                                          cancellable, error))
            goto out;
        }
      else
        {
          g_string_append (tmpfiles_d_buf, " - - - - ");
          g_string_append (tmpfiles_d_buf, g_file_info_get_symlink_target (file_info));
        }

      g_string_append_c (tmpfiles_d_buf, '\n');

      tmpfiles_d_line = g_string_free (tmpfiles_d_buf, FALSE);

      if (!g_output_stream_write_all (tmpfiles_out, tmpfiles_d_line,
                                      strlen (tmpfiles_d_line), &bytes_written,
                                      cancellable, error))
        goto out;
    }

  ret = TRUE;
 out:
  return ret;
}
static gboolean
_ostree_bootloader_grub2_query (OstreeBootloader *bootloader,
                                gboolean         *out_is_active,
                                GCancellable     *cancellable,
                                GError          **error)
{
  gboolean ret = FALSE;
  OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader);
  gs_unref_object GFile* efi_basedir = NULL;
  gs_unref_object GFileInfo *file_info = NULL;

  if (g_file_query_exists (self->config_path_bios, NULL))
    {
      *out_is_active = TRUE;
      ret = TRUE;
      goto out;
    }

  efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI");

  g_clear_object (&self->config_path_efi);

  if (g_file_query_exists (efi_basedir, NULL))
    {
      gs_unref_object GFileEnumerator *direnum = NULL;

      direnum = g_file_enumerate_children (efi_basedir, OSTREE_GIO_FAST_QUERYINFO,
                                           G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                           cancellable, error);
      if (!direnum)
        goto out;
  
      while (TRUE)
        {
          GFileInfo *file_info;
          const char *fname;
          gs_free char *subdir_grub_cfg = NULL;

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

          fname = g_file_info_get_name (file_info);
          if (strcmp (fname, "BOOT") == 0)
            continue;

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

          subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); 
          
          if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS))
            {
              self->config_path_efi = g_file_new_for_path (subdir_grub_cfg);
              break;
            }
        }

      if (self->config_path_efi)
        {
          self->is_efi = TRUE;
          *out_is_active = TRUE;
          ret = TRUE;
          goto out;
        }
    }
  else
    *out_is_active = FALSE;

  ret = TRUE;
 out:
  return ret;
}
Exemple #14
0
/*
 * checkout_tree_at:
 * @self: Repo
 * @mode: Options controlling all files
 * @overwrite_mode: Whether or not to overwrite files
 * @destination_parent_fd: Place tree here
 * @destination_name: Use this name for tree
 * @source: Source tree
 * @source_info: Source info
 * @cancellable: Cancellable
 * @error: Error
 *
 * Like ostree_repo_checkout_tree(), but check out @source into the
 * relative @destination_name, located by @destination_parent_fd.
 */
static gboolean
checkout_tree_at (OstreeRepo                        *self,
                  OstreeRepoCheckoutOptions         *options,
                  int                                destination_parent_fd,
                  const char                        *destination_name,
                  OstreeRepoFile                    *source,
                  GFileInfo                         *source_info,
                  GCancellable                      *cancellable,
                  GError                           **error)
{
  gboolean ret = FALSE;
  gboolean did_exist = FALSE;
  int destination_dfd = -1;
  int res;
  g_autoptr(GVariant) xattrs = NULL;
  g_autoptr(GFileEnumerator) dir_enum = NULL;

  /* Create initially with mode 0700, then chown/chmod only when we're
   * done.  This avoids anyone else being able to operate on partially
   * constructed dirs.
   */
  do
    res = mkdirat (destination_parent_fd, destination_name, 0700);
  while (G_UNLIKELY (res == -1 && errno == EINTR));
  if (res == -1)
    {
      if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES)
        did_exist = TRUE;
      else
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE,
                       &destination_dfd, error))
    goto out;

  /* Set the xattrs now, so any derived labeling works */
  if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER)
    {
      if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error))
        goto out;

      if (xattrs)
        {
          if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error))
            goto out;
        }
    }

  if (g_file_info_get_file_type (source_info) != G_FILE_TYPE_DIRECTORY)
    {
      ret = checkout_one_file_at (self, options,
                                  (GFile *) source,
                                  source_info,
                                  destination_dfd,
                                  g_file_info_get_name (source_info),
                                  cancellable, error);
      goto out;
    }
  dir_enum = g_file_enumerate_children ((GFile*)source,
                                        OSTREE_GIO_FAST_QUERYINFO, 
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, 
                                        error);
  if (!dir_enum)
    goto out;

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

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

      name = g_file_info_get_name (file_info);

      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
        {
          if (!checkout_tree_at (self, options,
                                 destination_dfd, name,
                                 (OstreeRepoFile*)src_child, file_info,
                                 cancellable, error))
            goto out;
        }
      else
        {
          if (!checkout_one_file_at (self, options,
                                     src_child, file_info,
                                     destination_dfd, name,
                                     cancellable, error))
            goto out;
        }
    }

  /* We do fchmod/fchown last so that no one else could access the
   * partially created directory and change content we're laying out.
   */
  if (!did_exist)
    {
      do
        res = fchmod (destination_dfd,
                      g_file_info_get_attribute_uint32 (source_info, "unix::mode"));
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

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

  /* Set directory mtime to 0, so that it is constant for all checkouts.
   * Must be done after setting permissions and creating all children.
   */
  if (!did_exist)
    {
      const struct timespec times[2] = { { 0, UTIME_OMIT }, { 0, } };
      do
        res = futimens (destination_dfd, times);
      while (G_UNLIKELY (res == -1 && errno == EINTR));
      if (G_UNLIKELY (res == -1))
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  if (fsync_is_enabled (self, options))
    {
      if (fsync (destination_dfd) == -1)
        {
          glnx_set_error_from_errno (error);
          goto out;
        }
    }

  ret = TRUE;
 out:
  if (destination_dfd != -1)
    (void) close (destination_dfd);
  return ret;
}
Exemple #15
0
/**
 * ostree_repo_list_refs:
 * @self: Repo
 * @refspec_prefix: (allow-none): Only list refs which match this prefix
 * @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum
 * @cancellable: Cancellable
 * @error: Error
 *
 * If @refspec_prefix is %NULL, list all local and remote refspecs,
 * with their current values in @out_all_refs.  Otherwise, only list
 * refspecs which have @refspec_prefix as a prefix.
 */
gboolean
ostree_repo_list_refs (OstreeRepo       *self,
                       const char       *refspec_prefix,
                       GHashTable      **out_all_refs,
                       GCancellable     *cancellable,
                       GError          **error)
{
    gboolean ret = FALSE;
    g_autoptr(GHashTable) ret_all_refs = NULL;
    g_autofree char *remote = NULL;
    g_autofree char *ref_prefix = NULL;

    ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

    if (refspec_prefix)
    {
        g_autoptr(GFile) dir = NULL;
        g_autoptr(GFile) child = NULL;
        g_autoptr(GFileInfo) info = NULL;

        if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
            goto out;

        if (remote)
            dir = g_file_get_child (self->remote_heads_dir, remote);
        else
            dir = g_object_ref (self->local_heads_dir);

        child = g_file_resolve_relative_path (dir, ref_prefix);
        if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
                                              &info, cancellable, error))
            goto out;

        if (info)
        {
            if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
            {
                if (!enumerate_refs_recurse (self, remote, child, child,
                                             ret_all_refs,
                                             cancellable, error))
                    goto out;
            }
            else
            {
                if (!add_ref_to_set (remote, dir, child, ret_all_refs,
                                     cancellable, error))
                    goto out;
            }
        }
    }
    else
    {
        g_autoptr(GFileEnumerator) remote_enumerator = NULL;

        if (!enumerate_refs_recurse (self, NULL, self->local_heads_dir, self->local_heads_dir,
                                     ret_all_refs,
                                     cancellable, error))
            goto out;

        remote_enumerator = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
                            0,
                            cancellable, error);

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

            if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child,
                                             cancellable, error))
                goto out;
            if (!info)
                break;

            name = g_file_info_get_name (info);
            if (!enumerate_refs_recurse (self, name, child, child,
                                         ret_all_refs,
                                         cancellable, error))
                goto out;
        }
    }

    ret = TRUE;
    ot_transfer_out_value (out_all_refs, &ret_all_refs);
out:
    return ret;
}
static gboolean
list_all_boot_directories (OstreeSysroot       *self,
                           GPtrArray          **out_bootdirs,
                           GCancellable        *cancellable,
                           GError             **error)
{
    gboolean ret = FALSE;
    gs_unref_object GFileEnumerator *dir_enum = NULL;
    gs_unref_object GFile *boot_ostree = NULL;
    gs_unref_ptrarray GPtrArray *ret_bootdirs = NULL;
    GError *temp_error = NULL;

    boot_ostree = g_file_resolve_relative_path (self->path, "boot/ostree");

    ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref);

    dir_enum = g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          cancellable, &temp_error);
    if (!dir_enum)
    {
        if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
            g_clear_error (&temp_error);
            goto done;
        }
        else
        {
            g_propagate_error (error, temp_error);
            goto out;
        }
    }

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

        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;

        /* Only look at directories ending in -CHECKSUM; nothing else
         * should be in here, but let's be conservative.
         */
        name = g_file_info_get_name (file_info);
        if (!parse_bootdir_name (name, NULL, NULL))
            continue;

        g_ptr_array_add (ret_bootdirs, g_object_ref (child));
    }

done:
    ret = TRUE;
    ot_transfer_out_value (out_bootdirs, &ret_bootdirs);
out:
    return ret;
}
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;
}
gboolean
_ostree_sysroot_list_deployment_dirs_for_os (GFile               *osdir,
        GPtrArray           *inout_deployments,
        GCancellable        *cancellable,
        GError             **error)
{
    gboolean ret = FALSE;
    const char *osname = gs_file_get_basename_cached (osdir);
    gs_unref_object GFileEnumerator *dir_enum = NULL;
    gs_unref_object GFile *osdeploy_dir = NULL;
    GError *temp_error = NULL;

    osdeploy_dir = g_file_get_child (osdir, "deploy");

    dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                          NULL, &temp_error);
    if (!dir_enum)
    {
        if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
            g_clear_error (&temp_error);
            goto done;
        }
        else
        {
            g_propagate_error (error, temp_error);
            goto out;
        }
    }

    while (TRUE)
    {
        const char *name;
        GFileInfo *file_info = NULL;
        GFile *child = NULL;
        gs_unref_object OstreeDeployment *deployment = NULL;
        gs_free char *csum = NULL;
        gint deployserial;

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

        name = g_file_info_get_name (file_info);

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

        if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error))
            goto out;

        deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1);
        g_ptr_array_add (inout_deployments, g_object_ref (deployment));
    }

done:
    ret = TRUE;
out:
    return ret;
}
static gboolean
migrate_rpm_and_yumdb (GFile          *targetroot,
                       GFile          *yumroot,
                       GCancellable   *cancellable,
                       GError        **error)

{
    gboolean ret = FALSE;
    gs_unref_object GFile *usrbin_rpm =
        g_file_resolve_relative_path (targetroot, "usr/bin/rpm");
    gs_unref_object GFile *legacyrpm_path =
        g_file_resolve_relative_path (yumroot, "var/lib/rpm");
    gs_unref_object GFile *newrpm_path =
        g_file_resolve_relative_path (targetroot, "usr/share/rpm");
    gs_unref_object GFile *src_yum_rpmdb_indexes =
        g_file_resolve_relative_path (yumroot, "var/lib/yum");
    gs_unref_object GFile *target_yum_rpmdb_indexes =
        g_file_resolve_relative_path (targetroot, "usr/share/yumdb");
    gs_unref_object GFile *yumroot_yumlib =
        g_file_get_child (yumroot, "var/lib/yum");
    gs_unref_object GFileEnumerator *direnum = NULL;

    direnum = g_file_enumerate_children (legacyrpm_path, "standard::name",
                                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                         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);

        if (g_str_has_prefix (name, "__db.") ||
                strcmp (name, ".dbenv.lock") == 0 ||
                strcmp (name, ".rpm.lock") == 0)
        {
            if (!gs_file_unlink (child, cancellable, error))
                goto out;
        }
    }

    (void) g_file_enumerator_close (direnum, cancellable, error);

    g_print ("Placing RPM db in /usr/share/rpm\n");
    if (!gs_file_rename (legacyrpm_path, newrpm_path, cancellable, error))
        goto out;

    /* Remove /var/lib/yum; we don't want it here. */
    if (!gs_shutil_rm_rf (yumroot_yumlib, cancellable, error))
        goto out;

    ret = TRUE;
out:
    return ret;
}
/**
 * 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;
}