• 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 #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