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 >= 202405home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69f7a90a.40cde.3f32aeed>
