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 "utils.h"
18
19#include <dirent.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdarg.h>
23#include <stdio.h>
24#include <sys/stat.h>
25#include <unistd.h>
26
27#include <algorithm>
28#include <map>
29#include <string>
30
31#include <android-base/file.h>
32#include <android-base/logging.h>
33
34void OneTimeFreeAllocator::Clear() {
35  for (auto& p : v_) {
36    delete[] p;
37  }
38  v_.clear();
39  cur_ = nullptr;
40  end_ = nullptr;
41}
42
43const char* OneTimeFreeAllocator::AllocateString(const std::string& s) {
44  size_t size = s.size() + 1;
45  if (cur_ + size > end_) {
46    size_t alloc_size = std::max(size, unit_size_);
47    char* p = new char[alloc_size];
48    v_.push_back(p);
49    cur_ = p;
50    end_ = p + alloc_size;
51  }
52  strcpy(cur_, s.c_str());
53  const char* result = cur_;
54  cur_ += size;
55  return result;
56}
57
58
59FileHelper FileHelper::OpenReadOnly(const std::string& filename) {
60    int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY | O_BINARY));
61    return FileHelper(fd);
62}
63
64FileHelper FileHelper::OpenWriteOnly(const std::string& filename) {
65    int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_BINARY | O_CREAT, 0644));
66    return FileHelper(fd);
67}
68
69FileHelper::~FileHelper() {
70  if (fd_ != -1) {
71    close(fd_);
72  }
73}
74
75ArchiveHelper::ArchiveHelper(int fd, const std::string& debug_filename) : valid_(false) {
76  int rc = OpenArchiveFd(fd, "", &handle_, false);
77  if (rc == 0) {
78    valid_ = true;
79  } else {
80    LOG(ERROR) << "Failed to open archive " << debug_filename << ": " << ErrorCodeString(rc);
81  }
82}
83
84ArchiveHelper::~ArchiveHelper() {
85  if (valid_) {
86    CloseArchive(handle_);
87  }
88}
89
90void PrintIndented(size_t indent, const char* fmt, ...) {
91  va_list ap;
92  va_start(ap, fmt);
93  printf("%*s", static_cast<int>(indent * 2), "");
94  vprintf(fmt, ap);
95  va_end(ap);
96}
97
98bool IsPowerOfTwo(uint64_t value) {
99  return (value != 0 && ((value & (value - 1)) == 0));
100}
101
102void GetEntriesInDir(const std::string& dirpath, std::vector<std::string>* files,
103                     std::vector<std::string>* subdirs) {
104  if (files != nullptr) {
105    files->clear();
106  }
107  if (subdirs != nullptr) {
108    subdirs->clear();
109  }
110  DIR* dir = opendir(dirpath.c_str());
111  if (dir == nullptr) {
112    PLOG(DEBUG) << "can't open dir " << dirpath;
113    return;
114  }
115  dirent* entry;
116  while ((entry = readdir(dir)) != nullptr) {
117    if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
118      continue;
119    }
120    if (IsDir(dirpath + std::string("/") + entry->d_name)) {
121      if (subdirs != nullptr) {
122        subdirs->push_back(entry->d_name);
123      }
124    } else {
125      if (files != nullptr) {
126        files->push_back(entry->d_name);
127      }
128    }
129  }
130  closedir(dir);
131}
132
133bool IsDir(const std::string& dirpath) {
134  struct stat st;
135  if (stat(dirpath.c_str(), &st) == 0) {
136    if (S_ISDIR(st.st_mode)) {
137      return true;
138    }
139  }
140  return false;
141}
142
143bool IsRegularFile(const std::string& filename) {
144  struct stat st;
145  if (stat(filename.c_str(), &st) == 0) {
146    if (S_ISREG(st.st_mode)) {
147      return true;
148    }
149  }
150  return false;
151}
152
153uint64_t GetFileSize(const std::string& filename) {
154  struct stat st;
155  if (stat(filename.c_str(), &st) == 0) {
156    return static_cast<uint64_t>(st.st_size);
157  }
158  return 0;
159}
160
161bool MkdirWithParents(const std::string& path) {
162  size_t prev_end = 0;
163  while (prev_end < path.size()) {
164    size_t next_end = path.find('/', prev_end + 1);
165    if (next_end == std::string::npos) {
166      break;
167    }
168    std::string dir_path = path.substr(0, next_end);
169    if (!IsDir(dir_path)) {
170#if defined(_WIN32)
171      int ret = mkdir(dir_path.c_str());
172#else
173      int ret = mkdir(dir_path.c_str(), 0755);
174#endif
175      if (ret != 0) {
176        PLOG(ERROR) << "failed to create dir " << dir_path;
177        return false;
178      }
179    }
180    prev_end = next_end;
181  }
182  return true;
183}
184
185bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) {
186  static std::map<std::string, android::base::LogSeverity> log_severity_map = {
187      {"verbose", android::base::VERBOSE},
188      {"debug", android::base::DEBUG},
189      {"warning", android::base::WARNING},
190      {"error", android::base::ERROR},
191      {"fatal", android::base::FATAL},
192  };
193  auto it = log_severity_map.find(name);
194  if (it != log_severity_map.end()) {
195    *severity = it->second;
196    return true;
197  }
198  return false;
199}
200
201bool IsRoot() {
202  static int is_root = -1;
203  if (is_root == -1) {
204#if defined(__linux__)
205    is_root = (getuid() == 0) ? 1 : 0;
206#else
207    is_root = 0;
208#endif
209  }
210  return is_root == 1;
211}
212