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