summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllan McRae <allan@archlinux.org>2012-07-18 12:25:37 +1000
committerAllan McRae <allan@archlinux.org>2012-12-14 12:35:34 +1000
commitc1abfeae1ec39a196262622662850b7d277a4734 (patch)
tree2fc58a7cc94d5731117e3a454594bb63b6f4ca76
parent6860e2f7032aed392f2526a7fb72cbf08dd3c25f (diff)
Detect inter-package conflicts between files and directories
Detect a conflict between a file/symlink in one package and a directory in another when both are being installed at once. A side effect is the creation of conflicts between a directory symlink and a real directory (e.g lib -> usr/lib in pkg1 and /lib in pkg2). Given we can not guarantee pkg1 is installed before pkg2, this is a genuine conflict. Signed-off-by: Allan McRae <allan@archlinux.org>
-rw-r--r--lib/libalpm/filelist.c51
-rw-r--r--test/pacman/tests/fileconflict002.py2
-rw-r--r--test/pacman/tests/fileconflict015.py2
3 files changed, 38 insertions, 17 deletions
diff --git a/lib/libalpm/filelist.c b/lib/libalpm/filelist.c
index f6c0ed45..1928056d 100644
--- a/lib/libalpm/filelist.c
+++ b/lib/libalpm/filelist.c
@@ -82,27 +82,52 @@ alpm_list_t *_alpm_filelist_intersection(alpm_filelist_t *filesA,
size_t ctrA = 0, ctrB = 0;
while(ctrA < filesA->count && ctrB < filesB->count) {
+ int cmp, isdirA, isdirB;
+ char *strA, *strB;
+
alpm_file_t *fileA = filesA->files + ctrA;
alpm_file_t *fileB = filesB->files + ctrB;
- const char *strA = fileA->name;
- const char *strB = fileB->name;
- /* skip directories, we don't care about them */
+
+ isdirA = 0;
+ strA = fileA->name;
if(strA[strlen(strA)-1] == '/') {
+ isdirA = 1;
+ strA = strndup(fileA->name, strlen(strA)-1);
+ }
+
+ isdirB = 0;
+ strB = fileB->name;
+ if(strB[strlen(strB)-1] == '/') {
+ isdirB = 1;
+ strB = strndup(fileB->name, strlen(strB)-1);
+ }
+
+ cmp = strcmp(strA, strB);
+ if(cmp < 0) {
ctrA++;
- } else if(strB[strlen(strB)-1] == '/') {
+ } else if(cmp > 0) {
ctrB++;
} else {
- int cmp = strcmp(strA, strB);
- if(cmp < 0) {
- ctrA++;
- } else if(cmp > 0) {
- ctrB++;
- } else {
- /* item in both, qualifies as an intersect */
+ /* TODO: this creates conflicts between a symlink to a directory in
+ * one package and a real directory in the other. For example,
+ * lib -> /usr/lib in pkg1 and /lib in pkg2. This would be allowed
+ * when installing one package at a time _provided_ pkg1 is installed
+ * first. This will need adjusted if the order of package install can
+ * be guaranteed to install the symlink first */
+
+ /* when not directories, item in both qualifies as an intersect */
+ if(! (isdirA && isdirB)) {
ret = alpm_list_add(ret, fileA);
- ctrA++;
- ctrB++;
}
+ ctrA++;
+ ctrB++;
+ }
+
+ if(isdirA) {
+ free(strA);
+ }
+ if(isdirB) {
+ free(strB);
}
}
diff --git a/test/pacman/tests/fileconflict002.py b/test/pacman/tests/fileconflict002.py
index e107cd2e..1e6113c1 100644
--- a/test/pacman/tests/fileconflict002.py
+++ b/test/pacman/tests/fileconflict002.py
@@ -19,5 +19,3 @@ self.addrule("PACMAN_RETCODE=1")
self.addrule("!PKG_EXIST=pkg1")
self.addrule("!PKG_EXIST=pkg2")
self.addrule("!FILE_EXIST=dir/realdir/file")
-
-self.expectfailure = True
diff --git a/test/pacman/tests/fileconflict015.py b/test/pacman/tests/fileconflict015.py
index 78634d7e..3c80bbcc 100644
--- a/test/pacman/tests/fileconflict015.py
+++ b/test/pacman/tests/fileconflict015.py
@@ -13,5 +13,3 @@ self.args = "-S pkg1 pkg2"
self.addrule("PACMAN_RETCODE=1")
self.addrule("!PKG_EXIST=pkg1")
self.addrule("!PKG_EXIST=pkg2")
-
-self.expectfailure = True