blob: c910c815494c04d84243467b49e1c880efe8e0f5 [file] [log] [blame]
Adam Lesinski6f6ceb72014-11-14 14:48:12 -08001/*
2 * Copyright (C) 2015 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 "Files.h"
18#include "Util.h"
19
20#include <cerrno>
21#include <dirent.h>
22#include <string>
23#include <sys/stat.h>
24
25namespace aapt {
26
27FileType getFileType(const StringPiece& path) {
28 struct stat sb;
29 if (stat(path.data(), &sb) < 0) {
30 if (errno == ENOENT || errno == ENOTDIR) {
31 return FileType::kNonexistant;
32 }
33 return FileType::kUnknown;
34 }
35
36 if (S_ISREG(sb.st_mode)) {
37 return FileType::kRegular;
38 } else if (S_ISDIR(sb.st_mode)) {
39 return FileType::kDirectory;
40 } else if (S_ISCHR(sb.st_mode)) {
41 return FileType::kCharDev;
42 } else if (S_ISBLK(sb.st_mode)) {
43 return FileType::kBlockDev;
44 } else if (S_ISFIFO(sb.st_mode)) {
45 return FileType::kFifo;
46 } else if (S_ISLNK(sb.st_mode)) {
47 return FileType::kSymlink;
48 } else if (S_ISSOCK(sb.st_mode)) {
49 return FileType::kSocket;
50 } else {
51 return FileType::kUnknown;
52 }
53}
54
55std::vector<std::string> listFiles(const StringPiece& root) {
56 DIR* dir = opendir(root.data());
57 if (dir == nullptr) {
58 Logger::error(Source{ root.toString() })
59 << "unable to open file: "
60 << strerror(errno)
61 << "."
62 << std::endl;
63 return {};
64 }
65
66 std::vector<std::string> files;
67 dirent* entry;
68 while ((entry = readdir(dir))) {
69 files.emplace_back(entry->d_name);
70 }
71
72 closedir(dir);
73 return files;
74}
75
76inline static int mkdirImpl(const StringPiece& path) {
77#ifdef HAVE_MS_C_RUNTIME
78 return _mkdir(path.toString().c_str());
79#else
80 return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
81#endif
82}
83
84bool mkdirs(const StringPiece& path) {
85 const char* start = path.begin();
86 const char* end = path.end();
87 for (const char* current = start; current != end; ++current) {
88 if (*current == sDirSep) {
89 StringPiece parentPath(start, current - start);
90 int result = mkdirImpl(parentPath);
91 if (result < 0 && errno != EEXIST) {
92 return false;
93 }
94 }
95 }
96 return mkdirImpl(path) == 0 || errno == EEXIST;
97}
98
99bool FileFilter::setPattern(const StringPiece& pattern) {
100 mPatternTokens = util::splitAndLowercase(pattern, ':');
101 return true;
102}
103
104bool FileFilter::operator()(const std::string& filename, FileType type) const {
105 if (filename == "." || filename == "..") {
106 return false;
107 }
108
109 const char kDir[] = "dir";
110 const char kFile[] = "file";
111 const size_t filenameLen = filename.length();
112 bool chatty = true;
113 for (const std::string& token : mPatternTokens) {
114 const char* tokenStr = token.c_str();
115 if (*tokenStr == '!') {
116 chatty = false;
117 tokenStr++;
118 }
119
120 if (strncasecmp(tokenStr, kDir, sizeof(kDir)) == 0) {
121 if (type != FileType::kDirectory) {
122 continue;
123 }
124 tokenStr += sizeof(kDir);
125 }
126
127 if (strncasecmp(tokenStr, kFile, sizeof(kFile)) == 0) {
128 if (type != FileType::kRegular) {
129 continue;
130 }
131 tokenStr += sizeof(kFile);
132 }
133
134 bool ignore = false;
135 size_t n = strlen(tokenStr);
136 if (*tokenStr == '*') {
137 // Math suffix.
138 tokenStr++;
139 n--;
140 if (n <= filenameLen) {
141 ignore = strncasecmp(tokenStr, filename.c_str() + filenameLen - n, n) == 0;
142 }
143 } else if (n > 1 && tokenStr[n - 1] == '*') {
144 // Match prefix.
145 ignore = strncasecmp(tokenStr, filename.c_str(), n - 1) == 0;
146 } else {
147 ignore = strcasecmp(tokenStr, filename.c_str()) == 0;
148 }
149
150 if (ignore) {
151 if (chatty) {
152 Logger::warn()
153 << "skipping " <<
154 (type == FileType::kDirectory ? "dir '" : "file '")
155 << filename
156 << "' due to ignore pattern '"
157 << token
158 << "'."
159 << std::endl;
160 }
161 return false;
162 }
163 }
164 return true;
165}
166
167
168} // namespace aapt