diff options
-rw-r--r-- | lib/libalpm/conflict.c | 32 | ||||
-rw-r--r-- | test/pacman/tests/fileconflict009.py | 20 | ||||
-rw-r--r-- | test/pacman/tests/fileconflict010.py | 20 |
3 files changed, 66 insertions, 6 deletions
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index 32f6f303..efa1a87c 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -328,15 +328,35 @@ const alpm_file_t *_alpm_filelist_contains(alpm_filelist_t *filelist, return NULL; } -static int dir_belongsto_pkg(const char *root, const char *dirpath, +static int dir_belongsto_pkg(alpm_handle_t *handle, const char *dirpath, alpm_pkg_t *pkg) { + alpm_list_t *i; struct stat sbuf; char path[PATH_MAX]; char abspath[PATH_MAX]; - struct dirent *ent = NULL; DIR *dir; + struct dirent *ent = NULL; + const char *root = handle->root; + + /* TODO: this is an overly strict check but currently pacman will not + * overwrite a directory with a file (case 10/11 in add.c). Adjusting that + * is not simple as even if the directory is being unowned by a conflicting + * package, pacman does not sort this to ensure all required directory + * "removals" happen before installation of file/symlink */ + + /* check that no other _installed_ package owns the directory */ + for(i = _alpm_db_get_pkgcache(handle->db_local); i; i = i->next) { + if(pkg == i->data) { + continue; + } + + if(_alpm_filelist_contains(alpm_pkg_get_files(i->data), dirpath)) { + return 0; + } + } + /* check all files in directory are owned by the package */ snprintf(abspath, PATH_MAX, "%s%s", root, dirpath); dir = opendir(abspath); if(dir == NULL) { @@ -349,13 +369,13 @@ static int dir_belongsto_pkg(const char *root, const char *dirpath, if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { continue; } - snprintf(path, PATH_MAX, "%s/%s", dirpath, name); + snprintf(path, PATH_MAX, "%s%s", dirpath, name); snprintf(abspath, PATH_MAX, "%s%s", root, path); if(stat(abspath, &sbuf) != 0) { continue; } if(S_ISDIR(sbuf.st_mode)) { - if(dir_belongsto_pkg(root, path, pkg)) { + if(dir_belongsto_pkg(handle, path, pkg)) { continue; } else { closedir(dir); @@ -529,9 +549,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t *handle, sprintf(dir, "%s/", filestr); if(_alpm_filelist_contains(alpm_pkg_get_files(dbpkg), dir)) { _alpm_log(handle, ALPM_LOG_DEBUG, - "check if all files in %s belongs to %s\n", + "check if all files in %s belong to %s\n", dir, dbpkg->name); - resolved_conflict = dir_belongsto_pkg(handle->root, filestr, dbpkg); + resolved_conflict = dir_belongsto_pkg(handle, dir, dbpkg); } free(dir); } diff --git a/test/pacman/tests/fileconflict009.py b/test/pacman/tests/fileconflict009.py new file mode 100644 index 00000000..904af4a3 --- /dev/null +++ b/test/pacman/tests/fileconflict009.py @@ -0,0 +1,20 @@ +self.description = "dir->symlink change during package upgrade (directory conflict)" + +lp1 = pmpkg("pkg1") +lp1.files = ["dir/"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.files = ["dir/"] +self.addpkg2db("local", lp2) + +p = pmpkg("pkg1", "1.0-2") +p.files = ["dir -> /usr/dir"] +self.addpkg2db("sync", p) + +self.args = "-S pkg1" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("PKG_VERSION=pkg2|1.0-1") +self.addrule("DIR_EXIST=dir/") diff --git a/test/pacman/tests/fileconflict010.py b/test/pacman/tests/fileconflict010.py new file mode 100644 index 00000000..0a3ce835 --- /dev/null +++ b/test/pacman/tests/fileconflict010.py @@ -0,0 +1,20 @@ +self.description = "dir->file change during package upgrade (directory conflict)" + +lp1 = pmpkg("pkg1") +lp1.files = ["dir/"] +self.addpkg2db("local", lp1) + +lp2 = pmpkg("pkg2") +lp2.files = ["dir/"] +self.addpkg2db("local", lp2) + +p = pmpkg("pkg1", "1.0-2") +p.files = ["dir"] +self.addpkg2db("sync", p) + +self.args = "-S pkg1" + +self.addrule("PACMAN_RETCODE=1") +self.addrule("PKG_VERSION=pkg1|1.0-1") +self.addrule("PKG_VERSION=pkg2|1.0-1") +self.addrule("DIR_EXIST=dir/") |