Relying on localdb to determine which trigger operations should match is
completely broken for PostTransaction hooks because the localdb has
already been updated.  Store a copy of the old version of any packages
being updated to use instead.

Fixes FS#47996

Signed-off-by: Andrew Gregory <[email protected]>
---
 lib/libalpm/add.c                                  | 14 +++----------
 lib/libalpm/hook.c                                 |  4 ++--
 lib/libalpm/package.c                              |  3 +++
 lib/libalpm/package.h                              |  1 +
 lib/libalpm/sync.c                                 |  8 ++++++++
 test/pacman/tests/TESTS                            |  1 +
 .../tests/hook-pkg-postinstall-trigger-match.py    | 23 ++++++++++++++++++++++
 7 files changed, 41 insertions(+), 13 deletions(-)
 create mode 100644 test/pacman/tests/hook-pkg-postinstall-trigger-match.py

diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index 2639fa7..f5c9a95 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -409,9 +409,8 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
        ASSERT(trans != NULL, return -1);
 
        /* see if this is an upgrade. if so, remove the old package first */
-       alpm_pkg_t *local = _alpm_db_get_pkgfromcache(db, newpkg->name);
-       if(local) {
-               int cmp = _alpm_pkg_compare_versions(newpkg, local);
+       if((oldpkg = newpkg->oldpkg)) {
+               int cmp = _alpm_pkg_compare_versions(newpkg, oldpkg);
                if(cmp < 0) {
                        log_msg = "downgrading";
                        progress = ALPM_PROGRESS_DOWNGRADE_START;
@@ -427,14 +426,8 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
                }
                is_upgrade = 1;
 
-               /* we'll need to save some record for backup checks later */
-               if(_alpm_pkg_dup(local, &oldpkg) == -1) {
-                       ret = -1;
-                       goto cleanup;
-               }
-
                /* copy over the install reason */
-               newpkg->reason = alpm_pkg_get_reason(local);
+               newpkg->reason = alpm_pkg_get_reason(oldpkg);
        } else {
                event.operation = ALPM_PACKAGE_INSTALL;
        }
@@ -630,7 +623,6 @@ static int commit_single_pkg(alpm_handle_t *handle, 
alpm_pkg_t *newpkg,
        EVENT(handle, &event);
 
 cleanup:
-       _alpm_pkg_free(oldpkg);
        return ret;
 }
 
diff --git a/lib/libalpm/hook.c b/lib/libalpm/hook.c
index 81c347e..6890a6e 100644
--- a/lib/libalpm/hook.c
+++ b/lib/libalpm/hook.c
@@ -374,7 +374,7 @@ static int _alpm_hook_trigger_match_file(alpm_handle_t 
*handle,
        /* check if file will be removed due to package upgrade */
        for(i = handle->trans->add; i; i = i->next) {
                alpm_pkg_t *spkg = i->data;
-               alpm_pkg_t *pkg = alpm_db_get_pkg(handle->db_local, spkg->name);
+               alpm_pkg_t *pkg = spkg->oldpkg;
                if(pkg) {
                        alpm_filelist_t filelist = pkg->files;
                        size_t f;
@@ -463,7 +463,7 @@ static int _alpm_hook_trigger_match_pkg(alpm_handle_t 
*handle,
                for(i = handle->trans->add; i; i = i->next) {
                        alpm_pkg_t *pkg = i->data;
                        if(_alpm_fnmatch_patterns(t->targets, pkg->name) == 0) {
-                               if(alpm_db_get_pkg(handle->db_local, 
pkg->name)) {
+                               if(pkg->oldpkg) {
                                        if(t->op & ALPM_HOOK_OP_UPGRADE) {
                                                if(hook->needs_targets) {
                                                        upgrade = 
alpm_list_add(upgrade, pkg->name);
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 4f8ddb3..f08df8b 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -682,6 +682,7 @@ void _alpm_pkg_free(alpm_pkg_t *pkg)
        alpm_list_free(pkg->deltas);
        alpm_list_free(pkg->delta_path);
        alpm_list_free(pkg->removes);
+       _alpm_pkg_free(pkg->oldpkg);
 
        if(pkg->origin == ALPM_PKG_FROM_FILE) {
                FREE(pkg->origin_data.file);
@@ -707,6 +708,8 @@ void _alpm_pkg_free_trans(alpm_pkg_t *pkg)
 
        alpm_list_free(pkg->removes);
        pkg->removes = NULL;
+       _alpm_pkg_free(pkg->oldpkg);
+       pkg->oldpkg = NULL;
 }
 
 /* Is spkg an upgrade for localpkg? */
diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h
index 65afaf7..9fea356 100644
--- a/lib/libalpm/package.h
+++ b/lib/libalpm/package.h
@@ -117,6 +117,7 @@ struct __alpm_pkg_t {
        alpm_list_t *deltas;
        alpm_list_t *delta_path;
        alpm_list_t *removes; /* in transaction targets only */
+       alpm_pkg_t *oldpkg; /* in transaction targets only */
 
        struct pkg_operations *ops;
 
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 3d3915c..00b68d0 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -659,10 +659,15 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t 
**data)
        for(i = trans->add; i; i = i->next) {
                /* update download size field */
                alpm_pkg_t *spkg = i->data;
+               alpm_pkg_t *lpkg = alpm_db_get_pkg(handle->db_local, 
spkg->name);
                if(compute_download_size(spkg) < 0) {
                        ret = -1;
                        goto cleanup;
                }
+               if(lpkg && _alpm_pkg_dup(lpkg, &spkg->oldpkg) != 0) {
+                       ret = -1;
+                       goto cleanup;
+               }
        }
 
 cleanup:
@@ -1260,6 +1265,9 @@ static int load_packages(alpm_handle_t *handle, 
alpm_list_t **data,
                pkgfile->reason = spkg->reason;
                /* copy over validation method */
                pkgfile->validation = spkg->validation;
+               /* transfer oldpkg */
+               pkgfile->oldpkg = spkg->oldpkg;
+               spkg->oldpkg = NULL;
                i->data = pkgfile;
                /* spkg has been removed from the target list, so we can free 
the
                 * sync-specific fields */
diff --git a/test/pacman/tests/TESTS b/test/pacman/tests/TESTS
index acdf769..9c33020 100644
--- a/test/pacman/tests/TESTS
+++ b/test/pacman/tests/TESTS
@@ -59,6 +59,7 @@ TESTS += test/pacman/tests/hook-file-remove-trigger-match.py
 TESTS += test/pacman/tests/hook-file-upgrade-nomatch.py
 TESTS += test/pacman/tests/hook-invalid-trigger.py
 TESTS += test/pacman/tests/hook-pkg-install-trigger-match.py
+TESTS += test/pacman/tests/hook-pkg-postinstall-trigger-match.py
 TESTS += test/pacman/tests/hook-pkg-remove-trigger-match.py
 TESTS += test/pacman/tests/hook-pkg-upgrade-trigger-match.py
 TESTS += test/pacman/tests/hook-target-list.py
diff --git a/test/pacman/tests/hook-pkg-postinstall-trigger-match.py 
b/test/pacman/tests/hook-pkg-postinstall-trigger-match.py
new file mode 100644
index 0000000..b9b07cd
--- /dev/null
+++ b/test/pacman/tests/hook-pkg-postinstall-trigger-match.py
@@ -0,0 +1,23 @@
+self.description = "Install a package matching a PostTransaction Install hook"
+
+self.add_script("hook-script", ": > hook-output")
+self.add_hook("hook",
+        """
+        [Trigger]
+        Type = Package
+        Operation = Install
+        Target = foo
+
+        [Action]
+        When = PostTransaction
+        Exec = bin/hook-script
+        """);
+
+sp = pmpkg("foo")
+self.addpkg2db("sync", sp)
+
+self.args = "-S foo"
+
+self.addrule("PACMAN_RETCODE=0")
+self.addrule("PKG_EXIST=foo")
+self.addrule("FILE_EXIST=hook-output")
-- 
2.7.1

Reply via email to