blob: 63399d69a166a34d7819e27d649a7bf25b99aa4e [file] [log] [blame]
/*
* 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)
{
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);
if ((size_t) size != fread(buf, 1, size, file)) {
free(buf);
fclose(file);
return string();
}
string result(buf, size);
free(buf);
fclose(file);
return result;
}
bool
is_executable(const string& filename)
{
int err;
struct stat st;
err = stat(filename.c_str(), &st);
if (err != 0) {
return false;
}
return (st.st_mode & S_IXUSR) != 0;
}
string
dirname(const string& filename)
{
size_t slash = filename.rfind('/');
if (slash == string::npos) {
return "";
} else if (slash == 0) {
return "/";
} else {
return string(filename, 0, slash);
}
}
string
leafname(const string& filename)
{
size_t slash = filename.rfind('/');
if (slash == string::npos) {
return filename;
} else if (slash == filename.length() - 1) {
return "";
} else {
return string(filename, slash + 1);
}
}