diff options
Diffstat (limited to 'tools/aapt2/Files.cpp')
-rw-r--r-- | tools/aapt2/Files.cpp | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/tools/aapt2/Files.cpp b/tools/aapt2/Files.cpp new file mode 100644 index 000000000000..c910c815494c --- /dev/null +++ b/tools/aapt2/Files.cpp @@ -0,0 +1,168 @@ +/* + * 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> + +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; + } else if (S_ISLNK(sb.st_mode)) { + return FileType::kSymlink; + } else if (S_ISSOCK(sb.st_mode)) { + return FileType::kSocket; + } 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 HAVE_MS_C_RUNTIME + 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; +} + +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 |