blob: 6a692e49781666e2ec0834f4ebe39fc31be5d359 [file] [log] [blame]
Adam Lesinskia6fe3452015-12-09 15:20:52 -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
Mark Punzalane5671592023-09-02 00:00:30 +000017#define _POSIX_THREAD_SAFE_FUNCTIONS // For mingw localtime_r().
18
Adam Lesinskia6fe3452015-12-09 15:20:52 -080019#include "io/FileSystem.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070020
Ryan Mitchellf3649d62018-08-02 16:16:45 -070021#include <dirent.h>
Mark Punzalane5671592023-09-02 00:00:30 +000022#include <sys/stat.h>
Ryan Mitchellf3649d62018-08-02 16:16:45 -070023
24#include "android-base/errors.h"
Jeremy Meyer56f36e82022-05-20 20:35:42 +000025#include "androidfw/Source.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080026#include "androidfw/StringPiece.h"
Adam Lesinski00451162017-10-03 07:44:08 -070027#include "io/FileStream.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080028#include "util/Files.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080029#include "util/Util.h"
Jeremy Meyer56f36e82022-05-20 20:35:42 +000030#include "utils/FileMap.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080031
Adam Lesinski00451162017-10-03 07:44:08 -070032using ::android::StringPiece;
Ryan Mitchellf3649d62018-08-02 16:16:45 -070033using ::android::base::SystemErrorCodeToString;
Adam Lesinskid5083f62017-01-16 15:07:21 -080034
Adam Lesinskia6fe3452015-12-09 15:20:52 -080035namespace aapt {
36namespace io {
37
Jeremy Meyer56f36e82022-05-20 20:35:42 +000038RegularFile::RegularFile(const android::Source& source) : source_(source) {
39}
Adam Lesinskia6fe3452015-12-09 15:20:52 -080040
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041std::unique_ptr<IData> RegularFile::OpenAsData() {
42 android::FileMap map;
Ryan Mitchell4382e442021-07-14 12:53:01 -070043 if (std::optional<android::FileMap> map = file::MmapPath(source_.path, nullptr)) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070044 if (map.value().getDataPtr() && map.value().getDataLength() > 0) {
45 return util::make_unique<MmappedData>(std::move(map.value()));
Adam Lesinskia6fe3452015-12-09 15:20:52 -080046 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070047 return util::make_unique<EmptyData>();
48 }
49 return {};
Adam Lesinskia6fe3452015-12-09 15:20:52 -080050}
51
Adam Lesinski00451162017-10-03 07:44:08 -070052std::unique_ptr<io::InputStream> RegularFile::OpenInputStream() {
53 return util::make_unique<FileInputStream>(source_.path);
54}
55
Jeremy Meyer56f36e82022-05-20 20:35:42 +000056const android::Source& RegularFile::GetSource() const {
Adam Lesinski00451162017-10-03 07:44:08 -070057 return source_;
58}
Adam Lesinskice5e56e2016-10-21 17:56:45 -070059
Mark Punzalane5671592023-09-02 00:00:30 +000060bool 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
Adam Lesinskice5e56e2016-10-21 17:56:45 -070077FileCollectionIterator::FileCollectionIterator(FileCollection* collection)
78 : current_(collection->files_.begin()), end_(collection->files_.end()) {}
79
Adam Lesinski00451162017-10-03 07:44:08 -070080bool FileCollectionIterator::HasNext() {
81 return current_ != end_;
82}
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083
84IFile* FileCollectionIterator::Next() {
85 IFile* result = current_->second.get();
86 ++current_;
87 return result;
Adam Lesinskia6fe3452015-12-09 15:20:52 -080088}
89
Yurii Zubrytskyia5775142022-11-02 17:49:49 -070090std::unique_ptr<FileCollection> FileCollection::Create(android::StringPiece root,
91 std::string* outError) {
Ryan Mitchellf3649d62018-08-02 16:16:45 -070092 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
Ryan Mitchellf22ed8d2019-02-20 08:05:31 -0800101 std::vector<std::string> sorted_files;
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700102 while (struct dirent *entry = readdir(d.get())) {
Yurii Zubrytskyia5775142022-11-02 17:49:49 -0700103 std::string prefix_path(root);
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700104 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
Ryan Mitchellf22ed8d2019-02-20 08:05:31 -0800128 sorted_files.push_back(full_path);
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700129 }
130 }
131
Ryan Mitchellf22ed8d2019-02-20 08:05:31 -0800132 std::sort(sorted_files.begin(), sorted_files.end());
133 for (const std::string& full_path : sorted_files) {
134 collection->InsertFile(full_path);
135 }
136
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700137 return collection;
138}
139
Yurii Zubrytskyia5775142022-11-02 17:49:49 -0700140IFile* 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();
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800149}
150
Yurii Zubrytskyia5775142022-11-02 17:49:49 -0700151IFile* FileCollection::FindFile(StringPiece path) {
152 auto iter = files_.find(path);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700153 if (iter != files_.end()) {
154 return iter->second.get();
155 }
156 return nullptr;
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800157}
158
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159std::unique_ptr<IFileCollectionIterator> FileCollection::Iterator() {
160 return util::make_unique<FileCollectionIterator>(this);
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800161}
162
Ryan Mitchell0ce89732018-10-03 09:20:57 -0700163char FileCollection::GetDirSeparator() {
164 return file::sDirSep;
165}
166
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700167} // namespace io
168} // namespace aapt