lib/transaction_files.c: fix leaving behind obsolete directories

Deleting obsolete directories is different from deleting obsolete files,
files need to be deleted by the first package that might change the file
into a different file type.
Directories need to be deleted by the last package that removes files
out of the directory to avoid ENOTEMPTY if another package has a file in
the given directory which is uninstalled later.

This fixes #282.
This commit is contained in:
Duncan Overbruck 2020-05-17 15:20:15 +02:00
parent a8d095a2ba
commit 62962208fd
No known key found for this signature in database
GPG Key ID: 335C1D17EC3D6E35
2 changed files with 220 additions and 3 deletions

View File

@ -443,7 +443,16 @@ collect_file(struct xbps_handle *xhp, const char *file, size_t size,
} else if (type == TYPE_DIR && item->old.type == TYPE_DIR) {
/*
* Multiple packages removing the same directory.
* Record the last package to remove this directory.
*/
if (idx < item->old.index || item->old.preserve)
return 0;
item->old.pkgname = pkgname;
item->old.pkgver = pkgver;
item->old.index = idx;
item->old.preserve = preserve;
item->old.update = update;
item->old.removepkg = removepkg;
return 0;
} else {
/*
@ -777,9 +786,9 @@ xbps_transaction_files(struct xbps_handle *xhp, xbps_object_iterator_t iter)
while ((obj = xbps_object_iterator_next(iter)) != NULL) {
bool update = false;
/*
* `idx` is used as package install index, to chose which
* choose the first package which owns or used to own the
* file deletes it.
* `idx` is used as package install index, to choose which
* choose the first or last package which owns or used to
* own the file or directory deletes it.
*/
idx++;

View File

@ -935,6 +935,210 @@ multiple_obsoletes_with_alternatives_unordered_body() {
atf_check_equal $? 0
}
atf_test_case obsolete_directory_multiple_packages1
obsolete_directory_multiple_packages1_head() {
atf_set "descr" "Remove multiple packages with the same obsolete directory, variant 1"
}
obsolete_directory_multiple_packages1_body() {
mkdir repo
mkdir -p pkg_A/usr/lib/gcc/9.2/include pkg_B/usr/lib/gcc/9.2/include
touch pkg_A/usr/lib/gcc/9.2/include/foo.h pkg_B/usr/lib/gcc/9.2/include/bar.h
cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvd A B
atf_check_equal $? 0
xbps-pkgdb -r root -av
atf_check_equal $? 0
rm -rf pkg_A pkg_B
mkdir -p pkg_A/usr/lib/gcc/9.3/include pkg_B/usr/lib/gcc/9.3/include
touch pkg_A/usr/lib/gcc/9.3/include/foo.h pkg_B/usr/lib/gcc/9.3/include/bar.h
cd repo
xbps-create -A noarch -n A-2.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-2.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvdu B A
xbps-pkgdb -r root -av
atf_check_equal $? 0
ls -lsa root/usr/lib/gcc
test -d root/usr/lib/gcc/9.2
atf_check_equal $? 1
}
atf_test_case obsolete_directory_multiple_packages2
obsolete_directory_multiple_packages2_head() {
atf_set "descr" "Remove multiple packages with the same obsolete directory, variant 2"
}
obsolete_directory_multiple_packages2_body() {
mkdir repo
mkdir -p pkg_A/usr/lib/gcc/9.2/include pkg_B/usr/lib/gcc/9.2/include
touch pkg_A/usr/lib/gcc/9.2/include/foo.h pkg_B/usr/lib/gcc/9.2/include/bar.h
cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvd A B
atf_check_equal $? 0
xbps-pkgdb -r root -av
atf_check_equal $? 0
rm -rf pkg_A pkg_B
mkdir -p pkg_A/usr/lib/gcc/9.3/include pkg_B/usr/lib/gcc/9.3/include
touch pkg_A/usr/lib/gcc/9.3/include/foo.h pkg_B/usr/lib/gcc/9.3/include/bar.h
cd repo
xbps-create -A noarch -n A-2.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-2.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvdu A B
xbps-pkgdb -r root -av
atf_check_equal $? 0
ls -lsa root/usr/lib/gcc
test -d root/usr/lib/gcc/9.2
atf_check_equal $? 1
}
atf_test_case obsolete_directory_multiple_packages3
obsolete_directory_multiple_packages3_head() {
atf_set "descr" "Remove multiple packages with the same obsolete directory, variant 3"
}
obsolete_directory_multiple_packages3_body() {
mkdir repo
mkdir -p pkg_A/usr/lib/gcc/9.2/include pkg_B/usr/lib/gcc/9.2/include pkg_C/usr/lib/gcc/9.2/include
touch pkg_A/usr/lib/gcc/9.2/include/foo.h pkg_B/usr/lib/gcc/9.2/include/bar.h pkg_C/usr/lib/gcc/9.2/include/fizz.h
cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-create -A noarch -n C-1.0_1 -s "C pkg" ../pkg_C
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvd A B C
atf_check_equal $? 0
xbps-pkgdb -r root -av
atf_check_equal $? 0
rm -rf pkg_A pkg_B pkg_C
mkdir -p pkg_A/usr/lib/gcc/9.3/include pkg_B/usr/lib/gcc/9.3/include pkg_C/usr/lib/gcc/9.3/include
touch pkg_A/usr/lib/gcc/9.3/include/foo.h pkg_B/usr/lib/gcc/9.3/include/bar.h pkg_C/usr/lib/gcc/9.3/include/fizz.h
cd repo
xbps-create -A noarch -n A-2.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-2.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-create -A noarch -n C-2.0_1 -s "C pkg" ../pkg_C
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvdu B A C
xbps-pkgdb -r root -av
atf_check_equal $? 0
ls -lsa root/usr/lib/gcc
test -d root/usr/lib/gcc/9.2
atf_check_equal $? 1
}
atf_test_case obsolete_directory_multiple_packages4
obsolete_directory_multiple_packages4_head() {
atf_set "descr" "Remove multiple packages with the same obsolete directory, variant 4"
}
obsolete_directory_multiple_packages4_body() {
mkdir repo
mkdir -p pkg_A/usr/lib/gcc/9.2/include pkg_B/usr/lib/gcc/9.2/include pkg_C/usr/lib/gcc/9.2/include
touch pkg_A/usr/lib/gcc/9.2/include/foo.h pkg_B/usr/lib/gcc/9.2/include/bar.h pkg_C/usr/lib/gcc/9.2/include/fizz.h
cd repo
xbps-create -A noarch -n A-1.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-1.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-create -A noarch -n C-1.0_1 -s "C pkg" ../pkg_C
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvd A B C
atf_check_equal $? 0
xbps-pkgdb -r root -av
atf_check_equal $? 0
rm -rf pkg_A pkg_B pkg_C
mkdir -p pkg_A/usr/lib/gcc/9.3/include pkg_B/usr/lib/gcc/9.3/include pkg_C/usr/lib/gcc/9.3/include
touch pkg_A/usr/lib/gcc/9.3/include/foo.h pkg_B/usr/lib/gcc/9.3/include/bar.h pkg_C/usr/lib/gcc/9.3/include/fizz.h
cd repo
xbps-create -A noarch -n A-2.0_1 -s "A pkg" ../pkg_A
atf_check_equal $? 0
xbps-create -A noarch -n B-2.0_1 -s "B pkg" ../pkg_B
atf_check_equal $? 0
xbps-create -A noarch -n C-2.0_1 -s "C pkg" ../pkg_C
atf_check_equal $? 0
xbps-rindex -d -a $PWD/*.xbps
atf_check_equal $? 0
cd ..
xbps-install -r root --repository=$PWD/repo -yvdu A B C
xbps-pkgdb -r root -av
atf_check_equal $? 0
ls -lsa root/usr/lib/gcc
test -d root/usr/lib/gcc/9.2
atf_check_equal $? 1
}
atf_init_test_cases() {
atf_add_test_case reinstall_obsoletes
atf_add_test_case root_symlinks_update
@ -957,4 +1161,8 @@ atf_init_test_cases() {
atf_add_test_case obsoletes_with_alternatives
atf_add_test_case multiple_obsoletes_with_alternatives
atf_add_test_case multiple_obsoletes_with_alternatives_unordered
atf_add_test_case obsolete_directory_multiple_packages1
atf_add_test_case obsolete_directory_multiple_packages2
atf_add_test_case obsolete_directory_multiple_packages3
atf_add_test_case obsolete_directory_multiple_packages4
}