blob: 65ee2351c972b59ce3ac4722818c1ecf8f5220c6 [file] [log] [blame]
Elliott Hughesdec12b22015-02-02 17:31:27 -08001/*
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
Elliott Hughes4f713192015-12-04 22:00:26 -080017#include "android-base/file.h"
Dan Albertc007bc32015-03-16 10:08:46 -070018
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070019#include "android-base/utf8.h"
20
Dan Albertc007bc32015-03-16 10:08:46 -070021#include <gtest/gtest.h>
Elliott Hughesdec12b22015-02-02 17:31:27 -080022
23#include <errno.h>
Elliott Hughesf682b472015-02-06 12:19:48 -080024#include <fcntl.h>
25#include <unistd.h>
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070026#include <wchar.h>
Dan Albertc007bc32015-03-16 10:08:46 -070027
28#include <string>
Elliott Hughesdec12b22015-02-02 17:31:27 -080029
liwugangc63cb072018-07-11 13:24:49 +080030#if !defined(_WIN32)
31#include <pwd.h>
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070032#else
33#include <processenv.h>
liwugangc63cb072018-07-11 13:24:49 +080034#endif
35
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070036#include "android-base/logging.h" // and must be after windows.h for ERROR
37
Elliott Hughesdec12b22015-02-02 17:31:27 -080038TEST(file, ReadFileToString_ENOENT) {
39 std::string s("hello");
40 errno = 0;
Dan Albertc007bc32015-03-16 10:08:46 -070041 ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
Elliott Hughesdec12b22015-02-02 17:31:27 -080042 EXPECT_EQ(ENOENT, errno);
Dan Albertc007bc32015-03-16 10:08:46 -070043 EXPECT_EQ("", s); // s was cleared.
Elliott Hughesdec12b22015-02-02 17:31:27 -080044}
45
Spencer Lowcf168a82015-05-24 15:36:28 -070046TEST(file, ReadFileToString_WriteStringToFile) {
Elliott Hughesf682b472015-02-06 12:19:48 -080047 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070048 ASSERT_NE(tf.fd, -1) << tf.path;
Alex Vallée47d67c92015-05-06 16:26:00 -040049 ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
Dan Albert850188f2015-04-29 17:09:53 -070050 << strerror(errno);
Elliott Hughesf682b472015-02-06 12:19:48 -080051 std::string s;
Alex Vallée47d67c92015-05-06 16:26:00 -040052 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
Dan Albert850188f2015-04-29 17:09:53 -070053 << strerror(errno);
Elliott Hughesf682b472015-02-06 12:19:48 -080054 EXPECT_EQ("abc", s);
55}
56
Josh Gaoffabc962016-09-14 16:11:45 -070057// symlinks require elevated privileges on Windows.
58#if !defined(_WIN32)
59TEST(file, ReadFileToString_WriteStringToFile_symlink) {
60 TemporaryFile target, link;
61 ASSERT_EQ(0, unlink(link.path));
62 ASSERT_EQ(0, symlink(target.path, link.path));
63 ASSERT_FALSE(android::base::WriteStringToFile("foo", link.path, false));
64 ASSERT_EQ(ELOOP, errno);
65 ASSERT_TRUE(android::base::WriteStringToFile("foo", link.path, true));
66
67 std::string s;
68 ASSERT_FALSE(android::base::ReadFileToString(link.path, &s));
69 ASSERT_EQ(ELOOP, errno);
70 ASSERT_TRUE(android::base::ReadFileToString(link.path, &s, true));
71 ASSERT_EQ("foo", s);
72}
73#endif
74
Dan Albert0c4b3a32015-04-29 11:32:23 -070075// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
76// sense on Windows.
77#if !defined(_WIN32)
Elliott Hughes9d1f5152015-02-17 10:16:04 -080078TEST(file, WriteStringToFile2) {
79 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070080 ASSERT_NE(tf.fd, -1) << tf.path;
Alex Vallée47d67c92015-05-06 16:26:00 -040081 ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
Dan Albertc007bc32015-03-16 10:08:46 -070082 getuid(), getgid()))
Dan Albert850188f2015-04-29 17:09:53 -070083 << strerror(errno);
Elliott Hughes9d1f5152015-02-17 10:16:04 -080084 struct stat sb;
Alex Vallée47d67c92015-05-06 16:26:00 -040085 ASSERT_EQ(0, stat(tf.path, &sb));
Colin Cross56b37342015-04-30 15:12:21 -070086 ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
Elliott Hughes9d1f5152015-02-17 10:16:04 -080087 ASSERT_EQ(getuid(), sb.st_uid);
88 ASSERT_EQ(getgid(), sb.st_gid);
89 std::string s;
Alex Vallée47d67c92015-05-06 16:26:00 -040090 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
Dan Albert850188f2015-04-29 17:09:53 -070091 << strerror(errno);
Elliott Hughes9d1f5152015-02-17 10:16:04 -080092 EXPECT_EQ("abc", s);
93}
Dan Albert0c4b3a32015-04-29 11:32:23 -070094#endif
Elliott Hughes9d1f5152015-02-17 10:16:04 -080095
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070096#if defined(_WIN32)
97TEST(file, NonUnicodeCharsWindows) {
98 constexpr auto kMaxEnvVariableValueSize = 32767;
99 std::wstring old_tmp;
100 old_tmp.resize(kMaxEnvVariableValueSize);
101 old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
102 std::wstring new_tmp = old_tmp;
103 if (new_tmp.back() != L'\\') {
104 new_tmp.push_back(L'\\');
105 }
106
107 {
108 auto path(new_tmp + L"锦绣成都\\");
109 _wmkdir(path.c_str());
110 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
111
112 TemporaryFile tf;
113 ASSERT_NE(tf.fd, -1) << tf.path;
114 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
115
116 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
117
118 std::string s;
119 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
120 EXPECT_EQ("abc", s);
121 }
122 {
123 auto path(new_tmp + L"директория с длинным именем\\");
124 _wmkdir(path.c_str());
125 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
126
127 TemporaryFile tf;
128 ASSERT_NE(tf.fd, -1) << tf.path;
129 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
130
131 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
132
133 std::string s;
134 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
135 EXPECT_EQ("abc", s);
136 }
137 {
138 auto path(new_tmp + L"äüöß weiß\\");
139 _wmkdir(path.c_str());
140 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
141
142 TemporaryFile tf;
143 ASSERT_NE(tf.fd, -1) << tf.path;
144 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
145
146 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
147
148 std::string s;
149 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
150 EXPECT_EQ("abc", s);
151 }
152
153 SetEnvironmentVariableW(L"TMP", old_tmp.c_str());
154}
155
156TEST(file, RootDirectoryWindows) {
157 constexpr auto kMaxEnvVariableValueSize = 32767;
158 std::wstring old_tmp;
159 old_tmp.resize(kMaxEnvVariableValueSize);
160 old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
161 SetEnvironmentVariableW(L"TMP", L"C:");
162
163 TemporaryFile tf;
164 ASSERT_NE(tf.fd, -1) << tf.path;
165
166 SetEnvironmentVariableW(L"TMP", old_tmp.c_str());
167}
168#endif
169
Elliott Hughesf682b472015-02-06 12:19:48 -0800170TEST(file, WriteStringToFd) {
171 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700172 ASSERT_NE(tf.fd, -1) << tf.path;
Dan Albertc007bc32015-03-16 10:08:46 -0700173 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
Elliott Hughesf682b472015-02-06 12:19:48 -0800174
Dan Albert850188f2015-04-29 17:09:53 -0700175 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
Elliott Hughesf682b472015-02-06 12:19:48 -0800176
177 std::string s;
Dan Albert850188f2015-04-29 17:09:53 -0700178 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
Elliott Hughesf682b472015-02-06 12:19:48 -0800179 EXPECT_EQ("abc", s);
180}
Elliott Hughes56085ed2015-04-24 21:57:16 -0700181
Elliott Hughes56085ed2015-04-24 21:57:16 -0700182TEST(file, WriteFully) {
183 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700184 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughes56085ed2015-04-24 21:57:16 -0700185 ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
Spencer Lowcbf26b72015-08-03 20:43:24 -0700186
187 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
188
Elliott Hughes56085ed2015-04-24 21:57:16 -0700189 std::string s;
Spencer Lowcbf26b72015-08-03 20:43:24 -0700190 s.resize(3);
191 ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
Dan Albert850188f2015-04-29 17:09:53 -0700192 << strerror(errno);
Elliott Hughes56085ed2015-04-24 21:57:16 -0700193 EXPECT_EQ("abc", s);
Spencer Lowcbf26b72015-08-03 20:43:24 -0700194
195 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
196
197 s.resize(1024);
198 ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
Elliott Hughes56085ed2015-04-24 21:57:16 -0700199}
Yabin Cuib6e314a2016-01-29 17:25:54 -0800200
liwugangc63cb072018-07-11 13:24:49 +0800201TEST(file, RemoveFileIfExists) {
Yabin Cuib6e314a2016-01-29 17:25:54 -0800202 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700203 ASSERT_NE(tf.fd, -1) << tf.path;
Yabin Cuib6e314a2016-01-29 17:25:54 -0800204 close(tf.fd);
205 tf.fd = -1;
206 std::string err;
207 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
208 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
209 TemporaryDir td;
210 ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
211 ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
liwugangc63cb072018-07-11 13:24:49 +0800212 ASSERT_EQ("is not a regular file or symbolic link", err);
Yabin Cuib6e314a2016-01-29 17:25:54 -0800213}
Elliott Hughesd3ff6e52016-08-23 15:53:45 -0700214
liwugangc63cb072018-07-11 13:24:49 +0800215TEST(file, RemoveFileIfExists_ENOTDIR) {
216 TemporaryFile tf;
217 close(tf.fd);
218 tf.fd = -1;
219 std::string err{"xxx"};
220 ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
221 ASSERT_EQ("xxx", err);
222}
223
224#if !defined(_WIN32)
225TEST(file, RemoveFileIfExists_EACCES) {
226 // EACCES -- one of the directories in the path has no search permission
227 // root can bypass permission restrictions, so drop root.
228 if (getuid() == 0) {
229 passwd* shell = getpwnam("shell");
230 setgid(shell->pw_gid);
231 setuid(shell->pw_uid);
232 }
233
234 TemporaryDir td;
235 TemporaryFile tf(td.path);
236 close(tf.fd);
237 tf.fd = -1;
238 std::string err{"xxx"};
239 // Remove dir's search permission.
240 ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
241 ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
242 ASSERT_EQ("Permission denied", err);
243 // Set dir's search permission again.
244 ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
245 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
246}
247#endif
248
Elliott Hughesd3ff6e52016-08-23 15:53:45 -0700249TEST(file, Readlink) {
250#if !defined(_WIN32)
251 // Linux doesn't allow empty symbolic links.
252 std::string min("x");
253 // ext2 and ext4 both have PAGE_SIZE limits.
Elliott Hughesa6c65702017-01-11 17:34:40 -0800254 // If file encryption is enabled, there's extra overhead to store the
255 // size of the encrypted symlink target. There's also an off-by-one
256 // in current kernels (and marlin/sailfish where we're seeing this
257 // failure are still on 3.18, far from current). http://b/33306057.
258 std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
Elliott Hughesd3ff6e52016-08-23 15:53:45 -0700259
260 TemporaryDir td;
261 std::string min_path{std::string(td.path) + "/" + "min"};
262 std::string max_path{std::string(td.path) + "/" + "max"};
263
264 ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
265 ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
266
267 std::string result;
268
269 result = "wrong";
270 ASSERT_TRUE(android::base::Readlink(min_path, &result));
271 ASSERT_EQ(min, result);
272
273 result = "wrong";
274 ASSERT_TRUE(android::base::Readlink(max_path, &result));
275 ASSERT_EQ(max, result);
276#endif
277}
Elliott Hughes82ff3152016-08-31 15:07:18 -0700278
Dimitry Ivanov840b6012016-09-09 10:49:21 -0700279TEST(file, Realpath) {
280#if !defined(_WIN32)
281 TemporaryDir td;
282 std::string basename = android::base::Basename(td.path);
283 std::string dir_name = android::base::Dirname(td.path);
284 std::string base_dir_name = android::base::Basename(dir_name);
285
286 {
287 std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
288 std::string result;
289 ASSERT_TRUE(android::base::Realpath(path, &result));
290 ASSERT_EQ(td.path, result);
291 }
292
293 {
294 std::string path = std::string(td.path) + "/..";
295 std::string result;
296 ASSERT_TRUE(android::base::Realpath(path, &result));
297 ASSERT_EQ(dir_name, result);
298 }
299
300 {
301 errno = 0;
302 std::string path = std::string(td.path) + "/foo.noent";
303 std::string result = "wrong";
304 ASSERT_TRUE(!android::base::Realpath(path, &result));
305 ASSERT_TRUE(result.empty());
306 ASSERT_EQ(ENOENT, errno);
307 }
308#endif
309}
310
Colin Crossbb3a5152017-02-23 17:41:56 -0800311TEST(file, GetExecutableDirectory) {
312 std::string path = android::base::GetExecutableDirectory();
313 ASSERT_NE("", path);
314 ASSERT_NE(android::base::GetExecutablePath(), path);
315 ASSERT_EQ('/', path[0]);
316 ASSERT_NE('/', path[path.size() - 1]);
317}
318
Elliott Hughes82ff3152016-08-31 15:07:18 -0700319TEST(file, GetExecutablePath) {
320 ASSERT_NE("", android::base::GetExecutablePath());
321}
Colin Cross58021d12017-02-23 21:23:05 -0800322
323TEST(file, Basename) {
324 EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
325 EXPECT_EQ("sh", android::base::Basename("sh"));
326 EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
327}
328
329TEST(file, Dirname) {
330 EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
331 EXPECT_EQ(".", android::base::Dirname("sh"));
332 EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
333}
Elliott Hughes9bb79712017-03-20 19:16:18 -0700334
335TEST(file, ReadFileToString_capacity) {
336 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700337 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughes9bb79712017-03-20 19:16:18 -0700338
339 // For a huge file, the overhead should still be small.
340 std::string s;
341 size_t size = 16 * 1024 * 1024;
342 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
343 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
344 EXPECT_EQ(size, s.size());
345 EXPECT_LT(s.capacity(), size + 16);
346
347 // Even for weird badly-aligned sizes.
348 size += 12345;
349 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
350 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
351 EXPECT_EQ(size, s.size());
352 EXPECT_LT(s.capacity(), size + 16);
353
354 // We'll shrink an enormous string if you read a small file into it.
355 size = 64;
356 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
357 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
358 EXPECT_EQ(size, s.size());
359 EXPECT_LT(s.capacity(), size + 16);
360}
361
362TEST(file, ReadFileToString_capacity_0) {
363 TemporaryFile tf;
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700364 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughes9bb79712017-03-20 19:16:18 -0700365
366 // Because /proc reports its files as zero-length, we don't actually trust
367 // any file that claims to be zero-length. Rather than add increasingly
368 // complex heuristics for shrinking the passed-in string in that case, we
369 // currently leave it alone.
370 std::string s;
371 size_t initial_capacity = s.capacity();
372 ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
373 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
374 EXPECT_EQ(0U, s.size());
375 EXPECT_EQ(initial_capacity, s.capacity());
376}