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