Home | History | Annotate | Download | only in base
      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 "android-base/file.h"
     18 
     19 #include <gtest/gtest.h>
     20 
     21 #include <errno.h>
     22 #include <fcntl.h>
     23 #include <unistd.h>
     24 
     25 #include <string>
     26 
     27 #include "android-base/test_utils.h"
     28 
     29 TEST(file, ReadFileToString_ENOENT) {
     30   std::string s("hello");
     31   errno = 0;
     32   ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
     33   EXPECT_EQ(ENOENT, errno);
     34   EXPECT_EQ("", s);  // s was cleared.
     35 }
     36 
     37 TEST(file, ReadFileToString_WriteStringToFile) {
     38   TemporaryFile tf;
     39   ASSERT_TRUE(tf.fd != -1);
     40   ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
     41     << strerror(errno);
     42   std::string s;
     43   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     44     << strerror(errno);
     45   EXPECT_EQ("abc", s);
     46 }
     47 
     48 // symlinks require elevated privileges on Windows.
     49 #if !defined(_WIN32)
     50 TEST(file, ReadFileToString_WriteStringToFile_symlink) {
     51   TemporaryFile target, link;
     52   ASSERT_EQ(0, unlink(link.path));
     53   ASSERT_EQ(0, symlink(target.path, link.path));
     54   ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false));
     55   ASSERT_EQ(ELOOP, errno);
     56   ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true));
     57 
     58   std::string s;
     59   ASSERT_FALSE(android::base::ReadFileToString(link.path, &s));
     60   ASSERT_EQ(ELOOP, errno);
     61   ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true));
     62   ASSERT_EQ("foo", s);
     63 }
     64 #endif
     65 
     66 // WriteStringToFile2 is explicitly for setting Unix permissions, which make no
     67 // sense on Windows.
     68 #if !defined(_WIN32)
     69 TEST(file, WriteStringToFile2) {
     70   TemporaryFile tf;
     71   ASSERT_TRUE(tf.fd != -1);
     72   ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
     73                                                getuid(), getgid()))
     74       << strerror(errno);
     75   struct stat sb;
     76   ASSERT_EQ(0, stat(tf.path, &sb));
     77   ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
     78   ASSERT_EQ(getuid(), sb.st_uid);
     79   ASSERT_EQ(getgid(), sb.st_gid);
     80   std::string s;
     81   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
     82     << strerror(errno);
     83   EXPECT_EQ("abc", s);
     84 }
     85 #endif
     86 
     87 TEST(file, WriteStringToFd) {
     88   TemporaryFile tf;
     89   ASSERT_TRUE(tf.fd != -1);
     90   ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
     91 
     92   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
     93 
     94   std::string s;
     95   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
     96   EXPECT_EQ("abc", s);
     97 }
     98 
     99 TEST(file, WriteFully) {
    100   TemporaryFile tf;
    101   ASSERT_TRUE(tf.fd != -1);
    102   ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
    103 
    104   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
    105 
    106   std::string s;
    107   s.resize(3);
    108   ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
    109     << strerror(errno);
    110   EXPECT_EQ("abc", s);
    111 
    112   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
    113 
    114   s.resize(1024);
    115   ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
    116 }
    117 
    118 TEST(file, RemoveFileIfExist) {
    119   TemporaryFile tf;
    120   ASSERT_TRUE(tf.fd != -1);
    121   close(tf.fd);
    122   tf.fd = -1;
    123   std::string err;
    124   ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
    125   ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
    126   TemporaryDir td;
    127   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
    128   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
    129   ASSERT_EQ("is not a regular or symbol link file", err);
    130 }
    131 
    132 TEST(file, Readlink) {
    133 #if !defined(_WIN32)
    134   // Linux doesn't allow empty symbolic links.
    135   std::string min("x");
    136   // ext2 and ext4 both have PAGE_SIZE limits.
    137   // If file encryption is enabled, there's extra overhead to store the
    138   // size of the encrypted symlink target. There's also an off-by-one
    139   // in current kernels (and marlin/sailfish where we're seeing this
    140   // failure are still on 3.18, far from current). http://b/33306057.
    141   std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
    142 
    143   TemporaryDir td;
    144   std::string min_path{std::string(td.path) + "/" + "min"};
    145   std::string max_path{std::string(td.path) + "/" + "max"};
    146 
    147   ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
    148   ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
    149 
    150   std::string result;
    151 
    152   result = "wrong";
    153   ASSERT_TRUE(android::base::Readlink(min_path, &result));
    154   ASSERT_EQ(min, result);
    155 
    156   result = "wrong";
    157   ASSERT_TRUE(android::base::Readlink(max_path, &result));
    158   ASSERT_EQ(max, result);
    159 #endif
    160 }
    161 
    162 TEST(file, Realpath) {
    163 #if !defined(_WIN32)
    164   TemporaryDir td;
    165   std::string basename = android::base::Basename(td.path);
    166   std::string dir_name = android::base::Dirname(td.path);
    167   std::string base_dir_name = android::base::Basename(dir_name);
    168 
    169   {
    170     std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
    171     std::string result;
    172     ASSERT_TRUE(android::base::Realpath(path, &result));
    173     ASSERT_EQ(td.path, result);
    174   }
    175 
    176   {
    177     std::string path = std::string(td.path) + "/..";
    178     std::string result;
    179     ASSERT_TRUE(android::base::Realpath(path, &result));
    180     ASSERT_EQ(dir_name, result);
    181   }
    182 
    183   {
    184     errno = 0;
    185     std::string path = std::string(td.path) + "/foo.noent";
    186     std::string result = "wrong";
    187     ASSERT_TRUE(!android::base::Realpath(path, &result));
    188     ASSERT_TRUE(result.empty());
    189     ASSERT_EQ(ENOENT, errno);
    190   }
    191 #endif
    192 }
    193 
    194 TEST(file, GetExecutableDirectory) {
    195   std::string path = android::base::GetExecutableDirectory();
    196   ASSERT_NE("", path);
    197   ASSERT_NE(android::base::GetExecutablePath(), path);
    198   ASSERT_EQ('/', path[0]);
    199   ASSERT_NE('/', path[path.size() - 1]);
    200 }
    201 
    202 TEST(file, GetExecutablePath) {
    203   ASSERT_NE("", android::base::GetExecutablePath());
    204 }
    205 
    206 TEST(file, Basename) {
    207   EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
    208   EXPECT_EQ("sh", android::base::Basename("sh"));
    209   EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
    210 }
    211 
    212 TEST(file, Dirname) {
    213   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
    214   EXPECT_EQ(".", android::base::Dirname("sh"));
    215   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
    216 }
    217 
    218 TEST(file, ReadFileToString_capacity) {
    219   TemporaryFile tf;
    220   ASSERT_TRUE(tf.fd != -1);
    221 
    222   // For a huge file, the overhead should still be small.
    223   std::string s;
    224   size_t size = 16 * 1024 * 1024;
    225   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
    226   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
    227   EXPECT_EQ(size, s.size());
    228   EXPECT_LT(s.capacity(), size + 16);
    229 
    230   // Even for weird badly-aligned sizes.
    231   size += 12345;
    232   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
    233   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
    234   EXPECT_EQ(size, s.size());
    235   EXPECT_LT(s.capacity(), size + 16);
    236 
    237   // We'll shrink an enormous string if you read a small file into it.
    238   size = 64;
    239   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
    240   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
    241   EXPECT_EQ(size, s.size());
    242   EXPECT_LT(s.capacity(), size + 16);
    243 }
    244 
    245 TEST(file, ReadFileToString_capacity_0) {
    246   TemporaryFile tf;
    247   ASSERT_TRUE(tf.fd != -1);
    248 
    249   // Because /proc reports its files as zero-length, we don't actually trust
    250   // any file that claims to be zero-length. Rather than add increasingly
    251   // complex heuristics for shrinking the passed-in string in that case, we
    252   // currently leave it alone.
    253   std::string s;
    254   size_t initial_capacity = s.capacity();
    255   ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
    256   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
    257   EXPECT_EQ(0U, s.size());
    258   EXPECT_EQ(initial_capacity, s.capacity());
    259 }
    260