1/* 2 * Copyright (C) 2016 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 "util.h" 18 19#include <sys/types.h> 20#include <sys/stat.h> 21#include <dirent.h> 22#include <string.h> 23#include <unistd.h> 24 25 26FileInfo::FileInfo() 27{ 28 memset(this, 0, sizeof(FileInfo)); 29} 30 31FileInfo::FileInfo(const FileInfo& that) 32{ 33 memcpy(this, &that, sizeof(FileInfo)); 34} 35 36FileInfo::FileInfo(const string& filename) 37{ 38 struct stat st; 39 int err = stat(filename.c_str(), &st); 40 if (err != 0) { 41 memset(this, 0, sizeof(FileInfo)); 42 } else { 43 exists = true; 44 mtime = st.st_mtime; 45 ctime = st.st_ctime; 46 size = st.st_size; 47 } 48} 49 50bool 51FileInfo::operator==(const FileInfo& that) const 52{ 53 return exists == that.exists 54 && mtime == that.mtime 55 && ctime == that.ctime 56 && size == that.size; 57} 58 59bool 60FileInfo::operator!=(const FileInfo& that) const 61{ 62 return exists != that.exists 63 || mtime != that.mtime 64 || ctime != that.ctime 65 || size != that.size; 66} 67 68FileInfo::~FileInfo() 69{ 70} 71 72TrackedFile::TrackedFile() 73 :filename(), 74 fileInfo() 75{ 76} 77 78TrackedFile::TrackedFile(const TrackedFile& that) 79{ 80 filename = that.filename; 81 fileInfo = that.fileInfo; 82} 83 84TrackedFile::TrackedFile(const string& file) 85 :filename(file), 86 fileInfo(file) 87{ 88} 89 90TrackedFile::~TrackedFile() 91{ 92} 93 94bool 95TrackedFile::HasChanged() const 96{ 97 FileInfo updated(filename); 98 return !updated.exists || fileInfo != updated; 99} 100 101void 102get_directory_contents(const string& name, map<string,FileInfo>* results) 103{ 104 DIR* dir = opendir(name.c_str()); 105 if (dir == NULL) { 106 return; 107 } 108 109 dirent* entry; 110 while ((entry = readdir(dir)) != NULL) { 111 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 112 continue; 113 } 114 if (entry->d_type == DT_DIR) { 115 string subdir = name + "/" + entry->d_name; 116 get_directory_contents(subdir, results); 117 } else if (entry->d_type == DT_LNK || entry->d_type == DT_REG) { 118 string filename(name + "/" + entry->d_name); 119 (*results)[filename] = FileInfo(filename); 120 } 121 } 122 123 closedir(dir); 124} 125 126bool 127directory_contents_differ(const map<string,FileInfo>& before, const map<string,FileInfo>& after) 128{ 129 if (before.size() != after.size()) { 130 return true; 131 } 132 map<string,FileInfo>::const_iterator b = before.begin(); 133 map<string,FileInfo>::const_iterator a = after.begin(); 134 while (b != before.end() && a != after.end()) { 135 if (b->first != a->first) { 136 return true; 137 } 138 if (a->second != b->second) { 139 return true; 140 } 141 a++; 142 b++; 143 } 144 return false; 145} 146 147string 148escape_quotes(const char* str) 149{ 150 string result; 151 while (*str) { 152 if (*str == '"') { 153 result += '\\'; 154 result += '"'; 155 } else { 156 result += *str; 157 } 158 } 159 return result; 160} 161 162string 163escape_for_commandline(const char* str) 164{ 165 if (strchr(str, '"') != NULL || strchr(str, ' ') != NULL 166 || strchr(str, '\t') != NULL) { 167 return escape_quotes(str); 168 } else { 169 return str; 170 } 171} 172 173static bool 174spacechr(char c) 175{ 176 return c == ' ' || c == '\t' || c == '\n' || c == '\r'; 177} 178 179string 180trim(const string& str) 181{ 182 const ssize_t N = (ssize_t)str.size(); 183 ssize_t begin = 0; 184 while (begin < N && spacechr(str[begin])) { 185 begin++; 186 } 187 ssize_t end = N - 1; 188 while (end >= begin && spacechr(str[end])) { 189 end--; 190 } 191 return string(str, begin, end-begin+1); 192} 193 194bool 195starts_with(const string& str, const string& prefix) 196{ 197 return str.compare(0, prefix.length(), prefix) == 0; 198} 199 200bool 201ends_with(const string& str, const string& suffix) 202{ 203 if (str.length() < suffix.length()) { 204 return false; 205 } else { 206 return str.compare(str.length()-suffix.length(), suffix.length(), suffix) == 0; 207 } 208} 209 210void 211split_lines(vector<string>* result, const string& str) 212{ 213 const int N = str.length(); 214 int begin = 0; 215 int end = 0; 216 for (; end < N; end++) { 217 const char c = str[end]; 218 if (c == '\r' || c == '\n') { 219 if (begin != end) { 220 result->push_back(string(str, begin, end-begin)); 221 } 222 begin = end+1; 223 } 224 } 225 if (begin != end) { 226 result->push_back(string(str, begin, end-begin)); 227 } 228} 229 230string 231read_file(const string& filename) 232{ 233 FILE* file = fopen(filename.c_str(), "r"); 234 if (file == NULL) { 235 return string(); 236 } 237 238 fseek(file, 0, SEEK_END); 239 int size = ftell(file); 240 fseek(file, 0, SEEK_SET); 241 242 char* buf = (char*)malloc(size); 243 if ((size_t) size != fread(buf, 1, size, file)) { 244 return string(); 245 } 246 247 string result(buf, size); 248 249 free(buf); 250 fclose(file); 251 252 return result; 253} 254 255 256