blob: b24ff6bb62912293067d96809dba8d7a68d48084 [file] [log] [blame]
/*
* Copyright (C) 2015 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 "Files.h"
#include "Util.h"
#include <cerrno>
#include <dirent.h>
#include <string>
#include <sys/stat.h>
#ifdef _WIN32
// Windows includes.
#include <direct.h>
#endif
namespace aapt {
FileType getFileType(const StringPiece& path) {
struct stat sb;
if (stat(path.data(), &sb) < 0) {
if (errno == ENOENT || errno == ENOTDIR) {
return FileType::kNonexistant;
}
return FileType::kUnknown;
}
if (S_ISREG(sb.st_mode)) {
return FileType::kRegular;
} else if (S_ISDIR(sb.st_mode)) {
return FileType::kDirectory;
} else if (S_ISCHR(sb.st_mode)) {
return FileType::kCharDev;
} else if (S_ISBLK(sb.st_mode)) {
return FileType::kBlockDev;
} else if (S_ISFIFO(sb.st_mode)) {
return FileType::kFifo;
#if defined(S_ISLNK)
} else if (S_ISLNK(sb.st_mode)) {
return FileType::kSymlink;
#endif
#if defined(S_ISSOCK)
} else if (S_ISSOCK(sb.st_mode)) {
return FileType::kSocket;
#endif
} else {
return FileType::kUnknown;
}
}
std::vector<std::string> listFiles(const StringPiece& root) {
DIR* dir = opendir(root.data());
if (dir == nullptr) {
Logger::error(Source{ root.toString() })
<< "unable to open file: "
<< strerror(errno)
<< "."
<< std::endl;
return {};
}
std::vector<std::string> files;
dirent* entry;
while ((entry = readdir(dir))) {
files.emplace_back(entry->d_name);
}
closedir(dir);
return files;
}
inline static int mkdirImpl(const StringPiece& path) {
#ifdef _WIN32
return _mkdir(path.toString().c_str());
#else
return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
#endif
}
bool mkdirs(const StringPiece& path) {
const char* start = path.begin();
const char* end = path.end();
for (const char* current = start; current != end; ++current) {
if (*current == sDirSep) {
StringPiece parentPath(start, current - start);
int result = mkdirImpl(parentPath);
if (result < 0 && errno != EEXIST) {
return false;
}
}
}
return mkdirImpl(path) == 0 || errno == EEXIST;
}
std::string getStem(const StringPiece& path) {
const char* start = path.begin();
const char* end = path.end();
for (const char* current = end - 1; current != start - 1; --current) {
if (*current == sDirSep) {
return std::string(start, current - start);
}
}
return {};
}
bool FileFilter::setPattern(const StringPiece& pattern) {
mPatternTokens = util::splitAndLowercase(pattern, ':');
return true;
}
bool FileFilter::operator()(const std::string& filename, FileType type) const {
if (filename == "." || filename == "..") {
return false;
}
const char kDir[] = "dir";
const char kFile[] = "file";
const size_t filenameLen = filename.length();
bool chatty = true;
for (const std::string& token : mPatternTokens) {
const char* tokenStr = token.c_str();
if (*tokenStr == '!') {
chatty = false;
tokenStr++;
}
if (strncasecmp(tokenStr, kDir, sizeof(kDir)) == 0) {
if (type != FileType::kDirectory) {
continue;
}
tokenStr += sizeof(kDir);
}
if (strncasecmp(tokenStr, kFile, sizeof(kFile)) == 0) {
if (type != FileType::kRegular) {
continue;
}
tokenStr += sizeof(kFile);
}
bool ignore = false;
size_t n = strlen(tokenStr);
if (*tokenStr == '*') {
// Math suffix.
tokenStr++;
n--;
if (n <= filenameLen) {
ignore = strncasecmp(tokenStr, filename.c_str() + filenameLen - n, n) == 0;
}
} else if (n > 1 && tokenStr[n - 1] == '*') {
// Match prefix.
ignore = strncasecmp(tokenStr, filename.c_str(), n - 1) == 0;
} else {
ignore = strcasecmp(tokenStr, filename.c_str()) == 0;
}
if (ignore) {
if (chatty) {
Logger::warn()
<< "skipping " <<
(type == FileType::kDirectory ? "dir '" : "file '")
<< filename
<< "' due to ignore pattern '"
<< token
<< "'."
<< std::endl;
}
return false;
}
}
return true;
}
} // namespace aapt