blob: 74d3675649d681682807a8e760b5e8842e051f50 [file] [log] [blame]
Elliott Hughes06209252013-11-06 16:20:54 -08001/*
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>
Nick Desaulniers094f3162016-07-19 15:20:24 -070021#include <string.h>
22#include <sys/utsname.h>
Matthias Hausner47a52102017-06-02 10:09:19 -070023#include <sys/vfs.h>
Elliott Hughes06209252013-11-06 16:20:54 -080024
Elliott Hughesf64b8ea2014-02-03 16:20:46 -080025#include "TemporaryFile.h"
26
Nick Desaulniers094f3162016-07-19 15:20:24 -070027// 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>
Matthias Hausner47a52102017-06-02 10:09:19 -070030#include <linux/magic.h>
Nick Desaulniers094f3162016-07-19 15:20:24 -070031#endif
32
Elliott Hughes06209252013-11-06 16:20:54 -080033TEST(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);
Elliott Hughesdb1ea342014-01-17 18:42:49 -080047
48 close(fd);
49}
50
51TEST(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
63TEST(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
75TEST(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);
Elliott Hughes06209252013-11-06 16:20:54 -080080}
Elliott Hughesf64b8ea2014-02-03 16:20:46 -080081
Elliott Hughesb587f332014-09-10 17:39:00 -070082TEST(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
Elliott Hughesf64b8ea2014-02-03 16:20:46 -0800102TEST(fcntl, fallocate_EINVAL) {
103 TemporaryFile tf;
104
Elliott Hughesb587f332014-09-10 17:39:00 -0700105 // fallocate/fallocate64 set errno.
106 // posix_fallocate/posix_fallocate64 return an errno value.
107
Elliott Hughesf64b8ea2014-02-03 16:20:46 -0800108 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);
Elliott Hughesf64b8ea2014-02-03 16:20:46 -0800115
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
125TEST(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
Elliott Hughes063525c2014-05-13 11:19:57 -0700131#if defined(__BIONIC__)
Elliott Hughesf64b8ea2014-02-03 16:20:46 -0800132 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}
Serban Constantinescu48501af2014-03-14 13:16:25 +0000149
150TEST(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}
Elliott Hughes3f525d42014-06-24 16:32:01 -0700165
166TEST(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
186TEST(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
207TEST(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}
Elliott Hughes55147ad2016-04-05 11:06:02 -0700249
250TEST(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}
Elliott Hughes7f72ad42016-04-05 11:56:03 -0700256
257TEST(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}
Nick Desaulniers094f3162016-07-19 15:20:24 -0700272
273static 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 */
286TEST(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;
Matthias Hausner47a52102017-06-02 10:09:19 -0700292 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 }
Nick Desaulniers094f3162016-07-19 15:20:24 -0700298 }
299}