1 /*
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
19 #include <cstring>
20 #include <fstream>
21 #include <vector>
22
23 #ifdef _WIN32
24 #include <direct.h>
25 #else
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #endif
29
30 #include <android-base/strings.h>
31
32 #include "logging.h"
33 #include "os.h"
34
35 using std::string;
36 using std::unique_ptr;
37 using std::vector;
38
39 using android::base::Split;
40
41 namespace android {
42 namespace aidl {
43
GetAbsolutePath(const string & path,string * absolute_path)44 bool IoDelegate::GetAbsolutePath(const string& path, string* absolute_path) {
45 #ifdef _WIN32
46
47 char buf[4096];
48 DWORD path_len = GetFullPathName(path.c_str(), sizeof(buf), buf, nullptr);
49 if (path_len <= 0 || path_len >= sizeof(buf)) {
50 LOG(ERROR) << "Failed to GetFullPathName(" << path << ")";
51 return false;
52 }
53 *absolute_path = buf;
54
55 return true;
56
57 #else
58
59 if (path.empty()) {
60 LOG(ERROR) << "Giving up on finding an absolute path to represent the "
61 "empty string.";
62 return false;
63 }
64 if (path[0] == OS_PATH_SEPARATOR) {
65 *absolute_path = path;
66 return true;
67 }
68
69 char buf[4096];
70 if (getcwd(buf, sizeof(buf)) == nullptr) {
71 LOG(ERROR) << "Path of current working directory does not fit in "
72 << sizeof(buf) << " bytes";
73 return false;
74 }
75
76 *absolute_path = buf;
77 *absolute_path += OS_PATH_SEPARATOR;
78 *absolute_path += path;
79 return true;
80 #endif
81 }
82
GetFileContents(const string & filename,const string & content_suffix) const83 unique_ptr<string> IoDelegate::GetFileContents(
84 const string& filename,
85 const string& content_suffix) const {
86 unique_ptr<string> contents;
87 std::ifstream in(filename, std::ios::in | std::ios::binary);
88 if (!in) {
89 return contents;
90 }
91 contents.reset(new string);
92 in.seekg(0, std::ios::end);
93 ssize_t file_size = in.tellg();
94 contents->resize(file_size + content_suffix.length());
95 in.seekg(0, std::ios::beg);
96 // Read the file contents into the beginning of the string
97 in.read(&(*contents)[0], file_size);
98 // Drop the suffix in at the end.
99 contents->replace(file_size, content_suffix.length(), content_suffix);
100 in.close();
101
102 return contents;
103 }
104
GetLineReader(const string & file_path) const105 unique_ptr<LineReader> IoDelegate::GetLineReader(
106 const string& file_path) const {
107 return LineReader::ReadFromFile(file_path);
108 }
109
FileIsReadable(const string & path) const110 bool IoDelegate::FileIsReadable(const string& path) const {
111 #ifdef _WIN32
112 // check that the file exists and is not write-only
113 return (0 == _access(path.c_str(), 0)) && // mode 0=exist
114 (0 == _access(path.c_str(), 4)); // mode 4=readable
115 #else
116 return (0 == access(path.c_str(), R_OK));
117 #endif
118 }
119
CreatedNestedDirs(const string & caller_base_dir,const vector<string> & nested_subdirs) const120 bool IoDelegate::CreatedNestedDirs(
121 const string& caller_base_dir,
122 const vector<string>& nested_subdirs) const {
123 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
139 // On darwin when you try to mkdir("/", ...) we get EISDIR.
140 if (!success && (errno != EEXIST && errno != EISDIR)) {
141 LOG(ERROR) << "Error while creating " << base_dir << ": "
142 << strerror(errno);
143 return false;
144 }
145 }
146 return true;
147 }
148
CreatePathForFile(const string & path) const149 bool IoDelegate::CreatePathForFile(const string& path) const {
150 if (path.empty()) {
151 return true;
152 }
153
154 string absolute_path;
155 if (!GetAbsolutePath(path, &absolute_path)) {
156 return false;
157 }
158
159 auto directories = Split(absolute_path, string{1u, OS_PATH_SEPARATOR});
160
161 // 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.
171 directories.pop_back();
172
173 return CreatedNestedDirs(base, directories);
174 }
175
GetCodeWriter(const string & file_path) const176 unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
177 const string& file_path) const {
178 return GetFileWriter(file_path);
179 }
180
RemovePath(const std::string & file_path) const181 void IoDelegate::RemovePath(const std::string& file_path) const {
182 #ifdef _WIN32
183 _unlink(file_path.c_str());
184 #else
185 unlink(file_path.c_str());
186 #endif
187 }
188
189 } // namespace android
190 } // namespace aidl
191