summaryrefslogtreecommitdiffstats
path: root/lib/libalpm/conflict.c
diff options
context:
space:
mode:
authorNagy Gabor <ngaba@bibl.u-szeged.hu>2009-01-02 17:43:05 +0100
committerDan McGee <dan@archlinux.org>2009-04-11 20:59:55 +0200
commit391952600d30bf7c28c5403c5c9e220d345ffe87 (patch)
tree2b22e18f512afc559c615b81317e0f7f0a63085a /lib/libalpm/conflict.c
parent634304feae6574d42e069a6718621cf2852f08ab (diff)
downloadpacman-391952600d30bf7c28c5403c5c9e220d345ffe87.tar.gz
pacman-391952600d30bf7c28c5403c5c9e220d345ffe87.tar.xz
Fix for trans001.py (FS#9088)
From now on _alpm_db_find_fileconflicts() works with upgrade and remove target lists (like checkdeps), which makes it transaction independent (we still need a trans param because of the progressbar). This is a small step towards the universal transaction. So we call this function directly from sync.c before commiting the remove transaction. This is much safer, but we can get false fileconflict error alarms in some tricky cases ("symlinks puzzle" etc). The patch on find_fileconflict looks complex, but it is mainly an "indent-patch", the new code-part can be found after the /* check remove list ... */ comment, and I modified something around the "file has changed hand" case (see comment modifications in the code). Unfortunately sync.c became more ugly, because we have to create 2 parallel internal transactions: to avoid duplicated work, upgrade transaction is used to load package data (filelists). This problem will disappear, when we finally get rid of internal transactions. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
Diffstat (limited to 'lib/libalpm/conflict.c')
-rw-r--r--lib/libalpm/conflict.c90
1 files changed, 45 insertions, 45 deletions
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c
index 499e55a4..4daa2194 100644
--- a/lib/libalpm/conflict.c
+++ b/lib/libalpm/conflict.c
@@ -350,16 +350,16 @@ void _alpm_fileconflict_free(pmfileconflict_t *conflict)
/* 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 */
-alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *root)
+alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
+ alpm_list_t *upgrade, alpm_list_t *remove)
{
- alpm_list_t *i, *conflicts = NULL;
- alpm_list_t *targets = trans->packages;
- int numtargs = alpm_list_count(targets);
+ alpm_list_t *i, *j, *conflicts = NULL;
+ int numtargs = alpm_list_count(upgrade);
int current;
ALPM_LOG_FUNC;
- if(db == NULL || targets == NULL || root == NULL) {
+ if(db == NULL || upgrade == NULL) {
return(NULL);
}
@@ -367,8 +367,8 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
* be possible with real transactions. Right now we only do half as much
* here as we do when we actually extract files in add.c with our 12
* different cases. */
- for(current = 1, i = targets; i; i = i->next, current++) {
- alpm_list_t *j, *k, *tmpfiles = NULL;
+ for(current = 1, i = upgrade; i; i = i->next, current++) {
+ alpm_list_t *k, *tmpfiles = NULL;
pmpkg_t *p1, *p2, *dbpkg;
char path[PATH_MAX+1];
@@ -392,7 +392,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
if(tmpfiles) {
for(k = tmpfiles; k; k = k->next) {
- snprintf(path, PATH_MAX, "%s%s", root, (char *)k->data);
+ snprintf(path, PATH_MAX, "%s%s", handle->root, (char *)k->data);
conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_TARGET, path,
alpm_pkg_get_name(p1), alpm_pkg_get_name(p2));
}
@@ -408,7 +408,7 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
_alpm_log(PM_LOG_DEBUG, "searching for filesystem conflicts: %s\n", p1->name);
dbpkg = _alpm_db_get_pkgfromcache(db, p1->name);
- /* Do two different checks here. f the package is currently installed,
+ /* Do two different checks here. If the package is currently installed,
* then only check files that are new in the new package. If the package
* is not currently installed, then simply stat the whole filelist */
if(dbpkg) {
@@ -420,12 +420,10 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
tmpfiles = alpm_list_strdup(alpm_pkg_get_files(p1));
}
- /* loop over each file to be installed */
for(j = tmpfiles; j; j = j->next) {
- int skip_conflict = 0;
filestr = j->data;
- snprintf(path, PATH_MAX, "%s%s", root, filestr);
+ snprintf(path, PATH_MAX, "%s%s", handle->root, filestr);
/* stat the file - if it exists, do some checks */
if(_alpm_lstat(path, &lsbuf) != 0) {
@@ -436,48 +434,50 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, char *roo
if(path[strlen(path)-1] == '/') {
if(S_ISDIR(lsbuf.st_mode)) {
_alpm_log(PM_LOG_DEBUG, "%s is a directory, not a conflict\n", path);
- skip_conflict = 1;
+ continue;
} else if(S_ISLNK(lsbuf.st_mode) && S_ISDIR(sbuf.st_mode)) {
_alpm_log(PM_LOG_DEBUG,
"%s is a symlink to a dir, hopefully not a conflict\n", path);
- skip_conflict = 1;
+ continue;
}
}
- if(!skip_conflict) {
- _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path);
-
- /* Look at all the targets to see if file has changed hands */
- int resolved_conflict = 0; /* have we acted on this conflict? */
- for(k = targets; k; k = k->next) {
- p2 = k->data;
- if(!p2 || strcmp(p1->name, p2->name) == 0) {
- continue;
- }
+ _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path);
- pmpkg_t *localp2 = _alpm_db_get_pkgfromcache(db, p2->name);
-
- /* Check if it used to exist in a package, but doesn't anymore */
- alpm_list_t *pkgfiles, *localfiles; /* added for readability */
- pkgfiles = alpm_pkg_get_files(p2);
- localfiles = alpm_pkg_get_files(localp2);
-
- if(localp2 && !alpm_list_find_str(pkgfiles, filestr)
- && alpm_list_find_str(localfiles, filestr)) {
- /* skip removal of file, but not add. this will prevent a second
- * package from removing the file when it was already installed
- * by its new owner (whether the file is in backup array or not */
- trans->skip_remove = alpm_list_add(trans->skip_remove, strdup(path));
- _alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr);
- resolved_conflict = 1;
- break;
- }
+ int resolved_conflict = 0; /* have we acted on this conflict? */
+
+ /* Check remove list (will we remove the conflicting local file?) */
+ for(k = remove; k && !resolved_conflict; k = k->next) {
+ pmpkg_t *rempkg = k->data;
+ if(rempkg && alpm_list_find_str(alpm_pkg_get_files(rempkg), filestr)) {
+ _alpm_log(PM_LOG_DEBUG, "local file will be removed, not a conflict: %s\n", filestr);
+ resolved_conflict = 1;
}
- if(!resolved_conflict) {
- _alpm_log(PM_LOG_DEBUG, "file found in conflict: %s\n", path);
- conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_FILESYSTEM,
- path, p1->name, NULL);
+ }
+
+ /* Look at all the targets to see if file has changed hands */
+ for(k = upgrade; k && !resolved_conflict; k = k->next) {
+ p2 = k->data;
+ if(!p2 || strcmp(p1->name, p2->name) == 0) {
+ continue;
+ }
+ pmpkg_t *localp2 = _alpm_db_get_pkgfromcache(db, p2->name);
+
+ /* localp2->files will be removed (target conflicts are handled by CHECK 1) */
+ if(localp2 && alpm_list_find_str(alpm_pkg_get_files(localp2), filestr)) {
+ /* skip removal of file, but not add. this will prevent a second
+ * package from removing the file when it was already installed
+ * by its new owner (whether the file is in backup array or not */
+ trans->skip_remove = alpm_list_add(trans->skip_remove, strdup(path));
+ _alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr);
+ resolved_conflict = 1;
}
}
+
+ if(!resolved_conflict) {
+ _alpm_log(PM_LOG_DEBUG, "file found in conflict: %s\n", path);
+ conflicts = add_fileconflict(conflicts, PM_FILECONFLICT_FILESYSTEM,
+ path, p1->name, NULL);
+ }
}
FREELIST(tmpfiles);
}