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@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