blob: 4e7ac82d1bea70c3f4a3b970d5177bce805eca14 [file] [log] [blame]
Dan Albertaac6b7c2015-03-16 10:08:46 -07001/*
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 Hughesb6351622015-12-04 22:00:26 -080017#include "android-base/file.h"
Dan Albertaac6b7c2015-03-16 10:08:46 -070018
19#include <errno.h>
20#include <fcntl.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23
24#include <string>
25
Elliott Hughesb6351622015-12-04 22:00:26 -080026#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
Elliott Hughes7d9a4792016-07-28 15:15:28 -070027#include "android-base/logging.h"
Elliott Hughesb6351622015-12-04 22:00:26 -080028#include "android-base/utf8.h"
Dan Albert5f770222015-03-26 23:33:28 -070029#include "utils/Compat.h"
Dan Albertaac6b7c2015-03-16 10:08:46 -070030
31namespace android {
32namespace base {
33
Elliott Hughes774d7f62015-11-11 18:02:29 +000034// Versions of standard library APIs that support UTF-8 strings.
35using namespace android::base::utf8;
36
Dan Albertaac6b7c2015-03-16 10:08:46 -070037bool ReadFdToString(int fd, std::string* content) {
38 content->clear();
39
40 char buf[BUFSIZ];
41 ssize_t n;
42 while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
43 content->append(buf, n);
44 }
45 return (n == 0) ? true : false;
46}
47
48bool ReadFileToString(const std::string& path, std::string* content) {
49 content->clear();
50
Elliott Hughesd5f8ae62015-09-01 13:35:44 -070051 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
Dan Albertaac6b7c2015-03-16 10:08:46 -070052 if (fd == -1) {
53 return false;
54 }
55 bool result = ReadFdToString(fd, content);
Nick Kralevich82921302015-05-20 08:59:21 -070056 close(fd);
Dan Albertaac6b7c2015-03-16 10:08:46 -070057 return result;
58}
59
60bool WriteStringToFd(const std::string& content, int fd) {
61 const char* p = content.data();
62 size_t left = content.size();
63 while (left > 0) {
64 ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
65 if (n == -1) {
66 return false;
67 }
68 p += n;
69 left -= n;
70 }
71 return true;
72}
73
74static bool CleanUpAfterFailedWrite(const std::string& path) {
75 // Something went wrong. Let's not leave a corrupt file lying around.
76 int saved_errno = errno;
77 unlink(path.c_str());
78 errno = saved_errno;
79 return false;
80}
81
82#if !defined(_WIN32)
83bool WriteStringToFile(const std::string& content, const std::string& path,
84 mode_t mode, uid_t owner, gid_t group) {
Elliott Hughesd5f8ae62015-09-01 13:35:44 -070085 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
86 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
Dan Albertaac6b7c2015-03-16 10:08:46 -070087 if (fd == -1) {
Elliott Hughes7d9a4792016-07-28 15:15:28 -070088 PLOG(ERROR) << "android::WriteStringToFile open failed";
Dan Albertaac6b7c2015-03-16 10:08:46 -070089 return false;
90 }
91
92 // We do an explicit fchmod here because we assume that the caller really
93 // meant what they said and doesn't want the umask-influenced mode.
94 if (fchmod(fd, mode) == -1) {
Elliott Hughes7d9a4792016-07-28 15:15:28 -070095 PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
Dan Albertaac6b7c2015-03-16 10:08:46 -070096 return CleanUpAfterFailedWrite(path);
97 }
98 if (fchown(fd, owner, group) == -1) {
Elliott Hughes7d9a4792016-07-28 15:15:28 -070099 PLOG(ERROR) << "android::WriteStringToFile fchown failed";
Dan Albertaac6b7c2015-03-16 10:08:46 -0700100 return CleanUpAfterFailedWrite(path);
101 }
102 if (!WriteStringToFd(content, fd)) {
Elliott Hughes7d9a4792016-07-28 15:15:28 -0700103 PLOG(ERROR) << "android::WriteStringToFile write failed";
Dan Albertaac6b7c2015-03-16 10:08:46 -0700104 return CleanUpAfterFailedWrite(path);
105 }
Nick Kralevich82921302015-05-20 08:59:21 -0700106 close(fd);
Dan Albertaac6b7c2015-03-16 10:08:46 -0700107 return true;
108}
109#endif
110
111bool WriteStringToFile(const std::string& content, const std::string& path) {
Elliott Hughesd5f8ae62015-09-01 13:35:44 -0700112 int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
113 int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
Dan Albertaac6b7c2015-03-16 10:08:46 -0700114 if (fd == -1) {
115 return false;
116 }
117
118 bool result = WriteStringToFd(content, fd);
Nick Kralevich82921302015-05-20 08:59:21 -0700119 close(fd);
Dan Albertaac6b7c2015-03-16 10:08:46 -0700120 return result || CleanUpAfterFailedWrite(path);
121}
122
Elliott Hughes20abc872015-04-24 21:57:16 -0700123bool ReadFully(int fd, void* data, size_t byte_count) {
124 uint8_t* p = reinterpret_cast<uint8_t*>(data);
125 size_t remaining = byte_count;
126 while (remaining > 0) {
127 ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
128 if (n <= 0) return false;
129 p += n;
130 remaining -= n;
131 }
132 return true;
133}
134
135bool WriteFully(int fd, const void* data, size_t byte_count) {
136 const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
137 size_t remaining = byte_count;
138 while (remaining > 0) {
139 ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
140 if (n == -1) return false;
141 p += n;
142 remaining -= n;
143 }
144 return true;
145}
146
Yabin Cui8f6a5a02016-01-29 17:25:54 -0800147bool RemoveFileIfExists(const std::string& path, std::string* err) {
148 struct stat st;
149#if defined(_WIN32)
150 //TODO: Windows version can't handle symbol link correctly.
151 int result = stat(path.c_str(), &st);
152 bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
153#else
154 int result = lstat(path.c_str(), &st);
155 bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
156#endif
157 if (result == 0) {
158 if (!file_type_removable) {
159 if (err != nullptr) {
160 *err = "is not a regular or symbol link file";
161 }
162 return false;
163 }
164 if (unlink(path.c_str()) == -1) {
165 if (err != nullptr) {
166 *err = strerror(errno);
167 }
168 return false;
169 }
170 }
171 return true;
172}
173
Dan Albertaac6b7c2015-03-16 10:08:46 -0700174} // namespace base
175} // namespace android