blob: 45ef65a3848d1a28b2787ff731df47551dfe717b [file] [log] [blame]
Christopher Wiley4a2884b2015-10-07 11:27:45 -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
17#include "io_delegate.h"
18
Christopher Wiley054afbd2015-10-16 17:08:43 -070019#include <cstring>
Christopher Wiley4a2884b2015-10-07 11:27:45 -070020#include <fstream>
Christopher Wiley054afbd2015-10-16 17:08:43 -070021#include <vector>
22
23#ifdef _WIN32
24#include <direct.h>
Steven Moreland21780812020-09-11 01:29:45 +000025#include <windows.h>
26#undef ERROR
Christopher Wiley054afbd2015-10-16 17:08:43 -070027#else
Jiyong Parke59c3682018-09-11 23:10:25 +090028#include <dirent.h>
Christopher Wiley054afbd2015-10-16 17:08:43 -070029#include <sys/stat.h>
Jiyong Parke59c3682018-09-11 23:10:25 +090030#include <sys/types.h>
Christopher Wiley9d6e0b22015-11-13 12:18:16 -080031#include <unistd.h>
Christopher Wiley054afbd2015-10-16 17:08:43 -070032#endif
33
Elliott Hughes0a620672015-12-04 13:53:18 -080034#include <android-base/strings.h>
Casey Dahlin64533512015-10-23 17:11:21 -070035
Christopher Wiley054afbd2015-10-16 17:08:43 -070036#include "logging.h"
37#include "os.h"
Christopher Wiley4a2884b2015-10-07 11:27:45 -070038
39using std::string;
40using std::unique_ptr;
Christopher Wiley054afbd2015-10-16 17:08:43 -070041using std::vector;
Christopher Wiley4a2884b2015-10-07 11:27:45 -070042
Steven Moreland6a945f32021-02-18 00:25:36 +000043using android::base::Error;
44using android::base::Result;
Casey Dahlin64533512015-10-23 17:11:21 -070045using android::base::Split;
46
Christopher Wiley4a2884b2015-10-07 11:27:45 -070047namespace android {
48namespace aidl {
49
Christopher Wiley8decf952016-06-02 16:27:26 -070050bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) {
51#ifdef _WIN32
52
53 char buf[4096];
54 DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr);
55 if (path_len <= 0 || path_len >= sizeof(buf)) {
Steven Moreland21780812020-09-11 01:29:45 +000056 AIDL_ERROR(path) << "Failed to GetFullPathName";
Christopher Wiley8decf952016-06-02 16:27:26 -070057 return false;
58 }
59 *absolute_path = buf;
60
61 return true;
62
63#else
64
65 if (path.empty()) {
Steven Moreland21780812020-09-11 01:29:45 +000066 AIDL_ERROR(path) << "Giving up on finding an absolute path to represent the empty string.";
Christopher Wiley8decf952016-06-02 16:27:26 -070067 return false;
68 }
69 if (path[0] == OS_PATH_SEPARATOR) {
70 *absolute_path = path;
71 return true;
72 }
73
74 char buf[4096];
75 if (getcwd(buf, sizeof(buf)) == nullptr) {
Steven Moreland21780812020-09-11 01:29:45 +000076 AIDL_ERROR(path) << "Path of current working directory does not fit in " << sizeof(buf)
77 << " bytes";
Christopher Wiley8decf952016-06-02 16:27:26 -070078 return false;
79 }
80
81 *absolute_path = buf;
82 *absolute_path += OS_PATH_SEPARATOR;
83 *absolute_path += path;
84 return true;
85#endif
86}
87
Christopher Wiley4a2884b2015-10-07 11:27:45 -070088unique_ptr<string> IoDelegate::GetFileContents(
89 const string& filename,
90 const string& content_suffix) const {
91 unique_ptr<string> contents;
92 std::ifstream in(filename, std::ios::in | std::ios::binary);
93 if (!in) {
94 return contents;
95 }
96 contents.reset(new string);
97 in.seekg(0, std::ios::end);
98 ssize_t file_size = in.tellg();
99 contents->resize(file_size + content_suffix.length());
100 in.seekg(0, std::ios::beg);
101 // Read the file contents into the beginning of the string
102 in.read(&(*contents)[0], file_size);
103 // Drop the suffix in at the end.
104 contents->replace(file_size, content_suffix.length(), content_suffix);
105 in.close();
106
107 return contents;
108}
109
Christopher Wileyef140932015-11-03 09:29:19 -0800110unique_ptr<LineReader> IoDelegate::GetLineReader(
111 const string& file_path) const {
112 return LineReader::ReadFromFile(file_path);
113}
114
Christopher Wiley72877ac2015-10-06 14:41:42 -0700115bool IoDelegate::FileIsReadable(const string& path) const {
116#ifdef _WIN32
117 // check that the file exists and is not write-only
118 return (0 == _access(path.c_str(), 0)) && // mode 0=exist
119 (0 == _access(path.c_str(), 4)); // mode 4=readable
120#else
121 return (0 == access(path.c_str(), R_OK));
122#endif
123}
Christopher Wiley054afbd2015-10-16 17:08:43 -0700124
Jiyong Park05463732018-08-09 16:03:02 +0900125static bool CreateNestedDirs(const string& caller_base_dir, const vector<string>& nested_subdirs) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700126 string base_dir = caller_base_dir;
127 if (base_dir.empty()) {
128 base_dir = ".";
129 }
130 for (const string& subdir : nested_subdirs) {
131 if (base_dir[base_dir.size() - 1] != OS_PATH_SEPARATOR) {
132 base_dir += OS_PATH_SEPARATOR;
133 }
134 base_dir += subdir;
135 bool success;
136#ifdef _WIN32
137 success = _mkdir(base_dir.c_str()) == 0;
138#else
139 success = mkdir(base_dir.c_str(),
140 S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
141#endif
Christopher Wiley3badcde2015-11-06 10:59:27 -0800142 // On darwin when you try to mkdir("/", ...) we get EISDIR.
143 if (!success && (errno != EEXIST && errno != EISDIR)) {
Steven Moreland21780812020-09-11 01:29:45 +0000144 AIDL_ERROR(caller_base_dir) << "Error while creating " << base_dir << ": " << strerror(errno);
Dan Albertd669de92016-04-15 13:42:41 -0700145 return false;
Christopher Wiley054afbd2015-10-16 17:08:43 -0700146 }
147 }
148 return true;
149}
150
Jiyong Park05463732018-08-09 16:03:02 +0900151bool IoDelegate::CreateDirForPath(const string& path) const {
Casey Dahlin64533512015-10-23 17:11:21 -0700152 if (path.empty()) {
153 return true;
154 }
155
Christopher Wiley8decf952016-06-02 16:27:26 -0700156 string absolute_path;
157 if (!GetAbsolutePath(path, &absolute_path)) {
158 return false;
Casey Dahlin64533512015-10-23 17:11:21 -0700159 }
160
Jiyong Park05463732018-08-09 16:03:02 +0900161 auto directories = Split(absolute_path, string{OS_PATH_SEPARATOR});
Casey Dahlin64533512015-10-23 17:11:21 -0700162
Christopher Wiley8decf952016-06-02 16:27:26 -0700163 // The "base" directory is just the root of the file system. On Windows,
164 // this will look like "C:\" but on Unix style file systems we get an empty
165 // string after splitting "/foo" with "/"
166 string base = directories[0];
167 if (base.empty()) {
168 base = "/";
169 }
170 directories.erase(directories.begin());
171
172 // Remove the actual file in question, we're just creating the directory path.
Jiyong Park05463732018-08-09 16:03:02 +0900173 bool is_file = path.back() != OS_PATH_SEPARATOR;
174 if (is_file) {
175 directories.pop_back();
176 }
Christopher Wiley8decf952016-06-02 16:27:26 -0700177
Jiyong Park05463732018-08-09 16:03:02 +0900178 return CreateNestedDirs(base, directories);
Casey Dahlin64533512015-10-23 17:11:21 -0700179}
180
Christopher Wiley054afbd2015-10-16 17:08:43 -0700181unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
182 const string& file_path) const {
Jiyong Park05463732018-08-09 16:03:02 +0900183 if (CreateDirForPath(file_path)) {
184 return CodeWriter::ForFile(file_path);
185 } else {
186 return nullptr;
187 }
Christopher Wiley054afbd2015-10-16 17:08:43 -0700188}
189
Christopher Wiley9d6e0b22015-11-13 12:18:16 -0800190void IoDelegate::RemovePath(const std::string& file_path) const {
191#ifdef _WIN32
192 _unlink(file_path.c_str());
193#else
194 unlink(file_path.c_str());
195#endif
196}
197
Jiyong Parke59c3682018-09-11 23:10:25 +0900198#ifdef _WIN32
Steven Moreland6a945f32021-02-18 00:25:36 +0000199Result<vector<string>> IoDelegate::ListFiles(const string&) const {
200 return Error() << "File listing not implemented on Windows";
Jiyong Parke59c3682018-09-11 23:10:25 +0900201}
202
203#else
Steven Moreland6a945f32021-02-18 00:25:36 +0000204static Result<void> add_list_files(const string& dirname, vector<string>* result) {
Steven Moreland21780812020-09-11 01:29:45 +0000205 AIDL_FATAL_IF(result == nullptr, dirname);
Jiyong Parke59c3682018-09-11 23:10:25 +0900206 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
Steven Moreland6a945f32021-02-18 00:25:36 +0000207
208 if (dir == nullptr) {
209 return Error() << "Failed to read directory '" << dirname << "': " << strerror(errno);
210 }
211
212 while (true) {
213 errno = 0;
214 struct dirent* ent = readdir(dir.get());
215 if (ent == nullptr) {
216 if (errno != 0) {
217 return Error() << "Failed to read directory entry in '" << dirname
218 << "': " << strerror(errno);
Jiyong Parke59c3682018-09-11 23:10:25 +0900219 }
Steven Moreland6a945f32021-02-18 00:25:36 +0000220 break;
221 }
222
223 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
224 continue;
225 }
226 if (ent->d_type == DT_REG) {
227 result->emplace_back(dirname + OS_PATH_SEPARATOR + ent->d_name);
228 } else if (ent->d_type == DT_DIR) {
229 if (auto ret = add_list_files(dirname + OS_PATH_SEPARATOR + ent->d_name, result); !ret.ok()) {
230 return ret;
Jiyong Parke59c3682018-09-11 23:10:25 +0900231 }
232 }
233 }
Steven Moreland6a945f32021-02-18 00:25:36 +0000234
235 return Result<void>();
Jiyong Parke59c3682018-09-11 23:10:25 +0900236}
237
Steven Moreland6a945f32021-02-18 00:25:36 +0000238Result<vector<string>> IoDelegate::ListFiles(const string& dir) const {
Jiyong Parke59c3682018-09-11 23:10:25 +0900239 vector<string> result;
Steven Moreland6a945f32021-02-18 00:25:36 +0000240 if (auto ret = add_list_files(dir, &result); !ret.ok()) {
241 return ret.error();
242 }
Jiyong Parke59c3682018-09-11 23:10:25 +0900243 return result;
244}
245#endif
246
Christopher Wiley4a2884b2015-10-07 11:27:45 -0700247} // namespace android
248} // namespace aidl