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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * b/28760453: 283 * Kernels older than 4.1 should have ext4 FALLOC_FL_PUNCH_HOLE disabled due to CVE-2015-8839. 284 * Devices that fail this test should cherry-pick the following commit: 285 * https://android.googlesource.com/kernel/msm/+/bdba352e898cbf57c8620ad68c8abf749c784d1f 286 */ 287 TEST(fcntl, falloc_punch) { 288 long major = 0, minor = 0; 289 ASSERT_TRUE(parse_kernel_release(&major, &minor)); 290 291 if (major < 4 || (major == 4 && minor < 1)) { 292 TemporaryFile tf; 293 struct statfs sfs; 294 ASSERT_EQ(0, fstatfs(tf.fd, &sfs)); 295 if (sfs.f_type == EXT4_SUPER_MAGIC) { 296 ASSERT_EQ(-1, fallocate(tf.fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, 1)); 297 ASSERT_EQ(errno, EOPNOTSUPP); 298 } 299 } 300 } 301