Make sure that modified symlinks are preserved.

When removing a package, symlinks owned by this package that have been
modified should be preserved, unless the force flag is set via xbps-remove(8).
This commit is contained in:
Juan RP 2014-10-25 06:43:30 +02:00
parent b81dedb770
commit 5fe3594cb5
2 changed files with 130 additions and 3 deletions

View File

@ -92,6 +92,43 @@ check_remove_pkg_files(struct xbps_handle *xhp,
return fail;
}
static char *
symlink_target(struct xbps_handle *xhp, const char *path)
{
struct stat sb;
char *lnk, *res;
ssize_t r;
if (lstat(path, &sb) == -1)
return NULL;
lnk = malloc(sb.st_size + 1);
assert(lnk);
r = readlink(path, lnk, sb.st_size + 1);
if (r < 0 || r > sb.st_size) {
free(lnk);
return NULL;
}
lnk[sb.st_size] = '\0';
if ((strncmp(lnk, "../", 3) == 0) || strchr(lnk, '/') == NULL) {
char *p, *dname;
/* relative */
p = strdup(path);
assert(p);
dname = dirname(p);
assert(dname);
dname += strlen(xhp->rootdir) + 1;
res = xbps_xasprintf("%s/%s", dname, lnk);
free(lnk);
} else {
/* absolute */
res = lnk;
}
return res;
}
static int
remove_pkg_files(struct xbps_handle *xhp,
xbps_dictionary_t dict,
@ -101,7 +138,7 @@ remove_pkg_files(struct xbps_handle *xhp,
xbps_array_t array;
xbps_object_iterator_t iter;
xbps_object_t obj;
const char *file, *sha256, *curobj = NULL;
const char *curobj = NULL;
/* These are symlinks in Void and must not be removed */
const char *basesymlinks[] = {
"/bin",
@ -113,9 +150,7 @@ remove_pkg_files(struct xbps_handle *xhp,
"/usr/lib64",
"/var/run",
};
char path[PATH_MAX];
int rv = 0;
bool found;
assert(xbps_object_type(dict) == XBPS_TYPE_DICTIONARY);
assert(key != NULL);
@ -140,6 +175,10 @@ remove_pkg_files(struct xbps_handle *xhp,
xbps_object_iterator_reset(iter);
while ((obj = xbps_object_iterator_next(iter))) {
const char *file, *sha256;
char path[PATH_MAX];
bool found;
xbps_dictionary_get_cstring_nocopy(obj, "file", &file);
snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file);
@ -205,6 +244,29 @@ remove_pkg_files(struct xbps_handle *xhp,
if (found) {
continue;
}
if (strcmp(key, "links") == 0) {
const char *target = NULL;
char *lnk;
lnk = symlink_target(xhp, path);
if (lnk == NULL) {
xbps_dbg_printf(xhp, "[remove] %s "
"symlink_target: %s\n", path, strerror(errno));
continue;
}
xbps_dictionary_get_cstring_nocopy(obj, "target", &target);
assert(target);
if (strcmp(lnk, target)) {
xbps_dbg_printf(xhp, "[remove] %s symlink "
"modified (stored %s current %s)\n", path,
target, lnk);
if ((xhp->flags & XBPS_FLAG_FORCE_REMOVE_FILES) == 0) {
free(lnk);
continue;
}
}
free(lnk);
}
/*
* Remove the object if possible.
*/

View File

@ -105,6 +105,69 @@ remove_symlinks_from_root_body() {
atf_check_equal $rv 0
}
atf_test_case keep_modified_symlinks
keep_modified_symlinks_head() {
atf_set "descr" "Tests for package removal: keep modified symlinks in rootdir"
}
keep_modified_symlinks_body() {
mkdir some_repo
mkdir -p pkg_A/bin
ln -sf /bin/bash pkg_A/bin/ash
ln -sf /bin/bash pkg_A/bin/sh
cd some_repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-rindex -a *.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root -C null.conf --repository=$PWD/some_repo -y A
atf_check_equal $? 0
ln -sf /bin/foo root/bin/sh
ln -sf foo root/bin/ash
xbps-remove -r root -yvd A
atf_check_equal $? 0
rv=1
if [ -h root/bin/sh -a -h root/bin/ash ]; then
rv=0
fi
atf_check_equal $rv 0
}
atf_test_case remove_symlinks_modified
remove_symlinks_modified_head() {
atf_set "descr" "Tests for package removal: force remove modified symlinks in rootdir"
}
remove_symlinks_modified_body() {
mkdir some_repo
mkdir -p pkg_A/bin
ln -sf /bin/bash pkg_A/bin/ash
ln -sf /bin/bash pkg_A/bin/sh
cd some_repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-rindex -a *.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root -C null.conf --repository=$PWD/some_repo -y A
atf_check_equal $? 0
ln -sf /bin/foo root/bin/sh
xbps-remove -r root -yvfd A
atf_check_equal $? 0
rv=0
if [ -h root/bin/sh -o -h root/bin/ash ]; then
rv=1
fi
atf_check_equal $rv 0
}
atf_test_case remove_readonly_files
remove_readonly_files_head() {
@ -160,8 +223,10 @@ remove_dups_body() {
atf_init_test_cases() {
atf_add_test_case keep_base_symlinks
atf_add_test_case keep_modified_symlinks
atf_add_test_case remove_readonly_files
atf_add_test_case remove_symlinks
atf_add_test_case remove_symlinks_from_root
atf_add_test_case remove_symlinks_modified
atf_add_test_case remove_dups
}