git: f9458655e78f - main - Add O_SYMLINK emulation
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 03 May 2026 19:59:06 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=f9458655e78f6532e962a13d28d6a6086b4156de
commit f9458655e78f6532e962a13d28d6a6086b4156de
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-04-12 08:48:32 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-05-03 19:58:36 +0000
Add O_SYMLINK emulation
for MacOSX partial compatibility, defined as O_PATH | O_SYNC | O_DIRECT.
libc openat() wrapper is modified to fstat() the descriptor and re-open
in the normal mode if the type is not symlink.
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D56365
---
lib/libc/include/libc_private.h | 3 +++
lib/libc/sys/Symbol.map | 4 ++++
lib/libc/sys/open.c | 4 +++-
lib/libc/sys/openat.c | 44 +++++++++++++++++++++++++++++++++++++++-
lib/libthr/thread/thr_syscalls.c | 5 ++++-
sys/sys/fcntl.h | 6 +++---
6 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 299629fce2ad..ef490e1a66ef 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -384,4 +384,7 @@ struct uexterror;
int __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz);
int __libc_uexterr_gettext(char *buf, size_t bufsz);
+int __impl_openat(int fd, const char *path, int flags, ...);
+int __openat_symlink(int fd, const char *path, int flags, int interposed);
+
#endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 8acffcfd714e..1bae1fb78538 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -75,3 +75,7 @@ FBSD_1.7 {
FBSD_1.9 {
pdwait;
};
+
+FBSDprivate_1.0 {
+ __openat_symlink;
+};
diff --git a/lib/libc/sys/open.c b/lib/libc/sys/open.c
index dd7bedebf141..d58a81f60b18 100644
--- a/lib/libc/sys/open.c
+++ b/lib/libc/sys/open.c
@@ -29,9 +29,11 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "namespace.h"
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdarg.h>
+#include "un-namespace.h"
#include "libc_private.h"
#pragma weak open
@@ -48,5 +50,5 @@ open(const char *path, int flags, ...)
} else {
mode = 0;
}
- return (INTERPOS_SYS(openat, AT_FDCWD, path, flags, mode));
+ return (__impl_openat(AT_FDCWD, path, flags, mode));
}
diff --git a/lib/libc/sys/openat.c b/lib/libc/sys/openat.c
index ba937cae3a3e..f4223be8aad7 100644
--- a/lib/libc/sys/openat.c
+++ b/lib/libc/sys/openat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 The FreeBSD Foundation.
+ * Copyright 2014, 2026 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
@@ -29,11 +29,46 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include "namespace.h"
#include <sys/types.h>
#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
#include <stdarg.h>
+#include <unistd.h>
+#include "un-namespace.h"
#include "libc_private.h"
+static int
+do_openat(int fd, const char *path, int flags, int interposed)
+{
+ if (interposed)
+ return (__sys_openat(fd, path, flags | O_PATH, 0));
+ return (INTERPOS_SYS(openat, fd, path, flags | O_PATH, 0));
+}
+
+int
+__openat_symlink(int fd, const char *path, int flags, int interposed)
+{
+ struct stat st;
+ int rfd, xfd, saved_errno;
+
+ flags &= ~O_SYMLINK;
+ rfd = do_openat(fd, path, flags | O_PATH | O_NOFOLLOW, interposed);
+ if (rfd != -1 && _fstat(rfd, &st) != -1 && !S_ISLNK(st.st_mode)) {
+ xfd = do_openat(rfd, "", flags | O_EMPTY_PATH, interposed);
+ saved_errno = errno;
+ /* dup to rfd to guarantee lowest fd number value */
+ if (_dup2(xfd, rfd) == -1) {
+ _close(rfd);
+ rfd = -1;
+ }
+ _close(xfd);
+ errno = saved_errno;
+ }
+ return (rfd);
+}
+
__sym_compat(openat, __impl_openat, FBSD_1.1);
__weak_reference(openat, __impl_openat);
__sym_default(openat, openat, FBSD_1.2);
@@ -45,12 +80,19 @@ openat(int fd, const char *path, int flags, ...)
va_list ap;
int mode;
+ if (__predict_false((flags & (O_SYMLINK | O_CREAT)) ==
+ (O_SYMLINK | O_CREAT))) {
+ errno = EINVAL;
+ return (-1);
+ }
if ((flags & O_CREAT) != 0) {
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
} else {
mode = 0;
+ if (__predict_false((flags & O_SYMLINK) == O_SYMLINK))
+ return (__openat_symlink(fd, path, flags, 0));
}
return (INTERPOS_SYS(openat, fd, path, flags, mode));
}
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
index bff2d0624aee..8168185188ea 100644
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -298,7 +298,10 @@ __thr_openat(int fd, const char *path, int flags, int mode)
curthread = _get_curthread();
_thr_cancel_enter(curthread);
- ret = __sys_openat(fd, path, flags, mode);
+ if (__predict_false((flags & O_SYMLINK) == O_SYMLINK))
+ ret = __openat_symlink(fd, path, flags, 1);
+ else
+ ret = __sys_openat(fd, path, flags, mode);
_thr_cancel_leave(curthread, ret == -1);
return (ret);
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
index 80cbca4ea753..bf64d06f2a4d 100644
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -145,10 +145,10 @@ typedef __pid_t pid_t;
/*
* Emulate MacOSX compatibility flag without consuming a flags bit.
- * It is not fully correct since reads over regular files opened with
- * this definition fail.
+ * Selected bits set does not define a useful open request and is
+ * unlikely to be specified by reasonable code.
*/
-#define O_SYMLINK (O_PATH | O_NOFOLLOW)
+#define O_SYMLINK (O_PATH | O_DSYNC | O_DIRECT)
#endif
#if __POSIX_VISIBLE >= 202405