From 744543110e3d12464a752d59956dc24a0f99b1d2 Mon Sep 17 00:00:00 2001 From: Yu Qi Zhang Date: Mon, 20 Jun 2016 20:20:58 +0000 Subject: [PATCH] refs: allow overwrite of empty folders We noticed that once a ref folder is created, there is no existing command that can remove it. For example, once "foo/bar" is created, even if the user deletes foo or all the refs under foo, the folder will persist. Now when the user attempts to create a ref "foo" either through commit or refs --create, if a folder "foo" exists but is empty of refs, the folder is removed and the new ref "foo" is created. New unit tests in tests-ref.sh verify this functionality. Closes: #354 Approved by: cgwalters --- src/libostree/ostree-repo-refs.c | 41 ++++++++++++++++++++++++++++++-- src/ostree/ot-builtin-commit.c | 10 +++++++- src/ostree/ot-builtin-refs.c | 10 +++++++- tests/test-refs.sh | 10 +++++++- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 29f03337..d9af2256 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -100,14 +100,51 @@ write_checksum_file_at (OstreeRepo *self, { size_t l = strlen (sha256); char *bufnl = alloca (l + 2); + g_autoptr(GError) temp_error = NULL; memcpy (bufnl, sha256, l); bufnl[l] = '\n'; bufnl[l+1] = '\0'; if (!_ostree_repo_file_replace_contents (self, dfd, name, (guint8*)bufnl, l + 1, - cancellable, error)) - goto out; + cancellable, &temp_error)) + { + if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + g_autoptr(GHashTable) refs = NULL; + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + + g_clear_error (&temp_error); + + if (!ostree_repo_list_refs (self, name, &refs, cancellable, error)) + goto out; + + g_hash_table_iter_init (&hashiter, refs); + + while ((g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))) + { + if (strcmp (name, (char *)hashkey) != 0) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Conflict: %s exists under %s when attempting write", (char*)hashkey, name); + goto out; + } + } + + if (!glnx_shutil_rm_rf_at (dfd, name, cancellable, error)) + goto out; + + if (!_ostree_repo_file_replace_contents (self, dfd, name, (guint8*)bufnl, l + 1, + cancellable, error)) + goto out; + } + else + { + g_propagate_error (error, g_steal_pointer (&temp_error)); + goto out; + } + } } ret = TRUE; diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 85c4c65d..ec3ca960 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -428,7 +428,15 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError else if (!opt_orphan) { if (!ostree_repo_resolve_rev (repo, opt_branch, TRUE, &parent, error)) - goto out; + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + /* A folder exists with the specified ref name, + * which is handled by _ostree_repo_write_ref */ + g_clear_error (error); + } + else goto out; + } } if (opt_editor) diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index 10647ec6..fbdaf1bc 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -74,7 +74,15 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab g_autofree char *checksum_existing = NULL; if (!ostree_repo_resolve_rev (repo, opt_create, TRUE, &checksum_existing, error)) - goto out; + { + if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY)) + { + /* A folder exists with the specified ref name, + * which is handled by _ostree_repo_write_ref */ + g_clear_error (error); + } + else goto out; + } if (checksum_existing != NULL) { diff --git a/tests/test-refs.sh b/tests/test-refs.sh index 3d229031..310b586f 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -92,8 +92,16 @@ fi ${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create1 assert_file_has_content refscount.create1 "^5$" -${CMD_PREFIX} ostree --repo=repo refs ctest --create ctest-new +${CMD_PREFIX} ostree --repo=repo refs ctest --create=ctest-new ${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create2 assert_file_has_content refscount.create2 "^6$" +#Check to see if a deleted folder can be re-used as the name of a ref +${CMD_PREFIX} ostree --repo=repo refs foo/ctest --delete +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create3 +assert_file_has_content refscount.create3 "^5$" +${CMD_PREFIX} ostree --repo=repo refs ctest --create=foo +${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create4 +assert_file_has_content refscount.create4 "^6$" + echo "ok refs"