Exemplo n.º 1
0
static gboolean
maybe_prune_loose_object (OtPruneData        *data,
                          OstreeRepoPruneFlags    flags,
                          const char         *checksum,
                          OstreeObjectType    objtype,
                          GCancellable       *cancellable,
                          GError            **error)
{
  g_autoptr(GVariant) key = NULL;

  key = ostree_object_name_serialize (checksum, objtype);

  if (!g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
    {
      g_debug ("Pruning unneeded object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE))
        {
          guint64 storage_size = 0;

          if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!prune_commitpartial_file (data->repo, checksum, cancellable, error))
                return FALSE;
            }

          if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
                                                      &storage_size, cancellable, error))
            return FALSE;

          if (!ostree_repo_delete_object (data->repo, objtype, checksum,
                                          cancellable, error))
            return FALSE;

          data->freed_bytes += storage_size;
        }
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_unreachable_meta++;
      else
        data->n_unreachable_content++;
    }
  else
    {
      g_debug ("Keeping needed object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_reachable_meta++;
      else
        data->n_reachable_content++;
    }

  return TRUE;
}
Exemplo n.º 2
0
char *
ostree_get_relative_object_path (const char         *checksum,
                                 OstreeObjectType    type,
                                 gboolean            compressed)
{
  GString *path;

  g_assert (strlen (checksum) == 64);

  path = g_string_new ("objects/");

  g_string_append_len (path, checksum, 2);
  g_string_append_c (path, '/');
  g_string_append (path, checksum + 2);
  g_string_append_c (path, '.');
  g_string_append (path, ostree_object_type_to_string (type));
  if (!OSTREE_OBJECT_TYPE_IS_META (type) && compressed)
    g_string_append (path, "z");

  return g_string_free (path, FALSE);
}
Exemplo n.º 3
0
void
ot_dump_object (OstreeObjectType   objtype,
                const char        *checksum,
                GVariant          *variant,
                OstreeDumpFlags    flags)
{
  g_print ("%s %s\n", ostree_object_type_to_string (objtype), checksum);

  if (flags & OSTREE_DUMP_RAW)
    {
      ot_dump_variant (variant);
      return;
    }

  switch (objtype)
  {
    case OSTREE_OBJECT_TYPE_COMMIT:
      dump_commit (variant, flags);
      break;
    /* TODO: Others could be implemented here */
    default:
      break;
  }
}
Exemplo n.º 4
0
static gboolean
fsck_one_object (OstreeRepo            *repo,
                 const char            *checksum,
                 OstreeObjectType       objtype,
                 GHashTable            *object_parents,
                 GVariant              *key,
                 gboolean              *out_found_corruption,
                 GCancellable          *cancellable,
                 GError               **error)
{
  g_autoptr(GError) temp_error = NULL;
  if (!ostree_repo_fsck_object (repo, objtype, checksum, cancellable, &temp_error))
    {
      gboolean object_missing = FALSE;
      g_auto(GStrv) parent_commits = NULL;
      g_autofree char *parent_commits_str = NULL;

      if (object_parents)
        {
          parent_commits = ostree_repo_traverse_parents_get_commits (object_parents, key);
          parent_commits_str = g_strjoinv (", ", parent_commits);
        }

      if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
        {
          g_clear_error (&temp_error);
          if (parent_commits_str)
            g_printerr ("Object missing in commits %s: %s.%s\n", parent_commits_str, checksum,
                        ostree_object_type_to_string (objtype));
          else
            g_printerr ("Object missing: %s.%s\n", checksum,
                        ostree_object_type_to_string (objtype));
          object_missing = TRUE;
        }
      else
        {
          if (parent_commits_str)
            g_prefix_error (&temp_error, "In commits %s: ", parent_commits_str);

          if (opt_delete)
            {
              g_printerr ("%s\n", temp_error->message);
              (void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL);
              object_missing = TRUE;
            }
          else if (opt_all)
            {
              *out_found_corruption = TRUE;
              g_printerr ("%s\n", temp_error->message);
            }
          else
            {
              g_propagate_error (error, g_steal_pointer (&temp_error));
              return FALSE;
            }
        }

      if (object_missing)
        {
          *out_found_corruption = TRUE;

          if (parent_commits != NULL && objtype != OSTREE_OBJECT_TYPE_COMMIT)
            {
              int i;

              /* The commit was missing or deleted, mark the commit partial */
              for (i = 0; parent_commits[i] != NULL; i++)
                {
                  const char *parent_commit = parent_commits[i];
                  OstreeRepoCommitState state;
                  if (!ostree_repo_load_commit (repo, parent_commit, NULL,
                                                &state, error))
                    return FALSE;
                  if ((state & OSTREE_REPO_COMMIT_STATE_PARTIAL) == 0)
                    {
                      g_printerr ("Marking commit as partial: %s\n", parent_commit);
                      if (!ostree_repo_mark_commit_partial (repo, parent_commit, TRUE, error))
                        return FALSE;
                    }
                }
            }
        }
    }

  return TRUE;
}
Exemplo n.º 5
0
static gboolean
fsck_reachable_objects_from_commits (OtFsckData            *data,
                                     GHashTable            *commits,
                                     GCancellable          *cancellable,
                                     GError               **error)
{
  gboolean ret = FALSE;
  GHashTableIter hash_iter;
  gpointer key, value;
  ot_lhash GHashTable *reachable_objects = NULL;
  ot_lobj GInputStream *input = NULL;
  ot_lobj GFileInfo *file_info = NULL;
  ot_lvariant GVariant *xattrs = NULL;
  ot_lvariant GVariant *metadata = NULL;
  ot_lfree guchar *computed_csum = NULL;
  ot_lfree char *tmp_checksum = NULL;

  reachable_objects = ostree_traverse_new_reachable ();

  g_hash_table_iter_init (&hash_iter, commits);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      GVariant *serialized_key = key;
      const char *checksum;
      OstreeObjectType objtype;

      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);

      g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT);

      if (!ostree_traverse_commit (data->repo, checksum, 0, reachable_objects,
                                   cancellable, error))
        goto out;
    }

  g_hash_table_iter_init (&hash_iter, reachable_objects);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      GVariant *serialized_key = key;
      const char *checksum;
      OstreeObjectType objtype;

      ostree_object_name_deserialize (serialized_key, &checksum, &objtype);

      g_clear_object (&input);
      g_clear_object (&file_info);
      g_clear_pointer (&xattrs, (GDestroyNotify) g_variant_unref);

      if (objtype == OSTREE_OBJECT_TYPE_COMMIT
          || objtype == OSTREE_OBJECT_TYPE_DIR_TREE 
          || objtype == OSTREE_OBJECT_TYPE_DIR_META)
        {
          g_clear_pointer (&metadata, (GDestroyNotify) g_variant_unref);
          if (!ostree_repo_load_variant (data->repo, objtype,
                                         checksum, &metadata, error))
            {
              g_prefix_error (error, "Loading metadata object %s: ", checksum);
              goto out;
            }

          if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!ostree_validate_structureof_commit (metadata, error))
                {
                  g_prefix_error (error, "While validating commit metadata '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
            {
              if (!ostree_validate_structureof_dirtree (metadata, error))
                {
                  g_prefix_error (error, "While validating directory tree '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_META)
            {
              if (!ostree_validate_structureof_dirmeta (metadata, error))
                {
                  g_prefix_error (error, "While validating directory metadata '%s': ", checksum);
                  goto out;
                }
            }
          else
            g_assert_not_reached ();
          
          input = g_memory_input_stream_new_from_data (g_variant_get_data (metadata),
                                                       g_variant_get_size (metadata),
                                                       NULL);
        }
      else if (objtype == OSTREE_OBJECT_TYPE_FILE)
        {
          guint32 mode;
          if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info,
                                      &xattrs, cancellable, error))
            {
              g_prefix_error (error, "Loading file object %s: ", checksum);
              goto out;
            }

          mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
          if (!ostree_validate_structureof_file_mode (mode, error))
            {
              g_prefix_error (error, "While validating file '%s': ", checksum);
              goto out;
            }
        }
      else
        {
          g_assert_not_reached ();
        }

      g_free (computed_csum);
      if (!ostree_checksum_file_from_input (file_info, xattrs, input,
                                            objtype, &computed_csum,
                                            cancellable, error))
        goto out;

      g_free (tmp_checksum);
      tmp_checksum = ostree_checksum_from_bytes (computed_csum);
      if (strcmp (checksum, tmp_checksum) != 0)
        {
          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                       "corrupted object %s.%s; actual checksum: %s",
                       checksum, ostree_object_type_to_string (objtype),
                       tmp_checksum);
          goto out;
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Exemplo n.º 6
0
static gboolean
load_and_fsck_one_object (OstreeRepo            *repo,
                          const char            *checksum,
                          OstreeObjectType       objtype,
                          gboolean              *out_found_corruption,
                          GCancellable          *cancellable,
                          GError               **error)
{
  gboolean ret = FALSE;
  gboolean missing = FALSE;
  gs_unref_variant GVariant *metadata = NULL;
  gs_unref_object GInputStream *input = NULL;
  gs_unref_object GFileInfo *file_info = NULL;
  gs_unref_variant GVariant *xattrs = NULL;
  GError *temp_error = NULL;

  if (OSTREE_OBJECT_TYPE_IS_META (objtype))
    {
      if (!ostree_repo_load_variant (repo, objtype,
                                     checksum, &metadata, &temp_error))
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_printerr ("Object missing: %s.%s\n", checksum,
                          ostree_object_type_to_string (objtype));
              missing = TRUE;
            }
          else
            {
              g_prefix_error (error, "Loading metadata object %s: ", checksum);
              goto out;
            }
        }
      else
        {
          if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!ostree_validate_structureof_commit (metadata, error))
                {
                  g_prefix_error (error, "While validating commit metadata '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_TREE)
            {
              if (!ostree_validate_structureof_dirtree (metadata, error))
                {
                  g_prefix_error (error, "While validating directory tree '%s': ", checksum);
                  goto out;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_DIR_META)
            {
              if (!ostree_validate_structureof_dirmeta (metadata, error))
                {
                  g_prefix_error (error, "While validating directory metadata '%s': ", checksum);
                  goto out;
                }
            }
      
          input = g_memory_input_stream_new_from_data (g_variant_get_data (metadata),
                                                       g_variant_get_size (metadata),
                                                       NULL);

        }
    }
  else
    {
      guint32 mode;
      g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
      if (!ostree_repo_load_file (repo, checksum, &input, &file_info,
                                  &xattrs, cancellable, &temp_error))
        {
          if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              g_printerr ("Object missing: %s.%s\n", checksum,
                          ostree_object_type_to_string (objtype));
              missing = TRUE;
            }
          else
            {
              g_prefix_error (error, "Loading file object %s: ", checksum);
              goto out;
            }
        }
      else
        {
          mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
          if (!ostree_validate_structureof_file_mode (mode, error))
            {
              g_prefix_error (error, "While validating file '%s': ", checksum);
              goto out;
            }
        }
    }

  if (missing)
    {
      *out_found_corruption = TRUE;
    }
  else
    {
      gs_free guchar *computed_csum = NULL;
      gs_free char *tmp_checksum = NULL;

      if (!ostree_checksum_file_from_input (file_info, xattrs, input,
                                            objtype, &computed_csum,
                                            cancellable, error))
        goto out;
      
      tmp_checksum = ostree_checksum_from_bytes (computed_csum);
      if (strcmp (checksum, tmp_checksum) != 0)
        {
          gs_free char *msg = g_strdup_printf ("corrupted object %s.%s; actual checksum: %s",
                                               checksum, ostree_object_type_to_string (objtype),
                                               tmp_checksum);
          if (opt_delete)
            {
              g_printerr ("%s\n", msg);
              (void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL);
              *out_found_corruption = TRUE;
            }
          else
            {
              g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg);
              goto out;
            }
        }
    }

  ret = TRUE;
 out:
  return ret;
}
Exemplo n.º 7
0
char *
ostree_object_to_string (const char *checksum,
                         OstreeObjectType objtype)
{
  return g_strconcat (checksum, ".", ostree_object_type_to_string (objtype), NULL);
}
Exemplo n.º 8
0
static gboolean
maybe_prune_loose_object (OtPruneData        *data,
                          OstreeRepoPruneFlags    flags,
                          const char         *checksum,
                          OstreeObjectType    objtype,
                          GCancellable       *cancellable,
                          GError            **error)
{
  gboolean reachable = FALSE;
  g_autoptr(GVariant) key = NULL;

  key = ostree_object_name_serialize (checksum, objtype);

  if (g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
    reachable = TRUE;
  else
    {
      guint64 storage_size = 0;

      g_debug ("Pruning unneeded object %s.%s", checksum,
               ostree_object_type_to_string (objtype));

      if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
                                                  &storage_size, cancellable, error))
        return FALSE;

      data->freed_bytes += storage_size;

      if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE))
        {
          if (objtype == OSTREE_OBJECT_TYPE_PAYLOAD_LINK)
            {
              ssize_t size;
              char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
              char target_checksum[OSTREE_SHA256_STRING_LEN+1];
              char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN];

              _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, data->repo->mode);
              size = readlinkat (data->repo->objects_dir_fd, loose_path_buf, target_buf, sizeof (target_buf));
              if (size < 0)
                return glnx_throw_errno_prefix (error, "readlinkat");

              if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN)
                return glnx_throw (error, "invalid data size for %s", loose_path_buf);

              sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3);

              g_autoptr(GVariant) target_key = ostree_object_name_serialize (target_checksum, OSTREE_OBJECT_TYPE_FILE);

              if (g_hash_table_lookup_extended (data->reachable, target_key, NULL, NULL))
                {
                  guint64 target_storage_size = 0;
                  if (!ostree_repo_query_object_storage_size (data->repo, OSTREE_OBJECT_TYPE_FILE, target_checksum,
                                                              &target_storage_size, cancellable, error))
                    return FALSE;

                  reachable = target_storage_size >= data->repo->payload_link_threshold;
                  if (reachable)
                    goto exit;
                }
            }
          else if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
            {
              if (!ostree_repo_mark_commit_partial (data->repo, checksum, FALSE, error))
                return FALSE;
            }

          if (!ostree_repo_delete_object (data->repo, objtype, checksum,
                                          cancellable, error))
            return FALSE;

        }

      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_unreachable_meta++;
      else
        data->n_unreachable_content++;
    }

 exit:
  if (reachable)
    {
      g_debug ("Keeping needed object %s.%s", checksum,
               ostree_object_type_to_string (objtype));
      if (OSTREE_OBJECT_TYPE_IS_META (objtype))
        data->n_reachable_meta++;
      else
        data->n_reachable_content++;
    }

  return TRUE;
}
Exemplo n.º 9
0
gboolean
ostree_builtin_show (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
{
  GOptionContext *context;
  gboolean ret = FALSE;
  const char *rev;
  gs_free char *resolved_rev = NULL;

  context = g_option_context_new ("OBJECT - Output a metadata object");
  g_option_context_add_main_entries (context, options, NULL);

  if (!g_option_context_parse (context, &argc, &argv, error))
    goto out;

  if (argc <= 1)
    {
      ot_util_usage_error (context, "An object argument is required", error);
      goto out;
    }
  rev = argv[1];

  if (opt_print_metadata_key || opt_print_detached_metadata_key)
    {
      gboolean detached = opt_print_detached_metadata_key != NULL;
      const char *key = detached ? opt_print_detached_metadata_key : opt_print_metadata_key;
      if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error))
        goto out;

      if (!do_print_metadata_key (repo, resolved_rev, detached, key, error))
        goto out;
    }
  else if (opt_print_related)
    {
      if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error))
        goto out;

      if (!do_print_related (repo, rev, resolved_rev, error))
        goto out;
    }
  else if (opt_print_variant_type)
    {
      if (!do_print_variant_generic (G_VARIANT_TYPE (opt_print_variant_type), rev, error))
        goto out;
    }
  else
    {
      gboolean found = FALSE;
      if (!ostree_validate_checksum_string (rev, NULL))
        {
          if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error))
            goto out;
          if (!print_object (repo, OSTREE_OBJECT_TYPE_COMMIT, resolved_rev, error))
            goto out;
        }
      else
        {
          if (!print_if_found (repo, OSTREE_OBJECT_TYPE_COMMIT, rev,
                               &found, cancellable, error))
            goto out;
          if (!print_if_found (repo, OSTREE_OBJECT_TYPE_DIR_META, rev,
                               &found, cancellable, error))
            goto out;
          if (!print_if_found (repo, OSTREE_OBJECT_TYPE_DIR_TREE, rev,
                               &found, cancellable, error))
            goto out;
          if (!found)
            {
              gs_unref_object GFileInfo *finfo = NULL;
              gs_unref_variant GVariant *xattrs = NULL;
              GFileType filetype;
              
              if (!ostree_repo_load_file (repo, resolved_rev, NULL, &finfo, &xattrs,
                                          cancellable, error))
                goto out;

              g_print ("Object: %s\nType: %s\n", rev, ostree_object_type_to_string (OSTREE_OBJECT_TYPE_FILE));
              filetype = g_file_info_get_file_type (finfo);
              g_print ("File Type: ");
              switch (filetype)
                {
                case G_FILE_TYPE_REGULAR:
                  g_print ("regular\n");
                  g_print ("Size: %" G_GUINT64_FORMAT "\n", g_file_info_get_size (finfo));
                  break;
                case G_FILE_TYPE_SYMBOLIC_LINK:
                  g_print ("symlink\n");
                  g_print ("Target: %s\n", g_file_info_get_symlink_target (finfo));
                  break;
                default:
                  g_printerr ("(unknown type %u)\n", (guint)filetype);
                }

              g_print ("Mode: 0%04o\n", g_file_info_get_attribute_uint32 (finfo, "unix::mode"));
              g_print ("Uid: %u\n", g_file_info_get_attribute_uint32 (finfo, "unix::uid"));
              g_print ("Gid: %u\n", g_file_info_get_attribute_uint32 (finfo, "unix::gid"));

              g_print ("Extended Attributes: ");
              if (xattrs)
                {
                  gs_free char *xattr_string = g_variant_print (xattrs, TRUE);
                  g_print ("{ %s }\n", xattr_string);
                }
              else
                {
                  g_print ("(none)\n");
                }
            }
        }
    }
 
  ret = TRUE;
 out:
  if (context)
    g_option_context_free (context);
  return ret;
}