From d1ae2b6d35630ba8ffa2c5a94574bbd8fea1f45c Mon Sep 17 00:00:00 2001
From: Xavier Chantry <shiningxc@gmail.com>
Date: Fri, 17 Jul 2009 15:48:57 +0200
Subject: [PATCH] Fix fileconflict004

Add a simple check in conflict.c to fix 004. But this breaks 005.

However, it looks like the situation of 004 where one package replaces one of
its directory by one file or one symlink is more common.

And in case of 005, pacman is no longer able to detect the fileconflict in
advance, but pacman can be more verbose when the extraction of the symlink (or
file) fails. The patch to add.c looks more complex than it is, I just moved and
reindented code to handle cases 10 and 11 together.

Signed-off-by: Xavier Chantry <shiningxc@gmail.com>
---
 lib/libalpm/add.c                |   48 +++++++++++++++++--------------------
 lib/libalpm/conflict.c           |    9 +++++++
 pactest/tests/fileconflict004.py |    2 -
 pactest/tests/fileconflict005.py |    1 +
 4 files changed, 32 insertions(+), 28 deletions(-)

diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index 4bd52de..ddbcfee 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -353,28 +353,30 @@ static int extract_single_file(struct archive *archive,
 	if(_alpm_lstat(filename, &lsbuf) != 0 || stat(filename, &sbuf) != 0) {
 		/* cases 1,2,3: couldn't stat an existing file, skip all backup checks */
 	} else {
-		if(S_ISDIR(lsbuf.st_mode) && S_ISDIR(entrymode)) {
-			/* case 12: existing dir, ignore it */
-			if(lsbuf.st_mode != entrymode) {
-				/* if filesystem perms are different than pkg perms, warn user */
-				int mask = 07777;
-				_alpm_log(PM_LOG_WARNING, _("directory permissions differ on %s\n"
-							"filesystem: %o  package: %o\n"), entryname, lsbuf.st_mode & mask,
-						entrymode & mask);
-				alpm_logaction("warning: directory permissions differ on %s\n"
+		if(S_ISDIR(lsbuf.st_mode)) {
+			if(S_ISDIR(entrymode)) {
+				/* case 12: existing dir, ignore it */
+				if(lsbuf.st_mode != entrymode) {
+					/* if filesystem perms are different than pkg perms, warn user */
+					int mask = 07777;
+					_alpm_log(PM_LOG_WARNING, _("directory permissions differ on %s\n"
+								"filesystem: %o  package: %o\n"), entryname, lsbuf.st_mode & mask,
+							entrymode & mask);
+					alpm_logaction("warning: directory permissions differ on %s\n"
 							"filesystem: %o  package: %o\n", entryname, lsbuf.st_mode & mask,
-						entrymode & mask);
+							entrymode & mask);
+				}
+				_alpm_log(PM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
+						entryname);
+				archive_read_data_skip(archive);
+				return(0);
+			} else {
+				/* case 10/11: trying to overwrite dir with file/symlink, don't allow it */
+				_alpm_log(PM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
+						entryname);
+				archive_read_data_skip(archive);
+				return(1);
 			}
-			_alpm_log(PM_LOG_DEBUG, "extract: skipping dir extraction of %s\n",
-					entryname);
-			archive_read_data_skip(archive);
-			return(0);
-		} else if(S_ISDIR(lsbuf.st_mode) && S_ISLNK(entrymode)) {
-			/* case 11: existing dir, symlink in package, ignore it */
-			_alpm_log(PM_LOG_DEBUG, "extract: skipping symlink extraction of %s\n",
-					entryname);
-			archive_read_data_skip(archive);
-			return(0);
 		} else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(entrymode)) {
 			/* case 9: existing symlink, dir in package */
 			if(S_ISDIR(sbuf.st_mode)) {
@@ -390,12 +392,6 @@ static int extract_single_file(struct archive *archive,
 				archive_read_data_skip(archive);
 				return(1);
 			}
-		} else if(S_ISDIR(lsbuf.st_mode) && S_ISREG(entrymode)) {
-			/* case 10: trying to overwrite dir tree with file, don't allow it */
-			_alpm_log(PM_LOG_ERROR, _("extract: not overwriting dir with file %s\n"),
-					entryname);
-			archive_read_data_skip(archive);
-			return(1);
 		} else if(S_ISREG(lsbuf.st_mode) && S_ISDIR(entrymode)) {
 			/* case 6: trying to overwrite file with dir */
 			_alpm_log(PM_LOG_DEBUG, "extract: overwriting file with dir %s\n",
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index db1656f..8fb0875 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -474,6 +474,15 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
 				}
 			}
 
+			if(S_ISDIR(lsbuf.st_mode) && dbpkg) {
+				char *tmp = malloc(strlen(filestr) + 2);
+				sprintf(tmp, "%s/", filestr);
+				if(alpm_list_find_str(alpm_pkg_get_files(dbpkg),tmp)) {
+					resolved_conflict = 1;
+				}
+				free(tmp);
+			}
+
 			if(!resolved_conflict) {
 				_alpm_log(PM_LOG_DEBUG, "file found in conflict: %s\n", path);
 				conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_FILESYSTEM,
diff --git a/pactest/tests/fileconflict004.py b/pactest/tests/fileconflict004.py
index 2396ced..a5347cc 100644
--- a/pactest/tests/fileconflict004.py
+++ b/pactest/tests/fileconflict004.py
@@ -17,5 +17,3 @@
 self.addrule("PKG_EXIST=pkg1")
 self.addrule("PKG_VERSION=pkg1|2.0-1")
 self.addrule("FILE_TYPE=test|link")
-
-self.expectfailure = True
diff --git a/pactest/tests/fileconflict005.py b/pactest/tests/fileconflict005.py
index b9c0fa9..59470e1 100644
--- a/pactest/tests/fileconflict005.py
+++ b/pactest/tests/fileconflict005.py
@@ -21,3 +21,4 @@
 self.addrule("PKG_EXIST=pkg1")
 self.addrule("PKG_VERSION=pkg1|1.0-1")
 
+self.expectfailure = True
-- 
1.6.1.2

