summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libalpm/add.c48
-rw-r--r--lib/libalpm/conflict.c57
-rw-r--r--pactest/tests/fileconflict004.py2
-rw-r--r--pactest/tests/fileconflict005.py1
-rw-r--r--pactest/tests/fileconflict006.py24
5 files changed, 103 insertions, 29 deletions
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index 4bd52dea..ddbcfeea 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 db1656fa..c4c57cb0 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -29,6 +29,7 @@
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
+#include <dirent.h>
/* libalpm */
#include "conflict.h"
@@ -348,6 +349,50 @@ void _alpm_fileconflict_free(pmfileconflict_t *conflict)
FREE(conflict);
}
+static int dir_belongsto_pkg(char *dirpath, pmpkg_t *pkg)
+{
+ struct dirent *ent = NULL;
+ struct stat sbuf;
+ char path[PATH_MAX];
+ char abspath[PATH_MAX];
+ DIR *dir;
+
+ snprintf(abspath, PATH_MAX, "%s%s", handle->root, dirpath);
+ dir = opendir(abspath);
+ if(dir == NULL) {
+ return(1);
+ }
+ while((ent = readdir(dir)) != NULL) {
+ const char *name = ent->d_name;
+
+ if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
+ continue;
+ }
+ snprintf(path, PATH_MAX, "%s/%s", dirpath, name);
+ snprintf(abspath, PATH_MAX, "%s%s", handle->root, path);
+ if(stat(abspath, &sbuf) != 0) {
+ continue;
+ }
+ if(S_ISDIR(sbuf.st_mode)) {
+ if(dir_belongsto_pkg(path, pkg)) {
+ continue;
+ } else {
+ closedir(dir);
+ return(0);
+ }
+ } else {
+ if(alpm_list_find_str(alpm_pkg_get_files(pkg),path)) {
+ continue;
+ } else {
+ closedir(dir);
+ return(0);
+ }
+ }
+ }
+ closedir(dir);
+ return(1);
+}
+
/* Find file conflicts that may occur during the transaction with two checks:
* 1: check every target against every target
* 2: check every target against the filesystem */
@@ -474,6 +519,18 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
}
}
+ /* check if all files of the dir belong to the installed pkg */
+ if(!resolved_conflict && S_ISDIR(lsbuf.st_mode) && dbpkg) {
+ char *dir = malloc(strlen(filestr) + 2);
+ sprintf(dir, "%s/", filestr);
+ if(alpm_list_find_str(alpm_pkg_get_files(dbpkg),dir)) {
+ _alpm_log(PM_LOG_DEBUG, "check if all files in %s belongs to %s\n",
+ dir, dbpkg->name);
+ resolved_conflict = dir_belongsto_pkg(filestr, dbpkg);
+ }
+ free(dir);
+ }
+
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 2396cedb..a5347ccd 100644
--- a/pactest/tests/fileconflict004.py
+++ b/pactest/tests/fileconflict004.py
@@ -17,5 +17,3 @@ self.addrule("PACMAN_RETCODE=0")
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 b9c0fa90..5c554afe 100644
--- a/pactest/tests/fileconflict005.py
+++ b/pactest/tests/fileconflict005.py
@@ -20,4 +20,3 @@ self.args = "-S pkg1"
self.addrule("PACMAN_RETCODE=1")
self.addrule("PKG_EXIST=pkg1")
self.addrule("PKG_VERSION=pkg1|1.0-1")
-
diff --git a/pactest/tests/fileconflict006.py b/pactest/tests/fileconflict006.py
new file mode 100644
index 00000000..84afff2d
--- /dev/null
+++ b/pactest/tests/fileconflict006.py
@@ -0,0 +1,24 @@
+self.description = "dir->symlink change during package upgrade (conflict)"
+
+p1 = pmpkg("pkg1", "1.0-1")
+p1.files = ["test/",
+ "test/file1",
+ "test/dir/file1",
+ "test/dir/file2"]
+self.addpkg2db("local", p1)
+
+p2 = pmpkg("pkg2")
+p2.files = ["test/dir/file3"]
+self.addpkg2db("local", p2)
+
+p3 = pmpkg("pkg1", "2.0-1")
+p3.files = ["test2/",
+ "test2/file3",
+ "test -> test2"]
+self.addpkg2db("sync", p3)
+
+self.args = "-S pkg1"
+
+self.addrule("PACMAN_RETCODE=1")
+self.addrule("PKG_EXIST=pkg1")
+self.addrule("PKG_VERSION=pkg1|1.0-1")