Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 03 May 2026 19:59:06 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: f9458655e78f - main - Add O_SYMLINK emulation
Message-ID:  <69f7a90a.40cde.3f32aeed@gitrepo.freebsd.org>

index | next in thread | raw e-mail

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


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f7a90a.40cde.3f32aeed>