• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 <errno.h>
20 #include <fcntl.h>
21 #include <ftw.h>
22 #include <libgen.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 
30 #include <memory>
31 #include <mutex>
32 #include <string>
33 #include <vector>
34 
35 #if defined(__APPLE__)
36 #include <mach-o/dyld.h>
37 #endif
38 #if defined(_WIN32)
39 #include <direct.h>
40 #include <windows.h>
41 #define O_NOFOLLOW 0
42 #define OS_PATH_SEPARATOR '\\'
43 #else
44 #define OS_PATH_SEPARATOR '/'
45 #endif
46 
47 #include "android-base/logging.h"  // and must be after windows.h for ERROR
48 #include "android-base/macros.h"   // For TEMP_FAILURE_RETRY on Darwin.
49 #include "android-base/unique_fd.h"
50 #include "android-base/utf8.h"
51 
52 #ifdef _WIN32
mkstemp(char * template_name)53 int mkstemp(char* template_name) {
54   if (_mktemp(template_name) == nullptr) {
55     return -1;
56   }
57   // Use open() to match the close() that TemporaryFile's destructor does.
58   // Use O_BINARY to match base file APIs.
59   return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
60 }
61 
mkdtemp(char * template_name)62 char* mkdtemp(char* template_name) {
63   if (_mktemp(template_name) == nullptr) {
64     return nullptr;
65   }
66   if (_mkdir(template_name) == -1) {
67     return nullptr;
68   }
69   return template_name;
70 }
71 #endif
72 
73 namespace {
74 
GetSystemTempDir()75 std::string GetSystemTempDir() {
76 #if defined(__ANDROID__)
77   const auto* tmpdir = getenv("TMPDIR");
78   if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
79   if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
80     return tmpdir;
81   }
82   // Tests running in app context can't access /data/local/tmp,
83   // so try current directory if /data/local/tmp is not accessible.
84   return ".";
85 #elif defined(_WIN32)
86   char tmp_dir[MAX_PATH];
87   DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);  // checks TMP env
88   CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
89   CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
90 
91   // GetTempPath() returns a path with a trailing slash, but init()
92   // does not expect that, so remove it.
93   CHECK_EQ(tmp_dir[result - 1], '\\');
94   tmp_dir[result - 1] = '\0';
95   return tmp_dir;
96 #else
97   const auto* tmpdir = getenv("TMPDIR");
98   if (tmpdir == nullptr) tmpdir = "/tmp";
99   return tmpdir;
100 #endif
101 }
102 
103 }  // namespace
104 
TemporaryFile()105 TemporaryFile::TemporaryFile() {
106   init(GetSystemTempDir());
107 }
108 
TemporaryFile(const std::string & tmp_dir)109 TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
110   init(tmp_dir);
111 }
112 
~TemporaryFile()113 TemporaryFile::~TemporaryFile() {
114   if (fd != -1) {
115     close(fd);
116   }
117   if (remove_file_) {
118     unlink(path);
119   }
120 }
121 
release()122 int TemporaryFile::release() {
123   int result = fd;
124   fd = -1;
125   return result;
126 }
127 
init(const std::string & tmp_dir)128 void TemporaryFile::init(const std::string& tmp_dir) {
129   snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
130   fd = mkstemp(path);
131 }
132 
TemporaryDir()133 TemporaryDir::TemporaryDir() {
134   init(GetSystemTempDir());
135 }
136 
~TemporaryDir()137 TemporaryDir::~TemporaryDir() {
138   if (!remove_dir_and_contents_) return;
139 
140   auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
141     switch (file_type) {
142       case FTW_D:
143       case FTW_DP:
144       case FTW_DNR:
145         if (rmdir(child) == -1) {
146           PLOG(ERROR) << "rmdir " << child;
147         }
148         break;
149       case FTW_NS:
150       default:
151         if (rmdir(child) != -1) break;
152         // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
153         FALLTHROUGH_INTENDED;
154       case FTW_F:
155       case FTW_SL:
156       case FTW_SLN:
157         if (unlink(child) == -1) {
158           PLOG(ERROR) << "unlink " << child;
159         }
160         break;
161     }
162     return 0;
163   };
164 
165   nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
166 }
167 
init(const std::string & tmp_dir)168 bool TemporaryDir::init(const std::string& tmp_dir) {
169   snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
170   return (mkdtemp(path) != nullptr);
171 }
172 
173 namespace android {
174 namespace base {
175 
176 // Versions of standard library APIs that support UTF-8 strings.
177 using namespace android::base::utf8;
178 
ReadFdToString(int fd,std::string * content)179 bool ReadFdToString(int fd, std::string* content) {
180   content->clear();
181 
182   // Although original we had small files in mind, this code gets used for
183   // very large files too, where the std::string growth heuristics might not
184   // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
185   struct stat sb;
186   if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
187     content->reserve(sb.st_size);
188   }
189 
190   char buf[BUFSIZ];
191   ssize_t n;
192   while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
193     content->append(buf, n);
194   }
195   return (n == 0) ? true : false;
196 }
197 
ReadFileToString(const std::string & path,std::string * content,bool follow_symlinks)198 bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
199   content->clear();
200 
201   int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
202   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
203   if (fd == -1) {
204     return false;
205   }
206   return ReadFdToString(fd, content);
207 }
208 
WriteStringToFd(const std::string & content,int fd)209 bool WriteStringToFd(const std::string& content, int fd) {
210   const char* p = content.data();
211   size_t left = content.size();
212   while (left > 0) {
213     ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
214     if (n == -1) {
215       return false;
216     }
217     p += n;
218     left -= n;
219   }
220   return true;
221 }
222 
CleanUpAfterFailedWrite(const std::string & path)223 static bool CleanUpAfterFailedWrite(const std::string& path) {
224   // Something went wrong. Let's not leave a corrupt file lying around.
225   int saved_errno = errno;
226   unlink(path.c_str());
227   errno = saved_errno;
228   return false;
229 }
230 
231 #if !defined(_WIN32)
WriteStringToFile(const std::string & content,const std::string & path,mode_t mode,uid_t owner,gid_t group,bool follow_symlinks)232 bool WriteStringToFile(const std::string& content, const std::string& path,
233                        mode_t mode, uid_t owner, gid_t group,
234                        bool follow_symlinks) {
235   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
236               (follow_symlinks ? 0 : O_NOFOLLOW);
237   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
238   if (fd == -1) {
239     PLOG(ERROR) << "android::WriteStringToFile open failed";
240     return false;
241   }
242 
243   // We do an explicit fchmod here because we assume that the caller really
244   // meant what they said and doesn't want the umask-influenced mode.
245   if (fchmod(fd, mode) == -1) {
246     PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
247     return CleanUpAfterFailedWrite(path);
248   }
249   if (fchown(fd, owner, group) == -1) {
250     PLOG(ERROR) << "android::WriteStringToFile fchown failed";
251     return CleanUpAfterFailedWrite(path);
252   }
253   if (!WriteStringToFd(content, fd)) {
254     PLOG(ERROR) << "android::WriteStringToFile write failed";
255     return CleanUpAfterFailedWrite(path);
256   }
257   return true;
258 }
259 #endif
260 
WriteStringToFile(const std::string & content,const std::string & path,bool follow_symlinks)261 bool WriteStringToFile(const std::string& content, const std::string& path,
262                        bool follow_symlinks) {
263   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
264               (follow_symlinks ? 0 : O_NOFOLLOW);
265   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0666)));
266   if (fd == -1) {
267     return false;
268   }
269   return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path);
270 }
271 
ReadFully(int fd,void * data,size_t byte_count)272 bool ReadFully(int fd, void* data, size_t byte_count) {
273   uint8_t* p = reinterpret_cast<uint8_t*>(data);
274   size_t remaining = byte_count;
275   while (remaining > 0) {
276     ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
277     if (n <= 0) return false;
278     p += n;
279     remaining -= n;
280   }
281   return true;
282 }
283 
284 #if defined(_WIN32)
285 // Windows implementation of pread. Note that this DOES move the file descriptors read position,
286 // but it does so atomically.
pread(int fd,void * data,size_t byte_count,off64_t offset)287 static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
288   DWORD bytes_read;
289   OVERLAPPED overlapped;
290   memset(&overlapped, 0, sizeof(OVERLAPPED));
291   overlapped.Offset = static_cast<DWORD>(offset);
292   overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
293   if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count),
294                 &bytes_read, &overlapped)) {
295     // In case someone tries to read errno (since this is masquerading as a POSIX call)
296     errno = EIO;
297     return -1;
298   }
299   return static_cast<ssize_t>(bytes_read);
300 }
301 #endif
302 
ReadFullyAtOffset(int fd,void * data,size_t byte_count,off64_t offset)303 bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
304   uint8_t* p = reinterpret_cast<uint8_t*>(data);
305   while (byte_count > 0) {
306     ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset));
307     if (n <= 0) return false;
308     p += n;
309     byte_count -= n;
310     offset += n;
311   }
312   return true;
313 }
314 
WriteFully(int fd,const void * data,size_t byte_count)315 bool WriteFully(int fd, const void* data, size_t byte_count) {
316   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
317   size_t remaining = byte_count;
318   while (remaining > 0) {
319     ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
320     if (n == -1) return false;
321     p += n;
322     remaining -= n;
323   }
324   return true;
325 }
326 
RemoveFileIfExists(const std::string & path,std::string * err)327 bool RemoveFileIfExists(const std::string& path, std::string* err) {
328   struct stat st;
329 #if defined(_WIN32)
330   // TODO: Windows version can't handle symbolic links correctly.
331   int result = stat(path.c_str(), &st);
332   bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
333 #else
334   int result = lstat(path.c_str(), &st);
335   bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
336 #endif
337   if (result == -1) {
338     if (errno == ENOENT || errno == ENOTDIR) return true;
339     if (err != nullptr) *err = strerror(errno);
340     return false;
341   }
342 
343   if (result == 0) {
344     if (!file_type_removable) {
345       if (err != nullptr) {
346         *err = "is not a regular file or symbolic link";
347       }
348       return false;
349     }
350     if (unlink(path.c_str()) == -1) {
351       if (err != nullptr) {
352         *err = strerror(errno);
353       }
354       return false;
355     }
356   }
357   return true;
358 }
359 
360 #if !defined(_WIN32)
Readlink(const std::string & path,std::string * result)361 bool Readlink(const std::string& path, std::string* result) {
362   result->clear();
363 
364   // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
365   // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
366   // waste memory to just start there. We add 1 so that we can recognize
367   // whether it actually fit (rather than being truncated to 4095).
368   std::vector<char> buf(4095 + 1);
369   while (true) {
370     ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
371     // Unrecoverable error?
372     if (size == -1) return false;
373     // It fit! (If size == buf.size(), it may have been truncated.)
374     if (static_cast<size_t>(size) < buf.size()) {
375       result->assign(&buf[0], size);
376       return true;
377     }
378     // Double our buffer and try again.
379     buf.resize(buf.size() * 2);
380   }
381 }
382 #endif
383 
384 #if !defined(_WIN32)
Realpath(const std::string & path,std::string * result)385 bool Realpath(const std::string& path, std::string* result) {
386   result->clear();
387 
388   // realpath may exit with EINTR. Retry if so.
389   char* realpath_buf = nullptr;
390   do {
391     realpath_buf = realpath(path.c_str(), nullptr);
392   } while (realpath_buf == nullptr && errno == EINTR);
393 
394   if (realpath_buf == nullptr) {
395     return false;
396   }
397   result->assign(realpath_buf);
398   free(realpath_buf);
399   return true;
400 }
401 #endif
402 
GetExecutablePath()403 std::string GetExecutablePath() {
404 #if defined(__linux__)
405   std::string path;
406   android::base::Readlink("/proc/self/exe", &path);
407   return path;
408 #elif defined(__APPLE__)
409   char path[PATH_MAX + 1];
410   uint32_t path_len = sizeof(path);
411   int rc = _NSGetExecutablePath(path, &path_len);
412   if (rc < 0) {
413     std::unique_ptr<char> path_buf(new char[path_len]);
414     _NSGetExecutablePath(path_buf.get(), &path_len);
415     return path_buf.get();
416   }
417   return path;
418 #elif defined(_WIN32)
419   char path[PATH_MAX + 1];
420   DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
421   if (result == 0 || result == sizeof(path) - 1) return "";
422   path[PATH_MAX - 1] = 0;
423   return path;
424 #else
425 #error unknown OS
426 #endif
427 }
428 
GetExecutableDirectory()429 std::string GetExecutableDirectory() {
430   return Dirname(GetExecutablePath());
431 }
432 
Basename(const std::string & path)433 std::string Basename(const std::string& path) {
434   // Copy path because basename may modify the string passed in.
435   std::string result(path);
436 
437 #if !defined(__BIONIC__)
438   // Use lock because basename() may write to a process global and return a
439   // pointer to that. Note that this locking strategy only works if all other
440   // callers to basename in the process also grab this same lock, but its
441   // better than nothing.  Bionic's basename returns a thread-local buffer.
442   static std::mutex& basename_lock = *new std::mutex();
443   std::lock_guard<std::mutex> lock(basename_lock);
444 #endif
445 
446   // Note that if std::string uses copy-on-write strings, &str[0] will cause
447   // the copy to be made, so there is no chance of us accidentally writing to
448   // the storage for 'path'.
449   char* name = basename(&result[0]);
450 
451   // In case basename returned a pointer to a process global, copy that string
452   // before leaving the lock.
453   result.assign(name);
454 
455   return result;
456 }
457 
Dirname(const std::string & path)458 std::string Dirname(const std::string& path) {
459   // Copy path because dirname may modify the string passed in.
460   std::string result(path);
461 
462 #if !defined(__BIONIC__)
463   // Use lock because dirname() may write to a process global and return a
464   // pointer to that. Note that this locking strategy only works if all other
465   // callers to dirname in the process also grab this same lock, but its
466   // better than nothing.  Bionic's dirname returns a thread-local buffer.
467   static std::mutex& dirname_lock = *new std::mutex();
468   std::lock_guard<std::mutex> lock(dirname_lock);
469 #endif
470 
471   // Note that if std::string uses copy-on-write strings, &str[0] will cause
472   // the copy to be made, so there is no chance of us accidentally writing to
473   // the storage for 'path'.
474   char* parent = dirname(&result[0]);
475 
476   // In case dirname returned a pointer to a process global, copy that string
477   // before leaving the lock.
478   result.assign(parent);
479 
480   return result;
481 }
482 
483 }  // namespace base
484 }  // namespace android
485