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 35using std::string; 36using std::unique_ptr; 37using std::vector; 38 39using android::base::Split; 40 41namespace android { 42namespace aidl { 43 44bool 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 83unique_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 105unique_ptr<LineReader> IoDelegate::GetLineReader( 106 const string& file_path) const { 107 return LineReader::ReadFromFile(file_path); 108} 109 110bool 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 120bool 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 149bool 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 176unique_ptr<CodeWriter> IoDelegate::GetCodeWriter( 177 const string& file_path) const { 178 return GetFileWriter(file_path); 179} 180 181void 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