From 592a091deb736fc8c171c79b847da4fffe0ea574 Mon Sep 17 00:00:00 2001 From: chantra Date: Feb 14 2022 16:57:29 +0000 Subject: [cow] Support hardlinks Since GH#1534, the way files are handled broke support for hardlinks in RPM CoW. This updates the CoW patch to properly handle hardlinks. Fixes: https://pagure.io/centos-sig-hyperscale/package-bugs/issue/14 --- diff --git a/SOURCES/cow...cow_signvalidation.diff b/SOURCES/cow...cow_signvalidation.diff index a76b5a8..3ca1c8e 100644 --- a/SOURCES/cow...cow_signvalidation.diff +++ b/SOURCES/cow...cow_signvalidation.diff @@ -582,7 +582,7 @@ index 39762c376..88807c53c 100644 } #endif diff --git a/plugins/reflink.c b/plugins/reflink.c -index 513887604..d5e6db27a 100644 +index 513887604..4fc1d74d1 100644 --- a/plugins/reflink.c +++ b/plugins/reflink.c @@ -13,6 +13,7 @@ @@ -593,6 +593,15 @@ index 513887604..d5e6db27a 100644 #include "lib/rpmte_internal.h" #include #include "rpmio/rpmio_internal.h" +@@ -28,7 +29,7 @@ + #undef HTDATATYPE + #define HASHTYPE inodeIndexHash + #define HTKEYTYPE rpm_ino_t +-#define HTDATATYPE int ++#define HTDATATYPE const char * + #include "lib/rpmhash.H" + #include "lib/rpmhash.C" + @@ -40,11 +41,6 @@ #define BUFFER_SIZE (1024 * 128) @@ -681,7 +690,16 @@ index 513887604..d5e6db27a 100644 rpmlog(RPMLOG_ERR, _("reflink: failed to seek for tail %p\n"), state->fd); return RPMRC_FAIL; -@@ -239,7 +220,7 @@ rpm_loff_t find(const unsigned char *digest, reflink_state state) { +@@ -182,7 +163,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) { + return RPMRC_FAIL; + } + state->inodeIndexes = inodeIndexHashCreate( +- state->keys, inodeId, inodeCmp, NULL, NULL ++ state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)rfree + ); + } + +@@ -239,13 +220,13 @@ rpm_loff_t find(const unsigned char *digest, reflink_state state) { return offset; } @@ -690,7 +708,46 @@ index 513887604..d5e6db27a 100644 mode_t file_mode, rpmFsmOp op) { struct file_clone_range fcr; -@@ -366,10 +347,21 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, + rpm_loff_t size; + int dst, rc; +- int *hlix; ++ const char **hl_target = NULL; + + reflink_state state = rpmPluginGetData(plugin); + if (state->table == NULL) { +@@ -262,18 +243,15 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, + /* check for hard link entry in table. GetEntry overwrites hlix with + * the address of the first match. + */ +- if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL, +- NULL)) { ++ if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target, ++ NULL, NULL)) { + /* entry is in table, use hard link */ +- char *fn = rpmfilesFN(state->files, hlix[0]); +- if (link(fn, path) != 0) { ++ if (link(hl_target[0], path) != 0) { + rpmlog(RPMLOG_ERR, + _("reflink: Unable to hard link %s -> %s due to %s\n"), +- fn, path, strerror(errno)); +- free(fn); ++ hl_target[0], path, strerror(errno)); + return RPMRC_FAIL; + } +- free(fn); + return RPMRC_PLUGIN_CONTENTS; + } + /* if we didn't hard link, then we'll track this inode as being +@@ -281,7 +259,7 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, + */ + if (rpmfiFNlink(fi) > 1) { + /* minor optimization: only store files with more than one link */ +- inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi)); ++ inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path)); + } + /* derived from wfd_open in fsm.c */ + mode_t old_umask = umask(0577); +@@ -366,10 +344,21 @@ static rpmRC reflink_fsm_file_pre(rpmPlugin plugin, rpmfi fi, const char* path, return RPMRC_OK; } @@ -1427,10 +1484,10 @@ index c3189d327..a110564e2 100644 (unset RPM_CONFIGDIR RPM_POPTEXEC_PATH; cd ${RPMTEST} && \ diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at new file mode 100644 -index 000000000..9e1b1559f +index 000000000..29165c1b9 --- /dev/null +++ b/tests/rpm2extents.at -@@ -0,0 +1,110 @@ +@@ -0,0 +1,141 @@ +# rpm2extents.at: Some very basic checks +# +# Copyright (C) 2022 Manu Bretelle @@ -1465,7 +1522,7 @@ index 000000000..9e1b1559f +# Check that transcoder writes checksig return code and content. +# +AT_SETUP([rpm2extents signature]) -+AT_KEYWORDS([rpm2extents digest signature]) ++AT_KEYWORDS([rpm2extents]) +AT_CHECK([ +RPMDB_INIT + @@ -1497,7 +1554,7 @@ index 000000000..9e1b1559f +AT_CLEANUP + +AT_SETUP([rpm2extents signature verification]) -+AT_KEYWORDS([rpm2extents digest signature]) ++AT_KEYWORDS([rpm2extents]) +AT_CHECK([ +RPMDB_INIT + @@ -1529,7 +1586,7 @@ index 000000000..9e1b1559f +AT_CLEANUP + +AT_SETUP([rpm2extents install package]) -+AT_KEYWORDS([rpm2extents install package]) ++AT_KEYWORDS([rpm2extents reflink]) +AT_SKIP_IF([$REFLINK_DISABLED]) +AT_CHECK([ +RPMDB_INIT @@ -1541,6 +1598,37 @@ index 000000000..9e1b1559f +[], +[]) +AT_CLEANUP ++ ++AT_SETUP([reflink hardlink package]) ++AT_KEYWORDS([reflink hardlink]) ++AT_SKIP_IF([$REFLINK_DISABLED]) ++AT_CHECK([ ++RPMDB_INIT ++ ++PKG=hlinktest-1.0-1.noarch.rpm ++runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null ++runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG} ++], ++[0], ++[], ++[]) ++AT_CLEANUP ++ ++AT_SETUP([rpm2extents install package]) ++AT_KEYWORDS([rpm2extents reflink]) ++AT_SKIP_IF([$REFLINK_DISABLED]) ++AT_CHECK([ ++RPMDB_INIT ++ ++runroot_other cat /data/RPMS/hello-2.0-1.x86_64.rpm | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/hello-2.0-1.x86_64.rpm 2> /dev/null ++runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/hello-2.0-1.x86_64.rpm ++], ++[0], ++[], ++[]) ++AT_CLEANUP ++ ++ diff --git a/tests/rpmtests.at b/tests/rpmtests.at index a1adab8e0..205fed6a3 100644 --- a/tests/rpmtests.at