main: Clean up fsck code: honor --quiet, warn (but continue) on missing objects
When we make fsck --delete work again, it will be convenient to continue on missing objects.
This commit is contained in:
parent
a4f5ad8542
commit
c8801ae489
|
|
@ -25,79 +25,50 @@
|
||||||
#include "ot-builtins.h"
|
#include "ot-builtins.h"
|
||||||
#include "ostree.h"
|
#include "ostree.h"
|
||||||
|
|
||||||
static gboolean quiet;
|
static gboolean opt_quiet;
|
||||||
static gboolean delete;
|
static gboolean opt_delete;
|
||||||
|
|
||||||
static GOptionEntry options[] = {
|
static GOptionEntry options[] = {
|
||||||
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, "Don't display informational messages", NULL },
|
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &opt_quiet, "Only print error messages", NULL },
|
||||||
{ "delete", 0, 0, G_OPTION_ARG_NONE, &delete, "Remove corrupted objects", NULL },
|
{ "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Remove corrupted objects", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
OstreeRepo *repo;
|
|
||||||
} OtFsckData;
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fsck_reachable_objects_from_commits (OtFsckData *data,
|
load_and_fsck_one_object (OstreeRepo *repo,
|
||||||
GHashTable *commits,
|
const char *checksum,
|
||||||
GCancellable *cancellable,
|
OstreeObjectType objtype,
|
||||||
GError **error)
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GHashTableIter hash_iter;
|
gboolean missing = FALSE;
|
||||||
gpointer key, value;
|
gs_unref_variant GVariant *metadata = NULL;
|
||||||
gs_unref_hashtable GHashTable *reachable_objects = NULL;
|
|
||||||
gs_unref_object GInputStream *input = NULL;
|
gs_unref_object GInputStream *input = NULL;
|
||||||
gs_unref_object GFileInfo *file_info = NULL;
|
gs_unref_object GFileInfo *file_info = NULL;
|
||||||
gs_unref_variant GVariant *xattrs = NULL;
|
gs_unref_variant GVariant *xattrs = NULL;
|
||||||
gs_unref_variant GVariant *metadata = NULL;
|
GError *temp_error = NULL;
|
||||||
gs_free guchar *computed_csum = NULL;
|
|
||||||
gs_free char *tmp_checksum = NULL;
|
|
||||||
|
|
||||||
reachable_objects = ostree_repo_traverse_new_reachable ();
|
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
|
||||||
|
|
||||||
g_hash_table_iter_init (&hash_iter, commits);
|
|
||||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
|
||||||
{
|
{
|
||||||
GVariant *serialized_key = key;
|
if (!ostree_repo_load_variant (repo, objtype,
|
||||||
const char *checksum;
|
checksum, &metadata, &temp_error))
|
||||||
OstreeObjectType objtype;
|
|
||||||
|
|
||||||
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
|
|
||||||
|
|
||||||
g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT);
|
|
||||||
|
|
||||||
if (!ostree_repo_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 (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||||
if (!ostree_repo_load_variant (data->repo, objtype,
|
{
|
||||||
checksum, &metadata, error))
|
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);
|
g_prefix_error (error, "Loading metadata object %s: ", checksum);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||||
{
|
{
|
||||||
if (!ostree_validate_structureof_commit (metadata, error))
|
if (!ostree_validate_structureof_commit (metadata, error))
|
||||||
|
|
@ -122,23 +93,35 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
g_assert_not_reached ();
|
|
||||||
|
|
||||||
input = g_memory_input_stream_new_from_data (g_variant_get_data (metadata),
|
input = g_memory_input_stream_new_from_data (g_variant_get_data (metadata),
|
||||||
g_variant_get_size (metadata),
|
g_variant_get_size (metadata),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (objtype == OSTREE_OBJECT_TYPE_FILE)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
guint32 mode;
|
||||||
|
g_assert (objtype == OSTREE_OBJECT_TYPE_FILE);
|
||||||
|
if (!ostree_repo_load_file (repo, checksum, &input, &file_info,
|
||||||
|
&xattrs, cancellable, &temp_error))
|
||||||
{
|
{
|
||||||
guint32 mode;
|
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||||
if (!ostree_repo_load_file (data->repo, checksum, &input, &file_info,
|
{
|
||||||
&xattrs, cancellable, error))
|
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);
|
g_prefix_error (error, "Loading file object %s: ", checksum);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
||||||
if (!ostree_validate_structureof_file_mode (mode, error))
|
if (!ostree_validate_structureof_file_mode (mode, error))
|
||||||
{
|
{
|
||||||
|
|
@ -146,18 +129,18 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
|
||||||
g_assert_not_reached ();
|
if (!missing)
|
||||||
}
|
{
|
||||||
|
gs_free guchar *computed_csum = NULL;
|
||||||
|
gs_free char *tmp_checksum = NULL;
|
||||||
|
|
||||||
g_free (computed_csum);
|
|
||||||
if (!ostree_checksum_file_from_input (file_info, xattrs, input,
|
if (!ostree_checksum_file_from_input (file_info, xattrs, input,
|
||||||
objtype, &computed_csum,
|
objtype, &computed_csum,
|
||||||
cancellable, error))
|
cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
g_free (tmp_checksum);
|
|
||||||
tmp_checksum = ostree_checksum_from_bytes (computed_csum);
|
tmp_checksum = ostree_checksum_from_bytes (computed_csum);
|
||||||
if (strcmp (checksum, tmp_checksum) != 0)
|
if (strcmp (checksum, tmp_checksum) != 0)
|
||||||
{
|
{
|
||||||
|
|
@ -174,12 +157,71 @@ fsck_reachable_objects_from_commits (OtFsckData *data,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fsck_reachable_objects_from_commits (OstreeRepo *repo,
|
||||||
|
GHashTable *commits,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GHashTableIter hash_iter;
|
||||||
|
gpointer key, value;
|
||||||
|
gs_unref_hashtable GHashTable *reachable_objects = NULL;
|
||||||
|
gs_unref_variant GVariant *metadata = NULL;
|
||||||
|
gs_free guchar *computed_csum = NULL;
|
||||||
|
guint i;
|
||||||
|
guint mod;
|
||||||
|
guint count;
|
||||||
|
|
||||||
|
reachable_objects = ostree_repo_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_repo_traverse_commit (repo, checksum, 0, reachable_objects,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = g_hash_table_size (reachable_objects);
|
||||||
|
mod = count / 10;
|
||||||
|
i = 0;
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!load_and_fsck_one_object (repo, checksum, objtype,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (i % mod == 0)
|
||||||
|
g_print ("%u/%u objects\n", i, count);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error)
|
ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GCancellable *cancellable, GError **error)
|
||||||
{
|
{
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
GOptionContext *context;
|
GOptionContext *context;
|
||||||
OtFsckData data;
|
|
||||||
GHashTableIter hash_iter;
|
GHashTableIter hash_iter;
|
||||||
gpointer key, value;
|
gpointer key, value;
|
||||||
gs_unref_object OstreeRepo *repo = NULL;
|
gs_unref_object OstreeRepo *repo = NULL;
|
||||||
|
|
@ -196,10 +238,8 @@ ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GCancellable *canc
|
||||||
if (!ostree_repo_check (repo, error))
|
if (!ostree_repo_check (repo, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
memset (&data, 0, sizeof (data));
|
if (!opt_quiet)
|
||||||
data.repo = repo;
|
g_print ("Enumerating objects...\n");
|
||||||
|
|
||||||
g_print ("Enumerating objects...\n");
|
|
||||||
|
|
||||||
if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL,
|
if (!ostree_repo_list_objects (repo, OSTREE_REPO_LIST_OBJECTS_ALL,
|
||||||
&objects, cancellable, error))
|
&objects, cancellable, error))
|
||||||
|
|
@ -224,10 +264,11 @@ ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GCancellable *canc
|
||||||
|
|
||||||
g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref);
|
g_clear_pointer (&objects, (GDestroyNotify) g_hash_table_unref);
|
||||||
|
|
||||||
g_print ("Verifying content integrity of %u commit objects...\n",
|
if (!opt_quiet)
|
||||||
(guint)g_hash_table_size (commits));
|
g_print ("Verifying content integrity of %u commit objects...\n",
|
||||||
|
(guint)g_hash_table_size (commits));
|
||||||
|
|
||||||
if (!fsck_reachable_objects_from_commits (&data, commits, cancellable, error))
|
if (!fsck_reachable_objects_from_commits (repo, commits, cancellable, error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue