]> git.saurik.com Git - apple/libc.git/blame - tests/mktemp.c
Libc-1158.50.2.tar.gz
[apple/libc.git] / tests / mktemp.c
CommitLineData
974e3884
A
1#include <fcntl.h>
2#include <stdlib.h>
3#include <sys/mount.h>
4#include <sys/param.h>
5#include <sys/stat.h>
6#include <System/sys/content_protection.h>
7#include <TargetConditionals.h>
8#include <unistd.h>
9
10#include <darwintest.h>
11
12#define ALLOWED_MKOSTEMP_FLAGS (O_APPEND | O_SHLOCK | O_EXLOCK | O_CLOEXEC)
13#define FCNTL_GETFL_EXPOSED_OFLAGS (O_APPEND)
14
15#define TEMPLATE_BASE "/tmp/mktemp_test."
16#define TEMPLATE_XS "XXXXXXXX"
17static const char template[] = TEMPLATE_BASE TEMPLATE_XS;
18
19static void test_mkostemp(int oflags);
20
21T_DECL(test_mkstemp, "basic mkstemp test")
22{
23 char path[sizeof(template)];
24 struct stat path_stat;
25 struct stat fd_stat;
26
27 memcpy(path, template, sizeof(template));
28
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",
34 template, path);
35
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");
41 T_ASSERT_TRUE(
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");
59 // close
60 T_ASSERT_POSIX_ZERO(close(fd),
61 "must be able to close the fd");
62}
63
64T_DECL(two_mkstemp_calls, "two mkstemp calls return different paths and fds")
65{
66 char path1[sizeof(template)];
67 char path2[sizeof(template)];
68 memcpy(path1, template, sizeof(path1));
69 memcpy(path2, template, sizeof(path2));
70
71 int fd1 = mkostemp(path1, 0);
72 T_ASSERT_POSIX_SUCCESS(fd1, "mkostemp must return a valid fd");
73
74 int fd2 = mkostemp(path2, 0);
75 T_ASSERT_POSIX_SUCCESS(fd2, "mkostemp must return a valid fd");
76
77 T_ASSERT_NE(fd1, fd2,
78 "two mkostemp calls must return different fds");
79 T_ASSERT_NE_STR(path1, path2,
80 "two mkostemp calls must return different paths");
81
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");
90}
91
92T_DECL(test_mktemp, "basic mktemp test")
93{
94 char path[sizeof(template)];
95
96 memcpy(path, template, sizeof(template));
97
98 T_ASSERT_EQ_PTR((void *) mktemp(path), (void *) path,
99 "mktemp must return its argument");
100
101 T_ASSERT_TRUE(memcmp(path, TEMPLATE_BASE, strlen(TEMPLATE_BASE)) == 0,
102 "mktemp must respect the template. template: %s, got: %s",
103 template, path);
104}
105
106T_DECL(test_mkdtemp, "basic mkdtemp test")
107{
108 char path[sizeof(template)];
109 struct stat dstat;
110
111 memcpy(path, template, sizeof(template));
112
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",
117 template, path);
118
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");
127 // cleanup
128 T_ASSERT_POSIX_ZERO(rmdir(path),
129 "must be able to rmdir the created directory");
130}
131
132T_DECL(mkostemp_no_flags, "mkostemp works with 0 oflags")
133{
134 test_mkostemp(0);
135}
136
137T_DECL(mkostemp_cloexec, "mkostemp works with O_CLOEXEC")
138{
139 test_mkostemp(O_CLOEXEC);
140}
141
142T_DECL(mkostemp_append, "mkostemp works with O_APPEND")
143{
144 test_mkostemp(O_APPEND);
145}
146
147T_DECL(mkostemp_all_flags, "mkostemp works with all allowed flags")
148{
149 test_mkostemp(ALLOWED_MKOSTEMP_FLAGS);
150}
151
152T_DECL(mkostemp_bad_flags, "mkostemp checks for disallowed flags")
153{
154 char path[sizeof(template)];
155 memcpy(path, template, sizeof(path));
156
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");
159}
160
161static void
162test_mkostemp(int oflags)
163{
164 char path[sizeof(template)];
165 int fd;
166
167 T_LOG("testing mkostemp with oflags %#x\n", oflags);
168
169 memcpy(path, template, sizeof(template));
170
171 fd = mkostemp(path, oflags);
172
173 T_ASSERT_POSIX_SUCCESS(fd,
174 "mkostemp must return a valid fd");
175
176 if (oflags & O_CLOEXEC) {
177 T_ASSERT_EQ(FD_CLOEXEC, fcntl(fd, F_GETFD),
178 "O_CLOEXEC must be visible through fcntl GETFD");
179 } else {
180 T_ASSERT_EQ(0, fcntl(fd, F_GETFD),
181 "must not add fcntl GETFD flags at will");
182 }
183
184 T_ASSERT_EQ(
185 (oflags & FCNTL_GETFL_EXPOSED_OFLAGS),
186 (fcntl(fd, F_GETFL) & FCNTL_GETFL_EXPOSED_OFLAGS),
187 "oflags must be visible through fcntl GETFL");
188
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");
193}
194
195#if TARGET_OS_IPHONE
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.
201T_DECL(test_mkstemp_dprotected_np, "basic mkstemp_dprotected_np test")
202{
203 char path[sizeof(template)];
204 int fd;
205 int protection_class;
206 struct statfs sfs;
207
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);
213 }
214
215 memcpy(path, template, sizeof(template));
216 // create a file
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",
222 template, path);
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");
227 // cleanup
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");
232}
233#endif