All of lore.kernel.org
 help / color / mirror / Atom feed
* [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks
@ 2026-05-12 22:20 Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 1/5] run_tests.sh: Allow the user to specify specific tests to run Mark Hatle
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

Changqing Li found the issue related to the renaming followed by a
hardlink causing failures.  Created test case(s) based on Paul
Barker's suggestion.

The test cases check both 'mv / ln', as well as specific calls to
both rename and renameat2.

Due to these tests it was observed that rename had the same bug as
renameat2, and the fix was applied there as well.

Changqing Li (1):
  renameat2/renameat: only ignore when both old and new path are not in
    PSEUDO_INCLUDE_PATHS

Mark Hatle (4):
  run_tests.sh: Allow the user to specify specific tests to run
  tests: Add mv then hardlink testing
  rename: only ignore when both old and new path are not in
    PSEUDO_INCLUDE_PATHS
  Makefile.in: Bump version to 1.9.7

 Makefile.in                    |   2 +-
 makewrappers                   |   4 +-
 ports/unix/guts/rename.c       |  26 +++++++++--
 ports/unix/guts/renameat.c     |  32 ++++++++++---
 run_tests.sh                   |  32 +++++++++++--
 test/test-mv-hardlink.sh       |  52 +++++++++++++++++++++
 test/test-rename-hardlink.c    |  87 +++++++++++++++++++++++++++++++++++
 test/test-rename-hardlink.sh   |  14 ++++++
 test/test-renameat-hardlink.c  | 101 +++++++++++++++++++++++++++++++++++++++++
 test/test-renameat-hardlink.sh |  14 ++++++
 10 files changed, 348 insertions(+), 16 deletions(-)
 create mode 100755 test/test-mv-hardlink.sh
 create mode 100644 test/test-rename-hardlink.c
 create mode 100755 test/test-rename-hardlink.sh
 create mode 100644 test/test-renameat-hardlink.c
 create mode 100755 test/test-renameat-hardlink.sh

-- 
1.8.3.1



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [pseudo][PATCH 1/5] run_tests.sh: Allow the user to specify specific tests to run
  2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
@ 2026-05-12 22:20 ` Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 2/5] tests: Add mv then hardlink testing Mark Hatle
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

From: Mark Hatle <mark.hatle@amd.com>

AI-Generated: Implemented with the assistance of github CoPilot (Claude Opus 4.6)

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 run_tests.sh | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/run_tests.sh b/run_tests.sh
index 1b6cfb9..306a561 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -4,11 +4,15 @@
 #
 
 opt_verbose=
+test_args=()
 
 usage()
 {
     echo >&2 "usage:"
-    echo >&2 "  run_tests [-v|--verbose]"
+    echo >&2 "  run_tests [-v|--verbose] [test ...]"
+    echo >&2 ""
+    echo >&2 "If no tests are specified, all tests are run."
+    echo >&2 "Tests can be specified as filenames (test-fstat.sh) or basenames (test-fstat)."
     exit 1
 }
 
@@ -19,9 +23,15 @@ do
         -v | --verbose)
                 opt_verbose=-v
                 ;;
-        *)
+        -h | --help)
+                usage
+                ;;
+        -*)
                 usage
                 ;;
+        *)
+                test_args+=("$arg")
+                ;;
         esac
 done
 
@@ -36,7 +46,23 @@ num_failed_tests=0
 
 tmplog="$(mktemp pseudo.log.XXXXXXXX)"
 
-for file in test/test*.sh
+if [ ${#test_args[@]} -gt 0 ]; then
+    test_files=()
+    for t in "${test_args[@]}"; do
+        # Strip directory prefix and ensure .sh suffix
+        t="${t##*/}"
+        t="${t%.sh}.sh"
+        if [ -f "test/$t" ]; then
+            test_files+=("test/$t")
+        else
+            echo >&2 "Warning: test/$t not found, skipping."
+        fi
+    done
+else
+    test_files=(test/test*.sh)
+fi
+
+for file in "${test_files[@]}"
 do
     filename=${file#test/}
     let num_tests++
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [pseudo][PATCH 2/5] tests: Add mv then hardlink testing
  2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 1/5] run_tests.sh: Allow the user to specify specific tests to run Mark Hatle
@ 2026-05-12 22:20 ` Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 3/5] renameat2/renameat: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS Mark Hatle
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

From: Mark Hatle <mark.hatle@amd.com>

Per the discussion:
   https://lists.openembedded.org/g/openembedded-core/topic/119214074#msg236712

Changqing Li found an issue with renameat (mv) from an ignored to an
included path was not updating the database properly.  This could lead
to an abort, but would definitely cause the new file/symlink to have
the wrong (in pseudo terms) uid/gid.

The test-mv-hardlink.sh is an attempt to implement the test case
suggested by Paul Barker.  It was noted that both rename and renameat
may suffer from the same issue, so additional test cases for each
implementation was added as well.

AI-Generated: Implemented with the assistance of github CoPilot (Claude Opus 4.6)

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 test/test-mv-hardlink.sh       |  52 +++++++++++++++++++++
 test/test-rename-hardlink.c    |  87 +++++++++++++++++++++++++++++++++++
 test/test-rename-hardlink.sh   |  14 ++++++
 test/test-renameat-hardlink.c  | 101 +++++++++++++++++++++++++++++++++++++++++
 test/test-renameat-hardlink.sh |  14 ++++++
 5 files changed, 268 insertions(+)
 create mode 100755 test/test-mv-hardlink.sh
 create mode 100644 test/test-rename-hardlink.c
 create mode 100755 test/test-rename-hardlink.sh
 create mode 100644 test/test-renameat-hardlink.c
 create mode 100755 test/test-renameat-hardlink.sh

diff --git a/test/test-mv-hardlink.sh b/test/test-mv-hardlink.sh
new file mode 100755
index 0000000..2963ef3
--- /dev/null
+++ b/test/test-mv-hardlink.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Test that rename (mv) from outside PSEUDO_INCLUDE_PATHS followed by
+# hardlink properly tracks file ownership.
+#
+# Reproduces: https://lists.openembedded.org/g/openembedded-core/message/236712
+#
+# In Yocto, files are often moved from ${B} (build dir, outside
+# PSEUDO_INCLUDE_PATHS) to ${D} (image dir, tracked by pseudo) and
+# then hardlinked. If pseudo doesn't track the rename, the hardlink
+# gets recorded with the real UID, causing inconsistent ownership
+# and pseudo abort on subsequent stat.
+
+# Create two directories:
+#   srcdir  - simulates ${B}, outside PSEUDO_INCLUDE_PATHS
+#   destdir - simulates ${D}, inside PSEUDO_INCLUDE_PATHS
+# Use realpath to resolve symlinks, since pseudo canonicalizes paths
+# internally and the PSEUDO_INCLUDE_PATHS prefix must match.
+srcdir=$(mktemp -d "$(realpath "${PWD}")/mv_hl_src_XXXXXX")
+destdir=$(mktemp -d "$(realpath "${PWD}")/mv_hl_dest_XXXXXX")
+trap "rm -rf '$srcdir' '$destdir'" EXIT
+
+# Restrict pseudo tracking to only destdir
+export PSEUDO_INCLUDE_PATHS="$destdir"
+
+echo hello > ${srcdir}/hello.txt
+
+mv ${srcdir}/hello.txt ${destdir}/hello.txt
+ln ${destdir}/hello.txt ${destdir}/hello2.txt
+
+# Both files should report uid 0 under pseudo
+dest_uid=$(\ls -n1 ${destdir}/hello.txt | awk '{ print $3 }')
+link_uid=$(\ls -n1 ${destdir}/hello2.txt | awk '{ print $3 }')
+
+if [ "$dest_uid" != "0" ]; then
+    echo "FAIL: dest uid is $dest_uid, expected 0"
+    exit 1
+fi
+
+if [ "$link_uid" != "0" ]; then
+    echo "FAIL: link uid is $link_uid, expected 0"
+    exit 1
+fi
+
+if [ "$dest_uid" != "$link_uid" ]; then
+    echo "FAIL: UIDs don't match (dest=$dest_uid, link=$link_uid)"
+    exit 1
+fi
+
+exit 0
diff --git a/test/test-rename-hardlink.c b/test/test-rename-hardlink.c
new file mode 100644
index 0000000..d3f7384
--- /dev/null
+++ b/test/test-rename-hardlink.c
@@ -0,0 +1,87 @@
+/*
+ * Test that rename() from outside PSEUDO_INCLUDE_PATHS followed by
+ * hardlink properly tracks file ownership.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+static int failures = 0;
+
+static void check(const char *desc, int condition) {
+	if (!condition) {
+		fprintf(stderr, "FAIL: %s\n", desc);
+		failures++;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct stat st1, st2;
+	char src_path[PATH_MAX];
+	char dest_path[PATH_MAX];
+	char link_path[PATH_MAX];
+	int fd;
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s <src_dir> <dest_dir>\n", argv[0]);
+		return 1;
+	}
+
+	/* Create a file in src_dir (outside PSEUDO_INCLUDE_PATHS) */
+	snprintf(src_path, sizeof(src_path), "%s/testfile.txt", argv[1]);
+	fd = open(src_path, O_CREAT | O_WRONLY, 0644);
+	if (fd < 0) {
+		perror("create source file");
+		return 1;
+	}
+	if (write(fd, "hello\n", 6) != 6) {
+		perror("write");
+		close(fd);
+		return 1;
+	}
+	close(fd);
+
+	/* rename() from untracked src_dir to tracked dest_dir */
+	snprintf(dest_path, sizeof(dest_path), "%s/testfile.txt", argv[2]);
+	if (rename(src_path, dest_path) != 0) {
+		perror("rename");
+		return 1;
+	}
+
+	/* Create a hardlink in the tracked directory */
+	snprintf(link_path, sizeof(link_path), "%s/testfile2.txt", argv[2]);
+	if (link(dest_path, link_path) != 0) {
+		perror("link");
+		return 1;
+	}
+
+	/* Stat both files and verify consistent uid 0 */
+	if (stat(dest_path, &st1) != 0) {
+		perror("stat dest");
+		return 1;
+	}
+	if (stat(link_path, &st2) != 0) {
+		perror("stat link");
+		return 1;
+	}
+
+	check("same inode", st1.st_ino == st2.st_ino);
+	check("UIDs match", st1.st_uid == st2.st_uid);
+	check("dest uid is 0", st1.st_uid == 0);
+	check("link uid is 0", st2.st_uid == 0);
+
+	unlink(link_path);
+	unlink(dest_path);
+
+	return failures;
+}
diff --git a/test/test-rename-hardlink.sh b/test/test-rename-hardlink.sh
new file mode 100755
index 0000000..8f2be60
--- /dev/null
+++ b/test/test-rename-hardlink.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Test that rename() from outside PSEUDO_INCLUDE_PATHS followed by
+# hardlink properly tracks file ownership.
+
+srcdir=$(mktemp -d "$(realpath "${PWD}")/ren_hl_src_XXXXXX")
+destdir=$(mktemp -d "$(realpath "${PWD}")/ren_hl_dest_XXXXXX")
+trap "rm -rf '$srcdir' '$destdir'" EXIT
+
+export PSEUDO_INCLUDE_PATHS="$destdir"
+
+./test/test-rename-hardlink "$srcdir" "$destdir"
diff --git a/test/test-renameat-hardlink.c b/test/test-renameat-hardlink.c
new file mode 100644
index 0000000..9c4840c
--- /dev/null
+++ b/test/test-renameat-hardlink.c
@@ -0,0 +1,101 @@
+/*
+ * Test that renameat() from outside PSEUDO_INCLUDE_PATHS followed by
+ * hardlink properly tracks file ownership.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ */
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+static int failures = 0;
+
+static void check(const char *desc, int condition) {
+	if (!condition) {
+		fprintf(stderr, "FAIL: %s\n", desc);
+		failures++;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	struct stat st1, st2;
+	char dest_path[PATH_MAX];
+	char link_path[PATH_MAX];
+	int fd, olddirfd, newdirfd;
+
+	if (argc != 3) {
+		fprintf(stderr, "Usage: %s <src_dir> <dest_dir>\n", argv[0]);
+		return 1;
+	}
+
+	/* Open directory fds for renameat */
+	olddirfd = open(argv[1], O_RDONLY | O_DIRECTORY);
+	if (olddirfd < 0) {
+		perror("open src_dir");
+		return 1;
+	}
+	newdirfd = open(argv[2], O_RDONLY | O_DIRECTORY);
+	if (newdirfd < 0) {
+		perror("open dest_dir");
+		close(olddirfd);
+		return 1;
+	}
+
+	/* Create a file in src_dir (outside PSEUDO_INCLUDE_PATHS) */
+	fd = openat(olddirfd, "testfile.txt", O_CREAT | O_WRONLY, 0644);
+	if (fd < 0) {
+		perror("create source file");
+		return 1;
+	}
+	if (write(fd, "hello\n", 6) != 6) {
+		perror("write");
+		close(fd);
+		return 1;
+	}
+	close(fd);
+
+	/* renameat() from untracked src_dir to tracked dest_dir */
+	if (renameat(olddirfd, "testfile.txt", newdirfd, "testfile.txt") != 0) {
+		perror("renameat");
+		return 1;
+	}
+
+	/* Create a hardlink using linkat in the tracked directory */
+	if (linkat(newdirfd, "testfile.txt", newdirfd, "testfile2.txt", 0) != 0) {
+		perror("linkat");
+		return 1;
+	}
+
+	/* Stat both files and verify consistent uid 0 */
+	snprintf(dest_path, sizeof(dest_path), "%s/testfile.txt", argv[2]);
+	snprintf(link_path, sizeof(link_path), "%s/testfile2.txt", argv[2]);
+
+	if (stat(dest_path, &st1) != 0) {
+		perror("stat dest");
+		return 1;
+	}
+	if (stat(link_path, &st2) != 0) {
+		perror("stat link");
+		return 1;
+	}
+
+	check("same inode", st1.st_ino == st2.st_ino);
+	check("UIDs match", st1.st_uid == st2.st_uid);
+	check("dest uid is 0", st1.st_uid == 0);
+	check("link uid is 0", st2.st_uid == 0);
+
+	unlinkat(newdirfd, "testfile2.txt", 0);
+	unlinkat(newdirfd, "testfile.txt", 0);
+	close(olddirfd);
+	close(newdirfd);
+
+	return failures;
+}
diff --git a/test/test-renameat-hardlink.sh b/test/test-renameat-hardlink.sh
new file mode 100755
index 0000000..b7e3a9e
--- /dev/null
+++ b/test/test-renameat-hardlink.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Test that renameat() from outside PSEUDO_INCLUDE_PATHS followed by
+# hardlink properly tracks file ownership.
+
+srcdir=$(mktemp -d "$(realpath "${PWD}")/renat_hl_src_XXXXXX")
+destdir=$(mktemp -d "$(realpath "${PWD}")/renat_hl_dest_XXXXXX")
+trap "rm -rf '$srcdir' '$destdir'" EXIT
+
+export PSEUDO_INCLUDE_PATHS="$destdir"
+
+./test/test-renameat-hardlink "$srcdir" "$destdir"
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [pseudo][PATCH 3/5] renameat2/renameat: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS
  2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 1/5] run_tests.sh: Allow the user to specify specific tests to run Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 2/5] tests: Add mv then hardlink testing Mark Hatle
@ 2026-05-12 22:20 ` Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 4/5] rename: " Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 5/5] Makefile.in: Bump version to 1.9.7 Mark Hatle
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

From: Changqing Li <changqing.li@windriver.com>

The patch is for fixing failure in the following scenario:
[snip of recipe]
    do_install() {
        mv ${B}/hello.txt ${D}/hello.txt
        ln ${D}/hello.txt ${D}/hello2.txt
    }
    FILES:${PN} += "/hello2.txt /hello.txt"
[snip of recipe]

do_package will failed with pseudo abort error.

Root Cause:
For command mv, when oldpath is not in PSEUDO_INCLUDE_PATHS, the renameat2
will skip the wrapper and call real renameat2, and no entry is inserted
in files.db. Then command ln, insert an entry for hello2.txt in
files.db, which with the same inode with hello.txt. During do_package
stage, when stat for hello.txt, it will find a path mismatch failure
like:
path mismatch [2 links]: ino 190860603 db 'hello2.txt' req 'hello.txt'

Fixed by:
For renameat2/renameat, change to only ignore wraper call when both old
and new path are not in PSEUDO_INCLUDE_PATHS. In guts/renameat.c, when
oldpath is not in PSEUDO_INCLUDE_PATHS and has no existing db entry,
OP_LINK on oldpath is silently dropped by pseudo_client_op, making the
subsequent OP_RENAME a no-op in files.db, so change renameat to create
the entry directly at newpath via OP_LINK when oldpath is ignored,
skipping the pointless LINK+RENAME sequence for oldpath

Helped-by: Paul Barker <paul@pbarker.dev>
Signed-off-by: Changqing Li <changqing.li@windriver.com>
Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 makewrappers               |  4 +++-
 ports/unix/guts/renameat.c | 32 +++++++++++++++++++++++++-------
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/makewrappers b/makewrappers
index df405fc..83f5ca6 100755
--- a/makewrappers
+++ b/makewrappers
@@ -430,7 +430,9 @@ class Function:
             return "0"
 
         mainpath = None
-        if "oldpath" in self.paths_to_munge:
+        if "oldpath" in self.paths_to_munge and "newpath" in self.paths_to_munge:
+            return "(pseudo_client_ignore_path(oldpath) && pseudo_client_ignore_path(newpath))"
+        elif "oldpath" in self.paths_to_munge:
             mainpath = "oldpath"
         elif "newpath" in self.paths_to_munge:
             mainpath = "newpath"
diff --git a/ports/unix/guts/renameat.c b/ports/unix/guts/renameat.c
index 5ac63f9..69130c6 100644
--- a/ports/unix/guts/renameat.c
+++ b/ports/unix/guts/renameat.c
@@ -113,14 +113,32 @@
 				oldbuf.st_ino = newbuf.st_ino;
 			}
 		}
-		pseudo_debug(PDBGF_OP, "creating new '%s' [%llu] to rename\n",
-			oldpath, (unsigned long long) oldbuf.st_ino);
-		pseudo_client_op(OP_LINK, 0, -1, olddirfd, oldpath, &oldbuf);
+		if (pseudo_client_ignore_path(oldpath)) {
+			/* oldpath is ignored (not in INCLUDE_PATHS), so
+			 * OP_LINK on it would be silently dropped and the
+			 * subsequent OP_RENAME would be a no-op. Instead,
+			 * create the entry directly at newpath.
+			 * OP_LINK does not override uid/gid with pseudo_fuid/
+			 * pseudo_fgid (unlike OP_CREAT), so set them explicitly
+			 * to avoid recording the host user's real ids.
+			 */
+			oldbuf.st_uid = pseudo_fuid;
+			oldbuf.st_gid = pseudo_fgid;
+			pseudo_debug(PDBGF_OP, "creating new '%s' [%llu] directly at newpath (oldpath ignored)\n",
+				newpath, (unsigned long long) oldbuf.st_ino);
+			pseudo_client_op(OP_LINK, 0, -1, newdirfd, newpath, &oldbuf);
+		} else {
+			pseudo_debug(PDBGF_OP, "creating new '%s' [%llu] to rename\n",
+				oldpath, (unsigned long long) oldbuf.st_ino);
+			pseudo_client_op(OP_LINK, 0, -1, olddirfd, oldpath, &oldbuf);
+			pseudo_client_op(OP_RENAME, 0, olddirfd, newdirfd, newpath, &oldbuf, oldpath);
+		}
+	} else {
+		/* special case: use 'fd' for olddirfd, because
+		 * we know it has no other meaning for RENAME
+		 */
+		pseudo_client_op(OP_RENAME, 0, olddirfd, newdirfd, newpath, &oldbuf, oldpath);
 	}
-	/* special case: use 'fd' for olddirfd, because
-	 * we know it has no other meaning for RENAME
-	 */
-	pseudo_client_op(OP_RENAME, 0, olddirfd, newdirfd, newpath, &oldbuf, oldpath);
 
 	errno = save_errno;
 /*	return rc;
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [pseudo][PATCH 4/5] rename: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS
  2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
                   ` (2 preceding siblings ...)
  2026-05-12 22:20 ` [pseudo][PATCH 3/5] renameat2/renameat: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS Mark Hatle
@ 2026-05-12 22:20 ` Mark Hatle
  2026-05-12 22:20 ` [pseudo][PATCH 5/5] Makefile.in: Bump version to 1.9.7 Mark Hatle
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

From: Mark Hatle <mark.hatle@amd.com>

While testing the fix for renameat, it was noted that rename had a similar
logic pattern.  Fix rename as well, this is based on the fix:

Author: Changqing Li <changqing.li@windriver.com>
Date:   Tue May 12 16:33:57 2026 +0800

    renameat2/renameat: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS

    The patch is for fixing failure in the following scenario:
    [snip of recipe]
        do_install() {
            mv ${B}/hello.txt ${D}/hello.txt
            ln ${D}/hello.txt ${D}/hello2.txt
        }
        FILES:${PN} += "/hello2.txt /hello.txt"
    [snip of recipe]

    do_package will failed with pseudo abort error.

    Root Cause:
    For command mv, when oldpath is not in PSEUDO_INCLUDE_PATHS, the renameat2
    will skip the wrapper and call real renameat2, and no entry is inserted
    in files.db. Then command ln, insert an entry for hello2.txt in
    files.db, which with the same inode with hello.txt. During do_package
    stage, when stat for hello.txt, it will find a path mismatch failure
    like:
    path mismatch [2 links]: ino 190860603 db 'hello2.txt' req 'hello.txt'

    Fixed by:
    For renameat2/renameat, change to only ignore wraper call when both old
    and new path are not in PSEUDO_INCLUDE_PATHS. In guts/renameat.c, when
    oldpath is not in PSEUDO_INCLUDE_PATHS and has no existing db entry,
    OP_LINK on oldpath is silently dropped by pseudo_client_op, making the
    subsequent OP_RENAME a no-op in files.db, so change renameat to create
    the entry directly at newpath via OP_LINK when oldpath is ignored,
    skipping the pointless LINK+RENAME sequence for oldpath

    Helped-by: Paul Barker <paul@pbarker.dev>
    Signed-off-by: Changqing Li <changqing.li@windriver.com>

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 ports/unix/guts/rename.c | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/ports/unix/guts/rename.c b/ports/unix/guts/rename.c
index 80bbf41..f065c6e 100644
--- a/ports/unix/guts/rename.c
+++ b/ports/unix/guts/rename.c
@@ -101,11 +101,29 @@
 				oldbuf.st_ino = newbuf.st_ino;
 			}
 		}
-		pseudo_debug(PDBGF_FILE, "creating new '%s' [%llu] to rename\n",
-			oldpath, (unsigned long long) oldbuf.st_ino);
-		pseudo_client_op(OP_LINK, 0, -1, -1, oldpath, &oldbuf);
+		if (pseudo_client_ignore_path(oldpath)) {
+			/* oldpath is ignored (not in INCLUDE_PATHS), so
+			 * OP_LINK on it would be silently dropped and the
+			 * subsequent OP_RENAME would be a no-op. Instead,
+			 * create the entry directly at newpath.
+			 * OP_LINK does not override uid/gid with pseudo_fuid/
+			 * pseudo_fgid (unlike OP_CREAT), so set them explicitly
+			 * to avoid recording the host user's real ids.
+			 */
+			oldbuf.st_uid = pseudo_fuid;
+			oldbuf.st_gid = pseudo_fgid;
+			pseudo_debug(PDBGF_OP, "creating new '%s' [%llu] directly at newpath (oldpath ignored)\n",
+				newpath, (unsigned long long) oldbuf.st_ino);
+			pseudo_client_op(OP_LINK, 0, -1, -1, newpath, &oldbuf);
+		} else {
+			pseudo_debug(PDBGF_FILE, "creating new '%s' [%llu] to rename\n",
+				oldpath, (unsigned long long) oldbuf.st_ino);
+			pseudo_client_op(OP_LINK, 0, -1, -1, oldpath, &oldbuf);
+			pseudo_client_op(OP_RENAME, 0, -1, -1, newpath, &oldbuf, oldpath);
+		}
+	} else {
+		pseudo_client_op(OP_RENAME, 0, -1, -1, newpath, &oldbuf, oldpath);
 	}
-	pseudo_client_op(OP_RENAME, 0, -1, -1, newpath, &oldbuf, oldpath);
 
 	errno = save_errno;
 /*	return rc;
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [pseudo][PATCH 5/5] Makefile.in: Bump version to 1.9.7
  2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
                   ` (3 preceding siblings ...)
  2026-05-12 22:20 ` [pseudo][PATCH 4/5] rename: " Mark Hatle
@ 2026-05-12 22:20 ` Mark Hatle
  4 siblings, 0 replies; 6+ messages in thread
From: Mark Hatle @ 2026-05-12 22:20 UTC (permalink / raw)
  To: yocto-patches, paul, changqing.li; +Cc: richard.purdie

From: Mark Hatle <mark.hatle@amd.com>

Signed-off-by: Mark Hatle <mark.hatle@amd.com>
---
 Makefile.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile.in b/Makefile.in
index b4f5f03..8719ddd 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -34,7 +34,7 @@ BITS=@BITS@
 ARCH_FLAGS=@ARCH_FLAGS@
 MARK64=@MARK64@
 RPATH=@RPATH@
-VERSION=1.9.6
+VERSION=1.9.7
 
 LIB=@LIB@
 BIN=bin
-- 
1.8.3.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-05-12 22:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-12 22:20 [pseudo][PATCH 0/5] Fix rename/renameat w/ hardlinks Mark Hatle
2026-05-12 22:20 ` [pseudo][PATCH 1/5] run_tests.sh: Allow the user to specify specific tests to run Mark Hatle
2026-05-12 22:20 ` [pseudo][PATCH 2/5] tests: Add mv then hardlink testing Mark Hatle
2026-05-12 22:20 ` [pseudo][PATCH 3/5] renameat2/renameat: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS Mark Hatle
2026-05-12 22:20 ` [pseudo][PATCH 4/5] rename: " Mark Hatle
2026-05-12 22:20 ` [pseudo][PATCH 5/5] Makefile.in: Bump version to 1.9.7 Mark Hatle

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.