You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
5.3 KiB
254 lines
5.3 KiB
/* |
|
* Copyright (C) 2016 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#include "util.h" |
|
|
|
#include <sys/types.h> |
|
#include <sys/stat.h> |
|
#include <dirent.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
|
|
FileInfo::FileInfo() |
|
{ |
|
memset(this, 0, sizeof(FileInfo)); |
|
} |
|
|
|
FileInfo::FileInfo(const FileInfo& that) |
|
{ |
|
memcpy(this, &that, sizeof(FileInfo)); |
|
} |
|
|
|
FileInfo::FileInfo(const string& filename) |
|
{ |
|
struct stat st; |
|
int err = stat(filename.c_str(), &st); |
|
if (err != 0) { |
|
memset(this, 0, sizeof(FileInfo)); |
|
} else { |
|
exists = true; |
|
mtime = st.st_mtime; |
|
ctime = st.st_ctime; |
|
size = st.st_size; |
|
} |
|
} |
|
|
|
bool |
|
FileInfo::operator==(const FileInfo& that) const |
|
{ |
|
return exists == that.exists |
|
&& mtime == that.mtime |
|
&& ctime == that.ctime |
|
&& size == that.size; |
|
} |
|
|
|
bool |
|
FileInfo::operator!=(const FileInfo& that) const |
|
{ |
|
return exists != that.exists |
|
|| mtime != that.mtime |
|
|| ctime != that.ctime |
|
|| size != that.size; |
|
} |
|
|
|
FileInfo::~FileInfo() |
|
{ |
|
} |
|
|
|
TrackedFile::TrackedFile() |
|
:filename(), |
|
fileInfo() |
|
{ |
|
} |
|
|
|
TrackedFile::TrackedFile(const TrackedFile& that) |
|
{ |
|
filename = that.filename; |
|
fileInfo = that.fileInfo; |
|
} |
|
|
|
TrackedFile::TrackedFile(const string& file) |
|
:filename(file), |
|
fileInfo(file) |
|
{ |
|
} |
|
|
|
TrackedFile::~TrackedFile() |
|
{ |
|
} |
|
|
|
bool |
|
TrackedFile::HasChanged() const |
|
{ |
|
FileInfo updated(filename); |
|
return !updated.exists || fileInfo != updated; |
|
} |
|
|
|
void |
|
get_directory_contents(const string& name, map<string,FileInfo>* results) |
|
{ |
|
int err; |
|
DIR* dir = opendir(name.c_str()); |
|
if (dir == NULL) { |
|
return; |
|
} |
|
|
|
dirent* entry; |
|
while ((entry = readdir(dir)) != NULL) { |
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { |
|
continue; |
|
} |
|
if (entry->d_type == DT_DIR) { |
|
string subdir = name + "/" + entry->d_name; |
|
get_directory_contents(subdir, results); |
|
} else if (entry->d_type == DT_LNK || entry->d_type == DT_REG) { |
|
string filename(name + "/" + entry->d_name); |
|
(*results)[filename] = FileInfo(filename); |
|
} |
|
} |
|
|
|
closedir(dir); |
|
} |
|
|
|
bool |
|
directory_contents_differ(const map<string,FileInfo>& before, const map<string,FileInfo>& after) |
|
{ |
|
if (before.size() != after.size()) { |
|
return true; |
|
} |
|
map<string,FileInfo>::const_iterator b = before.begin(); |
|
map<string,FileInfo>::const_iterator a = after.begin(); |
|
while (b != before.end() && a != after.end()) { |
|
if (b->first != a->first) { |
|
return true; |
|
} |
|
if (a->second != b->second) { |
|
return true; |
|
} |
|
a++; |
|
b++; |
|
} |
|
return false; |
|
} |
|
|
|
string |
|
escape_quotes(const char* str) |
|
{ |
|
string result; |
|
while (*str) { |
|
if (*str == '"') { |
|
result += '\\'; |
|
result += '"'; |
|
} else { |
|
result += *str; |
|
} |
|
} |
|
return result; |
|
} |
|
|
|
string |
|
escape_for_commandline(const char* str) |
|
{ |
|
if (strchr(str, '"') != NULL || strchr(str, ' ') != NULL |
|
|| strchr(str, '\t') != NULL) { |
|
return escape_quotes(str); |
|
} else { |
|
return str; |
|
} |
|
} |
|
|
|
static bool |
|
spacechr(char c) |
|
{ |
|
return c == ' ' || c == '\t' || c == '\n' || c == '\r'; |
|
} |
|
|
|
string |
|
trim(const string& str) |
|
{ |
|
const ssize_t N = (ssize_t)str.size(); |
|
ssize_t begin = 0; |
|
while (begin < N && spacechr(str[begin])) { |
|
begin++; |
|
} |
|
ssize_t end = N - 1; |
|
while (end >= begin && spacechr(str[end])) { |
|
end--; |
|
} |
|
return string(str, begin, end-begin+1); |
|
} |
|
|
|
bool |
|
starts_with(const string& str, const string& prefix) |
|
{ |
|
return str.compare(0, prefix.length(), prefix) == 0; |
|
} |
|
|
|
bool |
|
ends_with(const string& str, const string& suffix) |
|
{ |
|
if (str.length() < suffix.length()) { |
|
return false; |
|
} else { |
|
return str.compare(str.length()-suffix.length(), suffix.length(), suffix) == 0; |
|
} |
|
} |
|
|
|
void |
|
split_lines(vector<string>* result, const string& str) |
|
{ |
|
const int N = str.length(); |
|
int begin = 0; |
|
int end = 0; |
|
for (; end < N; end++) { |
|
const char c = str[end]; |
|
if (c == '\r' || c == '\n') { |
|
if (begin != end) { |
|
result->push_back(string(str, begin, end-begin)); |
|
} |
|
begin = end+1; |
|
} |
|
} |
|
if (begin != end) { |
|
result->push_back(string(str, begin, end-begin)); |
|
} |
|
} |
|
|
|
string |
|
read_file(const string& filename) |
|
{ |
|
FILE* file = fopen(filename.c_str(), "r"); |
|
if (file == NULL) { |
|
return string(); |
|
} |
|
|
|
fseek(file, 0, SEEK_END); |
|
int size = ftell(file); |
|
fseek(file, 0, SEEK_SET); |
|
|
|
char* buf = (char*)malloc(size); |
|
fread(buf, 1, size, file); |
|
|
|
string result(buf, size); |
|
|
|
free(buf); |
|
fclose(file); |
|
|
|
return result; |
|
} |
|
|
|
|
|
|