darling-xnu/tests/utimensat.c
2023-05-16 21:41:14 -07:00

86 lines
2.8 KiB
C

#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <darwintest.h>
#include <darwintest_utils.h>
T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
#define FILENAME "utimensat"
static const struct timespec tptr[][2] = {
{ { 0x12345678, 987654321 }, { 0x15263748, 123456789 }, },
{ { 0, UTIME_NOW }, { 0x15263748, 123456789 }, },
{ { 0x12345678, 987654321 }, { 0, UTIME_NOW }, },
{ { 0, UTIME_NOW }, { 0, UTIME_NOW }, },
{ { 0, UTIME_OMIT }, { 0x15263748, 123456789 }, },
{ { 0x12345678, 987654321 }, { 0, UTIME_OMIT }, },
{ { 0, UTIME_OMIT }, { 0, UTIME_OMIT }, },
{ { 0, UTIME_NOW }, { 0, UTIME_OMIT }, },
{ { 0, UTIME_OMIT }, { 0, UTIME_NOW }, },
};
T_DECL(utimensat, "Try various versions of utimensat")
{
T_SETUPBEGIN;
T_ASSERT_POSIX_ZERO(chdir(dt_tmpdir()), NULL);
// Skip the test if the current working directory is not on APFS.
struct statfs sfs = { 0 };
T_QUIET; T_ASSERT_POSIX_SUCCESS(statfs(".", &sfs), NULL);
if (memcmp(&sfs.f_fstypename[0], "apfs", strlen("apfs")) != 0) {
T_SKIP("utimensat is APFS-only, but working directory is non-APFS");
}
T_SETUPEND;
struct stat pre_st, post_st;
int fd;
T_ASSERT_POSIX_SUCCESS((fd = open(FILENAME, O_CREAT | O_RDWR, 0644)), NULL);
T_ASSERT_POSIX_ZERO(close(fd), NULL);
for (size_t i = 0; i < sizeof(tptr) / sizeof(tptr[0]); i++) {
T_LOG("=== {%ld, %ld} {%ld, %ld} ===",
tptr[i][0].tv_sec, tptr[i][0].tv_nsec,
tptr[i][1].tv_sec, tptr[i][1].tv_nsec);
struct timespec now;
clock_gettime(CLOCK_REALTIME, &now);
T_ASSERT_POSIX_ZERO(stat(FILENAME, &pre_st), NULL);
T_ASSERT_POSIX_ZERO(utimensat(AT_FDCWD, FILENAME, tptr[i], 0), NULL);
T_ASSERT_POSIX_ZERO(stat(FILENAME, &post_st), NULL);
if (tptr[i][0].tv_nsec == UTIME_NOW) {
T_ASSERT_GE(post_st.st_atimespec.tv_sec, now.tv_sec, NULL);
} else if (tptr[i][0].tv_nsec == UTIME_OMIT) {
T_ASSERT_EQ(post_st.st_atimespec.tv_sec, pre_st.st_atimespec.tv_sec, NULL);
T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, pre_st.st_atimespec.tv_nsec, NULL);
} else {
T_ASSERT_EQ(post_st.st_atimespec.tv_sec, tptr[i][0].tv_sec, NULL);
T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, tptr[i][0].tv_nsec, NULL);
}
if (tptr[i][1].tv_nsec == UTIME_NOW) {
T_ASSERT_GE(post_st.st_mtimespec.tv_sec, now.tv_sec, NULL);
} else if (tptr[i][1].tv_nsec == UTIME_OMIT) {
T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, pre_st.st_mtimespec.tv_sec, NULL);
T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, pre_st.st_mtimespec.tv_nsec, NULL);
} else {
T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, tptr[i][1].tv_sec, NULL);
T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, tptr[i][1].tv_nsec, NULL);
}
}
}