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>
This commit is contained in:
parent
f8f4c2a6f3
commit
e378170c25
2 changed files with 39 additions and 8 deletions
|
@ -433,7 +433,6 @@ alpm_list_t *_alpm_db_find_fileconflicts(pmdb_t *db, pmtrans_t *trans,
|
||||||
|
|
||||||
/* declarations for second check */
|
/* declarations for second check */
|
||||||
struct stat lsbuf, sbuf;
|
struct stat lsbuf, sbuf;
|
||||||
char *filestr = NULL;
|
|
||||||
|
|
||||||
/* CHECK 2: check every target against the filesystem */
|
/* CHECK 2: check every target against the filesystem */
|
||||||
_alpm_log(PM_LOG_DEBUG, "searching for filesystem conflicts: %s\n", p1->name);
|
_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) {
|
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);
|
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);
|
"%s is a symlink to a dir, hopefully not a conflict\n", path);
|
||||||
continue;
|
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?) */
|
/* Check remove list (will we remove the conflicting local file?) */
|
||||||
for(k = remove; k && !resolved_conflict; k = k->next) {
|
for(k = remove; k && !resolved_conflict; k = k->next) {
|
||||||
pmpkg_t *rempkg = k->data;
|
pmpkg_t *rempkg = k->data;
|
||||||
if(rempkg && alpm_list_find_str(alpm_pkg_get_files(rempkg), 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", filestr);
|
_alpm_log(PM_LOG_DEBUG,
|
||||||
|
"local file will be removed, not a conflict: %s\n",
|
||||||
|
relative_path);
|
||||||
resolved_conflict = 1;
|
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
|
/* skip removal of file, but not add. this will prevent a second
|
||||||
* package from removing the file when it was already installed
|
* package from removing the file when it was already installed
|
||||||
* by its new owner (whether the file is in backup array or not */
|
* by its new owner (whether the file is in backup array or not */
|
||||||
trans->skip_remove = alpm_list_add(trans->skip_remove, strdup(filestr));
|
trans->skip_remove = alpm_list_add(trans->skip_remove,
|
||||||
_alpm_log(PM_LOG_DEBUG, "file changed packages, adding to remove skiplist: %s\n", filestr);
|
strdup(filestr));
|
||||||
|
_alpm_log(PM_LOG_DEBUG,
|
||||||
|
"file changed packages, adding to remove skiplist: %s\n",
|
||||||
|
filestr);
|
||||||
resolved_conflict = 1;
|
resolved_conflict = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
test/pacman/tests/fileconflict008.py
Normal file
21
test/pacman/tests/fileconflict008.py
Normal file
|
@ -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")
|
Loading…
Add table
Reference in a new issue