diff --git a/Makefile-tests.am b/Makefile-tests.am index 4986b427..bb1cee41 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -72,7 +72,6 @@ test_scripts = \ tests/test-repo-checkout-subpath.sh \ tests/test-reset-nonlinear.sh \ tests/test-oldstyle-partial.sh \ - tests/test-setuid.sh \ tests/test-delta.sh \ tests/test-xattrs.sh \ tests/test-auto-summary.sh \ diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml index 4a86c1d2..c4842584 100644 --- a/man/ostree-commit.xml +++ b/man/ostree-commit.xml @@ -163,7 +163,15 @@ Boston, MA 02111-1307, USA. ="PATH" - File containing list of modifications to make permissions. + File containing list of modifications to make permissions (file mode, followed by space, followed by file path). + + + + + ="PATH" + + + File containing list of file paths to skip (one path per line). diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 1d96855d..a021fbfa 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -36,6 +36,7 @@ static char *opt_parent; static gboolean opt_orphan; static char *opt_branch; static char *opt_statoverride_file; +static char *opt_skiplist_file; static char **opt_metadata_strings; static char **opt_detached_metadata_strings; static gboolean opt_link_checkout_speedup; @@ -84,6 +85,7 @@ static GOptionEntry options[] = { { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" }, + { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, { "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL }, { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"}, { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, @@ -95,65 +97,85 @@ static GOptionEntry options[] = { }; static gboolean -parse_statoverride_file (GHashTable **out_mode_add, - GCancellable *cancellable, - GError **error) +parse_file_by_line (const char *path, + gboolean (*cb)(const char*, void*, GError**), + void *cbdata, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; - gsize len; - char **iter = NULL; /* nofree */ - g_autoptr(GHashTable) ret_hash = NULL; - g_autoptr(GFile) path = NULL; g_autofree char *contents = NULL; + g_autoptr(GFile) file = NULL; char **lines = NULL; - path = g_file_new_for_path (opt_statoverride_file); - - if (!g_file_load_contents (path, cancellable, &contents, &len, NULL, - error)) + file = g_file_new_for_path (path); + if (!g_file_load_contents (file, cancellable, &contents, NULL, NULL, error)) goto out; - - ret_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + lines = g_strsplit (contents, "\n", -1); - - for (iter = lines; iter && *iter; iter++) + for (char **iter = lines; iter && *iter; iter++) { - const char *line = *iter; + /* skip empty lines at least */ + if (**iter == '\0') + continue; - if (*line == '+') - { - const char *spc; - guint mode_add; - - spc = strchr (line + 1, ' '); - if (!spc) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Malformed statoverride file"); - goto out; - } - - mode_add = (guint32)(gint32)g_ascii_strtod (line + 1, NULL); - g_hash_table_insert (ret_hash, - g_strdup (spc + 1), - GUINT_TO_POINTER((gint32)mode_add)); - } + if (!cb (*iter, cbdata, error)) + goto out; } ret = TRUE; - ot_transfer_out_value (out_mode_add, &ret_hash); - out: +out: g_strfreev (lines); return ret; } +static gboolean +handle_statoverride_line (const char *line, + void *data, + GError **error) +{ + GHashTable *files = data; + const char *spc; + guint mode_add; + + spc = strchr (line, ' '); + if (spc == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Malformed statoverride file (no space found)"); + return FALSE; + } + + mode_add = (guint32)(gint32)g_ascii_strtod (line, NULL); + g_hash_table_insert (files, g_strdup (spc + 1), + GUINT_TO_POINTER((gint32)mode_add)); + return TRUE; +} + +static gboolean +handle_skiplist_line (const char *line, + void *data, + GError **error) +{ + GHashTable *files = data; + g_hash_table_add (files, g_strdup (line)); + return TRUE; +} + +struct CommitFilterData { + GHashTable *mode_adds; + GHashTable *skip_list; +}; + static OstreeRepoCommitFilterResult commit_filter (OstreeRepo *self, const char *path, GFileInfo *file_info, gpointer user_data) { - GHashTable *mode_adds = user_data; + struct CommitFilterData *data = user_data; + GHashTable *mode_adds = data->mode_adds; + GHashTable *skip_list = data->skip_list; gpointer value; if (opt_owner_uid >= 0) @@ -169,7 +191,13 @@ commit_filter (OstreeRepo *self, current_mode | mode_add); g_hash_table_remove (mode_adds, path); } - + + if (skip_list && g_hash_table_contains (skip_list, path)) + { + g_hash_table_remove (skip_list, path); + return OSTREE_REPO_COMMIT_FILTER_SKIP; + } + return OSTREE_REPO_COMMIT_FILTER_ALLOW; } @@ -310,9 +338,11 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError glnx_unref_object OstreeMutableTree *mtree = NULL; g_autofree char *tree_type = NULL; g_autoptr(GHashTable) mode_adds = NULL; + g_autoptr(GHashTable) skip_list = NULL; OstreeRepoCommitModifierFlags flags = 0; OstreeRepoCommitModifier *modifier = NULL; OstreeRepoTransactionStats stats; + struct CommitFilterData filter_data = { 0, }; context = g_option_context_new ("[PATH] - Commit a new revision"); @@ -324,7 +354,17 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError if (opt_statoverride_file) { - if (!parse_statoverride_file (&mode_adds, cancellable, error)) + mode_adds = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!parse_file_by_line (opt_statoverride_file, handle_statoverride_line, + mode_adds, cancellable, error)) + goto out; + } + + if (opt_skiplist_file) + { + skip_list = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + if (!parse_file_by_line (opt_skiplist_file, handle_skiplist_line, + skip_list, cancellable, error)) goto out; } @@ -359,9 +399,13 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError || opt_owner_uid >= 0 || opt_owner_gid >= 0 || opt_statoverride_file != NULL + || opt_skiplist_file != NULL || opt_no_xattrs) { - modifier = ostree_repo_commit_modifier_new (flags, commit_filter, mode_adds, NULL); + filter_data.mode_adds = mode_adds; + filter_data.skip_list = skip_list; + modifier = ostree_repo_commit_modifier_new (flags, commit_filter, + &filter_data, NULL); } if (opt_parent) @@ -491,6 +535,22 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError goto out; } + if (skip_list && g_hash_table_size (skip_list) > 0) + { + GHashTableIter hash_iter; + gpointer key; + + g_hash_table_iter_init (&hash_iter, skip_list); + + while (g_hash_table_iter_next (&hash_iter, &key, NULL)) + { + g_printerr ("Unmatched skip-list path: %s\n", (char*)key); + } + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Unmatched skip-list paths"); + goto out; + } + if (!ostree_repo_write_mtree (repo, mtree, &root, cancellable, error)) goto out; diff --git a/tests/basic-test.sh b/tests/basic-test.sh index b2477955..a44ee630 100755 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..54" +echo "1..55" $OSTREE checkout test2 checkout-test2 echo "ok checkout" @@ -179,13 +179,31 @@ cd ${test_tmpdir}/checkout-test2-4 $OSTREE commit -b test2 -s "no xattrs" --no-xattrs echo "ok commit with no xattrs" +# NB: The + is optional, but we need to make sure we support it cd ${test_tmpdir} cat > test-statoverride.txt < test-skiplist.txt < -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -set -euo pipefail - -echo "1..1" - -. $(dirname $0)/libtest.sh - -setup_test_repository "bare" - -cd ${test_tmpdir} -cat > test-statoverride.txt <