From ea2cb1d369b2d4afcde61ace59c594a06355ded2 Mon Sep 17 00:00:00 2001 From: Duncaen Date: Tue, 19 Mar 2019 13:12:08 +0100 Subject: [PATCH] unpack: keep conf_files replaced with symlinks, unpack as .new-pkgver --- include/xbps_api_impl.h | 2 +- lib/package_config_files.c | 8 ++- lib/package_unpack.c | 35 +++++++----- tests/xbps/libxbps/shell/conf_files_test.sh | 61 +++++++++++++++++++++ 4 files changed, 89 insertions(+), 17 deletions(-) diff --git a/include/xbps_api_impl.h b/include/xbps_api_impl.h index ce74c2c9..666c94af 100644 --- a/include/xbps_api_impl.h +++ b/include/xbps_api_impl.h @@ -115,7 +115,7 @@ int HIDDEN xbps_cb_message(struct xbps_handle *, xbps_dictionary_t, const char * int HIDDEN xbps_entry_is_a_conf_file(xbps_dictionary_t, const char *); int HIDDEN xbps_entry_install_conf_file(struct xbps_handle *, xbps_dictionary_t, xbps_dictionary_t, struct archive_entry *, const char *, - const char *); + const char *, bool); int HIDDEN xbps_repository_find_deps(struct xbps_handle *, xbps_array_t, xbps_dictionary_t); xbps_dictionary_t HIDDEN xbps_find_virtualpkg_in_conf(struct xbps_handle *, diff --git a/lib/package_config_files.c b/lib/package_config_files.c index a6e30656..a3c1a72e 100644 --- a/lib/package_config_files.c +++ b/lib/package_config_files.c @@ -63,7 +63,8 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, xbps_dictionary_t pkg_filesd, struct archive_entry *entry, const char *entry_pname, - const char *pkgver) + const char *pkgver, + bool symlink) { xbps_object_t obj, obj2; xbps_object_iterator_t iter, iter2; @@ -87,9 +88,10 @@ xbps_entry_install_conf_file(struct xbps_handle *xhp, xbps_dbg_printf(xhp, "%s: processing conf_file %s\n", pkgver, entry_pname); - if (pkg_filesd == NULL) { + if (pkg_filesd == NULL || symlink) { /* - * File exists on disk but it's not managed by the same package. + * 1. File exists on disk but it's not managed by the same package. + * 2. File exists on disk as symlink. * Install it as file.new-. */ version = xbps_pkg_version(pkgver); diff --git a/lib/package_unpack.c b/lib/package_unpack.c index 25a6388e..8c219418 100644 --- a/lib/package_unpack.c +++ b/lib/package_unpack.c @@ -87,7 +87,7 @@ unpack_archive(struct xbps_handle *xhp, const char *file, *entry_pname, *transact, *binpkg_pkgver; char *pkgname, *buf; int ar_rv, rv, error, entry_type, flags; - bool preserve, update, file_exists; + bool preserve, update, file_exists, keep_conf_file; bool skip_extract, force, xucd_stats; uid_t euid; @@ -287,7 +287,7 @@ unpack_archive(struct xbps_handle *xhp, * doesn't match, in that case overwrite the file. * Otherwise skip extracting it. */ - skip_extract = file_exists = false; + skip_extract = file_exists = keep_conf_file = false; if (lstat(entry_pname, &st) == 0) file_exists = true; /* @@ -303,32 +303,41 @@ unpack_archive(struct xbps_handle *xhp, "it's preserved.\n", pkgver, entry_pname); continue; } + + /* + * Check if current entry is a configuration file, + * that should be kept. + */ + if (!force && (entry_type == AE_IFREG)) { + buf = strchr(entry_pname, '.') + 1; + assert(buf != NULL); + keep_conf_file = xbps_entry_is_a_conf_file(binpkg_filesd, buf); + } + /* * If file to be extracted does not match the file type of - * file currently stored on disk, remove file on disk. + * file currently stored on disk and is not a conf file + * that should be kept, remove file on disk. */ - if (file_exists && + if (file_exists && !keep_conf_file && ((entry_statp->st_mode & S_IFMT) != (st.st_mode & S_IFMT))) (void)remove(entry_pname); if (!force && (entry_type == AE_IFREG)) { - buf = strchr(entry_pname, '.') + 1; - assert(buf != NULL); - if (file_exists && S_ISREG(st.st_mode)) { + if (file_exists && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) { /* - * Handle configuration files. Check if current - * entry is a configuration file and take action - * if required. Skip packages that don't have - * "conf_files" array on its XBPS_PKGPROPS + * Handle configuration files. + * Skip packages that don't have "conf_files" + * array on its XBPS_PKGPROPS * dictionary. */ - if (xbps_entry_is_a_conf_file(binpkg_filesd, buf)) { + if (keep_conf_file) { if (xhp->unpack_cb != NULL) xucd.entry_is_conf = true; rv = xbps_entry_install_conf_file(xhp, binpkg_filesd, pkg_filesd, entry, - entry_pname, pkgver); + entry_pname, pkgver, S_ISLNK(st.st_mode)); if (rv == -1) { /* error */ goto out; diff --git a/tests/xbps/libxbps/shell/conf_files_test.sh b/tests/xbps/libxbps/shell/conf_files_test.sh index f9ef29fd..117dabb4 100644 --- a/tests/xbps/libxbps/shell/conf_files_test.sh +++ b/tests/xbps/libxbps/shell/conf_files_test.sh @@ -165,9 +165,70 @@ tc4_body() { atf_check_equal $rval 0 } +# 5th test: configuration file replaced with symlink on disk, modified on upgrade. +# result: install new file as ".new-". +atf_test_case tc5 + +tc5_head() { + atf_set "descr" "Tests for configuration file handling: on-disk replaced with symlink, upgrade modified" +} + +tc5_body() { + mkdir repo + cd repo + mkdir pkg_a + echo "fooblah" > pkg_a/cf1.conf + chmod 644 pkg_a/cf1.conf + xbps-create -A noarch -n a-0.1_1 -s "pkg a" --config-files "/cf1.conf" pkg_a + atf_check_equal $? 0 + rm -rf pkg_a + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + xbps-install -C null.conf -r rootdir --repository=$PWD -yvd a + atf_check_equal $? 0 + + mv rootdir/cf1.conf rootdir/foobar.conf + ln -sf foobar.conf rootdir/cf1.conf + sed -e 's,fooblah,blahfoo,' -i rootdir/foobar.conf + chmod 644 rootdir/foobar.conf + + mkdir pkg_a + echo "bazbar" > pkg_a/cf1.conf + chmod 644 pkg_a/cf1.conf + xbps-create -A noarch -n a-0.2_1 -s "pkg a" --config-files "/cf1.conf" pkg_a + atf_check_equal $? 0 + + xbps-rindex -d -a $PWD/*.xbps + atf_check_equal $? 0 + rm -rf pkg_a + + xbps-install -C null.conf -r rootdir --repository=$PWD -yuvd + atf_check_equal $? 0 + + ls -lsa rootdir + test -h rootdir/cf1.conf + atf_check_equal $? 0 + + result="$(cat rootdir/cf1.conf)" + rval=1 + if [ "${result}" = "blahfoo" ]; then + rval=0 + fi + + echo "result: ${result}" + echo "expected: blahfoo" + atf_check_equal $rval 0 + rval=1 + if [ -s rootdir/cf1.conf.new-0.2_1 ]; then + rval=0 + fi + atf_check_equal $rval 0 +} + atf_init_test_cases() { atf_add_test_case tc1 atf_add_test_case tc2 atf_add_test_case tc3 atf_add_test_case tc4 + atf_add_test_case tc5 }