Home | History | Annotate | Download | only in tests
      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