1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "extractor.h"
17
18 #include <fstream>
19 #include <sstream>
20 #include "ability_base_log_wrapper.h"
21 #include "constants.h"
22 #include "file_path_utils.h"
23 #include "securec.h"
24 #include "string_ex.h"
25
26 namespace OHOS {
27 namespace AbilityBase {
28 namespace {
29 constexpr char EXT_NAME_ABC[] = ".abc";
30 }
Extractor(const std::string & source)31 Extractor::Extractor(const std::string &source) : zipFile_(source)
32 {
33 hapPath_ = source;
34 }
35
~Extractor()36 Extractor::~Extractor()
37 {}
38
Init()39 bool Extractor::Init()
40 {
41 if (!zipFile_.Open()) {
42 ABILITYBASE_LOGE("open zip file failed");
43 return false;
44 }
45 initial_ = true;
46 return true;
47 }
48
GetFileBuffer(const std::string & srcPath,std::ostringstream & dest)49 bool Extractor::GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)
50 {
51 if (!initial_) {
52 ABILITYBASE_LOGE("extractor is not initial");
53 return false;
54 }
55
56 if (srcPath.empty()) {
57 ABILITYBASE_LOGE("GetFileBuffer::srcPath is nullptr");
58 return false;
59 }
60
61 std::string relativePath = GetRelativePath(srcPath);
62 if (!ExtractByName(relativePath, dest)) {
63 ABILITYBASE_LOGE("GetFileBuffer::Extract file failed");
64 return false;
65 }
66
67 return true;
68 }
69
GetFileList(const std::string & srcPath,std::vector<std::string> & assetList)70 bool Extractor::GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)
71 {
72 if (!initial_) {
73 ABILITYBASE_LOGE("extractor is not initial");
74 return false;
75 }
76
77 if (srcPath.empty()) {
78 ABILITYBASE_LOGE("GetFileList::srcPath is nullptr");
79 return false;
80 }
81 zipFile_.GetAllFileList(srcPath, assetList);
82 if (assetList.empty()) {
83 ABILITYBASE_LOGW("empty dir: %{public}s", srcPath.c_str());
84 }
85
86 return true;
87 }
88
HasEntry(const std::string & fileName) const89 bool Extractor::HasEntry(const std::string &fileName) const
90 {
91 if (!initial_) {
92 ABILITYBASE_LOGE("extractor is not initial");
93 return false;
94 }
95
96 return zipFile_.HasEntry(fileName);
97 }
98
IsDirExist(const std::string & dir) const99 bool Extractor::IsDirExist(const std::string &dir) const
100 {
101 if (!initial_) {
102 ABILITYBASE_LOGE("extractor is not initial");
103 return false;
104 }
105 if (dir.empty()) {
106 ABILITYBASE_LOGE("param dir empty");
107 return false;
108 }
109 return zipFile_.IsDirExist(dir);
110 }
111
ExtractByName(const std::string & fileName,std::ostream & dest) const112 bool Extractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
113 {
114 if (!initial_) {
115 ABILITYBASE_LOGE("extractor is not initial");
116 return false;
117 }
118 if (!zipFile_.ExtractFile(fileName, dest)) {
119 ABILITYBASE_LOGE("extractor is not ExtractFile");
120 return false;
121 }
122 return true;
123 }
124
ExtractFile(const std::string & fileName,const std::string & targetPath) const125 bool Extractor::ExtractFile(const std::string &fileName, const std::string &targetPath) const
126 {
127 std::ofstream fileStream;
128 fileStream.open(targetPath, std::ios_base::out | std::ios_base::binary);
129 if (!fileStream.is_open()) {
130 ABILITYBASE_LOGE("fail to open %{private}s file to write", targetPath.c_str());
131 return false;
132 }
133 if ((!ExtractByName(fileName, fileStream)) || (!fileStream.good())) {
134 ABILITYBASE_LOGE("fail to extract %{public}s zip file into stream", fileName.c_str());
135 fileStream.clear();
136 fileStream.close();
137 if (remove(targetPath.c_str()) != 0) {
138 ABILITYBASE_LOGE("fail to remove %{private}s file which writes stream error", targetPath.c_str());
139 }
140 return false;
141 }
142 fileStream.clear();
143 fileStream.close();
144 return true;
145 }
146
GetSpecifiedTypeFiles(std::vector<std::string> & fileNames,const std::string & suffix)147 void Extractor::GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)
148 {
149 auto &entryMap = zipFile_.GetAllEntries();
150 for (const auto &entry : entryMap) {
151 std::string fileName = entry.first;
152 auto position = fileName.rfind('.');
153 if (position != std::string::npos) {
154 std::string suffixStr = fileName.substr(position);
155 if (LowerStr(suffixStr) == suffix) {
156 fileNames.emplace_back(fileName);
157 }
158 }
159 }
160 }
161
IsStageBasedModel(std::string abilityName)162 bool Extractor::IsStageBasedModel(std::string abilityName)
163 {
164 std::vector<std::string> splitStrs;
165 OHOS::SplitStr(abilityName, ".", splitStrs);
166 std::string name = splitStrs.empty() ? abilityName : splitStrs.back();
167 std::string entry = "assets/js/" + name + "/" + name + ".js";
168 bool isStageBasedModel = zipFile_.HasEntry(entry);
169 return isStageBasedModel;
170 }
171
IsSameHap(const std::string & hapPath) const172 bool Extractor::IsSameHap(const std::string& hapPath) const
173 {
174 return !hapPath_.empty() && !hapPath.empty() && hapPath_ == hapPath;
175 }
176
GetData(const std::string & fileName,bool) const177 std::unique_ptr<FileMapper> Extractor::GetData(const std::string &fileName, bool) const
178 {
179 std::string relativePath = GetRelativePath(fileName);
180 return zipFile_.CreateFileMapper(relativePath, FileMapperType::NORMAL_MEM);
181 }
182
GetSafeData(const std::string & fileName)183 std::shared_ptr<FileMapper> Extractor::GetSafeData(const std::string &fileName)
184 {
185 std::string relativePath = GetRelativePath(fileName);
186 if (!StringEndWith(relativePath, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
187 return nullptr;
188 }
189
190 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SAFE_ABC);
191 }
192
GetMmapData(const std::string & fileName)193 std::unique_ptr<FileMapper> Extractor::GetMmapData(const std::string &fileName)
194 {
195 std::string relativePath = GetRelativePath(fileName);
196 return zipFile_.CreateFileMapper(relativePath, FileMapperType::SHARED_MMAP);
197 }
198
UnzipData(std::unique_ptr<FileMapper> fileMapper,std::unique_ptr<uint8_t[]> & dataPtr,size_t & len) const199 bool Extractor::UnzipData(std::unique_ptr<FileMapper> fileMapper,
200 std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
201 {
202 if (!initial_) {
203 ABILITYBASE_LOGE("extractor is not initial");
204 return false;
205 }
206
207 if (!fileMapper) {
208 ABILITYBASE_LOGE("Input fileMapper is nullptr.");
209 return false;
210 }
211
212 if (!zipFile_.ExtractFileFromMMap(fileMapper->GetFileName(), fileMapper->GetDataPtr(), dataPtr, len)) {
213 ABILITYBASE_LOGE("extract file from MMap failed.");
214 return false;
215 }
216 return true;
217 }
218
IsStageModel()219 bool Extractor::IsStageModel()
220 {
221 if (isStageModel_.has_value()) {
222 return isStageModel_.value();
223 }
224 isStageModel_ = !zipFile_.HasEntry("config.json");
225 return isStageModel_.value();
226 }
227
ExtractToBufByName(const std::string & fileName,std::unique_ptr<uint8_t[]> & dataPtr,size_t & len)228 bool Extractor::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
229 size_t &len)
230 {
231 std::string relativePath = GetRelativePath(fileName);
232 return zipFile_.ExtractToBufByName(relativePath, dataPtr, len);
233 }
234
GetFileInfo(const std::string & fileName,FileInfo & fileInfo) const235 bool Extractor::GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const
236 {
237 std::string relativePath = GetRelativePath(fileName);
238 ZipEntry zipEntry;
239 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
240 ABILITYBASE_LOGE("Get zip entry failed.");
241 return false;
242 }
243
244 ZipPos offset = 0;
245 uint32_t length = 0;
246 if (!zipFile_.GetDataOffsetRelative(relativePath, offset, length)) {
247 ABILITYBASE_LOGE("Get data offset relative failed.");
248 return false;
249 }
250
251 fileInfo.fileName = fileName;
252 fileInfo.offset = static_cast<uint32_t>(offset);
253 fileInfo.length = static_cast<uint32_t>(length);
254 fileInfo.lastModTime = zipEntry.modifiedTime;
255 fileInfo.lastModDate = zipEntry.modifiedDate;
256 return true;
257 }
258
GetFileList(const std::string & srcPath,std::set<std::string> & fileSet)259 bool Extractor::GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)
260 {
261 if (!initial_) {
262 ABILITYBASE_LOGE("extractor is not initial");
263 return false;
264 }
265
266 if (srcPath.empty()) {
267 ABILITYBASE_LOGE("GetFileList::srcPath is nullptr");
268 return false;
269 }
270
271 zipFile_.GetChildNames(srcPath, fileSet);
272 if (fileSet.empty()) {
273 ABILITYBASE_LOGW("empty dir: %{public}s", srcPath.c_str());
274 }
275
276 return true;
277 }
278
IsHapCompress(const std::string & fileName) const279 bool Extractor::IsHapCompress(const std::string &fileName) const
280 {
281 std::string relativePath = GetRelativePath(fileName);
282 ZipEntry zipEntry;
283 if (!zipFile_.GetEntry(relativePath, zipEntry)) {
284 ABILITYBASE_LOGE("Get entry info by name failed. fileName: %{public}s", fileName.c_str());
285 return false;
286 }
287 return zipEntry.compressionMethod > 0;
288 }
289
290 std::mutex ExtractorUtil::mapMutex_;
291 std::unordered_map<std::string, std::shared_ptr<Extractor>> ExtractorUtil::extractorMap_;
GetLoadFilePath(const std::string & hapPath)292 std::string ExtractorUtil::GetLoadFilePath(const std::string &hapPath)
293 {
294 std::string loadPath;
295 if (StringStartWith(hapPath, Constants::ABS_CODE_PATH, std::string(Constants::ABS_CODE_PATH).length())) {
296 loadPath = GetLoadPath(hapPath);
297 } else {
298 loadPath = hapPath;
299 }
300 return loadPath;
301 }
302
GetExtractor(const std::string & hapPath,bool & newCreate,bool cache)303 std::shared_ptr<Extractor> ExtractorUtil::GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)
304 {
305 newCreate = false;
306 if (hapPath.empty()) {
307 ABILITYBASE_LOGE("Input hapPath is empty.");
308 return nullptr;
309 }
310 {
311 std::lock_guard<std::mutex> mapMutex(mapMutex_);
312 auto mapIter = extractorMap_.find(hapPath);
313 if (mapIter != extractorMap_.end()) {
314 ABILITYBASE_LOGD("Extractor exists, hapPath: %{private}s.", hapPath.c_str());
315 return mapIter->second;
316 }
317 }
318
319 std::shared_ptr<Extractor> extractor = std::make_shared<Extractor>(hapPath);
320 if (!extractor->Init()) {
321 ABILITYBASE_LOGE("Extractor create failed for %{private}s", hapPath.c_str());
322 return nullptr;
323 }
324 if (cache) {
325 std::lock_guard<std::mutex> mapMutex(mapMutex_);
326 extractorMap_.emplace(hapPath, extractor);
327 ABILITYBASE_LOGI("extractor cache size: %{public}zu.", extractorMap_.size());
328 }
329 newCreate = true;
330 return extractor;
331 }
332
DeleteExtractor(const std::string & hapPath)333 void ExtractorUtil::DeleteExtractor(const std::string &hapPath)
334 {
335 if (hapPath.empty()) {
336 ABILITYBASE_LOGE("DeleteExtractor hapPath is empty.");
337 return;
338 }
339
340 std::lock_guard<std::mutex> mapMutex(mapMutex_);
341 auto mapIter = extractorMap_.find(hapPath);
342 if (mapIter != extractorMap_.end()) {
343 ABILITYBASE_LOGI("DeleteExtractor, hapPath: %{public}s.", hapPath.c_str());
344 extractorMap_.erase(mapIter);
345 }
346 }
347 } // namespace AbilityBase
348 } // namespace OHOS
349