@@ -673,7 +673,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
if (fs_ctx->export_flags & V9FS_SM_MAPPED ||
fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
- err = mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0);
+ err = qemu_mknodat(dirfd, name, fs_ctx->fmode | S_IFREG, 0);
if (err == -1) {
goto out;
}
@@ -688,7 +688,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
}
} else if (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH ||
fs_ctx->export_flags & V9FS_SM_NONE) {
- err = mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
+ err = qemu_mknodat(dirfd, name, credp->fc_mode, credp->fc_rdev);
if (err == -1) {
goto out;
}
@@ -701,6 +701,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
err_end:
unlinkat_preserve_errno(dirfd, name, 0);
+
out:
close_preserve_errno(dirfd);
return err;
@@ -158,3 +158,36 @@ done:
close_preserve_errno(fd);
return ret;
}
+
+#ifndef SYS___pthread_fchdir
+# define SYS___pthread_fchdir 349
+#endif
+
+/*
+ * This is an undocumented OS X syscall. It would be best to avoid it,
+ * but there doesn't seem to be another safe way to implement mknodat.
+ * Dear Apple, please implement mknodat before you remove this syscall.
+ */
+static int fchdir_thread_local(int fd)
+{
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ return syscall(SYS___pthread_fchdir, fd);
+#pragma clang diagnostic pop
+}
+
+int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
+{
+ int preserved_errno, err;
+ if (fchdir_thread_local(dirfd) < 0) {
+ return -1;
+ }
+ err = mknod(filename, mode, dev);
+ preserved_errno = errno;
+ /* Stop using the thread-local cwd */
+ fchdir_thread_local(-1);
+ if (err < 0) {
+ errno = preserved_errno;
+ }
+ return err;
+}
@@ -68,3 +68,8 @@ int utimensat_nofollow(int dirfd, const char *filename,
{
return utimensat(dirfd, filename, times, AT_SYMLINK_NOFOLLOW);
}
+
+int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev)
+{
+ return mknodat(dirfd, filename, mode, dev);
+}
@@ -105,4 +105,6 @@ ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
int utimensat_nofollow(int dirfd, const char *filename,
const struct timespec times[2]);
+int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
+
#endif