Pacman currently bails when trying to extract a file over a directory
when using --force.  Instead of ignoring all conflict, perform the
check and skip any file-file conflicts. Conflicts between directories
and files are still flagged and cause the transation to abort.

As a bonus, we now know about files changing packages when using
--force, so we can skip removing them fixing upgrade046.

Signed-off-by: Allan McRae <[email protected]>
---
 doc/pacman.8.txt                |  2 ++
 lib/libalpm/conflict.c          | 26 ++++++++++++++++++++++++--
 lib/libalpm/sync.c              |  2 +-
 src/pacman/sync.c               |  3 +++
 test/pacman/tests/upgrade046.py |  2 --
 5 files changed, 30 insertions(+), 5 deletions(-)

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index 358d506..33a9421 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -205,6 +205,8 @@ Upgrade Options (apply to '-S' and '-U')[[UO]]
        Bypass file conflict checks and overwrite conflicting files. If the
        package that is about to be installed contains files that are already
        installed, this option will cause all those files to be overwritten.
+       Using '--force' will not allow overwriting a directory with a file or
+       installing packages with conflicting files and directories.
        This option should be used with care, ideally not at all.
 
 *\--asdeps*::
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index 610e5ad..6195c9c 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -439,8 +439,10 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t 
*handle,
                        alpm_pkg_t *p2 = j->data;
                        _alpm_filelist_resolve(handle, alpm_pkg_get_files(p2));
 
-                       common_files = 
_alpm_filelist_intersection(alpm_pkg_get_files(p1),
-                                       alpm_pkg_get_files(p2));
+                       alpm_filelist_t *p1_files = alpm_pkg_get_files(p1);
+                       alpm_filelist_t *p2_files = alpm_pkg_get_files(p2);
+
+                       common_files = _alpm_filelist_intersection(p1_files, 
p2_files);
 
                        if(common_files) {
                                alpm_list_t *k;
@@ -448,6 +450,18 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t 
*handle,
                                for(k = common_files; k; k = k->next) {
                                        alpm_file_t *file = k->data;
                                        snprintf(path, PATH_MAX, "%s%s", 
handle->root, file->name);
+
+                                       /* can skip file-file conflicts when 
forced */
+                                       if((handle->trans->flags & 
ALPM_TRANS_FLAG_FORCE) &&
+                                                       
alpm_filelist_contains(p1_files, file->name) &&
+                                                       
alpm_filelist_contains(p2_files, file->name)) {
+                                               _alpm_log(handle, 
ALPM_LOG_DEBUG,
+                                                       "%s exists in both '%s' 
and '%s'\n", file->name,
+                                                       p1->name, p2->name);
+                                               _alpm_log(handle, 
ALPM_LOG_DEBUG,
+                                                       "file-file conflict 
being forced\n");
+                                               continue;
+                                       }
                                        conflicts = add_fileconflict(handle, 
conflicts, path, p1, p2);
                                        if(handle->pm_errno == ALPM_ERR_MEMORY) 
{
                                                FREELIST(conflicts);
@@ -601,6 +615,14 @@ alpm_list_t *_alpm_db_find_fileconflicts(alpm_handle_t 
*handle,
                                }
                        }
 
+                       /* skip file-file conflicts when being forced */
+                       if((handle->trans->flags & ALPM_TRANS_FLAG_FORCE) &&
+                                       !S_ISDIR(file->mode) && 
!S_ISDIR(lsbuf.st_mode)) {
+                               _alpm_log(handle, ALPM_LOG_DEBUG,
+                                                       "file-file conflict 
being force\n");
+                               resolved_conflict = 1;
+                       }
+
                        if(!resolved_conflict) {
                                conflicts = add_fileconflict(handle, conflicts, 
path, p1, NULL);
                                if(handle->pm_errno == ALPM_ERR_MEMORY) {
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index be55500..15e6957 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -1241,7 +1241,7 @@ int _alpm_sync_commit(alpm_handle_t *handle, alpm_list_t 
**data)
        trans->state = STATE_COMMITING;
 
        /* fileconflict check */
-       if(!(trans->flags & (ALPM_TRANS_FLAG_FORCE|ALPM_TRANS_FLAG_DBONLY))) {
+       if(!(trans->flags & ALPM_TRANS_FLAG_DBONLY)) {
                EVENT(handle, ALPM_EVENT_FILECONFLICTS_START, NULL, NULL);
 
                _alpm_log(handle, ALPM_LOG_DEBUG, "looking for file 
conflicts\n");
diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index 417773d..924cdf5 100644
--- a/src/pacman/sync.c
+++ b/src/pacman/sync.c
@@ -881,6 +881,9 @@ int sync_prepare_execute(void)
                        alpm_strerror(err));
                switch(err) {
                        case ALPM_ERR_FILE_CONFLICTS:
+                               if(config->flags & ALPM_TRANS_FLAG_FORCE) {
+                                       printf(_("unable to %s directory-file 
conflicts\n"), "--force");
+                               }
                                for(i = data; i; i = alpm_list_next(i)) {
                                        alpm_fileconflict_t *conflict = i->data;
                                        switch(conflict->type) {
diff --git a/test/pacman/tests/upgrade046.py b/test/pacman/tests/upgrade046.py
index a02a713..d9ac66b 100644
--- a/test/pacman/tests/upgrade046.py
+++ b/test/pacman/tests/upgrade046.py
@@ -29,5 +29,3 @@
 self.addrule("FILE_MODIFIED=bin/foobar")
 self.addrule("FILE_EXIST=usr/share/file")
 self.addrule("FILE_MODIFIED=usr/share/file")
-
-self.expectfailure = True
-- 
1.8.1.3


Reply via email to