blob: b1ddc5d4d2ba6a6e884c45679d956ec3e0dffdb6 [file] [log] [blame]
Elliott Hughesdec12b22015-02-02 17:31:27 -08001/*
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
Elliott Hughes4f713192015-12-04 22:00:26 -080017#include "android-base/file.h"
Elliott Hughesdec12b22015-02-02 17:31:27 -080018
19#include <errno.h>
20#include <fcntl.h>
Mark Salyzyn46c2df52018-11-13 13:38:33 -080021#include <ftw.h>
Colin Cross58021d12017-02-23 21:23:05 -080022#include <libgen.h>
Mark Salyzyn0790b242018-11-12 12:29:14 -080023#include <stdio.h>
24#include <stdlib.h>
Florian Mayer3f1f2e02018-10-23 15:56:28 +010025#include <string.h>
Elliott Hughesdec12b22015-02-02 17:31:27 -080026#include <sys/stat.h>
27#include <sys/types.h>
Elliott Hughesd3ff6e52016-08-23 15:53:45 -070028#include <unistd.h>
Elliott Hughesdec12b22015-02-02 17:31:27 -080029
Josh Gao7307f092016-09-01 12:31:42 -070030#include <memory>
Colin Cross58021d12017-02-23 21:23:05 -080031#include <mutex>
Dan Albertc007bc32015-03-16 10:08:46 -070032#include <string>
Elliott Hughesd3ff6e52016-08-23 15:53:45 -070033#include <vector>
Elliott Hughesaf4885a2015-02-03 13:02:57 -080034
Elliott Hughes82ff3152016-08-31 15:07:18 -070035#if defined(__APPLE__)
Josh Gao7307f092016-09-01 12:31:42 -070036#include <mach-o/dyld.h>
Elliott Hughes82ff3152016-08-31 15:07:18 -070037#endif
38#if defined(_WIN32)
Mark Salyzyn0790b242018-11-12 12:29:14 -080039#include <direct.h>
Elliott Hughes82ff3152016-08-31 15:07:18 -070040#include <windows.h>
Elliott Hughes282ec452017-05-15 17:31:15 -070041#define O_NOFOLLOW 0
Mark Salyzyn0790b242018-11-12 12:29:14 -080042#define OS_PATH_SEPARATOR '\\'
43#else
44#define OS_PATH_SEPARATOR '/'
Elliott Hughes82ff3152016-08-31 15:07:18 -070045#endif
46
Mark Salyzyn46c2df52018-11-13 13:38:33 -080047#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
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070052namespace {
53
Mark Salyzyn0790b242018-11-12 12:29:14 -080054#ifdef _WIN32
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070055static int mkstemp(char* name_template, size_t size_in_chars) {
56 auto path = name_template;
57 if (_mktemp_s(path, size_in_chars) != 0) {
Mark Salyzyn0790b242018-11-12 12:29:14 -080058 return -1;
59 }
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070060
61 std::wstring path_wide;
62 CHECK(android::base::UTF8ToWide(path, &path_wide))
63 << "path can't be converted to wchar: " << path;
64
Mark Salyzyn0790b242018-11-12 12:29:14 -080065 // Use open() to match the close() that TemporaryFile's destructor does.
66 // Use O_BINARY to match base file APIs.
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070067 return _wopen(path_wide.c_str(), O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
Mark Salyzyn0790b242018-11-12 12:29:14 -080068}
69
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070070static char* mkdtemp(char* name_template, size_t size_in_chars) {
71 auto path = name_template;
72 if (_mktemp_s(path, size_in_chars) != 0) {
Mark Salyzyn0790b242018-11-12 12:29:14 -080073 return nullptr;
74 }
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070075
76 std::wstring path_wide;
77 CHECK(android::base::UTF8ToWide(path, &path_wide))
78 << "path can't be converted to wchar: " << path;
79
80 if (_wmkdir(path_wide.c_str()) != 0) {
Mark Salyzyn0790b242018-11-12 12:29:14 -080081 return nullptr;
82 }
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070083 return path;
Mark Salyzyn0790b242018-11-12 12:29:14 -080084}
85#endif
86
Mark Salyzyn0790b242018-11-12 12:29:14 -080087std::string GetSystemTempDir() {
88#if defined(__ANDROID__)
Mark Salyzyn6009a2d2018-11-13 15:34:38 -080089 const auto* tmpdir = getenv("TMPDIR");
90 if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
Mark Salyzyn0790b242018-11-12 12:29:14 -080091 if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
92 return tmpdir;
93 }
94 // Tests running in app context can't access /data/local/tmp,
95 // so try current directory if /data/local/tmp is not accessible.
96 return ".";
97#elif defined(_WIN32)
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -070098 wchar_t tmp_dir_w[MAX_PATH];
99 DWORD result = GetTempPathW(std::size(tmp_dir_w), tmp_dir_w); // checks TMP env
100 CHECK_NE(result, 0ul) << "GetTempPathW failed, error: " << GetLastError();
101 CHECK_LT(result, std::size(tmp_dir_w)) << "path truncated to: " << result;
Mark Salyzyn0790b242018-11-12 12:29:14 -0800102
103 // GetTempPath() returns a path with a trailing slash, but init()
104 // does not expect that, so remove it.
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700105 if (tmp_dir_w[result - 1] == L'\\') {
106 tmp_dir_w[result - 1] = L'\0';
107 }
108
109 std::string tmp_dir;
110 CHECK(android::base::WideToUTF8(tmp_dir_w, &tmp_dir)) << "path can't be converted to utf8";
111
Mark Salyzyn0790b242018-11-12 12:29:14 -0800112 return tmp_dir;
113#else
Mark Salyzyn6009a2d2018-11-13 15:34:38 -0800114 const auto* tmpdir = getenv("TMPDIR");
115 if (tmpdir == nullptr) tmpdir = "/tmp";
116 return tmpdir;
Mark Salyzyn0790b242018-11-12 12:29:14 -0800117#endif
118}
119
120} // namespace
121
122TemporaryFile::TemporaryFile() {
123 init(GetSystemTempDir());
124}
125
126TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
127 init(tmp_dir);
128}
129
130TemporaryFile::~TemporaryFile() {
131 if (fd != -1) {
132 close(fd);
133 }
134 if (remove_file_) {
135 unlink(path);
136 }
137}
138
139int TemporaryFile::release() {
140 int result = fd;
141 fd = -1;
142 return result;
143}
144
145void TemporaryFile::init(const std::string& tmp_dir) {
146 snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700147#if defined(_WIN32)
148 fd = mkstemp(path, sizeof(path));
149#else
Mark Salyzyn0790b242018-11-12 12:29:14 -0800150 fd = mkstemp(path);
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700151#endif
Mark Salyzyn0790b242018-11-12 12:29:14 -0800152}
153
154TemporaryDir::TemporaryDir() {
155 init(GetSystemTempDir());
156}
157
158TemporaryDir::~TemporaryDir() {
Mark Salyzynd2f58882018-11-13 13:38:33 -0800159 if (!remove_dir_and_contents_) return;
160
Mark Salyzyn46c2df52018-11-13 13:38:33 -0800161 auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
162 switch (file_type) {
163 case FTW_D:
164 case FTW_DP:
165 case FTW_DNR:
166 if (rmdir(child) == -1) {
167 PLOG(ERROR) << "rmdir " << child;
168 }
169 break;
170 case FTW_NS:
171 default:
172 if (rmdir(child) != -1) break;
173 // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
174 FALLTHROUGH_INTENDED;
175 case FTW_F:
176 case FTW_SL:
177 case FTW_SLN:
178 if (unlink(child) == -1) {
179 PLOG(ERROR) << "unlink " << child;
180 }
181 break;
182 }
183 return 0;
184 };
185
186 nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
Mark Salyzyn0790b242018-11-12 12:29:14 -0800187}
188
189bool TemporaryDir::init(const std::string& tmp_dir) {
190 snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700191#if defined(_WIN32)
192 return (mkdtemp(path, sizeof(path)) != nullptr);
193#else
Mark Salyzyn0790b242018-11-12 12:29:14 -0800194 return (mkdtemp(path) != nullptr);
Alex Buynytskyy43f0b0c2019-09-27 11:11:24 -0700195#endif
Mark Salyzyn0790b242018-11-12 12:29:14 -0800196}
197
Dan Albertc007bc32015-03-16 10:08:46 -0700198namespace android {
199namespace base {
200
Elliott Hughesc1fd4922015-11-11 18:02:29 +0000201// Versions of standard library APIs that support UTF-8 strings.
202using namespace android::base::utf8;
203
Josh Gao27241a72019-04-25 14:04:57 -0700204bool ReadFdToString(borrowed_fd fd, std::string* content) {
Elliott Hughesf682b472015-02-06 12:19:48 -0800205 content->clear();
206
Elliott Hughes9bb79712017-03-20 19:16:18 -0700207 // Although original we had small files in mind, this code gets used for
208 // very large files too, where the std::string growth heuristics might not
209 // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
210 struct stat sb;
Josh Gao27241a72019-04-25 14:04:57 -0700211 if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) {
Elliott Hughes9bb79712017-03-20 19:16:18 -0700212 content->reserve(sb.st_size);
213 }
214
Elliott Hughesf682b472015-02-06 12:19:48 -0800215 char buf[BUFSIZ];
216 ssize_t n;
Josh Gao27241a72019-04-25 14:04:57 -0700217 while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
Elliott Hughesf682b472015-02-06 12:19:48 -0800218 content->append(buf, n);
219 }
220 return (n == 0) ? true : false;
221}
222
Josh Gaoffabc962016-09-14 16:11:45 -0700223bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
Elliott Hughesdec12b22015-02-02 17:31:27 -0800224 content->clear();
225
Josh Gaoffabc962016-09-14 16:11:45 -0700226 int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
Christopher Ferris48d08c22017-04-05 12:09:17 -0700227 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
Elliott Hughesdec12b22015-02-02 17:31:27 -0800228 if (fd == -1) {
229 return false;
230 }
Christopher Ferris48d08c22017-04-05 12:09:17 -0700231 return ReadFdToString(fd, content);
Elliott Hughesdec12b22015-02-02 17:31:27 -0800232}
233
Josh Gao27241a72019-04-25 14:04:57 -0700234bool WriteStringToFd(const std::string& content, borrowed_fd fd) {
Elliott Hughesdec12b22015-02-02 17:31:27 -0800235 const char* p = content.data();
236 size_t left = content.size();
237 while (left > 0) {
Josh Gao27241a72019-04-25 14:04:57 -0700238 ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left));
Elliott Hughesdec12b22015-02-02 17:31:27 -0800239 if (n == -1) {
Elliott Hughesdec12b22015-02-02 17:31:27 -0800240 return false;
241 }
242 p += n;
243 left -= n;
244 }
Elliott Hughesdec12b22015-02-02 17:31:27 -0800245 return true;
246}
Elliott Hughes202f0242015-02-04 13:19:13 -0800247
248static bool CleanUpAfterFailedWrite(const std::string& path) {
249 // Something went wrong. Let's not leave a corrupt file lying around.
250 int saved_errno = errno;
251 unlink(path.c_str());
252 errno = saved_errno;
253 return false;
254}
255
Elliott Hughes31fa09c2015-02-04 19:38:28 -0800256#if !defined(_WIN32)
Dan Albertc007bc32015-03-16 10:08:46 -0700257bool WriteStringToFile(const std::string& content, const std::string& path,
Josh Gaoffabc962016-09-14 16:11:45 -0700258 mode_t mode, uid_t owner, gid_t group,
259 bool follow_symlinks) {
260 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
261 (follow_symlinks ? 0 : O_NOFOLLOW);
Christopher Ferris48d08c22017-04-05 12:09:17 -0700262 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
Elliott Hughes202f0242015-02-04 13:19:13 -0800263 if (fd == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700264 PLOG(ERROR) << "android::WriteStringToFile open failed";
Elliott Hughes202f0242015-02-04 13:19:13 -0800265 return false;
266 }
Elliott Hughesf682b472015-02-06 12:19:48 -0800267
Dan Albertc007bc32015-03-16 10:08:46 -0700268 // We do an explicit fchmod here because we assume that the caller really
269 // meant what they said and doesn't want the umask-influenced mode.
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800270 if (fchmod(fd, mode) == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700271 PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800272 return CleanUpAfterFailedWrite(path);
273 }
274 if (fchown(fd, owner, group) == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700275 PLOG(ERROR) << "android::WriteStringToFile fchown failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800276 return CleanUpAfterFailedWrite(path);
277 }
278 if (!WriteStringToFd(content, fd)) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700279 PLOG(ERROR) << "android::WriteStringToFile write failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800280 return CleanUpAfterFailedWrite(path);
281 }
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800282 return true;
Elliott Hughes202f0242015-02-04 13:19:13 -0800283}
Elliott Hughes31fa09c2015-02-04 19:38:28 -0800284#endif
Elliott Hughes202f0242015-02-04 13:19:13 -0800285
Josh Gaoffabc962016-09-14 16:11:45 -0700286bool WriteStringToFile(const std::string& content, const std::string& path,
287 bool follow_symlinks) {
288 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
289 (follow_symlinks ? 0 : O_NOFOLLOW);
Elliott Hughes282ec452017-05-15 17:31:15 -0700290 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0666)));
Elliott Hughes202f0242015-02-04 13:19:13 -0800291 if (fd == -1) {
292 return false;
293 }
Christopher Ferris48d08c22017-04-05 12:09:17 -0700294 return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path);
Elliott Hughes202f0242015-02-04 13:19:13 -0800295}
Dan Albertc007bc32015-03-16 10:08:46 -0700296
Josh Gao27241a72019-04-25 14:04:57 -0700297bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) {
Elliott Hughes56085ed2015-04-24 21:57:16 -0700298 uint8_t* p = reinterpret_cast<uint8_t*>(data);
299 size_t remaining = byte_count;
300 while (remaining > 0) {
Josh Gao27241a72019-04-25 14:04:57 -0700301 ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining));
Elliott Hughes56085ed2015-04-24 21:57:16 -0700302 if (n <= 0) return false;
303 p += n;
304 remaining -= n;
305 }
306 return true;
307}
308
Adam Lesinskide117e42017-06-19 10:27:38 -0700309#if defined(_WIN32)
310// Windows implementation of pread. Note that this DOES move the file descriptors read position,
311// but it does so atomically.
Josh Gao27241a72019-04-25 14:04:57 -0700312static ssize_t pread(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
Adam Lesinskide117e42017-06-19 10:27:38 -0700313 DWORD bytes_read;
314 OVERLAPPED overlapped;
315 memset(&overlapped, 0, sizeof(OVERLAPPED));
316 overlapped.Offset = static_cast<DWORD>(offset);
317 overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
Josh Gao27241a72019-04-25 14:04:57 -0700318 if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
319 static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) {
Adam Lesinskide117e42017-06-19 10:27:38 -0700320 // In case someone tries to read errno (since this is masquerading as a POSIX call)
321 errno = EIO;
322 return -1;
323 }
324 return static_cast<ssize_t>(bytes_read);
325}
326#endif
327
Josh Gao27241a72019-04-25 14:04:57 -0700328bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
Adam Lesinskide117e42017-06-19 10:27:38 -0700329 uint8_t* p = reinterpret_cast<uint8_t*>(data);
330 while (byte_count > 0) {
Josh Gao27241a72019-04-25 14:04:57 -0700331 ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), p, byte_count, offset));
Adam Lesinskide117e42017-06-19 10:27:38 -0700332 if (n <= 0) return false;
333 p += n;
334 byte_count -= n;
335 offset += n;
336 }
337 return true;
338}
339
Josh Gao27241a72019-04-25 14:04:57 -0700340bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
Elliott Hughes56085ed2015-04-24 21:57:16 -0700341 const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
342 size_t remaining = byte_count;
343 while (remaining > 0) {
Josh Gao27241a72019-04-25 14:04:57 -0700344 ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining));
Elliott Hughes56085ed2015-04-24 21:57:16 -0700345 if (n == -1) return false;
346 p += n;
347 remaining -= n;
348 }
349 return true;
350}
351
Yabin Cuib6e314a2016-01-29 17:25:54 -0800352bool RemoveFileIfExists(const std::string& path, std::string* err) {
353 struct stat st;
354#if defined(_WIN32)
liwugangc63cb072018-07-11 13:24:49 +0800355 // TODO: Windows version can't handle symbolic links correctly.
Yabin Cuib6e314a2016-01-29 17:25:54 -0800356 int result = stat(path.c_str(), &st);
357 bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
358#else
359 int result = lstat(path.c_str(), &st);
360 bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
361#endif
liwugangc63cb072018-07-11 13:24:49 +0800362 if (result == -1) {
363 if (errno == ENOENT || errno == ENOTDIR) return true;
364 if (err != nullptr) *err = strerror(errno);
365 return false;
366 }
367
Yabin Cuib6e314a2016-01-29 17:25:54 -0800368 if (result == 0) {
369 if (!file_type_removable) {
370 if (err != nullptr) {
liwugangc63cb072018-07-11 13:24:49 +0800371 *err = "is not a regular file or symbolic link";
Yabin Cuib6e314a2016-01-29 17:25:54 -0800372 }
373 return false;
374 }
375 if (unlink(path.c_str()) == -1) {
376 if (err != nullptr) {
377 *err = strerror(errno);
378 }
379 return false;
380 }
381 }
382 return true;
383}
384
Elliott Hughesd3ff6e52016-08-23 15:53:45 -0700385#if !defined(_WIN32)
386bool Readlink(const std::string& path, std::string* result) {
387 result->clear();
388
389 // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
390 // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
391 // waste memory to just start there. We add 1 so that we can recognize
392 // whether it actually fit (rather than being truncated to 4095).
393 std::vector<char> buf(4095 + 1);
394 while (true) {
395 ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
396 // Unrecoverable error?
397 if (size == -1) return false;
398 // It fit! (If size == buf.size(), it may have been truncated.)
399 if (static_cast<size_t>(size) < buf.size()) {
400 result->assign(&buf[0], size);
401 return true;
402 }
403 // Double our buffer and try again.
404 buf.resize(buf.size() * 2);
405 }
406}
407#endif
408
Dimitry Ivanov840b6012016-09-09 10:49:21 -0700409#if !defined(_WIN32)
410bool Realpath(const std::string& path, std::string* result) {
411 result->clear();
412
Yifan Hong5f4cb8a2019-03-21 15:20:53 -0700413 // realpath may exit with EINTR. Retry if so.
414 char* realpath_buf = nullptr;
415 do {
416 realpath_buf = realpath(path.c_str(), nullptr);
417 } while (realpath_buf == nullptr && errno == EINTR);
418
Dimitry Ivanov840b6012016-09-09 10:49:21 -0700419 if (realpath_buf == nullptr) {
420 return false;
421 }
422 result->assign(realpath_buf);
423 free(realpath_buf);
424 return true;
425}
426#endif
427
Elliott Hughes82ff3152016-08-31 15:07:18 -0700428std::string GetExecutablePath() {
429#if defined(__linux__)
430 std::string path;
431 android::base::Readlink("/proc/self/exe", &path);
432 return path;
433#elif defined(__APPLE__)
Elliott Hughes82ff3152016-08-31 15:07:18 -0700434 char path[PATH_MAX + 1];
Josh Gao7307f092016-09-01 12:31:42 -0700435 uint32_t path_len = sizeof(path);
436 int rc = _NSGetExecutablePath(path, &path_len);
437 if (rc < 0) {
438 std::unique_ptr<char> path_buf(new char[path_len]);
439 _NSGetExecutablePath(path_buf.get(), &path_len);
440 return path_buf.get();
441 }
Elliott Hughes82ff3152016-08-31 15:07:18 -0700442 return path;
443#elif defined(_WIN32)
444 char path[PATH_MAX + 1];
445 DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
446 if (result == 0 || result == sizeof(path) - 1) return "";
447 path[PATH_MAX - 1] = 0;
448 return path;
449#else
450#error unknown OS
451#endif
452}
453
Colin Crossbb3a5152017-02-23 17:41:56 -0800454std::string GetExecutableDirectory() {
455 return Dirname(GetExecutablePath());
456}
Colin Cross58021d12017-02-23 21:23:05 -0800457
Colin Crossbb3a5152017-02-23 17:41:56 -0800458std::string Basename(const std::string& path) {
Colin Cross58021d12017-02-23 21:23:05 -0800459 // Copy path because basename may modify the string passed in.
460 std::string result(path);
461
462#if !defined(__BIONIC__)
463 // Use lock because basename() 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 basename in the process also grab this same lock, but its
466 // better than nothing. Bionic's basename returns a thread-local buffer.
467 static std::mutex& basename_lock = *new std::mutex();
468 std::lock_guard<std::mutex> lock(basename_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* name = basename(&result[0]);
475
476 // In case basename returned a pointer to a process global, copy that string
477 // before leaving the lock.
478 result.assign(name);
479
480 return result;
481}
482
483std::string Dirname(const std::string& path) {
484 // Copy path because dirname may modify the string passed in.
485 std::string result(path);
486
487#if !defined(__BIONIC__)
488 // Use lock because dirname() may write to a process global and return a
489 // pointer to that. Note that this locking strategy only works if all other
490 // callers to dirname in the process also grab this same lock, but its
491 // better than nothing. Bionic's dirname returns a thread-local buffer.
492 static std::mutex& dirname_lock = *new std::mutex();
493 std::lock_guard<std::mutex> lock(dirname_lock);
494#endif
495
496 // Note that if std::string uses copy-on-write strings, &str[0] will cause
497 // the copy to be made, so there is no chance of us accidentally writing to
498 // the storage for 'path'.
499 char* parent = dirname(&result[0]);
500
501 // In case dirname returned a pointer to a process global, copy that string
502 // before leaving the lock.
503 result.assign(parent);
504
505 return result;
506}
507
Dan Albertc007bc32015-03-16 10:08:46 -0700508} // namespace base
509} // namespace android