1 /*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <gtest/gtest.h>
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <sys/utsname.h>
23 #include <sys/vfs.h>
24
25 #include "TemporaryFile.h"
26
27 // Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
28 #if !defined(FALLOC_FL_PUNCH_HOLE) || !defined(FALLOC_FL_KEEP_SIZE)
29 #include <linux/falloc.h>
30 #include <linux/magic.h>
31 #endif
32
TEST(fcntl,fcntl_smoke)33 TEST(fcntl, fcntl_smoke) {
34 int fd = open("/proc/version", O_RDONLY);
35 ASSERT_TRUE(fd != -1);
36
37 int flags = fcntl(fd, F_GETFD);
38 ASSERT_TRUE(flags != -1);
39 ASSERT_EQ(0, flags & FD_CLOEXEC);
40
41 int rc = fcntl(fd, F_SETFD, FD_CLOEXEC);
42 ASSERT_EQ(0, rc);
43
44 flags = fcntl(fd, F_GETFD);
45 ASSERT_TRUE(flags != -1);
46 ASSERT_EQ(FD_CLOEXEC, flags & FD_CLOEXEC);
47
48 close(fd);
49 }
50
TEST(fcntl,open_open64)51 TEST(fcntl, open_open64) {
52 int fd;
53
54 fd = open("/proc/version", O_RDONLY);
55 ASSERT_TRUE(fd != -1);
56 close(fd);
57
58 fd = open64("/proc/version", O_RDONLY);
59 ASSERT_TRUE(fd != -1);
60 close(fd);
61 }
62
TEST(fcntl,openat_openat64)63 TEST(fcntl, openat_openat64) {
64 int fd;
65
66 fd = openat(AT_FDCWD, "/proc/version", O_RDONLY);
67 ASSERT_TRUE(fd != -1);
68 close(fd);
69
70 fd = openat64(AT_FDCWD, "/proc/version", O_RDONLY);
71 ASSERT_TRUE(fd != -1);
72 close(fd);
73 }
74
TEST(fcntl,creat_creat64)75 TEST(fcntl, creat_creat64) {
76 ASSERT_EQ(-1, creat("", 0666));
77 ASSERT_EQ(ENOENT, errno);
78 ASSERT_EQ(-1, creat64("", 0666));
79 ASSERT_EQ(ENOENT, errno);
80 }
81
TEST(fcntl,posix_fadvise)82 TEST(fcntl, posix_fadvise) {
83 TemporaryFile tf;
84 errno = 0;
85
86 EXPECT_EQ(EBADF, posix_fadvise(-1, 0, 0, POSIX_FADV_NORMAL));
87 EXPECT_EQ(0, errno);
88
89 EXPECT_EQ(EBADF, posix_fadvise64(-1, 0, 0, POSIX_FADV_NORMAL));
90 EXPECT_EQ(0, errno);
91
92 EXPECT_EQ(EINVAL, posix_fadvise(tf.fd, 0, 0, -1));
93 EXPECT_EQ(0, errno);
94
95 EXPECT_EQ(EINVAL, posix_fadvise64(tf.fd, 0, 0, -1));
96 EXPECT_EQ(0, errno);
97
98 EXPECT_EQ(0, posix_fadvise(tf.fd, 0, 0, POSIX_FADV_NORMAL));
99 EXPECT_EQ(0, posix_fadvise64(tf.fd, 0, 0, POSIX_FADV_NORMAL));
100 }
101
TEST(fcntl,fallocate_EINVAL)102 TEST(fcntl, fallocate_EINVAL) {
103 TemporaryFile tf;
104
105 // fallocate/fallocate64 set errno.
106 // posix_fallocate/posix_fallocate64 return an errno value.
107
108 errno = 0;
109 ASSERT_EQ(-1, fallocate(tf.fd, 0, 0, -1));
110 ASSERT_EQ(EINVAL, errno);
111
112 errno = 0;
113 ASSERT_EQ(-1, fallocate64(tf.fd, 0, 0, -1));
114 ASSERT_EQ(EINVAL, errno);
115
116 errno = 0;
117 ASSERT_EQ(EINVAL, posix_fallocate(tf.fd, 0, -1));
118 ASSERT_EQ(0, errno);
119
120 errno = 0;
121 ASSERT_EQ(EINVAL, posix_fallocate64(tf.fd, 0, -1));
122 ASSERT_EQ(0, errno);
123 }
124
TEST(fcntl,fallocate)125 TEST(fcntl, fallocate) {
126 TemporaryFile tf;
127 struct stat sb;
128 ASSERT_EQ(0, fstat(tf.fd, &sb));
129 ASSERT_EQ(0, sb.st_size);
130
131 #if defined(__BIONIC__)
132 ASSERT_EQ(0, fallocate(tf.fd, 0, 0, 1));
133 ASSERT_EQ(0, fstat(tf.fd, &sb));
134 ASSERT_EQ(1, sb.st_size);
135
136 ASSERT_EQ(0, fallocate64(tf.fd, 0, 0, 2));
137 ASSERT_EQ(0, fstat(tf.fd, &sb));
138 ASSERT_EQ(2, sb.st_size);
139 #endif
140
141 ASSERT_EQ(0, posix_fallocate(tf.fd, 0, 3));
142 ASSERT_EQ(0, fstat(tf.fd, &sb));
143 ASSERT_EQ(3, sb.st_size);
144
145 ASSERT_EQ(0, posix_fallocate64(tf.fd, 0, 4));
146 ASSERT_EQ(0, fstat(tf.fd, &sb));
147 ASSERT_EQ(4, sb.st_size);
148 }
149
TEST(fcntl,f_getlk64)150 TEST(fcntl, f_getlk64) {
151 int fd = open64("/proc/version", O_RDONLY);
152 ASSERT_TRUE(fd != -1);
153
154 struct flock64 check_lock;
155 check_lock.l_type = F_WRLCK;
156 check_lock.l_start = 0;
157 check_lock.l_whence = SEEK_SET;
158 check_lock.l_len = 0;
159
160 int rc = fcntl(fd, F_GETLK64, &check_lock);
161 ASSERT_EQ(0, rc);
162
163 close(fd);
164 }
165
TEST(fcntl,splice)166 TEST(fcntl, splice) {
167 int pipe_fds[2];
168 ASSERT_EQ(0, pipe(pipe_fds));
169
170 int in = open("/proc/cpuinfo", O_RDONLY);
171 ASSERT_NE(in, -1);
172
173 TemporaryFile tf;
174
175 ssize_t bytes_read = splice(in, 0, pipe_fds[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE);
176 ASSERT_NE(bytes_read, -1);
177
178 ssize_t bytes_written = splice(pipe_fds[0], NULL, tf.fd, 0, bytes_read, SPLICE_F_MORE | SPLICE_F_MOVE);
179 ASSERT_EQ(bytes_read, bytes_written);
180
181 close(pipe_fds[0]);
182 close(pipe_fds[1]);
183 close(in);
184 }
185
TEST(fcntl,vmsplice)186 TEST(fcntl, vmsplice) {
187 int pipe_fds[2];
188 ASSERT_EQ(0, pipe(pipe_fds));
189
190 iovec v[2];
191 v[0].iov_base = const_cast<char*>("hello ");
192 v[0].iov_len = 6;
193 v[1].iov_base = const_cast<char*>("world\n");
194 v[1].iov_len = 6;
195 ssize_t bytes_written = vmsplice(pipe_fds[1], v, sizeof(v)/sizeof(iovec), 0);
196 ASSERT_EQ(v[0].iov_len + v[1].iov_len, static_cast<size_t>(bytes_written));
197 close(pipe_fds[1]);
198
199 char buf[BUFSIZ];
200 FILE* fp = fdopen(pipe_fds[0], "r");
201 ASSERT_TRUE(fp != NULL);
202 ASSERT_TRUE(fgets(buf, sizeof(buf), fp) != NULL);
203 fclose(fp);
204 ASSERT_STREQ("hello world\n", buf);
205 }
206
TEST(fcntl,tee)207 TEST(fcntl, tee) {
208 char expected[256];
209 FILE* expected_fp = fopen("/proc/version", "r");
210 ASSERT_TRUE(expected_fp != NULL);
211 ASSERT_TRUE(fgets(expected, sizeof(expected), expected_fp) != NULL);
212 fclose(expected_fp);
213
214 int pipe1[2];
215 ASSERT_EQ(0, pipe(pipe1));
216
217 int pipe2[2];
218 ASSERT_EQ(0, pipe(pipe2));
219
220 int in = open("/proc/version", O_RDONLY);
221 ASSERT_NE(in, -1);
222
223 // Write /proc/version into pipe1.
224 ssize_t bytes_read = splice(in, 0, pipe1[1], NULL, 8*1024, SPLICE_F_MORE | SPLICE_F_MOVE);
225 ASSERT_NE(bytes_read, -1);
226 close(pipe1[1]);
227
228 // Tee /proc/version from pipe1 into pipe2.
229 ssize_t bytes_teed = tee(pipe1[0], pipe2[1], SIZE_MAX, 0);
230 ASSERT_EQ(bytes_read, bytes_teed);
231 close(pipe2[1]);
232
233 // The out fds of both pipe1 and pipe2 should now contain /proc/version.
234 char buf1[BUFSIZ];
235 FILE* fp1 = fdopen(pipe1[0], "r");
236 ASSERT_TRUE(fp1 != NULL);
237 ASSERT_TRUE(fgets(buf1, sizeof(buf1), fp1) != NULL);
238 fclose(fp1);
239
240 char buf2[BUFSIZ];
241 FILE* fp2 = fdopen(pipe2[0], "r");
242 ASSERT_TRUE(fp2 != NULL);
243 ASSERT_TRUE(fgets(buf2, sizeof(buf2), fp2) != NULL);
244 fclose(fp2);
245
246 ASSERT_STREQ(expected, buf1);
247 ASSERT_STREQ(expected, buf2);
248 }
249
TEST(fcntl,readahead)250 TEST(fcntl, readahead) {
251 // Just check that the function is available.
252 errno = 0;
253 ASSERT_EQ(-1, readahead(-1, 0, 123));
254 ASSERT_EQ(EBADF, errno);
255 }
256
TEST(fcntl,sync_file_range)257 TEST(fcntl, sync_file_range) {
258 // Just check that the function is available.
259 errno = 0;
260 ASSERT_EQ(-1, sync_file_range(-1, 0, 0, 0));
261 ASSERT_EQ(EBADF, errno);
262
263 TemporaryFile tf;
264 ASSERT_EQ(0, sync_file_range(tf.fd, 0, 0, 0));
265
266 // The arguments to the underlying system call are in a different order on 32-bit ARM.
267 // Check that the `flags` argument gets passed to the kernel correctly.
268 errno = 0;
269 ASSERT_EQ(-1, sync_file_range(tf.fd, 0, 0, ~0));
270 ASSERT_EQ(EINVAL, errno);
271 }
272
parse_kernel_release(long * const major,long * const minor)273 static bool parse_kernel_release(long* const major, long* const minor) {
274 struct utsname buf;
275 if (uname(&buf) == -1) {
276 return false;
277 }
278 return sscanf(buf.release, "%ld.%ld", major, minor) == 2;
279 }
280
281 /*
282 * Kernels less than 4.1 are affected.
283 * Devices that fail this test should include change id from Nexus:
284 * Commit: 9b431291a1fadbdbcca1485711b5bab145112293
285 */
TEST(fcntl,falloc_punch)286 TEST(fcntl, falloc_punch) {
287 long major = 0, minor = 0;
288 ASSERT_TRUE(parse_kernel_release(&major, &minor));
289
290 if (major < 4 || (major == 4 && minor < 1)) {
291 TemporaryFile tf;
292 struct statfs sfs;
293 ASSERT_EQ(0, fstatfs(tf.fd, &sfs));
294 if (sfs.f_type == EXT4_SUPER_MAGIC) {
295 ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1));
296 ASSERT_EQ(errno, EOPNOTSUPP);
297 }
298 }
299 }
300