]>
Commit | Line | Data |
---|---|---|
5ba3f43e A |
1 | #include <sys/cdefs.h> |
2 | #include <sys/param.h> | |
3 | #include <sys/stat.h> | |
4 | #include <sys/time.h> | |
5 | #include <errno.h> | |
6 | #include <fcntl.h> | |
7 | #include <limits.h> | |
8 | #include <paths.h> | |
9 | #include <stdio.h> | |
10 | #include <string.h> | |
11 | #include <unistd.h> | |
12 | ||
13 | #include <darwintest.h> | |
14 | #include <darwintest_utils.h> | |
15 | ||
cb323159 A |
16 | T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true)); |
17 | ||
5ba3f43e A |
18 | #define FILENAME "utimensat" |
19 | ||
20 | static const struct timespec tptr[][2] = { | |
21 | { { 0x12345678, 987654321 }, { 0x15263748, 123456789 }, }, | |
22 | ||
23 | { { 0, UTIME_NOW }, { 0x15263748, 123456789 }, }, | |
24 | { { 0x12345678, 987654321 }, { 0, UTIME_NOW }, }, | |
25 | { { 0, UTIME_NOW }, { 0, UTIME_NOW }, }, | |
26 | ||
27 | { { 0, UTIME_OMIT }, { 0x15263748, 123456789 }, }, | |
28 | { { 0x12345678, 987654321 }, { 0, UTIME_OMIT }, }, | |
29 | { { 0, UTIME_OMIT }, { 0, UTIME_OMIT }, }, | |
30 | ||
31 | { { 0, UTIME_NOW }, { 0, UTIME_OMIT }, }, | |
32 | { { 0, UTIME_OMIT }, { 0, UTIME_NOW }, }, | |
33 | }; | |
34 | ||
35 | T_DECL(utimensat, "Try various versions of utimensat") | |
36 | { | |
37 | T_SETUPBEGIN; | |
38 | T_ASSERT_POSIX_ZERO(chdir(dt_tmpdir()), NULL); | |
a39ff7e2 A |
39 | // Skip the test if the current working directory is not on APFS. |
40 | struct statfs sfs = { 0 }; | |
41 | T_QUIET; T_ASSERT_POSIX_SUCCESS(statfs(".", &sfs), NULL); | |
42 | if (memcmp(&sfs.f_fstypename[0], "apfs", strlen("apfs")) != 0) { | |
43 | T_SKIP("utimensat is APFS-only, but working directory is non-APFS"); | |
44 | } | |
5ba3f43e A |
45 | T_SETUPEND; |
46 | ||
47 | struct stat pre_st, post_st; | |
48 | int fd; | |
49 | ||
0a7de745 | 50 | T_ASSERT_POSIX_SUCCESS((fd = open(FILENAME, O_CREAT | O_RDWR, 0644)), NULL); |
5ba3f43e A |
51 | T_ASSERT_POSIX_ZERO(close(fd), NULL); |
52 | ||
0a7de745 A |
53 | for (size_t i = 0; i < sizeof(tptr) / sizeof(tptr[0]); i++) { |
54 | T_LOG("=== {%ld, %ld} {%ld, %ld} ===", | |
55 | tptr[i][0].tv_sec, tptr[i][0].tv_nsec, | |
56 | tptr[i][1].tv_sec, tptr[i][1].tv_nsec); | |
5ba3f43e A |
57 | |
58 | struct timespec now; | |
59 | clock_gettime(CLOCK_REALTIME, &now); | |
60 | ||
61 | T_ASSERT_POSIX_ZERO(stat(FILENAME, &pre_st), NULL); | |
62 | T_ASSERT_POSIX_ZERO(utimensat(AT_FDCWD, FILENAME, tptr[i], 0), NULL); | |
63 | T_ASSERT_POSIX_ZERO(stat(FILENAME, &post_st), NULL); | |
64 | ||
65 | if (tptr[i][0].tv_nsec == UTIME_NOW) { | |
66 | T_ASSERT_GE(post_st.st_atimespec.tv_sec, now.tv_sec, NULL); | |
67 | } else if (tptr[i][0].tv_nsec == UTIME_OMIT) { | |
68 | T_ASSERT_EQ(post_st.st_atimespec.tv_sec, pre_st.st_atimespec.tv_sec, NULL); | |
69 | T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, pre_st.st_atimespec.tv_nsec, NULL); | |
70 | } else { | |
71 | T_ASSERT_EQ(post_st.st_atimespec.tv_sec, tptr[i][0].tv_sec, NULL); | |
72 | T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, tptr[i][0].tv_nsec, NULL); | |
73 | } | |
74 | ||
75 | if (tptr[i][1].tv_nsec == UTIME_NOW) { | |
76 | T_ASSERT_GE(post_st.st_mtimespec.tv_sec, now.tv_sec, NULL); | |
77 | } else if (tptr[i][1].tv_nsec == UTIME_OMIT) { | |
78 | T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, pre_st.st_mtimespec.tv_sec, NULL); | |
79 | T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, pre_st.st_mtimespec.tv_nsec, NULL); | |
80 | } else { | |
81 | T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, tptr[i][1].tv_sec, NULL); | |
82 | T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, tptr[i][1].tv_nsec, NULL); | |
83 | } | |
84 | } | |
85 | } |