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