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 #define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
18
19 #include "io/FileSystem.h"
20
21 #include <dirent.h>
22 #include <sys/stat.h>
23
24 #include "android-base/errors.h"
25 #include "androidfw/FileStream.h"
26 #include "androidfw/Source.h"
27 #include "androidfw/StringPiece.h"
28 #include "util/Files.h"
29 #include "util/Util.h"
30 #include "utils/FileMap.h"
31
32 using ::android::StringPiece;
33 using ::android::base::SystemErrorCodeToString;
34
35 namespace aapt {
36 namespace io {
37
RegularFile(const android::Source & source)38 RegularFile::RegularFile(const android::Source& source) : source_(source) {
39 }
40
OpenAsData()41 std::unique_ptr<IData> RegularFile::OpenAsData() {
42 android::FileMap map;
43 if (std::optional<android::FileMap> map = file::MmapPath(source_.path, nullptr)) {
44 if (map.value().getDataPtr() && map.value().getDataLength() > 0) {
45 return util::make_unique<MmappedData>(std::move(map.value()));
46 }
47 return util::make_unique<EmptyData>();
48 }
49 return {};
50 }
51
OpenInputStream()52 std::unique_ptr<android::InputStream> RegularFile::OpenInputStream() {
53 return util::make_unique<android::FileInputStream>(source_.path);
54 }
55
GetSource() const56 const android::Source& RegularFile::GetSource() const {
57 return source_;
58 }
59
GetModificationTime(struct tm * buf) const60 bool RegularFile::GetModificationTime(struct tm* buf) const {
61 if (buf == nullptr) {
62 return false;
63 }
64 struct stat stat_buf;
65 if (stat(source_.path.c_str(), &stat_buf) != 0) {
66 return false;
67 }
68
69 struct tm* ptm;
70 struct tm tm_result;
71 ptm = localtime_r(&stat_buf.st_mtime, &tm_result);
72
73 *buf = *ptm;
74 return true;
75 }
76
FileCollectionIterator(FileCollection * collection)77 FileCollectionIterator::FileCollectionIterator(FileCollection* collection)
78 : current_(collection->files_.begin()), end_(collection->files_.end()) {}
79
HasNext()80 bool FileCollectionIterator::HasNext() {
81 return current_ != end_;
82 }
83
Next()84 IFile* FileCollectionIterator::Next() {
85 IFile* result = current_->second.get();
86 ++current_;
87 return result;
88 }
89
Create(android::StringPiece root,std::string * outError)90 std::unique_ptr<FileCollection> FileCollection::Create(android::StringPiece root,
91 std::string* outError) {
92 std::unique_ptr<FileCollection> collection =
93 std::unique_ptr<FileCollection>(new FileCollection());
94
95 std::unique_ptr<DIR, decltype(closedir) *> d(opendir(root.data()), closedir);
96 if (!d) {
97 *outError = "failed to open directory: " + SystemErrorCodeToString(errno);
98 return nullptr;
99 }
100
101 std::vector<std::string> sorted_files;
102 while (struct dirent *entry = readdir(d.get())) {
103 std::string prefix_path(root);
104 file::AppendPath(&prefix_path, entry->d_name);
105
106 // The directory to iterate over looking for files
107 if (file::GetFileType(prefix_path) != file::FileType::kDirectory
108 || file::IsHidden(prefix_path)) {
109 continue;
110 }
111
112 std::unique_ptr<DIR, decltype(closedir)*> subdir(opendir(prefix_path.data()), closedir);
113 if (!subdir) {
114 *outError = "failed to open directory: " + SystemErrorCodeToString(errno);
115 return nullptr;
116 }
117
118 while (struct dirent* leaf_entry = readdir(subdir.get())) {
119 std::string full_path = prefix_path;
120 file::AppendPath(&full_path, leaf_entry->d_name);
121
122 // Do not add folders to the file collection
123 if (file::GetFileType(full_path) == file::FileType::kDirectory
124 || file::IsHidden(full_path)) {
125 continue;
126 }
127
128 sorted_files.push_back(full_path);
129 }
130 }
131
132 std::sort(sorted_files.begin(), sorted_files.end());
133 for (const std::string& full_path : sorted_files) {
134 collection->InsertFile(full_path);
135 }
136
137 return collection;
138 }
139
InsertFile(StringPiece path)140 IFile* FileCollection::InsertFile(StringPiece path) {
141 auto file = util::make_unique<RegularFile>(android::Source(path));
142 auto it = files_.lower_bound(path);
143 if (it != files_.end() && it->first == path) {
144 it->second = std::move(file);
145 } else {
146 it = files_.emplace_hint(it, path, std::move(file));
147 }
148 return it->second.get();
149 }
150
FindFile(StringPiece path)151 IFile* FileCollection::FindFile(StringPiece path) {
152 auto iter = files_.find(path);
153 if (iter != files_.end()) {
154 return iter->second.get();
155 }
156 return nullptr;
157 }
158
Iterator()159 std::unique_ptr<IFileCollectionIterator> FileCollection::Iterator() {
160 return util::make_unique<FileCollectionIterator>(this);
161 }
162
GetDirSeparator()163 char FileCollection::GetDirSeparator() {
164 return file::sDirSep;
165 }
166
167 } // namespace io
168 } // namespace aapt
169