diff --git a/ports/linux/guts/fopen64.c b/ports/linux/guts/fopen64.c
index e76da69..a6efd18 100644
--- a/ports/linux/guts/fopen64.c
+++ b/ports/linux/guts/fopen64.c
@@ -22,8 +22,11 @@
 		pseudo_debug(PDBGF_FILE, "fopen64 '%s': fd %d <FILE %p>\n", path, fd, (void *) rc);
 		if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
-				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				if (pseudo_client_path_matches_fd(path, fd, 0))
+					pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 			pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf);
 		} else {
diff --git a/ports/linux/guts/freopen64.c b/ports/linux/guts/freopen64.c
index 5fc9073..6057eda 100644
--- a/ports/linux/guts/freopen64.c
+++ b/ports/linux/guts/freopen64.c
@@ -21,8 +21,11 @@
 		pseudo_debug(PDBGF_FILE, "freopen64 '%s': fd %d\n", path, fd);
 		if (real___fxstat64(_STAT_VER, fd, &buf) != -1) {
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
-				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				if (pseudo_client_path_matches_fd(path, fd, 0))
+					pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 			pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf);
 		} else {
diff --git a/ports/linux/guts/openat.c b/ports/linux/guts/openat.c
index 656ac2b..13bd395 100644
--- a/ports/linux/guts/openat.c
+++ b/ports/linux/guts/openat.c
@@ -148,9 +148,15 @@
 		if (stat_rc != -1) {
 			buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode);
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(rc, PSEUDO_FS_MODE(mode, 0));
 				// file has no path, but has been created
-				pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf);
+				if (pseudo_client_path_matches_fd(path, rc, flags & O_NOFOLLOW) &&
+				    real___fxstat64(_STAT_VER, rc, &buf) != -1) {
+					buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, mode);
+					pseudo_client_op(OP_CREAT, 0, -1, dirfd, path, &buf);
+				}
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 				pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(flags), rc, dirfd, path, &buf);
 		} else {
diff --git a/ports/linux/openat2/guts/openat2.c b/ports/linux/openat2/guts/openat2.c
index a0acbe7..687029a 100644
--- a/ports/linux/openat2/guts/openat2.c
+++ b/ports/linux/openat2/guts/openat2.c
@@ -183,9 +183,15 @@
 		if (stat_rc != -1) {
 			buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, my_how.mode);
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(rc, PSEUDO_FS_MODE(my_how.mode, 0));
 				// file has no path, but has been created
-				pseudo_client_op(OP_CREAT, 0, -1, dirfd, pseudo_path, &buf);
+				if (pseudo_client_path_matches_fd(pseudo_path, rc, my_how.flags & O_NOFOLLOW) &&
+				    real___fxstat64(_STAT_VER, rc, &buf) != -1) {
+					buf.st_mode = PSEUDO_DB_MODE(buf.st_mode, my_how.mode);
+					pseudo_client_op(OP_CREAT, 0, -1, dirfd, pseudo_path, &buf);
+				}
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 				pseudo_client_op(OP_OPEN, PSEUDO_ACCESS(my_how.flags), rc, dirfd, pseudo_path, &buf);
 		} else {
diff --git a/ports/unix/guts/fopen.c b/ports/unix/guts/fopen.c
index 26a6abc..78388f7 100644
--- a/ports/unix/guts/fopen.c
+++ b/ports/unix/guts/fopen.c
@@ -21,8 +21,11 @@
 		pseudo_debug(PDBGF_OP, "fopen '%s': fd %d <FILE %p>\n", path, fd, (void *) rc);
 		if (base_fstat(fd, &buf) != -1) {
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
-				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				if (pseudo_client_path_matches_fd(path, fd, 0))
+					pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 			pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf);
 		} else {
diff --git a/ports/unix/guts/freopen.c b/ports/unix/guts/freopen.c
index 703b6aa..5d63c9f 100644
--- a/ports/unix/guts/freopen.c
+++ b/ports/unix/guts/freopen.c
@@ -21,8 +21,11 @@
 		pseudo_debug(PDBGF_OP, "freopen '%s': fd %d\n", path, fd);
 		if (base_fstat(fd, &buf) != -1) {
 			if (!existed) {
+				int path_lock_fd = pseudo_client_path_lock(0);
 				real_fchmod(fd, PSEUDO_FS_MODE(0666 & ~pseudo_umask, 0));
-				pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				if (pseudo_client_path_matches_fd(path, fd, 0))
+					pseudo_client_op(OP_CREAT, 0, -1, -1, path, &buf);
+				pseudo_client_path_unlock(path_lock_fd);
 			}
 			pseudo_client_op(OP_OPEN, pseudo_access_fopen(mode), fd, -1, path, &buf);
 		} else {
diff --git a/pseudo_client.c b/pseudo_client.c
index 759afeb..fe99aa6 100644
--- a/pseudo_client.c
+++ b/pseudo_client.c
@@ -1249,6 +1249,31 @@ pseudo_client_path_unlock(int fd) {
 	errno = save_errno;
 }
 
+/* Operations that can block, such as open() on a FIFO, can't hold the path
+ * lock across the real call.  Instead they take the lock afterwards and
+ * check that the path still names the file they opened before recording
+ * it.  With the lock held, no other client is part way through changing the
+ * path, so if it now names a different file, that client has already
+ * recorded the change, and recording ours would be wrong.
+ */
+int
+pseudo_client_path_matches_fd(const char *path, int fd, int nofollow) {
+	PSEUDO_STATBUF pbuf, fbuf;
+	int save_errno = errno;
+	int rc;
+
+	if (!path || fd < 0 || !pseudo_real_fstat || !pseudo_real_lstat || !pseudo_real_stat)
+		return 1;
+	rc = pseudo_real_fstat(fd, &fbuf) == 0 &&
+	     (nofollow ? pseudo_real_lstat(path, &pbuf) : pseudo_real_stat(path, &pbuf)) == 0 &&
+	     pbuf.st_dev == fbuf.st_dev && pbuf.st_ino == fbuf.st_ino;
+	if (!rc)
+		pseudo_debug(PDBGF_FILE, "'%s' no longer names fd %d, not recording it.\n",
+			path, fd);
+	errno = save_errno;
+	return rc;
+}
+
 static int
 client_connect(void) {
 	/* we have a server pid, is it responsive? */
diff --git a/pseudo_client.h b/pseudo_client.h
index 217981d..77fe2ff 100644
--- a/pseudo_client.h
+++ b/pseudo_client.h
@@ -30,6 +30,7 @@ extern int pseudo_client_shutdown(int);
 extern int pseudo_fd(int fd, int how);
 extern int pseudo_client_path_lock(int shared);
 extern void pseudo_client_path_unlock(int fd);
+extern int pseudo_client_path_matches_fd(const char *path, int fd, int nofollow);
 #define MOVE_FD	0
 #define COPY_FD	1
 #define PSEUDO_MIN_FD	20
@@ -53,6 +54,8 @@ extern FILE *pseudo_grp;
 
 /* pseudo_wrappers will try to initialize these */
 extern int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf);
+extern int (*pseudo_real_fstat)(int fd, PSEUDO_STATBUF *buf);
+extern int (*pseudo_real_stat)(const char *path, PSEUDO_STATBUF *buf);
 extern int (*pseudo_real_fork)(void);
 extern int (*pseudo_real_execv)(const char *, char * const *);
 
diff --git a/pseudo_util.c b/pseudo_util.c
index b8afe34..0267585 100644
--- a/pseudo_util.c
+++ b/pseudo_util.c
@@ -97,6 +97,8 @@ static int pseudo_util_initted = -1;  /* Not yet run */
 
 /* bypass wrapper logic on path computations */
 int (*pseudo_real_lstat)(const char *path, PSEUDO_STATBUF *buf) = NULL;
+int (*pseudo_real_fstat)(int fd, PSEUDO_STATBUF *buf) = NULL;
+int (*pseudo_real_stat)(const char *path, PSEUDO_STATBUF *buf) = NULL;
 /* bash workaround */
 int (*pseudo_real_unsetenv)(const char *) = unsetenv;
 char * (*pseudo_real_getenv)(const char *) = getenv;
diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c
index 78cdecf..102a838 100644
--- a/pseudo_wrappers.c
+++ b/pseudo_wrappers.c
@@ -174,6 +174,8 @@ pseudo_init_wrappers(void) {
 	pseudo_real_fsetxattr = real_fsetxattr;
 #endif
 	pseudo_real_lstat = base_lstat;
+	pseudo_real_fstat = base_fstat;
+	pseudo_real_stat = base_stat;
 	/* and these are used so the client's server spawn can bypass
 	 * wrappers.
 	 */
