blob: 120228d947973412837020a51d0793752cbdf6f7 [file] [log] [blame]
Dan Albertaac6b7c2015-03-16 10:08:46 -07001/*
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 Hughesb6351622015-12-04 22:00:26 -080017#include "android-base/file.h"
Dan Albertaac6b7c2015-03-16 10:08:46 -070018
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070019#include "android-base/utf8.h"
20
Dan Albertaac6b7c2015-03-16 10:08:46 -070021#include <gtest/gtest.h>
22
23#include <errno.h>
24#include <fcntl.h>
25#include <unistd.h>
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070026#include <wchar.h>
Dan Albertaac6b7c2015-03-16 10:08:46 -070027
28#include <string>
29
liwugang78cea682018-07-11 13:24:49 +080030#if !defined(_WIN32)
31#include <pwd.h>
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070032#else
Alex Buynytskyy19ba0882019-10-02 16:27:22 -070033#include <windows.h>
liwugang78cea682018-07-11 13:24:49 +080034#endif
35
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070036#include "android-base/logging.h" // and must be after windows.h for ERROR
37
Dan Albertaac6b7c2015-03-16 10:08:46 -070038TEST(file, ReadFileToString_ENOENT) {
39 std::string s("hello");
40 errno = 0;
41 ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
42 EXPECT_EQ(ENOENT, errno);
43 EXPECT_EQ("", s); // s was cleared.
44}
45
Spencer Low482fa6d2015-05-24 15:36:28 -070046TEST(file, ReadFileToString_WriteStringToFile) {
Dan Albertaac6b7c2015-03-16 10:08:46 -070047 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070048 ASSERT_NE(tf.fd, -1) << tf.path;
Alex Valléed0ac74c2015-05-06 16:26:00 -040049 ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
Dan Albert1a932622015-04-29 17:09:53 -070050 << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -070051 std::string s;
Alex Valléed0ac74c2015-05-06 16:26:00 -040052 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
Dan Albert1a932622015-04-29 17:09:53 -070053 << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -070054 EXPECT_EQ("abc", s);
55}
56
Josh Gao8e1f0d82016-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 Albert26cb8ff2015-04-29 11:32:23 -070075// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
76// sense on Windows.
77#if !defined(_WIN32)
Dan Albertaac6b7c2015-03-16 10:08:46 -070078TEST(file, WriteStringToFile2) {
79 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -070080 ASSERT_NE(tf.fd, -1) << tf.path;
Alex Valléed0ac74c2015-05-06 16:26:00 -040081 ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
Dan Albertaac6b7c2015-03-16 10:08:46 -070082 getuid(), getgid()))
Dan Albert1a932622015-04-29 17:09:53 -070083 << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -070084 struct stat sb;
Alex Valléed0ac74c2015-05-06 16:26:00 -040085 ASSERT_EQ(0, stat(tf.path, &sb));
Colin Crosseebcd142015-04-30 15:12:21 -070086 ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
Dan Albertaac6b7c2015-03-16 10:08:46 -070087 ASSERT_EQ(getuid(), sb.st_uid);
88 ASSERT_EQ(getgid(), sb.st_gid);
89 std::string s;
Alex Valléed0ac74c2015-05-06 16:26:00 -040090 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
Dan Albert1a932622015-04-29 17:09:53 -070091 << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -070092 EXPECT_EQ("abc", s);
93}
Dan Albert26cb8ff2015-04-29 11:32:23 -070094#endif
Dan Albertaac6b7c2015-03-16 10:08:46 -070095
Alex Buynytskyyab0407f2019-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()));
Alex Buynytskyy19ba0882019-10-02 16:27:22 -0700102 if (old_tmp.empty()) {
103 // Can't continue with empty TMP folder.
104 return;
105 }
106
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700107 std::wstring new_tmp = old_tmp;
108 if (new_tmp.back() != L'\\') {
109 new_tmp.push_back(L'\\');
110 }
111
112 {
113 auto path(new_tmp + L"锦绣成都\\");
114 _wmkdir(path.c_str());
115 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
116
117 TemporaryFile tf;
118 ASSERT_NE(tf.fd, -1) << tf.path;
119 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
120
121 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
122
123 std::string s;
124 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
125 EXPECT_EQ("abc", s);
126 }
127 {
128 auto path(new_tmp + L"директория с длинным именем\\");
129 _wmkdir(path.c_str());
130 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
131
132 TemporaryFile tf;
133 ASSERT_NE(tf.fd, -1) << tf.path;
134 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
135
136 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
137
138 std::string s;
139 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
140 EXPECT_EQ("abc", s);
141 }
142 {
143 auto path(new_tmp + L"äüöß weiß\\");
144 _wmkdir(path.c_str());
145 ASSERT_TRUE(SetEnvironmentVariableW(L"TMP", path.c_str()));
146
147 TemporaryFile tf;
148 ASSERT_NE(tf.fd, -1) << tf.path;
149 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
150
151 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
152
153 std::string s;
154 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
155 EXPECT_EQ("abc", s);
156 }
157
158 SetEnvironmentVariableW(L"TMP", old_tmp.c_str());
159}
160
161TEST(file, RootDirectoryWindows) {
162 constexpr auto kMaxEnvVariableValueSize = 32767;
163 std::wstring old_tmp;
Alex Buynytskyy19ba0882019-10-02 16:27:22 -0700164 bool tmp_is_empty = false;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700165 old_tmp.resize(kMaxEnvVariableValueSize);
166 old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
Alex Buynytskyy19ba0882019-10-02 16:27:22 -0700167 if (old_tmp.empty()) {
168 tmp_is_empty = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
169 }
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700170 SetEnvironmentVariableW(L"TMP", L"C:");
171
172 TemporaryFile tf;
173 ASSERT_NE(tf.fd, -1) << tf.path;
174
Alex Buynytskyy19ba0882019-10-02 16:27:22 -0700175 SetEnvironmentVariableW(L"TMP", tmp_is_empty ? nullptr : old_tmp.c_str());
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700176}
177#endif
178
Dan Albertaac6b7c2015-03-16 10:08:46 -0700179TEST(file, WriteStringToFd) {
180 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700181 ASSERT_NE(tf.fd, -1) << tf.path;
Dan Albertaac6b7c2015-03-16 10:08:46 -0700182 ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
183
Dan Albert1a932622015-04-29 17:09:53 -0700184 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -0700185
186 std::string s;
Dan Albert1a932622015-04-29 17:09:53 -0700187 ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
Dan Albertaac6b7c2015-03-16 10:08:46 -0700188 EXPECT_EQ("abc", s);
189}
Elliott Hughes20abc872015-04-24 21:57:16 -0700190
Elliott Hughes20abc872015-04-24 21:57:16 -0700191TEST(file, WriteFully) {
192 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700193 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughes20abc872015-04-24 21:57:16 -0700194 ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
Spencer Low38d002e2015-08-03 20:43:24 -0700195
196 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
197
Elliott Hughes20abc872015-04-24 21:57:16 -0700198 std::string s;
Spencer Low38d002e2015-08-03 20:43:24 -0700199 s.resize(3);
200 ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
Dan Albert1a932622015-04-29 17:09:53 -0700201 << strerror(errno);
Elliott Hughes20abc872015-04-24 21:57:16 -0700202 EXPECT_EQ("abc", s);
Spencer Low38d002e2015-08-03 20:43:24 -0700203
204 ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
205
206 s.resize(1024);
207 ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
Elliott Hughes20abc872015-04-24 21:57:16 -0700208}
Yabin Cui8f6a5a02016-01-29 17:25:54 -0800209
liwugang78cea682018-07-11 13:24:49 +0800210TEST(file, RemoveFileIfExists) {
Yabin Cui8f6a5a02016-01-29 17:25:54 -0800211 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700212 ASSERT_NE(tf.fd, -1) << tf.path;
Yabin Cui8f6a5a02016-01-29 17:25:54 -0800213 close(tf.fd);
214 tf.fd = -1;
215 std::string err;
216 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
217 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
218 TemporaryDir td;
219 ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
220 ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
liwugang78cea682018-07-11 13:24:49 +0800221 ASSERT_EQ("is not a regular file or symbolic link", err);
Yabin Cui8f6a5a02016-01-29 17:25:54 -0800222}
Elliott Hughesa634a9a2016-08-23 15:53:45 -0700223
liwugang78cea682018-07-11 13:24:49 +0800224TEST(file, RemoveFileIfExists_ENOTDIR) {
225 TemporaryFile tf;
226 close(tf.fd);
227 tf.fd = -1;
228 std::string err{"xxx"};
229 ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
230 ASSERT_EQ("xxx", err);
231}
232
233#if !defined(_WIN32)
234TEST(file, RemoveFileIfExists_EACCES) {
235 // EACCES -- one of the directories in the path has no search permission
236 // root can bypass permission restrictions, so drop root.
237 if (getuid() == 0) {
238 passwd* shell = getpwnam("shell");
239 setgid(shell->pw_gid);
240 setuid(shell->pw_uid);
241 }
242
243 TemporaryDir td;
244 TemporaryFile tf(td.path);
245 close(tf.fd);
246 tf.fd = -1;
247 std::string err{"xxx"};
248 // Remove dir's search permission.
249 ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
250 ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
251 ASSERT_EQ("Permission denied", err);
252 // Set dir's search permission again.
253 ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
254 ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
255}
256#endif
257
Elliott Hughesa634a9a2016-08-23 15:53:45 -0700258TEST(file, Readlink) {
259#if !defined(_WIN32)
260 // Linux doesn't allow empty symbolic links.
261 std::string min("x");
262 // ext2 and ext4 both have PAGE_SIZE limits.
Elliott Hughes7c2a67d2017-01-11 17:34:40 -0800263 // If file encryption is enabled, there's extra overhead to store the
264 // size of the encrypted symlink target. There's also an off-by-one
265 // in current kernels (and marlin/sailfish where we're seeing this
266 // failure are still on 3.18, far from current). http://b/33306057.
267 std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
Elliott Hughesa634a9a2016-08-23 15:53:45 -0700268
269 TemporaryDir td;
270 std::string min_path{std::string(td.path) + "/" + "min"};
271 std::string max_path{std::string(td.path) + "/" + "max"};
272
273 ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
274 ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
275
276 std::string result;
277
278 result = "wrong";
279 ASSERT_TRUE(android::base::Readlink(min_path, &result));
280 ASSERT_EQ(min, result);
281
282 result = "wrong";
283 ASSERT_TRUE(android::base::Readlink(max_path, &result));
284 ASSERT_EQ(max, result);
285#endif
286}
Elliott Hughes48f0eb52016-08-31 15:07:18 -0700287
Dimitry Ivanov4edc04f2016-09-09 10:49:21 -0700288TEST(file, Realpath) {
289#if !defined(_WIN32)
290 TemporaryDir td;
291 std::string basename = android::base::Basename(td.path);
292 std::string dir_name = android::base::Dirname(td.path);
293 std::string base_dir_name = android::base::Basename(dir_name);
294
295 {
296 std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
297 std::string result;
298 ASSERT_TRUE(android::base::Realpath(path, &result));
299 ASSERT_EQ(td.path, result);
300 }
301
302 {
303 std::string path = std::string(td.path) + "/..";
304 std::string result;
305 ASSERT_TRUE(android::base::Realpath(path, &result));
306 ASSERT_EQ(dir_name, result);
307 }
308
309 {
310 errno = 0;
311 std::string path = std::string(td.path) + "/foo.noent";
312 std::string result = "wrong";
313 ASSERT_TRUE(!android::base::Realpath(path, &result));
314 ASSERT_TRUE(result.empty());
315 ASSERT_EQ(ENOENT, errno);
316 }
317#endif
318}
319
Colin Cross2909be02017-02-23 17:41:56 -0800320TEST(file, GetExecutableDirectory) {
321 std::string path = android::base::GetExecutableDirectory();
322 ASSERT_NE("", path);
323 ASSERT_NE(android::base::GetExecutablePath(), path);
324 ASSERT_EQ('/', path[0]);
325 ASSERT_NE('/', path[path.size() - 1]);
326}
327
Elliott Hughes48f0eb52016-08-31 15:07:18 -0700328TEST(file, GetExecutablePath) {
329 ASSERT_NE("", android::base::GetExecutablePath());
330}
Colin Cross2e732e22017-02-23 21:23:05 -0800331
332TEST(file, Basename) {
333 EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
334 EXPECT_EQ("sh", android::base::Basename("sh"));
335 EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
336}
337
338TEST(file, Dirname) {
339 EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
340 EXPECT_EQ(".", android::base::Dirname("sh"));
341 EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
342}
Elliott Hughese9ab7ad2017-03-20 19:16:18 -0700343
344TEST(file, ReadFileToString_capacity) {
345 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700346 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughese9ab7ad2017-03-20 19:16:18 -0700347
348 // For a huge file, the overhead should still be small.
349 std::string s;
350 size_t size = 16 * 1024 * 1024;
351 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
352 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
353 EXPECT_EQ(size, s.size());
354 EXPECT_LT(s.capacity(), size + 16);
355
356 // Even for weird badly-aligned sizes.
357 size += 12345;
358 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
359 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
360 EXPECT_EQ(size, s.size());
361 EXPECT_LT(s.capacity(), size + 16);
362
363 // We'll shrink an enormous string if you read a small file into it.
364 size = 64;
365 ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
366 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
367 EXPECT_EQ(size, s.size());
368 EXPECT_LT(s.capacity(), size + 16);
369}
370
371TEST(file, ReadFileToString_capacity_0) {
372 TemporaryFile tf;
Alex Buynytskyyab0407f2019-09-27 11:11:24 -0700373 ASSERT_NE(tf.fd, -1) << tf.path;
Elliott Hughese9ab7ad2017-03-20 19:16:18 -0700374
375 // Because /proc reports its files as zero-length, we don't actually trust
376 // any file that claims to be zero-length. Rather than add increasingly
377 // complex heuristics for shrinking the passed-in string in that case, we
378 // currently leave it alone.
379 std::string s;
380 size_t initial_capacity = s.capacity();
381 ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
382 ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
383 EXPECT_EQ(0U, s.size());
384 EXPECT_EQ(initial_capacity, s.capacity());
385}