• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <windows.h>
26 #undef ERROR
27 #else
28 #include <dirent.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 #endif
33 
34 #include <android-base/strings.h>
35 
36 #include "logging.h"
37 #include "os.h"
38 
39 using std::string;
40 using std::unique_ptr;
41 using std::vector;
42 
43 using android::base::Error;
44 using android::base::Result;
45 using android::base::Split;
46 
47 namespace android {
48 namespace aidl {
49 
GetAbsolutePath(const string & path,string * absolute_path)50 bool 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)) {
56     AIDL_ERROR(path) << "Failed to GetFullPathName";
57     return false;
58   }
59   *absolute_path = buf;
60 
61   return true;
62 
63 #else
64 
65   if (path.empty()) {
66     AIDL_ERROR(path) << "Giving up on finding an absolute path to represent the empty string.";
67     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) {
76     AIDL_ERROR(path) << "Path of current working directory does not fit in " << sizeof(buf)
77                      << " bytes";
78     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 
GetFileContents(const string & filename,const string & content_suffix) const88 unique_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 
GetLineReader(const string & file_path) const110 unique_ptr<LineReader> IoDelegate::GetLineReader(
111     const string& file_path) const {
112   return LineReader::ReadFromFile(file_path);
113 }
114 
FileIsReadable(const string & path) const115 bool 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 }
124 
CreateNestedDirs(const string & caller_base_dir,const vector<string> & nested_subdirs)125 static bool CreateNestedDirs(const string& caller_base_dir, const vector<string>& nested_subdirs) {
126   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
142     // On darwin when you try to mkdir("/", ...) we get EISDIR.
143     if (!success && (errno != EEXIST && errno != EISDIR)) {
144       AIDL_ERROR(caller_base_dir) << "Error while creating " << base_dir << ": " << strerror(errno);
145       return false;
146     }
147   }
148   return true;
149 }
150 
CreateDirForPath(const string & path) const151 bool IoDelegate::CreateDirForPath(const string& path) const {
152   if (path.empty()) {
153     return true;
154   }
155 
156   string absolute_path;
157   if (!GetAbsolutePath(path, &absolute_path)) {
158     return false;
159   }
160 
161   auto directories = Split(absolute_path, string{OS_PATH_SEPARATOR});
162 
163   // 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.
173   bool is_file = path.back() != OS_PATH_SEPARATOR;
174   if (is_file) {
175     directories.pop_back();
176   }
177 
178   return CreateNestedDirs(base, directories);
179 }
180 
GetCodeWriter(const string & file_path) const181 unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
182     const string& file_path) const {
183   if (CreateDirForPath(file_path)) {
184     return CodeWriter::ForFile(file_path);
185   } else {
186     return nullptr;
187   }
188 }
189 
RemovePath(const std::string & file_path) const190 void 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 
198 #ifdef _WIN32
ListFiles(const string &) const199 Result<vector<string>> IoDelegate::ListFiles(const string&) const {
200   return Error() << "File listing not implemented on Windows";
201 }
202 
203 #else
add_list_files(const string & dirname,vector<string> * result)204 static Result<void> add_list_files(const string& dirname, vector<string>* result) {
205   AIDL_FATAL_IF(result == nullptr, dirname);
206   std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname.c_str()), closedir);
207 
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);
219       }
220       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;
231       }
232     }
233   }
234 
235   return Result<void>();
236 }
237 
ListFiles(const string & dir) const238 Result<vector<string>> IoDelegate::ListFiles(const string& dir) const {
239   vector<string> result;
240   if (auto ret = add_list_files(dir, &result); !ret.ok()) {
241     return ret.error();
242   }
243   return result;
244 }
245 #endif
246 
247 }  // namespace android
248 }  // namespace aidl
249