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