• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "android-base/utf8.h"
20 
21 #include <gtest/gtest.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <wchar.h>
27 
28 #include <string>
29 
30 #if !defined(_WIN32)
31 #include <pwd.h>
32 #else
33 #include <windows.h>
34 #endif
35 
36 #include "android-base/logging.h"  // and must be after windows.h for ERROR
37 
TEST(file,ReadFileToString_ENOENT)38 TEST(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 
TEST(file,ReadFileToString_WriteStringToFile)46 TEST(file, ReadFileToString_WriteStringToFile) {
47   TemporaryFile tf;
48   ASSERT_NE(tf.fd, -1) << tf.path;
49   ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
50     << strerror(errno);
51   std::string s;
52   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
53     << strerror(errno);
54   EXPECT_EQ("abc", s);
55 }
56 
57 // symlinks require elevated privileges on Windows.
58 #if !defined(_WIN32)
TEST(file,ReadFileToString_WriteStringToFile_symlink)59 TEST(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 
75 // WriteStringToFile2 is explicitly for setting Unix permissions, which make no
76 // sense on Windows.
77 #if !defined(_WIN32)
TEST(file,WriteStringToFile2)78 TEST(file, WriteStringToFile2) {
79   TemporaryFile tf;
80   ASSERT_NE(tf.fd, -1) << tf.path;
81   ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
82                                                getuid(), getgid()))
83       << strerror(errno);
84   struct stat sb;
85   ASSERT_EQ(0, stat(tf.path, &sb));
86   ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
87   ASSERT_EQ(getuid(), sb.st_uid);
88   ASSERT_EQ(getgid(), sb.st_gid);
89   std::string s;
90   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
91     << strerror(errno);
92   EXPECT_EQ("abc", s);
93 }
94 #endif
95 
96 #if defined(_WIN32)
TEST(file,NonUnicodeCharsWindows)97 TEST(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   if (old_tmp.empty()) {
103     // Can't continue with empty TMP folder.
104     return;
105   }
106 
107   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 
TEST(file,RootDirectoryWindows)161 TEST(file, RootDirectoryWindows) {
162   constexpr auto kMaxEnvVariableValueSize = 32767;
163   std::wstring old_tmp;
164   bool tmp_is_empty = false;
165   old_tmp.resize(kMaxEnvVariableValueSize);
166   old_tmp.resize(GetEnvironmentVariableW(L"TMP", old_tmp.data(), old_tmp.size()));
167   if (old_tmp.empty()) {
168     tmp_is_empty = (GetLastError() == ERROR_ENVVAR_NOT_FOUND);
169   }
170   SetEnvironmentVariableW(L"TMP", L"C:");
171 
172   TemporaryFile tf;
173   ASSERT_NE(tf.fd, -1) << tf.path;
174 
175   SetEnvironmentVariableW(L"TMP", tmp_is_empty ? nullptr : old_tmp.c_str());
176 }
177 #endif
178 
TEST(file,WriteStringToFd_StringLiteral)179 TEST(file, WriteStringToFd_StringLiteral) {
180   TemporaryFile tf;
181   ASSERT_NE(tf.fd, -1) << tf.path;
182   ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
183 
184   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
185 
186   std::string s;
187   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
188   EXPECT_EQ("abc", s);
189 }
190 
TEST(file,WriteStringToFd_String)191 TEST(file, WriteStringToFd_String) {
192   std::string testStr = "def";
193   TemporaryFile tf;
194   ASSERT_NE(tf.fd, -1) << tf.path;
195   ASSERT_TRUE(android::base::WriteStringToFd(testStr, tf.fd));
196 
197   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
198 
199   std::string s;
200   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
201   EXPECT_EQ(testStr, s);
202 }
203 
TEST(file,WriteStringToFd_StringView)204 TEST(file, WriteStringToFd_StringView) {
205   std::string_view testStrView = "ghi";
206   TemporaryFile tf;
207   ASSERT_NE(tf.fd, -1) << tf.path;
208   ASSERT_TRUE(android::base::WriteStringToFd(testStrView, tf.fd));
209 
210   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
211 
212   std::string s;
213   ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
214   EXPECT_EQ(testStrView, s);
215 }
216 
TEST(file,WriteFully)217 TEST(file, WriteFully) {
218   TemporaryFile tf;
219   ASSERT_NE(tf.fd, -1) << tf.path;
220   ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
221 
222   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
223 
224   std::string s;
225   s.resize(3);
226   ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
227     << strerror(errno);
228   EXPECT_EQ("abc", s);
229 
230   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
231 
232   s.resize(1024);
233   ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
234 }
235 
TEST(file,RemoveFileIfExists)236 TEST(file, RemoveFileIfExists) {
237   TemporaryFile tf;
238   ASSERT_NE(tf.fd, -1) << tf.path;
239   close(tf.fd);
240   tf.fd = -1;
241   std::string err;
242   ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
243   ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
244   TemporaryDir td;
245   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
246   ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
247   ASSERT_EQ("is not a regular file or symbolic link", err);
248 }
249 
TEST(file,RemoveFileIfExists_ENOTDIR)250 TEST(file, RemoveFileIfExists_ENOTDIR) {
251   TemporaryFile tf;
252   close(tf.fd);
253   tf.fd = -1;
254   std::string err{"xxx"};
255   ASSERT_TRUE(android::base::RemoveFileIfExists(std::string{tf.path} + "/abc", &err));
256   ASSERT_EQ("xxx", err);
257 }
258 
259 #if !defined(_WIN32)
TEST(file,RemoveFileIfExists_EACCES)260 TEST(file, RemoveFileIfExists_EACCES) {
261   // EACCES -- one of the directories in the path has no search permission
262   // root can bypass permission restrictions, so drop root.
263   if (getuid() == 0) {
264     passwd* shell = getpwnam("shell");
265     setgid(shell->pw_gid);
266     setuid(shell->pw_uid);
267   }
268 
269   TemporaryDir td;
270   TemporaryFile tf(td.path);
271   close(tf.fd);
272   tf.fd = -1;
273   std::string err{"xxx"};
274   // Remove dir's search permission.
275   ASSERT_TRUE(chmod(td.path, S_IRUSR | S_IWUSR) == 0);
276   ASSERT_FALSE(android::base::RemoveFileIfExists(tf.path, &err));
277   ASSERT_EQ("Permission denied", err);
278   // Set dir's search permission again.
279   ASSERT_TRUE(chmod(td.path, S_IRWXU) == 0);
280   ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err));
281 }
282 #endif
283 
TEST(file,Readlink)284 TEST(file, Readlink) {
285 #if !defined(_WIN32)
286   // Linux doesn't allow empty symbolic links.
287   std::string min("x");
288   // ext2 and ext4 both have PAGE_SIZE limits.
289   // If file encryption is enabled, there's extra overhead to store the
290   // size of the encrypted symlink target. There's also an off-by-one
291   // in current kernels (and marlin/sailfish where we're seeing this
292   // failure are still on 3.18, far from current). http://b/33306057.
293   std::string max(static_cast<size_t>(4096 - 2 - 1 - 1), 'x');
294 
295   TemporaryDir td;
296   std::string min_path{std::string(td.path) + "/" + "min"};
297   std::string max_path{std::string(td.path) + "/" + "max"};
298 
299   ASSERT_EQ(0, symlink(min.c_str(), min_path.c_str()));
300   ASSERT_EQ(0, symlink(max.c_str(), max_path.c_str()));
301 
302   std::string result;
303 
304   result = "wrong";
305   ASSERT_TRUE(android::base::Readlink(min_path, &result));
306   ASSERT_EQ(min, result);
307 
308   result = "wrong";
309   ASSERT_TRUE(android::base::Readlink(max_path, &result));
310   ASSERT_EQ(max, result);
311 #endif
312 }
313 
TEST(file,Realpath)314 TEST(file, Realpath) {
315 #if !defined(_WIN32)
316   TemporaryDir td;
317   std::string basename = android::base::Basename(td.path);
318   std::string dir_name = android::base::Dirname(td.path);
319   std::string base_dir_name = android::base::Basename(dir_name);
320 
321   {
322     std::string path = dir_name + "/../" + base_dir_name + "/" + basename;
323     std::string result;
324     ASSERT_TRUE(android::base::Realpath(path, &result));
325     ASSERT_EQ(td.path, result);
326   }
327 
328   {
329     std::string path = std::string(td.path) + "/..";
330     std::string result;
331     ASSERT_TRUE(android::base::Realpath(path, &result));
332     ASSERT_EQ(dir_name, result);
333   }
334 
335   {
336     errno = 0;
337     std::string path = std::string(td.path) + "/foo.noent";
338     std::string result = "wrong";
339     ASSERT_TRUE(!android::base::Realpath(path, &result));
340     ASSERT_TRUE(result.empty());
341     ASSERT_EQ(ENOENT, errno);
342   }
343 #endif
344 }
345 
TEST(file,GetExecutableDirectory)346 TEST(file, GetExecutableDirectory) {
347   std::string path = android::base::GetExecutableDirectory();
348   ASSERT_NE("", path);
349   ASSERT_NE(android::base::GetExecutablePath(), path);
350   ASSERT_EQ('/', path[0]);
351   ASSERT_NE('/', path[path.size() - 1]);
352 }
353 
TEST(file,GetExecutablePath)354 TEST(file, GetExecutablePath) {
355   ASSERT_NE("", android::base::GetExecutablePath());
356 }
357 
TEST(file,Basename)358 TEST(file, Basename) {
359   EXPECT_EQ("sh", android::base::Basename("/system/bin/sh"));
360   EXPECT_EQ("sh", android::base::Basename("sh"));
361   EXPECT_EQ("sh", android::base::Basename("/system/bin/sh/"));
362 
363   // Since we've copy & pasted bionic's implementation, copy & paste the tests.
364   EXPECT_EQ(".",   android::base::Basename(""));
365   EXPECT_EQ("lib", android::base::Basename("/usr/lib"));
366   EXPECT_EQ("usr", android::base::Basename("/usr/"));
367   EXPECT_EQ("usr", android::base::Basename("usr"));
368   EXPECT_EQ("/",   android::base::Basename("/"));
369   EXPECT_EQ(".",   android::base::Basename("."));
370   EXPECT_EQ("..",  android::base::Basename(".."));
371   EXPECT_EQ("/",   android::base::Basename("///"));
372   EXPECT_EQ("lib", android::base::Basename("//usr//lib//"));
373 }
374 
TEST(file,Dirname)375 TEST(file, Dirname) {
376   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh"));
377   EXPECT_EQ(".", android::base::Dirname("sh"));
378   EXPECT_EQ("/system/bin", android::base::Dirname("/system/bin/sh/"));
379 
380   // Since we've copy & pasted bionic's implementation, copy & paste the tests.
381   EXPECT_EQ(".", android::base::Dirname(""));
382   EXPECT_EQ("/usr", android::base::Dirname("/usr/lib"));
383   EXPECT_EQ("/", android::base::Dirname("/usr/"));
384   EXPECT_EQ(".", android::base::Dirname("usr"));
385   EXPECT_EQ(".", android::base::Dirname("."));
386   EXPECT_EQ(".", android::base::Dirname(".."));
387   EXPECT_EQ("/", android::base::Dirname("/"));
388 }
389 
TEST(file,ReadFileToString_capacity)390 TEST(file, ReadFileToString_capacity) {
391   TemporaryFile tf;
392   ASSERT_NE(tf.fd, -1) << tf.path;
393 
394   // For a huge file, the overhead should still be small.
395   std::string s;
396   size_t size = 16 * 1024 * 1024;
397   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
398   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
399   EXPECT_EQ(size, s.size());
400   EXPECT_LT(s.capacity(), size + 16);
401 
402   // Even for weird badly-aligned sizes.
403   size += 12345;
404   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
405   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
406   EXPECT_EQ(size, s.size());
407   EXPECT_LT(s.capacity(), size + 16);
408 
409   // We'll shrink an enormous string if you read a small file into it.
410   size = 64;
411   ASSERT_TRUE(android::base::WriteStringToFile(std::string(size, 'x'), tf.path));
412   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
413   EXPECT_EQ(size, s.size());
414   EXPECT_LT(s.capacity(), size + 16);
415 }
416 
TEST(file,ReadFileToString_capacity_0)417 TEST(file, ReadFileToString_capacity_0) {
418   TemporaryFile tf;
419   ASSERT_NE(tf.fd, -1) << tf.path;
420 
421   // Because /proc reports its files as zero-length, we don't actually trust
422   // any file that claims to be zero-length. Rather than add increasingly
423   // complex heuristics for shrinking the passed-in string in that case, we
424   // currently leave it alone.
425   std::string s;
426   size_t initial_capacity = s.capacity();
427   ASSERT_TRUE(android::base::WriteStringToFile("", tf.path));
428   ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s));
429   EXPECT_EQ(0U, s.size());
430   EXPECT_EQ(initial_capacity, s.capacity());
431 }
432