[pacman-dev] [PATCH] Detect inter-package conflicts between files and directories

Allan McRae allan at archlinux.org
Mon Jul 16 21:50:26 EDT 2012


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 on conflicts between a direcotry 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 at archlinux.org>
---
 lib/libalpm/conflict.c               | 48 +++++++++++++++++++++++++-----------
 test/pacman/tests/fileconflict002.py |  2 --
 test/pacman/tests/fileconflict015.py |  2 --
 3 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index f3b269f..041ba6f 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -274,28 +274,48 @@ static alpm_list_t *filelist_intersection(alpm_filelist_t *filesA,
 	size_t ctrA = 0, ctrB = 0;
 
 	while(ctrA < filesA->count && ctrB < filesB->count) {
+		int cmp, isdirA, isdirB;
+
 		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 */
+		char *strA = strdup(fileA->name);
+		char *strB = strdup(fileB->name);
+
+		isdirA = 0;
 		if(strA[strlen(strA)-1] == '/') {
+			isdirA = 1;
+			strA[strlen(strA)-1] = '\0';
+		}
+
+		isdirB = 0;
+		if(strB[strlen(strB)-1] == '/') {
+			isdirB = 1;
+			strB[strlen(strB)-1] = '\0';
+		}
+
+		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++;
+		}
+
+		free(strA);
+		free(strB);
 	}
 
 	return ret;
diff --git a/test/pacman/tests/fileconflict002.py b/test/pacman/tests/fileconflict002.py
index e107cd2..1e6113c 100644
--- a/test/pacman/tests/fileconflict002.py
+++ b/test/pacman/tests/fileconflict002.py
@@ -19,5 +19,3 @@
 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 78634d7..3c80bbc 100644
--- a/test/pacman/tests/fileconflict015.py
+++ b/test/pacman/tests/fileconflict015.py
@@ -13,5 +13,3 @@
 self.addrule("PACMAN_RETCODE=1")
 self.addrule("!PKG_EXIST=pkg1")
 self.addrule("!PKG_EXIST=pkg2")
-
-self.expectfailure = True
-- 
1.7.11.2



More information about the pacman-dev mailing list