xref: /aosp_15_r20/system/libbase/file.cpp (revision 8f0ba417480079999ba552f1087ae592091b9d02)
1*8f0ba417SAndroid Build Coastguard Worker /*
2*8f0ba417SAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*8f0ba417SAndroid Build Coastguard Worker  *
4*8f0ba417SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8f0ba417SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8f0ba417SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8f0ba417SAndroid Build Coastguard Worker  *
8*8f0ba417SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8f0ba417SAndroid Build Coastguard Worker  *
10*8f0ba417SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8f0ba417SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8f0ba417SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8f0ba417SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8f0ba417SAndroid Build Coastguard Worker  * limitations under the License.
15*8f0ba417SAndroid Build Coastguard Worker  */
16*8f0ba417SAndroid Build Coastguard Worker 
17*8f0ba417SAndroid Build Coastguard Worker #include "android-base/file.h"
18*8f0ba417SAndroid Build Coastguard Worker 
19*8f0ba417SAndroid Build Coastguard Worker #include <errno.h>
20*8f0ba417SAndroid Build Coastguard Worker #include <fcntl.h>
21*8f0ba417SAndroid Build Coastguard Worker #include <ftw.h>
22*8f0ba417SAndroid Build Coastguard Worker #include <libgen.h>
23*8f0ba417SAndroid Build Coastguard Worker #include <stdio.h>
24*8f0ba417SAndroid Build Coastguard Worker #include <stdlib.h>
25*8f0ba417SAndroid Build Coastguard Worker #include <string.h>
26*8f0ba417SAndroid Build Coastguard Worker #include <sys/param.h>
27*8f0ba417SAndroid Build Coastguard Worker #include <sys/stat.h>
28*8f0ba417SAndroid Build Coastguard Worker #include <sys/types.h>
29*8f0ba417SAndroid Build Coastguard Worker #include <unistd.h>
30*8f0ba417SAndroid Build Coastguard Worker 
31*8f0ba417SAndroid Build Coastguard Worker #include <memory>
32*8f0ba417SAndroid Build Coastguard Worker #include <mutex>
33*8f0ba417SAndroid Build Coastguard Worker #include <string>
34*8f0ba417SAndroid Build Coastguard Worker #include <vector>
35*8f0ba417SAndroid Build Coastguard Worker 
36*8f0ba417SAndroid Build Coastguard Worker #if defined(__APPLE__)
37*8f0ba417SAndroid Build Coastguard Worker #include <mach-o/dyld.h>
38*8f0ba417SAndroid Build Coastguard Worker #endif
39*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
40*8f0ba417SAndroid Build Coastguard Worker #include <direct.h>
41*8f0ba417SAndroid Build Coastguard Worker #include <windows.h>
42*8f0ba417SAndroid Build Coastguard Worker #define O_NOFOLLOW 0
43*8f0ba417SAndroid Build Coastguard Worker #define OS_PATH_SEPARATOR '\\'
44*8f0ba417SAndroid Build Coastguard Worker #else
45*8f0ba417SAndroid Build Coastguard Worker #define OS_PATH_SEPARATOR '/'
46*8f0ba417SAndroid Build Coastguard Worker #endif
47*8f0ba417SAndroid Build Coastguard Worker 
48*8f0ba417SAndroid Build Coastguard Worker #include "android-base/logging.h"  // and must be after windows.h for ERROR
49*8f0ba417SAndroid Build Coastguard Worker #include "android-base/macros.h"   // For TEMP_FAILURE_RETRY on Darwin.
50*8f0ba417SAndroid Build Coastguard Worker #include "android-base/unique_fd.h"
51*8f0ba417SAndroid Build Coastguard Worker #include "android-base/utf8.h"
52*8f0ba417SAndroid Build Coastguard Worker 
53*8f0ba417SAndroid Build Coastguard Worker namespace {
54*8f0ba417SAndroid Build Coastguard Worker 
55*8f0ba417SAndroid Build Coastguard Worker #ifdef _WIN32
mkstemp(char * name_template,size_t size_in_chars)56*8f0ba417SAndroid Build Coastguard Worker static int mkstemp(char* name_template, size_t size_in_chars) {
57*8f0ba417SAndroid Build Coastguard Worker   std::wstring path;
58*8f0ba417SAndroid Build Coastguard Worker   CHECK(android::base::UTF8ToWide(name_template, &path))
59*8f0ba417SAndroid Build Coastguard Worker       << "path can't be converted to wchar: " << name_template;
60*8f0ba417SAndroid Build Coastguard Worker   if (_wmktemp_s(path.data(), path.size() + 1) != 0) {
61*8f0ba417SAndroid Build Coastguard Worker     return -1;
62*8f0ba417SAndroid Build Coastguard Worker   }
63*8f0ba417SAndroid Build Coastguard Worker 
64*8f0ba417SAndroid Build Coastguard Worker   // Use open() to match the close() that TemporaryFile's destructor does.
65*8f0ba417SAndroid Build Coastguard Worker   // Use O_BINARY to match base file APIs.
66*8f0ba417SAndroid Build Coastguard Worker   int fd = _wopen(path.c_str(), O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
67*8f0ba417SAndroid Build Coastguard Worker   if (fd < 0) {
68*8f0ba417SAndroid Build Coastguard Worker     return -1;
69*8f0ba417SAndroid Build Coastguard Worker   }
70*8f0ba417SAndroid Build Coastguard Worker 
71*8f0ba417SAndroid Build Coastguard Worker   std::string path_utf8;
72*8f0ba417SAndroid Build Coastguard Worker   CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8";
73*8f0ba417SAndroid Build Coastguard Worker   CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0)
74*8f0ba417SAndroid Build Coastguard Worker       << "utf8 path can't be assigned back to name_template";
75*8f0ba417SAndroid Build Coastguard Worker 
76*8f0ba417SAndroid Build Coastguard Worker   return fd;
77*8f0ba417SAndroid Build Coastguard Worker }
78*8f0ba417SAndroid Build Coastguard Worker 
mkdtemp(char * name_template,size_t size_in_chars)79*8f0ba417SAndroid Build Coastguard Worker static char* mkdtemp(char* name_template, size_t size_in_chars) {
80*8f0ba417SAndroid Build Coastguard Worker   std::wstring path;
81*8f0ba417SAndroid Build Coastguard Worker   CHECK(android::base::UTF8ToWide(name_template, &path))
82*8f0ba417SAndroid Build Coastguard Worker       << "path can't be converted to wchar: " << name_template;
83*8f0ba417SAndroid Build Coastguard Worker 
84*8f0ba417SAndroid Build Coastguard Worker   if (_wmktemp_s(path.data(), path.size() + 1) != 0) {
85*8f0ba417SAndroid Build Coastguard Worker     return nullptr;
86*8f0ba417SAndroid Build Coastguard Worker   }
87*8f0ba417SAndroid Build Coastguard Worker 
88*8f0ba417SAndroid Build Coastguard Worker   if (_wmkdir(path.c_str()) != 0) {
89*8f0ba417SAndroid Build Coastguard Worker     return nullptr;
90*8f0ba417SAndroid Build Coastguard Worker   }
91*8f0ba417SAndroid Build Coastguard Worker 
92*8f0ba417SAndroid Build Coastguard Worker   std::string path_utf8;
93*8f0ba417SAndroid Build Coastguard Worker   CHECK(android::base::WideToUTF8(path, &path_utf8)) << "path can't be converted to utf8";
94*8f0ba417SAndroid Build Coastguard Worker   CHECK(strcpy_s(name_template, size_in_chars, path_utf8.c_str()) == 0)
95*8f0ba417SAndroid Build Coastguard Worker       << "utf8 path can't be assigned back to name_template";
96*8f0ba417SAndroid Build Coastguard Worker 
97*8f0ba417SAndroid Build Coastguard Worker   return name_template;
98*8f0ba417SAndroid Build Coastguard Worker }
99*8f0ba417SAndroid Build Coastguard Worker #endif
100*8f0ba417SAndroid Build Coastguard Worker 
GetSystemTempDir()101*8f0ba417SAndroid Build Coastguard Worker std::string GetSystemTempDir() {
102*8f0ba417SAndroid Build Coastguard Worker #if defined(__ANDROID__)
103*8f0ba417SAndroid Build Coastguard Worker   const auto* tmpdir = getenv("TMPDIR");
104*8f0ba417SAndroid Build Coastguard Worker   if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
105*8f0ba417SAndroid Build Coastguard Worker   if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
106*8f0ba417SAndroid Build Coastguard Worker     return tmpdir;
107*8f0ba417SAndroid Build Coastguard Worker   }
108*8f0ba417SAndroid Build Coastguard Worker   // Tests running in app context can't access /data/local/tmp,
109*8f0ba417SAndroid Build Coastguard Worker   // so try current directory if /data/local/tmp is not accessible.
110*8f0ba417SAndroid Build Coastguard Worker   return ".";
111*8f0ba417SAndroid Build Coastguard Worker #elif defined(_WIN32)
112*8f0ba417SAndroid Build Coastguard Worker   wchar_t tmp_dir_w[MAX_PATH];
113*8f0ba417SAndroid Build Coastguard Worker   DWORD result = GetTempPathW(std::size(tmp_dir_w), tmp_dir_w);  // checks TMP env
114*8f0ba417SAndroid Build Coastguard Worker   CHECK_NE(result, 0ul) << "GetTempPathW failed, error: " << GetLastError();
115*8f0ba417SAndroid Build Coastguard Worker   CHECK_LT(result, std::size(tmp_dir_w)) << "path truncated to: " << result;
116*8f0ba417SAndroid Build Coastguard Worker 
117*8f0ba417SAndroid Build Coastguard Worker   // GetTempPath() returns a path with a trailing slash, but init()
118*8f0ba417SAndroid Build Coastguard Worker   // does not expect that, so remove it.
119*8f0ba417SAndroid Build Coastguard Worker   if (tmp_dir_w[result - 1] == L'\\') {
120*8f0ba417SAndroid Build Coastguard Worker     tmp_dir_w[result - 1] = L'\0';
121*8f0ba417SAndroid Build Coastguard Worker   }
122*8f0ba417SAndroid Build Coastguard Worker 
123*8f0ba417SAndroid Build Coastguard Worker   std::string tmp_dir;
124*8f0ba417SAndroid Build Coastguard Worker   CHECK(android::base::WideToUTF8(tmp_dir_w, &tmp_dir)) << "path can't be converted to utf8";
125*8f0ba417SAndroid Build Coastguard Worker 
126*8f0ba417SAndroid Build Coastguard Worker   return tmp_dir;
127*8f0ba417SAndroid Build Coastguard Worker #else
128*8f0ba417SAndroid Build Coastguard Worker   const auto* tmpdir = getenv("TMPDIR");
129*8f0ba417SAndroid Build Coastguard Worker   if (tmpdir == nullptr) tmpdir = "/tmp";
130*8f0ba417SAndroid Build Coastguard Worker   return tmpdir;
131*8f0ba417SAndroid Build Coastguard Worker #endif
132*8f0ba417SAndroid Build Coastguard Worker }
133*8f0ba417SAndroid Build Coastguard Worker 
134*8f0ba417SAndroid Build Coastguard Worker }  // namespace
135*8f0ba417SAndroid Build Coastguard Worker 
TemporaryFile()136*8f0ba417SAndroid Build Coastguard Worker TemporaryFile::TemporaryFile() {
137*8f0ba417SAndroid Build Coastguard Worker   init(GetSystemTempDir());
138*8f0ba417SAndroid Build Coastguard Worker }
139*8f0ba417SAndroid Build Coastguard Worker 
TemporaryFile(const std::string & tmp_dir)140*8f0ba417SAndroid Build Coastguard Worker TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
141*8f0ba417SAndroid Build Coastguard Worker   init(tmp_dir);
142*8f0ba417SAndroid Build Coastguard Worker }
143*8f0ba417SAndroid Build Coastguard Worker 
~TemporaryFile()144*8f0ba417SAndroid Build Coastguard Worker TemporaryFile::~TemporaryFile() {
145*8f0ba417SAndroid Build Coastguard Worker   if (fd != -1) {
146*8f0ba417SAndroid Build Coastguard Worker     close(fd);
147*8f0ba417SAndroid Build Coastguard Worker   }
148*8f0ba417SAndroid Build Coastguard Worker   if (remove_file_) {
149*8f0ba417SAndroid Build Coastguard Worker     unlink(path);
150*8f0ba417SAndroid Build Coastguard Worker   }
151*8f0ba417SAndroid Build Coastguard Worker }
152*8f0ba417SAndroid Build Coastguard Worker 
release()153*8f0ba417SAndroid Build Coastguard Worker int TemporaryFile::release() {
154*8f0ba417SAndroid Build Coastguard Worker   int result = fd;
155*8f0ba417SAndroid Build Coastguard Worker   fd = -1;
156*8f0ba417SAndroid Build Coastguard Worker   return result;
157*8f0ba417SAndroid Build Coastguard Worker }
158*8f0ba417SAndroid Build Coastguard Worker 
init(const std::string & tmp_dir)159*8f0ba417SAndroid Build Coastguard Worker void TemporaryFile::init(const std::string& tmp_dir) {
160*8f0ba417SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
161*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
162*8f0ba417SAndroid Build Coastguard Worker   fd = mkstemp(path, sizeof(path));
163*8f0ba417SAndroid Build Coastguard Worker #else
164*8f0ba417SAndroid Build Coastguard Worker   fd = mkstemp(path);
165*8f0ba417SAndroid Build Coastguard Worker #endif
166*8f0ba417SAndroid Build Coastguard Worker }
167*8f0ba417SAndroid Build Coastguard Worker 
TemporaryDir()168*8f0ba417SAndroid Build Coastguard Worker TemporaryDir::TemporaryDir() {
169*8f0ba417SAndroid Build Coastguard Worker   init(GetSystemTempDir());
170*8f0ba417SAndroid Build Coastguard Worker }
171*8f0ba417SAndroid Build Coastguard Worker 
~TemporaryDir()172*8f0ba417SAndroid Build Coastguard Worker TemporaryDir::~TemporaryDir() {
173*8f0ba417SAndroid Build Coastguard Worker   if (!remove_dir_and_contents_) return;
174*8f0ba417SAndroid Build Coastguard Worker 
175*8f0ba417SAndroid Build Coastguard Worker   auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
176*8f0ba417SAndroid Build Coastguard Worker     switch (file_type) {
177*8f0ba417SAndroid Build Coastguard Worker       case FTW_D:
178*8f0ba417SAndroid Build Coastguard Worker       case FTW_DP:
179*8f0ba417SAndroid Build Coastguard Worker       case FTW_DNR:
180*8f0ba417SAndroid Build Coastguard Worker         if (rmdir(child) == -1) {
181*8f0ba417SAndroid Build Coastguard Worker           PLOG(ERROR) << "rmdir " << child;
182*8f0ba417SAndroid Build Coastguard Worker         }
183*8f0ba417SAndroid Build Coastguard Worker         break;
184*8f0ba417SAndroid Build Coastguard Worker       case FTW_NS:
185*8f0ba417SAndroid Build Coastguard Worker       default:
186*8f0ba417SAndroid Build Coastguard Worker         if (rmdir(child) != -1) break;
187*8f0ba417SAndroid Build Coastguard Worker         // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
188*8f0ba417SAndroid Build Coastguard Worker         FALLTHROUGH_INTENDED;
189*8f0ba417SAndroid Build Coastguard Worker       case FTW_F:
190*8f0ba417SAndroid Build Coastguard Worker       case FTW_SL:
191*8f0ba417SAndroid Build Coastguard Worker       case FTW_SLN:
192*8f0ba417SAndroid Build Coastguard Worker         if (unlink(child) == -1) {
193*8f0ba417SAndroid Build Coastguard Worker           PLOG(ERROR) << "unlink " << child;
194*8f0ba417SAndroid Build Coastguard Worker         }
195*8f0ba417SAndroid Build Coastguard Worker         break;
196*8f0ba417SAndroid Build Coastguard Worker     }
197*8f0ba417SAndroid Build Coastguard Worker     return 0;
198*8f0ba417SAndroid Build Coastguard Worker   };
199*8f0ba417SAndroid Build Coastguard Worker 
200*8f0ba417SAndroid Build Coastguard Worker   nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
201*8f0ba417SAndroid Build Coastguard Worker }
202*8f0ba417SAndroid Build Coastguard Worker 
init(const std::string & tmp_dir)203*8f0ba417SAndroid Build Coastguard Worker bool TemporaryDir::init(const std::string& tmp_dir) {
204*8f0ba417SAndroid Build Coastguard Worker   snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
205*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
206*8f0ba417SAndroid Build Coastguard Worker   return (mkdtemp(path, sizeof(path)) != nullptr);
207*8f0ba417SAndroid Build Coastguard Worker #else
208*8f0ba417SAndroid Build Coastguard Worker   return (mkdtemp(path) != nullptr);
209*8f0ba417SAndroid Build Coastguard Worker #endif
210*8f0ba417SAndroid Build Coastguard Worker }
211*8f0ba417SAndroid Build Coastguard Worker 
212*8f0ba417SAndroid Build Coastguard Worker namespace android {
213*8f0ba417SAndroid Build Coastguard Worker namespace base {
214*8f0ba417SAndroid Build Coastguard Worker 
215*8f0ba417SAndroid Build Coastguard Worker // Versions of standard library APIs that support UTF-8 strings.
216*8f0ba417SAndroid Build Coastguard Worker using namespace android::base::utf8;
217*8f0ba417SAndroid Build Coastguard Worker 
ReadFdToString(borrowed_fd fd,std::string * content)218*8f0ba417SAndroid Build Coastguard Worker bool ReadFdToString(borrowed_fd fd, std::string* content) {
219*8f0ba417SAndroid Build Coastguard Worker   content->clear();
220*8f0ba417SAndroid Build Coastguard Worker 
221*8f0ba417SAndroid Build Coastguard Worker   // Although original we had small files in mind, this code gets used for
222*8f0ba417SAndroid Build Coastguard Worker   // very large files too, where the std::string growth heuristics might not
223*8f0ba417SAndroid Build Coastguard Worker   // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
224*8f0ba417SAndroid Build Coastguard Worker   struct stat sb;
225*8f0ba417SAndroid Build Coastguard Worker   if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0 && sb.st_size <= SSIZE_MAX) {
226*8f0ba417SAndroid Build Coastguard Worker     // Shrink the string capacity to fit the file, but if the capacity is only
227*8f0ba417SAndroid Build Coastguard Worker     // slightly larger than needed, avoid reallocating. std::string::reserve no
228*8f0ba417SAndroid Build Coastguard Worker     // longer lowers capacity after P0966R1, but it does round the request up a
229*8f0ba417SAndroid Build Coastguard Worker     // small amount (e.g. 8 or 16 bytes).
230*8f0ba417SAndroid Build Coastguard Worker     size_t fd_size = sb.st_size;
231*8f0ba417SAndroid Build Coastguard Worker     if (fd_size > content->capacity()) {
232*8f0ba417SAndroid Build Coastguard Worker       content->reserve(fd_size);
233*8f0ba417SAndroid Build Coastguard Worker     } else if (fd_size < content->capacity() && content->capacity() - fd_size >= 64) {
234*8f0ba417SAndroid Build Coastguard Worker       content->shrink_to_fit();
235*8f0ba417SAndroid Build Coastguard Worker       content->reserve(fd_size);
236*8f0ba417SAndroid Build Coastguard Worker     }
237*8f0ba417SAndroid Build Coastguard Worker   }
238*8f0ba417SAndroid Build Coastguard Worker 
239*8f0ba417SAndroid Build Coastguard Worker   char buf[4096] __attribute__((__uninitialized__));
240*8f0ba417SAndroid Build Coastguard Worker   ssize_t n;
241*8f0ba417SAndroid Build Coastguard Worker   while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
242*8f0ba417SAndroid Build Coastguard Worker     content->append(buf, n);
243*8f0ba417SAndroid Build Coastguard Worker   }
244*8f0ba417SAndroid Build Coastguard Worker   return (n == 0) ? true : false;
245*8f0ba417SAndroid Build Coastguard Worker }
246*8f0ba417SAndroid Build Coastguard Worker 
ReadFileToString(const std::string & path,std::string * content,bool follow_symlinks)247*8f0ba417SAndroid Build Coastguard Worker bool ReadFileToString(const std::string& path, std::string* content, bool follow_symlinks) {
248*8f0ba417SAndroid Build Coastguard Worker   content->clear();
249*8f0ba417SAndroid Build Coastguard Worker 
250*8f0ba417SAndroid Build Coastguard Worker   int flags = O_RDONLY | O_CLOEXEC | O_BINARY | (follow_symlinks ? 0 : O_NOFOLLOW);
251*8f0ba417SAndroid Build Coastguard Worker   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags)));
252*8f0ba417SAndroid Build Coastguard Worker   if (fd == -1) {
253*8f0ba417SAndroid Build Coastguard Worker     return false;
254*8f0ba417SAndroid Build Coastguard Worker   }
255*8f0ba417SAndroid Build Coastguard Worker   return ReadFdToString(fd, content);
256*8f0ba417SAndroid Build Coastguard Worker }
257*8f0ba417SAndroid Build Coastguard Worker 
WriteStringToFd(std::string_view content,borrowed_fd fd)258*8f0ba417SAndroid Build Coastguard Worker bool WriteStringToFd(std::string_view content, borrowed_fd fd) {
259*8f0ba417SAndroid Build Coastguard Worker   const char* p = content.data();
260*8f0ba417SAndroid Build Coastguard Worker   size_t left = content.size();
261*8f0ba417SAndroid Build Coastguard Worker   while (left > 0) {
262*8f0ba417SAndroid Build Coastguard Worker     ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left));
263*8f0ba417SAndroid Build Coastguard Worker     if (n == -1) {
264*8f0ba417SAndroid Build Coastguard Worker       return false;
265*8f0ba417SAndroid Build Coastguard Worker     }
266*8f0ba417SAndroid Build Coastguard Worker     p += n;
267*8f0ba417SAndroid Build Coastguard Worker     left -= n;
268*8f0ba417SAndroid Build Coastguard Worker   }
269*8f0ba417SAndroid Build Coastguard Worker   return true;
270*8f0ba417SAndroid Build Coastguard Worker }
271*8f0ba417SAndroid Build Coastguard Worker 
CleanUpAfterFailedWrite(const std::string & path)272*8f0ba417SAndroid Build Coastguard Worker static bool CleanUpAfterFailedWrite(const std::string& path) {
273*8f0ba417SAndroid Build Coastguard Worker   // Something went wrong. Let's not leave a corrupt file lying around.
274*8f0ba417SAndroid Build Coastguard Worker   int saved_errno = errno;
275*8f0ba417SAndroid Build Coastguard Worker   unlink(path.c_str());
276*8f0ba417SAndroid Build Coastguard Worker   errno = saved_errno;
277*8f0ba417SAndroid Build Coastguard Worker   return false;
278*8f0ba417SAndroid Build Coastguard Worker }
279*8f0ba417SAndroid Build Coastguard Worker 
280*8f0ba417SAndroid Build Coastguard Worker #if !defined(_WIN32)
WriteStringToFile(const std::string & content,const std::string & path,mode_t mode,uid_t owner,gid_t group,bool follow_symlinks)281*8f0ba417SAndroid Build Coastguard Worker bool WriteStringToFile(const std::string& content, const std::string& path,
282*8f0ba417SAndroid Build Coastguard Worker                        mode_t mode, uid_t owner, gid_t group,
283*8f0ba417SAndroid Build Coastguard Worker                        bool follow_symlinks) {
284*8f0ba417SAndroid Build Coastguard Worker   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
285*8f0ba417SAndroid Build Coastguard Worker               (follow_symlinks ? 0 : O_NOFOLLOW);
286*8f0ba417SAndroid Build Coastguard Worker   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode)));
287*8f0ba417SAndroid Build Coastguard Worker   if (fd == -1) {
288*8f0ba417SAndroid Build Coastguard Worker     PLOG(ERROR) << "android::WriteStringToFile open failed";
289*8f0ba417SAndroid Build Coastguard Worker     return false;
290*8f0ba417SAndroid Build Coastguard Worker   }
291*8f0ba417SAndroid Build Coastguard Worker 
292*8f0ba417SAndroid Build Coastguard Worker   // We do an explicit fchmod here because we assume that the caller really
293*8f0ba417SAndroid Build Coastguard Worker   // meant what they said and doesn't want the umask-influenced mode.
294*8f0ba417SAndroid Build Coastguard Worker   if (fchmod(fd, mode) == -1) {
295*8f0ba417SAndroid Build Coastguard Worker     PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
296*8f0ba417SAndroid Build Coastguard Worker     return CleanUpAfterFailedWrite(path);
297*8f0ba417SAndroid Build Coastguard Worker   }
298*8f0ba417SAndroid Build Coastguard Worker   if (fchown(fd, owner, group) == -1) {
299*8f0ba417SAndroid Build Coastguard Worker     PLOG(ERROR) << "android::WriteStringToFile fchown failed";
300*8f0ba417SAndroid Build Coastguard Worker     return CleanUpAfterFailedWrite(path);
301*8f0ba417SAndroid Build Coastguard Worker   }
302*8f0ba417SAndroid Build Coastguard Worker   if (!WriteStringToFd(content, fd)) {
303*8f0ba417SAndroid Build Coastguard Worker     PLOG(ERROR) << "android::WriteStringToFile write failed";
304*8f0ba417SAndroid Build Coastguard Worker     return CleanUpAfterFailedWrite(path);
305*8f0ba417SAndroid Build Coastguard Worker   }
306*8f0ba417SAndroid Build Coastguard Worker   return true;
307*8f0ba417SAndroid Build Coastguard Worker }
308*8f0ba417SAndroid Build Coastguard Worker #endif
309*8f0ba417SAndroid Build Coastguard Worker 
WriteStringToFile(const std::string & content,const std::string & path,bool follow_symlinks)310*8f0ba417SAndroid Build Coastguard Worker bool WriteStringToFile(const std::string& content, const std::string& path,
311*8f0ba417SAndroid Build Coastguard Worker                        bool follow_symlinks) {
312*8f0ba417SAndroid Build Coastguard Worker   int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY |
313*8f0ba417SAndroid Build Coastguard Worker               (follow_symlinks ? 0 : O_NOFOLLOW);
314*8f0ba417SAndroid Build Coastguard Worker   android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), flags, 0666)));
315*8f0ba417SAndroid Build Coastguard Worker   if (fd == -1) {
316*8f0ba417SAndroid Build Coastguard Worker     return false;
317*8f0ba417SAndroid Build Coastguard Worker   }
318*8f0ba417SAndroid Build Coastguard Worker   return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path);
319*8f0ba417SAndroid Build Coastguard Worker }
320*8f0ba417SAndroid Build Coastguard Worker 
ReadFully(borrowed_fd fd,void * data,size_t byte_count)321*8f0ba417SAndroid Build Coastguard Worker bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) {
322*8f0ba417SAndroid Build Coastguard Worker   uint8_t* p = reinterpret_cast<uint8_t*>(data);
323*8f0ba417SAndroid Build Coastguard Worker   size_t remaining = byte_count;
324*8f0ba417SAndroid Build Coastguard Worker   while (remaining > 0) {
325*8f0ba417SAndroid Build Coastguard Worker     ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining));
326*8f0ba417SAndroid Build Coastguard Worker     if (n == 0) {  // EOF
327*8f0ba417SAndroid Build Coastguard Worker       errno = ENODATA;
328*8f0ba417SAndroid Build Coastguard Worker       return false;
329*8f0ba417SAndroid Build Coastguard Worker     }
330*8f0ba417SAndroid Build Coastguard Worker     if (n == -1) return false;
331*8f0ba417SAndroid Build Coastguard Worker     p += n;
332*8f0ba417SAndroid Build Coastguard Worker     remaining -= n;
333*8f0ba417SAndroid Build Coastguard Worker   }
334*8f0ba417SAndroid Build Coastguard Worker   return true;
335*8f0ba417SAndroid Build Coastguard Worker }
336*8f0ba417SAndroid Build Coastguard Worker 
337*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
338*8f0ba417SAndroid Build Coastguard Worker // Windows implementation of pread. Note that this DOES move the file descriptors read position,
339*8f0ba417SAndroid Build Coastguard Worker // but it does so atomically.
pread(borrowed_fd fd,void * data,size_t byte_count,off64_t offset)340*8f0ba417SAndroid Build Coastguard Worker static ssize_t pread(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
341*8f0ba417SAndroid Build Coastguard Worker   DWORD bytes_read;
342*8f0ba417SAndroid Build Coastguard Worker   OVERLAPPED overlapped;
343*8f0ba417SAndroid Build Coastguard Worker   memset(&overlapped, 0, sizeof(OVERLAPPED));
344*8f0ba417SAndroid Build Coastguard Worker   overlapped.Offset = static_cast<DWORD>(offset);
345*8f0ba417SAndroid Build Coastguard Worker   overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
346*8f0ba417SAndroid Build Coastguard Worker   if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
347*8f0ba417SAndroid Build Coastguard Worker                 static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) {
348*8f0ba417SAndroid Build Coastguard Worker     // In case someone tries to read errno (since this is masquerading as a POSIX call)
349*8f0ba417SAndroid Build Coastguard Worker     errno = EIO;
350*8f0ba417SAndroid Build Coastguard Worker     return -1;
351*8f0ba417SAndroid Build Coastguard Worker   }
352*8f0ba417SAndroid Build Coastguard Worker   return static_cast<ssize_t>(bytes_read);
353*8f0ba417SAndroid Build Coastguard Worker }
354*8f0ba417SAndroid Build Coastguard Worker 
pwrite(borrowed_fd fd,const void * data,size_t byte_count,off64_t offset)355*8f0ba417SAndroid Build Coastguard Worker static ssize_t pwrite(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
356*8f0ba417SAndroid Build Coastguard Worker   DWORD bytes_written;
357*8f0ba417SAndroid Build Coastguard Worker   OVERLAPPED overlapped;
358*8f0ba417SAndroid Build Coastguard Worker   memset(&overlapped, 0, sizeof(OVERLAPPED));
359*8f0ba417SAndroid Build Coastguard Worker   overlapped.Offset = static_cast<DWORD>(offset);
360*8f0ba417SAndroid Build Coastguard Worker   overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
361*8f0ba417SAndroid Build Coastguard Worker   if (!WriteFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
362*8f0ba417SAndroid Build Coastguard Worker                  static_cast<DWORD>(byte_count), &bytes_written, &overlapped)) {
363*8f0ba417SAndroid Build Coastguard Worker     // In case someone tries to read errno (since this is masquerading as a POSIX call)
364*8f0ba417SAndroid Build Coastguard Worker     errno = EIO;
365*8f0ba417SAndroid Build Coastguard Worker     return -1;
366*8f0ba417SAndroid Build Coastguard Worker   }
367*8f0ba417SAndroid Build Coastguard Worker   return static_cast<ssize_t>(bytes_written);
368*8f0ba417SAndroid Build Coastguard Worker }
369*8f0ba417SAndroid Build Coastguard Worker #endif
370*8f0ba417SAndroid Build Coastguard Worker 
ReadFullyAtOffset(borrowed_fd fd,void * data,size_t byte_count,off64_t offset)371*8f0ba417SAndroid Build Coastguard Worker bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
372*8f0ba417SAndroid Build Coastguard Worker   uint8_t* p = reinterpret_cast<uint8_t*>(data);
373*8f0ba417SAndroid Build Coastguard Worker   while (byte_count > 0) {
374*8f0ba417SAndroid Build Coastguard Worker     ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), p, byte_count, offset));
375*8f0ba417SAndroid Build Coastguard Worker     if (n == 0) {  // EOF
376*8f0ba417SAndroid Build Coastguard Worker       errno = ENODATA;
377*8f0ba417SAndroid Build Coastguard Worker       return false;
378*8f0ba417SAndroid Build Coastguard Worker     }
379*8f0ba417SAndroid Build Coastguard Worker     if (n == -1) return false;
380*8f0ba417SAndroid Build Coastguard Worker     p += n;
381*8f0ba417SAndroid Build Coastguard Worker     byte_count -= n;
382*8f0ba417SAndroid Build Coastguard Worker     offset += n;
383*8f0ba417SAndroid Build Coastguard Worker   }
384*8f0ba417SAndroid Build Coastguard Worker   return true;
385*8f0ba417SAndroid Build Coastguard Worker }
386*8f0ba417SAndroid Build Coastguard Worker 
WriteFullyAtOffset(borrowed_fd fd,const void * data,size_t byte_count,off64_t offset)387*8f0ba417SAndroid Build Coastguard Worker bool WriteFullyAtOffset(borrowed_fd fd, const void* data, size_t byte_count, off64_t offset) {
388*8f0ba417SAndroid Build Coastguard Worker   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
389*8f0ba417SAndroid Build Coastguard Worker   size_t remaining = byte_count;
390*8f0ba417SAndroid Build Coastguard Worker   while (remaining > 0) {
391*8f0ba417SAndroid Build Coastguard Worker     ssize_t n = TEMP_FAILURE_RETRY(pwrite(fd.get(), p, remaining, offset));
392*8f0ba417SAndroid Build Coastguard Worker     if (n == -1) return false;
393*8f0ba417SAndroid Build Coastguard Worker     p += n;
394*8f0ba417SAndroid Build Coastguard Worker     remaining -= n;
395*8f0ba417SAndroid Build Coastguard Worker     offset += n;
396*8f0ba417SAndroid Build Coastguard Worker   }
397*8f0ba417SAndroid Build Coastguard Worker   return true;
398*8f0ba417SAndroid Build Coastguard Worker }
399*8f0ba417SAndroid Build Coastguard Worker 
WriteFully(borrowed_fd fd,const void * data,size_t byte_count)400*8f0ba417SAndroid Build Coastguard Worker bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
401*8f0ba417SAndroid Build Coastguard Worker   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
402*8f0ba417SAndroid Build Coastguard Worker   size_t remaining = byte_count;
403*8f0ba417SAndroid Build Coastguard Worker   while (remaining > 0) {
404*8f0ba417SAndroid Build Coastguard Worker     ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining));
405*8f0ba417SAndroid Build Coastguard Worker     if (n == -1) return false;
406*8f0ba417SAndroid Build Coastguard Worker     p += n;
407*8f0ba417SAndroid Build Coastguard Worker     remaining -= n;
408*8f0ba417SAndroid Build Coastguard Worker   }
409*8f0ba417SAndroid Build Coastguard Worker   return true;
410*8f0ba417SAndroid Build Coastguard Worker }
411*8f0ba417SAndroid Build Coastguard Worker 
RemoveFileIfExists(const std::string & path,std::string * err)412*8f0ba417SAndroid Build Coastguard Worker bool RemoveFileIfExists(const std::string& path, std::string* err) {
413*8f0ba417SAndroid Build Coastguard Worker   struct stat st;
414*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
415*8f0ba417SAndroid Build Coastguard Worker   // TODO: Windows version can't handle symbolic links correctly.
416*8f0ba417SAndroid Build Coastguard Worker   int result = stat(path.c_str(), &st);
417*8f0ba417SAndroid Build Coastguard Worker   bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
418*8f0ba417SAndroid Build Coastguard Worker #else
419*8f0ba417SAndroid Build Coastguard Worker   int result = lstat(path.c_str(), &st);
420*8f0ba417SAndroid Build Coastguard Worker   bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
421*8f0ba417SAndroid Build Coastguard Worker #endif
422*8f0ba417SAndroid Build Coastguard Worker   if (result == -1) {
423*8f0ba417SAndroid Build Coastguard Worker     if (errno == ENOENT || errno == ENOTDIR) return true;
424*8f0ba417SAndroid Build Coastguard Worker     if (err != nullptr) *err = strerror(errno);
425*8f0ba417SAndroid Build Coastguard Worker     return false;
426*8f0ba417SAndroid Build Coastguard Worker   }
427*8f0ba417SAndroid Build Coastguard Worker 
428*8f0ba417SAndroid Build Coastguard Worker   if (result == 0) {
429*8f0ba417SAndroid Build Coastguard Worker     if (!file_type_removable) {
430*8f0ba417SAndroid Build Coastguard Worker       if (err != nullptr) {
431*8f0ba417SAndroid Build Coastguard Worker         *err = "is not a regular file or symbolic link";
432*8f0ba417SAndroid Build Coastguard Worker       }
433*8f0ba417SAndroid Build Coastguard Worker       return false;
434*8f0ba417SAndroid Build Coastguard Worker     }
435*8f0ba417SAndroid Build Coastguard Worker     if (unlink(path.c_str()) == -1) {
436*8f0ba417SAndroid Build Coastguard Worker       if (err != nullptr) {
437*8f0ba417SAndroid Build Coastguard Worker         *err = strerror(errno);
438*8f0ba417SAndroid Build Coastguard Worker       }
439*8f0ba417SAndroid Build Coastguard Worker       return false;
440*8f0ba417SAndroid Build Coastguard Worker     }
441*8f0ba417SAndroid Build Coastguard Worker   }
442*8f0ba417SAndroid Build Coastguard Worker   return true;
443*8f0ba417SAndroid Build Coastguard Worker }
444*8f0ba417SAndroid Build Coastguard Worker 
445*8f0ba417SAndroid Build Coastguard Worker #if !defined(_WIN32)
Readlink(const std::string & path,std::string * result)446*8f0ba417SAndroid Build Coastguard Worker bool Readlink(const std::string& path, std::string* result) {
447*8f0ba417SAndroid Build Coastguard Worker   result->clear();
448*8f0ba417SAndroid Build Coastguard Worker 
449*8f0ba417SAndroid Build Coastguard Worker   // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
450*8f0ba417SAndroid Build Coastguard Worker   // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
451*8f0ba417SAndroid Build Coastguard Worker   // waste memory to just start there. We add 1 so that we can recognize
452*8f0ba417SAndroid Build Coastguard Worker   // whether it actually fit (rather than being truncated to 4095).
453*8f0ba417SAndroid Build Coastguard Worker   std::vector<char> buf(4095 + 1);
454*8f0ba417SAndroid Build Coastguard Worker   while (true) {
455*8f0ba417SAndroid Build Coastguard Worker     ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
456*8f0ba417SAndroid Build Coastguard Worker     // Unrecoverable error?
457*8f0ba417SAndroid Build Coastguard Worker     if (size == -1) return false;
458*8f0ba417SAndroid Build Coastguard Worker     // It fit! (If size == buf.size(), it may have been truncated.)
459*8f0ba417SAndroid Build Coastguard Worker     if (static_cast<size_t>(size) < buf.size()) {
460*8f0ba417SAndroid Build Coastguard Worker       result->assign(&buf[0], size);
461*8f0ba417SAndroid Build Coastguard Worker       return true;
462*8f0ba417SAndroid Build Coastguard Worker     }
463*8f0ba417SAndroid Build Coastguard Worker     // Double our buffer and try again.
464*8f0ba417SAndroid Build Coastguard Worker     buf.resize(buf.size() * 2);
465*8f0ba417SAndroid Build Coastguard Worker   }
466*8f0ba417SAndroid Build Coastguard Worker }
467*8f0ba417SAndroid Build Coastguard Worker #endif
468*8f0ba417SAndroid Build Coastguard Worker 
469*8f0ba417SAndroid Build Coastguard Worker #if !defined(_WIN32)
Realpath(const std::string & path,std::string * result)470*8f0ba417SAndroid Build Coastguard Worker bool Realpath(const std::string& path, std::string* result) {
471*8f0ba417SAndroid Build Coastguard Worker   result->clear();
472*8f0ba417SAndroid Build Coastguard Worker 
473*8f0ba417SAndroid Build Coastguard Worker   // realpath may exit with EINTR. Retry if so.
474*8f0ba417SAndroid Build Coastguard Worker   char* realpath_buf = nullptr;
475*8f0ba417SAndroid Build Coastguard Worker   do {
476*8f0ba417SAndroid Build Coastguard Worker     realpath_buf = realpath(path.c_str(), nullptr);
477*8f0ba417SAndroid Build Coastguard Worker   } while (realpath_buf == nullptr && errno == EINTR);
478*8f0ba417SAndroid Build Coastguard Worker 
479*8f0ba417SAndroid Build Coastguard Worker   if (realpath_buf == nullptr) {
480*8f0ba417SAndroid Build Coastguard Worker     return false;
481*8f0ba417SAndroid Build Coastguard Worker   }
482*8f0ba417SAndroid Build Coastguard Worker   result->assign(realpath_buf);
483*8f0ba417SAndroid Build Coastguard Worker   free(realpath_buf);
484*8f0ba417SAndroid Build Coastguard Worker   return true;
485*8f0ba417SAndroid Build Coastguard Worker }
486*8f0ba417SAndroid Build Coastguard Worker #endif
487*8f0ba417SAndroid Build Coastguard Worker 
GetExecutablePath()488*8f0ba417SAndroid Build Coastguard Worker std::string GetExecutablePath() {
489*8f0ba417SAndroid Build Coastguard Worker #if defined(__linux__)
490*8f0ba417SAndroid Build Coastguard Worker   std::string path;
491*8f0ba417SAndroid Build Coastguard Worker   android::base::Readlink("/proc/self/exe", &path);
492*8f0ba417SAndroid Build Coastguard Worker   return path;
493*8f0ba417SAndroid Build Coastguard Worker #elif defined(__APPLE__)
494*8f0ba417SAndroid Build Coastguard Worker   char path[PATH_MAX + 1];
495*8f0ba417SAndroid Build Coastguard Worker   uint32_t path_len = sizeof(path);
496*8f0ba417SAndroid Build Coastguard Worker   int rc = _NSGetExecutablePath(path, &path_len);
497*8f0ba417SAndroid Build Coastguard Worker   if (rc < 0) {
498*8f0ba417SAndroid Build Coastguard Worker     std::unique_ptr<char> path_buf(new char[path_len]);
499*8f0ba417SAndroid Build Coastguard Worker     _NSGetExecutablePath(path_buf.get(), &path_len);
500*8f0ba417SAndroid Build Coastguard Worker     return path_buf.get();
501*8f0ba417SAndroid Build Coastguard Worker   }
502*8f0ba417SAndroid Build Coastguard Worker   return path;
503*8f0ba417SAndroid Build Coastguard Worker #elif defined(_WIN32)
504*8f0ba417SAndroid Build Coastguard Worker   char path[PATH_MAX + 1];
505*8f0ba417SAndroid Build Coastguard Worker   DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
506*8f0ba417SAndroid Build Coastguard Worker   if (result == 0 || result == sizeof(path) - 1) return "";
507*8f0ba417SAndroid Build Coastguard Worker   path[PATH_MAX - 1] = 0;
508*8f0ba417SAndroid Build Coastguard Worker   return path;
509*8f0ba417SAndroid Build Coastguard Worker #elif defined(__EMSCRIPTEN__)
510*8f0ba417SAndroid Build Coastguard Worker   abort();
511*8f0ba417SAndroid Build Coastguard Worker #else
512*8f0ba417SAndroid Build Coastguard Worker #error unknown OS
513*8f0ba417SAndroid Build Coastguard Worker #endif
514*8f0ba417SAndroid Build Coastguard Worker }
515*8f0ba417SAndroid Build Coastguard Worker 
GetExecutableDirectory()516*8f0ba417SAndroid Build Coastguard Worker std::string GetExecutableDirectory() {
517*8f0ba417SAndroid Build Coastguard Worker   return Dirname(GetExecutablePath());
518*8f0ba417SAndroid Build Coastguard Worker }
519*8f0ba417SAndroid Build Coastguard Worker 
520*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
Basename(std::string_view path)521*8f0ba417SAndroid Build Coastguard Worker std::string Basename(std::string_view path) {
522*8f0ba417SAndroid Build Coastguard Worker   // TODO: how much of this is actually necessary for mingw?
523*8f0ba417SAndroid Build Coastguard Worker 
524*8f0ba417SAndroid Build Coastguard Worker   // Copy path because basename may modify the string passed in.
525*8f0ba417SAndroid Build Coastguard Worker   std::string result(path);
526*8f0ba417SAndroid Build Coastguard Worker 
527*8f0ba417SAndroid Build Coastguard Worker   // Use lock because basename() may write to a process global and return a
528*8f0ba417SAndroid Build Coastguard Worker   // pointer to that. Note that this locking strategy only works if all other
529*8f0ba417SAndroid Build Coastguard Worker   // callers to basename in the process also grab this same lock, but its
530*8f0ba417SAndroid Build Coastguard Worker   // better than nothing.  Bionic's basename returns a thread-local buffer.
531*8f0ba417SAndroid Build Coastguard Worker   static std::mutex& basename_lock = *new std::mutex();
532*8f0ba417SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(basename_lock);
533*8f0ba417SAndroid Build Coastguard Worker 
534*8f0ba417SAndroid Build Coastguard Worker   // Note that if std::string uses copy-on-write strings, &str[0] will cause
535*8f0ba417SAndroid Build Coastguard Worker   // the copy to be made, so there is no chance of us accidentally writing to
536*8f0ba417SAndroid Build Coastguard Worker   // the storage for 'path'.
537*8f0ba417SAndroid Build Coastguard Worker   char* name = basename(&result[0]);
538*8f0ba417SAndroid Build Coastguard Worker 
539*8f0ba417SAndroid Build Coastguard Worker   // In case basename returned a pointer to a process global, copy that string
540*8f0ba417SAndroid Build Coastguard Worker   // before leaving the lock.
541*8f0ba417SAndroid Build Coastguard Worker   result.assign(name);
542*8f0ba417SAndroid Build Coastguard Worker 
543*8f0ba417SAndroid Build Coastguard Worker   return result;
544*8f0ba417SAndroid Build Coastguard Worker }
545*8f0ba417SAndroid Build Coastguard Worker #else
546*8f0ba417SAndroid Build Coastguard Worker // Copied from bionic so that Basename() below can be portable and thread-safe.
_basename_r(const char * path,size_t path_size,char * buffer,size_t buffer_size)547*8f0ba417SAndroid Build Coastguard Worker static int _basename_r(const char* path, size_t path_size, char* buffer, size_t buffer_size) {
548*8f0ba417SAndroid Build Coastguard Worker   const char* startp = nullptr;
549*8f0ba417SAndroid Build Coastguard Worker   const char* endp = nullptr;
550*8f0ba417SAndroid Build Coastguard Worker   int len;
551*8f0ba417SAndroid Build Coastguard Worker   int result;
552*8f0ba417SAndroid Build Coastguard Worker 
553*8f0ba417SAndroid Build Coastguard Worker   // Empty or NULL string gets treated as ".".
554*8f0ba417SAndroid Build Coastguard Worker   if (path == nullptr || path_size == 0) {
555*8f0ba417SAndroid Build Coastguard Worker     startp = ".";
556*8f0ba417SAndroid Build Coastguard Worker     len = 1;
557*8f0ba417SAndroid Build Coastguard Worker     goto Exit;
558*8f0ba417SAndroid Build Coastguard Worker   }
559*8f0ba417SAndroid Build Coastguard Worker 
560*8f0ba417SAndroid Build Coastguard Worker   // Strip trailing slashes.
561*8f0ba417SAndroid Build Coastguard Worker   endp = path + path_size - 1;
562*8f0ba417SAndroid Build Coastguard Worker   while (endp > path && *endp == '/') {
563*8f0ba417SAndroid Build Coastguard Worker     endp--;
564*8f0ba417SAndroid Build Coastguard Worker   }
565*8f0ba417SAndroid Build Coastguard Worker 
566*8f0ba417SAndroid Build Coastguard Worker   // All slashes becomes "/".
567*8f0ba417SAndroid Build Coastguard Worker   if (endp == path && *endp == '/') {
568*8f0ba417SAndroid Build Coastguard Worker     startp = "/";
569*8f0ba417SAndroid Build Coastguard Worker     len = 1;
570*8f0ba417SAndroid Build Coastguard Worker     goto Exit;
571*8f0ba417SAndroid Build Coastguard Worker   }
572*8f0ba417SAndroid Build Coastguard Worker 
573*8f0ba417SAndroid Build Coastguard Worker   // Find the start of the base.
574*8f0ba417SAndroid Build Coastguard Worker   startp = endp;
575*8f0ba417SAndroid Build Coastguard Worker   while (startp > path && *(startp - 1) != '/') {
576*8f0ba417SAndroid Build Coastguard Worker     startp--;
577*8f0ba417SAndroid Build Coastguard Worker   }
578*8f0ba417SAndroid Build Coastguard Worker 
579*8f0ba417SAndroid Build Coastguard Worker   len = endp - startp +1;
580*8f0ba417SAndroid Build Coastguard Worker 
581*8f0ba417SAndroid Build Coastguard Worker  Exit:
582*8f0ba417SAndroid Build Coastguard Worker   result = len;
583*8f0ba417SAndroid Build Coastguard Worker   if (buffer == nullptr) {
584*8f0ba417SAndroid Build Coastguard Worker     return result;
585*8f0ba417SAndroid Build Coastguard Worker   }
586*8f0ba417SAndroid Build Coastguard Worker   if (len > static_cast<int>(buffer_size) - 1) {
587*8f0ba417SAndroid Build Coastguard Worker     len = buffer_size - 1;
588*8f0ba417SAndroid Build Coastguard Worker     result = -1;
589*8f0ba417SAndroid Build Coastguard Worker     errno = ERANGE;
590*8f0ba417SAndroid Build Coastguard Worker   }
591*8f0ba417SAndroid Build Coastguard Worker 
592*8f0ba417SAndroid Build Coastguard Worker   if (len >= 0) {
593*8f0ba417SAndroid Build Coastguard Worker     memcpy(buffer, startp, len);
594*8f0ba417SAndroid Build Coastguard Worker     buffer[len] = 0;
595*8f0ba417SAndroid Build Coastguard Worker   }
596*8f0ba417SAndroid Build Coastguard Worker   return result;
597*8f0ba417SAndroid Build Coastguard Worker }
Basename(std::string_view path)598*8f0ba417SAndroid Build Coastguard Worker std::string Basename(std::string_view path) {
599*8f0ba417SAndroid Build Coastguard Worker   char buf[PATH_MAX] __attribute__((__uninitialized__));
600*8f0ba417SAndroid Build Coastguard Worker   const auto size = _basename_r(path.data(), path.size(), buf, sizeof(buf));
601*8f0ba417SAndroid Build Coastguard Worker   return size > 0 ? std::string(buf, size) : std::string();
602*8f0ba417SAndroid Build Coastguard Worker }
603*8f0ba417SAndroid Build Coastguard Worker #endif
604*8f0ba417SAndroid Build Coastguard Worker 
605*8f0ba417SAndroid Build Coastguard Worker #if defined(_WIN32)
Dirname(std::string_view path)606*8f0ba417SAndroid Build Coastguard Worker std::string Dirname(std::string_view path) {
607*8f0ba417SAndroid Build Coastguard Worker   // TODO: how much of this is actually necessary for mingw?
608*8f0ba417SAndroid Build Coastguard Worker 
609*8f0ba417SAndroid Build Coastguard Worker   // Copy path because dirname may modify the string passed in.
610*8f0ba417SAndroid Build Coastguard Worker   std::string result(path);
611*8f0ba417SAndroid Build Coastguard Worker 
612*8f0ba417SAndroid Build Coastguard Worker   // Use lock because dirname() may write to a process global and return a
613*8f0ba417SAndroid Build Coastguard Worker   // pointer to that. Note that this locking strategy only works if all other
614*8f0ba417SAndroid Build Coastguard Worker   // callers to dirname in the process also grab this same lock, but its
615*8f0ba417SAndroid Build Coastguard Worker   // better than nothing.  Bionic's dirname returns a thread-local buffer.
616*8f0ba417SAndroid Build Coastguard Worker   static std::mutex& dirname_lock = *new std::mutex();
617*8f0ba417SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> lock(dirname_lock);
618*8f0ba417SAndroid Build Coastguard Worker 
619*8f0ba417SAndroid Build Coastguard Worker   // Note that if std::string uses copy-on-write strings, &str[0] will cause
620*8f0ba417SAndroid Build Coastguard Worker   // the copy to be made, so there is no chance of us accidentally writing to
621*8f0ba417SAndroid Build Coastguard Worker   // the storage for 'path'.
622*8f0ba417SAndroid Build Coastguard Worker   char* parent = dirname(&result[0]);
623*8f0ba417SAndroid Build Coastguard Worker 
624*8f0ba417SAndroid Build Coastguard Worker   // In case dirname returned a pointer to a process global, copy that string
625*8f0ba417SAndroid Build Coastguard Worker   // before leaving the lock.
626*8f0ba417SAndroid Build Coastguard Worker   result.assign(parent);
627*8f0ba417SAndroid Build Coastguard Worker 
628*8f0ba417SAndroid Build Coastguard Worker   return result;
629*8f0ba417SAndroid Build Coastguard Worker }
630*8f0ba417SAndroid Build Coastguard Worker #else
631*8f0ba417SAndroid Build Coastguard Worker // Copied from bionic so that Dirname() below can be portable and thread-safe.
_dirname_r(const char * path,size_t path_size,char * buffer,size_t buffer_size)632*8f0ba417SAndroid Build Coastguard Worker static int _dirname_r(const char* path, size_t path_size, char* buffer, size_t buffer_size) {
633*8f0ba417SAndroid Build Coastguard Worker   const char* endp = nullptr;
634*8f0ba417SAndroid Build Coastguard Worker   int len;
635*8f0ba417SAndroid Build Coastguard Worker   int result;
636*8f0ba417SAndroid Build Coastguard Worker 
637*8f0ba417SAndroid Build Coastguard Worker   // Empty or NULL string gets treated as ".".
638*8f0ba417SAndroid Build Coastguard Worker   if (path == nullptr || path_size == 0) {
639*8f0ba417SAndroid Build Coastguard Worker     path = ".";
640*8f0ba417SAndroid Build Coastguard Worker     len = 1;
641*8f0ba417SAndroid Build Coastguard Worker     goto Exit;
642*8f0ba417SAndroid Build Coastguard Worker   }
643*8f0ba417SAndroid Build Coastguard Worker 
644*8f0ba417SAndroid Build Coastguard Worker   // Strip trailing slashes.
645*8f0ba417SAndroid Build Coastguard Worker   endp = path + path_size - 1;
646*8f0ba417SAndroid Build Coastguard Worker   while (endp > path && *endp == '/') {
647*8f0ba417SAndroid Build Coastguard Worker     endp--;
648*8f0ba417SAndroid Build Coastguard Worker   }
649*8f0ba417SAndroid Build Coastguard Worker 
650*8f0ba417SAndroid Build Coastguard Worker   // Find the start of the dir.
651*8f0ba417SAndroid Build Coastguard Worker   while (endp > path && *endp != '/') {
652*8f0ba417SAndroid Build Coastguard Worker     endp--;
653*8f0ba417SAndroid Build Coastguard Worker   }
654*8f0ba417SAndroid Build Coastguard Worker 
655*8f0ba417SAndroid Build Coastguard Worker   // Either the dir is "/" or there are no slashes.
656*8f0ba417SAndroid Build Coastguard Worker   if (endp == path) {
657*8f0ba417SAndroid Build Coastguard Worker     path = (*endp == '/') ? "/" : ".";
658*8f0ba417SAndroid Build Coastguard Worker     len = 1;
659*8f0ba417SAndroid Build Coastguard Worker     goto Exit;
660*8f0ba417SAndroid Build Coastguard Worker   }
661*8f0ba417SAndroid Build Coastguard Worker 
662*8f0ba417SAndroid Build Coastguard Worker   do {
663*8f0ba417SAndroid Build Coastguard Worker     endp--;
664*8f0ba417SAndroid Build Coastguard Worker   } while (endp > path && *endp == '/');
665*8f0ba417SAndroid Build Coastguard Worker 
666*8f0ba417SAndroid Build Coastguard Worker   len = endp - path + 1;
667*8f0ba417SAndroid Build Coastguard Worker 
668*8f0ba417SAndroid Build Coastguard Worker  Exit:
669*8f0ba417SAndroid Build Coastguard Worker   result = len;
670*8f0ba417SAndroid Build Coastguard Worker   if (len + 1 > MAXPATHLEN) {
671*8f0ba417SAndroid Build Coastguard Worker     errno = ENAMETOOLONG;
672*8f0ba417SAndroid Build Coastguard Worker     return -1;
673*8f0ba417SAndroid Build Coastguard Worker   }
674*8f0ba417SAndroid Build Coastguard Worker   if (buffer == nullptr) {
675*8f0ba417SAndroid Build Coastguard Worker     return result;
676*8f0ba417SAndroid Build Coastguard Worker   }
677*8f0ba417SAndroid Build Coastguard Worker 
678*8f0ba417SAndroid Build Coastguard Worker   if (len > static_cast<int>(buffer_size) - 1) {
679*8f0ba417SAndroid Build Coastguard Worker     len = buffer_size - 1;
680*8f0ba417SAndroid Build Coastguard Worker     result = -1;
681*8f0ba417SAndroid Build Coastguard Worker     errno = ERANGE;
682*8f0ba417SAndroid Build Coastguard Worker   }
683*8f0ba417SAndroid Build Coastguard Worker 
684*8f0ba417SAndroid Build Coastguard Worker   if (len >= 0) {
685*8f0ba417SAndroid Build Coastguard Worker     memcpy(buffer, path, len);
686*8f0ba417SAndroid Build Coastguard Worker     buffer[len] = 0;
687*8f0ba417SAndroid Build Coastguard Worker   }
688*8f0ba417SAndroid Build Coastguard Worker   return result;
689*8f0ba417SAndroid Build Coastguard Worker }
Dirname(std::string_view path)690*8f0ba417SAndroid Build Coastguard Worker std::string Dirname(std::string_view path) {
691*8f0ba417SAndroid Build Coastguard Worker   char buf[PATH_MAX] __attribute__((__uninitialized__));
692*8f0ba417SAndroid Build Coastguard Worker   const auto size = _dirname_r(path.data(), path.size(), buf, sizeof(buf));
693*8f0ba417SAndroid Build Coastguard Worker   return size > 0 ? std::string(buf, size) : std::string();
694*8f0ba417SAndroid Build Coastguard Worker }
695*8f0ba417SAndroid Build Coastguard Worker #endif
696*8f0ba417SAndroid Build Coastguard Worker 
697*8f0ba417SAndroid Build Coastguard Worker }  // namespace base
698*8f0ba417SAndroid Build Coastguard Worker }  // namespace android
699