blob: 4b2e00a0d53ea690bb5b1f6693c584e8984716bf [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>
25#else
Jiyong Parke59c3682018-09-11 23:10:25 +090026#include <dirent.h>
Christopher Wiley054afbd2015-10-16 17:08:43 -070027#include <sys/stat.h>
Jiyong Parke59c3682018-09-11 23:10:25 +090028#include <sys/types.h>
Christopher Wiley9d6e0b22015-11-13 12:18:16 -080029#include <unistd.h>
Christopher Wiley054afbd2015-10-16 17:08:43 -070030#endif
31
Elliott Hughes0a620672015-12-04 13:53:18 -080032#include <android-base/strings.h>
Casey Dahlin64533512015-10-23 17:11:21 -070033
Christopher Wiley054afbd2015-10-16 17:08:43 -070034#include "logging.h"
35#include "os.h"
Christopher Wiley4a2884b2015-10-07 11:27:45 -070036
37using std::string;
38using std::unique_ptr;
Christopher Wiley054afbd2015-10-16 17:08:43 -070039using std::vector;
Christopher Wiley4a2884b2015-10-07 11:27:45 -070040
Casey Dahlin64533512015-10-23 17:11:21 -070041using android::base::Split;
42
Christopher Wiley4a2884b2015-10-07 11:27:45 -070043namespace android {
44namespace aidl {
45
Christopher Wiley8decf952016-06-02 16:27:26 -070046bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) {
47#ifdef _WIN32
48
49 char buf[4096];
50 DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr);
51 if (path_len <= 0 || path_len >= sizeof(buf)) {
52 LOG(ERROR) << "Failed to GetFullPathName(" << path << ")";
53 return false;
54 }
55 *absolute_path = buf;
56
57 return true;
58
59#else
60
61 if (path.empty()) {
62 LOG(ERROR) << "Giving up on finding an absolute path to represent the "
63 "empty string.";
64 return false;
65 }
66 if (path[0] == OS_PATH_SEPARATOR) {
67 *absolute_path = path;
68 return true;
69 }
70
71 char buf[4096];
72 if (getcwd(buf, sizeof(buf)) == nullptr) {
73 LOG(ERROR) << "Path of current working directory does not fit in "
74 << sizeof(buf) << " bytes";
75 return false;
76 }
77
78 *absolute_path = buf;
79 *absolute_path += OS_PATH_SEPARATOR;
80 *absolute_path += path;
81 return true;
82#endif
83}
84
Christopher Wiley4a2884b2015-10-07 11:27:45 -070085unique_ptr<string> IoDelegate::GetFileContents(
86 const string& filename,
87 const string& content_suffix) const {
88 unique_ptr<string> contents;
89 std::ifstream in(filename, std::ios::in | std::ios::binary);
90 if (!in) {
91 return contents;
92 }
93 contents.reset(new string);
94 in.seekg(0, std::ios::end);
95 ssize_t file_size = in.tellg();
96 contents->resize(file_size + content_suffix.length());
97 in.seekg(0, std::ios::beg);
98 // Read the file contents into the beginning of the string
99 in.read(&(*contents)[0], file_size);
100 // Drop the suffix in at the end.
101 contents->replace(file_size, content_suffix.length(), content_suffix);
102 in.close();
103
104 return contents;
105}
106
Christopher Wileyef140932015-11-03 09:29:19 -0800107unique_ptr<LineReader> IoDelegate::GetLineReader(
108 const string& file_path) const {
109 return LineReader::ReadFromFile(file_path);
110}
111
Christopher Wiley72877ac2015-10-06 14:41:42 -0700112bool IoDelegate::FileIsReadable(const string& path) const {
113#ifdef _WIN32
114 // check that the file exists and is not write-only
115 return (0 == _access(path.c_str(), 0)) && // mode 0=exist
116 (0 == _access(path.c_str(), 4)); // mode 4=readable
117#else
118 return (0 == access(path.c_str(), R_OK));
119#endif
120}
Christopher Wiley054afbd2015-10-16 17:08:43 -0700121
Jiyong Park05463732018-08-09 16:03:02 +0900122static bool CreateNestedDirs(const string& caller_base_dir, const vector<string>& nested_subdirs) {
Christopher Wiley054afbd2015-10-16 17:08:43 -0700123 string base_dir = caller_base_dir;
124 if (base_dir.empty()) {
125 base_dir = ".";
126 }
127 for (const string& subdir : nested_subdirs) {
128 if (base_dir[base_dir.size() - 1] != OS_PATH_SEPARATOR) {
129 base_dir += OS_PATH_SEPARATOR;
130 }
131 base_dir += subdir;
132 bool success;
133#ifdef _WIN32
134 success = _mkdir(base_dir.c_str()) == 0;
135#else
136 success = mkdir(base_dir.c_str(),
137 S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
138#endif
Christopher Wiley3badcde2015-11-06 10:59:27 -0800139 // On darwin when you try to mkdir("/", ...) we get EISDIR.
140 if (!success && (errno != EEXIST && errno != EISDIR)) {
Dan Albertd669de92016-04-15 13:42:41 -0700141 LOG(ERROR) << "Error while creating " << base_dir << ": "
142 << strerror(errno);
143 return false;
Christopher Wiley054afbd2015-10-16 17:08:43 -0700144 }
145 }
146 return true;
147}
148
Jiyong Park05463732018-08-09 16:03:02 +0900149bool IoDelegate::CreateDirForPath(const string& path) const {
Casey Dahlin64533512015-10-23 17:11:21 -0700150 if (path.empty()) {
151 return true;
152 }
153
Christopher Wiley8decf952016-06-02 16:27:26 -0700154 string absolute_path;
155 if (!GetAbsolutePath(path, &absolute_path)) {
156 return false;
Casey Dahlin64533512015-10-23 17:11:21 -0700157 }
158
Jiyong Park05463732018-08-09 16:03:02 +0900159 auto directories = Split(absolute_path, string{OS_PATH_SEPARATOR});
Casey Dahlin64533512015-10-23 17:11:21 -0700160
Christopher Wiley8decf952016-06-02 16:27:26 -0700161 // The "base" directory is just the root of the file system. On Windows,
162 // this will look like "C:\" but on Unix style file systems we get an empty
163 // string after splitting "/foo" with "/"
164 string base = directories[0];
165 if (base.empty()) {
166 base = "/";
167 }
168 directories.erase(directories.begin());
169
170 // Remove the actual file in question, we're just creating the directory path.
Jiyong Park05463732018-08-09 16:03:02 +0900171 bool is_file = path.back() != OS_PATH_SEPARATOR;
172 if (is_file) {
173 directories.pop_back();
174 }
Christopher Wiley8decf952016-06-02 16:27:26 -0700175
Jiyong Park05463732018-08-09 16:03:02 +0900176 return CreateNestedDirs(base, directories);
Casey Dahlin64533512015-10-23 17:11:21 -0700177}
178
Christopher Wiley054afbd2015-10-16 17:08:43 -0700179unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
180 const string& file_path) const {
Jiyong Park05463732018-08-09 16:03:02 +0900181 if (CreateDirForPath(file_path)) {
182 return CodeWriter::ForFile(file_path);
183 } else {
184 return nullptr;
185 }
Christopher Wiley054afbd2015-10-16 17:08:43 -0700186}
187
Christopher Wiley9d6e0b22015-11-13 12:18:16 -0800188void IoDelegate::RemovePath(const std::string& file_path) const {
189#ifdef _WIN32
190 _unlink(file_path.c_str());
191#else
192 unlink(file_path.c_str());
193#endif
194}
195
Jiyong Parke59c3682018-09-11 23:10:25 +0900196#ifdef _WIN32
197vector<string> IoDelegate::ListFiles(const string&) const {
198 vector<string> result;
199 return result;
200}
201
202#else
203static void add_list_files(const string& dirname, vector<string>* result) {
204 CHECK(result != nullptr);
205 std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
206 if (dir != nullptr) {
207 while (struct dirent* ent = readdir(dir.get())) {
208 if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
209 continue;
210 }
211 if (ent->d_type == DT_REG) {
212 result->emplace_back(dirname + OS_PATH_SEPARATOR + ent->d_name);
213 } else if (ent->d_type == DT_DIR) {
214 add_list_files(dirname + OS_PATH_SEPARATOR + ent->d_name, result);
215 }
216 }
217 }
218}
219
220vector<string> IoDelegate::ListFiles(const string& dir) const {
221 vector<string> result;
222 add_list_files(dir, &result);
223 return result;
224}
225#endif
226
Christopher Wiley4a2884b2015-10-07 11:27:45 -0700227} // namespace android
228} // namespace aidl