Пример #1
0
/**
 * ostree_diff_dirs:
 * @flags: Flags
 * @a: First directory path, or %NULL
 * @b: First directory path
 * @modified: (element-type OstreeDiffItem): Modified files
 * @removed: (element-type Gio.File): Removed files
 * @added: (element-type Gio.File): Added files
 * @cancellable: Cancellable
 * @error: Error
 *
 * Compute the difference between directory @a and @b as 3 separate
 * sets of #OstreeDiffItem in @modified, @removed, and @added.
 */
gboolean
ostree_diff_dirs (OstreeDiffFlags flags,
                  GFile          *a,
                  GFile          *b,
                  GPtrArray      *modified,
                  GPtrArray      *removed,
                  GPtrArray      *added,
                  GCancellable   *cancellable,
                  GError        **error)
{
  return ostree_diff_dirs_with_options (flags, a, b, modified,
                                        removed, added, NULL,
                                        cancellable, error);
}
Пример #2
0
gboolean
ostree_builtin_diff (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
  gboolean ret = FALSE;
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(OstreeRepo) repo = NULL;
  const char *src;
  const char *target;
  g_autofree char *src_prev = NULL;
  g_autoptr(GFile) srcf = NULL;
  g_autoptr(GFile) targetf = NULL;
  g_autoptr(GPtrArray) modified = NULL;
  g_autoptr(GPtrArray) removed = NULL;
  g_autoptr(GPtrArray) added = NULL;

  context = g_option_context_new ("REV TARGETDIR");

  if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error))
    goto out;

  if (argc < 2)
    {
      gchar *help = g_option_context_get_help (context, TRUE, NULL);
      g_printerr ("%s\n", help);
      g_free (help);
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                               "REV must be specified");
      goto out;
    }

  if (argc == 2)
    {
      src_prev = g_strconcat (argv[1], "^", NULL);
      src = src_prev;
      target = argv[1];
    }
  else
    {
      src = argv[1];
      target = argv[2];
    }

  if (!opt_stats && !opt_fs_diff)
    opt_fs_diff = TRUE;

  if (opt_fs_diff)
    {
      OstreeDiffFlags diff_flags = OSTREE_DIFF_FLAGS_NONE; 

      if (opt_no_xattrs)
        diff_flags |= OSTREE_DIFF_FLAGS_IGNORE_XATTRS;
      
      if (!parse_file_or_commit (repo, src, &srcf, cancellable, error))
        goto out;
      if (!parse_file_or_commit (repo, target, &targetf, cancellable, error))
        goto out;

      modified = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_diff_item_unref);
      removed = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
      added = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);

      OstreeDiffDirsOptions diff_opts = { opt_owner_uid, opt_owner_gid };
      if (!ostree_diff_dirs_with_options (diff_flags, srcf, targetf, modified, removed,
                                          added, &diff_opts, cancellable, error))
        goto out;

      ostree_diff_print (srcf, targetf, modified, removed, added);
    }

  if (opt_stats)
    {
      g_autoptr(GHashTable) reachable_a = NULL;
      g_autoptr(GHashTable) reachable_b = NULL;
      g_autoptr(GHashTable) reachable_intersection = NULL;
      g_autofree char *rev_a = NULL;
      g_autofree char *rev_b = NULL;
      g_autofree char *size = NULL;
      guint a_size;
      guint b_size;
      guint64 total_common;

      if (!ostree_repo_resolve_rev (repo, src, FALSE, &rev_a, error))
        goto out;
      if (!ostree_repo_resolve_rev (repo, target, FALSE, &rev_b, error))
        goto out;

      if (!ostree_repo_traverse_commit (repo, rev_a, 0, &reachable_a, cancellable, error))
        goto out;
      if (!ostree_repo_traverse_commit (repo, rev_b, 0, &reachable_b, cancellable, error))
        goto out;

      a_size = g_hash_table_size (reachable_a);
      b_size = g_hash_table_size (reachable_b);
      g_print ("[A] Object Count: %u\n", a_size);
      g_print ("[B] Object Count: %u\n", b_size);

      reachable_intersection = reachable_set_intersect (reachable_a, reachable_b);

      g_print ("Common Object Count: %u\n", g_hash_table_size (reachable_intersection));

      if (!object_set_total_size (repo, reachable_intersection, &total_common,
                                  cancellable, error))
        goto out;
      size = g_format_size_full (total_common, 0);
      g_print ("Common Object Size: %s\n", size);
    }

  ret = TRUE;
 out:
  return ret;
}
Пример #3
0
/**
 * ostree_diff_dirs_with_options:
 * @flags: Flags
 * @a: First directory path, or %NULL
 * @b: First directory path
 * @modified: (element-type OstreeDiffItem): Modified files
 * @removed: (element-type Gio.File): Removed files
 * @added: (element-type Gio.File): Added files
 * @cancellable: Cancellable
 * @options: (allow-none): Options
 * @error: Error
 *
 * Compute the difference between directory @a and @b as 3 separate
 * sets of #OstreeDiffItem in @modified, @removed, and @added.
 */
gboolean
ostree_diff_dirs_with_options (OstreeDiffFlags        flags,
                               GFile                 *a,
                               GFile                 *b,
                               GPtrArray             *modified,
                               GPtrArray             *removed,
                               GPtrArray             *added,
                               OstreeDiffDirsOptions *options,
                               GCancellable          *cancellable,
                               GError               **error)
{
  gboolean ret = FALSE;
  GError *temp_error = NULL;
  g_autoptr(GFileEnumerator) dir_enum = NULL;
  g_autoptr(GFile) child_a = NULL;
  g_autoptr(GFile) child_b = NULL;
  g_autoptr(GFileInfo) child_a_info = NULL;
  g_autoptr(GFileInfo) child_b_info = NULL;
  OstreeDiffDirsOptions default_opts = OSTREE_DIFF_DIRS_OPTIONS_INIT;

  if (!options)
    options = &default_opts;

  /* If we're diffing versus a repo, and either of them have xattrs disabled,
   * then disable for both.
   */
  OstreeRepo *repo;
  if (OSTREE_IS_REPO_FILE (a))
    repo = ostree_repo_file_get_repo ((OstreeRepoFile*)a);
  else if (OSTREE_IS_REPO_FILE (b))
    repo = ostree_repo_file_get_repo ((OstreeRepoFile*)b);
  else
    repo = NULL;
  if (repo != NULL && repo->disable_xattrs)
    flags |= OSTREE_DIFF_FLAGS_IGNORE_XATTRS;

  if (a == NULL)
    {
      if (!diff_add_dir_recurse (b, added, cancellable, error))
        goto out;

      ret = TRUE;
      goto out;
    }

  child_a_info = g_file_query_info (a, OSTREE_GIO_FAST_QUERYINFO,
                                    G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                    cancellable, error);
  if (!child_a_info)
    goto out;

  child_b_info = g_file_query_info (b, OSTREE_GIO_FAST_QUERYINFO,
                                    G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                    cancellable, error);
  if (!child_b_info)
    goto out;

  /* Fast path test for unmodified directories */
  if (g_file_info_get_file_type (child_a_info) == G_FILE_TYPE_DIRECTORY
      && g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY
      && OSTREE_IS_REPO_FILE (a)
      && OSTREE_IS_REPO_FILE (b))
    {
      OstreeRepoFile *a_repof = (OstreeRepoFile*) a;
      OstreeRepoFile *b_repof = (OstreeRepoFile*) b;
      
      if (strcmp (ostree_repo_file_tree_get_contents_checksum (a_repof),
                  ostree_repo_file_tree_get_contents_checksum (b_repof)) == 0)
        {
          ret = TRUE;
          goto out;
        }
    }

  g_clear_object (&child_a_info);
  g_clear_object (&child_b_info);

  dir_enum = g_file_enumerate_children (a, OSTREE_GIO_FAST_QUERYINFO, 
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, error);
  if (!dir_enum)
    goto out;

  while ((child_a_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
    {
      const char *name;
      GFileType child_a_type;
      GFileType child_b_type;

      name = g_file_info_get_name (child_a_info);

      g_clear_object (&child_a);
      child_a = g_file_get_child (a, name);
      child_a_type = g_file_info_get_file_type (child_a_info);

      g_clear_object (&child_b);
      child_b = g_file_get_child (b, name);

      g_clear_object (&child_b_info);
      child_b_info = g_file_query_info (child_b, OSTREE_GIO_FAST_QUERYINFO,
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable,
                                        &temp_error);
      if (!child_b_info)
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_ptr_array_add (removed, g_object_ref (child_a));
            }
          else
            {
              g_propagate_error (error, temp_error);
              goto out;
            }
        }
      else
        {
          if (options->owner_uid >= 0)
            g_file_info_set_attribute_uint32 (child_b_info, "unix::uid", options->owner_uid);
          if (options->owner_gid >= 0)
            g_file_info_set_attribute_uint32 (child_b_info, "unix::gid", options->owner_gid);

          child_b_type = g_file_info_get_file_type (child_b_info);
          if (child_a_type != child_b_type)
            {
              OstreeDiffItem *diff_item = diff_item_new (child_a, child_a_info,
                                                   child_b, child_b_info, NULL, NULL);
              
              g_ptr_array_add (modified, diff_item);
            }
          else
            {
              OstreeDiffItem *diff_item = NULL;

              if (!diff_files (flags, child_a, child_a_info, child_b, child_b_info, &diff_item,
                               cancellable, error))
                goto out;
              
              if (diff_item)
                g_ptr_array_add (modified, diff_item); /* Transfer ownership */

              if (child_a_type == G_FILE_TYPE_DIRECTORY)
                {
                  if (!ostree_diff_dirs_with_options (flags, child_a, child_b, modified,
                                                      removed, added, options,
                                                      cancellable, error))
                    goto out;
                }
            }
        }
      
      g_clear_object (&child_a_info);
    }
  if (temp_error != NULL)
    {
      g_propagate_error (error, temp_error);
      goto out;
    }

  g_clear_object (&dir_enum);
  dir_enum = g_file_enumerate_children (b, OSTREE_GIO_FAST_QUERYINFO, 
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable, error);
  if (!dir_enum)
    goto out;

  g_clear_object (&child_b_info);
  while ((child_b_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
    {
      const char *name;

      name = g_file_info_get_name (child_b_info);

      g_clear_object (&child_a);
      child_a = g_file_get_child (a, name);

      g_clear_object (&child_b);
      child_b = g_file_get_child (b, name);

      g_clear_object (&child_a_info);
      child_a_info = g_file_query_info (child_a, OSTREE_GIO_FAST_QUERYINFO,
                                        G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
                                        cancellable,
                                        &temp_error);
      if (!child_a_info)
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_ptr_array_add (added, g_object_ref (child_b));
              if (g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY)
                {
                  if (!diff_add_dir_recurse (child_b, added, cancellable, error))
                    goto out;
                }
            }
          else
            {
              g_propagate_error (error, temp_error);
              goto out;
            }
        }
      g_clear_object (&child_b_info);
    }
  if (temp_error != NULL)
    {
      g_propagate_error (error, temp_error);
      goto out;
    }

  ret = TRUE;
 out:
  return ret;
}