LibC: Move a handful of functions into <sys/stat.h>

I'm not sure why they were defined elsewhere, POSIX tells us where they
belong.

This fixes the coreutils port, which currently fails with an 'undeclared
function' error.
This commit is contained in:
Linus Groh authored and Nico Weber committed 2025-12-06 14:15:52 -05:00
1 parent 65609194cf
commit ffa3524e33
6 files changed
+82 -84

No files matched your search

-62
View File
@@ -6,7 +6,6 @@
*/
#include <bits/pthread_cancel.h>
#include <bits/utimens.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
@@ -120,65 +119,4 @@ int posix_fallocate(int fd, off_t offset, off_t len)
// posix_fallocate does not set errno.
return -static_cast<int>(syscall(SC_posix_fallocate, fd, offset, len));
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html
int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag)
{
if (!path) {
errno = EFAULT;
return -1;
}
return __utimens(dirfd, path, times, flag);
}
int __utimens(int fd, char const* path, struct timespec const times[2], int flag)
{
size_t path_length = 0;
if (path) {
path_length = strlen(path);
if (path_length > INT32_MAX) {
errno = EINVAL;
return -1;
}
}
// POSIX allows AT_SYMLINK_NOFOLLOW flag or no flags.
if (flag & ~AT_SYMLINK_NOFOLLOW) {
errno = EINVAL;
return -1;
}
// Return early without error since both changes are to be omitted.
if (times && times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
return 0;
// According to POSIX, when times is a nullptr, it's equivalent to setting
// both last access time and last modification time to the current time.
// Setting the times argument to nullptr if it matches this case prevents
// the need to copy it in the kernel.
if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW)
times = nullptr;
if (times) {
for (int i = 0; i < 2; ++i) {
if ((times[i].tv_nsec != UTIME_NOW && times[i].tv_nsec != UTIME_OMIT)
&& (times[i].tv_nsec < 0 || times[i].tv_nsec >= 1'000'000'000L)) {
errno = EINVAL;
return -1;
}
}
}
int rc = 0;
if (path) {
// NOTE: fd is treated as dirfd for this syscall.
Syscall::SC_utimensat_params params { fd, { path, path_length }, times, flag };
rc = syscall(SC_utimensat, &params);
} else {
Syscall::SC_futimens_params params { fd, times };
rc = syscall(SC_futimens, &params);
}
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}
-2
View File
@@ -37,6 +37,4 @@ int inode_watcher_remove_watch(int fd, int wd);
int posix_fadvise(int fd, off_t offset, off_t len, int advice);
int posix_fallocate(int fd, off_t offset, off_t len);
int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag);
__END_DECLS
+79
View File
@@ -87,6 +87,24 @@ int mkfifoat(int dirfd, char const* pathname, mode_t mode)
return mknodat(dirfd, pathname, mode | S_IFIFO, 0);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknod.html
int mknod(char const* pathname, mode_t mode, dev_t dev)
{
return mknodat(AT_FDCWD, pathname, mode, dev);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html
int mknodat(int dirfd, char const* pathname, mode_t mode, dev_t dev)
{
if (!pathname) {
errno = EFAULT;
return -1;
}
Syscall::SC_mknod_params params { { pathname, strlen(pathname) }, mode, dev, dirfd };
int rc = syscall(SC_mknod, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
static int do_stat(int dirfd, char const* path, struct stat* statbuf, bool follow_symlinks)
{
if (!path) {
@@ -128,4 +146,65 @@ int futimens(int fd, struct timespec const times[2])
{
return __utimens(fd, nullptr, times, 0);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/utimensat.html
int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag)
{
if (!path) {
errno = EFAULT;
return -1;
}
return __utimens(dirfd, path, times, flag);
}
int __utimens(int fd, char const* path, struct timespec const times[2], int flag)
{
size_t path_length = 0;
if (path) {
path_length = strlen(path);
if (path_length > INT32_MAX) {
errno = EINVAL;
return -1;
}
}
// POSIX allows AT_SYMLINK_NOFOLLOW flag or no flags.
if (flag & ~AT_SYMLINK_NOFOLLOW) {
errno = EINVAL;
return -1;
}
// Return early without error since both changes are to be omitted.
if (times && times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
return 0;
// According to POSIX, when times is a nullptr, it's equivalent to setting
// both last access time and last modification time to the current time.
// Setting the times argument to nullptr if it matches this case prevents
// the need to copy it in the kernel.
if (times && times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW)
times = nullptr;
if (times) {
for (int i = 0; i < 2; ++i) {
if ((times[i].tv_nsec != UTIME_NOW && times[i].tv_nsec != UTIME_OMIT)
&& (times[i].tv_nsec < 0 || times[i].tv_nsec >= 1'000'000'000L)) {
errno = EINVAL;
return -1;
}
}
}
int rc = 0;
if (path) {
// NOTE: fd is treated as dirfd for this syscall.
Syscall::SC_utimensat_params params { fd, { path, path_length }, times, flag };
rc = syscall(SC_utimensat, &params);
} else {
Syscall::SC_futimens_params params { fd, times };
rc = syscall(SC_futimens, &params);
}
__RETURN_WITH_ERRNO(rc, rc, -1);
}
}
+3
View File
@@ -21,10 +21,13 @@ int mkdir(char const* pathname, mode_t);
int mkdirat(int dirfd, char const* pathname, mode_t);
int mkfifo(char const* pathname, mode_t);
int mkfifoat(int dirfd, char const* pathname, mode_t);
int mknod(char const* pathname, mode_t, dev_t);
int mknodat(int dirfd, char const* pathname, mode_t, dev_t);
int fstat(int fd, struct stat* statbuf);
int lstat(char const* path, struct stat* statbuf);
int stat(char const* path, struct stat* statbuf);
int fstatat(int fd, char const* path, struct stat* statbuf, int flags);
int futimens(int fd, struct timespec const times[2]);
int utimensat(int dirfd, char const* path, struct timespec const times[2], int flag);
__END_DECLS
-18
View File
@@ -826,24 +826,6 @@ int faccessat(int dirfd, char const* pathname, int mode, int flags)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknod.html
int mknod(char const* pathname, mode_t mode, dev_t dev)
{
return mknodat(AT_FDCWD, pathname, mode, dev);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknodat.html
int mknodat(int dirfd, char const* pathname, mode_t mode, dev_t dev)
{
if (!pathname) {
errno = EFAULT;
return -1;
}
Syscall::SC_mknod_params params { { pathname, strlen(pathname) }, mode, dev, dirfd };
int rc = syscall(SC_mknod, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fpathconf.html
long fpathconf([[maybe_unused]] int fd, int name)
{
-2
View File
@@ -107,8 +107,6 @@ unsigned int alarm(unsigned int seconds);
int access(char const* pathname, int mode);
int faccessat(int dirfd, char const* pathname, int mode, int flags);
int isatty(int fd);
int mknod(char const* pathname, mode_t, dev_t);
int mknodat(int dirfd, char const* pathname, mode_t, dev_t);
long fpathconf(int fd, int name);
long pathconf(char const* path, int name);
char* getlogin(void);