diff --git a/repos/libports/src/lib/compat-libc/compat.cc b/repos/libports/src/lib/compat-libc/compat.cc index ba9779513a..97ac29ec5d 100644 --- a/repos/libports/src/lib/compat-libc/compat.cc +++ b/repos/libports/src/lib/compat-libc/compat.cc @@ -1,6 +1,7 @@ /* * \brief FreeBSD-11 function versions * \author Sebastian Sumpf + * \author Benjamin Lamowski * \date 2023-06-12 */ @@ -12,15 +13,22 @@ */ #include -#define _WANT_FREEBSD11_STAT /* enable freebsd11_stat */ +#define _WANT_FREEBSD11_STAT /* enable freebsd11_stat and freebsd11_dirent */ #define _KERNEL /* disable 'stat' */ #include + +#include /* needed for memset() in dirent.h */ +#include #include +#include extern "C" int libc_stat(const char *, struct stat*); extern "C" int libc_fstat(int, struct stat *); +extern "C" int libc_lstat(const char *, struct stat*); -static void _to_freebsd11(struct stat *libc_buf, struct freebsd11_stat *buf) +extern "C" int libc_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); + +static void _to_freebsd11_stat(struct stat *libc_buf, struct freebsd11_stat *buf) { buf->st_dev = libc_buf->st_dev; buf->st_ino = libc_buf->st_ino; @@ -38,6 +46,25 @@ static void _to_freebsd11(struct stat *libc_buf, struct freebsd11_stat *buf) buf->st_birthtim = libc_buf->st_birthtim; } + +static bool _to_freebsd11_dirent(struct dirent *libc_buf, struct freebsd11_dirent *buf) +{ + buf->d_fileno = libc_buf->d_fileno; + buf->d_type = libc_buf->d_type; + buf->d_namlen = libc_buf->d_namlen; + /* Calculation taken from FreeBSD's FREEBSD11_DIRSIZ macro */ + buf->d_reclen = sizeof(struct freebsd11_dirent) + - sizeof(buf->d_name) + + ((buf->d_namlen + 1 + 3) &~ 3); + if (libc_buf->d_namlen >= sizeof(buf->d_name)) + return false; + + strncpy(buf->d_name, libc_buf->d_name, sizeof(buf->d_name)); + + return true; +} + + static void* libc_handle(void) { static void *handle = NULL; @@ -48,6 +75,9 @@ static void* libc_handle(void) int (*_stat)(char const*, struct stat*); int (*_fstat)(int, struct stat *); +int (*_lstat)(char const*, struct stat*); +int (*_readdir_r)(DIR *dirp, struct dirent *entry, struct dirent **result); + int libc_stat(const char *path, struct stat *buf) { @@ -66,6 +96,24 @@ int libc_fstat(int fd, struct stat *buf) return _fstat(fd, buf); } + +int libc_lstat(const char *path, struct stat *buf) +{ + if (!_lstat) + _lstat = (int (*)(const char*, struct stat*)) dlsym(libc_handle(), "lstat"); + + return _lstat(path, buf); +} + +int libc_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) +{ + if (!_readdir_r) + _readdir_r = (int (*)(DIR *dirp, struct dirent *entry, struct dirent **result)) dlsym(libc_handle(), "readdir_r"); + + return _readdir_r(dirp, entry, result); +} + + extern "C" int freebsd11_stat(const char *path, struct freebsd11_stat *buf) { struct stat libc_buf { }; @@ -73,7 +121,7 @@ extern "C" int freebsd11_stat(const char *path, struct freebsd11_stat *buf) int err = libc_stat(path, &libc_buf); if (err) return err; - _to_freebsd11(&libc_buf, buf); + _to_freebsd11_stat(&libc_buf, buf); return 0; } @@ -86,10 +134,48 @@ extern "C" int freebsd11_fstat(int fd, struct freebsd11_stat *buf) int err = libc_fstat(fd, &libc_buf); if (err) return err; - _to_freebsd11(&libc_buf, buf); + _to_freebsd11_stat(&libc_buf, buf); return 0; } +extern "C" int freebsd11_lstat(const char *path, struct freebsd11_stat *buf) +{ + struct stat libc_buf { }; + + int err = libc_lstat(path, &libc_buf); + if (err) return err; + + _to_freebsd11_stat(&libc_buf, buf); + + return 0; +} + + +extern "C" int freebsd11_readdir_r(DIR *dirp, + struct freebsd11_dirent *entry, + struct freebsd11_dirent**result) +{ + struct dirent libc_entry { }; + struct dirent * libc_result; + + int err = libc_readdir_r(dirp, &libc_entry, &libc_result); + if (err) return err; + + if (libc_result != NULL) { + if (!_to_freebsd11_dirent(&libc_entry, entry)) { + *result = NULL; + return ENAMETOOLONG; + } else { + *result = entry; + } + } + + return 0; +} + + __sym_compat(fstat, freebsd11_fstat, FBSD_1.0); __sym_compat(stat, freebsd11_stat, FBSD_1.0); +__sym_compat(lstat, freebsd11_lstat, FBSD_1.0); +__sym_compat(readdir_r, freebsd11_readdir_r, FBSD_1.0);