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:
parent
b81dedb770
commit
5fe3594cb5
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user