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 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 83 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 105 unique_ptr<LineReader> IoDelegate::GetLineReader( 106 const string& file_path) const { 107 return LineReader::ReadFromFile(file_path); 108 } 109 110 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 120 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 149 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 176 unique_ptr<CodeWriter> IoDelegate::GetCodeWriter( 177 const string& file_path) const { 178 return GetFileWriter(file_path); 179 } 180 181 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