6 #include <System/sys/content_protection.h>
7 #include <TargetConditionals.h>
10 #include <darwintest.h>
12 #define ALLOWED_MKOSTEMP_FLAGS (O_APPEND | O_SHLOCK | O_EXLOCK | O_CLOEXEC)
13 #define FCNTL_GETFL_EXPOSED_OFLAGS (O_APPEND)
15 #define TEMPLATE_BASE "/tmp/mktemp_test."
16 #define TEMPLATE_XS "XXXXXXXX"
17 static const char template[] = TEMPLATE_BASE TEMPLATE_XS
;
19 static void test_mkostemp(int oflags
);
21 T_DECL(mkstemp
, "basic mkstemp test")
23 char path
[sizeof(template)];
24 struct stat path_stat
;
27 memcpy(path
, template, sizeof(template));
29 int fd
= mkstemp(path
);
30 T_ASSERT_POSIX_SUCCESS(fd
,
31 "mkstemp must return a valid fd");
32 T_ASSERT_TRUE(memcmp(path
, TEMPLATE_BASE
, strlen(TEMPLATE_BASE
)) == 0,
33 "mkstemp must respect the template. template: %s, got: %s",
36 // stat fd and path, compare those
37 T_ASSERT_POSIX_ZERO(stat(path
, &path_stat
),
38 "must be able to stat the path");
39 T_ASSERT_POSIX_ZERO(fstat(fd
, &fd_stat
),
40 "must be able to fstat the fd");
42 (path_stat
.st_dev
== fd_stat
.st_dev
) &&
43 (path_stat
.st_ino
== fd_stat
.st_ino
),
44 "fd does not match the file path");
45 // verify file attributes
46 T_ASSERT_TRUE(S_ISREG(path_stat
.st_mode
),
47 "the path must point to a regular file");
48 T_ASSERT_EQ(0600, (path_stat
.st_mode
& 0777),
49 "created file must have 0600 permissions");
50 T_ASSERT_EQ_LLONG(0LL, path_stat
.st_size
,
51 "created file must be empty");
52 // unlink and stat again
53 T_ASSERT_POSIX_ZERO(unlink(path
),
54 "must be able to unlink the created file");
55 T_ASSERT_POSIX_ZERO(fstat(fd
, &fd_stat
),
56 "must be able to stat the fd after unlink");
57 T_ASSERT_EQ(0, fd_stat
.st_nlink
,
58 "must not have any hard links to the file after unlink");
60 T_ASSERT_POSIX_ZERO(close(fd
),
61 "must be able to close the fd");
64 T_DECL(two_mkstemp_calls
, "two mkstemp calls return different paths and fds")
66 char path1
[sizeof(template)];
67 char path2
[sizeof(template)];
68 memcpy(path1
, template, sizeof(path1
));
69 memcpy(path2
, template, sizeof(path2
));
71 int fd1
= mkostemp(path1
, 0);
72 T_ASSERT_POSIX_SUCCESS(fd1
, "mkostemp must return a valid fd");
74 int fd2
= mkostemp(path2
, 0);
75 T_ASSERT_POSIX_SUCCESS(fd2
, "mkostemp must return a valid fd");
78 "two mkostemp calls must return different fds");
79 T_ASSERT_NE_STR(path1
, path2
,
80 "two mkostemp calls must return different paths");
82 T_EXPECT_POSIX_ZERO(unlink(path1
),
83 "unlink must succeed for the first file");
84 T_EXPECT_POSIX_ZERO(unlink(path2
),
85 "unlink must succeed for the second file");
86 T_EXPECT_POSIX_ZERO(close(fd1
),
87 "close must succeed for the first fd");
88 T_EXPECT_POSIX_ZERO(close(fd2
),
89 "close must succeed for the second fd");
92 T_DECL(mktemp
, "basic mktemp test")
94 char path
[sizeof(template)];
96 memcpy(path
, template, sizeof(template));
98 T_ASSERT_EQ_PTR((void *) mktemp(path
), (void *) path
,
99 "mktemp must return its argument");
101 T_ASSERT_TRUE(memcmp(path
, TEMPLATE_BASE
, strlen(TEMPLATE_BASE
)) == 0,
102 "mktemp must respect the template. template: %s, got: %s",
106 T_DECL(mkdtemp
, "basic mkdtemp test")
108 char path
[sizeof(template)];
111 memcpy(path
, template, sizeof(template));
113 T_ASSERT_EQ_PTR((void *) mkdtemp(path
), (void *) path
,
114 "mkdtemp must return its argument");
115 T_ASSERT_TRUE(memcmp(path
, TEMPLATE_BASE
, strlen(TEMPLATE_BASE
)) == 0,
116 "mkdtemp must respect the template. template: %s, got: %s",
119 // stat fd and path, compare those
120 T_ASSERT_POSIX_ZERO(stat(path
, &dstat
),
121 "must be able to stat the path");
122 // verify file attributes
123 T_ASSERT_TRUE(S_ISDIR(dstat
.st_mode
),
124 "the path must point to a directory");
125 T_ASSERT_EQ(0700, (dstat
.st_mode
& 0777),
126 "created directory must have 0700 permissions");
128 T_ASSERT_POSIX_ZERO(rmdir(path
),
129 "must be able to rmdir the created directory");
132 T_DECL(mkostemp_no_flags
, "mkostemp works with 0 oflags")
137 T_DECL(mkostemp_cloexec
, "mkostemp works with O_CLOEXEC")
139 test_mkostemp(O_CLOEXEC
);
142 T_DECL(mkostemp_append
, "mkostemp works with O_APPEND")
144 test_mkostemp(O_APPEND
);
147 T_DECL(mkostemp_all_flags
, "mkostemp works with all allowed flags")
149 test_mkostemp(ALLOWED_MKOSTEMP_FLAGS
);
152 T_DECL(mkostemp_bad_flags
, "mkostemp checks for disallowed flags")
154 char path
[sizeof(template)];
155 memcpy(path
, template, sizeof(path
));
157 T_ASSERT_EQ(-1, mkostemp(path
, O_CREAT
), "mkostemp must not allow O_CREAT");
158 T_ASSERT_EQ(-1, mkostemp(path
, O_NONBLOCK
), "mkostemp must not allow O_NONBLOCK");
162 test_mkostemp(int oflags
)
164 char path
[sizeof(template)];
167 T_LOG("testing mkostemp with oflags %#x\n", oflags
);
169 memcpy(path
, template, sizeof(template));
171 fd
= mkostemp(path
, oflags
);
173 T_ASSERT_POSIX_SUCCESS(fd
,
174 "mkostemp must return a valid fd");
176 if (oflags
& O_CLOEXEC
) {
177 T_ASSERT_EQ(FD_CLOEXEC
, fcntl(fd
, F_GETFD
),
178 "O_CLOEXEC must be visible through fcntl GETFD");
180 T_ASSERT_EQ(0, fcntl(fd
, F_GETFD
),
181 "must not add fcntl GETFD flags at will");
185 (oflags
& FCNTL_GETFL_EXPOSED_OFLAGS
),
186 (fcntl(fd
, F_GETFL
) & FCNTL_GETFL_EXPOSED_OFLAGS
),
187 "oflags must be visible through fcntl GETFL");
189 T_EXPECT_POSIX_ZERO(unlink(path
),
190 "must be able to unlink the created file");
191 T_EXPECT_POSIX_ZERO(close(fd
),
192 "must be able to close the fd");
196 // mkstemp_dprotected_np is marked as __OSX_UNAVAILABLE, so its usage
197 // has to be guarded by target conditionals. Having a testcase that
198 // always does T_SKIP on OS X yields another issue. The compiler starts
199 // demanding to mark the test function definition as noreturn. Just
200 // don't compile the testcase for OS X.
201 T_DECL(mkstemp_dprotected_np
, "basic mkstemp_dprotected_np test")
203 char path
[sizeof(template)];
205 int protection_class
;
208 // the test requires /tmp to be HFS
209 T_ASSERT_POSIX_ZERO(statfs("/tmp", &sfs
), "must be able to statfs /tmp");
210 if (strcmp(sfs
.f_fstypename
, "hfs") != 0) {
211 T_SKIP("Can only test dprotected on a HFS filesystem. Got %s,"
212 "skipping the test.", sfs
.f_fstypename
);
215 memcpy(path
, template, sizeof(template));
217 fd
= mkstemp_dprotected_np(path
, PROTECTION_CLASS_B
, 0);
218 T_ASSERT_POSIX_SUCCESS(fd
,
219 "mkstemp_dprotected_np must return a valid fd");
220 T_ASSERT_TRUE(memcmp(path
, TEMPLATE_BASE
, strlen(TEMPLATE_BASE
)) == 0,
221 "mkstemp_dprotected_np must respect the template. template: %s, got: %s",
223 // verify protection class
224 protection_class
= fcntl(fd
, F_GETPROTECTIONCLASS
);
225 T_WITH_ERRNO
; T_ASSERT_EQ(protection_class
, PROTECTION_CLASS_B
,
226 "must get back the protection class from fcntl");
228 T_ASSERT_POSIX_ZERO(close(fd
),
229 "must be able to close the fd");
230 T_ASSERT_POSIX_ZERO(unlink(path
),
231 "must be able to unlink the created file");