diff --git a/src/kernel/emulation/linux/CMakeLists.txt b/src/kernel/emulation/linux/CMakeLists.txt index 8de3d8a09..4a738d697 100644 --- a/src/kernel/emulation/linux/CMakeLists.txt +++ b/src/kernel/emulation/linux/CMakeLists.txt @@ -24,6 +24,7 @@ set(emulation_sources simple.c errno.c readline.c + common_at.c machdep/machdeps.c machdep/machdep-table.S machdep/tls.c @@ -131,6 +132,7 @@ set(emulation_sources network/bind.c network/listen.c stat/fstat.c + stat/fstatat.c stat/lstat.c stat/stat.c stat/stat64_extended.c diff --git a/src/kernel/emulation/linux/common_at.c b/src/kernel/emulation/linux/common_at.c new file mode 100644 index 000000000..698f0bdf5 --- /dev/null +++ b/src/kernel/emulation/linux/common_at.c @@ -0,0 +1,16 @@ +#include "common_at.h" + +int atflags_bsd_to_linux(int flags) +{ + int linux_flags = 0; + + if (flags & BSD_AT_SYMLINK_NOFOLLOW) + linux_flags |= LINUX_AT_SYMLINK_NOFOLLOW; + if (flags & BSD_AT_REMOVEDIR) + linux_flags |= LINUX_AT_REMOVEDIR; + if (flags & BSD_AT_SYMLINK_FOLLOW) + linux_flags |= LINUX_AT_SYMLINK_FOLLOW; + + return linux_flags; +} + diff --git a/src/kernel/emulation/linux/common_at.h b/src/kernel/emulation/linux/common_at.h new file mode 100644 index 000000000..f49af03a9 --- /dev/null +++ b/src/kernel/emulation/linux/common_at.h @@ -0,0 +1,25 @@ +#ifndef _COMMON_AT_H +#define _COMMON_AT_H +// Common declarations for the *at family of system calls + +#define LINUX_AT_FDCWD -100 +#define LINUX_AT_SYMLINK_NOFOLLOW 0x100 +#define LINUX_AT_REMOVEDIR 0x200 +#define LINUX_AT_SYMLINK_FOLLOW 0x400 + +#define BSD_AT_FDCWD -2 +#define BSD_AT_SYMLINK_NOFOLLOW 0x20 +#define BSD_AT_REMOVEDIR 0x80 +#define BSD_AT_SYMLINK_FOLLOW 0x40 + +int atflags_bsd_to_linux(int flags); + +static inline int atfd(int fd) +{ + if (fd == BSD_AT_FDCWD) + return LINUX_AT_FDCWD; + return fd; +} + +#endif + diff --git a/src/kernel/emulation/linux/stat/fstatat.c b/src/kernel/emulation/linux/stat/fstatat.c new file mode 100644 index 000000000..a170b09dc --- /dev/null +++ b/src/kernel/emulation/linux/stat/fstatat.c @@ -0,0 +1,51 @@ +#include "fstatat.h" +#include "common.h" +#include "../base.h" +#include "../errno.h" +#include "../common_at.h" +#include + +long sys_fstatat(int fd, const char* path, struct stat* stat, int flag) +{ + int ret; + struct linux_stat lstat; + int linux_flags; + + linux_flags = atflags_bsd_to_linux(flag); + +#ifdef __NR_newfstatat + ret = LINUX_SYSCALL(__NR_newfstatat, atfd(fd), path, &lstat, linux_flags); +#else + ret = LINUX_SYSCALL(__NR_fstatat64, atfd(fd), path, &lstat, linux_flags); +#endif + + if (ret < 0) + return errno_linux_to_bsd(ret); + + stat_linux_to_bsd(&lstat, stat); + + return 0; +} + +long sys_fstatat64(int fd, const char* path, struct stat64* stat, int flag) +{ + int ret; + struct linux_stat lstat; + int linux_flags; + + linux_flags = atflags_bsd_to_linux(flag); + +#ifdef __NR_newfstatat + ret = LINUX_SYSCALL(__NR_newfstatat, atfd(fd), path, &lstat, linux_flags); +#else + ret = LINUX_SYSCALL(__NR_fstatat64, atfd(fd), path, &lstat, linux_flags); +#endif + + if (ret < 0) + return errno_linux_to_bsd(ret); + + stat_linux_to_bsd64(&lstat, stat); + + return 0; +} + diff --git a/src/kernel/emulation/linux/stat/fstatat.h b/src/kernel/emulation/linux/stat/fstatat.h new file mode 100644 index 000000000..74f2c1b94 --- /dev/null +++ b/src/kernel/emulation/linux/stat/fstatat.h @@ -0,0 +1,11 @@ +#ifndef LINUX_FSTATAT_H +#define LINUX_FSTATAT_H + +struct stat; +struct stat64; + +long sys_fstatat(int fd, const char* path, struct stat* stat, int flag); +long sys_fstatat64(int fd, const char* path, struct stat64* stat, int flag); + +#endif + diff --git a/src/kernel/emulation/linux/syscalls.c b/src/kernel/emulation/linux/syscalls.c index 887b10f0a..4ee422e06 100644 --- a/src/kernel/emulation/linux/syscalls.c +++ b/src/kernel/emulation/linux/syscalls.c @@ -100,6 +100,7 @@ #include "network/socketpair.h" #include "dirent/getdirentries.h" #include "stat/fstat.h" +#include "stat/fstatat.h" #include "stat/stat.h" #include "stat/lstat.h" #include "stat/statfs.h" @@ -332,6 +333,8 @@ void* __bsd_syscall_table[600] = { [415] = sys_pwrite_nocancel, [417] = sys_poll_nocancel, [423] = sys_semwait_signal_nocancel, + [469] = sys_fstatat, + [470] = sys_fstatat64, [500] = sys_getentropy, };