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 29TEST(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 37TEST(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) 50TEST(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) 69TEST(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 87TEST(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 99TEST(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 118TEST(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 132TEST(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 162TEST(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 194TEST(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 202TEST(file, GetExecutablePath) { 203 ASSERT_NE("", android::base::GetExecutablePath()); 204} 205 206TEST(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 212TEST(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 218TEST(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 245TEST(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