blob: 03ce4ea7e904575c3017d264cb26b1e456adb363 [file] [log] [blame]
Elliott Hughesdec12b22015-02-02 17:31:27 -08001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Elliott Hughes4f713192015-12-04 22:00:26 -080017#include "android-base/file.h"
Elliott Hughesdec12b22015-02-02 17:31:27 -080018
19#include <errno.h>
20#include <fcntl.h>
21#include <sys/stat.h>
22#include <sys/types.h>
Elliott Hughesd3ff6e52016-08-23 15:53:45 -070023#include <unistd.h>
Elliott Hughesdec12b22015-02-02 17:31:27 -080024
Dan Albertc007bc32015-03-16 10:08:46 -070025#include <string>
Elliott Hughesd3ff6e52016-08-23 15:53:45 -070026#include <vector>
Elliott Hughesaf4885a2015-02-03 13:02:57 -080027
Elliott Hughes4f713192015-12-04 22:00:26 -080028#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
Elliott Hughese5dd71a2016-07-28 15:15:28 -070029#include "android-base/logging.h"
Elliott Hughes4f713192015-12-04 22:00:26 -080030#include "android-base/utf8.h"
Dan Albert94d13602015-03-26 23:33:28 -070031#include "utils/Compat.h"
Dan Albertc007bc32015-03-16 10:08:46 -070032
Elliott Hughes82ff3152016-08-31 15:07:18 -070033#if defined(__APPLE__)
34#import <Carbon/Carbon.h>
35#endif
36#if defined(_WIN32)
37#include <windows.h>
38#endif
39
Dan Albertc007bc32015-03-16 10:08:46 -070040namespace android {
41namespace base {
42
Elliott Hughesc1fd4922015-11-11 18:02:29 +000043// Versions of standard library APIs that support UTF-8 strings.
44using namespace android::base::utf8;
45
Dan Albertc007bc32015-03-16 10:08:46 -070046bool ReadFdToString(int fd, std::string* content) {
Elliott Hughesf682b472015-02-06 12:19:48 -080047 content->clear();
48
49 char buf[BUFSIZ];
50 ssize_t n;
51 while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
52 content->append(buf, n);
53 }
54 return (n == 0) ? true : false;
55}
56
Dan Albertc007bc32015-03-16 10:08:46 -070057bool ReadFileToString(const std::string& path, std::string* content) {
Elliott Hughesdec12b22015-02-02 17:31:27 -080058 content->clear();
59
Elliott Hughes470d79a2015-09-01 13:35:44 -070060 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
Elliott Hughesdec12b22015-02-02 17:31:27 -080061 if (fd == -1) {
62 return false;
63 }
Elliott Hughesf682b472015-02-06 12:19:48 -080064 bool result = ReadFdToString(fd, content);
Nick Kralevich95db36e2015-05-20 08:59:21 -070065 close(fd);
Elliott Hughesf682b472015-02-06 12:19:48 -080066 return result;
Elliott Hughesdec12b22015-02-02 17:31:27 -080067}
68
Dan Albertc007bc32015-03-16 10:08:46 -070069bool WriteStringToFd(const std::string& content, int fd) {
Elliott Hughesdec12b22015-02-02 17:31:27 -080070 const char* p = content.data();
71 size_t left = content.size();
72 while (left > 0) {
73 ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
74 if (n == -1) {
Elliott Hughesdec12b22015-02-02 17:31:27 -080075 return false;
76 }
77 p += n;
78 left -= n;
79 }
Elliott Hughesdec12b22015-02-02 17:31:27 -080080 return true;
81}
Elliott Hughes202f0242015-02-04 13:19:13 -080082
83static bool CleanUpAfterFailedWrite(const std::string& path) {
84 // Something went wrong. Let's not leave a corrupt file lying around.
85 int saved_errno = errno;
86 unlink(path.c_str());
87 errno = saved_errno;
88 return false;
89}
90
Elliott Hughes31fa09c2015-02-04 19:38:28 -080091#if !defined(_WIN32)
Dan Albertc007bc32015-03-16 10:08:46 -070092bool WriteStringToFile(const std::string& content, const std::string& path,
93 mode_t mode, uid_t owner, gid_t group) {
Elliott Hughes470d79a2015-09-01 13:35:44 -070094 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
95 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
Elliott Hughes202f0242015-02-04 13:19:13 -080096 if (fd == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -070097 PLOG(ERROR) << "android::WriteStringToFile open failed";
Elliott Hughes202f0242015-02-04 13:19:13 -080098 return false;
99 }
Elliott Hughesf682b472015-02-06 12:19:48 -0800100
Dan Albertc007bc32015-03-16 10:08:46 -0700101 // We do an explicit fchmod here because we assume that the caller really
102 // meant what they said and doesn't want the umask-influenced mode.
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800103 if (fchmod(fd, mode) == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700104 PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800105 return CleanUpAfterFailedWrite(path);
106 }
107 if (fchown(fd, owner, group) == -1) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700108 PLOG(ERROR) << "android::WriteStringToFile fchown failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800109 return CleanUpAfterFailedWrite(path);
110 }
111 if (!WriteStringToFd(content, fd)) {
Elliott Hughese5dd71a2016-07-28 15:15:28 -0700112 PLOG(ERROR) << "android::WriteStringToFile write failed";
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800113 return CleanUpAfterFailedWrite(path);
114 }
Nick Kralevich95db36e2015-05-20 08:59:21 -0700115 close(fd);
Elliott Hughes9d1f5152015-02-17 10:16:04 -0800116 return true;
Elliott Hughes202f0242015-02-04 13:19:13 -0800117}
Elliott Hughes31fa09c2015-02-04 19:38:28 -0800118#endif
Elliott Hughes202f0242015-02-04 13:19:13 -0800119
Dan Albertc007bc32015-03-16 10:08:46 -0700120bool WriteStringToFile(const std::string& content, const std::string& path) {
Elliott Hughes470d79a2015-09-01 13:35:44 -0700121 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
122 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
Elliott Hughes202f0242015-02-04 13:19:13 -0800123 if (fd == -1) {
124 return false;
125 }
Elliott Hughesf682b472015-02-06 12:19:48 -0800126
127 bool result = WriteStringToFd(content, fd);
Nick Kralevich95db36e2015-05-20 08:59:21 -0700128 close(fd);
Elliott Hughesf682b472015-02-06 12:19:48 -0800129 return result || CleanUpAfterFailedWrite(path);
Elliott Hughes202f0242015-02-04 13:19:13 -0800130}
Dan Albertc007bc32015-03-16 10:08:46 -0700131
Elliott Hughes56085ed2015-04-24 21:57:16 -0700132bool ReadFully(int fd, void* data, size_t byte_count) {
133 uint8_t* p = reinterpret_cast<uint8_t*>(data);
134 size_t remaining = byte_count;
135 while (remaining > 0) {
136 ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
137 if (n <= 0) return false;
138 p += n;
139 remaining -= n;
140 }
141 return true;
142}
143
144bool WriteFully(int fd, const void* data, size_t byte_count) {
145 const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
146 size_t remaining = byte_count;
147 while (remaining > 0) {
148 ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
149 if (n == -1) return false;
150 p += n;
151 remaining -= n;
152 }
153 return true;
154}
155
Yabin Cuib6e314a2016-01-29 17:25:54 -0800156bool RemoveFileIfExists(const std::string& path, std::string* err) {
157 struct stat st;
158#if defined(_WIN32)
159 //TODO: Windows version can't handle symbol link correctly.
160 int result = stat(path.c_str(), &st);
161 bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
162#else
163 int result = lstat(path.c_str(), &st);
164 bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
165#endif
166 if (result == 0) {
167 if (!file_type_removable) {
168 if (err != nullptr) {
169 *err = "is not a regular or symbol link file";
170 }
171 return false;
172 }
173 if (unlink(path.c_str()) == -1) {
174 if (err != nullptr) {
175 *err = strerror(errno);
176 }
177 return false;
178 }
179 }
180 return true;
181}
182
Elliott Hughesd3ff6e52016-08-23 15:53:45 -0700183#if !defined(_WIN32)
184bool Readlink(const std::string& path, std::string* result) {
185 result->clear();
186
187 // Most Linux file systems (ext2 and ext4, say) limit symbolic links to
188 // 4095 bytes. Since we'll copy out into the string anyway, it doesn't
189 // waste memory to just start there. We add 1 so that we can recognize
190 // whether it actually fit (rather than being truncated to 4095).
191 std::vector<char> buf(4095 + 1);
192 while (true) {
193 ssize_t size = readlink(path.c_str(), &buf[0], buf.size());
194 // Unrecoverable error?
195 if (size == -1) return false;
196 // It fit! (If size == buf.size(), it may have been truncated.)
197 if (static_cast<size_t>(size) < buf.size()) {
198 result->assign(&buf[0], size);
199 return true;
200 }
201 // Double our buffer and try again.
202 buf.resize(buf.size() * 2);
203 }
204}
205#endif
206
Elliott Hughes82ff3152016-08-31 15:07:18 -0700207std::string GetExecutablePath() {
208#if defined(__linux__)
209 std::string path;
210 android::base::Readlink("/proc/self/exe", &path);
211 return path;
212#elif defined(__APPLE__)
213 // TODO: use _NSGetExecutablePath instead (http://b/31240820)?
214 CFBundleRef mainBundle = CFBundleGetMainBundle();
215 CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
216 CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
217 CFRelease(executableURL);
218
219 char path[PATH_MAX + 1];
220 CFStringGetFileSystemRepresentation(executablePathString, path, sizeof(PATH_MAX)-1);
221 CFRelease(executablePathString);
222 return path;
223#elif defined(_WIN32)
224 char path[PATH_MAX + 1];
225 DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
226 if (result == 0 || result == sizeof(path) - 1) return "";
227 path[PATH_MAX - 1] = 0;
228 return path;
229#else
230#error unknown OS
231#endif
232}
233
Dan Albertc007bc32015-03-16 10:08:46 -0700234} // namespace base
235} // namespace android