From 7eadeb14a52af31cbec6c21ed86141433abffa8c Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 2 Feb 2018 14:11:49 +0100 Subject: [PATCH] prune: support .payload-link files Prune payload-links to files that are not present in the repository. A .payload-link is stored only once, even if there are two objects with different checksums but same payload. In the case prune deletes the file referred by the payload-link, the other file won't have any .payload-reference left. A better algorithm to deal with this case would be to delete every .payload-link file and then recreate them all for the objects that are left in the repository at the expense of calculating the checksum for each object in repository. Signed-off-by: Giuseppe Scrivano --- src/libostree/ostree-repo-prune.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index fc3cfa548e..b7143a3d11 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -46,11 +46,14 @@ maybe_prune_loose_object (OtPruneData *data, 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)) + if (g_hash_table_lookup_extended (data->reachable, key, NULL, NULL)) + reachable = TRUE; + else { g_debug ("Pruning unneeded object %s.%s", checksum, ostree_object_type_to_string (objtype)); @@ -58,6 +61,23 @@ maybe_prune_loose_object (OtPruneData *data, { guint64 storage_size = 0; + if (objtype == OSTREE_OBJECT_TYPE_PAYLOAD_LINK) + { + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; + char target_checksum[OSTREE_SHA256_STRING_LEN+1]; + + _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, data->repo->mode); + if (readlinkat (data->repo->objects_dir_fd, loose_path_buf, target_checksum, sizeof (target_checksum)) < 0) + return glnx_throw_errno (error); + + 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)) + { + reachable = TRUE; + goto exit; + } + } if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { if (!ostree_repo_mark_commit_partial (data->repo, checksum, FALSE, error)) @@ -79,7 +99,9 @@ maybe_prune_loose_object (OtPruneData *data, else data->n_unreachable_content++; } - else + + exit: + if (reachable) { g_debug ("Keeping needed object %s.%s", checksum, ostree_object_type_to_string (objtype)); @@ -233,6 +255,7 @@ repo_prune_internal (OstreeRepo *self, g_autoptr(GHashTable) reachable_owned = g_hash_table_ref (options->reachable); data.reachable = reachable_owned; + GLNX_HASH_TABLE_FOREACH_KV (objects, GVariant*, serialized_key, GVariant*, objdata) { const char *checksum; @@ -283,7 +306,7 @@ repo_prune_internal (OstreeRepo *self, * of traversing all commits, only refs will be used. Particularly * when combined with @depth, this is a convenient way to delete * history from the repository. - * + * * Use the %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine * statistics on objects that would be deleted, without actually * deleting them.