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 "hitrace_meter.h"
24 #include "securec.h"
25 #include "string_ex.h"
26 
27 namespace OHOS {
28 namespace AbilityBase {
29 namespace {
30 constexpr char EXT_NAME_ABC[] = ".abc";
31 }
Extractor(const std::string &source)32 Extractor::Extractor(const std::string &source) : zipFile_(source)
33 {
34     hapPath_ = source;
35 }
36 
~Extractor()37 Extractor::~Extractor()
38 {}
39 
Init()40 bool Extractor::Init()
41 {
42     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
43     if (!zipFile_.Open()) {
44         ABILITYBASE_LOGD("open zip file failed");
45         return false;
46     }
47     initial_ = true;
48     return true;
49 }
50 
GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)51 bool Extractor::GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)
52 {
53     std::unique_ptr<uint8_t[]> data;
54     size_t dataLen = 0;
55 
56     if (!ExtractToBufByName(srcPath, data, dataLen)) {
57         return false;
58     }
59 
60     dest.write(reinterpret_cast<char*>(data.get()), dataLen);
61     return true;
62 }
63 
GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)64 bool Extractor::GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)
65 {
66     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
67     if (!initial_) {
68         ABILITYBASE_LOGE("not init");
69         return false;
70     }
71 
72     if (srcPath.empty()) {
73         ABILITYBASE_LOGE("empty srcPath");
74         return false;
75     }
76     zipFile_.GetAllFileList(srcPath, assetList);
77     if (assetList.empty()) {
78         ABILITYBASE_LOGW("empty dir: %{public}s", srcPath.c_str());
79     }
80 
81     return true;
82 }
83 
HasEntry(const std::string &fileName) const84 bool Extractor::HasEntry(const std::string &fileName) const
85 {
86     if (!initial_) {
87         ABILITYBASE_LOGE("not init");
88         return false;
89     }
90 
91     return zipFile_.HasEntry(fileName);
92 }
93 
IsDirExist(const std::string &dir)94 bool Extractor::IsDirExist(const std::string &dir)
95 {
96     if (!initial_) {
97         ABILITYBASE_LOGE("not init");
98         return false;
99     }
100     if (dir.empty()) {
101         ABILITYBASE_LOGE("dir empty");
102         return false;
103     }
104     return zipFile_.IsDirExist(dir);
105 }
106 
ExtractByName(const std::string &fileName, std::ostream &dest) const107 bool Extractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
108 {
109     std::unique_ptr<uint8_t[]> data;
110     size_t dataLen = 0;
111     if (!ExtractToBufByName(fileName, data, dataLen)) {
112         ABILITYBASE_LOGE("ExtractFile fail: %{public}s", fileName.c_str());
113         return false;
114     }
115     dest.write(reinterpret_cast<char*>(data.get()), dataLen);
116     return true;
117 }
118 
GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)119 void Extractor::GetSpecifiedTypeFiles(std::vector<std::string> &fileNames, const std::string &suffix)
120 {
121     auto &entryMap = zipFile_.GetAllEntries();
122     for (const auto &entry : entryMap) {
123         std::string fileName = entry.first;
124         auto position = fileName.rfind('.');
125         if (position != std::string::npos) {
126             std::string suffixStr = fileName.substr(position);
127             if (LowerStr(suffixStr) == suffix) {
128                 fileNames.emplace_back(fileName);
129             }
130         }
131     }
132 }
133 
GetData(const std::string &fileName) const134 std::unique_ptr<FileMapper> Extractor::GetData(const std::string &fileName) const
135 {
136     std::string relativePath = GetRelativePath(fileName);
137     return zipFile_.CreateFileMapper(relativePath, FileMapperType::NORMAL_MEM);
138 }
139 
GetSafeData(const std::string &fileName)140 std::shared_ptr<FileMapper> Extractor::GetSafeData(const std::string &fileName)
141 {
142     std::string relativePath = GetRelativePath(fileName);
143     if (!StringEndWith(relativePath, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
144         return nullptr;
145     }
146 
147     return zipFile_.CreateFileMapper(relativePath, FileMapperType::SAFE_ABC);
148 }
149 
GetMmapData(const std::string &fileName)150 std::unique_ptr<FileMapper> Extractor::GetMmapData(const std::string &fileName)
151 {
152     std::string relativePath = GetRelativePath(fileName);
153     return zipFile_.CreateFileMapper(relativePath, FileMapperType::SHARED_MMAP);
154 }
155 
UnzipData(std::unique_ptr<FileMapper> fileMapper, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const156 bool Extractor::UnzipData(std::unique_ptr<FileMapper> fileMapper,
157     std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
158 {
159     if (!initial_) {
160         ABILITYBASE_LOGE("not init");
161         return false;
162     }
163 
164     if (!fileMapper) {
165         ABILITYBASE_LOGE("null fileMapper");
166         return false;
167     }
168 
169     if (!zipFile_.ExtractFileFromMMap(fileMapper->GetFileName(), fileMapper->GetDataPtr(), dataPtr, len)) {
170         ABILITYBASE_LOGE("ExtractFileFromMMap failed");
171         return false;
172     }
173     return true;
174 }
175 
IsStageModel()176 bool Extractor::IsStageModel()
177 {
178     if (isStageModel_.has_value()) {
179         return isStageModel_.value();
180     }
181     isStageModel_ = !zipFile_.HasEntry("config.json");
182     return isStageModel_.value();
183 }
184 
ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const185 bool Extractor::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
186     size_t &len) const
187 {
188     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
189     std::string relativePath = GetRelativePath(fileName);
190     return zipFile_.ExtractToBufByName(relativePath, dataPtr, len);
191 }
192 
GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const193 bool Extractor::GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const
194 {
195     std::string relativePath = GetRelativePath(fileName);
196     ZipEntry zipEntry;
197     if (!zipFile_.GetEntry(relativePath, zipEntry)) {
198         ABILITYBASE_LOGE("Get entry failed");
199         return false;
200     }
201 
202     ZipPos offset = 0;
203     uint32_t length = 0;
204     if (!zipFile_.GetDataOffsetRelative(zipEntry, offset, length)) {
205         ABILITYBASE_LOGE("GetDataOffsetRelative failed");
206         return false;
207     }
208 
209     fileInfo.fileName = fileName;
210     fileInfo.offset = static_cast<uint32_t>(offset);
211     fileInfo.length = static_cast<uint32_t>(length);
212     fileInfo.lastModTime = zipEntry.modifiedTime;
213     fileInfo.lastModDate = zipEntry.modifiedDate;
214     return true;
215 }
216 
GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)217 bool Extractor::GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)
218 {
219     if (!initial_) {
220         ABILITYBASE_LOGE("not init");
221         return false;
222     }
223 
224     if (srcPath.empty()) {
225         ABILITYBASE_LOGE("empty srcPath");
226         return false;
227     }
228 
229     zipFile_.GetChildNames(srcPath, fileSet);
230     if (fileSet.empty()) {
231         ABILITYBASE_LOGD("empty dir: %{public}s", srcPath.c_str());
232     }
233 
234     return true;
235 }
236 
IsHapCompress(const std::string &fileName) const237 bool Extractor::IsHapCompress(const std::string &fileName) const
238 {
239     std::string relativePath = GetRelativePath(fileName);
240     ZipEntry zipEntry;
241     if (!zipFile_.GetEntry(relativePath, zipEntry)) {
242         ABILITYBASE_LOGE("GetEntry failed fileName: %{public}s", fileName.c_str());
243         return false;
244     }
245     return zipEntry.compressionMethod > 0;
246 }
247 
248 std::mutex ExtractorUtil::mapMutex_;
249 std::unordered_map<std::string, std::shared_ptr<Extractor>> ExtractorUtil::extractorMap_;
GetLoadFilePath(const std::string &hapPath)250 std::string ExtractorUtil::GetLoadFilePath(const std::string &hapPath)
251 {
252     std::string loadPath;
253     if (StringStartWith(hapPath, Constants::ABS_CODE_PATH, std::string(Constants::ABS_CODE_PATH).length())) {
254         loadPath = GetLoadPath(hapPath);
255     } else {
256         loadPath = hapPath;
257     }
258     return loadPath;
259 }
260 
GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)261 std::shared_ptr<Extractor> ExtractorUtil::GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)
262 {
263     newCreate = false;
264     if (hapPath.empty()) {
265         ABILITYBASE_LOGE("empty hapPath");
266         return nullptr;
267     }
268     {
269         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_find_from_cache");
270         std::lock_guard<std::mutex> mapMutex(mapMutex_);
271         auto mapIter = extractorMap_.find(hapPath);
272         if (mapIter != extractorMap_.end()) {
273             ABILITYBASE_LOGD("hapPath: %{private}s", hapPath.c_str());
274             return mapIter->second;
275         }
276     }
277 
278     std::shared_ptr<Extractor> extractor = std::make_shared<Extractor>(hapPath);
279     if (!extractor->Init()) {
280         ABILITYBASE_LOGD("create failed for %{private}s", hapPath.c_str());
281         return nullptr;
282     }
283     if (cache) {
284         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, "GetExtractor_store");
285         std::lock_guard<std::mutex> mapMutex(mapMutex_);
286         extractorMap_.emplace(hapPath, extractor);
287         ABILITYBASE_LOGD("extractor cache size: %{public}zu", extractorMap_.size());
288     }
289     newCreate = true;
290     return extractor;
291 }
292 
DeleteExtractor(const std::string &hapPath)293 void ExtractorUtil::DeleteExtractor(const std::string &hapPath)
294 {
295     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
296     if (hapPath.empty()) {
297         ABILITYBASE_LOGE("empty hapPath");
298         return;
299     }
300 
301     std::lock_guard<std::mutex> mapMutex(mapMutex_);
302     auto mapIter = extractorMap_.find(hapPath);
303     if (mapIter != extractorMap_.end()) {
304         ABILITYBASE_LOGI("hapPath: %{public}s", hapPath.c_str());
305         extractorMap_.erase(mapIter);
306     }
307 }
308 }  // namespace AbilityBase
309 }  // namespace OHOS
310