Home | History | Annotate | Download | only in aidl
      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