diff mbox series

[pseudo,4/5] rename: only ignore when both old and new path are not in PSEUDO_INCLUDE_PATHS

Message ID 1778624443-20857-5-git-send-email-mark.hatle@kernel.crashing.org
State New
Headers show
Series Fix rename/renameat w/ hardlinks | expand

Commit Message

Mark Hatle May 12, 2026, 10:20 p.m. UTC
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 mbox series

Patch

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;