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 <dirent.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #endif
31 
32 #include <android-base/strings.h>
33 
34 #include "logging.h"
35 #include "os.h"
36 
37 using std::string;
38 using std::unique_ptr;
39 using std::vector;
40 
41 using android::base::Split;
42 
43 namespace android {
44 namespace aidl {
45 
GetAbsolutePath(const string & path,string * absolute_path)46 bool 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 
GetFileContents(const string & filename,const string & content_suffix) const85 unique_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 
GetLineReader(const string & file_path) const107 unique_ptr<LineReader> IoDelegate::GetLineReader(
108     const string& file_path) const {
109   return LineReader::ReadFromFile(file_path);
110 }
111 
FileIsReadable(const string & path) const112 bool 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 }
121 
CreateNestedDirs(const string & caller_base_dir,const vector<string> & nested_subdirs)122 static bool CreateNestedDirs(const string& caller_base_dir, const vector<string>& nested_subdirs) {
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 
CreateDirForPath(const string & path) const149 bool IoDelegate::CreateDirForPath(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{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   bool is_file = path.back() != OS_PATH_SEPARATOR;
172   if (is_file) {
173     directories.pop_back();
174   }
175 
176   return CreateNestedDirs(base, directories);
177 }
178 
GetCodeWriter(const string & file_path) const179 unique_ptr<CodeWriter> IoDelegate::GetCodeWriter(
180     const string& file_path) const {
181   if (CreateDirForPath(file_path)) {
182     return CodeWriter::ForFile(file_path);
183   } else {
184     return nullptr;
185   }
186 }
187 
RemovePath(const std::string & file_path) const188 void 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 
196 #ifdef _WIN32
ListFiles(const string &) const197 vector<string> IoDelegate::ListFiles(const string&) const {
198   vector<string> result;
199   return result;
200 }
201 
202 #else
add_list_files(const string & dirname,vector<string> * result)203 static 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 
ListFiles(const string & dir) const220 vector<string> IoDelegate::ListFiles(const string& dir) const {
221   vector<string> result;
222   add_list_files(dir, &result);
223   return result;
224 }
225 #endif
226 
227 }  // namespace android
228 }  // namespace aidl
229