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