michal-grzedzicki / rpms / rpm

Forked from rpms/rpm 5 months ago
Clone
629b27
From fd8ffffced543e248847d63e9375fb95584f998d Mon Sep 17 00:00:00 2001
629b27
From: chantra <chantr4@gmail.com>
629b27
Date: Fri, 11 Feb 2022 18:09:47 -0800
629b27
Subject: [PATCH 22/30] [reflink] fix support for hardlinks
629b27
629b27
a `suffix` made of ";${tid}" is now used until the changes are commited. As such, when
629b27
linking the file, we should link to the suffixed file.
629b27
629b27
The `suffix` is currently internal only to rpmPackageFilesInstall and there is
629b27
no obvious way to use data from struct `filedata_s` without exposing it to
629b27
a bunch of other places such as rpmplugin*.
629b27
We already keep track of the first file index. We used to use this to fetch the
629b27
file name, but due to suffix, the file is not named correctly, e.g it
629b27
has the name we will want at the end, once the transaction is commited,
629b27
not the temporary name.
629b27
Instead of re-implementing a local suffix that may change over time as
629b27
the implementation evolves, we can store the name of the file we should link to
629b27
in the hash instead of the index, which we were then using to fetch the
629b27
file name.
629b27
When hardlinking, we can then retrieve the name of the target file
629b27
instead of the index, like we previously did, and hardlink to that
629b27
without any issues.
629b27
Add a test to validate that reflink can handle hardlinking.
629b27
629b27
Originally, the test added would fail with:
629b27
629b27
```
629b27
error: reflink: Unable to hard link /foo/hello -> /foo/hello-bar;6207219c due to No such file or directory
629b27
error: Plugin reflink: hook fsm_file_install failed
629b27
error: unpacking of archive failed on file /foo/hello-bar;6207219c:
629b27
cpio: (error 0x2)
629b27
error: hlinktest-1.0-1.noarch: install failed
629b27
./rpm2extents.at:114: exit code was 1, expected 0
629b27
499. rpm2extents.at:112: 499. reflink hardlink package
629b27
(rpm2extents.at:112): FAILED (rpm2extents.at:114)
629b27
```
629b27
629b27
After this change, the test passes.
629b27
---
629b27
 plugins/reflink.c    | 19 ++++++++-----------
629b27
 tests/rpm2extents.at | 15 +++++++++++++++
629b27
 2 files changed, 23 insertions(+), 11 deletions(-)
629b27
629b27
diff --git a/plugins/reflink.c b/plugins/reflink.c
629b27
index d5e6db27a..4fc1d74d1 100644
629b27
--- a/plugins/reflink.c
629b27
+++ b/plugins/reflink.c
629b27
@@ -29,7 +29,7 @@
629b27
 #undef HTDATATYPE
629b27
 #define HASHTYPE inodeIndexHash
629b27
 #define HTKEYTYPE rpm_ino_t
629b27
-#define HTDATATYPE int
629b27
+#define HTDATATYPE const char *
629b27
 #include "lib/rpmhash.H"
629b27
 #include "lib/rpmhash.C"
629b27
 
629b27
@@ -163,7 +163,7 @@ static rpmRC reflink_psm_pre(rpmPlugin plugin, rpmte te) {
629b27
 	    return RPMRC_FAIL;
629b27
 	}
629b27
 	state->inodeIndexes = inodeIndexHashCreate(
629b27
-	    state->keys, inodeId, inodeCmp, NULL, NULL
629b27
+	    state->keys, inodeId, inodeCmp, NULL, (inodeIndexHashFreeData)rfree
629b27
 	);
629b27
     }
629b27
 
629b27
@@ -226,7 +226,7 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa
629b27
     struct file_clone_range fcr;
629b27
     rpm_loff_t size;
629b27
     int dst, rc;
629b27
-    int *hlix;
629b27
+    const char **hl_target = NULL;
629b27
 
629b27
     reflink_state state = rpmPluginGetData(plugin);
629b27
     if (state->table == NULL) {
629b27
@@ -243,18 +243,15 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa
629b27
 	/* check for hard link entry in table. GetEntry overwrites hlix with
629b27
 	 * the address of the first match.
629b27
 	 */
629b27
-	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hlix, NULL,
629b27
-	                           NULL)) {
629b27
+	if (inodeIndexHashGetEntry(state->inodeIndexes, inode, &hl_target,
629b27
+				   NULL, NULL)) {
629b27
 	    /* entry is in table, use hard link */
629b27
-	    char *fn = rpmfilesFN(state->files, hlix[0]);
629b27
-	    if (link(fn, path) != 0) {
629b27
+	    if (link(hl_target[0], path) != 0) {
629b27
 		rpmlog(RPMLOG_ERR,
629b27
 		       _("reflink: Unable to hard link %s -> %s due to %s\n"),
629b27
-		       fn, path, strerror(errno));
629b27
-		free(fn);
629b27
+		       hl_target[0], path, strerror(errno));
629b27
 		return RPMRC_FAIL;
629b27
 	    }
629b27
-	    free(fn);
629b27
 	    return RPMRC_PLUGIN_CONTENTS;
629b27
 	}
629b27
 	/* if we didn't hard link, then we'll track this inode as being
629b27
@@ -262,7 +259,7 @@ static rpmRC reflink_fsm_file_install(rpmPlugin plugin, rpmfi fi, const char* pa
629b27
 	 */
629b27
 	if (rpmfiFNlink(fi) > 1) {
629b27
 	    /* minor optimization: only store files with more than one link */
629b27
-	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rpmfiFX(fi));
629b27
+	    inodeIndexHashAddEntry(state->inodeIndexes, inode, rstrdup(path));
629b27
 	}
629b27
 	/* derived from wfd_open in fsm.c */
629b27
 	mode_t old_umask = umask(0577);
629b27
diff --git a/tests/rpm2extents.at b/tests/rpm2extents.at
629b27
index fa124ac03..5c66de7f6 100644
629b27
--- a/tests/rpm2extents.at
629b27
+++ b/tests/rpm2extents.at
629b27
@@ -123,3 +123,18 @@ test -f ${RPMTEST}/usr/bin/hello
629b27
 [],
629b27
 [])
629b27
 AT_CLEANUP
629b27
+
629b27
+AT_SETUP([reflink hardlink package])
629b27
+AT_KEYWORDS([reflink hardlink])
629b27
+AT_SKIP_IF([$REFLINK_DISABLED])
629b27
+AT_CHECK([
629b27
+RPMDB_INIT
629b27
+
629b27
+PKG=hlinktest-1.0-1.noarch.rpm
629b27
+runroot_other cat /data/RPMS/${PKG} | runroot_other rpm2extents SHA256 > ${RPMTEST}/tmp/${PKG} 2> /dev/null
629b27
+runroot_plugins rpm -i --nodigest --nodeps --undefine=%__transaction_dbus_announce /tmp/${PKG}
629b27
+],
629b27
+[0],
629b27
+[],
629b27
+[])
629b27
+AT_CLEANUP
629b27
-- 
629b27
2.35.1
629b27