diff options
author | Dan McGee <dan@archlinux.org> | 2011-06-27 09:07:06 -0500 |
---|---|---|
committer | Dan McGee <dan@archlinux.org> | 2011-06-27 09:15:31 -0500 |
commit | e378170c2555b656ef87715d8284d038037ced5f (patch) | |
tree | ec6987dcd3f351903881bedee0a3bd846aa7fbe4 | |
parent | f8f4c2a6f301ab423f3ca702ebc24854cc701683 (diff) | |
download | pacman-e378170c2555b656ef87715d8284d038037ced5f.tar.xz |
Ensure a file can be replaced by a directory
This addresses FS#24904. In a normal upgrade case, this replacement
seems to work just fine. However, when doing a sync "replace" type
upgrade, we weren't properly handling this edge case due to path
comparison not ignoring trailing slashes. Fix this by pruning any
trailing slashes past a certain point of file conflict resolution where
we no longer need them, which allows us to safely detect cases such as
now tested in the new pactest.
Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r-- | lib/libalpm/conflict.c | 26 | ||||
-rw-r--r-- | test/pacman/tests/fileconflict008.py | 21 |
2 files changed, 39 insertions, 8 deletions
diff --git a/lib/libalpm/conflict.c b/lib/libalpm/conflict.c index b1df1086..db10d329 100644 --- a/lib/libalpm/conflict.c +++ b/lib/libalpm/conflict.c @@ -433,7 +433,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, /* declarations for second check */ struct stat lsbuf, sbuf; - char *filestr = NULL; /* CHECK 2: check every target against the filesystem */ _alpm_log(PM_LOG_DEBUG, "searching for filesystem conflicts: %s\n", p1->name); @@ -452,7 +451,9 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, } for(j = tmpfiles; j; j = j->next) { - filestr = j->data; + const char *filestr = j->data, *relative_path; + /* have we acted on this conflict? */ + int resolved_conflict = 0; snprintf(path, PATH_MAX, "%s%s", handle->root, filestr); @@ -471,16 +472,22 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, "%s is a symlink to a dir, hopefully not a conflict\n", path); continue; } + /* if we made it to here, we want all subsequent path comparisons to + * not include the trailing slash. This allows things like file -> + * directory replacements. */ + path[strlen(path) - 1] = '\0'; } - _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path); - int resolved_conflict = 0; /* have we acted on this conflict? */ + _alpm_log(PM_LOG_DEBUG, "checking possible conflict: %s\n", path); + relative_path = path + strlen(handle->root); /* 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); + if(alpm_list_find_str(alpm_pkg_get_files(rempkg), relative_path)) { + _alpm_log(PM_LOG_DEBUG, + "local file will be removed, not a conflict: %s\n", + relative_path); resolved_conflict = 1; } } @@ -498,8 +505,11 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans, /* 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(filestr)); - _alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr); + trans->skip_remove = alpm_list_add(trans->skip_remove, + strdup(filestr)); + _alpm_log(PM_LOG_DEBUG, + "file changed packages, adding to remove skiplist: %s\n", + filestr); resolved_conflict = 1; } } diff --git a/test/pacman/tests/fileconflict008.py b/test/pacman/tests/fileconflict008.py new file mode 100644 index 00000000..24ea8852 --- /dev/null +++ b/test/pacman/tests/fileconflict008.py @@ -0,0 +1,21 @@ +self.description = "Fileconflict file -> dir on package replacement (FS#24904)" + +lp = pmpkg("dummy") +lp.files = ["dir/filepath", + "dir/file"] +self.addpkg2db("local", lp) + +p1 = pmpkg("replace") +p1.provides = ["dummy"] +p1.replaces = ["dummy"] +p1.files = ["dir/filepath/", + "dir/filepath/file", + "dir/file", + "dir/file2"] +self.addpkg2db("sync", p1) + +self.args = "-Su" + +self.addrule("PACMAN_RETCODE=0") +self.addrule("!PKG_EXIST=dummy") +self.addrule("PKG_EXIST=replace") |