summaryrefslogtreecommitdiff
path: root/lib/libalpm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libalpm')
-rw-r--r--lib/libalpm/add.c48
-rw-r--r--lib/libalpm/conflict.c57
2 files changed, 79 insertions, 26 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,